shennian 0.2.88 → 0.2.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/dist/assets/wechat-channel/macos/manifest.json +22 -0
  2. package/dist/assets/wechat-channel/macos/shennian-wechat-channel-helper +0 -0
  3. package/dist/bin/shennian.js +1 -1
  4. package/dist/publish-build-manifest.json +548 -0
  5. package/dist/scripts/wechat-rpa-confirmation.mjs +5 -97
  6. package/dist/src/agent-env.js +4 -105
  7. package/dist/src/agents/adapter.d.ts +6 -0
  8. package/dist/src/agents/adapter.js +1 -19
  9. package/dist/src/agents/claude.js +8 -305
  10. package/dist/src/agents/codex-control.d.ts +35 -0
  11. package/dist/src/agents/codex-control.js +2 -0
  12. package/dist/src/agents/codex-utils.js +7 -200
  13. package/dist/src/agents/codex.d.ts +8 -0
  14. package/dist/src/agents/codex.js +15 -863
  15. package/dist/src/agents/command-spec.js +2 -413
  16. package/dist/src/agents/config-status.js +1 -226
  17. package/dist/src/agents/cursor.js +1 -249
  18. package/dist/src/agents/custom.js +4 -271
  19. package/dist/src/agents/detect.js +1 -56
  20. package/dist/src/agents/external-channel-instructions.js +10 -94
  21. package/dist/src/agents/gemini.js +1 -173
  22. package/dist/src/agents/manager.js +13 -157
  23. package/dist/src/agents/model-registry/cache.js +1 -37
  24. package/dist/src/agents/model-registry/discovery.js +2 -187
  25. package/dist/src/agents/model-registry/parsers.js +4 -447
  26. package/dist/src/agents/model-registry/runner.js +1 -30
  27. package/dist/src/agents/model-registry/service.js +1 -78
  28. package/dist/src/agents/model-registry/types.js +1 -8
  29. package/dist/src/agents/model-registry.js +1 -18
  30. package/dist/src/agents/openclaw.js +2 -275
  31. package/dist/src/agents/opencode.js +1 -231
  32. package/dist/src/agents/pi-context.js +12 -217
  33. package/dist/src/agents/pi.js +14 -723
  34. package/dist/src/agents/platform-instructions.js +9 -54
  35. package/dist/src/channels/base.d.ts +4 -1
  36. package/dist/src/channels/base.js +1 -3
  37. package/dist/src/channels/registry.js +1 -30
  38. package/dist/src/channels/reply-split.js +10 -89
  39. package/dist/src/channels/runtime.d.ts +1 -0
  40. package/dist/src/channels/runtime.js +5 -533
  41. package/dist/src/channels/secret-registry.d.ts +1 -0
  42. package/dist/src/channels/secret-registry.js +1 -46
  43. package/dist/src/channels/websocket.js +8 -378
  44. package/dist/src/channels/wechat-channel/anchor.d.ts +10 -0
  45. package/dist/src/channels/wechat-channel/anchor.js +1 -0
  46. package/dist/src/channels/wechat-channel/client.d.ts +74 -0
  47. package/dist/src/channels/wechat-channel/client.js +1 -0
  48. package/dist/src/channels/wechat-channel/cooldown.d.ts +15 -0
  49. package/dist/src/channels/wechat-channel/cooldown.js +1 -0
  50. package/dist/src/channels/wechat-channel/fingerprint.d.ts +28 -0
  51. package/dist/src/channels/wechat-channel/fingerprint.js +1 -0
  52. package/dist/src/channels/wechat-channel/helper-assets.d.ts +37 -0
  53. package/dist/src/channels/wechat-channel/helper-assets.js +1 -0
  54. package/dist/src/channels/wechat-channel/helper-client.d.ts +25 -0
  55. package/dist/src/channels/wechat-channel/helper-client.js +3 -0
  56. package/dist/src/channels/wechat-channel/helper-protocol.d.ts +84 -0
  57. package/dist/src/channels/wechat-channel/helper-protocol.js +1 -0
  58. package/dist/src/channels/wechat-channel/index.d.ts +17 -0
  59. package/dist/src/channels/wechat-channel/index.js +1 -0
  60. package/dist/src/channels/wechat-channel/ledger.d.ts +33 -0
  61. package/dist/src/channels/wechat-channel/ledger.js +1 -0
  62. package/dist/src/channels/wechat-channel/media-resolver.d.ts +32 -0
  63. package/dist/src/channels/wechat-channel/media-resolver.js +1 -0
  64. package/dist/src/channels/wechat-channel/message-key.d.ts +19 -0
  65. package/dist/src/channels/wechat-channel/message-key.js +1 -0
  66. package/dist/src/channels/wechat-channel/observer.d.ts +64 -0
  67. package/dist/src/channels/wechat-channel/observer.js +1 -0
  68. package/dist/src/channels/wechat-channel/outbound-ledger.d.ts +69 -0
  69. package/dist/src/channels/wechat-channel/outbound-ledger.js +2 -0
  70. package/dist/src/channels/wechat-channel/outbound-sender.d.ts +26 -0
  71. package/dist/src/channels/wechat-channel/outbound-sender.js +1 -0
  72. package/dist/src/channels/wechat-channel/preflight.d.ts +37 -0
  73. package/dist/src/channels/wechat-channel/preflight.js +1 -0
  74. package/dist/src/channels/wechat-channel/runner.d.ts +34 -0
  75. package/dist/src/channels/wechat-channel/runner.js +1 -0
  76. package/dist/src/channels/wechat-channel/runtime.d.ts +45 -0
  77. package/dist/src/channels/wechat-channel/runtime.js +1 -0
  78. package/dist/src/channels/wechat-channel/scheduler.d.ts +35 -0
  79. package/dist/src/channels/wechat-channel/scheduler.js +1 -0
  80. package/dist/src/channels/wechat-rpa/macos-flow.js +1 -96
  81. package/dist/src/channels/wechat-rpa/macos.js +6 -48
  82. package/dist/src/channels/wechat-rpa/normalizer.js +7 -127
  83. package/dist/src/channels/wechat-rpa.d.ts +21 -0
  84. package/dist/src/channels/wechat-rpa.js +6 -1022
  85. package/dist/src/channels/wecom.js +4 -357
  86. package/dist/src/commands/agent.js +6 -131
  87. package/dist/src/commands/daemon-windows.js +8 -48
  88. package/dist/src/commands/daemon.js +19 -1013
  89. package/dist/src/commands/external-attachments.js +1 -51
  90. package/dist/src/commands/external.js +1 -137
  91. package/dist/src/commands/manager.js +2 -389
  92. package/dist/src/commands/pair-qr.js +1 -6
  93. package/dist/src/commands/pair.js +9 -287
  94. package/dist/src/commands/tools.js +1 -34
  95. package/dist/src/commands/upgrade.js +1 -198
  96. package/dist/src/config/index.js +1 -35
  97. package/dist/src/daemon-log.js +6 -58
  98. package/dist/src/env-path.js +1 -64
  99. package/dist/src/fs/boundary.js +1 -126
  100. package/dist/src/fs/handler.js +1 -130
  101. package/dist/src/fs/security.js +1 -32
  102. package/dist/src/fs/text-decoder.d.ts +10 -0
  103. package/dist/src/fs/text-decoder.js +1 -0
  104. package/dist/src/index.js +2 -404
  105. package/dist/src/log-reporter.js +1 -16
  106. package/dist/src/manager/prompt.js +29 -34
  107. package/dist/src/manager/registry.js +2 -269
  108. package/dist/src/manager/runtime.js +19 -1003
  109. package/dist/src/native-fusion/config.js +1 -5
  110. package/dist/src/native-fusion/opencode-parser.js +3 -123
  111. package/dist/src/native-fusion/parser-common.js +8 -264
  112. package/dist/src/native-fusion/parsers.js +8 -729
  113. package/dist/src/native-fusion/service.d.ts +10 -0
  114. package/dist/src/native-fusion/service.js +2 -198
  115. package/dist/src/native-fusion/state.js +1 -22
  116. package/dist/src/native-fusion/types.js +1 -1
  117. package/dist/src/region.js +1 -88
  118. package/dist/src/relay/client.js +1 -343
  119. package/dist/src/session/archive-zip.js +1 -220
  120. package/dist/src/session/handlers/agent-config.js +1 -150
  121. package/dist/src/session/handlers/agents.js +1 -55
  122. package/dist/src/session/handlers/chat.js +2 -733
  123. package/dist/src/session/handlers/control.js +1 -55
  124. package/dist/src/session/handlers/fs.js +1 -747
  125. package/dist/src/session/handlers/session-refresh.js +1 -35
  126. package/dist/src/session/handlers/skills.js +1 -121
  127. package/dist/src/session/handlers/title.js +1 -60
  128. package/dist/src/session/handlers/tool-detail.d.ts +3 -0
  129. package/dist/src/session/handlers/tool-detail.js +1 -0
  130. package/dist/src/session/manager.d.ts +3 -0
  131. package/dist/src/session/manager.js +1 -261
  132. package/dist/src/session/projection.js +1 -54
  133. package/dist/src/session/queue.js +4 -317
  134. package/dist/src/session/remote-attachments.js +1 -72
  135. package/dist/src/session/store.js +3 -109
  136. package/dist/src/session/types.d.ts +4 -0
  137. package/dist/src/session/types.js +1 -4
  138. package/dist/src/skills/registry.js +15 -148
  139. package/dist/src/skills/setup.js +1 -101
  140. package/dist/src/tools/markdown-to-pdf.js +10 -346
  141. package/dist/src/upgrade/engine.js +3 -347
  142. package/package.json +3 -2
  143. package/dist/scripts/wechat-rpa-download-candidates.mjs +0 -105
