shennian 0.4.60 → 0.4.62
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/publish-build-manifest.json +56 -31
- package/dist/src/agents/acp/manifests.d.ts +4 -4
- package/dist/src/agents/codex-managed-room-tools.d.ts +1 -1
- package/dist/src/agents/codex-managed-room-tools.js +1 -1
- package/dist/src/agents/pi-managed-extension.js +1 -1
- package/dist/src/commands/room.js +2 -2
- package/dist/src/commands/schedule.d.ts +2 -0
- package/dist/src/commands/schedule.js +2 -0
- package/dist/src/index.js +3 -3
- package/dist/src/manager/runtime.d.ts +1 -0
- package/dist/src/manager/runtime.js +4 -4
- package/dist/src/room/managed-prompt-composer.js +7 -7
- package/dist/src/room/managed-room-ipc.d.ts +3 -0
- package/dist/src/room/managed-room-ipc.js +2 -2
- package/dist/src/room/room-action-client-types.d.ts +1 -0
- package/dist/src/room/room-action-client.d.ts +4 -1
- package/dist/src/room/room-action-client.js +1 -1
- package/dist/src/schedules/personal-context.d.ts +3 -0
- package/dist/src/schedules/personal-context.js +1 -0
- package/dist/src/schedules/server-client.d.ts +19 -0
- package/dist/src/schedules/server-client.js +1 -0
- package/dist/src/session/handlers/chat-adapter-config.js +1 -1
- package/dist/src/session/handlers/chat-recovery.js +1 -1
- package/dist/src/session/handlers/chat.d.ts +9 -1
- package/dist/src/session/handlers/chat.js +3 -1
- package/dist/src/session/manager.d.ts +3 -1
- package/dist/src/session/manager.js +2 -2
- package/dist/src/session/queue-helpers.js +1 -1
- package/dist/src/session/queue-message.d.ts +30 -0
- package/dist/src/session/queue-message.js +1 -0
- package/dist/src/session/queue-types.d.ts +20 -0
- package/dist/src/session/queue-types.js +1 -0
- package/dist/src/session/queue.d.ts +13 -32
- package/dist/src/session/queue.js +1 -1
- package/dist/src/session/queued-chat-dispatch.d.ts +1 -0
- package/dist/src/session/queued-chat-dispatch.js +1 -1
- package/dist/src/session/turn-trigger.d.ts +5 -0
- package/node_modules/@shennian/wire/dist/index.d.ts +1 -0
- package/node_modules/@shennian/wire/dist/index.js +1 -0
- package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
- package/node_modules/@shennian/wire/dist/schedule.d.ts +37 -0
- package/node_modules/@shennian/wire/dist/schedule.js +1 -0
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"jsMinified": true,
|
|
4
4
|
"minifier": "esbuild",
|
|
5
|
-
"fileCount":
|
|
5
|
+
"fileCount": 206,
|
|
6
6
|
"files": [
|
|
7
7
|
{
|
|
8
8
|
"file": "bin/shennian.js",
|
|
@@ -111,8 +111,8 @@
|
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
"file": "src/agents/codex-managed-room-tools.js",
|
|
114
|
-
"beforeBytes":
|
|
115
|
-
"afterBytes":
|
|
114
|
+
"beforeBytes": 15680,
|
|
115
|
+
"afterBytes": 9844
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
118
|
"file": "src/agents/codex-utils.js",
|
|
@@ -246,8 +246,8 @@
|
|
|
246
246
|
},
|
|
247
247
|
{
|
|
248
248
|
"file": "src/agents/pi-managed-extension.js",
|
|
249
|
-
"beforeBytes":
|
|
250
|
-
"afterBytes":
|
|
249
|
+
"beforeBytes": 10227,
|
|
250
|
+
"afterBytes": 9273
|
|
251
251
|
},
|
|
252
252
|
{
|
|
253
253
|
"file": "src/agents/pi-managed-model-broker.js",
|
|
@@ -351,14 +351,19 @@
|
|
|
351
351
|
},
|
|
352
352
|
{
|
|
353
353
|
"file": "src/commands/room.js",
|
|
354
|
-
"beforeBytes":
|
|
355
|
-
"afterBytes":
|
|
354
|
+
"beforeBytes": 18424,
|
|
355
|
+
"afterBytes": 10626
|
|
356
356
|
},
|
|
357
357
|
{
|
|
358
358
|
"file": "src/commands/runtime.js",
|
|
359
359
|
"beforeBytes": 5624,
|
|
360
360
|
"afterBytes": 3146
|
|
361
361
|
},
|
|
362
|
+
{
|
|
363
|
+
"file": "src/commands/schedule.js",
|
|
364
|
+
"beforeBytes": 1288,
|
|
365
|
+
"afterBytes": 936
|
|
366
|
+
},
|
|
362
367
|
{
|
|
363
368
|
"file": "src/commands/tools.js",
|
|
364
369
|
"beforeBytes": 1572,
|
|
@@ -441,8 +446,8 @@
|
|
|
441
446
|
},
|
|
442
447
|
{
|
|
443
448
|
"file": "src/index.js",
|
|
444
|
-
"beforeBytes":
|
|
445
|
-
"afterBytes":
|
|
449
|
+
"beforeBytes": 38639,
|
|
450
|
+
"afterBytes": 19406
|
|
446
451
|
},
|
|
447
452
|
{
|
|
448
453
|
"file": "src/log-redaction.js",
|
|
@@ -471,8 +476,8 @@
|
|
|
471
476
|
},
|
|
472
477
|
{
|
|
473
478
|
"file": "src/manager/runtime.js",
|
|
474
|
-
"beforeBytes":
|
|
475
|
-
"afterBytes":
|
|
479
|
+
"beforeBytes": 28698,
|
|
480
|
+
"afterBytes": 14642
|
|
476
481
|
},
|
|
477
482
|
{
|
|
478
483
|
"file": "src/manager/worker-ipc.js",
|
|
@@ -646,8 +651,8 @@
|
|
|
646
651
|
},
|
|
647
652
|
{
|
|
648
653
|
"file": "src/room/managed-prompt-composer.js",
|
|
649
|
-
"beforeBytes":
|
|
650
|
-
"afterBytes":
|
|
654
|
+
"beforeBytes": 10441,
|
|
655
|
+
"afterBytes": 11173
|
|
651
656
|
},
|
|
652
657
|
{
|
|
653
658
|
"file": "src/room/managed-room-binding.js",
|
|
@@ -656,8 +661,8 @@
|
|
|
656
661
|
},
|
|
657
662
|
{
|
|
658
663
|
"file": "src/room/managed-room-ipc.js",
|
|
659
|
-
"beforeBytes":
|
|
660
|
-
"afterBytes":
|
|
664
|
+
"beforeBytes": 14052,
|
|
665
|
+
"afterBytes": 6859
|
|
661
666
|
},
|
|
662
667
|
{
|
|
663
668
|
"file": "src/room/mirror-sync-service.js",
|
|
@@ -686,8 +691,8 @@
|
|
|
686
691
|
},
|
|
687
692
|
{
|
|
688
693
|
"file": "src/room/room-action-client.js",
|
|
689
|
-
"beforeBytes":
|
|
690
|
-
"afterBytes":
|
|
694
|
+
"beforeBytes": 29197,
|
|
695
|
+
"afterBytes": 14837
|
|
691
696
|
},
|
|
692
697
|
{
|
|
693
698
|
"file": "src/room/room-binding-client.js",
|
|
@@ -699,6 +704,16 @@
|
|
|
699
704
|
"beforeBytes": 30575,
|
|
700
705
|
"afterBytes": 17164
|
|
701
706
|
},
|
|
707
|
+
{
|
|
708
|
+
"file": "src/schedules/personal-context.js",
|
|
709
|
+
"beforeBytes": 1503,
|
|
710
|
+
"afterBytes": 1451
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
"file": "src/schedules/server-client.js",
|
|
714
|
+
"beforeBytes": 2475,
|
|
715
|
+
"afterBytes": 1710
|
|
716
|
+
},
|
|
702
717
|
{
|
|
703
718
|
"file": "src/security/managed-agent-credential-paths.js",
|
|
704
719
|
"beforeBytes": 1853,
|
|
@@ -776,8 +791,8 @@
|
|
|
776
791
|
},
|
|
777
792
|
{
|
|
778
793
|
"file": "src/session/handlers/chat-adapter-config.js",
|
|
779
|
-
"beforeBytes":
|
|
780
|
-
"afterBytes":
|
|
794
|
+
"beforeBytes": 3042,
|
|
795
|
+
"afterBytes": 1288
|
|
781
796
|
},
|
|
782
797
|
{
|
|
783
798
|
"file": "src/session/handlers/chat-events.js",
|
|
@@ -786,8 +801,8 @@
|
|
|
786
801
|
},
|
|
787
802
|
{
|
|
788
803
|
"file": "src/session/handlers/chat-recovery.js",
|
|
789
|
-
"beforeBytes":
|
|
790
|
-
"afterBytes":
|
|
804
|
+
"beforeBytes": 6752,
|
|
805
|
+
"afterBytes": 3526
|
|
791
806
|
},
|
|
792
807
|
{
|
|
793
808
|
"file": "src/session/handlers/chat-session-lifecycle.js",
|
|
@@ -796,8 +811,8 @@
|
|
|
796
811
|
},
|
|
797
812
|
{
|
|
798
813
|
"file": "src/session/handlers/chat.js",
|
|
799
|
-
"beforeBytes":
|
|
800
|
-
"afterBytes":
|
|
814
|
+
"beforeBytes": 33859,
|
|
815
|
+
"afterBytes": 14585
|
|
801
816
|
},
|
|
802
817
|
{
|
|
803
818
|
"file": "src/session/handlers/control.js",
|
|
@@ -866,8 +881,8 @@
|
|
|
866
881
|
},
|
|
867
882
|
{
|
|
868
883
|
"file": "src/session/manager.js",
|
|
869
|
-
"beforeBytes":
|
|
870
|
-
"afterBytes":
|
|
884
|
+
"beforeBytes": 42639,
|
|
885
|
+
"afterBytes": 22478
|
|
871
886
|
},
|
|
872
887
|
{
|
|
873
888
|
"file": "src/session/native-cleanup-outbox.js",
|
|
@@ -891,8 +906,13 @@
|
|
|
891
906
|
},
|
|
892
907
|
{
|
|
893
908
|
"file": "src/session/queue-helpers.js",
|
|
894
|
-
"beforeBytes":
|
|
895
|
-
"afterBytes":
|
|
909
|
+
"beforeBytes": 7920,
|
|
910
|
+
"afterBytes": 3969
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
"file": "src/session/queue-message.js",
|
|
914
|
+
"beforeBytes": 2938,
|
|
915
|
+
"afterBytes": 1881
|
|
896
916
|
},
|
|
897
917
|
{
|
|
898
918
|
"file": "src/session/queue-retry.js",
|
|
@@ -904,15 +924,20 @@
|
|
|
904
924
|
"beforeBytes": 1663,
|
|
905
925
|
"afterBytes": 909
|
|
906
926
|
},
|
|
927
|
+
{
|
|
928
|
+
"file": "src/session/queue-types.js",
|
|
929
|
+
"beforeBytes": 11,
|
|
930
|
+
"afterBytes": 1
|
|
931
|
+
},
|
|
907
932
|
{
|
|
908
933
|
"file": "src/session/queue.js",
|
|
909
|
-
"beforeBytes":
|
|
910
|
-
"afterBytes":
|
|
934
|
+
"beforeBytes": 43949,
|
|
935
|
+
"afterBytes": 19384
|
|
911
936
|
},
|
|
912
937
|
{
|
|
913
938
|
"file": "src/session/queued-chat-dispatch.js",
|
|
914
|
-
"beforeBytes":
|
|
915
|
-
"afterBytes":
|
|
939
|
+
"beforeBytes": 2850,
|
|
940
|
+
"afterBytes": 1594
|
|
916
941
|
},
|
|
917
942
|
{
|
|
918
943
|
"file": "src/session/run-recovery/barrier.js",
|
|
@@ -26,11 +26,11 @@ declare const manifestSchema: z.ZodObject<{
|
|
|
26
26
|
}>>;
|
|
27
27
|
}, "strict", z.ZodTypeAny, {
|
|
28
28
|
id: string;
|
|
29
|
-
schemaVersion: 1;
|
|
30
29
|
name: string;
|
|
30
|
+
schemaVersion: 1;
|
|
31
31
|
args: string[];
|
|
32
|
-
protocol: "acp";
|
|
33
32
|
command: string;
|
|
33
|
+
protocol: "acp";
|
|
34
34
|
enabled: boolean;
|
|
35
35
|
homepage?: string | undefined;
|
|
36
36
|
clientCapabilities?: {
|
|
@@ -40,10 +40,10 @@ declare const manifestSchema: z.ZodObject<{
|
|
|
40
40
|
} | undefined;
|
|
41
41
|
}, {
|
|
42
42
|
id: string;
|
|
43
|
-
schemaVersion: 1;
|
|
44
43
|
name: string;
|
|
45
|
-
|
|
44
|
+
schemaVersion: 1;
|
|
46
45
|
command: string;
|
|
46
|
+
protocol: "acp";
|
|
47
47
|
args?: string[] | undefined;
|
|
48
48
|
enabled?: boolean | undefined;
|
|
49
49
|
homepage?: string | undefined;
|
|
@@ -18,7 +18,7 @@ export type CodexDynamicToolCallResponse = {
|
|
|
18
18
|
contentItems: ManagedRoomDynamicContentItem[];
|
|
19
19
|
};
|
|
20
20
|
export declare const CODEX_MANAGED_ROOM_DYNAMIC_TOOLS: CodexDynamicToolSpec[];
|
|
21
|
-
export declare const CODEX_MANAGED_MANAGER_DYNAMIC_TOOLS:
|
|
21
|
+
export declare const CODEX_MANAGED_MANAGER_DYNAMIC_TOOLS: CodexDynamicToolSpec[];
|
|
22
22
|
/**
|
|
23
23
|
* Per-adapter, per-turn capability binding for Codex app-server dynamic tools.
|
|
24
24
|
* The short Room token never enters Codex's process or persisted rollout.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const I={shennian_schedule:"schedule",shennian_room_status:"status",shennian_room_read:"read",shennian_room_send:"send",shennian_room_attachment_get:"attachment.get",shennian_room_pause:"pause",shennian_manager_sessions_list:"manager.sessions.list",shennian_manager_sessions_start:"manager.sessions.start",shennian_manager_sessions_send:"manager.sessions.send",shennian_manager_sessions_queue_list:"manager.sessions.queue",shennian_manager_sessions_queue_edit:"manager.sessions.queue.edit",shennian_manager_sessions_queue_delete:"manager.sessions.queue.delete",shennian_manager_sessions_stop:"manager.sessions.stop",shennian_manager_sessions_read:"manager.sessions.read",shennian_manager_memory_path:"manager.memory.path"},b={shennian_schedule:new Set(["operation","id","version","operationId","timeDescription","timezone","prompt"]),shennian_room_status:new Set,shennian_room_read:new Set(["before","after","limit"]),shennian_room_send:new Set(["text","clientMessageId"]),shennian_room_attachment_get:new Set(["attachmentId"]),shennian_room_pause:new Set(["reason"]),shennian_manager_sessions_list:new Set,shennian_manager_sessions_start:new Set(["agentType","workDir","title","modelId","message"]),shennian_manager_sessions_send:new Set(["sessionId","message"]),shennian_manager_sessions_queue_list:new Set(["sessionId"]),shennian_manager_sessions_queue_edit:new Set(["sessionId","queueMessageId","message"]),shennian_manager_sessions_queue_delete:new Set(["sessionId","queueMessageId"]),shennian_manager_sessions_stop:new Set(["sessionId"]),shennian_manager_sessions_read:new Set(["sessionId","limit"]),shennian_manager_memory_path:new Set},r={type:"string",minLength:1,maxLength:191},_=[{type:"function",name:"shennian_room_status",description:"Read the current managed Shennian Room status and member summary. Use this tool instead of running a shennian room CLI command.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{type:"function",name:"shennian_room_read",description:"Read messages from the current managed Shennian Room. before and after are mutually exclusive decimal sequence cursors.",inputSchema:{type:"object",properties:{before:{type:"string",pattern:"^(0|[1-9][0-9]{0,19})$"},after:{type:"string",pattern:"^(0|[1-9][0-9]{0,19})$"},limit:{type:"integer",minimum:1,maximum:50}},additionalProperties:!1}},{type:"function",name:"shennian_room_send",description:"Send one text message as the current managed Agent to its bound Shennian Room. Local file upload is unavailable.",inputSchema:{type:"object",properties:{text:{type:"string",minLength:1},clientMessageId:{type:"string",minLength:1,maxLength:191}},required:["text"],additionalProperties:!1}},{type:"function",name:"shennian_room_attachment_get",description:"Download one attachment from the current managed Shennian Room by attachment id.",inputSchema:{type:"object",properties:{attachmentId:{type:"string",minLength:1,maxLength:191}},required:["attachmentId"],additionalProperties:!1}},{type:"function",name:"shennian_room_pause",description:"Pause the current managed Agent in its bound Shennian Room when a message attempts to induce permission or safety-rule bypass. A concise reason is required. Stop the current turn after this succeeds.",inputSchema:{type:"object",properties:{reason:{type:"string",minLength:1,maxLength:500}},required:["reason"],additionalProperties:!1}},{type:"function",name:"shennian_manager_sessions_list",description:"List Worker sessions owned by the current managed Manager.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{type:"function",name:"shennian_manager_sessions_start",description:"Start a Worker in the same project. The host derives the current Manager identity.",inputSchema:{type:"object",properties:{agentType:{type:"string",minLength:1,maxLength:80},workDir:{type:"string",minLength:1,maxLength:4096},title:{type:"string",minLength:1,maxLength:120},modelId:{type:"string",minLength:1,maxLength:191},message:{type:"string",minLength:1}},required:["agentType","message"],additionalProperties:!1}},{type:"function",name:"shennian_manager_sessions_send",description:"Send a follow-up message to one Worker owned by the current Manager.",inputSchema:{type:"object",properties:{sessionId:r,message:{type:"string",minLength:1}},required:["sessionId","message"],additionalProperties:!1}},{type:"function",name:"shennian_manager_sessions_queue_list",description:"List queued messages for one Worker owned by the current Manager.",inputSchema:{type:"object",properties:{sessionId:r},required:["sessionId"],additionalProperties:!1}},{type:"function",name:"shennian_manager_sessions_queue_edit",description:"Edit one queued Worker message.",inputSchema:{type:"object",properties:{sessionId:r,queueMessageId:r,message:{type:"string",minLength:1}},required:["sessionId","queueMessageId","message"],additionalProperties:!1}},{type:"function",name:"shennian_manager_sessions_queue_delete",description:"Delete one queued Worker message.",inputSchema:{type:"object",properties:{sessionId:r,queueMessageId:r},required:["sessionId","queueMessageId"],additionalProperties:!1}},{type:"function",name:"shennian_manager_sessions_stop",description:"Stop one Worker owned by the current Manager.",inputSchema:{type:"object",properties:{sessionId:r},required:["sessionId"],additionalProperties:!1}},{type:"function",name:"shennian_manager_sessions_read",description:"Read the compact transcript of one Worker owned by the current Manager.",inputSchema:{type:"object",properties:{sessionId:r,limit:{type:"integer",minimum:1,maximum:500}},required:["sessionId"],additionalProperties:!1}},{type:"function",name:"shennian_manager_memory_path",description:"Read the current Manager project memory directory path.",inputSchema:{type:"object",properties:{},additionalProperties:!1}}],y={type:"function",name:"shennian_schedule",description:"Manage scheduled work in this conversation for its owner. Use operation list/create/update/pause/resume/delete. For create provide a stable operationId, timeDescription (\u6BCF\u592909:00, \u6BCF\u5468\u4E0009:00, \u6BCF\u969424\u5C0F\u65F6, 30\u5206\u949F\u540E or ISO time), timezone and a self-contained work prompt. Query first to obtain id and version for changes. Reply in ordinary text only after success.",inputSchema:{type:"object",properties:{operation:{type:"string",enum:["list","create","update","pause","resume","delete"]},id:{type:"string"},version:{type:"integer"},operationId:{type:"string"},timeDescription:{type:"string"},timezone:{type:"string"},prompt:{type:"string"}},required:["operation"],additionalProperties:!1}},q=[..._.slice(0,5),y],A=[..._,y];class C{token=null;executor=null;threadId=null;turnId=null;generation=0;consumedCallIds=new Set;abortController=null;configure(e,s){this.abortController?.abort(),this.generation+=1,this.token=e?.trim()||null,this.executor=s??null,this.abortController=this.token&&this.executor?new AbortController:null,this.turnId=null,this.consumedCallIds.clear()}isConfigured(){return!!(this.token&&this.executor)}bindThread(e){this.threadId=e,this.turnId=null,this.consumedCallIds.clear()}bindTurn(e,s){return!this.isConfigured()||!this.threadId||e!==this.threadId?!1:(this.turnId===s||(this.turnId=s,this.consumedCallIds.clear()),!0)}deactivateTurn(){this.abortController?.abort(),this.generation+=1,this.token=null,this.executor=null,this.abortController=null,this.turnId=null,this.consumedCallIds.clear()}reset(){this.deactivateTurn(),this.threadId=null}async execute(e){const s=m(e.threadId),i=m(e.turnId),t=m(e.callId),h=m(e.tool),o=I[h],c=this.token,p=this.executor,l=this.abortController,f=this.generation;if(!s||!i||!t||!o||e.namespace!==null||!c||!p||!l||s!==this.threadId||i!==this.turnId||this.consumedCallIds.has(t))return u("managed_room_tool_context_unavailable");const g=x(h,e.arguments);if(!g)return u("invalid_params");this.consumedCallIds.add(t);try{const d=await p({...g,context:c,action:o},{signal:l.signal,...o==="attachment.get"?{attachmentOutput:"codex-inline"}:{}});if(o==="pause"){const a=[{type:"inputText",text:JSON.stringify(d)}];return this.deactivateTurn(),{success:!0,contentItems:a}}if(f!==this.generation||c!==this.token||p!==this.executor||s!==this.threadId||i!==this.turnId)return u("managed_room_tool_context_revoked");if(o==="attachment.get"){const a=S(d);return a?{success:!0,contentItems:a}:u("managed_room_attachment_presentation_invalid")}return{success:!0,contentItems:[{type:"inputText",text:JSON.stringify(d)}]}}catch(d){const a=w(d);return u(a)}}}function S(n){if(!n||typeof n!="object"||Array.isArray(n))return null;const e=n.codexContentItems;if(!Array.isArray(e)||e.length<1||e.length>2)return null;const s=[];for(const i of e){if(!i||typeof i!="object"||Array.isArray(i))return null;const t=i;if(t.type==="inputText"&&typeof t.text=="string"){s.push({type:"inputText",text:t.text});continue}if(t.type==="inputImage"&&typeof t.imageUrl=="string"&&/^data:image\/(?:jpeg|png|webp|gif);base64,[A-Za-z0-9+/]*={0,2}$/.test(t.imageUrl)){s.push({type:"inputImage",imageUrl:t.imageUrl});continue}if(t.type==="inputAudio"&&typeof t.audioUrl=="string"&&/^data:audio\/(?:mpeg|mp4|ogg|wav|webm|x-wav);base64,[A-Za-z0-9+/]*={0,2}$/.test(t.audioUrl)){s.push({type:"inputAudio",audioUrl:t.audioUrl});continue}return null}return s}function m(n){return typeof n=="string"&&n.trim()?n.trim():""}function x(n,e){if(e==null)return{};if(typeof e!="object"||Array.isArray(e))return null;const s=e,i=b[n];return Object.keys(s).some(t=>!i.has(t))?null:s}function w(n){const e=n&&typeof n=="object"?n.code:void 0;return typeof e=="string"&&/^[a-z0-9_]{1,80}$/.test(e)?e:"managed_room_tool_failed"}function u(n){return{success:!1,contentItems:[{type:"inputText",text:n}]}}export{A as CODEX_MANAGED_MANAGER_DYNAMIC_TOOLS,q as CODEX_MANAGED_ROOM_DYNAMIC_TOOLS,C as CodexManagedRoomToolBinding};
|
|
@@ -66,7 +66,7 @@ function tokenize(command) {
|
|
|
66
66
|
function commandAllowed(argv) {
|
|
67
67
|
if (argv[0] !== 'shennian') return false;
|
|
68
68
|
if (ALLOW_ROOM && argv[1] === 'room') {
|
|
69
|
-
return ['status', 'read', 'send', 'pause'].includes(argv[2]) ||
|
|
69
|
+
return ['status', 'read', 'send', 'pause', 'schedule'].includes(argv[2]) ||
|
|
70
70
|
(argv[2] === 'attachment' && argv[3] === 'get');
|
|
71
71
|
}
|
|
72
72
|
if (ALLOW_MANAGER && argv[1] === 'manager') {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import b from"node:crypto";import U from"node:fs";import
|
|
2
|
-
`)}catch(a){if(a instanceof A){
|
|
1
|
+
import b from"node:crypto";import U from"node:fs";import w from"node:path";import{PublicAttachmentCache as O}from"../room/public-attachment-cache.js";import{PublicRoomClient as L,PublicRoomClientError as A}from"../room/public-room-client.js";import{callDaemonIpc as j}from"../daemon-ipc/client.js";import{DaemonIpcError as S}from"../daemon-ipc/protocol.js";import{MANAGED_ROOM_IPC_ROOT_ENV as k,resolveManagedRoomIpcPaths as D}from"../daemon-ipc/paths.js";import{MANAGED_ROOM_CONTEXT_ENV as P}from"../room/managed-context.js";import{createRoomInviteQr as N}from"../room/invite-qr.js";const T="https://shennian.net/install.md",$={write:e=>{process.stdout.write(e)},fail:()=>{process.exitCode=1}};function te(e,t={}){const o=t.client??new L,a=t.cache??new O({client:o}),s=t.io??$,u=t.createInviteQr??N,c=e.command("room").description("Use one explicitly referenced Shennian Room");c.command("schedule").description("Manage scheduled work in the current managed conversation").requiredOption("--operation <operation>","list/create/update/pause/resume/delete").option("--id <id>").option("--version <version>").option("--operation-id <operationId>").option("--time-description <timeDescription>").option("--timezone <timezone>").option("--prompt <prompt>").action(async i=>p("room.schedule",s,async()=>{const n=h();if(!n)throw new Error("managed_room_context_required");return v(n,"schedule",{...i,version:i.version?Number(i.version):void 0})})),c.command("create").description("Create a Room as the paired user").requiredOption("--name <name>","Room name").action(async i=>p("room.create",s,async()=>{R("create");const n=i.name.trim();(!n||n.length>80)&&r("invalid_room_name","Room name must contain 1 to 80 characters.");const m=await o.create(n),d=_(m.room,"invalid_room_response");typeof d.inviteUrl!="string"&&r("invalid_room_response","Shennian returned an invalid Room invitation.");const f=await u(d.inviteUrl).catch(()=>({imagePath:null,mimeType:"image/png",payload:d.inviteUrl}));return{...m,sharing:{inviteUrl:d.inviteUrl,inviteQr:f,installGuideUrl:T}}})),c.command("join <invite-url>").description("Join or request access through an official Room invitation").option("--message <message>","Introduction and reason required when owner approval is enabled").action(async(i,n)=>p("room.join",s,async()=>{R("join");const m=I(i,"invite"),d=n.message?.trim();return d&&d.length>500&&r("join_message_too_long","Join request message must be at most 500 characters."),o.join(m.roomId,m.inviteToken,d)})),c.command("open <room-url>").description("Open one Room where the paired user is already a member").action(async i=>p("room.open",s,async()=>{R("open");const n=I(i,"stable");return o.open(n.roomId)})),c.command("status [room-ref]").description("Show the managed Room, or one explicitly referenced Room").action(async i=>p("room.status",s,()=>{const n=h();return n?(i&&r("managed_room_ref_forbidden","Do not pass a Room reference in managed Room context."),v(n,"status",{})):o.status(x(i))})),c.command("read [room-ref]").description("Read recent, older, or newer messages from one Room").option("--before <sequence>","Read messages before this sequence").option("--after <sequence>","Read messages after this sequence").option("--limit <count>","Maximum messages, 1 to 50","50").action(async(i,n)=>{await p("room.read",s,async()=>{n.before&&n.after&&r("ambiguous_sequence_cursor","--before and --after are mutually exclusive."),n.before&&!M(n.before)&&r("invalid_sequence","--before sequence is invalid."),n.after&&!M(n.after)&&r("invalid_sequence","--after sequence is invalid.");const m=Number(n.limit);(!Number.isInteger(m)||m<1||m>50)&&r("invalid_limit","--limit must be between 1 and 50.");const d=h();if(d)return i&&r("managed_room_ref_forbidden","Do not pass a Room reference in managed Room context."),v(d,"read",{...n.before?{before:n.before}:{},...n.after?{after:n.after}:{},limit:m});const f=x(i),y=await o.read(f,{before:n.before,after:n.after,limit:m});return G(y,f,a)})}),c.command("send [room-ref]").description("Send text and up to 10 files as the paired user").option("--text <text>","Message text").option("--file <path>","Local file path; repeat for multiple files",C,[]).action(async(i,n)=>{await p("room.send",s,async()=>{const m=n.text?.trim()??"";!m&&n.file.length===0&&r("room_message_empty","Provide --text or at least one --file."),n.file.length>10&&r("room_attachments_too_many","A message can contain at most 10 files.");const d=h();if(d)return i&&r("managed_room_ref_forbidden","Do not pass a Room reference in managed Room context."),v(d,"send",{clientMessageId:`managed:${b.randomUUID()}`,text:m,files:n.file});const f=x(i),y=[];for(const z of n.file)y.push(await E(o,f,z));return o.send(f,{clientMessageId:`cli:${b.randomUUID()}`,...m?{text:m}:{},...y.length>0?{attachmentIds:y}:{}})})}),c.command("pause").description("Pause the current managed Agent in its bound Room").requiredOption("--reason <reason>","Short reason shown to all Room members").action(async i=>p("room.pause",s,()=>{const n=h();return n||r("managed_room_context_required","Pause is only available in managed Room context."),v(n,"pause",{reason:i.reason})})),c.command("attachment").description("Download Room attachments through Shennian").command("get [room-ref] [attachment-id]").description("Download and verify one Room attachment").action(async(i,n)=>{await p("room.attachment.get",s,async()=>{const m=h(),d=m?i:n;return(!d||!/^ratt_[A-Za-z0-9_-]{1,191}$/.test(d))&&r("invalid_attachment_ref","attachment-id is invalid."),m?v(m,"attachment.get",{attachmentId:d}):a.materialize(x(i),d)})}),c.command("leave <room-ref>").description("Leave one explicitly referenced Room").action(async i=>p("room.leave",s,()=>(R("leave"),o.leave(q(i))))),c.command("list",{hidden:!0}).action(()=>g(s,"command_removed","Room listing is not available to Agents.",null)),c.command("search",{hidden:!0}).allowUnknownOption(!0).action(()=>g(s,"command_removed","Room search is not available to Agents.",null)),c.command("agent",{hidden:!0}).allowUnknownOption(!0).action(()=>g(s,"command_removed","Managed Agents are created in the Shennian mobile App.",null))}async function p(e,t,o){try{const a=await o();t.write(`${JSON.stringify({ok:!0,command:e,result:a})}
|
|
2
|
+
`)}catch(a){if(a instanceof A){g(t,a.code,a.message,a.nextAction);return}if(a instanceof S){g(t,a.code,a.message,null);return}g(t,"room_command_failed","Shennian Room command failed.",null)}}function h(){return process.env[P]?.trim()||null}async function v(e,t,o){const a=process.env[k]?.trim();if(!a||!w.isAbsolute(a))throw new S("managed_room_context_unavailable","Managed Room IPC context is unavailable.");return j({method:"managed-room.execute",params:{context:e,action:t,...o},paths:D(a),timeoutMs:t==="send"||t==="attachment.get"?18e4:15e3})}function R(e){h()&&r("managed_room_action_forbidden",`${e} is not available in managed Room context.`)}function x(e){return e||r("room_ref_required","Use an official Room URL returned by Shennian."),q(e)}function q(e){return I(e,"stable").roomId}function I(e,t){let o;const a=t==="invite"?"invalid_invite_url":"invalid_room_ref",s=t==="invite"?"Use an official Shennian Room invitation URL.":"Use an official Room URL returned by Shennian.";try{o=new URL(e)}catch{r(a,s)}const u=o.pathname.match(/^\/spaces\/([A-Za-z0-9_-]{1,191})$/),c=o.searchParams.get("invite");return(o.protocol!=="https:"||o.hostname!=="app.shennian.net"||o.port||o.username||o.password||o.hash||!u||o.searchParams.has("access")||[...o.searchParams.keys()].some(l=>l!=="invite")||t==="stable"&&c!=null||t==="invite"&&(c==null||!/^[A-Za-z0-9_-]{32,256}$/.test(c)))&&r(a,s),{roomId:u[1],...c?{inviteToken:c}:{}}}function M(e){return/^(0|[1-9]\d{0,19})$/.test(e)}function C(e,t){return[...t,e]}async function E(e,t,o){const a=w.resolve(o);let s;try{s=await U.promises.lstat(a)}catch{r("file_not_found",`File does not exist: ${o}`)}(!s.isFile()||s.isSymbolicLink())&&r("invalid_file",`Not a regular file: ${o}`),(s.size<1||s.size>100*1024*1024)&&r("invalid_file_size","Each file must be between 1 byte and 100 MB.");const u=await U.promises.readFile(a),c=b.createHash("sha256").update(u).digest("hex"),l=F(a),i=await e.initializeAttachment(t,{clientUploadId:`cli:${b.randomUUID()}`,name:w.basename(a),mediaKind:l.startsWith("image/")?"image":l.startsWith("audio/")?"audio":"file",mimeType:l,byteSize:s.size,sha256:c}),n=_(i.attachment,"invalid_attachment_response"),m=_(i.upload,"invalid_attachment_response");(typeof n.id!="string"||typeof m.url!="string"||m.method!=="PUT")&&r("invalid_attachment_response","Shennian returned an invalid attachment response.");const d=_(m.headers,"invalid_attachment_response");return Object.values(d).some(f=>typeof f!="string")&&r("invalid_attachment_response","Shennian returned invalid upload headers."),J(m.url),await e.upload(m.url,d,u),await e.completeAttachment(t,n.id),n.id}function F(e){const t=w.extname(e).toLowerCase();return{".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".webp":"image/webp",".gif":"image/gif",".heic":"image/heic",".mp3":"audio/mpeg",".wav":"audio/wav",".m4a":"audio/mp4",".mp4":"video/mp4",".mov":"video/quicktime",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".json":"application/json",".csv":"text/csv",".zip":"application/zip",".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}[t]??"application/octet-stream"}function G(e,t,o){return Array.isArray(e.messages)||r("invalid_server_response","Shennian returned invalid messages."),{messages:e.messages.map(a=>{const s=_(a,"invalid_server_response"),u=Array.isArray(s.attachments)?s.attachments:[];return{...s,attachments:u.map(c=>{const l=_(c,"invalid_server_response");return(typeof l.attachmentId!="string"||typeof l.name!="string"||typeof l.mimeType!="string"||typeof l.byteSize!="string"||typeof l.sha256!="string")&&r("invalid_server_response","Shennian returned invalid attachment metadata."),{...l,...o.lookup(t,l)}})}})}}function _(e,t){return(!e||typeof e!="object"||Array.isArray(e))&&r(t,"Invalid structured response."),e}function J(e){let t;try{t=new URL(e)}catch{r("invalid_attachment_response","Invalid upload URL.")}const o=t.protocol==="http:"&&(t.hostname==="localhost"||t.hostname==="127.0.0.1");(t.protocol!=="https:"&&!o||t.username||t.password||t.hash)&&r("invalid_attachment_response","Invalid upload URL.")}function r(e,t){throw new A(e,t)}function g(e,t,o,a){e.write(`${JSON.stringify({ok:!1,error:t,message:o,nextAction:a})}
|
|
3
3
|
`),e.fail()}export{te as registerRoomCommand};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{callDaemonIpc as i}from"../daemon-ipc/client.js";import{resolveManagedRoomIpcPaths as n}from"../daemon-ipc/paths.js";function a(t){t.command("schedule").description("Manage scheduled work in this conversation").requiredOption("--operation <operation>","list/create/update/pause/resume/delete").option("--id <id>").option("--version <version>").option("--operation-id <operationId>").option("--time-description <timeDescription>").option("--timezone <timezone>").option("--prompt <prompt>").action(async o=>{try{const e=process.env.SHENNIAN_SCHEDULE_CONTEXT;if(!e)throw new Error("schedule_context_required");const r=await i({method:"schedule.personal",paths:n(),params:{...o,version:o.version?Number(o.version):void 0,context:e},timeoutMs:15e3});process.stdout.write(`${JSON.stringify(r)}
|
|
2
|
+
`)}catch(e){console.error(e instanceof Error?e.message:"schedules_unavailable"),process.exitCode=1}})}export{a as registerScheduleCommand};
|
package/dist/src/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`),process.exitCode=1}function Oo(n){const i=[`trigger=${n.trigger??"unknown"}`,`phase=${n.phase}`,`code=${n.code??"unknown"}`,`attempt=${n.reconnectAttempt}`];return n.reason&&i.push(`reason=${n.reason}`),n.error&&i.push(`error=${n.error}`),i.join(" ")}const s=new fe;s.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(B),s.enablePositionalOptions(),je(s),He(s),s.option("--api <url>","Server URL override").option("--name <name>","Machine name",he.hostname()).action(async n=>{const i=p(),d=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??i.serverUrl??void 0;await ke(d,n.name)}),s.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async n=>{const i=H("env.json");try{const e=JSON.parse(j.readFileSync(i,"utf-8"));for(const[a,o]of Object.entries(e))process.env[a]||(process.env[a]=o);ae()}catch{}Ce(Q(process.env,p()));const d=io();oe()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(d),process.exit(0));const c=Ee(),v=eo({lockPath:$o,instanceId:c});v.acquired||(console.log(`[${new Date().toISOString()}] daemon already running`+(v.ownerPid?` (PID ${v.ownerPid})`:"")+", skipping duplicate start"),clearInterval(d),process.exit(0));try{const e=xo();if(e&&e!==process.pid)try{process.kill(e,0),console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),v.release(),process.exit(0)}catch{}}catch{}const q=Te(process.env,de)?[]:Ae(process.pid);q.length>0&&(console.log(`[${new Date().toISOString()}] daemon already running (PID ${q[0]}), skipping duplicate start`),v.release(),process.exit(0)),ne(process.pid,c,{version:B}),re(process.pid,void 0,c),process.on("exit",()=>{X(process.pid,c),ee(c)}),process.on("exit",v.release);let x=null;try{x=Ye()}catch(e){console.error(`[upgrade] updater bootstrap unavailable: ${e instanceof Error?e.message:String(e)}`)}const E=await Je();if(E){x||(console.error("[upgrade] Crash-loop rollback blocked: updater bootstrap unavailable"),process.exit(1));try{Ze({fromVersion:B,targetVersion:E.from,oldDaemonPid:process.pid,operation:"rollback",rollbackJobId:E.jobId},{readiness:x}),console.error(`[upgrade] New version crashed ${E.attemptCount} times; external rollback scheduled.`),process.stdin.resume();return}catch(e){console.error(`[upgrade] Crash-loop rollback could not start: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}try{Do()}catch(e){console.error(`[personal-sync] data epoch initialization failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}const l=p(),f=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??l.serverUrl??F.cn.url,g=te(),y=await Xe({serverUrl:f,authToken:l.machineToken??l.accessToken}),w=y.map(e=>e.type),N=oo(y),h=new go,A=new ho,C=new Po(h),I=new uo(f),pe=new bo({actionClient:I}),ge=new ko({actionClient:I});let S=null,t;const z=Eo({authority:C,actionClient:I,attachmentCache:pe,attachmentUploader:ge,observations:A,getMachineCredentials:()=>({machineToken:p().machineToken}),managerExecutor:e=>t.executeManagedManagerAction(e),onPaused:({registryKey:e,sessionId:a})=>{const r=h.getByRegistryKey(e)?.binding;r&&h.setBinding({registryKey:e,bindingId:r.bindingId,roomId:r.roomId,agentIdentityId:r.agentIdentityId,agentMembershipId:r.agentMembershipId,status:"paused",activationMode:"paused"}),C.revokeSession(e),t?.discardPendingManagedRoomMessages(a)}});let O=null,V=null,L=null;const R=await se({paths:co(),handlers:mo({daemonVersion:g,protocolVersion:po,getStatus:()=>Me(),getAgents:()=>y,completeAgentAuthentication:e=>t.resumePendingAcpAuthentication(e),startUpgrade:async e=>{if(!O)throw new Error("upgrade_unavailable");return O(e)},prepareExternalUpgrade:e=>{if(!V)throw new Error("external_upgrade_unavailable");return V(e)},cancelExternalUpgrade:()=>{if(!L)throw new Error("external_upgrade_unavailable");return L()}})});let b;try{b=await se({paths:lo(),handlers:{"managed-room.execute":e=>z(e)}})}catch(e){throw await R.close(),e}let J=!1;const U=()=>{J||(J=!0,Promise.allSettled([R.close(),b.close()]).finally(()=>process.exit(0)))};if(process.once("SIGINT",U),process.once("SIGTERM",U),!l.machineToken){console.error('Shennian CLI is not paired. Run "shennian pair --browser" or "shennian pair --token" first.'),await Promise.allSettled([R.close(),b.close()]),process.exitCode=1;return}process.removeListener("SIGINT",U),process.removeListener("SIGTERM",U);const K=`${No(f)}/relay/machine`,D=l.machineToken;if(!D)return;try{await Uo({serverUrl:f,machineToken:D,machineId:l.machineId})}catch(e){console.error(`[personal-sync] machine authority verification failed: ${e instanceof Error?e.message:String(e)}`),await Promise.allSettled([R.close(),b.close()]),process.exit(1)}l.machineId&&ro(f,l.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${K}... (v${g}) agents: ${w.join(",")}`),P({level:"info",wsEvent:"daemon.start",metadata:{version:g,agents:w}});let T=null,M=null,_=0,u=Ke();const W=ye(l.autoUpgrade),m=new we({serverUrl:K,machineToken:D,cliVersion:g,agentList:w,autoUpgradePolicy:W,sessionSyncProtocolVersion:ie,sessionSyncCapabilities:ce,daemonInstallationId:Ao(),dataEpoch:le,updaterProtocolVersion:1,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),P({level:"info",wsEvent:"daemon.connected"}),N.some(o=>o.models.length>0)&&m.sendEvent({type:"event",event:"machine.agents",payload:{agentList:w,agents:N}}),no(y,{serverUrl:l.serverUrl??f,authToken:l.machineToken??l.accessToken}).then(o=>{JSON.stringify(o)!==JSON.stringify(N)&&m.sendEvent({type:"event",event:"machine.agents",payload:{agentList:w,agents:o}})}).catch(()=>{}),u&&m.sendEvent({type:"event",event:"upgrade",payload:{state:"recovering",machineId:"self",from:u.from,to:u.to,...u.jobId?{jobId:u.jobId}:{},activeRunCount:t.getPendingRecoveryCount()}}),$.start(),M?.start();const e=++_,a=async()=>{try{if(await t.synchronizeSessionDeletions(),await t.recoverInterruptedRuns(),u){const o=u;u=null,o.jobId&&Qe(o.jobId,o.to),ze(),console.log(`[${new Date().toISOString()}] [upgrade] ${o.operation==="rollback"?"Rolled back":"Healthy"}: ${o.from} \u2192 ${o.to}`),to({kind:"upgrade",result:o.operation==="rollback"?"rolled_back":"healthy",stage:"terminal"}),m.sendEvent({type:"event",event:"upgrade",payload:{state:o.operation==="rollback"?"rolled_back":"healthy",machineId:"self",from:o.from,to:o.to,...o.jobId?{jobId:o.jobId}:{}}}),o.operation!=="rollback"&&m.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:o.from,to:o.to}})}e===_&&m.getState()==="connected"&&T?.handleConnected()}catch(o){if(console.error("[session.deletions] startup catch-up failed",o),e===_&&m.getState()==="connected"){if(o instanceof Mo)return;const r=o instanceof To?Math.max(1e3,o.retryAfterMs):5e3;setTimeout(()=>{a()},r).unref?.()}}};a()},onDisconnected:e=>{_+=1,t?.revokeProjectFsHandles(),M?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${Oo(e)}`),P({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onProjectFsCapabilityChanged:e=>{e||t?.revokeProjectFsHandles()},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),P({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),t.handleReq(e)}});T=ao()?new so(m):null,M=new vo({registry:h,observations:A,actionClient:I,getMachineCredentials:()=>({machineToken:p().machineToken}),isSessionDeleted:e=>new Io().hasSession(e),onMessages:async(e,a,o,r)=>{await S?.processMessages(e,a,o,r)},onBindingPaused:e=>{C.revokeSession(e.registryKey),e.lifecycleState==="closed"?t?.retireManagedRoomSession(e.nianSessionId).catch(()=>{console.warn("[room.sync] retired session cleanup failed")}):t?.discardPendingManagedRoomMessages(e.nianSessionId)}});const $=new We({currentVersion:g,machineId:l.machineId??"unknown-machine",serverUrl:l.serverUrl??f,getIdleState:()=>t.getUpgradeIdleState(),sessionSyncProtocolVersion:ie,dataEpoch:le,advertisedCapabilities:ce,updaterProtocolVersion:1,startUpgrade:async(e,a)=>{const{handleUpgradeStart:o}=await import("./commands/upgrade.js");await o(m,"auto-upgrade",e,{currentVersion:g,prepareForUpgrade:r=>t.prepareForUpgrade(r),cancelUpgradePreparation:()=>t.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0,waitForCompletion:!0,canHandoff:a?void 0:()=>t.getUpgradeIdleState().idle})}});$.setPolicy(W),t=new Fe(m,T,g,$,new fo({registry:h,observations:A,bindingClient:I,getMachineCredentials:()=>{const e=p();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${c}`}),{prepare:()=>Ue(),isDisabled:()=>oe(),shutdownAfterResponse:()=>{setTimeout(()=>{De(),process.kill(process.pid,"SIGTERM")},100).unref?.()}},e=>C.revokeToken(e),z,null,Be(D)),O=async e=>{const a=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=typeof a.targetVersion=="string"?a.targetVersion:void 0,r=a.confirmedMajor===!0;return await Oe(m,`local-upgrade-${Date.now()}`,o,{currentVersion:g,confirmedMajor:r,prepareForUpgrade:ue=>t.prepareForUpgrade(ue),cancelUpgradePreparation:()=>t.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0})},V=e=>{const a=e&&typeof e=="object"&&!Array.isArray(e)?e:{},r=`desktop-${(typeof a.targetVersion=="string"?a.targetVersion:"unknown").replace(/[^A-Za-z0-9._-]/g,"_")}-${Date.now()}`;return{jobId:r,...t.prepareForUpgrade(r)}},L=()=>(t.cancelUpgradePreparation(),{cancelled:!0}),S=new wo({registry:h,observations:A,enqueueConversationBatch:e=>t.enqueueManagedRoomBatch(e),loadContext:async e=>{const a=p().machineToken?.trim(),o=e.binding;if(!a||!o)throw new Error("managed_room_context_unavailable");const r=await I.status({machineToken:a,roomId:o.roomId,bindingId:o.bindingId});if(!yo(h,e)||!So(e,r))throw new Error("managed_room_binding_unavailable");return{roomName:r.room.name,memberCount:r.room.memberCount,members:r.room.members,agentsByIdentityId:r.agent?{[r.agentIdentityId]:r.agent}:{},agentSystemPromptsByIdentityId:r.agent?{[r.agentIdentityId]:r.agent.systemPrompt??""}:{}}},issueManagedRoomContext:(e,a)=>{const o=p().machineToken;if(!o)throw new Error("machine_not_authorized");return C.issue({registryKey:e,machineCredential:o,activationCauseMessageId:a})},audit:new Ro,resolveManagedAgentPolicy:e=>Co({...e,runtime:y.find(a=>a.type===e.registration.runtimeAdapter)})}),t.setManagedRoomTurnPreparer(e=>S.prepareConversationTurn(e)),t.setManagedAgentDirectTurnPreparer(e=>S.prepareDirectConversationTurn(e)),t.setManagedRecoveryPreparer(async e=>e.source==="managed_direct"?S.prepareDirectConversationTurn(e.sessionId):e.source!=="managed_room"||!e.roomContextRegistryKey||!e.activationCauseMessageId||!e.rootCauseMessageId||!e.activationSequence||e.activationHopCount===null?null:S.prepareConversationTurn([{registryKey:e.roomContextRegistryKey,causeMessageId:e.activationCauseMessageId,rootCauseMessageId:e.rootCauseMessageId,sequence:e.activationSequence,hopCount:e.activationHopCount}])),j.mkdirSync(de,{recursive:!0}),ne(process.pid,c,{version:g}),re(process.pid,void 0,c),m.connect(),process.stdin.resume();let Y=!1;const Z=async()=>{if(!Y){Y=!0,console.log(k.gray(`
|
|
3
|
-
Disconnecting...`)),P({level:"info",wsEvent:"daemon.stop"}),clearInterval(
|
|
1
|
+
import{registerScheduleCommand as fe}from"./commands/schedule.js";import{resolvePersonalScheduleContext as ve}from"./schedules/personal-context.js";import{executeServerSchedule as Z,deliverServerSchedule as Ie}from"./schedules/server-client.js";import{Command as Se}from"commander";import R from"chalk";import ye from"node:os";import j from"node:fs";import{loadConfig as m,saveConfig as we,getConfigPath as Ce,getShennianDir as be,resolveShennianPath as H,normalizeAutoUpgradePolicy as ke}from"./config/index.js";import{CliRelayClient as Re}from"./relay/client.js";import{collectKnownLogSecrets as X,installCliLogRedaction as Pe,sanitizeCliLogValue as Ee}from"./log-redaction.js";import{registerPairCommand as Ae,runSmartStart as Te}from"./commands/pair.js";import{registerLogoutCommand as Ue}from"./commands/logout.js";import{clearDaemonPidIfOwner as ee,createDaemonInstanceId as De,clearDaemonLauncher as oe,findRunningDaemonProcessIds as Me,isRemoteAccessDisabled as ne,prepareRemoteAccessPause as _e,stopPreparedRemoteAccessService as xe,isIsolatedDaemonE2eInstance as $e,getDaemonStatus as Ne,registerDaemonCommand as Oe,writeDaemonPid as re,writeDaemonLauncher as te}from"./commands/daemon.js";import{registerRuntimeCommand as Ve}from"./commands/runtime.js";import{registerAgentCommand as Le}from"./commands/agent.js";import{registerManagerCommand as je}from"./commands/manager.js";import{handleUpgradeStart as He,registerUpgradeCommand as Be}from"./commands/upgrade.js";import{registerToolsCommand as Fe}from"./commands/tools.js";import{registerIntegrationCommand as Ge}from"./commands/integration.js";import{registerRoomCommand as qe}from"./commands/room.js";import{SessionManager as ze}from"./session/manager.js";import{createTrustedProjectFsRequestResolver as Je}from"./session/handlers/project-fs.js";import{SERVERS as B,regionToUrl as Ke,urlToRegion as We}from"./region.js";import{clearUpgradeAttempt as Ye,getCurrentVersion as ae,handleStartupCrashCheck as Qe,readUpgradeAttempt as Ze}from"./upgrade/engine.js";import{AutoUpgradeScheduler as Xe}from"./upgrade/scheduler.js";import{ensureUpdaterInstalled as eo}from"./upgrade/updater-bootstrap.js";import{launchUpdater as oo,markUpdaterHealthy as no}from"./upgrade/updater-launcher.js";import{detectAgents as ro}from"./agents/detect.js";import{augmentProcessPath as ie}from"./env-path.js";import{acquireDaemonInstanceLock as to}from"./commands/daemon-instance-lock.js";ie();const F=ae();import{getCachedAgentInfos as ao,resolveAgentInfos as io}from"./agents/model-registry.js";import{initCliLogReporter as so,reportLog as P,reportUpgradeAggregateMetric as co}from"./log-reporter.js";import{isNativeFusionEnabled as lo}from"./native-fusion/config.js";import{NativeSessionFusionService as mo}from"./native-fusion/service.js";import{startDaemonLogRetention as po}from"./daemon-log.js";import{startDaemonIpcServer as se}from"./daemon-ipc/server.js";import{resolveDaemonIpcPaths as go,resolveManagedRoomIpcPaths as uo}from"./daemon-ipc/paths.js";import{createDaemonControlHandlers as ho}from"./daemon-ipc/control.js";import{DAEMON_IPC_VERSION as fo}from"./daemon-ipc/protocol.js";import{RoomSessionRegistry as vo}from"./room/session-registry.js";import{HttpRoomBindingClient as Io}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as So}from"./room/managed-room-binding.js";import{RoomHostSessionObservationStore as yo}from"./room/host-session-observations.js";import{RoomMirrorSyncService as wo}from"./room/mirror-sync-service.js";import{NativeSourceDeletionStore as Co}from"./native-fusion/native-source-deletions.js";import{matchesRoomOwner as bo,isCurrentRegistration as ko}from"./room/registration-authority.js";import{RoomActivationService as Ro,resolveManagedAgentPolicy as Po}from"./room/activation-service.js";import{RoomActivationAudit as Eo}from"./room/activation-audit.js";import{RoomAttachmentCache as Ao}from"./room/attachment-cache.js";import{RoomAttachmentUploader as To}from"./room/attachment-upload.js";import{ManagedRoomContextAuthority as Uo}from"./room/managed-context.js";import{createManagedRoomExecutor as Do}from"./room/managed-room-ipc.js";import{SESSION_SYNC_PROTOCOL_VERSION as ce,SESSION_SYNC_ADVERTISED_CAPABILITIES as de}from"@shennian/wire";import{getDaemonInstallationId as Mo}from"./session/store.js";import{synchronizeMachinePersonalAuthority as _o}from"./personal-sync/machine-authority.js";import{CLI_SESSION_SYNC_DATA_EPOCH as le,ensurePersonalDataEpoch as xo}from"./personal-sync/epoch.js";import{DeletionSyncRetryWaitError as $o,DeletionSyncTerminalError as No}from"./session/deletion-sync-state.js";const me=be(),Oo=H("daemon.pid"),Vo=H("daemon.instance.lock");function Lo(){try{const t=j.readFileSync(Oo,"utf-8").trim();if(t.startsWith("{")){const p=JSON.parse(t),c=Number(p.pid);return Number.isInteger(c)&&c>0?c:null}const s=parseInt(t,10);return Number.isInteger(s)&&s>0?s:null}catch{return null}}function jo(t){return t.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function G(){process.stdout.write(`${JSON.stringify({ok:!1,error:"integration_command_retired",message:"Room MCP and Hooks were retired. Use the Shennian Skill and CLI.",nextAction:{type:"open_install_guide",url:"https://shennian.net/install.md"}})}
|
|
2
|
+
`),process.exitCode=1}function Ho(t){const s=[`trigger=${t.trigger??"unknown"}`,`phase=${t.phase}`,`code=${t.code??"unknown"}`,`attempt=${t.reconnectAttempt}`];return t.reason&&s.push(`reason=${t.reason}`),t.error&&s.push(`error=${t.error}`),s.join(" ")}const i=new Se;i.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(F),i.enablePositionalOptions(),Ge(i),qe(i),fe(i),i.option("--api <url>","Server URL override").option("--name <name>","Machine name",ye.hostname()).action(async t=>{const s=m(),p=t.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??s.serverUrl??void 0;await Te(p,t.name)}),i.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async t=>{const s=H("env.json");try{const e=JSON.parse(j.readFileSync(s,"utf-8"));for(const[n,o]of Object.entries(e))process.env[n]||(process.env[n]=o);ie()}catch{}Pe(X(process.env,m()));const p=po();ne()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(p),process.exit(0));const c=De(),I=to({lockPath:Vo,instanceId:c});I.acquired||(console.log(`[${new Date().toISOString()}] daemon already running`+(I.ownerPid?` (PID ${I.ownerPid})`:"")+", skipping duplicate start"),clearInterval(p),process.exit(0));try{const e=Lo();if(e&&e!==process.pid)try{process.kill(e,0),console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),I.release(),process.exit(0)}catch{}}catch{}const q=$e(process.env,me)?[]:Me(process.pid);q.length>0&&(console.log(`[${new Date().toISOString()}] daemon already running (PID ${q[0]}), skipping duplicate start`),I.release(),process.exit(0)),re(process.pid,c,{version:F}),te(process.pid,void 0,c),process.on("exit",()=>{ee(process.pid,c),oe(c)}),process.on("exit",I.release);let $=null;try{$=eo()}catch(e){console.error(`[upgrade] updater bootstrap unavailable: ${e instanceof Error?e.message:String(e)}`)}const E=await Qe();if(E){$||(console.error("[upgrade] Crash-loop rollback blocked: updater bootstrap unavailable"),process.exit(1));try{oo({fromVersion:F,targetVersion:E.from,oldDaemonPid:process.pid,operation:"rollback",rollbackJobId:E.jobId},{readiness:$}),console.error(`[upgrade] New version crashed ${E.attemptCount} times; external rollback scheduled.`),process.stdin.resume();return}catch(e){console.error(`[upgrade] Crash-loop rollback could not start: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}try{xo()}catch(e){console.error(`[personal-sync] data epoch initialization failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}const d=m(),g=t.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??d.serverUrl??B.cn.url,h=ae(),y=await ro({serverUrl:g,authToken:d.machineToken??d.accessToken}),w=y.map(e=>e.type),N=ao(y),u=new vo,A=new yo,C=new Uo(u),v=new Io(g),ge=new Ao({actionClient:v}),ue=new To({actionClient:v});let S=null,r;const z=Do({authority:C,actionClient:v,attachmentCache:ge,attachmentUploader:ue,observations:A,getMachineCredentials:()=>({machineToken:m().machineToken}),managerExecutor:e=>r.executeManagedManagerAction(e),scheduleExecutor:(e,n,o)=>Z({serverUrl:g,machineToken:m().machineToken,sessionId:e,action:n,args:o}),onPaused:({registryKey:e,sessionId:n})=>{const a=u.getByRegistryKey(e)?.binding;a&&u.setBinding({registryKey:e,bindingId:a.bindingId,roomId:a.roomId,agentIdentityId:a.agentIdentityId,agentMembershipId:a.agentMembershipId,status:"paused",activationMode:"paused"}),C.revokeSession(e),r?.discardPendingManagedRoomMessages(n)}});let O=null,V=null,L=null;const b=await se({paths:go(),handlers:ho({daemonVersion:h,protocolVersion:fo,getStatus:()=>Ne(),getAgents:()=>y,completeAgentAuthentication:e=>r.resumePendingAcpAuthentication(e),startUpgrade:async e=>{if(!O)throw new Error("upgrade_unavailable");return O(e)},prepareExternalUpgrade:e=>{if(!V)throw new Error("external_upgrade_unavailable");return V(e)},cancelExternalUpgrade:()=>{if(!L)throw new Error("external_upgrade_unavailable");return L()}})});let k;try{k=await se({paths:uo(),handlers:{"managed-room.execute":e=>z(e),"schedule.personal":async e=>{const n=e,o=ve(n?.context);if(u.getByNianSessionId(o)?.binding)throw new Error("schedule_personal_context_required");return await Z({serverUrl:g,machineToken:m().machineToken,sessionId:o,action:n.operation,args:n})}}})}catch(e){throw await b.close(),e}let J=!1;const T=()=>{J||(J=!0,Promise.allSettled([b.close(),k.close()]).finally(()=>process.exit(0)))};if(process.once("SIGINT",T),process.once("SIGTERM",T),!d.machineToken){console.error('Shennian CLI is not paired. Run "shennian pair --browser" or "shennian pair --token" first.'),await Promise.allSettled([b.close(),k.close()]),process.exitCode=1;return}process.removeListener("SIGINT",T),process.removeListener("SIGTERM",T);const K=`${jo(g)}/relay/machine`,U=d.machineToken;if(!U)return;try{await _o({serverUrl:g,machineToken:U,machineId:d.machineId})}catch(e){console.error(`[personal-sync] machine authority verification failed: ${e instanceof Error?e.message:String(e)}`),await Promise.allSettled([b.close(),k.close()]),process.exit(1)}d.machineId&&so(g,d.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${K}... (v${h}) agents: ${w.join(",")}`),P({level:"info",wsEvent:"daemon.start",metadata:{version:h,agents:w}});let D=null,M=null,_=0,f=Ze();const W=ke(d.autoUpgrade),l=new Re({serverUrl:K,machineToken:U,cliVersion:h,agentList:w,autoUpgradePolicy:W,sessionSyncProtocolVersion:ce,sessionSyncCapabilities:de,daemonInstallationId:Mo(),dataEpoch:le,updaterProtocolVersion:1,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),P({level:"info",wsEvent:"daemon.connected"}),N.some(o=>o.models.length>0)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:w,agents:N}}),io(y,{serverUrl:d.serverUrl??g,authToken:d.machineToken??d.accessToken}).then(o=>{JSON.stringify(o)!==JSON.stringify(N)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:w,agents:o}})}).catch(()=>{}),f&&l.sendEvent({type:"event",event:"upgrade",payload:{state:"recovering",machineId:"self",from:f.from,to:f.to,...f.jobId?{jobId:f.jobId}:{},activeRunCount:r.getPendingRecoveryCount()}}),x.start(),M?.start();const e=++_,n=async()=>{try{if(await r.synchronizeSessionDeletions(),await r.recoverInterruptedRuns(),f){const o=f;f=null,o.jobId&&no(o.jobId,o.to),Ye(),console.log(`[${new Date().toISOString()}] [upgrade] ${o.operation==="rollback"?"Rolled back":"Healthy"}: ${o.from} \u2192 ${o.to}`),co({kind:"upgrade",result:o.operation==="rollback"?"rolled_back":"healthy",stage:"terminal"}),l.sendEvent({type:"event",event:"upgrade",payload:{state:o.operation==="rollback"?"rolled_back":"healthy",machineId:"self",from:o.from,to:o.to,...o.jobId?{jobId:o.jobId}:{}}}),o.operation!=="rollback"&&l.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:o.from,to:o.to}})}e===_&&l.getState()==="connected"&&D?.handleConnected()}catch(o){if(console.error("[session.deletions] startup catch-up failed",o),e===_&&l.getState()==="connected"){if(o instanceof No)return;const a=o instanceof $o?Math.max(1e3,o.retryAfterMs):5e3;setTimeout(()=>{n()},a).unref?.()}}};n()},onDisconnected:e=>{_+=1,r?.revokeProjectFsHandles(),M?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${Ho(e)}`),P({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onProjectFsCapabilityChanged:e=>{e||r?.revokeProjectFsHandles()},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),P({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),r.handleReq(e)}});D=lo()?new mo(l):null,M=new wo({registry:u,observations:A,actionClient:v,getMachineCredentials:()=>({machineToken:m().machineToken}),isSessionDeleted:e=>new Co().hasSession(e),onMessages:async(e,n,o,a)=>{await S?.processMessages(e,n,o,a)},onBindingPaused:e=>{C.revokeSession(e.registryKey),e.lifecycleState==="closed"?r?.retireManagedRoomSession(e.nianSessionId).catch(()=>{console.warn("[room.sync] retired session cleanup failed")}):r?.discardPendingManagedRoomMessages(e.nianSessionId)}});const x=new Xe({currentVersion:h,machineId:d.machineId??"unknown-machine",serverUrl:d.serverUrl??g,getIdleState:()=>r.getUpgradeIdleState(),sessionSyncProtocolVersion:ce,dataEpoch:le,advertisedCapabilities:de,updaterProtocolVersion:1,startUpgrade:async(e,n)=>{const{handleUpgradeStart:o}=await import("./commands/upgrade.js");await o(l,"auto-upgrade",e,{currentVersion:h,prepareForUpgrade:a=>r.prepareForUpgrade(a),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0,waitForCompletion:!0,canHandoff:n?void 0:()=>r.getUpgradeIdleState().idle})}});x.setPolicy(W),r=new ze(l,D,h,x,new So({registry:u,observations:A,bindingClient:v,getMachineCredentials:()=>{const e=m();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${c}`}),{prepare:()=>_e(),isDisabled:()=>ne(),shutdownAfterResponse:()=>{setTimeout(()=>{xe(),process.kill(process.pid,"SIGTERM")},100).unref?.()}},e=>C.revokeToken(e),z,null,Je(U)),O=async e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=typeof n.targetVersion=="string"?n.targetVersion:void 0,a=n.confirmedMajor===!0;return await He(l,`local-upgrade-${Date.now()}`,o,{currentVersion:h,confirmedMajor:a,prepareForUpgrade:he=>r.prepareForUpgrade(he),cancelUpgradePreparation:()=>r.cancelUpgradePreparation(),shutdownAfterHandoff:()=>{setTimeout(()=>process.kill(process.pid,"SIGTERM"),100).unref?.()},suppressResponse:!0})},V=e=>{const n=e&&typeof e=="object"&&!Array.isArray(e)?e:{},a=`desktop-${(typeof n.targetVersion=="string"?n.targetVersion:"unknown").replace(/[^A-Za-z0-9._-]/g,"_")}-${Date.now()}`;return{jobId:a,...r.prepareForUpgrade(a)}},L=()=>(r.cancelUpgradePreparation(),{cancelled:!0}),S=new Ro({registry:u,observations:A,enqueueConversationBatch:e=>r.enqueueManagedRoomBatch(e),loadContext:async e=>{const n=m().machineToken?.trim(),o=e.binding;if(!n||!o)throw new Error("managed_room_context_unavailable");const a=await v.status({machineToken:n,roomId:o.roomId,bindingId:o.bindingId});if(!ko(u,e)||!bo(e,a))throw new Error("managed_room_binding_unavailable");return{roomName:a.room.name,memberCount:a.room.memberCount,members:a.room.members,agentsByIdentityId:a.agent?{[a.agentIdentityId]:a.agent}:{},agentSystemPromptsByIdentityId:a.agent?{[a.agentIdentityId]:a.agent.systemPrompt??""}:{}}},issueManagedRoomContext:(e,n)=>{const o=m().machineToken;if(!o)throw new Error("machine_not_authorized");return C.issue({registryKey:e,machineCredential:o,activationCauseMessageId:n})},audit:new Eo,resolveManagedAgentPolicy:e=>Po({...e,runtime:y.find(n=>n.type===e.registration.runtimeAdapter)})}),r.scheduleHandler=e=>Ie({serverUrl:g,machineToken:m().machineToken,req:e,client:l,queue:r.getScheduleQueue(),registry:u}),r.getScheduleQueue().validateScheduledTarget=async e=>{if(!e.bindingId||!e.roomId)return"ready";if(u.getByNianSessionId(e.sessionId)?.binding?.bindingId!==e.bindingId)return"ended";const o=await v.status({machineToken:m().machineToken,roomId:e.roomId,bindingId:e.bindingId});return o.status==="active"&&o.room.status==="active"?"ready":"ended"},r.setManagedRoomTurnPreparer(e=>S.prepareConversationTurn(e)),r.setManagedAgentDirectTurnPreparer(e=>S.prepareDirectConversationTurn(e)),r.setManagedRecoveryPreparer(async e=>e.source==="managed_direct"?S.prepareDirectConversationTurn(e.sessionId):e.source!=="managed_room"||!e.roomContextRegistryKey||!e.activationCauseMessageId||!e.rootCauseMessageId||!e.activationSequence||e.activationHopCount===null?null:S.prepareConversationTurn([{registryKey:e.roomContextRegistryKey,causeMessageId:e.activationCauseMessageId,rootCauseMessageId:e.rootCauseMessageId,sequence:e.activationSequence,hopCount:e.activationHopCount}])),j.mkdirSync(me,{recursive:!0}),re(process.pid,c,{version:h}),te(process.pid,void 0,c),l.connect(),process.stdin.resume();let Y=!1;const Q=async()=>{if(!Y){Y=!0,console.log(R.gray(`
|
|
3
|
+
Disconnecting...`)),P({level:"info",wsEvent:"daemon.stop"}),clearInterval(p);try{await r.cleanup(),x.stop(),D?.stop(),M?.stop(),l.disconnect(),await Promise.allSettled([b.close(),k.close()]),ee(process.pid,c),oe(c)}finally{process.exit(0)}}};process.on("SIGINT",()=>{Q()}),process.on("SIGTERM",()=>{Q()})}),i.command("workbuddy-session-hook",{hidden:!0}).description("(retired) WorkBuddy Room Hook").allowUnknownOption(!0).action(()=>G()),i.command("room-session-hook",{hidden:!0}).description("(internal) Authorize the official Room tool for one trusted Agent Session").argument("<runtime>","Trusted runtime adapter").allowUnknownOption(!0).action(()=>G()),i.command("room-tool-server",{hidden:!0}).description("(internal) Run the official Shennian Room MCP tool").allowUnknownOption(!0).action(()=>G());const pe=i.command("config").description("View or modify configuration");pe.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${Ce()}`);const t=m(),s=Ee(t,X(process.env,t));if(t.serverUrl){const p=We(t.serverUrl);console.log(`Region: ${p} (${B[p].label})`)}console.log(JSON.stringify(s,null,2))}),pe.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((t,s)=>{const p=m();if(t==="server"){s!=="cn"&&s!=="global"&&(console.error(R.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const c=s;p.serverUrl=Ke(c),we(p),console.log(R.green(`\u2713 Server set to ${B[c].label}`)),console.log(R.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(R.red(`\u2717 Unknown config key: ${t}. Supported: server`)),process.exit(1)}),Ae(i),Ue(i),Oe(i),Ve(i),Le(i),je(i),Be(i),Fe(i),i.parse();
|
|
@@ -55,6 +55,7 @@ export declare class ManagerRuntimeService {
|
|
|
55
55
|
getManagedAgentPolicyForWorker(managerSessionId: string, workDir: string): CompiledManagedAgentPolicy | null;
|
|
56
56
|
isNativeSkillManager(managerSessionId: string, workDir: string): boolean;
|
|
57
57
|
isManagedWorkerSession(sessionId: string): boolean;
|
|
58
|
+
isManagedRoomBoundManager(sessionId: string): boolean;
|
|
58
59
|
setManagerWorkerDefaults(sessionId: string, agentType?: AgentType | null, modelId?: string | null): void;
|
|
59
60
|
getManagerWorkerDefaults(sessionId: string): {
|
|
60
61
|
agentType: AgentType | null;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import _ from"node:http";import{createHash as N,randomBytes as x,randomUUID as f}from"node:crypto";import
|
|
2
|
-
`).trim()}function $(o){return o==="worker.final"?"completed":o==="worker.error"?"failed":o==="worker.aborted"?"stopped":"progress"}function U(o,e){return`manager-inbox:${N("sha256").update(o).update("\0").update(e.map(r=>r.id).join("\0")).digest("hex").slice(0,32)}`}async function j(o){const e=[];let t=0;for await(const r of o){const n=Buffer.isBuffer(r)?r:Buffer.from(r);if(t+=n.length,t>H)throw new Error("Request body too large");e.push(n)}return e.length===0?{}:JSON.parse(Buffer.concat(e).toString("utf8"))}function G(o,e,t,r){o.client.sendRes({type:"res",id:e,ok:t,...t?{payload:r}:{error:String(r.error||"unknown error")}})}function S(){return F()?y.join(v.tmpdir(),"shennian-vitest-runtime",String(process.pid),"manager-ipc.json"):P("runtime","manager-ipc.json")}function F(){return(process.env.VITEST==="true"||!!process.env.VITEST_WORKER_ID)&&!process.env.SHENNIAN_HOME?.trim()}class ue{opts;managedPolicies=new Map;registry=new T;channelRuntime;server=null;ipcUrl=null;ipcToken=x(24).toString("hex");healthTimer=null;startPromise=null;workerTextAcc=new Map;constructor(e){this.opts=e,this.channelRuntime=e.channelRuntime??new q}async start(){return this.startPromise?this.startPromise:(this.startPromise=this.doStart(),this.startPromise)}async doStart(){if(this.server)return;this.server=_.createServer((t,r)=>{this.handleIpc(t,r)}),this.server.requestTimeout=m,this.server.timeout=m,this.server.keepAliveTimeout=m,this.server.headersTimeout=m+5e3,await new Promise((t,r)=>{this.server.once("error",r),this.server.listen(0,"127.0.0.1",()=>t())});const e=this.server.address();typeof e=="object"&&e&&(this.ipcUrl=`http://127.0.0.1:${e.port}`,this.writeIpcRuntimeFile()),this.server.unref(),await this.channelRuntime.start(),this.healthTimer=setInterval(()=>this.scanWorkerHealth(),6e4),this.healthTimer.unref(),this.recoverPersistedInboxDeliveries()}async ready(){await this.start()}async stop(){this.healthTimer&&clearInterval(this.healthTimer),this.healthTimer=null,await this.channelRuntime.stop(),await new Promise(e=>{if(!this.server)return e();this.server.close(()=>e())}),this.server=null,this.ipcUrl=null,this.removeIpcRuntimeFile()}writeIpcRuntimeFile(){if(this.ipcUrl)try{const e=S();
|
|
1
|
+
import _ from"node:http";import{createHash as N,randomBytes as x,randomUUID as f}from"node:crypto";import g from"node:fs";import v from"node:os";import y from"node:path";import{ManagerRegistry as T}from"./registry.js";import{appendMessage as D}from"../session/store.js";import{requestSessionIndexPublish as W}from"../session/index-publisher.js";import{RetiredChannelRuntime as q}from"./retired-external-channel-compat.js";import{resolveShennianPath as P}from"../config/index.js";import{buildExternalChannelInstructions as B}from"../agents/external-channel-instructions.js";import{getPersonalSyncIdentity as I}from"../personal-sync/epoch.js";import{handleWorkerIpcRoute as E}from"./worker-ipc.js";import{deriveWorkerTitle as O,formatWorkerMarkdown as C}from"./worker-markdown.js";const H=Number(process.env.SHENNIAN_MANAGER_IPC_BODY_MAX_BYTES||2*1024*1024),m=12*6e4;let R=null;function ae(o){R=o}function oe(){return R}function h(o){return y.resolve(o||v.homedir())}function c(o,e,t){o.writeHead(e,{"content-type":"application/json; charset=utf-8"}),o.end(JSON.stringify(t))}function M(o){return o.replace(/\r\n/g,`
|
|
2
|
+
`).trim()}function $(o){return o==="worker.final"?"completed":o==="worker.error"?"failed":o==="worker.aborted"?"stopped":"progress"}function U(o,e){return`manager-inbox:${N("sha256").update(o).update("\0").update(e.map(r=>r.id).join("\0")).digest("hex").slice(0,32)}`}async function j(o){const e=[];let t=0;for await(const r of o){const n=Buffer.isBuffer(r)?r:Buffer.from(r);if(t+=n.length,t>H)throw new Error("Request body too large");e.push(n)}return e.length===0?{}:JSON.parse(Buffer.concat(e).toString("utf8"))}function G(o,e,t,r){o.client.sendRes({type:"res",id:e,ok:t,...t?{payload:r}:{error:String(r.error||"unknown error")}})}function S(){return F()?y.join(v.tmpdir(),"shennian-vitest-runtime",String(process.pid),"manager-ipc.json"):P("runtime","manager-ipc.json")}function F(){return(process.env.VITEST==="true"||!!process.env.VITEST_WORKER_ID)&&!process.env.SHENNIAN_HOME?.trim()}class ue{opts;managedPolicies=new Map;registry=new T;channelRuntime;server=null;ipcUrl=null;ipcToken=x(24).toString("hex");healthTimer=null;startPromise=null;workerTextAcc=new Map;constructor(e){this.opts=e,this.channelRuntime=e.channelRuntime??new q}async start(){return this.startPromise?this.startPromise:(this.startPromise=this.doStart(),this.startPromise)}async doStart(){if(this.server)return;this.server=_.createServer((t,r)=>{this.handleIpc(t,r)}),this.server.requestTimeout=m,this.server.timeout=m,this.server.keepAliveTimeout=m,this.server.headersTimeout=m+5e3,await new Promise((t,r)=>{this.server.once("error",r),this.server.listen(0,"127.0.0.1",()=>t())});const e=this.server.address();typeof e=="object"&&e&&(this.ipcUrl=`http://127.0.0.1:${e.port}`,this.writeIpcRuntimeFile()),this.server.unref(),await this.channelRuntime.start(),this.healthTimer=setInterval(()=>this.scanWorkerHealth(),6e4),this.healthTimer.unref(),this.recoverPersistedInboxDeliveries()}async ready(){await this.start()}async stop(){this.healthTimer&&clearInterval(this.healthTimer),this.healthTimer=null,await this.channelRuntime.stop(),await new Promise(e=>{if(!this.server)return e();this.server.close(()=>e())}),this.server=null,this.ipcUrl=null,this.removeIpcRuntimeFile()}writeIpcRuntimeFile(){if(this.ipcUrl)try{const e=S();g.mkdirSync(y.dirname(e),{recursive:!0}),g.writeFileSync(e,JSON.stringify({url:this.ipcUrl,token:this.ipcToken,pid:process.pid,updatedAt:new Date().toISOString()},null,2),{mode:384}),g.chmodSync(e,384)}catch{}}removeIpcRuntimeFile(){try{const e=S(),t=JSON.parse(g.readFileSync(e,"utf-8"));(t.url===this.ipcUrl||t.token===this.ipcToken)&&g.unlinkSync(e)}catch{}}getInjectedEnv(e,t,r,n){return this.ipcUrl?{SHENNIAN_MANAGER_SESSION_ID:e,SHENNIAN_MANAGER_AGENT_SESSION_ID:t??"",SHENNIAN_MANAGER_WORKDIR:h(r),SHENNIAN_MANAGER_MODEL:n,SHENNIAN_MANAGER_IPC_URL:this.ipcUrl,SHENNIAN_MANAGER_IPC_TOKEN:this.ipcToken}:{}}registerManager(e){this.registry.upsertManager({...e,workDir:h(e.workDir),machineId:process.env.SHENNIAN_MACHINE_ID??null,managedRoomBound:e.managedRoomBound??(this.managedPolicies.has(e.sessionId)||void 0)})}setManagedAgentPolicy(e,t){if(t){this.managedPolicies.set(e,t);const r=this.registry.getManager(e);r&&!r.managedRoomBound&&this.registry.upsertManager({...r,managedRoomBound:!0})}else this.managedPolicies.delete(e)}getManagedAgentPolicyForWorker(e,t){const r=this.registry.getManager(e),n=this.managedPolicies.get(e);return!r||!n||h(t)!==r.workDir?null:n}isNativeSkillManager(e,t){const r=this.registry.getManager(e);return r?.controllerKind==="native_skill"&&h(t)===r.workDir}isManagedWorkerSession(e){return!!this.findWorker(e)}isManagedRoomBoundManager(e){return this.registry.getManager(e)?.managedRoomBound===!0}setManagerWorkerDefaults(e,t,r){const n=this.registry.getManager(e);n&&this.registry.upsertManager({...n,defaultWorkerAgentType:t??null,defaultWorkerModelId:r??null})}getManagerWorkerDefaults(e){const t=this.registry.getManager(e);return{agentType:t?.defaultWorkerAgentType??null,modelId:t?.defaultWorkerModelId??null}}noteManagerAgentSession(e,t,r,n){const s=this.registry.getManager(e);this.registry.upsertManager({sessionId:e,agentSessionId:t,workDir:h(r),machineId:process.env.SHENNIAN_MACHINE_ID??null,modelId:n,agentType:s?.agentType,providerModelId:s?.providerModelId})}noteAgentEvent(e,t){const r=this.findWorker(e);if(!r)return;const n={lastActivityAt:new Date().toISOString(),runId:t.runId};t.agentSessionId&&(n.agentSessionId=t.agentSessionId);const s=`${e}:${t.runId}`;let i=t.message||r.summary||"(\u65E0\u53EF\u89C1\u5185\u5BB9)";if(t.state==="delta"&&t.text&&!t.thinking){const u=(this.workerTextAcc.get(s)??"")+t.text;this.workerTextAcc.set(s,u);const a=M(u);a&&(n.summary=a.length>160?`${a.slice(0,160)}...`:a)}if(t.state==="final"||t.state==="error"||t.state==="aborted"){n.status=t.state;const u=M(this.workerTextAcc.get(s)??"");u&&(n.summary=u.length>240?`${u.slice(0,240)}...`:u,i=t.message||u),this.workerTextAcc.delete(s)}else t.state==="start"&&(n.status="running");const d=this.registry.updateWorker(e,n);d&&(t.state==="final"||t.state==="error"||t.state==="aborted")&&this.enqueueWorkerEvent(d.managedBy,d,t.state,t.runId,i)}findWorker(e){return this.registry.load().workers[e]}async handleAppReq(e){G(this.opts.getRuntime(),e.id,!1,{error:"feature_retired"})}async handleIpc(e,t){if(e.headers.authorization!==`Bearer ${this.ipcToken}`){c(t,401,{ok:!1,error:"Unauthorized"});return}try{const r=new URL(e.url??"/","http://127.0.0.1"),n=await j(e);if(r.pathname.startsWith("/channel/")||r.pathname.startsWith("/external/")||r.pathname.startsWith("/wechat-rpa/")){c(t,410,{ok:!1,error:"feature_retired"});return}const s=await E({registry:this.registry,getRuntime:this.opts.getRuntime,dispatchReq:this.opts.dispatchReq,dispatchChatEnqueue:this.dispatchChatEnqueue.bind(this),appendManagerVisibleMarkdown:this.appendManagerVisibleMarkdown.bind(this)},r.pathname,n,String(e.headers["x-shennian-manager-session-id"]||""));if(s){c(t,s.status,s.body);return}c(t,404,{ok:!1,error:`Unknown manager IPC path: ${r.pathname}`})}catch(r){c(t,400,{ok:!1,error:r instanceof Error?r.message:String(r)})}}async executeScopedWorkerAction(e,t,r){const n={"manager.sessions.list":"/sessions/list","manager.sessions.start":"/sessions/start","manager.sessions.send":"/sessions/send","manager.sessions.queue":"/sessions/queue","manager.sessions.queue.edit":"/sessions/queue/edit","manager.sessions.queue.delete":"/sessions/queue/delete","manager.sessions.stop":"/sessions/stop","manager.sessions.read":"/sessions/read","manager.memory.path":"/memory/path"},s=await E({registry:this.registry,getRuntime:this.opts.getRuntime,dispatchReq:this.opts.dispatchReq,dispatchChatEnqueue:this.dispatchChatEnqueue.bind(this),appendManagerVisibleMarkdown:this.appendManagerVisibleMarkdown.bind(this)},n[t],r,e);if(!s||s.status<200||s.status>=300)throw new Error(String(s?.body.error||"Managed Manager action failed"));return JSON.parse(JSON.stringify(s.body))}async dispatchChatEnqueue(e,t,r,n,s,i,d){if((await this.opts.dispatchReq({type:"req",id:`manager-enqueue-${f()}`,method:"chat.enqueue",params:{...I(),sessionId:e,text:n,agentType:t,workDir:r,agentSessionId:s,modelId:i,managedWorkerParentSessionId:d}}))?.durableQueueHandoff===!1)throw new Error("manager_worker_queue_handoff_unconfirmed")}appendManagerVisibleMarkdown(e,t,r){this.registry.getManager(e)?.controllerKind!=="native_skill"&&(D(e,{id:r,sessionId:e,role:"agent",ts:Date.now(),payload:t},"committed"),W(this.opts.getRuntime().client))}enqueueWorkerEvent(e,t,r,n,s){const i=this.registry.enqueueInboxEvent({managerSessionId:e,workerSessionId:t.sessionId,kind:r==="final"?"worker.final":r==="error"?"worker.error":"worker.aborted",priority:"normal",runId:n??null,summary:s||t.summary||"(\u65E0\u53EF\u89C1\u6458\u8981)"}),d=this.registry.getManager(e);i&&d?.controllerKind!=="native_skill"&&this.drainManagerInbox(e)}scanWorkerHealth(){const e=Date.now(),t=this.registry.load(),r=this.opts.getRuntime();for(const n of Object.values(t.workers)){if(n.status!=="running")continue;const s=e-Date.parse(n.createdAt);if(s<10*6e4)continue;const i=e-Date.parse(n.lastActivityAt),d=r.sessions.get(n.sessionId)?.currentRunId,u=!!r.chatQueue?.getSnapshot(n.sessionId).pending.length;if(!d){if(!u&&i>=10*6e4){const w="\u672A\u627E\u5230\u6D3B\u52A8\u4E2D\u7684 Provider Run \u6216\u5F85\u5904\u7406\u6D88\u606F\uFF1B\u5DF2\u5C06\u9057\u7559\u7684\u8FD0\u884C\u72B6\u6001\u6536\u655B\u4E3A\u5931\u8D25\u3002\u539F Worker \u4F1A\u8BDD\u4ECD\u4FDD\u7559\uFF0C\u53EF\u7EE7\u7EED\u53D1\u9001\u65B0\u6D88\u606F\u3002",p=this.registry.updateWorker(n.sessionId,{status:"error",lastActivityAt:new Date(e).toISOString(),summary:w});p&&this.enqueueWorkerEvent(p.managedBy,p,"error",n.runId??void 0,w)}continue}const a=n.healthNotifiedAt?Date.parse(n.healthNotifiedAt):0;if(a&&e-a<10*6e4)continue;const l=t.managers[n.managedBy];if(!l)continue;const A=Math.max(0,Math.floor(i/6e4)),b=M(n.runId?this.workerTextAcc.get(`${n.sessionId}:${n.runId}`)??"":""),k=`\u5DF2\u8FD0\u884C ${Math.floor(s/6e4)} \u5206\u949F\uFF0C\u5C1A\u672A\u7ED3\u675F\u3002
|
|
3
3
|
|
|
4
4
|
\u5F53\u524D\u53EF\u89C1\u8FDB\u5C55\uFF1A
|
|
5
5
|
- \u6700\u8FD1\u6587\u672C\uFF1A${b||n.summary||"(\u65E0\u53EF\u89C1\u5185\u5BB9)"}
|
|
6
6
|
- \u6700\u8FD1\u6D3B\u52A8\u65F6\u95F4\uFF1A${n.lastActivityAt}
|
|
7
|
-
- \u6700\u8FD1 ${A} \u5206\u949F\u6CA1\u6709\u65B0\u6D3B\u52A8\u3002`;this.registry.updateWorker(n.sessionId,{healthNotifiedAt:new Date(e).toISOString(),lastHealthSummary:k}),this.registry.enqueueInboxEvent({managerSessionId:l.sessionId,workerSessionId:n.sessionId,kind:"worker.health",priority:"normal",runId:n.runId??null,summary:k})&&l.controllerKind!=="native_skill"&&this.drainManagerInbox(l.sessionId)}}async interruptAndResumeManager(e,t,r){this.opts.getRuntime().sessions.get(e.sessionId)?.currentRunId&&await this.opts.dispatchReq({type:"req",id:`manager-interrupt-${f()}`,method:"chat.abort",params:{...I(),sessionId:e.sessionId}}),await this.dispatchManagerContinuation(e,t,!1,r)}bindManagerAdapterEvents(e,t){t.on("agentEvent",r=>{if(r.state==="start"&&r.agentSessionId){const n=this.registry.getManager(e);n&&this.noteManagerAgentSession(e,r.agentSessionId,n.workDir,n.modelId)}r.state==="start"&&(this.acknowledgeManagerInboxDelivery(e),this.updateManagerStatus(e,"running")),(r.state==="final"||r.state==="error"||r.state==="aborted")&&(this.updateManagerStatus(e,"idle"),queueMicrotask(()=>{this.drainManagerInbox(e)}))})}updateManagerStatus(e,t){const r=this.registry.getManager(e);r&&this.registry.upsertManager({...r,status:t})}async drainManagerInbox(e){const t=this.registry.getManager(e);if(!t||t.deliveringInboxEventIds?.length)return;const r=this.registry.listInboxEvents(e);if(!r.length)return;const n=r.find(a=>a.priority==="high"),s=this.opts.getRuntime().sessions.get(e);if(t.status!=="idle"&&!n||s?.currentRunId&&!n)return;const i=n?[n]:r.slice(0,20),d=i.map(a=>{const l=this.registry.getWorkerForManager(e,a.workerSessionId);return
|
|
7
|
+
- \u6700\u8FD1 ${A} \u5206\u949F\u6CA1\u6709\u65B0\u6D3B\u52A8\u3002`;this.registry.updateWorker(n.sessionId,{healthNotifiedAt:new Date(e).toISOString(),lastHealthSummary:k}),this.registry.enqueueInboxEvent({managerSessionId:l.sessionId,workerSessionId:n.sessionId,kind:"worker.health",priority:"normal",runId:n.runId??null,summary:k})&&l.controllerKind!=="native_skill"&&this.drainManagerInbox(l.sessionId)}}async interruptAndResumeManager(e,t,r){this.opts.getRuntime().sessions.get(e.sessionId)?.currentRunId&&await this.opts.dispatchReq({type:"req",id:`manager-interrupt-${f()}`,method:"chat.abort",params:{...I(),sessionId:e.sessionId}}),await this.dispatchManagerContinuation(e,t,!1,r)}bindManagerAdapterEvents(e,t){t.on("agentEvent",r=>{if(r.state==="start"&&r.agentSessionId){const n=this.registry.getManager(e);n&&this.noteManagerAgentSession(e,r.agentSessionId,n.workDir,n.modelId)}r.state==="start"&&(this.acknowledgeManagerInboxDelivery(e),this.updateManagerStatus(e,"running")),(r.state==="final"||r.state==="error"||r.state==="aborted")&&(this.updateManagerStatus(e,"idle"),queueMicrotask(()=>{this.drainManagerInbox(e)}))})}updateManagerStatus(e,t){const r=this.registry.getManager(e);r&&this.registry.upsertManager({...r,status:t})}async drainManagerInbox(e){const t=this.registry.getManager(e);if(!t||t.deliveringInboxEventIds?.length)return;const r=this.registry.listInboxEvents(e);if(!r.length)return;const n=r.find(a=>a.priority==="high"),s=this.opts.getRuntime().sessions.get(e);if(t.status!=="idle"&&!n||s?.currentRunId&&!n)return;const i=n?[n]:r.slice(0,20),d=i.map(a=>{const l=this.registry.getWorkerForManager(e,a.workerSessionId);return C({kind:$(a.kind),sessionId:a.workerSessionId,title:l?.title||O(l?.userGoal||l?.summary||a.summary),body:a.summary})}).join(`
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
`),u=U(e,i);try{n&&s?.currentRunId?(this.registry.upsertManager({...t,status:"interrupting",deliveringInboxEventIds:i.map(l=>l.id)}),await this.interruptAndResumeManager(t,d,u)):(this.registry.upsertManager({...t,status:"running",deliveringInboxEventIds:i.map(l=>l.id)}),await this.dispatchManagerContinuation(t,d,!0,u)),this.registry.removeInboxEvents(e,i.map(l=>l.id));const a=this.registry.getManager(e);a&&this.registry.upsertManager({...a,deliveringInboxEventIds:[]})}catch(a){this.registry.upsertManager({...t,status:"idle",deliveringInboxEventIds:[]}),console.error(`[manager-inbox] delivery failed sessionId=${e}: ${a instanceof Error?a.message:String(a)}`)}}acknowledgeManagerInboxDelivery(e){const t=this.registry.getManager(e),r=t?.deliveringInboxEventIds??[];!t||r.length===0||(this.registry.removeInboxEvents(e,r),this.registry.upsertManager({...t,deliveringInboxEventIds:[]}))}recoverPersistedInboxDeliveries(){const e=this.registry.load(),t=this.opts.getRuntime();for(const r of Object.values(e.managers)){if(t.sessions.get(r.sessionId)?.currentRunId)continue;(r.status!=="idle"||r.deliveringInboxEventIds?.length)&&this.registry.upsertManager({...r,status:"idle",deliveringInboxEventIds:[]});const s=this.registry.listInboxEvents(r.sessionId).filter(i=>i.kind==="worker.health"&&!t.sessions.get(i.workerSessionId)?.currentRunId).map(i=>i.id);this.registry.removeInboxEvents(r.sessionId,s),this.registry.listInboxEvents(r.sessionId).length>0&&queueMicrotask(()=>{this.drainManagerInbox(r.sessionId)})}}async dispatchManagerContinuation(e,t,r=!1,n){const s=e.agentType??"manager",i=s==="manager"?e.modelId:e.providerModelId??void 0,d={...I(),sessionId:e.sessionId,text:t,agentType:s,sessionMode:"manager",workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:i,managerDefaultWorkerAgentType:e.defaultWorkerAgentType??null,managerDefaultWorkerModelId:e.defaultWorkerModelId??null,...e.managedRoomBound?{managedAgentDirect:!0}:{},clientMessageId:n,managerEventId:n};if((await this.opts.dispatchReq({type:"req",id:`manager-${r?"enqueue":"send"}-${f()}`,method:"chat.enqueue",params:d}))?.durableQueueHandoff===!1)throw new Error("manager_event_queue_handoff_unconfirmed")}getExternalChannelStatus(e){return this.channelRuntime.getManagerChannelStatus(e)}getManagerExternalChannelSystemPrompt(e){return this.channelRuntime.listManagerExternalChannels(e).map(t=>
|
|
11
|
+
`),u=U(e,i);try{n&&s?.currentRunId?(this.registry.upsertManager({...t,status:"interrupting",deliveringInboxEventIds:i.map(l=>l.id)}),await this.interruptAndResumeManager(t,d,u)):(this.registry.upsertManager({...t,status:"running",deliveringInboxEventIds:i.map(l=>l.id)}),await this.dispatchManagerContinuation(t,d,!0,u)),this.registry.removeInboxEvents(e,i.map(l=>l.id));const a=this.registry.getManager(e);a&&this.registry.upsertManager({...a,deliveringInboxEventIds:[]})}catch(a){this.registry.upsertManager({...t,status:"idle",deliveringInboxEventIds:[]}),console.error(`[manager-inbox] delivery failed sessionId=${e}: ${a instanceof Error?a.message:String(a)}`)}}acknowledgeManagerInboxDelivery(e){const t=this.registry.getManager(e),r=t?.deliveringInboxEventIds??[];!t||r.length===0||(this.registry.removeInboxEvents(e,r),this.registry.upsertManager({...t,deliveringInboxEventIds:[]}))}recoverPersistedInboxDeliveries(){const e=this.registry.load(),t=this.opts.getRuntime();for(const r of Object.values(e.managers)){if(t.sessions.get(r.sessionId)?.currentRunId)continue;(r.status!=="idle"||r.deliveringInboxEventIds?.length)&&this.registry.upsertManager({...r,status:"idle",deliveringInboxEventIds:[]});const s=this.registry.listInboxEvents(r.sessionId).filter(i=>i.kind==="worker.health"&&!t.sessions.get(i.workerSessionId)?.currentRunId).map(i=>i.id);this.registry.removeInboxEvents(r.sessionId,s),this.registry.listInboxEvents(r.sessionId).length>0&&queueMicrotask(()=>{this.drainManagerInbox(r.sessionId)})}}async dispatchManagerContinuation(e,t,r=!1,n){const s=e.agentType??"manager",i=s==="manager"?e.modelId:e.providerModelId??void 0,d={...I(),sessionId:e.sessionId,text:t,agentType:s,sessionMode:"manager",workDir:e.workDir,agentSessionId:e.agentSessionId,modelId:i,managerDefaultWorkerAgentType:e.defaultWorkerAgentType??null,managerDefaultWorkerModelId:e.defaultWorkerModelId??null,...e.managedRoomBound?{managedAgentDirect:!0}:{},clientMessageId:n,managerEventId:n};if((await this.opts.dispatchReq({type:"req",id:`manager-${r?"enqueue":"send"}-${f()}`,method:"chat.enqueue",params:d}))?.durableQueueHandoff===!1)throw new Error("manager_event_queue_handoff_unconfirmed")}getExternalChannelStatus(e){return this.channelRuntime.getManagerChannelStatus(e)}getManagerExternalChannelSystemPrompt(e){return this.channelRuntime.listManagerExternalChannels(e).map(t=>B(t,void 0,e,"manager")).join(`
|
|
12
12
|
|
|
13
13
|
`).trim()}}export{ue as ManagerRuntimeService,oe as getManagerRuntimeService,ae as setManagerRuntimeService};
|