feat(wechat): MindSpace public draft push with 143 host defaults

Add public-page WeChat draft button, publication standard conversion for poem/prose/generic pages, and quick push APIs. Default Studio release SSH targets to john@180.159.29.143 with 105 edge upstream via 10.10.0.2.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-09-11 12:32:13 +08:00
parent c5284a70c9
commit d8eaef3fbd
29 changed files with 2094 additions and 140 deletions
@@ -2,6 +2,8 @@ import crypto from 'node:crypto';
import fs from 'node:fs';
import path from 'node:path';
import { createAgentRunGateway } from '../agent-run-gateway.mjs';
import { releaseMaterializedPageDeliveryContracts } from '../mindspace-delivery-contract.mjs';
import { resolvePublishDir } from '../user-publish.mjs';
import { createGoalRunService } from '../goal-run-service.mjs';
import { isDirectChatSessionId } from '../direct-chat-service.mjs';
import {
@@ -288,6 +290,16 @@ export function bootstrapPortalGatewayServices({
sessionId,
sinceMs: runStartedAtMs,
}),
releaseUserPageDeliveryContractsOnSuccess: async ({
userId,
relativePaths,
}) =>
releaseMaterializedPageDeliveryContracts({
pool,
userId,
relativePaths,
publishDir: resolvePublishDir(h5Root, { id: userId }),
}),
isSessionExternallyBusy: ({ sessionId }) =>
isSessionPageDeliveryActive(sessionId),
validateRunDeliverables,
@@ -3,6 +3,10 @@ import {
quickPlazaFromChat,
quickPlazaFromPublicHtml,
} from '../mindspace-chat-plaza.mjs';
import {
getQuickWechatDraftFromPublicHtmlStatus,
quickWechatDraftFromPublicHtml,
} from '../mindspace-chat-wechat-draft.mjs';
function assertRouter(api) {
if (
@@ -41,6 +45,11 @@ export function attachPortalMindSpaceChatShareRoutes(
getQuickPlazaFromPublicHtmlStatusFn =
getQuickPlazaFromPublicHtmlStatus,
quickPlazaFromPublicHtmlFn = quickPlazaFromPublicHtml,
getWechatMpConfig = () => null,
getWechatPageDraft = () => null,
getQuickWechatDraftFromPublicHtmlStatusFn =
getQuickWechatDraftFromPublicHtmlStatus,
quickWechatDraftFromPublicHtmlFn = quickWechatDraftFromPublicHtml,
now = Date.now,
logger = console,
} = {},
@@ -268,4 +277,90 @@ export function attachPortalMindSpaceChatShareRoutes(
}
},
);
api.get(
'/mindspace/v1/pages/quick-wechat-draft-from-public-html/status',
async (req, res) => {
const pages = getMindSpacePages();
const publications = getMindSpacePublications();
const chatSave = getMindSpaceChatSave();
const draftService = getWechatPageDraft?.();
if (!pages || !chatSave || !draftService) {
return sendError(
res,
req,
503,
'wechat_draft_unavailable',
'公众号草稿推送未启用',
);
}
try {
const relativePath = String(
req.query?.relative_path ??
req.query?.relativePath ??
'',
).trim();
const result = await getQuickWechatDraftFromPublicHtmlStatusFn({
user: req.currentUser,
relativePath,
mindSpacePages: pages,
mindSpacePublications: publications,
readWorkspaceHtml: (input) => chatSave.readWorkspaceHtml(input),
getWechatMpConfig,
getWechatPageDraft: () => draftService,
});
return sendData(res, req, result);
} catch (error) {
return handleMindSpaceError(res, req, error);
}
},
);
api.post(
'/mindspace/v1/pages/quick-wechat-draft-from-public-html',
async (req, res) => {
const pages = getMindSpacePages();
const publications = getMindSpacePublications();
const chatSave = getMindSpaceChatSave();
const draftService = getWechatPageDraft?.();
if (!pages || !chatSave || !draftService) {
return sendError(
res,
req,
503,
'wechat_draft_unavailable',
'公众号草稿推送未启用',
);
}
const startedAt = now();
try {
const relativePath = String(
req.body?.relative_path ??
req.body?.relativePath ??
'',
).trim();
const result = await quickWechatDraftFromPublicHtmlFn({
user: req.currentUser,
relativePath,
mindSpacePages: pages,
mindSpacePublications: publications,
readWorkspaceHtml: (input) => chatSave.readWorkspaceHtml(input),
getWechatPageDraft: () => draftService,
});
logger.info('[quick-wechat-draft-public-html] ok', {
ms: now() - startedAt,
pageId: result.pageId ?? result.run?.pageId,
draftMediaId: result.draftMediaId,
relativePath,
});
return sendData(res, req, result, 201);
} catch (error) {
logger.error('[quick-wechat-draft-public-html] error:', {
ms: now() - startedAt,
error,
});
return handleMindSpaceError(res, req, error);
}
},
);
}
@@ -121,6 +121,8 @@ test('chat share module preserves route inventory and order', () => {
'POST /mindspace/v1/pages/quick-plaza-from-chat',
'GET /mindspace/v1/pages/quick-plaza-from-public-html/status',
'POST /mindspace/v1/pages/quick-plaza-from-public-html',
'GET /mindspace/v1/pages/quick-wechat-draft-from-public-html/status',
'POST /mindspace/v1/pages/quick-wechat-draft-from-public-html',
]);
});
@@ -350,6 +352,16 @@ test('chat share routes preserve availability gates and MindSpace fallback error
assert.equal(res.body.error.code, 'plaza_unavailable');
}
for (const route of [
'GET /mindspace/v1/pages/quick-wechat-draft-from-public-html/status',
'POST /mindspace/v1/pages/quick-wechat-draft-from-public-html',
]) {
const res = createResponseRecorder();
await unavailableApi.routes.get(route)(createRequest(), res);
assert.equal(res.statusCode, 503, route);
assert.equal(res.body.error.code, 'wechat_draft_unavailable');
}
const failureApi = createRouterRecorder();
const failure = new Error('share failed');
const dependencies = createDependencies({