@@ -1,96 +1 @@
1
- // @arch docs/features/wechat-rpa-channel.md
2
- // @test src/__tests__/wechat-rpa-normalizer.test.ts
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { execFile } from 'node:child_process';
6
- import { promisify } from 'node:util';
7
- const execFileAsync = promisify(execFile);
8
- export async function runMacWeChatRpaFlow(options) {
9
- if (process.platform !== 'darwin') {
10
- throw new Error('WeChat RPA macOS flow can only run on macOS');
11
- }
12
- const scriptPath = resolveFlowScriptPath(options.scriptPath, options.workDir);
13
- const args = [
14
- scriptPath,
15
- '--group',
16
- options.groupName,
17
- '--idle-seconds',
18
- String(Number.isFinite(options.idleSeconds) ? options.idleSeconds : 15),
19
- ];
20
- if (options.forceForeground)
21
- args.push('--force');
22
- if (options.noRestore)
23
- args.push('--no-restore');
24
- if (options.replyText)
25
- args.push('--reply-text', options.replyText);
26
- if (options.attachmentPath)
27
- args.push('--attachment-path', options.attachmentPath);
28
- if (options.downloadAttachmentsDir)
29
- args.push('--download-attachments-dir', options.downloadAttachmentsDir);
30
- if (Number.isFinite(options.recentLimit) && Number(options.recentLimit) > 0) {
31
- args.push('--recent-limit', String(options.recentLimit));
32
- }
33
- let stdout = '';
34
- let stderr = '';
35
- try {
36
- const result = await execFileAsync(process.execPath, args, {
37
- cwd: options.workDir || process.cwd(),
38
- timeout: options.timeoutMs ?? 120_000,
39
- maxBuffer: 20 * 1024 * 1024,
40
- });
41
- stdout = result.stdout;
42
- stderr = result.stderr;
43
- }
44
- catch (error) {
45
- const execError = error;
46
- stdout = execError.stdout || '';
47
- stderr = execError.stderr || '';
48
- const parsed = parseFlowStdout(stdout);
49
- if (parsed?.interrupted)
50
- return parsed;
51
- if (parsed && hasPartialSendProgress(parsed))
52
- return parsed;
53
- throw new Error(stderr.trim() || stdout.slice(0, 1_000) || execError.message || 'WeChat RPA flow failed');
54
- }
55
- try {
56
- const parsed = JSON.parse(stdout);
57
- if (parsed.interrupted)
58
- return parsed;
59
- if (!parsed.ok && hasSendAttempt(parsed))
60
- return parsed;
61
- if (!parsed.ok)
62
- throw new Error(parsed.error || 'WeChat RPA flow failed');
63
- return parsed;
64
- }
65
- catch (error) {
66
- const detail = stderr.trim() || stdout.slice(0, 1_000);
67
- throw new Error(detail || (error instanceof Error ? error.message : String(error)));
68
- }
69
- }
70
- function parseFlowStdout(stdout) {
71
- try {
72
- return JSON.parse(stdout);
73
- }
74
- catch {
75
- return null;
76
- }
77
- }
78
- function hasPartialSendProgress(result) {
79
- return Boolean(result.sentReplyObserved || result.sentAttachmentObserved);
80
- }
81
- function hasSendAttempt(result) {
82
- return Boolean(result.sentReply || result.sentAttachment || result.sentReplyObserved || result.sentAttachmentObserved);
83
- }
84
- function resolveFlowScriptPath(scriptPath, workDir) {
85
- const candidates = [
86
- scriptPath,
87
- process.env.SHENNIAN_WECHAT_RPA_FLOW_SCRIPT,
88
- workDir ? path.join(workDir, 'scripts/wechat-rpa-flow.mjs') : '',
89
- path.resolve(process.cwd(), 'scripts/wechat-rpa-flow.mjs'),
90
- ].filter(Boolean);
91
- const found = candidates.find((candidate) => fs.existsSync(candidate));
92
- if (!found) {
93
- throw new Error('WeChat RPA flow script is missing; set SHENNIAN_WECHAT_RPA_FLOW_SCRIPT or channel flowScriptPath');
94
- }
95
- return path.resolve(found);
96
- }
1
+ import d from"node:fs";import i from"node:path";import{execFile as h}from"node:child_process";import{promisify as f}from"node:util";const l=f(h);async function R(e){if(process.platform!=="darwin")throw new Error("WeChat RPA macOS flow can only run on macOS");const n=[p(e.scriptPath,e.workDir),"--group",e.groupName,"--idle-seconds",String(Number.isFinite(e.idleSeconds)?e.idleSeconds:15)];e.forceForeground&&n.push("--force"),e.noRestore&&n.push("--no-restore"),e.replyText&&n.push("--reply-text",e.replyText),e.attachmentPath&&n.push("--attachment-path",e.attachmentPath),e.downloadAttachmentsDir&&n.push("--download-attachments-dir",e.downloadAttachmentsDir),Number.isFinite(e.recentLimit)&&Number(e.recentLimit)>0&&n.push("--recent-limit",String(e.recentLimit));let t="",s="";try{const r=await l(process.execPath,n,{cwd:e.workDir||process.cwd(),timeout:e.timeoutMs??12e4,maxBuffer:20971520});t=r.stdout,s=r.stderr}catch(r){const a=r;t=a.stdout||"",s=a.stderr||"";const c=m(t);if(c?.interrupted||c&&u(c))return c;throw new Error(s.trim()||t.slice(0,1e3)||a.message||"WeChat RPA flow failed")}try{const r=JSON.parse(t);if(r.interrupted||!r.ok&&w(r))return r;if(!r.ok)throw new Error(r.error||"WeChat RPA flow failed");return r}catch(r){const a=s.trim()||t.slice(0,1e3);throw new Error(a||(r instanceof Error?r.message:String(r)))}}function m(e){try{return JSON.parse(e)}catch{return null}}function u(e){return!!(e.sentReplyObserved||e.sentAttachmentObserved)}function w(e){return!!(e.sentReply||e.sentAttachment||e.sentReplyObserved||e.sentAttachmentObserved)}function p(e,o){const t=[e,process.env.SHENNIAN_WECHAT_RPA_FLOW_SCRIPT,o?i.join(o,"scripts/wechat-rpa-flow.mjs"):"",i.resolve(process.cwd(),"scripts/wechat-rpa-flow.mjs")].filter(Boolean).find(s=>d.existsSync(s));if(!t)throw new Error("WeChat RPA flow script is missing; set SHENNIAN_WECHAT_RPA_FLOW_SCRIPT or channel flowScriptPath");return i.resolve(t)}export{R as runMacWeChatRpaFlow};
@@ -1,9 +1,4 @@
1
- // @arch docs/features/wechat-rpa-channel.md
2
- // @test src/__tests__/wechat-rpa-normalizer.test.ts
3
- import { execFile } from 'node:child_process';
4
- import { promisify } from 'node:util';
5
- const execFileAsync = promisify(execFile);
6
- const WECHAT_PROBE_SCRIPT = `
1
+ import{execFile as r}from"node:child_process";import{promisify as s}from"node:util";const i=s(r),a=`
7
2
  tell application "System Events"
