shennian 0.3.63 → 0.3.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/publish-build-manifest.json +78 -63
  2. package/dist/src/agents/adapter.d.ts +5 -1
  3. package/dist/src/agents/claude.d.ts +3 -2
  4. package/dist/src/agents/claude.js +6 -6
  5. package/dist/src/agents/workbuddy.d.ts +3 -2
  6. package/dist/src/agents/workbuddy.js +2 -2
  7. package/dist/src/index.js +3 -3
  8. package/dist/src/manager/runtime.js +8 -8
  9. package/dist/src/native-fusion/codex-files.d.ts +2 -0
  10. package/dist/src/native-fusion/codex-files.js +1 -0
  11. package/dist/src/native-fusion/codex-parser.d.ts +1 -2
  12. package/dist/src/native-fusion/codex-parser.js +3 -5
  13. package/dist/src/native-fusion/codex-user-input.d.ts +11 -0
  14. package/dist/src/native-fusion/codex-user-input.js +5 -0
  15. package/dist/src/native-fusion/file-watcher.d.ts +13 -5
  16. package/dist/src/native-fusion/file-watcher.js +1 -1
  17. package/dist/src/native-fusion/local-repository.d.ts +2 -0
  18. package/dist/src/native-fusion/local-repository.js +2 -2
  19. package/dist/src/native-fusion/parser-common.d.ts +1 -0
  20. package/dist/src/native-fusion/parser-common.js +4 -4
  21. package/dist/src/native-fusion/parsers.d.ts +1 -0
  22. package/dist/src/native-fusion/parsers.js +2 -2
  23. package/dist/src/native-fusion/service.d.ts +3 -0
  24. package/dist/src/native-fusion/service.js +2 -2
  25. package/dist/src/native-fusion/state.js +2 -2
  26. package/dist/src/native-fusion/types.d.ts +4 -0
  27. package/dist/src/personal-sync/epoch.d.ts +17 -0
  28. package/dist/src/personal-sync/epoch.js +2 -0
  29. package/dist/src/personal-sync/identity.js +2 -2
  30. package/dist/src/personal-sync/machine-authority.d.ts +11 -0
  31. package/dist/src/personal-sync/machine-authority.js +1 -0
  32. package/dist/src/personal-sync/metrics.d.ts +7 -1
  33. package/dist/src/personal-sync/metrics.js +1 -1
  34. package/dist/src/personal-sync/paths.d.ts +2 -5
  35. package/dist/src/personal-sync/paths.js +1 -1
  36. package/dist/src/relay/client.d.ts +8 -2
  37. package/dist/src/relay/client.js +1 -1
  38. package/dist/src/session/attachment-transfer-store.d.ts +10 -3
  39. package/dist/src/session/canonical-store.d.ts +2 -0
  40. package/dist/src/session/canonical-store.js +5 -5
  41. package/dist/src/session/deletion-sync-state.d.ts +18 -0
  42. package/dist/src/session/deletion-sync-state.js +2 -2
  43. package/dist/src/session/handlers/chat.js +2 -2
  44. package/dist/src/session/handlers/fs.js +1 -1
  45. package/dist/src/session/handlers/message-status.js +1 -1
  46. package/dist/src/session/handlers/title.js +1 -1
  47. package/dist/src/session/handlers/tool-detail.js +1 -1
  48. package/dist/src/session/handlers/voice-window.js +1 -1
  49. package/dist/src/session/history-subscriptions.js +1 -1
  50. package/dist/src/session/index-publisher.d.ts +2 -2
  51. package/dist/src/session/index-publisher.js +1 -1
  52. package/dist/src/session/manager.d.ts +1 -0
  53. package/dist/src/session/manager.js +1 -1
  54. package/dist/src/session/native-session-lifecycle.js +4 -4
  55. package/dist/src/session/queue.d.ts +1 -0
  56. package/dist/src/session/queue.js +4 -4
  57. package/dist/src/session/store.d.ts +16 -0
  58. package/dist/src/session/store.js +2 -2
  59. package/node_modules/@shennian/wire/dist/frames.d.ts +3 -0
  60. package/node_modules/@shennian/wire/dist/fs.d.ts +16 -6
  61. package/node_modules/@shennian/wire/dist/machine.d.ts +2 -0
  62. package/node_modules/@shennian/wire/dist/message-payload.js +2 -0
  63. package/node_modules/@shennian/wire/dist/session-sync.d.ts +76 -33
  64. package/node_modules/@shennian/wire/dist/session-sync.js +50 -2
  65. package/node_modules/@shennian/wire/dist/session.d.ts +20 -10
  66. package/node_modules/@shennian/wire/dist/tool-detail.d.ts +3 -2
  67. package/node_modules/@shennian/wire/package.json +1 -1
  68. package/package.json +1 -1
  69. package/dist/src/personal-sync/account-namespace.d.ts +0 -6
  70. package/dist/src/personal-sync/account-namespace.js +0 -1
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 128,
5
+ "fileCount": 131,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian.js",
@@ -21,8 +21,8 @@
21
21
  },
22
22
  {
23
23
  "file": "src/agents/claude.js",
24
- "beforeBytes": 11959,
25
- "afterBytes": 6164
24
+ "beforeBytes": 12169,
25
+ "afterBytes": 6313
26
26
  },
27
27
  {
28
28
  "file": "src/agents/codex-utils.js",
@@ -136,8 +136,8 @@
136
136
  },
137
137
  {
138
138
  "file": "src/agents/workbuddy.js",
139
- "beforeBytes": 14265,
140
- "afterBytes": 7150
139
+ "beforeBytes": 14475,
140
+ "afterBytes": 7299
141
141
  },
142
142
  {
143
143
  "file": "src/commands/daemon-process.js",
@@ -276,8 +276,8 @@
276
276
  },
277
277
  {
278
278
  "file": "src/index.js",
279
- "beforeBytes": 23134,
280
- "afterBytes": 12013
279
+ "beforeBytes": 24052,
280
+ "afterBytes": 12458
281
281
  },
282
282
  {
283
283
  "file": "src/log-reporter.js",
@@ -301,13 +301,23 @@
301
301
  },
302
302
  {
303
303
  "file": "src/manager/runtime.js",
304
- "beforeBytes": 71949,
305
- "afterBytes": 36578
304
+ "beforeBytes": 72214,
305
+ "afterBytes": 36669
306
+ },
307
+ {
308
+ "file": "src/native-fusion/codex-files.js",
309
+ "beforeBytes": 2623,
310
+ "afterBytes": 1339
306
311
  },
307
312
  {
308
313
  "file": "src/native-fusion/codex-parser.js",
309
- "beforeBytes": 30367,
310
- "afterBytes": 12930
314
+ "beforeBytes": 28748,
315
+ "afterBytes": 11925
316
+ },
317
+ {
318
+ "file": "src/native-fusion/codex-user-input.js",
319
+ "beforeBytes": 4098,
320
+ "afterBytes": 1925
311
321
  },
312
322
  {
313
323
  "file": "src/native-fusion/config.js",
@@ -316,13 +326,13 @@
316
326
  },
317
327
  {
318
328
  "file": "src/native-fusion/file-watcher.js",
319
- "beforeBytes": 2954,
320
- "afterBytes": 1278
329
+ "beforeBytes": 7353,
330
+ "afterBytes": 3024
321
331
  },
322
332
  {
323
333
  "file": "src/native-fusion/local-repository.js",
324
- "beforeBytes": 24537,
325
- "afterBytes": 12150
334
+ "beforeBytes": 25241,
335
+ "afterBytes": 12409
326
336
  },
327
337
  {
328
338
  "file": "src/native-fusion/native-source-deletions.js",
@@ -336,28 +346,28 @@
336
346
  },
337
347
  {
338
348
  "file": "src/native-fusion/parser-common.js",
339
- "beforeBytes": 7739,
340
- "afterBytes": 3552
349
+ "beforeBytes": 8685,
350
+ "afterBytes": 3912
341
351
  },
342
352
  {
343
353
  "file": "src/native-fusion/parsers.js",
344
- "beforeBytes": 5543,
345
- "afterBytes": 3005
354
+ "beforeBytes": 5850,
355
+ "afterBytes": 3235
346
356
  },
347
357
  {
348
358
  "file": "src/native-fusion/service.js",
349
- "beforeBytes": 26155,
350
- "afterBytes": 12343
359
+ "beforeBytes": 29648,
360
+ "afterBytes": 13788
351
361
  },
352
362
  {
353
363
  "file": "src/native-fusion/session-header.js",
354
- "beforeBytes": 4283,
364
+ "beforeBytes": 4294,
355
365
  "afterBytes": 1996
356
366
  },
357
367
  {
358
368
  "file": "src/native-fusion/state.js",
359
- "beforeBytes": 3489,
360
- "afterBytes": 1745
369
+ "beforeBytes": 4112,
370
+ "afterBytes": 2111
361
371
  },
