@sleep2agi/agent-network 2.3.0-preview.16 → 2.3.0-preview.18
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.
- package/dist/bin/cli.js +1 -1
- package/dist/bin/goal-wake-log-render.d.ts +31 -0
- package/dist/src/client.js +1 -1
- package/dist/src/environ-alias.d.ts +14 -0
- package/dist/src/im/feishu/adapter.d.ts +11 -0
- package/dist/src/im/feishu/outbound-route.d.ts +62 -0
- package/dist/src/im/feishu/worker.js +136 -122
- package/dist/src/node-server.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface WakeLogEntryShape {
|
|
2
|
+
ts?: string;
|
|
3
|
+
status?: string;
|
|
4
|
+
summary?: string;
|
|
5
|
+
task_id?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface WakeLogGoalShape {
|
|
8
|
+
goal_id: string;
|
|
9
|
+
progress_log?: WakeLogEntryShape[];
|
|
10
|
+
}
|
|
11
|
+
export interface WakeLogRenderOpts {
|
|
12
|
+
/** Trim to the last N entries. undefined = all. */
|
|
13
|
+
tail?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Format progress_log as a JSON object suitable for `--json` output.
|
|
17
|
+
* Pure. Never reads/writes filesystem. Legacy goals without
|
|
18
|
+
* progress_log render as empty array (not error).
|
|
19
|
+
*/
|
|
20
|
+
export declare function renderWakeLogJson(goal: WakeLogGoalShape, opts?: WakeLogRenderOpts): {
|
|
21
|
+
goal_id: string;
|
|
22
|
+
total: number;
|
|
23
|
+
returned: number;
|
|
24
|
+
entries: WakeLogEntryShape[];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Format progress_log as a table for human console output.
|
|
28
|
+
* Column layout mirrors printGoalShow so the two commands read
|
|
29
|
+
* consistently. Empty log renders a single "(none)" line, not an error.
|
|
30
|
+
*/
|
|
31
|
+
export declare function renderWakeLogText(goal: WakeLogGoalShape, opts?: WakeLogRenderOpts): string;
|
package/dist/src/client.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function a0_0x4c0c(_0x3fd69e,_0x53a316){_0x3fd69e=_0x3fd69e-0x116;const _0x58dac8=a0_0x58da();let _0x4c0cc1=_0x58dac8[_0x3fd69e];return _0x4c0cc1;}const a0_0x2657ce=a0_0x4c0c;(function(_0x19d1c7,_0x282ba7){const _0x363cea=a0_0x4c0c,_0x9a75bb=_0x19d1c7();while(!![]){try{const _0x5ad9fe=parseInt(_0x363cea(0x15e))/0x1+-parseInt(_0x363cea(0x138))/0x2+parseInt(_0x363cea(0x127))/0x3*(parseInt(_0x363cea(0x16b))/0x4)+-parseInt(_0x363cea(0x14f))/0x5+parseInt(_0x363cea(0x154))/0x6+parseInt(_0x363cea(0x152))/0x7*(parseInt(_0x363cea(0x11e))/0x8)+-parseInt(_0x363cea(0x11f))/0x9;if(_0x5ad9fe===_0x282ba7)break;else _0x9a75bb['push'](_0x9a75bb['shift']());}catch(_0x49a933){_0x9a75bb['push'](_0x9a75bb['shift']());}}}(a0_0x58da,0xd1c7d));function a0_0x58da(){const _0x1c5aa2=['sdk-','status','sseAbort','send_reply','AbortError','POST','content','368RnfkKB','send','send_task','2.0','text/event-stream','connected','registered','Authorization','slice','log','ack_inbox','/mcp','1736LUPtfb','29301174rxFoSZ','name','normal','idle','getReader','reconnectDelay','get_inbox','connectSSE','35292Rpymsd','get_all_status','report_status','autoConnect','message','new_message','split','pop','server','heartbeat\x20failed:\x20','heartbeatInterval','application/json','text','send_message','running','alias','from_session','219474tDpqJS','resumeId','cwd','completed','Bearer\x20','emit','type','toTimeString','disconnect','call','processInbox','heartbeatTimer','s...','read','connect','agent','getAllStatus','messages','url','sleep','disconnected','offline','min','309165ahOefj','data:\x20','result','29351nSnbMU','now','10112322reDtlD','token','body','parse','broadcast','new_task','SSE\x20failed:\x20','signal','match','tools/call','608961IMqZXG','abort','reply','SSE\x20connected','inbox\x20error:\x20','catch'];a0_0x58da=function(){return _0x1c5aa2;};return a0_0x58da();}import{EventEmitter as a0_0x377cd4}from'events';import{hostname as a0_0x4d5960}from'os';class T extends a0_0x377cd4{[a0_0x2657ce(0x14a)];[a0_0x2657ce(0x136)];[a0_0x2657ce(0x155)];[a0_0x2657ce(0x147)];[a0_0x2657ce(0x139)];[a0_0x2657ce(0x131)];[a0_0x2657ce(0x124)];[a0_0x2657ce(0x143)];['sseAbort'];[a0_0x2657ce(0x135)]=!0x1;constructor(_0x4a4592){const _0x22fa9b=a0_0x2657ce;super();if(this[_0x22fa9b(0x14a)]=_0x4a4592[_0x22fa9b(0x14a)]['replace'](/\/$/,''),this[_0x22fa9b(0x136)]=_0x4a4592[_0x22fa9b(0x136)],this[_0x22fa9b(0x155)]=_0x4a4592[_0x22fa9b(0x155)],this[_0x22fa9b(0x147)]=_0x4a4592[_0x22fa9b(0x147)]||'sdk',this['resumeId']=_0x22fa9b(0x164)+_0x4a4592[_0x22fa9b(0x136)]+'-'+Date['now']()['toString'](0x24),this[_0x22fa9b(0x131)]=_0x4a4592[_0x22fa9b(0x131)]??0x2bf20,this[_0x22fa9b(0x124)]=_0x4a4592[_0x22fa9b(0x124)]??0xbb8,_0x4a4592[_0x22fa9b(0x12a)]!==!0x1)this[_0x22fa9b(0x146)]();}[a0_0x2657ce(0x11b)](_0x3e98d2){const _0x6bb20e=a0_0x2657ce;console['log']('['+new Date()[_0x6bb20e(0x13f)]()['slice'](0x0,0x8)+']\x20[commhub:'+this[_0x6bb20e(0x136)]+']\x20'+_0x3e98d2);}async['call'](_0x47ca4d,_0x51caa2){const _0x4efd73=a0_0x2657ce;let _0x30c7ed={'Content-Type':_0x4efd73(0x132),'Accept':'application/json,\x20text/event-stream'};if(this['token'])_0x30c7ed['Authorization']='Bearer\x20'+this[_0x4efd73(0x155)];let _0x3a92a4=await(await fetch(this[_0x4efd73(0x14a)]+_0x4efd73(0x11d),{'method':_0x4efd73(0x169),'headers':_0x30c7ed,'body':JSON['stringify']({'jsonrpc':_0x4efd73(0x16e),'id':Date[_0x4efd73(0x153)](),'method':_0x4efd73(0x15d),'params':{'name':_0x47ca4d,'arguments':_0x51caa2}})}))[_0x4efd73(0x133)](),_0x36e225=_0x3a92a4[_0x4efd73(0x15c)](/data: (.+)/),_0x15c4cb=_0x36e225?JSON[_0x4efd73(0x157)](_0x36e225[0x1]):JSON[_0x4efd73(0x157)](_0x3a92a4),_0x42f66d=_0x15c4cb?.[_0x4efd73(0x151)]?.[_0x4efd73(0x16a)]?.[0x0]?.[_0x4efd73(0x133)];return _0x42f66d?JSON['parse'](_0x42f66d):_0x15c4cb;}async[a0_0x2657ce(0x146)](){const _0x437cba=a0_0x2657ce;if(this['running'])return;this[_0x437cba(0x135)]=!0x0,await this[_0x437cba(0x165)](_0x437cba(0x122)),this['log'](_0x437cba(0x118)),this[_0x437cba(0x143)]=setInterval(()=>{const _0x5c5c1c=_0x437cba;this[_0x5c5c1c(0x165)](_0x5c5c1c(0x122))[_0x5c5c1c(0x163)](_0x1ad2bf=>this[_0x5c5c1c(0x11b)](_0x5c5c1c(0x130)+_0x1ad2bf[_0x5c5c1c(0x12b)]));},this['heartbeatInterval']),this[_0x437cba(0x126)]();}async[a0_0x2657ce(0x140)](){const _0x44edd9=a0_0x2657ce;if(this[_0x44edd9(0x135)]=!0x1,this['sseAbort']?.[_0x44edd9(0x15f)](),this[_0x44edd9(0x143)])clearInterval(this[_0x44edd9(0x143)]);await this[_0x44edd9(0x165)](_0x44edd9(0x14d))['catch'](()=>{}),this[_0x44edd9(0x11b)](_0x44edd9(0x14c));}async[a0_0x2657ce(0x16c)](_0x8b1486,_0x24d241,_0x395ae5=a0_0x2657ce(0x121)){const _0x4c6145=a0_0x2657ce;return this['call'](_0x4c6145(0x16d),{'alias':_0x8b1486,'task':_0x24d241,'priority':_0x395ae5,'from_session':this[_0x4c6145(0x136)]});}async[a0_0x2657ce(0x12b)](_0x198bc6,_0x475701){const _0x2f95a8=a0_0x2657ce;return this[_0x2f95a8(0x141)](_0x2f95a8(0x134),{'alias':_0x198bc6,'message':_0x475701,'from_session':this[_0x2f95a8(0x136)]});}async[a0_0x2657ce(0x160)](_0x312da0,_0x5b6834,_0x5d9264=a0_0x2657ce(0x13b)){const _0x8241e2=a0_0x2657ce;return this[_0x8241e2(0x141)](_0x8241e2(0x167),{'in_reply_to':_0x312da0,'text':_0x5b6834,'status':_0x5d9264});}async['status'](_0x264d16,_0x2b7dcf){const _0x9fe182=a0_0x2657ce;return this['call'](_0x9fe182(0x129),{'resume_id':this[_0x9fe182(0x139)],'alias':this[_0x9fe182(0x136)],'status':_0x264d16,'server':a0_0x4d5960(),'hostname':a0_0x4d5960(),'agent':this[_0x9fe182(0x147)],'project_dir':process[_0x9fe182(0x13a)](),..._0x2b7dcf});}async[a0_0x2657ce(0x148)](){const _0x28039c=a0_0x2657ce;return this[_0x28039c(0x141)](_0x28039c(0x128),{});}async['broadcast'](_0x26cd49,_0x504c1a){const _0x2ec300=a0_0x2657ce;return this[_0x2ec300(0x141)]('broadcast',{'message':_0x26cd49,'filter_server':_0x504c1a?.[_0x2ec300(0x12f)],'filter_status':_0x504c1a?.['status']});}async['connectSSE'](){const _0x5c5250=a0_0x2657ce;let _0x94b820=encodeURIComponent(this[_0x5c5250(0x136)]),_0x19955d=this[_0x5c5250(0x14a)]+'/events/'+_0x94b820,_0x4b99ab=this[_0x5c5250(0x124)];while(this[_0x5c5250(0x135)]){try{this['sseAbort']=new AbortController();let _0x5d57d3={'Accept':_0x5c5250(0x116)};if(this['token'])_0x5d57d3[_0x5c5250(0x119)]=_0x5c5250(0x13c)+this[_0x5c5250(0x155)];let _0x28e212=await fetch(_0x19955d,{'headers':_0x5d57d3,'signal':this[_0x5c5250(0x166)][_0x5c5250(0x15b)]});if(!_0x28e212['ok']||!_0x28e212[_0x5c5250(0x156)]){this['log'](_0x5c5250(0x15a)+_0x28e212[_0x5c5250(0x165)]),await this[_0x5c5250(0x14b)](_0x4b99ab),_0x4b99ab=Math[_0x5c5250(0x14e)](_0x4b99ab*1.5,0xea60);continue;}_0x4b99ab=this['reconnectDelay'];let _0x4d3ab3=_0x28e212['body'][_0x5c5250(0x123)](),_0x3e6139=new TextDecoder(),_0x130a3f='';while(this['running']){let {done:_0x59c671,value:_0x1d29d1}=await _0x4d3ab3[_0x5c5250(0x145)]();if(_0x59c671)break;_0x130a3f+=_0x3e6139['decode'](_0x1d29d1,{'stream':!0x0});let _0x52bcd1=_0x130a3f[_0x5c5250(0x12d)]('\x0a');_0x130a3f=_0x52bcd1[_0x5c5250(0x12e)]()||'';for(let _0x167a31 of _0x52bcd1){if(!_0x167a31['startsWith'](_0x5c5250(0x150)))continue;try{let _0x1a5a16=JSON[_0x5c5250(0x157)](_0x167a31[_0x5c5250(0x11a)](0x6));if(_0x1a5a16[_0x5c5250(0x13e)]===_0x5c5250(0x117)){this[_0x5c5250(0x11b)](_0x5c5250(0x161)),this['emit'](_0x5c5250(0x117));continue;}if(_0x1a5a16['type']===_0x5c5250(0x159)||_0x1a5a16['type']===_0x5c5250(0x12c)||_0x1a5a16[_0x5c5250(0x13e)]===_0x5c5250(0x158))await this[_0x5c5250(0x142)]();}catch{}}}}catch(_0x42b950){if(_0x42b950[_0x5c5250(0x120)]===_0x5c5250(0x168))break;this[_0x5c5250(0x13d)]('error',_0x42b950),this[_0x5c5250(0x11b)]('SSE\x20error:\x20'+_0x42b950[_0x5c5250(0x12b)]);}if(this['running'])this[_0x5c5250(0x13d)](_0x5c5250(0x14c)),this[_0x5c5250(0x11b)]('SSE\x20reconnecting\x20in\x20'+_0x4b99ab/0x3e8+_0x5c5250(0x144)),await this['sleep'](_0x4b99ab),_0x4b99ab=Math[_0x5c5250(0x14e)](_0x4b99ab*1.5,0xea60);}}async[a0_0x2657ce(0x142)](){const _0x49e01f=a0_0x2657ce;try{let _0x58195a=(await this[_0x49e01f(0x141)](_0x49e01f(0x125),{'alias':this[_0x49e01f(0x136)],'limit':0xa}))?.[_0x49e01f(0x149)]||[];for(let _0x50eff7 of _0x58195a)await this[_0x49e01f(0x141)](_0x49e01f(0x11c),{'alias':this[_0x49e01f(0x136)],'message_id':_0x50eff7['id']}),this[_0x49e01f(0x11b)]('←\x20'+_0x50eff7[_0x49e01f(0x137)]+':\x20'+_0x50eff7[_0x49e01f(0x16a)][_0x49e01f(0x11a)](0x0,0x3c)),this[_0x49e01f(0x13d)]('task',_0x50eff7),this[_0x49e01f(0x13d)](_0x49e01f(0x12b),_0x50eff7);}catch(_0xfefe66){this[_0x49e01f(0x11b)](_0x49e01f(0x162)+_0xfefe66[_0x49e01f(0x12b)]);}}['sleep'](_0x1f723a){return new Promise(_0x4625fc=>setTimeout(_0x4625fc,_0x1f723a));}}var $=T;export{$ as default,T as CommHub};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Parse the environ blob (NUL-separated key=val) and return the
|
|
2
|
+
* COMMHUB_ALIAS value if present, else null. Exported for testing. */
|
|
3
|
+
export declare function parseEnvironAlias(environBlob: string): string | null;
|
|
4
|
+
/** Read /proc/<pid>/environ and return the COMMHUB_ALIAS value.
|
|
5
|
+
* Any file-read error (not-a-Linux, permission denied, race with
|
|
6
|
+
* process exit) returns null — caller must not fail-closed on that
|
|
7
|
+
* (the process is stale/gone/inaccessible, not our problem). */
|
|
8
|
+
export declare function readEnvironAlias(pid: number): string | null;
|
|
9
|
+
/** Scan /proc for pids whose COMMHUB_ALIAS env matches any of the
|
|
10
|
+
* target aliases. Linux-only (procfs); returns null on non-Linux or
|
|
11
|
+
* when /proc is unreadable — caller MUST fail-closed on null per
|
|
12
|
+
* the same #180 R2 fail-closed contract as findNodeProcessesByAlias.
|
|
13
|
+
* Self-pid + init (PID 1) are excluded. */
|
|
14
|
+
export declare function findEnvironAliasMatches(aliases: Iterable<string>, selfPid: number): number[] | null;
|
|
@@ -94,6 +94,17 @@ export declare function parsePostContent(rawJson: string): string;
|
|
|
94
94
|
* @internal exported for unit tests.
|
|
95
95
|
*/
|
|
96
96
|
export declare function extractPostImageKeys(rawJson: string): string[];
|
|
97
|
+
/**
|
|
98
|
+
* Sanitize a Feishu-supplied `file_name` so it's safe to append to a
|
|
99
|
+
* filesystem path. Strips `/`, `\`, `..`, control characters, and NUL
|
|
100
|
+
* bytes. Empty / all-stripped input falls back to a placeholder that
|
|
101
|
+
* uses the message id, so a hostile client can never write outside the
|
|
102
|
+
* conversation's `<mediaDir>/<convKey>/` directory.
|
|
103
|
+
*
|
|
104
|
+
* NOT a full display-safety pass — the LLM still sees the sanitized
|
|
105
|
+
* bytes and shouldn't render them as HTML/etc. That's a Layer above.
|
|
106
|
+
*/
|
|
107
|
+
export declare function sanitizeFileName(raw: string, fallback: string): string;
|
|
97
108
|
/**
|
|
98
109
|
* Feishu text-message practical chunk threshold (RFC-020 §16).
|
|
99
110
|
*
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC-020 §16.1 — feishu outbound route decision (pure helper).
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for the `adapter.send` decision tree that
|
|
5
|
+
* picks among text / interactive card / image (rendered PNG) / file /
|
|
6
|
+
* imagePath outputs. Extracted into a pure module so the production
|
|
7
|
+
* call site AND the unit tests can bind the same function — previously
|
|
8
|
+
* the test mirrored the decision tree in a sibling `pickRoute` helper,
|
|
9
|
+
* which would drift silently if the production tree changed.
|
|
10
|
+
*
|
|
11
|
+
* Inputs are the minimal data the decision needs:
|
|
12
|
+
*
|
|
13
|
+
* - `text` / `imagePath` / `files` — payload from `NormalizedIMMessage`
|
|
14
|
+
* - `forceTextOnly` — caption-mode hint (RFC-020 §15.2)
|
|
15
|
+
* - `mode` — channel-config `outboundRender` (`"plain"` / `"card"` /
|
|
16
|
+
* `"auto"`, RFC-020 §16)
|
|
17
|
+
*
|
|
18
|
+
* Outputs the chosen `route` plus a short `reason` string for log /
|
|
19
|
+
* debug. The CALLER (adapter.send) actually performs the upload /
|
|
20
|
+
* render side-effects keyed on the route — this function does no I/O.
|
|
21
|
+
*
|
|
22
|
+
* Behavior contract (mirrors adapter.send line-for-line, locked by
|
|
23
|
+
* `feishu-outbound-render-mode.test.ts`):
|
|
24
|
+
*
|
|
25
|
+
* 1. `imagePath` set → `image_upload`
|
|
26
|
+
* 2. `files[0].path` set → `file_upload`
|
|
27
|
+
* 3. `forceTextOnly` true → `text`
|
|
28
|
+
* 4. mode "plain" → `text` (always)
|
|
29
|
+
* 5. mode "card" → `card_short_md` iff `looksLikeMarkdown(text)` AND
|
|
30
|
+
* NOT `shouldRenderAsImage(text)`; else `text`
|
|
31
|
+
* 6. mode "auto" → `image_render` iff `shouldRenderAsImage(text)`;
|
|
32
|
+
* else `card_short_md` iff `looksLikeMarkdown(text)`; else `text`
|
|
33
|
+
* 7. unknown mode (defensive default-default) → `text`
|
|
34
|
+
*
|
|
35
|
+
* The production switch in adapter.send may add the actual upload /
|
|
36
|
+
* render / lark API calls keyed on the route, but the route itself
|
|
37
|
+
* is decided HERE. To change the decision, change this file.
|
|
38
|
+
*/
|
|
39
|
+
export type OutboundRoute = "image_upload" | "file_upload" | "text" | "card_short_md" | "image_render";
|
|
40
|
+
export interface RouteInput {
|
|
41
|
+
text?: string;
|
|
42
|
+
imagePath?: string;
|
|
43
|
+
files?: {
|
|
44
|
+
name: string;
|
|
45
|
+
path?: string;
|
|
46
|
+
}[];
|
|
47
|
+
forceTextOnly?: boolean;
|
|
48
|
+
/** `outboundRender` from the channel config. Defaults to "plain" when
|
|
49
|
+
* absent so a caller that doesn't read the config still gets the
|
|
50
|
+
* "Vincent default" behavior. */
|
|
51
|
+
mode?: "plain" | "card" | "auto";
|
|
52
|
+
}
|
|
53
|
+
export interface RouteDecision {
|
|
54
|
+
route: OutboundRoute;
|
|
55
|
+
reason: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Decide the outbound route for a `NormalizedIMMessage` (or a subset
|
|
59
|
+
* of its fields). Pure — no I/O, no SDK calls; safe to call from tests
|
|
60
|
+
* directly.
|
|
61
|
+
*/
|
|
62
|
+
export declare function resolveOutboundRoute(input: RouteInput): RouteDecision;
|