8
3
  set isRunning to exists process "WeChat"
9
4
  if isRunning is false then
@@ -17,47 +12,10 @@ tell application "System Events"
17
12
  set titleText to name of window 1
18
13
  end try
19
14
  end if
20
- return (isFront as text) & "\n" & titleText
15
+ return (isFront as text) & "
16
+ " & titleText
21
17
  end tell
22
18
  end tell
23
- `;
24
- export async function probeMacWeChat() {
25
- if (process.platform !== 'darwin') {
26
- return { ok: false, platform: process.platform, wechatRunning: false, frontmost: false, message: 'macOS only' };
27
- }
28
- try {
29
- const { stdout } = await execFileAsync('osascript', ['-e', WECHAT_PROBE_SCRIPT], { timeout: 5_000 });
30
- const output = stdout.trim();
31
- if (output === 'not_running') {
32
- return { ok: true, platform: process.platform, wechatRunning: false, frontmost: false };
33
- }
34
- const [frontmostText, ...titleParts] = output.split('\n');
35
- return {
36
- ok: true,
37
- platform: process.platform,
38
- wechatRunning: true,
39
- frontmost: frontmostText === 'true',
40
- windowTitle: titleParts.join('\n').trim() || undefined,
41
- };
42
- }
43
- catch (err) {
44
- return {
45
- ok: false,
46
- platform: process.platform,
47
- wechatRunning: false,
48
- frontmost: false,
49
- message: err instanceof Error ? err.message : String(err),
50
- };
51
- }
52
- }
53
- export function observedMessageFromProbe(result) {
54
- if (!result.ok || !result.wechatRunning || !result.windowTitle)
55
- return null;
56
- return {
57
- conversationName: result.windowTitle,
58
- senderName: 'WeChat RPA',
59
- text: `[微信窗口可见性探测] WeChat ${result.frontmost ? '位于前台' : '未位于前台'},当前窗口:${result.windowTitle}`,
60
- observedAt: new Date().toISOString(),
61
- rawId: `probe:${result.windowTitle}:${result.frontmost}`,
62
- };
63
- }
19
+ `;async function m(){if(process.platform!=="darwin")return{ok:!1,platform:process.platform,wechatRunning:!1,frontmost:!1,message:"macOS only"};try{const{stdout:t}=await i("osascript",["-e",a],{timeout:5e3}),e=t.trim();if(e==="not_running")return{ok:!0,platform:process.platform,wechatRunning:!1,frontmost:!1};const[n,...o]=e.split(`
20
+ `);return{ok:!0,platform:process.platform,wechatRunning:!0,frontmost:n==="true",windowTitle:o.join(`
21
+ `).trim()||void 0}}catch(t){return{ok:!1,platform:process.platform,wechatRunning:!1,frontmost:!1,message:t instanceof Error?t.message:String(t)}}}function c(t){return!t.ok||!t.wechatRunning||!t.windowTitle?null:{conversationName:t.windowTitle,senderName:"WeChat RPA",text:`[\u5FAE\u4FE1\u7A97\u53E3\u53EF\u89C1\u6027\u63A2\u6D4B] WeChat ${t.frontmost?"\u4F4D\u4E8E\u524D\u53F0":"\u672A\u4F4D\u4E8E\u524D\u53F0"}\uFF0C\u5F53\u524D\u7A97\u53E3\uFF1A${t.windowTitle}`,observedAt:new Date().toISOString(),rawId:`probe:${t.windowTitle}:${t.frontmost}`}}export{c as observedMessageFromProbe,m as probeMacWeChat};
@@ -1,127 +1,7 @@
1
- // @arch docs/features/wechat-rpa-channel.md
2
- // @test src/__tests__/wechat-rpa-normalizer.test.ts
3
- import { createHash } from 'node:crypto';
4
- const MAX_DEDUP_KEYS = 500;
5
- export class WeChatRpaDeduper {
6
- seen = new Set();
7
- queue = [];
8
- constructor(initialMessageIds = []) {
9
- for (const id of initialMessageIds) {
10
- if (!id || this.seen.has(id))
11
- continue;
12
- this.seen.add(id);
13
- this.queue.push(id);
14
- }
15
- this.trim();
16
- }
17
- accept(messageId) {
18
- if (this.seen.has(messageId))
19
- return false;
20
- this.seen.add(messageId);
21
- this.queue.push(messageId);
22
- this.trim();
23
- return true;
24
- }
25
- snapshot() {
26
- return [...this.queue];
27
- }
28
- trim() {
29
- while (this.queue.length > MAX_DEDUP_KEYS) {
30
- const old = this.queue.shift();
31
- if (old)
32
- this.seen.delete(old);
33
- }
34
- }
35
- }
36
- export function normalizeWeChatRpaMessage(input, options = {}) {
37
- const conversationName = cleanText(input.conversationName);
38
- const text = cleanText(input.text);
39
- const attachments = normalizeAttachments(input.attachments);
40
- if (!conversationName || (!text && attachments.length === 0))
41
- return null;
42
- const senderName = cleanText(input.senderName || '') || null;
43
- const receivedAt = normalizeIso(input.observedAt);
44
- const conversationId = weChatRpaConversationId(conversationName);
45
- const senderId = stableId('wechat-sender', senderName || 'unknown');
46
- const rawRef = cleanText(input.rawId || '') || null;
47
- const isMentioned = input.isMentioned === true || isMentionedByText(text, options.selfNicknames);
48
- const messageId = rawRef
49
- ? stableId('wechat-message', `${conversationName}\n${rawRef}`)
50
- : stableId('wechat-message', `${conversationName}\n${senderName || ''}\n${text}\n${attachments.map((item) => item.name || item.url || item.type).join('\n')}\n${receivedAt}`);
51
- return {
52
- conversationId,
53
- conversationName,
54
- messageId,
55
- sender: { id: senderId, name: senderName },
56
- text,
57
- attachments,
58
- receivedAt,
59
- isMentioned,
60
- rawRef,
61
- };
62
- }
63
- export function weChatRpaConversationId(conversationName) {
64
- return stableId('wechat-conversation', cleanText(conversationName));
65
- }
66
- function cleanText(value) {
67
- return value.replace(/\s+/g, ' ').trim();
68
- }
69
- function normalizeAttachments(value) {
70
- if (!Array.isArray(value))
71
- return [];
72
- return value
73
- .map((item) => {
74
- const url = item?.url ? cleanText(item.url) : '';
75
- const localPath = item?.localPath ? cleanText(item.localPath) : '';
76
- const availability = normalizeAvailability(item?.availability, { url, localPath });
77
- return {
78
- type: cleanText(String(item?.type || 'file')) || 'file',
79
- ...(item?.name ? { name: cleanText(item.name) } : {}),
80
- ...(url ? { url } : {}),
81
- ...(item?.mimeType ? { mimeType: cleanText(item.mimeType) } : {}),
82
- ...(Number.isFinite(item?.size) && Number(item.size) > 0 ? { size: Number(item.size) } : {}),
83
- ...(localPath ? { localPath } : {}),
84
- ...(item?.thumbnailPath ? { thumbnailPath: cleanText(item.thumbnailPath) } : {}),
85
- ...(item?.hash ? { hash: cleanText(item.hash) } : {}),
86
- ...(availability ? { availability } : {}),
87
- ...(item?.machineId ? { machineId: cleanText(item.machineId) } : {}),
88
- ...(item?.expiresAt ? { expiresAt: cleanText(item.expiresAt) } : {}),
89
- ...(item?.providerError ? { providerError: cleanText(item.providerError) } : {}),
90
- };
91
- })
92
- .filter((item) => item.type);
93
- }
94
- function normalizeAvailability(value, sources) {
95
- if (value === 'edge-local'
96
- || value === 'server-url'
97
- || value === 'pending-download'
98
- || value === 'metadata-only'
99
- || value === 'unavailable-large') {
100
- return value;
101
- }
102
- if (sources.localPath)
103
- return 'edge-local';
104
- if (sources.url)
105
- return 'server-url';
106
- return 'metadata-only';
107
- }
108
- function normalizeIso(value) {
109
- if (!value)
110
- return new Date().toISOString();
111
- const date = new Date(value);
112
- return Number.isNaN(date.getTime()) ? new Date().toISOString() : date.toISOString();
113
- }
114
- function stableId(prefix, value) {
115
- return `${prefix}:${createHash('sha256').update(value).digest('hex').slice(0, 24)}`;
116
- }
117
- function isMentionedByText(text, selfNicknames) {
118
- const aliases = Array.isArray(selfNicknames)
119
- ? selfNicknames.map((item) => cleanText(item)).filter(Boolean)
120
- : [];
121
- if (!aliases.length)
122
- return false;
123
- return aliases.some((alias) => {
124
- const escaped = alias.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
125
- return new RegExp(`@\\s*${escaped}(?=$|\\s|[,。!?,.!?::;;、)])`).test(text);
126
- });
127
- }
1
+ import{createHash as m}from"node:crypto";const g=500;class I{seen=new Set;queue=[];constructor(e=[]){for(const t of e)!t||this.seen.has(t)||(this.seen.add(t),this.queue.push(t));this.trim()}accept(e){return this.seen.has(e)?!1:(this.seen.add(e),this.queue.push(e),this.trim(),!0)}snapshot(){return[...this.queue]}trim(){for(;this.queue.length>g;){const e=this.queue.shift();e&&this.seen.delete(e)}}}function N(n,e={}){const t=r(n.conversationName),a=r(n.text),s=w(n.attachments);if(!t||!a&&s.length===0)return null;const i=r(n.senderName||"")||null,h=$(n.observedAt),u=y(t),d=o("wechat-sender",i||"unknown"),c=r(n.rawId||"")||null,f=n.isMentioned===!0||x(a,e.selfNicknames),p=c?o("wechat-message",`${t}
2
+ ${c}`):o("wechat-message",`${t}
3
+ ${i||""}
4
+ ${a}
5
+ ${s.map(l=>l.name||l.url||l.type).join(`
6
+ `)}
7
+ ${h}`);return{conversationId:u,conversationName:t,messageId:p,sender:{id:d,name:i},text:a,attachments:s,receivedAt:h,isMentioned:f,rawRef:c}}function y(n){return o("wechat-conversation",r(n))}function r(n){return n.replace(/\s+/g," ").trim()}function w(n){return Array.isArray(n)?n.map(e=>{const t=e?.url?r(e.url):"",a=e?.localPath?r(e.localPath):"",s=b(e?.availability,{url:t,localPath:a});return{type:r(String(e?.type||"file"))||"file",...e?.name?{name:r(e.name)}:{},...t?{url:t}:{},...e?.mimeType?{mimeType:r(e.mimeType)}:{},...Number.isFinite(e?.size)&&Number(e.size)>0?{size:Number(e.size)}:{},...a?{localPath:a}:{},...e?.thumbnailPath?{thumbnailPath:r(e.thumbnailPath)}:{},...e?.hash?{hash:r(e.hash)}:{},...s?{availability:s}:{},...e?.machineId?{machineId:r(e.machineId)}:{},...e?.expiresAt?{expiresAt:r(e.expiresAt)}:{},...e?.providerError?{providerError:r(e.providerError)}:{}}}).filter(e=>e.type):[]}function b(n,e){return n==="edge-local"||n==="server-url"||n==="pending-download"||n==="metadata-only"||n==="unavailable-large"?n:e.localPath?"edge-local":e.url?"server-url":"metadata-only"}function $(n){if(!n)return new Date().toISOString();const e=new Date(n);return Number.isNaN(e.getTime())?new Date().toISOString():e.toISOString()}function o(n,e){return`${n}:${m("sha256").update(e).digest("hex").slice(0,24)}`}function x(n,e){const t=Array.isArray(e)?e.map(a=>r(a)).filter(Boolean):[];return t.length?t.some(a=>{const s=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`@\\s*${s}(?=$|\\s|[\uFF0C\u3002\uFF01\uFF1F,.!?:\uFF1A\uFF1B;\u3001)])`).test(n)}):!1}export{I as WeChatRpaDeduper,N as normalizeWeChatRpaMessage,y as weChatRpaConversationId};
@@ -1,5 +1,25 @@
1
1
  import type { ExternalChannelAdapter, ExternalChannelConfig, ExternalChannelRuntimeStatus, ExternalChannelSendResult, ExternalMessageEvent, ExternalReply } from './base.js';