362
372
  {
363
373
  "file": "src/native-fusion/types.js",
@@ -365,24 +375,29 @@
365
375
  "afterBytes": 60
366
376
  },
367
377
  {
368
- "file": "src/personal-sync/account-namespace.js",
369
- "beforeBytes": 1412,
370
- "afterBytes": 879
378
+ "file": "src/personal-sync/epoch.js",
379
+ "beforeBytes": 8116,
380
+ "afterBytes": 3955
371
381
  },
372
382
  {
373
383
  "file": "src/personal-sync/identity.js",
374
- "beforeBytes": 1928,
375
- "afterBytes": 1024
384
+ "beforeBytes": 2427,
385
+ "afterBytes": 1324
386
+ },
387
+ {
388
+ "file": "src/personal-sync/machine-authority.js",
389
+ "beforeBytes": 1835,
390
+ "afterBytes": 1127
376
391
  },
377
392
  {
378
393
  "file": "src/personal-sync/metrics.js",
379
- "beforeBytes": 1504,
380
- "afterBytes": 904
394
+ "beforeBytes": 2258,
395
+ "afterBytes": 1391
381
396
  },
382
397
  {
383
398
  "file": "src/personal-sync/paths.js",
384
- "beforeBytes": 1345,
385
- "afterBytes": 830
399
+ "beforeBytes": 910,
400
+ "afterBytes": 479
386
401
  },
387
402
  {
388
403
  "file": "src/region.js",
@@ -391,8 +406,8 @@
391
406
  },
392
407
  {
393
408
  "file": "src/relay/client.js",
394
- "beforeBytes": 12612,
395
- "afterBytes": 6310
409
+ "beforeBytes": 14515,
410
+ "afterBytes": 7173
396
411
  },
397
412
  {
398
413
  "file": "src/room/activation-audit.js",
@@ -506,13 +521,13 @@
506
521
  },
507
522
  {
508
523
  "file": "src/session/canonical-store.js",
509
- "beforeBytes": 29295,
510
- "afterBytes": 14384
524
+ "beforeBytes": 31550,
525
+ "afterBytes": 15208
511
526
  },
512
527
  {
513
528
  "file": "src/session/deletion-sync-state.js",
514
- "beforeBytes": 2411,
515
- "afterBytes": 1389
529
+ "beforeBytes": 5030,
530
+ "afterBytes": 2897
516
531
  },
517
532
  {
518
533
  "file": "src/session/handlers/agent-capabilities.js",
@@ -531,8 +546,8 @@
531
546
  },
532
547
  {
533
548
  "file": "src/session/handlers/chat.js",
534
- "beforeBytes": 34791,
535
- "afterBytes": 14783
549
+ "beforeBytes": 35022,
550
+ "afterBytes": 14909
536
551
  },
537
552
  {
538
553
  "file": "src/session/handlers/control.js",
@@ -541,13 +556,13 @@
541
556
  },
542
557
  {
543
558
  "file": "src/session/handlers/fs.js",
544
- "beforeBytes": 20840,
545
- "afterBytes": 10026
559
+ "beforeBytes": 21924,
560
+ "afterBytes": 10383
546
561
  },
547
562
  {
548
563
  "file": "src/session/handlers/message-status.js",
549
- "beforeBytes": 561,
550
- "afterBytes": 313
564
+ "beforeBytes": 676,
565
+ "afterBytes": 392
551
566
  },
552
567
  {
553
568
  "file": "src/session/handlers/room-managed.js",
@@ -561,33 +576,33 @@
561
576
  },
562
577
  {
563
578
  "file": "src/session/handlers/title.js",
564
- "beforeBytes": 3013,
565
- "afterBytes": 1583
579
+ "beforeBytes": 3128,
580
+ "afterBytes": 1668
566
581
  },
567
582
  {
568
583
  "file": "src/session/handlers/tool-detail.js",
569
- "beforeBytes": 6010,
570
- "afterBytes": 3159
584
+ "beforeBytes": 6399,
585
+ "afterBytes": 3357
571
586
  },
572
587
  {
573
588
  "file": "src/session/handlers/voice-window.js",
574
- "beforeBytes": 2324,
575
- "afterBytes": 1105
589
+ "beforeBytes": 2556,
590
+ "afterBytes": 1252
576
591
  },
577
592
  {
578
593
  "file": "src/session/history-subscriptions.js",
579
- "beforeBytes": 8069,
580
- "afterBytes": 4010
594
+ "beforeBytes": 8639,
595
+ "afterBytes": 4283
581
596
  },
582
597
  {
583
598
  "file": "src/session/index-publisher.js",
584
- "beforeBytes": 3275,
585
- "afterBytes": 1470
599
+ "beforeBytes": 7582,
600
+ "afterBytes": 3747
586
601
  },
587
602
  {
588
603
  "file": "src/session/manager.js",
589
- "beforeBytes": 25643,
590
- "afterBytes": 13365
604
+ "beforeBytes": 27929,
605
+ "afterBytes": 14336
591
606
  },
592
607
  {
593
608
  "file": "src/session/native-cleanup-outbox.js",
@@ -596,8 +611,8 @@
596
611
  },
597
612
  {
598
613
  "file": "src/session/native-session-lifecycle.js",
599
- "beforeBytes": 14173,
600
- "afterBytes": 6442
614
+ "beforeBytes": 14160,
615
+ "afterBytes": 6446
601
616
  },
602
617
  {
603
618
  "file": "src/session/projection.js",
@@ -606,13 +621,13 @@
606
621
  },
607
622
  {
608
623
  "file": "src/session/queue.js",
609
- "beforeBytes": 18893,
610
- "afterBytes": 8613
624
+ "beforeBytes": 19312,
625
+ "afterBytes": 8831
611
626
  },
612
627
  {
613
628
  "file": "src/session/store.js",
614
- "beforeBytes": 21755,
615
- "afterBytes": 11408
629
+ "beforeBytes": 25840,
630
+ "afterBytes": 13364
616
631
  },
