from __future__ import annotations import argparse import json from pathlib import Path def replace_required(text: str, old: str, new: str, label: str) -> str: if new in text: return text if old not in text: raise RuntimeError(f'{label} marker not found') return text.replace(old, new, 1) def patch_send_ts(text: str) -> str: text = replace_required( text, '}): Promise<{ messageId: string }> {\n const { to, text, opts } = params;\n', '}): Promise<{ messageId: string; createTimeMs: number }> {\n const { to, text, opts } = params;\n', 'TS send return type', ) text = replace_required( text, ' const clientId = generateClientId();\n const req = buildSendMessageReq({', ' const clientId = generateClientId();\n const createTimeMs = Date.now();\n const req = buildSendMessageReq({', 'TS create time', ) text = replace_required( text, ' });\n try {\n await sendMessageApi({', ' });\n if (!req.msg?.item_list?.[0]) throw new Error("sendMessageWeixin: text item missing");\n req.msg.item_list[0].create_time_ms = createTimeMs;\n try {\n await sendMessageApi({', 'TS request timestamp', ) text = replace_required( text, ' return { messageId: clientId };\n}\n\n/** Send a single structured MessageItem downstream. */', ' return { messageId: clientId, createTimeMs };\n}\n\n/** Send a single structured MessageItem downstream. */', 'TS send result', ) return text def patch_send_js(text: str) -> str: text = replace_required( text, ' const clientId = generateClientId();\n const req = buildSendMessageReq({', ' const clientId = generateClientId();\n const createTimeMs = Date.now();\n const req = buildSendMessageReq({', 'JS create time', ) text = replace_required( text, ' });\n try {\n await sendMessageApi({', ' });\n if (!req.msg?.item_list?.[0])\n throw new Error("sendMessageWeixin: text item missing");\n req.msg.item_list[0].create_time_ms = createTimeMs;\n try {\n await sendMessageApi({', 'JS request timestamp', ) text = replace_required( text, ' return { messageId: clientId };\n}\n/** Send a single structured MessageItem downstream. */', ' return { messageId: clientId, createTimeMs };\n}\n/** Send a single structured MessageItem downstream. */', 'JS send result', ) return text def patch_process_ts(text: str) -> str: old = '''await sendMessageWeixin({ to: ctx.To, text, opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId, }});''' new = '''const sentText = await sendMessageWeixin({ to: ctx.To, text, opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId, }}); rememberHermesOutboundTextMessage(deps.accountId, ctx.To, text, sentText.createTimeMs);''' text = replace_required(text, old, new, 'TS fallback text send') old = '''await sendMessageWeixin({ to: ctx.To, text, opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId, }});''' new = '''const sentText = await sendMessageWeixin({ to: ctx.To, text, opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId, }}); rememberHermesOutboundTextMessage(deps.accountId, ctx.To, text, sentText.createTimeMs);''' return replace_required(text, old, new, 'TS normal text send') def patch_process_js(text: str) -> str: old = '''await sendMessageWeixin({ to: ctx.To, text, opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId, } });''' new = '''const sentText = await sendMessageWeixin({ to: ctx.To, text, opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId, } }); rememberHermesOutboundTextMessage(deps.accountId, ctx.To, text, sentText.createTimeMs);''' text = replace_required(text, old, new, 'JS fallback text send') old = '''await sendMessageWeixin({ to: ctx.To, text, opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId, } });''' new = '''const sentText = await sendMessageWeixin({ to: ctx.To, text, opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId, } }); rememberHermesOutboundTextMessage(deps.accountId, ctx.To, text, sentText.createTimeMs);''' return replace_required(text, old, new, 'JS normal text send') def apply(root: Path) -> dict[str, bool]: transforms = { 'src/messaging/send.ts': patch_send_ts, 'dist/src/messaging/send.js': patch_send_js, 'src/messaging/process-message.ts': patch_process_ts, 'dist/src/messaging/process-message.js': patch_process_js, } changed = {} for relative, transform in transforms.items(): path = root / relative original = path.read_text(encoding='utf-8') updated = transform(original) changed[relative] = updated != original if updated != original: path.write_text(updated, encoding='utf-8') return changed def main() -> int: parser = argparse.ArgumentParser() parser.add_argument('plugin_root', type=Path) args = parser.parse_args() root = args.plugin_root.resolve() print(json.dumps({'plugin_root': str(root), 'changed': apply(root)}, ensure_ascii=False)) return 0 if __name__ == '__main__': raise SystemExit(main())