2
2
  import { type WeChatRpaObservedMessage } from './wechat-rpa/normalizer.js';
3
+ type WeChatRpaSecret = {
4
+ type: 'wechat-rpa';
5
+ source?: 'macos-probe' | 'macos-flow' | 'windows-visual-flow' | 'wechat-rpa-lab' | 'fixture-jsonl';
6
+ fixturePath?: string;
7
+ pollIntervalMs?: number;
8
+ groups?: Array<{
9
+ name: string;
10
+ }>;
11
+ forceForeground?: boolean;
12
+ noRestore?: boolean;
13
+ downloadAttachments?: boolean;
14
+ downloadAttachmentsDir?: string;
15
+ idleSeconds?: number;
16
+ recentLimit?: number;
17
+ selfNickname?: string;
18
+ flowScriptPath?: string;
19
+ canReply?: boolean;
20
+ systemPrompt?: string;
21
+ updatedAt: string;
22
+ };
3
23
  export declare function selectWeChatRpaLabReadKind(recentLimit?: number | null): 'read-latest' | 'scroll-read';
4
24
  type WeChatRpaEvent = ExternalMessageEvent & {
5
25
  type: 'external.message';
@@ -51,5 +71,6 @@ export declare function planWeChatRpaLabSendTasks(input: {
51
71
  }): Array<Record<string, unknown>>;
52
72
  export declare function weChatRpaLabTaskKindForAttachment(filePath: string): 'send-image' | 'send-video' | 'send-file';
53
73
  export declare function materializeWeChatRpaOutboundAttachment(workDir: string, attachment: NonNullable<ExternalReply['attachment']>): Promise<string>;
74
+ export declare function resolveWeChatRpaInboundAttachmentDir(config: Pick<ExternalChannelConfig, 'id'>, secret: Pick<WeChatRpaSecret, 'downloadAttachments' | 'downloadAttachmentsDir'>): string | undefined;
54
75
  export declare function annotateWeChatRpaInboundAttachments(attachments: WeChatRpaObservedMessage['attachments']): WeChatRpaObservedMessage['attachments'];
55
76
  export {};