617
632
  {
618
633
  "file": "src/session/tool-detail-store.js",
@@ -33,6 +33,10 @@ export type AgentSendResult = {
33
33
  export type AgentSendContext = {
34
34
  source: 'room_activation';
35
35
  };
36
+ export type AgentStartOptions = {
37
+ /** Test-only callers can disable provider-native history persistence. */
38
+ persistNativeSession?: boolean;
39
+ };
36
40
  export interface AgentAdapterEvents {
37
41
  agentEvent: [event: AgentEvent];
38
42
  error: [error: Error];
@@ -51,7 +55,7 @@ export declare abstract class AgentAdapter extends EventEmitter<AgentAdapterEven
51
55
  canStop?: boolean;
52
56
  }>;
53
57
  setTitle?(agentSessionId: string, title: string, workDir?: string): Promise<void>;
54
- abstract start(sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
58
+ abstract start(sessionId: string, workDir: string, agentSessionId?: string | null, options?: AgentStartOptions): Promise<void>;
55
59
  abstract send(text: string, modelId?: string, reasoningEffort?: string, attachments?: ChatAttachmentMeta[], systemPrompt?: string | null, context?: AgentSendContext): Promise<void | AgentSendResult>;
56
60
  abstract resume(agentSessionId: string): Promise<void>;
57
61
  abstract stop(): Promise<void>;
@@ -1,4 +1,4 @@
1
- import { AgentAdapter } from './adapter.js';
1
+ import { AgentAdapter, type AgentStartOptions } from './adapter.js';
2
2
  import type { ChatAttachmentMeta, ExternalChannelSessionStatus } from '@shennian/wire';
3
3
  export declare function normalizeClaudeModelId(modelId?: string | null): string;
4
4
  export declare function normalizeClaudeReasoningEffort(reasoningEffort?: string | null): string | undefined;
@@ -16,6 +16,7 @@ export declare class ClaudeAdapter extends AgentAdapter {
16
16
  private runId;
17
17
  private hasEmittedText;
18
18
  private terminalState;
19
+ private persistNativeSession;
19
20
  constructor(options?: {
20
21
  systemPrompt?: string;
21
22
  hidden?: boolean;
@@ -28,7 +29,7 @@ export declare class ClaudeAdapter extends AgentAdapter {
28
29
  externalChannel?: ExternalChannelSessionStatus | null;
29
30
  env?: NodeJS.ProcessEnv;
30
31
  }): void;
31
- start(sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
32
+ start(sessionId: string, workDir: string, agentSessionId?: string | null, options?: AgentStartOptions): Promise<void>;
32
33
  send(text: string, modelId?: string, reasoningEffort?: string, _attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null): Promise<void>;
33
34
  resume(agentSessionId: string): Promise<void>;
34
35
  stop(): Promise<void>;
@@ -1,8 +1,8 @@
1
- import{createInterface as f}from"node:readline";import{randomUUID as h}from"node:crypto";import{AgentAdapter as g,registerAgent as S}from"./adapter.js";import{resolveBuiltinCommand as p,spawnAgentCommand as I,spawnResolvedCommandSync as E}from"./command-spec.js";import{buildAgentProcessEnv as m}from"../agent-env.js";import{buildPlatformInstructions as c}from"./platform-instructions.js";function x(i){return i?.trim()||"default"}const y=new Set(["low","medium","high","xhigh","max"]),a=new Map;function w(i){const t=i?.trim();if(t){if(y.has(t))return t;throw new Error(`Unsupported Claude reasoning effort "${t}". Supported values: low, medium, high, xhigh, max.`)}}function $(){a.clear()}function C(i){const t=i.trim();return t?!t.includes("claude.ai connectors are disabled because"):!1}function k(){const i=p("claude");if(!i)return!1;const t=`${i.kind}:${i.path}:${i.command}:${i.args.join("\0")}`;if(a.has(t))return a.get(t)??!1;try{const e=E(i,["--help"],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,env:m()}),s=`${e.stdout??""}
2
- ${e.stderr??""}`,o=/(?:^|\s)--effort(?:\s|,|<)/.test(s);return a.set(t,o),o}catch{return a.set(t,!1),!1}}class v extends g{options;type="claude";process=null;agentSessionId=null;sessionId=null;workDir=null;seq=0;runId="";hasEmittedText=!1;terminalState="open";constructor(t={}){super(),this.options=t}externalChannel=null;shennianSessionId=null;extraEnv={};configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{}}async start(t,e,s){this.sessionId=t,this.workDir=e,this.seq=0,s&&(this.agentSessionId=s)}async send(t,e,s,o,u){await this.killProcess(),this.runId=h(),this.resetRunState();const n=["-p",t,"--output-format","stream-json","--verbose"],r=this.options.systemPrompt??c(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,u);r&&n.push("--append-system-prompt",r),this.options.hidden&&n.push("--name","Shennian Manager Substrate"),process.getuid?.()!==0&&n.push("--dangerously-skip-permissions"),n.push("--model",x(e));const l=w(s);l&&k()&&n.push("--effort",l),this.agentSessionId&&n.push("--resume",this.agentSessionId),this.spawnAndParse(n)}async resume(t){await this.killProcess(),this.agentSessionId=t,this.runId=h(),this.resetRunState();const e=["--resume",t,"--output-format","stream-json","--verbose"],s=this.options.systemPrompt??c(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0);s&&e.push("--append-system-prompt",s),this.options.hidden&&e.push("--name","Shennian Manager Substrate"),process.getuid?.()!==0&&e.push("--dangerously-skip-permissions"),this.spawnAndParse(e)}async stop(){await this.killProcess()}spawnAndParse(t){const e=p("claude");if(!e){this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?'));return}const s=I(e,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:m(this.extraEnv)});this.process=s,f({input:s.stdout}).on("line",n=>{if(n.trim())try{const r=JSON.parse(n);this.handleStreamEvent(r)}catch{}});let u="";s.stderr?.on("data",n=>{const r=n.toString();if(u+=r,this.terminalState==="open")for(const l of r.split(`
3
- `)){const d=l.trim();C(d)&&this.emitEvent({state:"delta",text:d+`
4
- `})}}),s.on("close",n=>{this.process===s&&(this.process=null,this.handleProcessClose(n,u))}),s.on("error",n=>{this.process===s&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?')):this.emit("error",n))})}handleStreamEvent(t){if(t.type==="system"&&t.subtype==="init"&&t.session_id){this.agentSessionId=t.session_id,this.emitEvent({state:"start",agentSessionId:this.agentSessionId});return}if(t.type==="system"&&t.subtype==="api_retry"&&t.error==="authentication_failed"){this.emitErrorIfOpen({state:"error",message:'Claude authentication failed. Run "claude auth login" and retry.'});return}if(t.type==="assistant"){if(t.message?.content){for(const e of t.message.content)if(e.type==="text"&&e.text){const s=this.hasEmittedText?`
1
+ import{createInterface as f}from"node:readline";import{randomUUID as d}from"node:crypto";import{AgentAdapter as g,registerAgent as S}from"./adapter.js";import{resolveBuiltinCommand as p,spawnAgentCommand as I,spawnResolvedCommandSync as E}from"./command-spec.js";import{buildAgentProcessEnv as m}from"../agent-env.js";import{buildPlatformInstructions as c}from"./platform-instructions.js";function x(i){return i?.trim()||"default"}const y=new Set(["low","medium","high","xhigh","max"]),o=new Map;function v(i){const e=i?.trim();if(e){if(y.has(e))return e;throw new Error(`Unsupported Claude reasoning effort "${e}". Supported values: low, medium, high, xhigh, max.`)}}function R(){o.clear()}function w(i){const e=i.trim();return e?!e.includes("claude.ai connectors are disabled because"):!1}function C(){const i=p("claude");if(!i)return!1;const e=`${i.kind}:${i.path}:${i.command}:${i.args.join("\0")}`;if(o.has(e))return o.get(e)??!1;try{const t=E(i,["--help"],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,env:m()}),s=`${t.stdout??""}
2
+ ${t.stderr??""}`,a=/(?:^|\s)--effort(?:\s|,|<)/.test(s);return o.set(e,a),a}catch{return o.set(e,!1),!1}}class k extends g{options;type="claude";process=null;agentSessionId=null;sessionId=null;workDir=null;seq=0;runId="";hasEmittedText=!1;terminalState="open";persistNativeSession=!0;constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{}}async start(e,t,s,a){this.sessionId=e,this.workDir=t,this.seq=0,this.persistNativeSession=a?.persistNativeSession!==!1,s&&(this.agentSessionId=s)}async send(e,t,s,a,u){await this.killProcess(),this.runId=d(),this.resetRunState();const n=["-p",e,"--output-format","stream-json","--verbose"];this.persistNativeSession||n.push("--no-session-persistence");const r=this.options.systemPrompt??c(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,u);r&&n.push("--append-system-prompt",r),this.options.hidden&&n.push("--name","Shennian Manager Substrate"),process.getuid?.()!==0&&n.push("--dangerously-skip-permissions"),n.push("--model",x(t));const l=v(s);l&&C()&&n.push("--effort",l),this.agentSessionId&&n.push("--resume",this.agentSessionId),this.spawnAndParse(n)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=d(),this.resetRunState();const t=["--resume",e,"--output-format","stream-json","--verbose"],s=this.options.systemPrompt??c(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0);s&&t.push("--append-system-prompt",s),this.options.hidden&&t.push("--name","Shennian Manager Substrate"),process.getuid?.()!==0&&t.push("--dangerously-skip-permissions"),this.spawnAndParse(t)}async stop(){await this.killProcess()}spawnAndParse(e){const t=p("claude");if(!t){this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?'));return}const s=I(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:m(this.extraEnv)});this.process=s,f({input:s.stdout}).on("line",n=>{if(n.trim())try{const r=JSON.parse(n);this.handleStreamEvent(r)}catch{}});let u="";s.stderr?.on("data",n=>{const r=n.toString();if(u+=r,this.terminalState==="open")for(const l of r.split(`
3
+ `)){const h=l.trim();w(h)&&this.emitEvent({state:"delta",text:h+`
4
+ `})}}),s.on("close",n=>{this.process===s&&(this.process=null,this.handleProcessClose(n,u))}),s.on("error",n=>{this.process===s&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?')):this.emit("error",n))})}handleStreamEvent(e){if(e.type==="system"&&e.subtype==="init"&&e.session_id){this.agentSessionId=e.session_id,this.emitEvent({state:"start",agentSessionId:this.agentSessionId});return}if(e.type==="system"&&e.subtype==="api_retry"&&e.error==="authentication_failed"){this.emitErrorIfOpen({state:"error",message:'Claude authentication failed. Run "claude auth login" and retry.'});return}if(e.type==="assistant"){if(e.message?.content){for(const t of e.message.content)if(t.type==="text"&&t.text){const s=this.hasEmittedText?`
5
5
 
6
- `:"";this.emitEvent({state:"delta",text:s+e.text}),this.hasEmittedText=!0}else e.type==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.type==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});return}if(t.subtype==="text"&&t.text){const e=this.hasEmittedText?`
6
+ `:"";this.emitEvent({state:"delta",text:s+t.text}),this.hasEmittedText=!0}else t.type==="thinking"&&t.thinking?this.emitEvent({state:"delta",text:t.thinking,thinking:!0}):t.type==="tool_use"&&this.emitEvent({state:"tool-call",name:t.name,args:t.input});return}if(e.subtype==="text"&&e.text){const t=this.hasEmittedText?`
7
7
 
8
- `:"";this.emitEvent({state:"delta",text:e+t.text}),this.hasEmittedText=!0}else t.subtype==="thinking"&&t.thinking?this.emitEvent({state:"delta",text:t.thinking,thinking:!0}):t.subtype==="tool_use"&&this.emitEvent({state:"tool-call",name:t.name,args:t.input});return}if(t.type==="result")if(t.subtype==="tool_result"){const e=typeof t.content=="string"?t.content:JSON.stringify(t.content);this.emitEvent({state:"tool-result",name:t.name,result:e})}else if(t.subtype==="success"){t.session_id&&(this.agentSessionId=t.session_id);const e=t.usage??t.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:e?{inputTokens:e.input_tokens,outputTokens:e.output_tokens}:void 0})}else t.subtype==="error"&&this.emitErrorIfOpen({state:"error",message:t.error??t.result??"unknown error"})}handleProcessClose(t,e){if(t!==0&&t!==null){const s=e.trim()||`claude exited with code ${t}`;this.emitErrorIfOpen({state:"error",message:s});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(t){this.terminalState==="open"&&(this.terminalState="final",this.emitEvent(t))}emitErrorIfOpen(t){this.terminalState==="open"&&(this.terminalState="error",this.emitEvent(t))}resetRunState(){this.seq=0,this.hasEmittedText=!1,this.terminalState="open"}emitEvent(t){const e={...t,runId:this.runId,seq:this.seq++};this.emit("agentEvent",e)}async killProcess(){const t=this.process;t&&(this.process=null,t.kill("SIGTERM"),await new Promise(e=>{t.on("close",e),setTimeout(()=>{t.kill("SIGKILL"),e()},3e3)}))}}S("claude",()=>new v);export{v as ClaudeAdapter,x as normalizeClaudeModelId,w as normalizeClaudeReasoningEffort,$ as resetClaudeCapabilityCacheForTests,C as shouldForwardClaudeStderrLine,k as supportsClaudeReasoningEffort};
8
+ `:"";this.emitEvent({state:"delta",text:t+e.text}),this.hasEmittedText=!0}else e.subtype==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.subtype==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});return}if(e.type==="result")if(e.subtype==="tool_result"){const t=typeof e.content=="string"?e.content:JSON.stringify(e.content);this.emitEvent({state:"tool-result",name:e.name,result:t})}else if(e.subtype==="success"){e.session_id&&(this.agentSessionId=e.session_id);const t=e.usage??e.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:t?{inputTokens:t.input_tokens,outputTokens:t.output_tokens}:void 0})}else e.subtype==="error"&&this.emitErrorIfOpen({state:"error",message:e.error??e.result??"unknown error"})}handleProcessClose(e,t){if(e!==0&&e!==null){const s=t.trim()||`claude exited with code ${e}`;this.emitErrorIfOpen({state:"error",message:s});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="final",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.emitEvent(e))}resetRunState(){this.seq=0,this.hasEmittedText=!1,this.terminalState="open"}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}async killProcess(){const e=this.process;e&&(this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}))}}S("claude",()=>new k);export{k as ClaudeAdapter,x as normalizeClaudeModelId,v as normalizeClaudeReasoningEffort,R as resetClaudeCapabilityCacheForTests,w as shouldForwardClaudeStderrLine,C as supportsClaudeReasoningEffort};
@@ -1,6 +1,6 @@
1
1
  import { type ChildProcess } from 'node:child_process';
2
2
  import type { ChatAttachmentMeta, ExternalChannelSessionStatus, SessionRunPhase } from '@shennian/wire';
3
- import { AgentAdapter, type AgentSendContext } from './adapter.js';
3
+ import { AgentAdapter, type AgentSendContext, type AgentStartOptions } from './adapter.js';
4
4
  export declare function normalizeWorkBuddyModelId(modelId?: string | null): string | undefined;
5
5
  export declare function normalizeWorkBuddyReasoningEffort(value?: string | null): string | undefined;
6
6
  export declare function workBuddySystemPromptArgs(systemPrompt: string | null, platform: NodeJS.Platform, promptFile?: string): string[];
@@ -16,6 +16,7 @@ export declare class WorkBuddyAdapter extends AgentAdapter {
16
16
  private terminalState;
17
17
  private hasEmittedText;
18
18
  private runPhase;
19
+ private persistNativeSession;
19
20
  private externalChannel;
20
21
  private shennianSessionId;
21
22
  private extraEnv;
@@ -24,7 +25,7 @@ export declare class WorkBuddyAdapter extends AgentAdapter {
24
25
  externalChannel?: ExternalChannelSessionStatus | null;
25
26
  env?: NodeJS.ProcessEnv;
26
27
  }): void;
27
- start(_sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
28
+ start(_sessionId: string, workDir: string, agentSessionId?: string | null, options?: AgentStartOptions): Promise<void>;
28
29
  send(text: string, modelId?: string, reasoningEffort?: string, _attachments?: ChatAttachmentMeta[], agentSystemPrompt?: string | null, context?: AgentSendContext): Promise<void>;
29
30
  resume(agentSessionId: string): Promise<void>;
30
31
  stop(): Promise<void>;
@@ -1,3 +1,3 @@
1
- import{spawnSync as g}from"node:child_process";import{createInterface as y}from"node:readline";import{randomUUID as w}from"node:crypto";import k from"node:path";import{AgentAdapter as I,registerAgent as S}from"./adapter.js";import{resolveBuiltinCommand as x,spawnAgentCommand as E}from"./command-spec.js";import{buildAgentProcessEnv as _}from"../agent-env.js";import{buildPlatformInstructions as B,ensurePlatformInstructionsFile as P}from"./platform-instructions.js";import{resolveWindowsSystemRoot as T}from"../windows-shell.js";const W=new Set(["minimal","low","medium","high","xhigh","max"]);function C(s){const t=s?.trim();return t&&t!=="auto"?t:void 0}function A(s){const t=s?.trim();if(t){if(W.has(t))return t;throw new Error(`Unsupported WorkBuddy reasoning effort "${t}". Supported values: minimal, low, medium, high, xhigh, max.`)}}function O(s,t,e){if(!s)return[];if(t==="win32"){if(!e)throw new Error("WorkBuddy system prompt file is required on Windows.");return["--system-prompt-file",e]}return["--append-system-prompt",s]}function q(s){const t=s.split(/\n\n(?=<[^>\n]+>\n)/);return(t[t.length-1]??s).replace(/^\[群消息\][ \t]+<[^>\n]+>\n/,"").replace(/^\[群消息\]\n?/,"").replace(/^<[^>\n]+>\n/,"").trim()}function p(s,t=process.platform,e=R){t==="win32"&&s.pid&&e(s.pid)||s.kill("SIGTERM")}function R(s){const t=k.win32.join(T(),"System32","taskkill.exe");return g(t,["/pid",String(s),"/T","/F"],{stdio:"ignore",windowsHide:!0,timeout:5e3}).status===0}class D extends I{type="workbuddy";process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="open";hasEmittedText=!1;runPhase=null;externalChannel=null;shennianSessionId=null;extraEnv={};configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{}}async start(t,e,n){this.workDir=e,this.seq=0,n&&(this.agentSessionId=n)}async send(t,e,n,o,a,r){await this.killProcess(),this.runId=w(),this.resetRunState();const u=r?.source==="room_activation",i=["-p",u?q(t):t,"--output-format","stream-json","--verbose","--permission-mode","bypassPermissions","--setting-sources","user,project,local"],d=C(e);d&&i.push("--model",d),i.push("--tools","default"),u&&i.push("--max-turns","8");const h=this.shennianSessionId?.startsWith("room-managed-")&&!this.agentSessionId&&!u?null:B(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a);if(h){const c=process.platform==="win32"?P(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a):void 0;i.push(...O(h,process.platform,c))}const m=A(n);m&&i.push("--effort",m),this.agentSessionId&&i.push("--resume",this.agentSessionId),this.spawnAndParse(i)}async resume(t){await this.killProcess(),this.agentSessionId=t,this.resetRunState()}async stop(){await this.killProcess()}async getStatus(){return{active:this.process!=null&&this.terminalState==="open",runId:this.runId||null,runPhase:this.runPhase,canStop:this.process!=null&&this.terminalState==="open"}}spawnAndParse(t){const e=x("workbuddy");if(!e){this.emit("error",new Error("WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry."));return}const n=E(e,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:_(this.extraEnv)});this.process=n,y({input:n.stdout}).on("line",r=>{if(r.trim())try{this.handleStreamEvent(JSON.parse(r))}catch{}});let a="";n.stderr?.on("data",r=>{a=`${a}${r.toString()}`.slice(-8e3)}),n.on("close",r=>{this.process===n&&(this.process=null,this.runPhase=null,this.handleProcessClose(r,a))}),n.on("error",r=>{if(this.process!==n)return;this.process=null,this.runPhase=null;const u=r.code==="ENOENT";this.emitErrorIfOpen({state:"error",message:u?"WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry.":l(r.message)})})}handleStreamEvent(t){if(t.type==="system"&&t.subtype==="init"&&t.session_id){this.agentSessionId=t.session_id,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:t.session_id});return}if(t.type==="control_request"&&t.request?.subtype==="can_use_tool"){this.runPhase="waiting_approval",this.emitEvent({state:"approval-pending",name:t.request.tool_name,args:t.request.input,approval:{title:`WorkBuddy \u8BF7\u6C42\u4F7F\u7528 ${t.request.tool_name||"\u5DE5\u5177"}`,source:"workbuddy",actionHint:"\u8BF7\u5728 WorkBuddy \u6216\u795E\u5FF5\u4E2D\u786E\u8BA4\u540E\u7EE7\u7EED\u3002"}});return}if(t.type==="assistant"){const n=t.message?.content;if(n?.length)for(const o of n)this.handleContentBlock(o);else t.text&&this.emitText(t.text,!!t.thinking);return}if(t.type!=="result")return;if(t.subtype==="tool_result"){this.runPhase="tool_running",this.emitEvent({state:"tool-result",name:t.name,result:f(t.content)});return}if(t.subtype==="error"||t.error){this.emitErrorIfOpen({state:"error",message:l(t.error||t.result||"WorkBuddy failed.")});return}!this.hasEmittedText&&t.result&&this.emitText(t.result,!1),t.session_id&&(this.agentSessionId=t.session_id);const e=t.usage??t.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:e?{inputTokens:e.input_tokens??0,outputTokens:e.output_tokens??0}:void 0})}handleContentBlock(t){t.type==="text"&&t.text?this.emitText(t.text,!1):t.type==="thinking"&&t.thinking?this.emitText(t.thinking,!0):t.type==="tool_use"?(this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:t.name,args:t.input})):t.type==="tool_result"&&this.emitEvent({state:"tool-result",name:t.name,result:f(t.content)})}emitText(t,e){this.runPhase=e?"thinking":"streaming_text";const n=!e&&this.hasEmittedText?`
1
+ import{spawnSync as g}from"node:child_process";import{createInterface as y}from"node:readline";import{randomUUID as S}from"node:crypto";import w from"node:path";import{AgentAdapter as k,registerAgent as I}from"./adapter.js";import{resolveBuiltinCommand as x,spawnAgentCommand as E}from"./command-spec.js";import{buildAgentProcessEnv as _}from"../agent-env.js";import{buildPlatformInstructions as B,ensurePlatformInstructionsFile as P}from"./platform-instructions.js";import{resolveWindowsSystemRoot as T}from"../windows-shell.js";const W=new Set(["minimal","low","medium","high","xhigh","max"]);function C(s){const t=s?.trim();return t&&t!=="auto"?t:void 0}function A(s){const t=s?.trim();if(t){if(W.has(t))return t;throw new Error(`Unsupported WorkBuddy reasoning effort "${t}". Supported values: minimal, low, medium, high, xhigh, max.`)}}function O(s,t,e){if(!s)return[];if(t==="win32"){if(!e)throw new Error("WorkBuddy system prompt file is required on Windows.");return["--system-prompt-file",e]}return["--append-system-prompt",s]}function q(s){const t=s.split(/\n\n(?=<[^>\n]+>\n)/);return(t[t.length-1]??s).replace(/^\[群消息\][ \t]+<[^>\n]+>\n/,"").replace(/^\[群消息\]\n?/,"").replace(/^<[^>\n]+>\n/,"").trim()}function p(s,t=process.platform,e=R){t==="win32"&&s.pid&&e(s.pid)||s.kill("SIGTERM")}function R(s){const t=w.win32.join(T(),"System32","taskkill.exe");return g(t,["/pid",String(s),"/T","/F"],{stdio:"ignore",windowsHide:!0,timeout:5e3}).status===0}class D extends k{type="workbuddy";process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="open";hasEmittedText=!1;runPhase=null;persistNativeSession=!0;externalChannel=null;shennianSessionId=null;extraEnv={};configure(t){this.shennianSessionId=t.sessionId??null,this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{}}async start(t,e,n,r){this.workDir=e,this.seq=0,this.persistNativeSession=r?.persistNativeSession!==!1,n&&(this.agentSessionId=n)}async send(t,e,n,r,a,i){await this.killProcess(),this.runId=S(),this.resetRunState();const u=i?.source==="room_activation",o=["-p",u?q(t):t,"--output-format","stream-json","--verbose","--permission-mode","bypassPermissions","--setting-sources","user,project,local"];this.persistNativeSession||o.push("--no-session-persistence");const d=C(e);d&&o.push("--model",d),o.push("--tools","default"),u&&o.push("--max-turns","8");const h=this.shennianSessionId?.startsWith("room-managed-")&&!this.agentSessionId&&!u?null:B(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a);if(h){const c=process.platform==="win32"?P(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a):void 0;o.push(...O(h,process.platform,c))}const m=A(n);m&&o.push("--effort",m),this.agentSessionId&&o.push("--resume",this.agentSessionId),this.spawnAndParse(o)}async resume(t){await this.killProcess(),this.agentSessionId=t,this.resetRunState()}async stop(){await this.killProcess()}async getStatus(){return{active:this.process!=null&&this.terminalState==="open",runId:this.runId||null,runPhase:this.runPhase,canStop:this.process!=null&&this.terminalState==="open"}}spawnAndParse(t){const e=x("workbuddy");if(!e){this.emit("error",new Error("WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry."));return}const n=E(e,t,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:_(this.extraEnv)});this.process=n,y({input:n.stdout}).on("line",i=>{if(i.trim())try{this.handleStreamEvent(JSON.parse(i))}catch{}});let a="";n.stderr?.on("data",i=>{a=`${a}${i.toString()}`.slice(-8e3)}),n.on("close",i=>{this.process===n&&(this.process=null,this.runPhase=null,this.handleProcessClose(i,a))}),n.on("error",i=>{if(this.process!==n)return;this.process=null,this.runPhase=null;const u=i.code==="ENOENT";this.emitErrorIfOpen({state:"error",message:u?"WorkBuddy was not found. Install WorkBuddy Desktop or the CodeBuddy CLI, then retry.":l(i.message)})})}handleStreamEvent(t){if(t.type==="system"&&t.subtype==="init"&&t.session_id){this.agentSessionId=t.session_id,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:t.session_id});return}if(t.type==="control_request"&&t.request?.subtype==="can_use_tool"){this.runPhase="waiting_approval",this.emitEvent({state:"approval-pending",name:t.request.tool_name,args:t.request.input,approval:{title:`WorkBuddy \u8BF7\u6C42\u4F7F\u7528 ${t.request.tool_name||"\u5DE5\u5177"}`,source:"workbuddy",actionHint:"\u8BF7\u5728 WorkBuddy \u6216\u795E\u5FF5\u4E2D\u786E\u8BA4\u540E\u7EE7\u7EED\u3002"}});return}if(t.type==="assistant"){const n=t.message?.content;if(n?.length)for(const r of n)this.handleContentBlock(r);else t.text&&this.emitText(t.text,!!t.thinking);return}if(t.type!=="result")return;if(t.subtype==="tool_result"){this.runPhase="tool_running",this.emitEvent({state:"tool-result",name:t.name,result:f(t.content)});return}if(t.subtype==="error"||t.error){this.emitErrorIfOpen({state:"error",message:l(t.error||t.result||"WorkBuddy failed.")});return}!this.hasEmittedText&&t.result&&this.emitText(t.result,!1),t.session_id&&(this.agentSessionId=t.session_id);const e=t.usage??t.message?.usage;this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:e?{inputTokens:e.input_tokens??0,outputTokens:e.output_tokens??0}:void 0})}handleContentBlock(t){t.type==="text"&&t.text?this.emitText(t.text,!1):t.type==="thinking"&&t.thinking?this.emitText(t.thinking,!0):t.type==="tool_use"?(this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:t.name,args:t.input})):t.type==="tool_result"&&this.emitEvent({state:"tool-result",name:t.name,result:f(t.content)})}emitText(t,e){this.runPhase=e?"thinking":"streaming_text";const n=!e&&this.hasEmittedText?`
2
2
 
3
- `:"";this.emitEvent({state:"delta",text:n+t,thinking:e||void 0}),e||(this.hasEmittedText=!0)}handleProcessClose(t,e){if(t!==0&&t!==null){this.emitErrorIfOpen({state:"error",message:l(e)||`WorkBuddy exited with code ${t}.`});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(t){this.terminalState==="open"&&(this.terminalState="final",this.runPhase=null,this.emitEvent(t))}emitErrorIfOpen(t){this.terminalState==="open"&&(this.terminalState="error",this.runPhase=null,this.emitEvent(t))}emitEvent(t){this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}resetRunState(){this.seq=0,this.terminalState="open",this.hasEmittedText=!1,this.runPhase=null}async killProcess(){const t=this.process;t&&(this.process=null,this.runPhase=null,p(t),await new Promise(e=>{let n=!1;const o=()=>{n||(n=!0,e())};t.once("close",o),setTimeout(()=>{p(t),o()},3e3).unref?.()}))}}function f(s){if(typeof s=="string")return s;try{return JSON.stringify(s)}catch{return"[unserializable WorkBuddy tool result]"}}function l(s){return s.replace(/(Authorization\s*:\s*)Bearer\s+[A-Za-z0-9._~+/-]+/gi,"$1Bearer [redacted]").replace(/(api[-_ ]?key|access[-_ ]?token|refresh[-_ ]?token|connector[-_ ]?token)(\s*[:=]\s*)[^\s,;]+/gi,"$1$2[redacted]").trim().slice(0,2e3)}S("workbuddy",()=>new D);export{D as WorkBuddyAdapter,C as normalizeWorkBuddyModelId,A as normalizeWorkBuddyReasoningEffort,l as sanitizeWorkBuddyError,p as terminateWorkBuddyProcess,q as workBuddyRoomActivationText,O as workBuddySystemPromptArgs};
3
+ `:"";this.emitEvent({state:"delta",text:n+t,thinking:e||void 0}),e||(this.hasEmittedText=!0)}handleProcessClose(t,e){if(t!==0&&t!==null){this.emitErrorIfOpen({state:"error",message:l(e)||`WorkBuddy exited with code ${t}.`});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0})}emitFinalIfOpen(t){this.terminalState==="open"&&(this.terminalState="final",this.runPhase=null,this.emitEvent(t))}emitErrorIfOpen(t){this.terminalState==="open"&&(this.terminalState="error",this.runPhase=null,this.emitEvent(t))}emitEvent(t){this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}resetRunState(){this.seq=0,this.terminalState="open",this.hasEmittedText=!1,this.runPhase=null}async killProcess(){const t=this.process;t&&(this.process=null,this.runPhase=null,p(t),await new Promise(e=>{let n=!1;const r=()=>{n||(n=!0,e())};t.once("close",r),setTimeout(()=>{p(t),r()},3e3).unref?.()}))}}function f(s){if(typeof s=="string")return s;try{return JSON.stringify(s)}catch{return"[unserializable WorkBuddy tool result]"}}function l(s){return s.replace(/(Authorization\s*:\s*)Bearer\s+[A-Za-z0-9._~+/-]+/gi,"$1Bearer [redacted]").replace(/(api[-_ ]?key|access[-_ ]?token|refresh[-_ ]?token|connector[-_ ]?token)(\s*[:=]\s*)[^\s,;]+/gi,"$1$2[redacted]").trim().slice(0,2e3)}I("workbuddy",()=>new D);export{D as WorkBuddyAdapter,C as normalizeWorkBuddyModelId,A as normalizeWorkBuddyReasoningEffort,l as sanitizeWorkBuddyError,p as terminateWorkBuddyProcess,q as workBuddyRoomActivationText,O as workBuddySystemPromptArgs};
package/dist/src/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import{Command as te}from"commander";import S from"chalk";import re from"node:os";import b from"node:fs";import{loadConfig as d,saveConfig as ie,getConfigPath as se,getShennianDir as ae,resolveShennianPath as J,normalizeAutoUpgradePolicy as ce}from"./config/index.js";import{CliRelayClient as me}from"./relay/client.js";import{registerPairCommand as le,runSmartStart as de}from"./commands/pair.js";import{clearDaemonPidIfOwner as z,createDaemonInstanceId as pe,clearDaemonLauncher as j,findRunningDaemonProcessIds as ge,isRemoteAccessDisabled as ue,isIsolatedDaemonE2eInstance as he,registerDaemonCommand as fe,writeDaemonPid as K,writeDaemonLauncher as W}from"./commands/daemon.js";import{registerRuntimeCommand as ve}from"./commands/runtime.js";import{registerManagerCommand as Se}from"./commands/manager.js";import{registerUpgradeCommand as we}from"./commands/upgrade.js";import{registerToolsCommand as Ie}from"./commands/tools.js";import{registerIntegrationCommand as ye}from"./commands/integration.js";import{registerRoomCommand as Re}from"./commands/room.js";import{SessionManager as Ce}from"./session/manager.js";import{SERVERS as P,regionToUrl as ke,urlToRegion as De}from"./region.js";import{getCurrentVersion as Y,handleStartupCrashCheck as Ee}from"./upgrade/engine.js";import{AutoUpgradeScheduler as Te}from"./upgrade/scheduler.js";import{detectAgents as Ue}from"./agents/detect.js";import{augmentProcessPath as Q}from"./env-path.js";Q();const q=Y();import{getCachedAgentInfos as Ae,resolveAgentInfos as Ne}from"./agents/model-registry.js";import{initCliLogReporter as Oe,reportLog as w}from"./log-reporter.js";import{isNativeFusionEnabled as $e}from"./native-fusion/config.js";import{NativeSessionFusionService as be}from"./native-fusion/service.js";import{startDaemonLogRetention as Pe}from"./daemon-log.js";import{startDaemonIpcServer as _e}from"./daemon-ipc/server.js";import{RoomSessionRegistry as Me}from"./room/session-registry.js";import{HttpRoomBindingClient as Le}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as xe}from"./room/managed-room-binding.js";import{RoomHostSessionObservationStore as Ve}from"./room/host-session-observations.js";import{RoomMirrorSyncService as Be}from"./room/mirror-sync-service.js";import{RoomActivationService as Ge}from"./room/activation-service.js";import{RoomActivationAudit as He}from"./room/activation-audit.js";import{RoomAttachmentCache as Fe}from"./room/attachment-cache.js";import{RoomAttachmentUploader as Je}from"./room/attachment-upload.js";import{ManagedRoomContextAuthority as ze}from"./room/managed-context.js";import{createManagedRoomIpcHandlers as je}from"./room/managed-room-ipc.js";import{SESSION_SYNC_PROTOCOL_VERSION as Ke,SESSION_SYNC_REQUIRED_CAPABILITIES as We}from"@shennian/wire";import{getDaemonInstallationId as Ye}from"./session/store.js";import{synchronizeActiveAccountNamespace as Qe}from"./personal-sync/account-namespace.js";import{getPersonalSyncLocalMetrics as qe}from"./personal-sync/metrics.js";const X=ae(),Xe=J("daemon.pid");function Ze(){try{const o=b.readFileSync(Xe,"utf-8").trim();if(o.startsWith("{")){const r=JSON.parse(o),c=Number(r.pid);return Number.isInteger(c)&&c>0?c:null}const n=parseInt(o,10);return Number.isInteger(n)&&n>0?n:null}catch{return null}}function eo(o){return o.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function _(){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 oo(o){const n=[`trigger=${o.trigger??"unknown"}`,`phase=${o.phase}`,`code=${o.code??"unknown"}`,`attempt=${o.reconnectAttempt}`];return o.reason&&n.push(`reason=${o.reason}`),o.error&&n.push(`error=${o.error}`),n.join(" ")}async function Z(o,n=5e3){const r=Date.now();for(;Date.now()-r<n;){try{process.kill(o,0)}catch{return!0}await new Promise(c=>setTimeout(c,100))}try{return process.kill(o,0),!1}catch{return!0}}const t=new te;t.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(q),t.enablePositionalOptions(),ye(t),Re(t),t.option("--api <url>","Server URL override").option("--name <name>","Machine name",re.hostname()).action(async o=>{const n=d(),r=o.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??n.serverUrl??void 0;await de(r,o.name)}),t.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async o=>{const n=J("env.json");try{const e=JSON.parse(b.readFileSync(n,"utf-8"));for(const[i,a]of Object.entries(e))process.env[i]||(process.env[i]=a);Q()}catch{}const r=Pe();ue()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(r),process.exit(0));const c=!!(process.env.INVOCATION_ID||process.env.JOURNAL_STREAM||process.env.SHENNIAN_DESKTOP_SERVER_URL),M=async(e,i)=>{console.log(`[${new Date().toISOString()}] ${i} (PID ${e})`),process.kill(e,"SIGTERM"),await Z(e)||(process.kill(e,"SIGKILL"),await Z(e,2e3))};try{const e=Ze();if(e&&e!==process.pid)try{process.kill(e,0),c?await M(e,"managed start taking over from existing daemon"):(console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),process.exit(0))}catch{}}catch{}const U=he(process.env,X)?[]:ge(process.pid);if(U.length>0)if(c)for(const e of U)try{await M(e,"managed start taking over from orphan daemon")}catch{}else console.log(`[${new Date().toISOString()}] daemon already running (PID ${U[0]}), skipping duplicate start`),process.exit(0);const l=pe();K(process.pid,l,{version:q}),W(process.pid,void 0,l),process.on("exit",()=>{z(process.pid,l),j(l)}),await Ee()&&(console.log(`[${new Date().toISOString()}] Rolled back to previous version, restarting...`),process.exit(0));const s=d(),g=o.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??s.serverUrl??P.cn.url,p=Y(),A=Ue(),h=A.map(e=>e.type),N=Ae(A),I=new Me,y=new Ve,L=new ze(I),f=new Le(g),oe=new Fe({actionClient:f}),ne=new Je({actionClient:f});let x=null;const R=await _e({handlers:{"personal.sync.metrics":()=>qe(),...je({authority:L,actionClient:f,attachmentCache:oe,attachmentUploader:ne,observations:y,getMachineCredentials:()=>({machineToken:d().machineToken})})}});let V=!1;const C=()=>{V||(V=!0,R.close().finally(()=>process.exit(0)))};if(process.once("SIGINT",C),process.once("SIGTERM",C),!s.machineToken){console.error('Shennian CLI is not paired. Run "shennian pair --browser" or "shennian pair --token" first.'),await R.close(),process.exitCode=1;return}process.removeListener("SIGINT",C),process.removeListener("SIGTERM",C);const B=`${eo(g)}/relay/machine`,O=s.machineToken;if(!O)return;try{s.accountNamespaceId=await Qe({serverUrl:g,machineToken:O,machineId:s.machineId})}catch(e){console.error(`[personal-sync] account namespace verification failed: ${e instanceof Error?e.message:String(e)}`),await R.close(),process.exitCode=1;return}s.machineId&&Oe(g,s.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${B}... (v${p}) agents: ${h.join(",")}`),w({level:"info",wsEvent:"daemon.start",metadata:{version:p,agents:h}});let k=null,D=null,E=0;const G=ce(s.autoUpgrade),m=new me({serverUrl:B,machineToken:O,cliVersion:p,agentList:h,autoUpgradePolicy:G,sessionSyncProtocolVersion:Ke,sessionSyncCapabilities:We,daemonInstallationId:Ye(),onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),w({level:"info",wsEvent:"daemon.connected"}),N.some(a=>a.models.length>0)&&m.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:N}}),Ne(A,{serverUrl:s.serverUrl??g,authToken:s.machineToken??s.accessToken}).then(a=>{JSON.stringify(a)!==JSON.stringify(N)&&m.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:a}})}).catch(()=>{}),import("./upgrade/engine.js").then(({readUpgradeAttempt:a,clearUpgradeAttempt:$})=>{const v=a();$(),v&&(console.log(`[${new Date().toISOString()}] [upgrade] Reporting success: ${v.from} \u2192 ${v.to}`),m.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:v.from,to:v.to}}))}).catch(()=>{}),T.start(),D?.start();const e=++E,i=async()=>{try{await u.synchronizeSessionDeletions(),e===E&&m.getState()==="connected"&&k?.handleConnected()}catch(a){console.error("[session.deletions] startup catch-up failed",a),e===E&&m.getState()==="connected"&&setTimeout(()=>{i()},5e3).unref?.()}};i()},onDisconnected:e=>{E+=1,D?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${oo(e)}`),w({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),w({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),u.handleReq(e)}});k=$e()?new be(m):null,D=new Be({registry:I,observations:y,actionClient:f,getMachineCredentials:()=>({machineToken:d().machineToken}),onMessages:async(e,i,a,$)=>{await x?.processMessages(e,i,a,$)}});const T=new Te({currentVersion:p,machineId:s.machineId??"unknown-machine",serverUrl:s.serverUrl??g,getIdleState:()=>u.getUpgradeIdleState(),startUpgrade:async e=>{const{handleUpgradeStart:i}=await import("./commands/upgrade.js");await i(m,"auto-upgrade",e,{currentVersion:p})}});T.setPolicy(G);const u=new Ce(m,k,p,T,new xe({registry:I,observations:y,bindingClient:f,getMachineCredentials:()=>{const e=d();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${l}`}));x=new Ge({registry:I,observations:y,activate:e=>u.activateRoomSession(e),issueManagedRoomContext:e=>{const i=d().machineToken;if(!i)throw new Error("machine_not_authorized");return L.issue({registryKey:e,machineCredential:i})},abort:e=>u.abortRoomSession(e),audit:new He}),b.mkdirSync(X,{recursive:!0}),K(process.pid,l,{version:p}),W(process.pid,void 0,l),m.connect(),process.stdin.resume();let H=!1;const F=async()=>{if(!H){H=!0,console.log(S.gray(`
3
- Disconnecting...`)),w({level:"info",wsEvent:"daemon.stop"}),clearInterval(r);try{await u.cleanup(),T.stop(),k?.stop(),D?.stop(),m.disconnect(),await R.close(),z(process.pid,l),j(l)}finally{process.exit(0)}}};process.on("SIGINT",()=>{F()}),process.on("SIGTERM",()=>{F()})}),t.command("workbuddy-session-hook",{hidden:!0}).description("(retired) WorkBuddy Room Hook").allowUnknownOption(!0).action(()=>_()),t.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(()=>_()),t.command("room-tool-server",{hidden:!0}).description("(internal) Run the official Shennian Room MCP tool").allowUnknownOption(!0).action(()=>_());const ee=t.command("config").description("View or modify configuration");ee.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${se()}`);const n={...d()};if(n.machineToken&&(n.machineToken=n.machineToken.slice(0,12)+"..."),n.serverUrl){const r=De(n.serverUrl);console.log(`Region: ${r} (${P[r].label})`)}console.log(JSON.stringify(n,null,2))}),ee.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((o,n)=>{const r=d();if(o==="server"){n!=="cn"&&n!=="global"&&(console.error(S.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const c=n;r.serverUrl=ke(c),ie(r),console.log(S.green(`\u2713 Server set to ${P[c].label}`)),console.log(S.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(S.red(`\u2717 Unknown config key: ${o}. Supported: server`)),process.exit(1)}),le(t),fe(t),ve(t),Se(t),we(t),Ie(t),t.parse();
1
+ import{Command as te}from"commander";import w from"chalk";import re from"node:os";import b from"node:fs";import{loadConfig as d,saveConfig as ie,getConfigPath as se,getShennianDir as ae,resolveShennianPath as J,normalizeAutoUpgradePolicy as ce}from"./config/index.js";import{CliRelayClient as me}from"./relay/client.js";import{registerPairCommand as le,runSmartStart as de}from"./commands/pair.js";import{clearDaemonPidIfOwner as z,createDaemonInstanceId as pe,clearDaemonLauncher as j,findRunningDaemonProcessIds as ge,isRemoteAccessDisabled as ue,isIsolatedDaemonE2eInstance as he,registerDaemonCommand as fe,writeDaemonPid as K,writeDaemonLauncher as W}from"./commands/daemon.js";import{registerRuntimeCommand as Se}from"./commands/runtime.js";import{registerManagerCommand as ve}from"./commands/manager.js";import{registerUpgradeCommand as we}from"./commands/upgrade.js";import{registerToolsCommand as Ie}from"./commands/tools.js";import{registerIntegrationCommand as ye}from"./commands/integration.js";import{registerRoomCommand as Re}from"./commands/room.js";import{SessionManager as Ce}from"./session/manager.js";import{SERVERS as P,regionToUrl as ke,urlToRegion as De}from"./region.js";import{getCurrentVersion as Y,handleStartupCrashCheck as Ee}from"./upgrade/engine.js";import{AutoUpgradeScheduler as Te}from"./upgrade/scheduler.js";import{detectAgents as Ae}from"./agents/detect.js";import{augmentProcessPath as Q}from"./env-path.js";Q();const q=Y();import{getCachedAgentInfos as Ue,resolveAgentInfos as Oe}from"./agents/model-registry.js";import{initCliLogReporter as $e,reportLog as I}from"./log-reporter.js";import{isNativeFusionEnabled as Ne}from"./native-fusion/config.js";import{NativeSessionFusionService as be}from"./native-fusion/service.js";import{startDaemonLogRetention as Pe}from"./daemon-log.js";import{startDaemonIpcServer as _e}from"./daemon-ipc/server.js";import{RoomSessionRegistry as Me}from"./room/session-registry.js";import{HttpRoomBindingClient as Le}from"./room/room-binding-client.js";import{TrustedManagedRoomBinder as xe}from"./room/managed-room-binding.js";import{RoomHostSessionObservationStore as Ve}from"./room/host-session-observations.js";import{RoomMirrorSyncService as Be}from"./room/mirror-sync-service.js";import{RoomActivationService as He}from"./room/activation-service.js";import{RoomActivationAudit as Ge}from"./room/activation-audit.js";import{RoomAttachmentCache as Fe}from"./room/attachment-cache.js";import{RoomAttachmentUploader as Je}from"./room/attachment-upload.js";import{ManagedRoomContextAuthority as ze}from"./room/managed-context.js";import{createManagedRoomIpcHandlers as je}from"./room/managed-room-ipc.js";import{SESSION_SYNC_PROTOCOL_VERSION as Ke,SESSION_SYNC_REQUIRED_CAPABILITIES as We}from"@shennian/wire";import{getDaemonInstallationId as Ye}from"./session/store.js";import{synchronizeMachinePersonalAuthority as Qe}from"./personal-sync/machine-authority.js";import{getPersonalSyncLocalMetrics as qe}from"./personal-sync/metrics.js";import{CLI_SESSION_SYNC_DATA_EPOCH as Xe,ensurePersonalDataEpoch as Ze}from"./personal-sync/epoch.js";import{DeletionSyncRetryWaitError as eo,DeletionSyncTerminalError as oo}from"./session/deletion-sync-state.js";const X=ae(),no=J("daemon.pid");function to(){try{const o=b.readFileSync(no,"utf-8").trim();if(o.startsWith("{")){const i=JSON.parse(o),c=Number(i.pid);return Number.isInteger(c)&&c>0?c:null}const n=parseInt(o,10);return Number.isInteger(n)&&n>0?n:null}catch{return null}}function ro(o){return o.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function _(){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 io(o){const n=[`trigger=${o.trigger??"unknown"}`,`phase=${o.phase}`,`code=${o.code??"unknown"}`,`attempt=${o.reconnectAttempt}`];return o.reason&&n.push(`reason=${o.reason}`),o.error&&n.push(`error=${o.error}`),n.join(" ")}async function Z(o,n=5e3){const i=Date.now();for(;Date.now()-i<n;){try{process.kill(o,0)}catch{return!0}await new Promise(c=>setTimeout(c,100))}try{return process.kill(o,0),!1}catch{return!0}}const t=new te;t.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(q),t.enablePositionalOptions(),ye(t),Re(t),t.option("--api <url>","Server URL override").option("--name <name>","Machine name",re.hostname()).action(async o=>{const n=d(),i=o.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??n.serverUrl??void 0;await de(i,o.name)}),t.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async o=>{const n=J("env.json");try{const e=JSON.parse(b.readFileSync(n,"utf-8"));for(const[s,r]of Object.entries(e))process.env[s]||(process.env[s]=r);Q()}catch{}const i=Pe();ue()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(i),process.exit(0));const c=!!(process.env.INVOCATION_ID||process.env.JOURNAL_STREAM||process.env.SHENNIAN_DESKTOP_SERVER_URL),M=async(e,s)=>{console.log(`[${new Date().toISOString()}] ${s} (PID ${e})`),process.kill(e,"SIGTERM"),await Z(e)||(process.kill(e,"SIGKILL"),await Z(e,2e3))};try{const e=to();if(e&&e!==process.pid)try{process.kill(e,0),c?await M(e,"managed start taking over from existing daemon"):(console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),process.exit(0))}catch{}}catch{}const U=he(process.env,X)?[]:ge(process.pid);if(U.length>0)if(c)for(const e of U)try{await M(e,"managed start taking over from orphan daemon")}catch{}else console.log(`[${new Date().toISOString()}] daemon already running (PID ${U[0]}), skipping duplicate start`),process.exit(0);const l=pe();K(process.pid,l,{version:q}),W(process.pid,void 0,l),process.on("exit",()=>{z(process.pid,l),j(l)}),await Ee()&&(console.log(`[${new Date().toISOString()}] Rolled back to previous version, restarting...`),process.exit(0));try{Ze()}catch(e){console.error(`[personal-sync] data epoch initialization failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}const a=d(),g=o.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??a.serverUrl??P.cn.url,p=Y(),O=Ae(),h=O.map(e=>e.type),$=Ue(O),y=new Me,R=new Ve,L=new ze(y),f=new Le(g),oe=new Fe({actionClient:f}),ne=new Je({actionClient:f});let x=null;const C=await _e({handlers:{"personal.sync.metrics":()=>qe(),...je({authority:L,actionClient:f,attachmentCache:oe,attachmentUploader:ne,observations:R,getMachineCredentials:()=>({machineToken:d().machineToken})})}});let V=!1;const k=()=>{V||(V=!0,C.close().finally(()=>process.exit(0)))};if(process.once("SIGINT",k),process.once("SIGTERM",k),!a.machineToken){console.error('Shennian CLI is not paired. Run "shennian pair --browser" or "shennian pair --token" first.'),await C.close(),process.exitCode=1;return}process.removeListener("SIGINT",k),process.removeListener("SIGTERM",k);const B=`${ro(g)}/relay/machine`,N=a.machineToken;if(!N)return;try{await Qe({serverUrl:g,machineToken:N,machineId:a.machineId})}catch(e){console.error(`[personal-sync] machine authority verification failed: ${e instanceof Error?e.message:String(e)}`),await C.close(),process.exitCode=1;return}a.machineId&&$e(g,a.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${B}... (v${p}) agents: ${h.join(",")}`),I({level:"info",wsEvent:"daemon.start",metadata:{version:p,agents:h}});let D=null,E=null,T=0;const H=ce(a.autoUpgrade),m=new me({serverUrl:B,machineToken:N,cliVersion:p,agentList:h,autoUpgradePolicy:H,sessionSyncProtocolVersion:Ke,sessionSyncCapabilities:We,daemonInstallationId:Ye(),dataEpoch:Xe,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),I({level:"info",wsEvent:"daemon.connected"}),$.some(r=>r.models.length>0)&&m.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:$}}),Oe(O,{serverUrl:a.serverUrl??g,authToken:a.machineToken??a.accessToken}).then(r=>{JSON.stringify(r)!==JSON.stringify($)&&m.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:r}})}).catch(()=>{}),import("./upgrade/engine.js").then(({readUpgradeAttempt:r,clearUpgradeAttempt:S})=>{const v=r();S(),v&&(console.log(`[${new Date().toISOString()}] [upgrade] Reporting success: ${v.from} \u2192 ${v.to}`),m.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:v.from,to:v.to}}))}).catch(()=>{}),A.start(),E?.start();const e=++T,s=async()=>{try{await u.synchronizeSessionDeletions(),e===T&&m.getState()==="connected"&&D?.handleConnected()}catch(r){if(console.error("[session.deletions] startup catch-up failed",r),e===T&&m.getState()==="connected"){if(r instanceof oo)return;const S=r instanceof eo?Math.max(1e3,r.retryAfterMs):5e3;setTimeout(()=>{s()},S).unref?.()}}};s()},onDisconnected:e=>{T+=1,E?.stop(),console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${io(e)}`),I({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),I({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),u.handleReq(e)}});D=Ne()?new be(m):null,E=new Be({registry:y,observations:R,actionClient:f,getMachineCredentials:()=>({machineToken:d().machineToken}),onMessages:async(e,s,r,S)=>{await x?.processMessages(e,s,r,S)}});const A=new Te({currentVersion:p,machineId:a.machineId??"unknown-machine",serverUrl:a.serverUrl??g,getIdleState:()=>u.getUpgradeIdleState(),startUpgrade:async e=>{const{handleUpgradeStart:s}=await import("./commands/upgrade.js");await s(m,"auto-upgrade",e,{currentVersion:p})}});A.setPolicy(H);const u=new Ce(m,D,p,A,new xe({registry:y,observations:R,bindingClient:f,getMachineCredentials:()=>{const e=d();return{machineId:e.machineId,machineToken:e.machineToken}},hostProcessIdentity:()=>`daemon:${l}`}));x=new He({registry:y,observations:R,activate:e=>u.activateRoomSession(e),issueManagedRoomContext:e=>{const s=d().machineToken;if(!s)throw new Error("machine_not_authorized");return L.issue({registryKey:e,machineCredential:s})},abort:e=>u.abortRoomSession(e),audit:new Ge}),b.mkdirSync(X,{recursive:!0}),K(process.pid,l,{version:p}),W(process.pid,void 0,l),m.connect(),process.stdin.resume();let G=!1;const F=async()=>{if(!G){G=!0,console.log(w.gray(`
3
+ Disconnecting...`)),I({level:"info",wsEvent:"daemon.stop"}),clearInterval(i);try{await u.cleanup(),A.stop(),D?.stop(),E?.stop(),m.disconnect(),await C.close(),z(process.pid,l),j(l)}finally{process.exit(0)}}};process.on("SIGINT",()=>{F()}),process.on("SIGTERM",()=>{F()})}),t.command("workbuddy-session-hook",{hidden:!0}).description("(retired) WorkBuddy Room Hook").allowUnknownOption(!0).action(()=>_()),t.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(()=>_()),t.command("room-tool-server",{hidden:!0}).description("(internal) Run the official Shennian Room MCP tool").allowUnknownOption(!0).action(()=>_());const ee=t.command("config").description("View or modify configuration");ee.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${se()}`);const n={...d()};if(n.machineToken&&(n.machineToken=n.machineToken.slice(0,12)+"..."),n.serverUrl){const i=De(n.serverUrl);console.log(`Region: ${i} (${P[i].label})`)}console.log(JSON.stringify(n,null,2))}),ee.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((o,n)=>{const i=d();if(o==="server"){n!=="cn"&&n!=="global"&&(console.error(w.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const c=n;i.serverUrl=ke(c),ie(i),console.log(w.green(`\u2713 Server set to ${P[c].label}`)),console.log(w.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(w.red(`\u2717 Unknown config key: ${o}. Supported: server`)),process.exit(1)}),le(t),fe(t),Se(t),ve(t),we(t),Ie(t),t.parse();