shennian 0.4.42 → 0.4.44

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 (81) hide show
  1. package/dist/publish-build-manifest.json +130 -50
  2. package/dist/src/agents/adapter.d.ts +8 -0
  3. package/dist/src/agents/adapter.js +1 -1
  4. package/dist/src/agents/codex.d.ts +3 -1
  5. package/dist/src/agents/codex.js +10 -10
  6. package/dist/src/agents/pi-coding-agent.d.ts +3 -1
  7. package/dist/src/agents/pi-coding-agent.js +4 -4
  8. package/dist/src/commands/daemon-process.d.ts +2 -0
  9. package/dist/src/commands/daemon-process.js +1 -1
  10. package/dist/src/commands/daemon.d.ts +1 -1
  11. package/dist/src/commands/daemon.js +6 -6
  12. package/dist/src/commands/manager.js +1 -1
  13. package/dist/src/index.js +2 -2
  14. package/dist/src/manager/prompt.d.ts +1 -1
  15. package/dist/src/manager/prompt.js +4 -3
  16. package/dist/src/manager/registry.d.ts +9 -3
  17. package/dist/src/manager/registry.js +1 -1
  18. package/dist/src/manager/runtime.d.ts +9 -16
  19. package/dist/src/manager/runtime.js +8 -20
  20. package/dist/src/manager/worker-ipc.d.ts +17 -0
  21. package/dist/src/manager/worker-ipc.js +1 -0
  22. package/dist/src/manager/worker-markdown.d.ts +10 -0
  23. package/dist/src/manager/worker-markdown.js +6 -0
  24. package/dist/src/native-fusion/codex-message-parser.d.ts +9 -0
  25. package/dist/src/native-fusion/codex-message-parser.js +1 -0
  26. package/dist/src/native-fusion/codex-parser.js +3 -3
  27. package/dist/src/native-fusion/service.d.ts +3 -0
  28. package/dist/src/native-fusion/service.js +2 -2
  29. package/dist/src/native-fusion/state.js +2 -2
  30. package/dist/src/native-fusion/types.d.ts +2 -0
  31. package/dist/src/room/activation-service.js +5 -5
  32. package/dist/src/room/managed-room-binding.js +1 -1
  33. package/dist/src/room/mirror-sync-service.d.ts +2 -0
  34. package/dist/src/room/mirror-sync-service.js +1 -1
  35. package/dist/src/room/registration-authority.d.ts +4 -0
  36. package/dist/src/room/registration-authority.js +1 -0
  37. package/dist/src/room/room-action-client-types.d.ts +136 -0
  38. package/dist/src/room/room-action-client-types.js +1 -0
  39. package/dist/src/room/room-action-client.d.ts +3 -134
  40. package/dist/src/room/room-action-client.js +1 -1
  41. package/dist/src/room/session-registry.d.ts +5 -0
  42. package/dist/src/room/session-registry.js +2 -2
  43. package/dist/src/session/deletion-sync-validation.d.ts +2 -0
  44. package/dist/src/session/deletion-sync-validation.js +1 -0
  45. package/dist/src/session/handlers/agent-control.d.ts +4 -0
  46. package/dist/src/session/handlers/agent-control.js +1 -0
  47. package/dist/src/session/handlers/agent-workspace-validation.d.ts +1 -0
  48. package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
  49. package/dist/src/session/handlers/chat-adapter-config.d.ts +11 -0
  50. package/dist/src/session/handlers/chat-adapter-config.js +1 -0
  51. package/dist/src/session/handlers/chat-events.d.ts +5 -0
  52. package/dist/src/session/handlers/chat-events.js +2 -0
  53. package/dist/src/session/handlers/chat-recovery.d.ts +4 -0
  54. package/dist/src/session/handlers/chat-recovery.js +1 -0
  55. package/dist/src/session/handlers/chat-session-lifecycle.d.ts +9 -0
  56. package/dist/src/session/handlers/chat-session-lifecycle.js +1 -0
  57. package/dist/src/session/handlers/chat.d.ts +1 -3
  58. package/dist/src/session/handlers/chat.js +1 -2
  59. package/dist/src/session/handlers/room-managed.d.ts +1 -0
  60. package/dist/src/session/handlers/room-managed.js +1 -1
  61. package/dist/src/session/manager.d.ts +3 -6
  62. package/dist/src/session/manager.js +2 -2
  63. package/dist/src/session/queue-helpers.d.ts +14 -0
  64. package/dist/src/session/queue-helpers.js +11 -0
  65. package/dist/src/session/queue-retry.d.ts +11 -0
  66. package/dist/src/session/queue-retry.js +1 -0
  67. package/dist/src/session/queue-storage.d.ts +7 -0
  68. package/dist/src/session/queue-storage.js +2 -0
  69. package/dist/src/session/queue.d.ts +25 -11
  70. package/dist/src/session/queue.js +1 -12
  71. package/dist/src/session/queued-chat-dispatch.d.ts +8 -0
  72. package/dist/src/session/queued-chat-dispatch.js +1 -0
  73. package/dist/src/session/run-recovery/schema.d.ts +3 -1
  74. package/dist/src/session/run-recovery/schema.js +1 -1
  75. package/dist/src/session/turn-trigger.d.ts +33 -0
  76. package/dist/src/session/turn-trigger.js +1 -0
  77. package/dist/src/session/types.d.ts +2 -1
  78. package/node_modules/@shennian/wire/dist/message-payload.js +1 -1
  79. package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
  80. package/node_modules/@shennian/wire/dist/session.d.ts +12 -0
  81. package/package.json +1 -1
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 184,
5
+ "fileCount": 200,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian.js",
@@ -91,8 +91,8 @@
91
91
  },
92
92
  {
93
93
  "file": "src/agents/adapter.js",
94
- "beforeBytes": 3557,
95
- "afterBytes": 1913
94
+ "beforeBytes": 3707,
95
+ "afterBytes": 1948
96
96
  },
97
97
  {
98
98
  "file": "src/agents/claude-managed-permissions.js",
@@ -121,8 +121,8 @@
121
121
  },
122
122
  {
123
123
  "file": "src/agents/codex.js",
124
- "beforeBytes": 66408,
125
- "afterBytes": 34028
124
+ "beforeBytes": 67113,
125
+ "afterBytes": 34450
126
126
  },
127
127
  {
128
128
  "file": "src/agents/command-spec.js",
@@ -241,8 +241,8 @@
241
241
  },
242
242
  {
243
243
  "file": "src/agents/pi-coding-agent.js",
244
- "beforeBytes": 24853,
245
- "afterBytes": 13461
244
+ "beforeBytes": 25531,
245
+ "afterBytes": 13883
246
246
  },
247
247
  {
248
248
  "file": "src/agents/pi-managed-extension.js",
@@ -296,8 +296,8 @@
296
296
  },
297
297
  {
298
298
  "file": "src/commands/daemon-process.js",
299
- "beforeBytes": 3400,
300
- "afterBytes": 1859
299
+ "beforeBytes": 5337,
300
+ "afterBytes": 2995
301
301
  },
302
302
  {
303
303
  "file": "src/commands/daemon-start-wait.js",
@@ -311,8 +311,8 @@
311
311
  },
312
312
  {
313
313
  "file": "src/commands/daemon.js",
314
- "beforeBytes": 46021,
315
- "afterBytes": 22106
314
+ "beforeBytes": 45807,
315
+ "afterBytes": 21994
316
316
  },
317
317
  {
318
318
  "file": "src/commands/integration.js",
@@ -326,8 +326,8 @@
326
326
  },
327
327
  {
328
328
  "file": "src/commands/manager.js",
329
- "beforeBytes": 6845,
330
- "afterBytes": 4471
329
+ "beforeBytes": 10029,
330
+ "afterBytes": 6444
331
331
  },
332
332
  {
333
333
  "file": "src/commands/pair-authorization.js",
@@ -441,8 +441,8 @@
441
441
  },
442
442
  {
443
443
  "file": "src/index.js",
444
- "beforeBytes": 35948,
445
- "afterBytes": 17839
444
+ "beforeBytes": 36726,
445
+ "afterBytes": 18286
446
446
  },
447
447
  {
448
448
  "file": "src/log-redaction.js",
@@ -456,13 +456,13 @@
456
456
  },
457
457
  {
458
458
  "file": "src/manager/prompt.js",
459
- "beforeBytes": 4370,
460
- "afterBytes": 7133
459
+ "beforeBytes": 4582,
460
+ "afterBytes": 7519
461
461
  },
462
462
  {
463
463
  "file": "src/manager/registry.js",
464
- "beforeBytes": 13848,
465
- "afterBytes": 6731
464
+ "beforeBytes": 14080,
465
+ "afterBytes": 6882
466
466
  },
467
467
  {
468
468
  "file": "src/manager/retired-external-channel-compat.js",
@@ -471,18 +471,33 @@
471
471
  },
472
472
  {
473
473
  "file": "src/manager/runtime.js",
474
- "beforeBytes": 76547,
475
- "afterBytes": 38248
474
+ "beforeBytes": 25164,
475
+ "afterBytes": 12805
476
+ },
477
+ {
478
+ "file": "src/manager/worker-ipc.js",
479
+ "beforeBytes": 10872,
480
+ "afterBytes": 5983
481
+ },
482
+ {
483
+ "file": "src/manager/worker-markdown.js",
484
+ "beforeBytes": 1327,
485
+ "afterBytes": 884
476
486
  },
477
487
  {
478
488
  "file": "src/native-fusion/codex-files.js",
479
489
  "beforeBytes": 4582,
480
490
  "afterBytes": 2163
481
491
  },
492
+ {
493
+ "file": "src/native-fusion/codex-message-parser.js",
494
+ "beforeBytes": 4048,
495
+ "afterBytes": 1955
496
+ },
482
497
  {
483
498
  "file": "src/native-fusion/codex-parser.js",
484
- "beforeBytes": 30250,
485
- "afterBytes": 12466
499
+ "beforeBytes": 26689,
500
+ "afterBytes": 10912
486
501
  },
487
502
  {
488
503
  "file": "src/native-fusion/codex-user-input.js",
@@ -526,8 +541,8 @@
526
541
  },
527
542
  {
528
543
  "file": "src/native-fusion/service.js",
529
- "beforeBytes": 36125,
530
- "afterBytes": 16121
544
+ "beforeBytes": 37567,
545
+ "afterBytes": 16892
531
546
  },
532
547
  {
533
548
  "file": "src/native-fusion/session-header.js",
@@ -536,8 +551,8 @@
536
551
  },
537
552
  {
538
553
  "file": "src/native-fusion/state.js",
539
- "beforeBytes": 4112,
540
- "afterBytes": 2111
554
+ "beforeBytes": 4401,
555
+ "afterBytes": 2293
541
556
  },
542
557
  {
543
558
  "file": "src/native-fusion/types.js",
@@ -591,8 +606,8 @@
591
606
  },
592
607
  {
593
608
  "file": "src/room/activation-service.js",
594
- "beforeBytes": 24183,
595
- "afterBytes": 12030
609
+ "beforeBytes": 24933,
610
+ "afterBytes": 12454
596
611
  },
597
612
  {
598
613
  "file": "src/room/attachment-cache.js",
@@ -636,8 +651,8 @@
636
651
  },
637
652
  {
638
653
  "file": "src/room/managed-room-binding.js",
639
- "beforeBytes": 7191,
640
- "afterBytes": 3831
654
+ "beforeBytes": 6573,
655
+ "afterBytes": 3483
641
656
  },
642
657
  {
643
658
  "file": "src/room/managed-room-ipc.js",
@@ -646,8 +661,8 @@
646
661
  },
647
662
  {
648
663
  "file": "src/room/mirror-sync-service.js",
649
- "beforeBytes": 7894,
650
- "afterBytes": 3589
664
+ "beforeBytes": 9331,
665
+ "afterBytes": 4258
651
666
  },
652
667
  {
653
668
  "file": "src/room/public-attachment-cache.js",
@@ -659,10 +674,20 @@
659
674
  "beforeBytes": 5858,
660
675
  "afterBytes": 3219
661
676
  },
677
+ {
678
+ "file": "src/room/registration-authority.js",
679
+ "beforeBytes": 1006,
680
+ "afterBytes": 462
681
+ },
682
+ {
683
+ "file": "src/room/room-action-client-types.js",
684
+ "beforeBytes": 329,
685
+ "afterBytes": 132
686
+ },
662
687
  {
663
688
  "file": "src/room/room-action-client.js",
664
- "beforeBytes": 28756,
665
- "afterBytes": 14487
689
+ "beforeBytes": 29009,
690
+ "afterBytes": 14697
666
691
  },
667
692
  {
668
693
  "file": "src/room/room-binding-client.js",
@@ -671,8 +696,8 @@
671
696
  },
672
697
  {
673
698
  "file": "src/room/session-registry.js",
674
- "beforeBytes": 27871,
675
- "afterBytes": 15713
699
+ "beforeBytes": 30575,
700
+ "afterBytes": 17164
676
701
  },
677
702
  {
678
703
  "file": "src/security/managed-agent-credential-paths.js",
@@ -716,9 +741,14 @@
716
741
  },
717
742
  {
718
743
  "file": "src/session/deletion-sync-state.js",
719
- "beforeBytes": 6015,
744
+ "beforeBytes": 6026,
720
745
  "afterBytes": 3190
721
746
  },
747
+ {
748
+ "file": "src/session/deletion-sync-validation.js",
749
+ "beforeBytes": 1590,
750
+ "afterBytes": 919
751
+ },
722
752
  {
723
753
  "file": "src/session/handlers/agent-capabilities.js",
724
754
  "beforeBytes": 767,
@@ -729,20 +759,45 @@
729
759
  "beforeBytes": 5590,
730
760
  "afterBytes": 2803
731
761
  },
762
+ {
763
+ "file": "src/session/handlers/agent-control.js",
764
+ "beforeBytes": 6699,
765
+ "afterBytes": 3876
766
+ },
732
767
  {
733
768
  "file": "src/session/handlers/agent-workspace-validation.js",
734
- "beforeBytes": 8799,
735
- "afterBytes": 4597
769
+ "beforeBytes": 9051,
770
+ "afterBytes": 4712
736
771
  },
737
772
  {
738
773
  "file": "src/session/handlers/agents.js",
739
774
  "beforeBytes": 2274,
740
775
  "afterBytes": 1134
741
776
  },
777
+ {
778
+ "file": "src/session/handlers/chat-adapter-config.js",
779
+ "beforeBytes": 2814,
780
+ "afterBytes": 1159
781
+ },
782
+ {
783
+ "file": "src/session/handlers/chat-events.js",
784
+ "beforeBytes": 15468,
785
+ "afterBytes": 6683
786
+ },
787
+ {
788
+ "file": "src/session/handlers/chat-recovery.js",
789
+ "beforeBytes": 6002,
790
+ "afterBytes": 3291
791
+ },
792
+ {
793
+ "file": "src/session/handlers/chat-session-lifecycle.js",
794
+ "beforeBytes": 3728,
795
+ "afterBytes": 1723
796
+ },
742
797
  {
743
798
  "file": "src/session/handlers/chat.js",
744
- "beforeBytes": 58009,
745
- "afterBytes": 24871
799
+ "beforeBytes": 32547,
800
+ "afterBytes": 13978
746
801
  },
747
802
  {
748
803
  "file": "src/session/handlers/control.js",
@@ -776,8 +831,8 @@
776
831
  },
777
832
  {
778
833
  "file": "src/session/handlers/room-managed.js",
779
- "beforeBytes": 4813,
780
- "afterBytes": 2536
834
+ "beforeBytes": 4928,
835
+ "afterBytes": 2628
781
836
  },
782
837
  {
783
838
  "file": "src/session/handlers/session-refresh.js",
@@ -811,8 +866,8 @@
811
866
  },
812
867
  {
813
868
  "file": "src/session/manager.js",
814
- "beforeBytes": 50398,
815
- "afterBytes": 26589
869
+ "beforeBytes": 41802,
870
+ "afterBytes": 21965
816
871
  },
817
872
  {
818
873
  "file": "src/session/native-cleanup-outbox.js",
@@ -834,10 +889,30 @@
834
889
  "beforeBytes": 1991,
835
890
  "afterBytes": 966
836
891
  },
892
+ {
893
+ "file": "src/session/queue-helpers.js",
894
+ "beforeBytes": 7270,
895
+ "afterBytes": 3812
896
+ },
897
+ {
898
+ "file": "src/session/queue-retry.js",
899
+ "beforeBytes": 1253,
900
+ "afterBytes": 561
901
+ },
902
+ {
903
+ "file": "src/session/queue-storage.js",
904
+ "beforeBytes": 1663,
905
+ "afterBytes": 909
906
+ },
837
907
  {
838
908
  "file": "src/session/queue.js",
839
- "beforeBytes": 36820,
840
- "afterBytes": 16528
909
+ "beforeBytes": 40646,
910
+ "afterBytes": 18459
911
+ },
912
+ {
913
+ "file": "src/session/queued-chat-dispatch.js",
914
+ "beforeBytes": 2356,
915
+ "afterBytes": 1264
841
916
  },
842
917
  {
843
918
  "file": "src/session/run-recovery/barrier.js",
@@ -856,8 +931,8 @@
856
931
  },
857
932
  {
858
933
  "file": "src/session/run-recovery/schema.js",
859
- "beforeBytes": 6517,
860
- "afterBytes": 4173
934
+ "beforeBytes": 6647,
935
+ "afterBytes": 4272
861
936
  },
862
937
  {
863
938
  "file": "src/session/store.js",
@@ -869,6 +944,11 @@
869
944
  "beforeBytes": 2886,
870
945
  "afterBytes": 1429
871
946
  },
947
+ {
948
+ "file": "src/session/turn-trigger.js",
949
+ "beforeBytes": 106,
950
+ "afterBytes": 1
951
+ },
872
952
  {
873
953
  "file": "src/session/types.js",
874
954
  "beforeBytes": 159,
@@ -52,6 +52,11 @@ export type AgentSendContext = {
52
52
  /** Marks internal recovery input; it must never be persisted as user-authored text. */
53
53
  recovery?: 'upgrade';
54
54
  };
55
+ export type AgentActiveInput = {
56
+ text: string;
57
+ attachments?: ChatAttachmentMeta[];
58
+ clientMessageId?: string;
59
+ };
55
60
  export type ImportedAgentMessage = {
56
61
  /** Stable within repeated imports of the same provider session. */
57
62
  sourceId: string;
@@ -122,6 +127,9 @@ export declare abstract class AgentAdapter extends EventEmitter<AgentAdapterEven
122
127
  abstract readonly type: AgentType;
123
128
  /** Explicit fail-closed default; resumable adapters must opt in. */
124
129
  get recoveryCapabilities(): AgentRecoveryCapabilities;
130
+ /** Explicit fail-closed capability for adding input to the current provider turn. */
131
+ get supportsActiveInput(): boolean;
132
+ injectActiveInput?(input: AgentActiveInput): Promise<void>;
125
133
  configure?(options: {
126
134
  sessionId?: string;
127
135
  externalChannel?: ExternalChannelSessionStatus | null;
@@ -1 +1 @@
1
- import{EventEmitter as o}from"node:events";import{RECOVERY_CONTINUE_TEXT as u}from"../session/run-recovery/schema.js";class l extends o{get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!1}}async inspectInterruptedRun(e){if(!this.getStatus)return{state:"interrupted",providerRunId:e.providerRunId};const r=await this.getStatus().catch(()=>null);return r?.active?{state:"active",providerRunId:r.runId??e.providerRunId,runPhase:r.runPhase}:{state:"interrupted",providerRunId:e.providerRunId}}async recoverInterruptedRun(e){const r=await this.inspectInterruptedRun(e);if(r.state==="terminal"&&this.recoveryCapabilities.inspectTerminal)return{result:"terminal_reconciled"};if(r.state==="active"&&this.recoveryCapabilities.reattachRun)return{result:"reattached"};if(!e.agentSessionId)return{result:"interrupted_by_upgrade",reason:"missing_agent_session"};if(!this.recoveryCapabilities.resumeSession)return{result:"interrupted_by_upgrade",reason:"resume_unsupported"};if(e.continueDispatchState!=="none")return{result:"recovery_failed",reason:"continue_dispatch_outcome_unknown"};try{return e.beforeContinueDispatch?.(),await this.send(u,e.modelId??void 0,e.reasoningEffort??void 0,void 0,e.systemPrompt,e.sendContext),{result:"continued"}}catch(i){const a=i instanceof Error?i.message:String(i),n=a.toLowerCase();return{result:"recovery_failed",reason:n.includes("auth")||n.includes("login")?"authentication_required":n.includes("permission")||n.includes("capability")?"permission_context_unavailable":n.includes("session")&&n.includes("not")?"provider_session_missing":"provider_error",message:a.slice(0,500)}}}}const s=new Map;function p(t,e){s.set(t,e)}function f(t){s.delete(t)}function g(t){const e=s.get(t);return e?e():null}function m(){return[...s.keys()]}export{l as AgentAdapter,g as createAgent,m as getRegisteredAgents,p as registerAgent,f as unregisterAgent};
1
+ import{EventEmitter as o}from"node:events";import{RECOVERY_CONTINUE_TEXT as u}from"../session/run-recovery/schema.js";class l extends o{get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!1}}get supportsActiveInput(){return!1}async inspectInterruptedRun(e){if(!this.getStatus)return{state:"interrupted",providerRunId:e.providerRunId};const r=await this.getStatus().catch(()=>null);return r?.active?{state:"active",providerRunId:r.runId??e.providerRunId,runPhase:r.runPhase}:{state:"interrupted",providerRunId:e.providerRunId}}async recoverInterruptedRun(e){const r=await this.inspectInterruptedRun(e);if(r.state==="terminal"&&this.recoveryCapabilities.inspectTerminal)return{result:"terminal_reconciled"};if(r.state==="active"&&this.recoveryCapabilities.reattachRun)return{result:"reattached"};if(!e.agentSessionId)return{result:"interrupted_by_upgrade",reason:"missing_agent_session"};if(!this.recoveryCapabilities.resumeSession)return{result:"interrupted_by_upgrade",reason:"resume_unsupported"};if(e.continueDispatchState!=="none")return{result:"recovery_failed",reason:"continue_dispatch_outcome_unknown"};try{return e.beforeContinueDispatch?.(),await this.send(u,e.modelId??void 0,e.reasoningEffort??void 0,void 0,e.systemPrompt,e.sendContext),{result:"continued"}}catch(i){const a=i instanceof Error?i.message:String(i),n=a.toLowerCase();return{result:"recovery_failed",reason:n.includes("auth")||n.includes("login")?"authentication_required":n.includes("permission")||n.includes("capability")?"permission_context_unavailable":n.includes("session")&&n.includes("not")?"provider_session_missing":"provider_error",message:a.slice(0,500)}}}}const s=new Map;function p(t,e){s.set(t,e)}function f(t){s.delete(t)}function g(t){const e=s.get(t);return e?e():null}function m(){return[...s.keys()]}export{l as AgentAdapter,g as createAgent,m as getRegisteredAgents,p as registerAgent,f as unregisterAgent};
@@ -1,4 +1,4 @@
1
- import { AgentAdapter, type AgentSendContext, type AgentSendResult, type AgentStartOptions } from './adapter.js';
1
+ import { AgentAdapter, type AgentActiveInput, type AgentSendContext, type AgentSendResult, type AgentStartOptions } from './adapter.js';
2
2
  import { type ChatAttachmentMeta, type ExternalChannelSessionStatus } from '@shennian/wire';
3
3
  import type { SessionRunPhase } from '@shennian/wire';
4
4
  import { type CompiledManagedAgentPolicy } from '../security/managed-agent-policy.js';
@@ -19,6 +19,8 @@ export declare function buildCodexQueuedText(text: string, attachments?: ChatAtt
19
19
  export declare function buildCodexQueueArgs(threadId: string, text: string, attachments?: ChatAttachmentMeta[]): string[];
20
20
  export declare class CodexAdapter extends AgentAdapter {
21
21
  private readonly options;
22
+ get supportsActiveInput(): boolean;
23
+ injectActiveInput(input: AgentActiveInput): Promise<void>;
22
24
  readonly type: "codex";
23
25
  get recoveryCapabilities(): {
24
26
  inspectTerminal: boolean;
@@ -1,17 +1,17 @@
1
- import{spawnSync as O}from"node:child_process";import{createInterface as S}from"node:readline";import{createHash as w,randomUUID as q}from"node:crypto";import g from"node:path";import{AgentAdapter as N,registerAgent as D}from"./adapter.js";import{resolveBuiltinCommand as T,spawnAgentCommand as x}from"./command-spec.js";import{buildAgentProcessEnv as L,buildManagedAgentProcessEnv as F,buildManagedNativeFullProcessEnv as $}from"../agent-env.js";import{ensurePlatformInstructionsFile as U}from"./platform-instructions.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as C}from"@shennian/wire";import{isCodexThreadTailInterrupted as W}from"../native-fusion/codex-files.js";import{resolveManagedAgentAdapterEnforcement as z,isManagedAgentNativeFull as R}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as B}from"../security/managed-agent-runtime.js";import{CODEX_MANAGED_ROOM_DYNAMIC_TOOLS as G,CodexManagedRoomToolBinding as J}from"./codex-managed-room-tools.js";import{assertCodexManagedPermissionProfile as E,CODEX_MANAGED_RUNTIME_SECURITY as V,compileCodexManagedPermissions as H,extractCodexMcpServerNames as X}from"./codex-managed-permissions.js";import{CODEX_APP_SERVER_CLIENT_INFO as K,extractAppServerErrorMessage as _,formatCodexErrorMessage as Q,formatTransientCodexStatus as Y,isCodexCollabAgentItem as j,isCodexCollabAgentToolName as y,isCodexLegacyCollabAgentItem as Z,isCodexUnsupportedEffortError as ee,isMissingCodexRolloutError as v,isTransientCodexErrorMessage as te,looksLikeCodexInteractiveAuthPrompt as re,looksLikeFatalCodexStderr as se,normalizeCodexModelId as I,normalizeCodexReasoningEffort as ne,normalizeCodexStderr as k,normalizeTerminalText as ie,safeStringify as A,stripGitDirectiveArtifacts as oe}from"./codex-utils.js";import{isCodexUnsupportedEffortError as Ne,isMissingCodexRolloutError as De,normalizeCodexModelId as Le,normalizeCodexReasoningEffort as Fe}from"./codex-utils.js";B("codex",V);function P(o){const e=o instanceof Error?o.message:String(o);return/already has an active writer|thread-store conflict/i.test(e)}function ae(o){const e=o instanceof Error?o.message:String(o);return/paginated(?:_threads|\s+(?:thread\s+)?history)?.*(?:not supported|unsupported|unavailable)/i.test(e)||/(?:not supported|unsupported|unavailable).*paginated(?:_threads|\s+(?:thread\s+)?history)?/i.test(e)}function de(o){const e=o instanceof Error?o.message:String(o);return/unknown field [`'"]?excludeTurns/i.test(e)||/excludeTurns.*(?:not supported|unsupported|unavailable)/i.test(e)}function le(o){const e=o instanceof Error?o.message:String(o);return/(?:method not found|unknown method).*(?:project\/list|project\/create)/i.test(e)||/(?:project\/list|project\/create).*(?:not supported|unsupported|unavailable)/i.test(e)}function ce(o,e){const t=g.resolve(e);let r;for(const s of o)if(s.id)for(const i of s.roots??[]){if(!i.path)continue;const n=g.resolve(i.path),a=g.relative(n,t);!(a===""||!a.startsWith("..")&&!g.isAbsolute(a))||n.length<=(r?.rootLength??-1)||(r={id:s.id,rootLength:n.length})}return r?.id}function ue(o,e){const t=e?.flatMap(s=>he(s)).filter(s=>!/^https?:\/\//i.test(s.path)).filter(s=>s.path);return{type:"text",text:me(o,e),text_elements:[],...t?.length?{local_images:t}:{}}}function he(o){if(o.kind==="image")return o.previewData?[{path:o.path,data:o.previewData,mimeType:o.mimeType}]:[{path:o.path}];if(o.mimeType.startsWith("video/")){const e=pe(o.path);return e?[{path:e}]:[]}return[]}function pe(o){if(!o||/^https?:\/\//i.test(o))return null;const e=g.extname(o),r=`${e?o.slice(0,-e.length):o}.preview.png`;return O("ffmpeg",["-y","-ss","0","-i",o,"-frames:v","1","-vf","scale=320:-1",r],{stdio:"ignore",timeout:15e3}).status===0?r:null}function me(o,e){const t=e?.filter(i=>i.kind!=="image").filter(i=>i.path&&!/^https?:\/\//i.test(i.path));if(!t?.length||t.every(i=>o.includes(i.path)))return o;const s=t.map((i,n)=>{const a=i.name||`attachment-${n+1}`,d=i.mimeType?` (${i.mimeType})`:"";return`[${M(a)}${d}](<${i.path}>)`});return[o,"",...s].join(`
2
- `)}function ge(o,e){const t=e?.filter(s=>s.path&&!/^https?:\/\//i.test(s.path)&&!o.includes(s.path));if(!t?.length)return o;const r=t.map((s,i)=>{const n=M(s.name||`attachment-${i+1}`);return s.kind==="image"?`![${n}](<${s.path}>)`:`[${n}](<${s.path}>)`});return[o,"",...r].join(`
3
- `)}function fe(o,e,t){return["queue","--thread",o,"--message",ge(e,t)]}function M(o){return o.replace(/[[\]\\]/g,"\\$&")}class ye extends N{options;type="codex";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;workDir=null;seq=0;runId="";pendingUsage;agentSessionId=null;hasEmittedText=!1;textTail="";terminalState="open";forceCloseTimer=null;stderrBuf="";rpcSeq=1;pendingRequests=new Map;appServerReady=null;appServerStartupError=null;activeTurnId=null;deltaItemIds=new Set;lastTransientStatus="";agentSystemPrompt="";managedAgentPolicy=null;managedPermissionConfig=null;configurationRestartRequired=!1;managedRoomTools=new J;configuredManagedRoomContextToken=null;configuredManagedRoomExecutor=null;managedRoomToolThreadId=null;preparedExternalOwnerThreadId=null;managedTurnReplay=null;managedAsyncRecovery=null;persistNativeSession=!0;nativeSessionVisibility="user";constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){const t=this.configurationFingerprint();this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),("managedRoomContextToken"in e||"managedRoomExecutor"in e)&&(this.managedRoomTools.deactivateTurn(),this.configuredManagedRoomContextToken=e.managedRoomContextToken?.trim()||null,this.configuredManagedRoomExecutor=e.managedRoomExecutor??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir);const r=this.configurationFingerprint();t!==r&&this.process&&(this.configurationRestartRequired=!0)}configurationFingerprint(){const e=Object.keys(this.extraEnv).sort().map(t=>[t,this.extraEnv[t]??null]);return w("sha256").update(JSON.stringify({sessionId:this.shennianSessionId,externalChannel:this.externalChannel,env:e,managedAgentPolicy:this.managedAgentPolicy})).digest("hex")}buildProcessEnv(e={}){if(!this.managedAgentPolicy)return L({...e,...this.extraEnv});if(R(this.managedAgentPolicy))return $({...e,...this.extraEnv});const t=Object.fromEntries(Object.entries(this.extraEnv).filter(([r])=>r!=="SHENNIAN_MANAGED_ROOM_CONTEXT"&&r!=="SHENNIAN_MANAGED_ROOM_IPC_ROOT"));return F({agentType:"codex",providerEnv:t,sessionEnv:t,runtimeEnv:e})}async start(e,t,r,s){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=s?.persistNativeSession!==!1,this.nativeSessionVisibility=s?.nativeSessionVisibility??"user",r&&(this.agentSessionId=r)}async prepareSend(e,t,r,s,i,n){const a=i?.trim()??"";if(a!==this.agentSystemPrompt&&(this.agentSystemPrompt=a,this.process&&await this.killProcess(!0)),!(!this.agentSessionId||this.activeTurnId)){this.preparedExternalOwnerThreadId=null;try{await this.ensureAppServer(I(t))}catch(d){if(!P(d))throw d;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:d});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:d});this.preparedExternalOwnerThreadId=this.agentSessionId}}}async send(e,t,r,s,i,n){if(n?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");if(n?.source==="room_activation"&&(!this.configuredManagedRoomContextToken||!this.configuredManagedRoomExecutor))throw new Error("codex_managed_room_tool_context_unavailable");this.activeTurnId&&(await this.interruptActiveTurn().catch(()=>{}),await this.killProcess(!0)),this.configurationRestartRequired&&this.process&&await this.killProcess(!0),this.configurationRestartRequired=!1;const a=I(t),d=ne(r),c=i?.trim()??"";if(c!==this.agentSystemPrompt&&(this.agentSystemPrompt=c,this.process&&await this.killProcess(!0)),n?.source==="room_activation"&&this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),this.runId=q(),this.seq=0,this.resetRunState(),this.agentSessionId&&this.preparedExternalOwnerThreadId===this.agentSessionId)return this.preparedExternalOwnerThreadId=null,{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)};try{await this.ensureAppServer(a)}catch(h){if(!this.agentSessionId||!P(h))throw h;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:h});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:h});return{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)}}const l=this.agentSessionId;if(!l)throw new Error("codex app-server did not create a thread");this.emitEvent({state:"start",agentSessionId:l}),this.managedTurnReplay=this.managedPermissionConfig?{text:e,modelId:a,reasoningEffort:d,attachments:s,recoveryCount:0}:null;const p=await this.startTurnWithRecovery(l,e,a,d,s),m=this.agentSessionId??l;if(this.activeTurnId=p.turn?.id??null,this.managedRoomToolThreadId===m&&this.activeTurnId&&!this.managedRoomTools.bindTurn(m,this.activeTurnId))throw await this.killProcess(),new Error("codex_managed_room_turn_binding_failed");return{deliveryMode:"direct"}}isThreadTailInterrupted(e){return this.options.isThreadTailInterrupted?.(e)??W(e)}async enqueueForExternalOwner(e,t,r){const s=T("codex");if(!s)throw new Error('Command "codex" not found. Is OpenAI Codex CLI installed?');const i=fe(e,t,r),n=x(s,i,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});return await new Promise((a,d)=>{let c="",l="",p=!1;const m=(u,f)=>{p||(p=!0,clearTimeout(h),u?d(u):a(f))},h=setTimeout(()=>{n.kill("SIGTERM"),m(new Error("Codex Desktop message queue timed out"))},6e4);h.unref?.(),n.stdout?.on("data",u=>{c+=u.toString()}),n.stderr?.on("data",u=>{l+=u.toString()}),n.once("error",u=>m(u)),n.once("close",u=>{const f=`${c}
4
- ${l}`.trim();if(u!==0){m(new Error(f||`codex queue exited with code ${u??"unknown"}`));return}const b=f.match(/Queued message\s+([^\s]+)\s+for thread/i)?.[1];m(void 0,b)})})}async resume(e){await this.killProcess(),this.agentSessionId=e,this.resetTextState()}async setTitle(e,t,r){const s=e.trim(),i=t.replace(/\s+/g," ").trim();!s||!i||(this.agentSessionId=s,r?.trim()&&(this.workDir=r),await this.ensureAppServer(),await this.sendRpc("thread/name/set",{threadId:s,name:i}))}async stop(){this.managedRoomTools.deactivateTurn(),await this.interruptActiveTurn().catch(()=>{}),await this.killProcess()}async getStatus(){const e=this.agentSessionId,t=this.activeTurnId;if(!e||!this.process)return{active:!1,runId:t,runPhase:null,canStop:!1};let r=null;try{r=(await this.sendRpc("thread/read",{threadId:e,includeTurns:!1},5e3)).thread?.status??null}catch{}const s=r?.type==="active"||!!t;return{active:s,runId:t,runPhase:s?this.mapThreadStatusToRunPhase(r):null,canStop:!!(s&&t&&this.process)}}spawnCodex(e){const t=T("codex");if(!t){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const r=x(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=r,S({input:r.stdout}).on("line",n=>{if(n.trim())try{const a=JSON.parse(n);this.handleStreamEvent(a)}catch{this.emitEvent({state:"delta",text:n})}});let i="";r.stderr?.on("data",n=>{i+=n.toString()}),r.on("close",n=>{this.process===r&&(this.process=null,this.clearForceCloseTimer(),this.handleProcessClose(n,i))}),r.on("error",n=>{this.process===r&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}spawnAppServer(){const e=T("codex");if(!e){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const t=["app-server","--listen","stdio://"],r=this.options.modelInstructionsFile??U(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,this.agentSystemPrompt);r&&t.push("-c",`model_instructions_file=${JSON.stringify(r)}`);const s=x(e,t,{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});this.process=s,this.stderrBuf="",this.appServerStartupError=null,S({input:s.stdout}).on("line",n=>{if(!n.trim())return;let a;try{a=JSON.parse(n)}catch{this.handleAppServerNonJsonStdout(n);return}this.handleAppServerMessage(a)}),s.stderr?.on("data",n=>{this.stderrBuf+=n.toString()}),s.on("close",n=>{if(this.process!==s)return;const a=this.activeTurnId!=null;this.process=null,this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(new Error(k(this.stderrBuf)||`codex app-server exited with code ${n}`)),this.terminalState==="open"&&a&&this.handleProcessClose(n,this.stderrBuf)}),s.on("error",n=>{this.process===s&&(this.process=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(n),n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}async ensureAppServer(e){return this.appServerReady?this.appServerReady:(this.spawnAppServer(),this.appServerReady=this.initializeAppServer(e).catch(async t=>{throw this.appServerReady=null,await this.killProcess(),t}),this.appServerReady)}async initializeAppServer(e){const t=I(e);await this.sendRpc("initialize",{clientInfo:K,capabilities:{experimentalApi:!0}}),this.managedPermissionConfig=this.managedAgentPolicy&&!R(this.managedAgentPolicy)?await this.buildManagedPermissionConfig():null;const r=!!(this.configuredManagedRoomContextToken||this.configuredManagedRoomExecutor);if(this.managedAgentPolicy&&r&&!this.managedRoomTools.isConfigured()&&(this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),!this.managedRoomTools.isConfigured()))throw new Error("codex_managed_room_tool_context_unavailable");if(this.agentSessionId&&this.managedAgentPolicy&&r&&this.agentSessionId!==this.managedRoomToolThreadId){if(!this.managedRoomTools.isConfigured())throw new Error("codex_managed_room_tool_context_unavailable");this.agentSessionId=null}if(this.agentSessionId){const c={threadId:this.agentSessionId,cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},persistExtendedHistory:!0,...t?{model:t}:{}};let l;try{l=await this.sendRpc("thread/resume",{...c,excludeTurns:!0})}catch(p){if(!de(p))throw p;l=await this.sendRpc("thread/resume",c)}this.agentSessionId=l.thread?.id??this.agentSessionId,this.managedPermissionConfig&&E(l,this.managedPermissionConfig.profileId),this.managedAgentPolicy&&r&&(this.managedRoomTools.bindThread(this.agentSessionId),this.managedRoomToolThreadId=this.agentSessionId);return}const s=this.options.hidden||this.nativeSessionVisibility==="internal"||!this.persistNativeSession,i=s?void 0:await this.resolveCodexProjectId(),n={cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},serviceName:"Shennian",...s?{}:{threadSource:"user"},experimentalRawEvents:!1,persistExtendedHistory:!0,...this.managedAgentPolicy&&r?{dynamicTools:G}:{},...i?{projectId:i}:{},...t?{model:t}:{}};let a;if(s&&!this.managedPermissionConfig)a=await this.sendRpc("thread/start",n);else try{a=await this.sendRpc("thread/start",{...n,historyMode:"paginated"})}catch(c){throw ae(c)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5728 Codex Desktop \u4E2D\u7EE7\u7EED\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u964D\u7EA7\u521B\u5EFA\u4E0D\u53EF\u89C1\u7684 legacy \u4F1A\u8BDD\u3002",{cause:c}):c}const d=a.thread?.id;if(!d)throw new Error("codex app-server thread/start returned no thread id");this.managedPermissionConfig&&E(a,this.managedPermissionConfig.profileId),this.managedAgentPolicy&&r&&(this.managedRoomTools.bindThread(d),this.managedRoomToolThreadId=d),this.agentSessionId=d}async buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e)throw new Error("managed_agent_policy_missing");const t=e.adapterPolicy.externalCapabilities.mcp?[]:X(await this.sendRpc("config/read",{cwd:e.adapterPolicy.workDir}));return H(z(e),e.adapterPolicy.workDir,{configuredMcpServerNames:t,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}async resolveCodexProjectId(){const e=this.workDir?.trim();if(e)try{const t=[];let r;do{const c=await this.sendRpc("project/list",{limit:100,...r?{cursor:r}:{}});t.push(...c.data??[]),r=c.nextCursor}while(r);const s=ce(t,e);if(s)return s;const i=g.resolve(e),n=`shennian-project-${w("sha256").update(i).digest("hex")}`,d=(await this.sendRpc("project/create",{idempotencyKey:n,name:g.basename(i)||i,roots:[{path:i}],metadata:{createdBy:"Shennian"}})).project?.id;if(!d)throw new Error("codex app-server project/create returned no project id");return d}catch(t){throw le(t)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5F52\u5C5E\u5230 Codex Desktop \u9879\u76EE\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u76F4\u63A5\u4FEE\u6539 Codex Desktop \u7684\u79C1\u6709\u4FA7\u680F\u7D22\u5F15\u3002",{cause:t}):t}}async startTurnWithRecovery(e,t,r,s,i){try{return await this.startTurn(e,t,r,s,i)}catch(n){if(!v(n))throw n;if(this.managedAgentPolicy||this.managedPermissionConfig){this.logManagedThreadLifecycle("rollout.missing",{threadId:e,recovery:"recreate"}),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(r);const a=this.agentSessionId;if(!a)throw new Error("codex app-server did not recreate the managed thread",{cause:n});return this.logManagedThreadLifecycle("thread.recreated",{previousThreadId:e,threadId:a}),this.emitEvent({state:"start",agentSessionId:a}),await this.startFreshManagedTurnWithReadinessRetry(a,t,r,s,i)}return await this.killProcess(),await this.ensureAppServer(r),await this.startTurn(e,t,r,s,i)}}async startFreshManagedTurnWithReadinessRetry(e,t,r,s,i){const n=[0,100,300,1e3];let a;for(let d=0;d<n.length;d+=1){const c=n[d];c>0&&await new Promise(l=>setTimeout(l,c));try{const l=await this.startTurn(e,t,r,s,i);return d>0&&this.logManagedThreadLifecycle("rollout.ready",{threadId:e,attempt:d+1}),l}catch(l){if(a=l,!v(l)||d===n.length-1)throw l;this.logManagedThreadLifecycle("rollout.retry",{threadId:e,attempt:d+2,delayMs:n[d+1]})}}throw a}logManagedThreadLifecycle(e,t){console.error(`[codex.managed] ${JSON.stringify({event:e,...t})}`)}async startTurn(e,t,r,s,i){try{return await this.sendRpc("turn/start",{threadId:e,input:[ue(t,i)],approvalPolicy:"never",...this.managedPermissionConfig?{}:{sandboxPolicy:{type:"dangerFullAccess"}},...r?{model:r}:{},...s?{effort:s}:{}})}catch(n){throw s&&ee(n)?new Error(`Codex app-server does not accept reasoning effort "${s}" for this turn. Refresh models or upgrade Codex CLI, then retry.`,{cause:n}):n}}async interruptActiveTurn(){const e=this.agentSessionId,t=this.activeTurnId;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),!(!e||!t||!this.process)&&await this.sendRpc("turn/interrupt",{threadId:e,turnId:t},5e3)}sendRpc(e,t,r=6e4){if(this.appServerStartupError)return Promise.reject(this.appServerStartupError);const s=this.process;if(!s?.stdin)return Promise.reject(new Error("codex app-server is not running"));const i=this.rpcSeq++,n=JSON.stringify({id:i,method:e,params:t});return new Promise((a,d)=>{const c=setTimeout(()=>{this.pendingRequests.delete(i),d(new Error(`codex app-server request timed out: ${e}`))},r);this.pendingRequests.set(i,{resolve:a,reject:d,timer:c}),s.stdin.write(`${n}
5
- `,l=>{l&&(clearTimeout(c),this.pendingRequests.delete(i),d(l))})})}handleAppServerMessage(e){if(e.method==="item/tool/call"&&e.id!=null){this.handleManagedRoomToolCall(e.id,e.params??{});return}if(e.id!=null){const r=typeof e.id=="number"?this.pendingRequests.get(e.id):void 0;r&&(clearTimeout(r.timer),this.pendingRequests.delete(e.id),e.error?r.reject(new Error(e.error.message||`codex app-server error ${e.error.code??""}`.trim())):r.resolve(e.result))}if(!e.method)return;const t=e.params??{};switch(e.method){case"turn/started":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null,i=typeof t.threadId=="string"?t.threadId:"";s&&(this.activeTurnId=s,this.managedRoomToolThreadId===i&&!this.managedRoomTools.bindTurn(i,s)&&this.emitErrorIfOpen("codex_managed_room_turn_binding_failed"));break}case"thread/status/changed":{const r=typeof t.threadId=="string"?t.threadId:"";if(r&&this.agentSessionId&&r!==this.agentSessionId)break;const s=typeof t.status=="object"&&t.status!==null?t.status:null;s?.type==="active"&&this.emitEvent({state:"heartbeat",runPhase:this.mapThreadStatusToRunPhase(s)});break}case"item/agentMessage/delta":{const r=typeof t.itemId=="string"?t.itemId:"";r&&this.deltaItemIds.add(r),typeof t.delta=="string"&&this.emitText(t.delta);break}case"item/completed":this.handleAppServerCompletedItem(t);break;case"thread/tokenUsage/updated":this.handleAppServerUsage(t);break;case"turn/completed":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null;(!this.activeTurnId||s===this.activeTurnId)&&(this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),this.emitFinalIfOpen());break}case"turn/failed":{const r=_(t);if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r||"turn failed");break}case"error":{const r=_(t);if(te(r)){this.emitTransientStatus(r);return}if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r);break}}}scheduleManagedAsyncRolloutRecovery(e){if(!this.managedAgentPolicy&&!this.managedPermissionConfig||!this.managedTurnReplay||!v(new Error(e)))return!1;if(this.managedAsyncRecovery)return!0;if(this.managedTurnReplay.recoveryCount>=2)return!1;this.managedTurnReplay.recoveryCount+=1;const t=this.managedTurnReplay.recoveryCount;return this.logManagedThreadLifecycle("rollout.failed-async",{threadId:this.agentSessionId,recoveryCount:t}),this.managedAsyncRecovery=this.recoverManagedTurnAfterAsyncRolloutFailure().catch(r=>{const s=v(r)?"no rollout found after managed thread recovery":r instanceof Error?r.message:"managed thread recovery failed";this.emitErrorIfOpen(s)}).finally(()=>{this.managedAsyncRecovery=null}),!0}async recoverManagedTurnAfterAsyncRolloutFailure(){const e=this.managedTurnReplay,t=this.agentSessionId;if(!e||!t||this.terminalState!=="open")return;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(e.modelId);const r=this.agentSessionId;if(!r)throw new Error("codex app-server did not recreate the managed thread");this.logManagedThreadLifecycle("thread.recreated-async",{previousThreadId:t,threadId:r,recoveryCount:e.recoveryCount}),this.emitEvent({state:"start",agentSessionId:r});const s=await this.startFreshManagedTurnWithReadinessRetry(r,e.text,e.modelId,e.reasoningEffort,e.attachments);if(this.activeTurnId=s.turn?.id??null,this.managedRoomToolThreadId===r&&this.activeTurnId&&!this.managedRoomTools.bindTurn(r,this.activeTurnId))throw new Error("codex_managed_room_turn_binding_failed")}async handleManagedRoomToolCall(e,t){const r=await this.managedRoomTools.execute(t);if(this.writeAppServerResponse(e,r),r.success&&t.tool==="shennian_room_send"){const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:null,i=typeof s?.text=="string"?s.text.trim():"";i&&this.emitText(i,"block")}}writeAppServerResponse(e,t){const r=this.process;r?.stdin&&r.stdin.write(`${JSON.stringify({id:e,result:t})}
6
- `)}mapThreadStatusToRunPhase(e){const t=e?.type==="active"&&Array.isArray(e.activeFlags)?e.activeFlags:[];return t.includes("waitingOnApproval")?"waiting_approval":t.includes("waitingOnUserInput")?"waiting_user_input":"thinking"}handleAppServerNonJsonStdout(e){const t=ie(e);re(t)&&this.failAppServerStartup(new Error("Codex \u672A\u767B\u5F55\u3002\u8BF7\u5148\u5728\u8FD9\u53F0\u7535\u8111\u7684\u7EC8\u7AEF\u8FD0\u884C `codex`\uFF0C\u6309\u63D0\u793A\u5B8C\u6210 ChatGPT \u767B\u5F55\u6216\u914D\u7F6E API key\uFF0C\u7136\u540E\u518D\u56DE\u5230\u795E\u5FF5\u53D1\u9001\u6D88\u606F\u3002"))}failAppServerStartup(e){this.appServerStartupError||(this.appServerStartupError=e,this.rejectAllPending(e),this.process?.kill("SIGTERM"))}handleAppServerCompletedItem(e){const t=typeof e.item=="object"&&e.item!==null?e.item:null;if(!(!t||typeof t.type!="string")&&!j(t))switch(t.type){case"agentMessage":{const r=typeof t.id=="string"?t.id:"";if(r&&this.deltaItemIds.has(r))return;typeof t.text=="string"&&this.emitText(t.text,"block");break}case"commandExecution":{const r=typeof t.command=="string"?t.command:"",s=typeof t.aggregatedOutput=="string"?t.aggregatedOutput:"";r&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:r}}),this.emitEvent({state:"tool-result",name:"command_execution",result:[s,t.exitCode!=null?`
7
- (exit ${t.exitCode})`:""].join("").trim()});break}case"mcpToolCall":case"dynamicToolCall":{const r=typeof t.tool=="string"?t.tool:t.type;if(y(r))return;const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:{};this.emitEvent({state:"tool-call",name:r,args:s}),this.emitEvent({state:"tool-result",name:r,result:A(t.error??t.result??t.contentItems??"")});break}case"fileChange":break;case"approvalRequest":case"approval_request":case"permissionRequest":case"permission_request":case"userInputRequired":case"user_input_required":{this.emitApprovalPending(t);break}}}handleAppServerUsage(e){const t=typeof e.tokenUsage=="object"&&e.tokenUsage!==null?e.tokenUsage:null,r=typeof t?.last=="object"&&t.last!==null?t.last:null,s=typeof t?.total=="object"&&t.total!==null?t.total:null,i=r??s;if(!i)return;const n=typeof i.inputTokens=="number"?i.inputTokens:void 0,a=typeof i.outputTokens=="number"?i.outputTokens:void 0;(n!=null||a!=null)&&(this.pendingUsage={inputTokens:n??0,outputTokens:a??0})}handleCodexItemLine(e){const t=e.item;if(t?.type&&!Z(t))switch(t.type){case"agent_message":case"reasoning":{e.type==="item.completed"&&t.text&&this.emitText(t.text,"block");break}case"command_execution":{if(e.type==="item.started"&&t.command&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:t.command}}),e.type==="item.completed"){const r=[t.aggregated_output??"",t.exit_code!=null?`
1
+ import{spawnSync as q}from"node:child_process";import{createInterface as w}from"node:readline";import{createHash as S,randomUUID as N}from"node:crypto";import g from"node:path";import{AgentAdapter as D,registerAgent as L}from"./adapter.js";import{resolveBuiltinCommand as T,spawnAgentCommand as x}from"./command-spec.js";import{buildAgentProcessEnv as F,buildManagedAgentProcessEnv as $,buildManagedNativeFullProcessEnv as U}from"../agent-env.js";import{ensurePlatformInstructionsFile as W}from"./platform-instructions.js";import{CODEX_DESKTOP_SEND_UNAVAILABLE as C}from"@shennian/wire";import{isCodexThreadTailInterrupted as z}from"../native-fusion/codex-files.js";import{resolveManagedAgentAdapterEnforcement as B,isManagedAgentNativeFull as R}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as G}from"../security/managed-agent-runtime.js";import{CODEX_MANAGED_ROOM_DYNAMIC_TOOLS as J,CodexManagedRoomToolBinding as V}from"./codex-managed-room-tools.js";import{assertCodexManagedPermissionProfile as E,CODEX_MANAGED_RUNTIME_SECURITY as H,compileCodexManagedPermissions as X,extractCodexMcpServerNames as K}from"./codex-managed-permissions.js";import{CODEX_APP_SERVER_CLIENT_INFO as Q,extractAppServerErrorMessage as _,formatCodexErrorMessage as j,formatTransientCodexStatus as Y,isCodexCollabAgentItem as Z,isCodexCollabAgentToolName as y,isCodexLegacyCollabAgentItem as ee,isCodexUnsupportedEffortError as te,isMissingCodexRolloutError as v,isTransientCodexErrorMessage as re,looksLikeCodexInteractiveAuthPrompt as se,looksLikeFatalCodexStderr as ne,normalizeCodexModelId as I,normalizeCodexReasoningEffort as ie,normalizeCodexStderr as k,normalizeTerminalText as oe,safeStringify as A,stripGitDirectiveArtifacts as ae}from"./codex-utils.js";import{isCodexUnsupportedEffortError as Ne,isMissingCodexRolloutError as De,normalizeCodexModelId as Le,normalizeCodexReasoningEffort as Fe}from"./codex-utils.js";G("codex",H);function P(o){const e=o instanceof Error?o.message:String(o);return/already has an active writer|thread-store conflict/i.test(e)}function de(o){const e=o instanceof Error?o.message:String(o);return/paginated(?:_threads|\s+(?:thread\s+)?history)?.*(?:not supported|unsupported|unavailable)/i.test(e)||/(?:not supported|unsupported|unavailable).*paginated(?:_threads|\s+(?:thread\s+)?history)?/i.test(e)}function le(o){const e=o instanceof Error?o.message:String(o);return/unknown field [`'"]?excludeTurns/i.test(e)||/excludeTurns.*(?:not supported|unsupported|unavailable)/i.test(e)}function ce(o){const e=o instanceof Error?o.message:String(o);return/(?:method not found|unknown method).*(?:project\/list|project\/create)/i.test(e)||/(?:project\/list|project\/create).*(?:not supported|unsupported|unavailable)/i.test(e)}function ue(o,e){const t=g.resolve(e);let r;for(const s of o)if(s.id)for(const i of s.roots??[]){if(!i.path)continue;const n=g.resolve(i.path),a=g.relative(n,t);!(a===""||!a.startsWith("..")&&!g.isAbsolute(a))||n.length<=(r?.rootLength??-1)||(r={id:s.id,rootLength:n.length})}return r?.id}function M(o,e){const t=e?.flatMap(s=>he(s)).filter(s=>!/^https?:\/\//i.test(s.path)).filter(s=>s.path);return{type:"text",text:me(o,e),text_elements:[],...t?.length?{local_images:t}:{}}}function he(o){if(o.kind==="image")return o.previewData?[{path:o.path,data:o.previewData,mimeType:o.mimeType}]:[{path:o.path}];if(o.mimeType.startsWith("video/")){const e=pe(o.path);return e?[{path:e}]:[]}return[]}function pe(o){if(!o||/^https?:\/\//i.test(o))return null;const e=g.extname(o),r=`${e?o.slice(0,-e.length):o}.preview.png`;return q("ffmpeg",["-y","-ss","0","-i",o,"-frames:v","1","-vf","scale=320:-1",r],{stdio:"ignore",timeout:15e3}).status===0?r:null}function me(o,e){const t=e?.filter(i=>i.kind!=="image").filter(i=>i.path&&!/^https?:\/\//i.test(i.path));if(!t?.length||t.every(i=>o.includes(i.path)))return o;const s=t.map((i,n)=>{const a=i.name||`attachment-${n+1}`,d=i.mimeType?` (${i.mimeType})`:"";return`[${b(a)}${d}](<${i.path}>)`});return[o,"",...s].join(`
2
+ `)}function ge(o,e){const t=e?.filter(s=>s.path&&!/^https?:\/\//i.test(s.path)&&!o.includes(s.path));if(!t?.length)return o;const r=t.map((s,i)=>{const n=b(s.name||`attachment-${i+1}`);return s.kind==="image"?`![${n}](<${s.path}>)`:`[${n}](<${s.path}>)`});return[o,"",...r].join(`
3
+ `)}function fe(o,e,t){return["queue","--thread",o,"--message",ge(e,t)]}function b(o){return o.replace(/[[\]\\]/g,"\\$&")}class ye extends D{options;get supportsActiveInput(){return!0}async injectActiveInput(e){const t=this.agentSessionId,r=this.activeTurnId;if(!t||!r||!this.process)throw new Error("codex_active_turn_unavailable");const s=await this.sendRpc("turn/steer",{threadId:t,expectedTurnId:r,input:[M(e.text,e.attachments)],...e.clientMessageId?{clientUserMessageId:e.clientMessageId}:{}});if(s.turnId&&s.turnId!==r)throw new Error("codex_active_turn_changed")}type="codex";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;workDir=null;seq=0;runId="";pendingUsage;agentSessionId=null;hasEmittedText=!1;textTail="";terminalState="open";forceCloseTimer=null;stderrBuf="";rpcSeq=1;pendingRequests=new Map;appServerReady=null;appServerStartupError=null;activeTurnId=null;deltaItemIds=new Set;lastTransientStatus="";agentSystemPrompt="";managedAgentPolicy=null;managedPermissionConfig=null;configurationRestartRequired=!1;managedRoomTools=new V;configuredManagedRoomContextToken=null;configuredManagedRoomExecutor=null;managedRoomToolThreadId=null;preparedExternalOwnerThreadId=null;managedTurnReplay=null;managedAsyncRecovery=null;persistNativeSession=!0;nativeSessionVisibility="user";constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){const t=this.configurationFingerprint();this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),("managedRoomContextToken"in e||"managedRoomExecutor"in e)&&(this.managedRoomTools.deactivateTurn(),this.configuredManagedRoomContextToken=e.managedRoomContextToken?.trim()||null,this.configuredManagedRoomExecutor=e.managedRoomExecutor??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir);const r=this.configurationFingerprint();t!==r&&this.process&&(this.configurationRestartRequired=!0)}configurationFingerprint(){const e=Object.keys(this.extraEnv).sort().map(t=>[t,this.extraEnv[t]??null]);return S("sha256").update(JSON.stringify({sessionId:this.shennianSessionId,externalChannel:this.externalChannel,env:e,managedAgentPolicy:this.managedAgentPolicy})).digest("hex")}buildProcessEnv(e={}){if(!this.managedAgentPolicy)return F({...e,...this.extraEnv});if(R(this.managedAgentPolicy))return U({...e,...this.extraEnv});const t=Object.fromEntries(Object.entries(this.extraEnv).filter(([r])=>r!=="SHENNIAN_MANAGED_ROOM_CONTEXT"&&r!=="SHENNIAN_MANAGED_ROOM_IPC_ROOT"));return $({agentType:"codex",providerEnv:t,sessionEnv:t,runtimeEnv:e})}async start(e,t,r,s){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=s?.persistNativeSession!==!1,this.nativeSessionVisibility=s?.nativeSessionVisibility??"user",r&&(this.agentSessionId=r)}async prepareSend(e,t,r,s,i,n){const a=i?.trim()??"";if(a!==this.agentSystemPrompt&&(this.agentSystemPrompt=a,this.process&&await this.killProcess(!0)),!(!this.agentSessionId||this.activeTurnId)){this.preparedExternalOwnerThreadId=null;try{await this.ensureAppServer(I(t))}catch(d){if(!P(d))throw d;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:d});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:d});this.preparedExternalOwnerThreadId=this.agentSessionId}}}async send(e,t,r,s,i,n){if(n?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");if(n?.source==="room_activation"&&(!this.configuredManagedRoomContextToken||!this.configuredManagedRoomExecutor))throw new Error("codex_managed_room_tool_context_unavailable");this.activeTurnId&&(await this.interruptActiveTurn().catch(()=>{}),await this.killProcess(!0)),this.configurationRestartRequired&&this.process&&await this.killProcess(!0),this.configurationRestartRequired=!1;const a=I(t),d=ie(r),c=i?.trim()??"";if(c!==this.agentSystemPrompt&&(this.agentSystemPrompt=c,this.process&&await this.killProcess(!0)),n?.source==="room_activation"&&this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),this.runId=N(),this.seq=0,this.resetRunState(),this.agentSessionId&&this.preparedExternalOwnerThreadId===this.agentSessionId)return this.preparedExternalOwnerThreadId=null,{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)};try{await this.ensureAppServer(a)}catch(h){if(!this.agentSessionId||!P(h))throw h;if(n?.source==="room_activation")throw new Error("codex_managed_thread_owned_externally",{cause:h});if(this.isThreadTailInterrupted(this.agentSessionId))throw new Error(C,{cause:h});return{deliveryMode:"external_owner_queue",queuedSubmissionId:await this.enqueueForExternalOwner(this.agentSessionId,e,s)}}const l=this.agentSessionId;if(!l)throw new Error("codex app-server did not create a thread");this.emitEvent({state:"start",agentSessionId:l}),this.managedTurnReplay=this.managedPermissionConfig?{text:e,modelId:a,reasoningEffort:d,attachments:s,recoveryCount:0}:null;const p=await this.startTurnWithRecovery(l,e,a,d,s),m=this.agentSessionId??l;if(this.activeTurnId=p.turn?.id??null,this.managedRoomToolThreadId===m&&this.activeTurnId&&!this.managedRoomTools.bindTurn(m,this.activeTurnId))throw await this.killProcess(),new Error("codex_managed_room_turn_binding_failed");return{deliveryMode:"direct"}}isThreadTailInterrupted(e){return this.options.isThreadTailInterrupted?.(e)??z(e)}async enqueueForExternalOwner(e,t,r){const s=T("codex");if(!s)throw new Error('Command "codex" not found. Is OpenAI Codex CLI installed?');const i=fe(e,t,r),n=x(s,i,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});return await new Promise((a,d)=>{let c="",l="",p=!1;const m=(u,f)=>{p||(p=!0,clearTimeout(h),u?d(u):a(f))},h=setTimeout(()=>{n.kill("SIGTERM"),m(new Error("Codex Desktop message queue timed out"))},6e4);h.unref?.(),n.stdout?.on("data",u=>{c+=u.toString()}),n.stderr?.on("data",u=>{l+=u.toString()}),n.once("error",u=>m(u)),n.once("close",u=>{const f=`${c}
4
+ ${l}`.trim();if(u!==0){m(new Error(f||`codex queue exited with code ${u??"unknown"}`));return}const O=f.match(/Queued message\s+([^\s]+)\s+for thread/i)?.[1];m(void 0,O)})})}async resume(e){await this.killProcess(),this.agentSessionId=e,this.resetTextState()}async setTitle(e,t,r){const s=e.trim(),i=t.replace(/\s+/g," ").trim();!s||!i||(this.agentSessionId=s,r?.trim()&&(this.workDir=r),await this.ensureAppServer(),await this.sendRpc("thread/name/set",{threadId:s,name:i}))}async stop(){this.managedRoomTools.deactivateTurn(),await this.interruptActiveTurn().catch(()=>{}),await this.killProcess()}async getStatus(){const e=this.agentSessionId,t=this.activeTurnId;if(!e||!this.process)return{active:!1,runId:t,runPhase:null,canStop:!1};let r=null;try{r=(await this.sendRpc("thread/read",{threadId:e,includeTurns:!1},5e3)).thread?.status??null}catch{}const s=r?.type==="active"||!!t;return{active:s,runId:t,runPhase:s?this.mapThreadStatusToRunPhase(r):null,canStop:!!(s&&t&&this.process)}}spawnCodex(e){const t=T("codex");if(!t){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const r=x(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=r,w({input:r.stdout}).on("line",n=>{if(n.trim())try{const a=JSON.parse(n);this.handleStreamEvent(a)}catch{this.emitEvent({state:"delta",text:n})}});let i="";r.stderr?.on("data",n=>{i+=n.toString()}),r.on("close",n=>{this.process===r&&(this.process=null,this.clearForceCloseTimer(),this.handleProcessClose(n,i))}),r.on("error",n=>{this.process===r&&(this.process=null,n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}spawnAppServer(){const e=T("codex");if(!e){this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?'));return}const t=["app-server","--listen","stdio://"],r=this.options.modelInstructionsFile??W(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,this.agentSystemPrompt);r&&t.push("-c",`model_instructions_file=${JSON.stringify(r)}`);const s=x(e,t,{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:this.buildProcessEnv({NO_COLOR:"1"})});this.process=s,this.stderrBuf="",this.appServerStartupError=null,w({input:s.stdout}).on("line",n=>{if(!n.trim())return;let a;try{a=JSON.parse(n)}catch{this.handleAppServerNonJsonStdout(n);return}this.handleAppServerMessage(a)}),s.stderr?.on("data",n=>{this.stderrBuf+=n.toString()}),s.on("close",n=>{if(this.process!==s)return;const a=this.activeTurnId!=null;this.process=null,this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(new Error(k(this.stderrBuf)||`codex app-server exited with code ${n}`)),this.terminalState==="open"&&a&&this.handleProcessClose(n,this.stderrBuf)}),s.on("error",n=>{this.process===s&&(this.process=null,this.managedRoomTools.reset(),this.clearConfiguredManagedRoomContext(),this.rejectAllPending(n),n.code==="ENOENT"?this.emit("error",new Error('Command "codex" not found. Is OpenAI Codex CLI installed?')):this.emit("error",n))})}async ensureAppServer(e){return this.appServerReady?this.appServerReady:(this.spawnAppServer(),this.appServerReady=this.initializeAppServer(e).catch(async t=>{throw this.appServerReady=null,await this.killProcess(),t}),this.appServerReady)}async initializeAppServer(e){const t=I(e);await this.sendRpc("initialize",{clientInfo:Q,capabilities:{experimentalApi:!0}}),this.managedPermissionConfig=this.managedAgentPolicy&&!R(this.managedAgentPolicy)?await this.buildManagedPermissionConfig():null;const r=!!(this.configuredManagedRoomContextToken||this.configuredManagedRoomExecutor);if(this.managedAgentPolicy&&r&&!this.managedRoomTools.isConfigured()&&(this.managedRoomTools.configure(this.configuredManagedRoomContextToken,this.configuredManagedRoomExecutor),!this.managedRoomTools.isConfigured()))throw new Error("codex_managed_room_tool_context_unavailable");if(this.agentSessionId&&this.managedAgentPolicy&&r&&this.agentSessionId!==this.managedRoomToolThreadId){if(!this.managedRoomTools.isConfigured())throw new Error("codex_managed_room_tool_context_unavailable");this.agentSessionId=null}if(this.agentSessionId){const c={threadId:this.agentSessionId,cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},persistExtendedHistory:!0,...t?{model:t}:{}};let l;try{l=await this.sendRpc("thread/resume",{...c,excludeTurns:!0})}catch(p){if(!le(p))throw p;l=await this.sendRpc("thread/resume",c)}this.agentSessionId=l.thread?.id??this.agentSessionId,this.managedPermissionConfig&&E(l,this.managedPermissionConfig.profileId),this.managedAgentPolicy&&r&&(this.managedRoomTools.bindThread(this.agentSessionId),this.managedRoomToolThreadId=this.agentSessionId);return}const s=this.options.hidden||this.nativeSessionVisibility==="internal"||!this.persistNativeSession,i=s?void 0:await this.resolveCodexProjectId(),n={cwd:this.workDir,approvalPolicy:"never",...this.managedPermissionConfig?{config:this.managedPermissionConfig.threadConfig}:{sandbox:"danger-full-access"},serviceName:"Shennian",...s?{}:{threadSource:"user"},experimentalRawEvents:!1,persistExtendedHistory:!0,...this.managedAgentPolicy&&r?{dynamicTools:J}:{},...i?{projectId:i}:{},...t?{model:t}:{}};let a;if(s&&!this.managedPermissionConfig)a=await this.sendRpc("thread/start",n);else try{a=await this.sendRpc("thread/start",{...n,historyMode:"paginated"})}catch(c){throw de(c)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5728 Codex Desktop \u4E2D\u7EE7\u7EED\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u964D\u7EA7\u521B\u5EFA\u4E0D\u53EF\u89C1\u7684 legacy \u4F1A\u8BDD\u3002",{cause:c}):c}const d=a.thread?.id;if(!d)throw new Error("codex app-server thread/start returned no thread id");this.managedPermissionConfig&&E(a,this.managedPermissionConfig.profileId),this.managedAgentPolicy&&r&&(this.managedRoomTools.bindThread(d),this.managedRoomToolThreadId=d),this.agentSessionId=d}async buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e)throw new Error("managed_agent_policy_missing");const t=e.adapterPolicy.externalCapabilities.mcp?[]:K(await this.sendRpc("config/read",{cwd:e.adapterPolicy.workDir}));return X(B(e),e.adapterPolicy.workDir,{configuredMcpServerNames:t,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}async resolveCodexProjectId(){const e=this.workDir?.trim();if(e)try{const t=[];let r;do{const c=await this.sendRpc("project/list",{limit:100,...r?{cursor:r}:{}});t.push(...c.data??[]),r=c.nextCursor}while(r);const s=ue(t,e);if(s)return s;const i=g.resolve(e),n=`shennian-project-${S("sha256").update(i).digest("hex")}`,d=(await this.sendRpc("project/create",{idempotencyKey:n,name:g.basename(i)||i,roots:[{path:i}],metadata:{createdBy:"Shennian"}})).project?.id;if(!d)throw new Error("codex app-server project/create returned no project id");return d}catch(t){throw ce(t)?new Error("\u5F53\u524D Codex CLI \u4E0D\u652F\u6301\u521B\u5EFA\u53EF\u5F52\u5C5E\u5230 Codex Desktop \u9879\u76EE\u7684\u65B0\u4F1A\u8BDD\uFF0C\u8BF7\u624B\u52A8\u5347\u7EA7 Codex CLI \u540E\u91CD\u8BD5\u3002\u795E\u5FF5\u4E0D\u4F1A\u81EA\u52A8\u5347\u7EA7\uFF0C\u4E5F\u4E0D\u4F1A\u76F4\u63A5\u4FEE\u6539 Codex Desktop \u7684\u79C1\u6709\u4FA7\u680F\u7D22\u5F15\u3002",{cause:t}):t}}async startTurnWithRecovery(e,t,r,s,i){try{return await this.startTurn(e,t,r,s,i)}catch(n){if(!v(n))throw n;if(this.managedAgentPolicy||this.managedPermissionConfig){this.logManagedThreadLifecycle("rollout.missing",{threadId:e,recovery:"recreate"}),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(r);const a=this.agentSessionId;if(!a)throw new Error("codex app-server did not recreate the managed thread",{cause:n});return this.logManagedThreadLifecycle("thread.recreated",{previousThreadId:e,threadId:a}),this.emitEvent({state:"start",agentSessionId:a}),await this.startFreshManagedTurnWithReadinessRetry(a,t,r,s,i)}return await this.killProcess(),await this.ensureAppServer(r),await this.startTurn(e,t,r,s,i)}}async startFreshManagedTurnWithReadinessRetry(e,t,r,s,i){const n=[0,100,300,1e3];let a;for(let d=0;d<n.length;d+=1){const c=n[d];c>0&&await new Promise(l=>setTimeout(l,c));try{const l=await this.startTurn(e,t,r,s,i);return d>0&&this.logManagedThreadLifecycle("rollout.ready",{threadId:e,attempt:d+1}),l}catch(l){if(a=l,!v(l)||d===n.length-1)throw l;this.logManagedThreadLifecycle("rollout.retry",{threadId:e,attempt:d+2,delayMs:n[d+1]})}}throw a}logManagedThreadLifecycle(e,t){console.error(`[codex.managed] ${JSON.stringify({event:e,...t})}`)}async startTurn(e,t,r,s,i){try{return await this.sendRpc("turn/start",{threadId:e,input:[M(t,i)],approvalPolicy:"never",...this.managedPermissionConfig?{}:{sandboxPolicy:{type:"dangerFullAccess"}},...r?{model:r}:{},...s?{effort:s}:{}})}catch(n){throw s&&te(n)?new Error(`Codex app-server does not accept reasoning effort "${s}" for this turn. Refresh models or upgrade Codex CLI, then retry.`,{cause:n}):n}}async interruptActiveTurn(){const e=this.agentSessionId,t=this.activeTurnId;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),!(!e||!t||!this.process)&&await this.sendRpc("turn/interrupt",{threadId:e,turnId:t},5e3)}sendRpc(e,t,r=6e4){if(this.appServerStartupError)return Promise.reject(this.appServerStartupError);const s=this.process;if(!s?.stdin)return Promise.reject(new Error("codex app-server is not running"));const i=this.rpcSeq++,n=JSON.stringify({id:i,method:e,params:t});return new Promise((a,d)=>{const c=setTimeout(()=>{this.pendingRequests.delete(i),d(new Error(`codex app-server request timed out: ${e}`))},r);this.pendingRequests.set(i,{resolve:a,reject:d,timer:c}),s.stdin.write(`${n}
5
+ `,l=>{l&&(clearTimeout(c),this.pendingRequests.delete(i),d(l))})})}handleAppServerMessage(e){if(e.method==="item/tool/call"&&e.id!=null){this.handleManagedRoomToolCall(e.id,e.params??{});return}if(e.id!=null){const r=typeof e.id=="number"?this.pendingRequests.get(e.id):void 0;r&&(clearTimeout(r.timer),this.pendingRequests.delete(e.id),e.error?r.reject(new Error(e.error.message||`codex app-server error ${e.error.code??""}`.trim())):r.resolve(e.result))}if(!e.method)return;const t=e.params??{};switch(e.method){case"turn/started":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null,i=typeof t.threadId=="string"?t.threadId:"";s&&(this.activeTurnId=s,this.managedRoomToolThreadId===i&&!this.managedRoomTools.bindTurn(i,s)&&this.emitErrorIfOpen("codex_managed_room_turn_binding_failed"));break}case"thread/status/changed":{const r=typeof t.threadId=="string"?t.threadId:"";if(r&&this.agentSessionId&&r!==this.agentSessionId)break;const s=typeof t.status=="object"&&t.status!==null?t.status:null;s?.type==="active"&&this.emitEvent({state:"heartbeat",runPhase:this.mapThreadStatusToRunPhase(s)});break}case"item/agentMessage/delta":{const r=typeof t.itemId=="string"?t.itemId:"";r&&this.deltaItemIds.add(r),typeof t.delta=="string"&&this.emitText(t.delta);break}case"item/completed":this.handleAppServerCompletedItem(t);break;case"thread/tokenUsage/updated":this.handleAppServerUsage(t);break;case"turn/completed":{const r=typeof t.turn=="object"&&t.turn!==null?t.turn:null,s=typeof r?.id=="string"?r.id:null;(!this.activeTurnId||s===this.activeTurnId)&&(this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),this.emitFinalIfOpen());break}case"turn/failed":{const r=_(t);if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r||"turn failed");break}case"error":{const r=_(t);if(re(r)){this.emitTransientStatus(r);return}if(this.scheduleManagedAsyncRolloutRecovery(r))return;this.emitErrorIfOpen(r);break}}}scheduleManagedAsyncRolloutRecovery(e){if(!this.managedAgentPolicy&&!this.managedPermissionConfig||!this.managedTurnReplay||!v(new Error(e)))return!1;if(this.managedAsyncRecovery)return!0;if(this.managedTurnReplay.recoveryCount>=2)return!1;this.managedTurnReplay.recoveryCount+=1;const t=this.managedTurnReplay.recoveryCount;return this.logManagedThreadLifecycle("rollout.failed-async",{threadId:this.agentSessionId,recoveryCount:t}),this.managedAsyncRecovery=this.recoverManagedTurnAfterAsyncRolloutFailure().catch(r=>{const s=v(r)?"no rollout found after managed thread recovery":r instanceof Error?r.message:"managed thread recovery failed";this.emitErrorIfOpen(s)}).finally(()=>{this.managedAsyncRecovery=null}),!0}async recoverManagedTurnAfterAsyncRolloutFailure(){const e=this.managedTurnReplay,t=this.agentSessionId;if(!e||!t||this.terminalState!=="open")return;this.activeTurnId=null,this.managedRoomTools.deactivateTurn(),await this.killProcess(!0),this.agentSessionId=null,this.managedRoomToolThreadId=null,await this.ensureAppServer(e.modelId);const r=this.agentSessionId;if(!r)throw new Error("codex app-server did not recreate the managed thread");this.logManagedThreadLifecycle("thread.recreated-async",{previousThreadId:t,threadId:r,recoveryCount:e.recoveryCount}),this.emitEvent({state:"start",agentSessionId:r});const s=await this.startFreshManagedTurnWithReadinessRetry(r,e.text,e.modelId,e.reasoningEffort,e.attachments);if(this.activeTurnId=s.turn?.id??null,this.managedRoomToolThreadId===r&&this.activeTurnId&&!this.managedRoomTools.bindTurn(r,this.activeTurnId))throw new Error("codex_managed_room_turn_binding_failed")}async handleManagedRoomToolCall(e,t){const r=await this.managedRoomTools.execute(t);if(this.writeAppServerResponse(e,r),r.success&&t.tool==="shennian_room_send"){const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:null,i=typeof s?.text=="string"?s.text.trim():"";i&&this.emitText(i,"block")}}writeAppServerResponse(e,t){const r=this.process;r?.stdin&&r.stdin.write(`${JSON.stringify({id:e,result:t})}
6
+ `)}mapThreadStatusToRunPhase(e){const t=e?.type==="active"&&Array.isArray(e.activeFlags)?e.activeFlags:[];return t.includes("waitingOnApproval")?"waiting_approval":t.includes("waitingOnUserInput")?"waiting_user_input":"thinking"}handleAppServerNonJsonStdout(e){const t=oe(e);se(t)&&this.failAppServerStartup(new Error("Codex \u672A\u767B\u5F55\u3002\u8BF7\u5148\u5728\u8FD9\u53F0\u7535\u8111\u7684\u7EC8\u7AEF\u8FD0\u884C `codex`\uFF0C\u6309\u63D0\u793A\u5B8C\u6210 ChatGPT \u767B\u5F55\u6216\u914D\u7F6E API key\uFF0C\u7136\u540E\u518D\u56DE\u5230\u795E\u5FF5\u53D1\u9001\u6D88\u606F\u3002"))}failAppServerStartup(e){this.appServerStartupError||(this.appServerStartupError=e,this.rejectAllPending(e),this.process?.kill("SIGTERM"))}handleAppServerCompletedItem(e){const t=typeof e.item=="object"&&e.item!==null?e.item:null;if(!(!t||typeof t.type!="string")&&!Z(t))switch(t.type){case"agentMessage":{const r=typeof t.id=="string"?t.id:"";if(r&&this.deltaItemIds.has(r))return;typeof t.text=="string"&&this.emitText(t.text,"block");break}case"commandExecution":{const r=typeof t.command=="string"?t.command:"",s=typeof t.aggregatedOutput=="string"?t.aggregatedOutput:"";r&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:r}}),this.emitEvent({state:"tool-result",name:"command_execution",result:[s,t.exitCode!=null?`
7
+ (exit ${t.exitCode})`:""].join("").trim()});break}case"mcpToolCall":case"dynamicToolCall":{const r=typeof t.tool=="string"?t.tool:t.type;if(y(r))return;const s=typeof t.arguments=="object"&&t.arguments!==null?t.arguments:{};this.emitEvent({state:"tool-call",name:r,args:s}),this.emitEvent({state:"tool-result",name:r,result:A(t.error??t.result??t.contentItems??"")});break}case"fileChange":break;case"approvalRequest":case"approval_request":case"permissionRequest":case"permission_request":case"userInputRequired":case"user_input_required":{this.emitApprovalPending(t);break}}}handleAppServerUsage(e){const t=typeof e.tokenUsage=="object"&&e.tokenUsage!==null?e.tokenUsage:null,r=typeof t?.last=="object"&&t.last!==null?t.last:null,s=typeof t?.total=="object"&&t.total!==null?t.total:null,i=r??s;if(!i)return;const n=typeof i.inputTokens=="number"?i.inputTokens:void 0,a=typeof i.outputTokens=="number"?i.outputTokens:void 0;(n!=null||a!=null)&&(this.pendingUsage={inputTokens:n??0,outputTokens:a??0})}handleCodexItemLine(e){const t=e.item;if(t?.type&&!ee(t))switch(t.type){case"agent_message":case"reasoning":{e.type==="item.completed"&&t.text&&this.emitText(t.text,"block");break}case"command_execution":{if(e.type==="item.started"&&t.command&&this.emitEvent({state:"tool-call",name:"command_execution",args:{command:t.command}}),e.type==="item.completed"){const r=[t.aggregated_output??"",t.exit_code!=null?`
8
8
  (exit ${t.exit_code})`:""];this.emitEvent({state:"tool-result",name:"command_execution",result:r.join("").trim()||String(t.status??"")})}break}case"mcp_tool_call":{if(t.tool&&y(t.tool))return;if(e.type==="item.started"&&this.emitEvent({state:"tool-call",name:t.tool??"mcp_tool",args:{server:t.server,...t.arguments&&typeof t.arguments=="object"?t.arguments:{}}}),e.type==="item.completed"){const r=t.error&&typeof t.error=="object"?t.error.message:void 0;this.emitEvent({state:"tool-result",name:t.tool??"mcp_tool",result:r??A(t.result)})}break}case"file_change":break;case"web_search":{e.type==="item.completed"&&t.query&&this.emitText(`[web_search] ${t.query}`,"block");break}case"todo_list":{if(e.type==="item.completed"&&t.items?.length){const r=t.items.map(s=>`- [${s.completed?"x":" "}] ${s.text}`).join(`
9
- `);this.emitText(r,"block")}break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{(e.type==="item.started"||e.type==="item.completed")&&this.emitApprovalPending(t);break}case"error":{e.type==="item.completed"&&t.message&&this.emitEvent({state:"error",message:t.message});break}default:break}}handleStreamEvent(e){const t=e.type??e.event;switch(t?.startsWith("item.")&&this.handleCodexItemLine(e),t){case"turn.completed":{const s=e.usage;if(s){const i=s.input_tokens??s.prompt_tokens,n=s.output_tokens??s.completion_tokens;(i!=null||n!=null)&&(this.pendingUsage={inputTokens:i??0,outputTokens:n??0})}this.emitFinalIfOpen();return}case"turn.failed":{const s=typeof e.error=="object"&&e.error?.message?e.error.message:typeof e.error=="string"?e.error:"turn failed";this.emitErrorIfOpen(s);return}case"error":{const s=typeof e.message=="string"?e.message:"";if(s.includes("Reconnecting"))return;this.emitErrorIfOpen(s||(typeof e.error=="string"?e.error:"stream error"));return}case"thread.started":{const s=e.thread_id??e.session_id??e.id;typeof s=="string"&&s&&(this.agentSessionId=s,this.emitEvent({state:"start",agentSessionId:this.agentSessionId}));return}case"turn.started":return}if(t?.startsWith("item."))return;switch(e.type??e.event){case"message":case"text":case"content":{const s=e.content??e.text;s&&this.emitText(s);break}case"function_call":case"tool_call":{if(this.isApprovalLikeName(e.name)){this.emitApprovalPending(e);break}if(e.name&&y(e.name))return;this.emitEvent({state:"tool-call",name:e.name,args:e.arguments??e.input});break}case"function_call_output":case"tool_result":{if(e.name&&y(e.name))return;this.emitEvent({state:"tool-result",name:e.name,result:e.output??e.result});break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{this.emitApprovalPending(e);break}case"error":break;case"done":case"completed":{e.usage&&(this.pendingUsage={inputTokens:e.usage.prompt_tokens??e.usage.input_tokens??0,outputTokens:e.usage.completion_tokens??e.usage.output_tokens??0}),this.emitFinalIfOpen();break}}}emitEvent(e){if(this.terminalState!=="open"&&e.state!=="final"&&e.state!=="error"&&e.state!=="aborted")return;const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}isApprovalLikeName(e){return typeof e!="string"?!1:/approval|permission|confirm|user[_-]?input|request[_-]?user/i.test(e)}emitApprovalPending(e){const t=typeof e.command=="string"?e.command:"",r=typeof e.title=="string"&&e.title.trim()?e.title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",s=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:t?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${t}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";this.emitEvent({state:"approval-pending",approval:{title:r,content:s,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"}})}async killProcess(e=!1){const t=this.process;if(this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),e||this.clearConfiguredManagedRoomContext(),!t){this.rejectAllPending(new Error("codex app-server stopped"));return}this.process=null,this.clearForceCloseTimer(),t.kill("SIGTERM"),await new Promise(r=>{t.on("close",r),setTimeout(()=>{t.kill("SIGKILL"),r()},3e3)}),this.rejectAllPending(new Error("codex app-server stopped"))}rejectAllPending(e){for(const[t,r]of this.pendingRequests.entries())clearTimeout(r.timer),r.reject(e),this.pendingRequests.delete(t)}handleProcessClose(e,t){const r=k(t);if(e!==0&&e!==null){const s=r||`codex exited with code ${e}`;this.emitErrorIfOpen(s)}else se(r)?this.emitErrorIfOpen(r):this.emitFinalIfOpen();this.pendingUsage=void 0}emitFinalIfOpen(){this.terminalState==="open"&&(this.terminalState="final",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"final",usage:this.pendingUsage,agentSessionId:this.agentSessionId??void 0}),this.killProcess().catch(()=>{}))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"error",message:Q(e)}),this.scheduleProcessClose())}resetRunState(){this.pendingUsage=void 0,this.terminalState="open",this.deltaItemIds.clear(),this.lastTransientStatus="",this.clearForceCloseTimer(),this.resetTextState()}clearConfiguredManagedRoomContext(){this.configuredManagedRoomContextToken=null,this.configuredManagedRoomExecutor=null}emitTransientStatus(e){const t=Y(e);!t||t===this.lastTransientStatus||this.terminalState!=="open"||(this.lastTransientStatus=t,this.emitEvent({state:"delta",text:`${t}
10
- `,thinking:!0}))}resetTextState(){this.hasEmittedText=!1,this.textTail=""}emitText(e,t="delta"){if(!e)return;let r=oe(e);r&&(t==="block"&&this.hasEmittedText&&!r.startsWith(`
9
+ `);this.emitText(r,"block")}break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{(e.type==="item.started"||e.type==="item.completed")&&this.emitApprovalPending(t);break}case"error":{e.type==="item.completed"&&t.message&&this.emitEvent({state:"error",message:t.message});break}default:break}}handleStreamEvent(e){const t=e.type??e.event;switch(t?.startsWith("item.")&&this.handleCodexItemLine(e),t){case"turn.completed":{const s=e.usage;if(s){const i=s.input_tokens??s.prompt_tokens,n=s.output_tokens??s.completion_tokens;(i!=null||n!=null)&&(this.pendingUsage={inputTokens:i??0,outputTokens:n??0})}this.emitFinalIfOpen();return}case"turn.failed":{const s=typeof e.error=="object"&&e.error?.message?e.error.message:typeof e.error=="string"?e.error:"turn failed";this.emitErrorIfOpen(s);return}case"error":{const s=typeof e.message=="string"?e.message:"";if(s.includes("Reconnecting"))return;this.emitErrorIfOpen(s||(typeof e.error=="string"?e.error:"stream error"));return}case"thread.started":{const s=e.thread_id??e.session_id??e.id;typeof s=="string"&&s&&(this.agentSessionId=s,this.emitEvent({state:"start",agentSessionId:this.agentSessionId}));return}case"turn.started":return}if(t?.startsWith("item."))return;switch(e.type??e.event){case"message":case"text":case"content":{const s=e.content??e.text;s&&this.emitText(s);break}case"function_call":case"tool_call":{if(this.isApprovalLikeName(e.name)){this.emitApprovalPending(e);break}if(e.name&&y(e.name))return;this.emitEvent({state:"tool-call",name:e.name,args:e.arguments??e.input});break}case"function_call_output":case"tool_result":{if(e.name&&y(e.name))return;this.emitEvent({state:"tool-result",name:e.name,result:e.output??e.result});break}case"approval_request":case"approvalRequest":case"permission_request":case"permissionRequest":case"user_input_required":case"userInputRequired":{this.emitApprovalPending(e);break}case"error":break;case"done":case"completed":{e.usage&&(this.pendingUsage={inputTokens:e.usage.prompt_tokens??e.usage.input_tokens??0,outputTokens:e.usage.completion_tokens??e.usage.output_tokens??0}),this.emitFinalIfOpen();break}}}emitEvent(e){if(this.terminalState!=="open"&&e.state!=="final"&&e.state!=="error"&&e.state!=="aborted")return;const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}isApprovalLikeName(e){return typeof e!="string"?!1:/approval|permission|confirm|user[_-]?input|request[_-]?user/i.test(e)}emitApprovalPending(e){const t=typeof e.command=="string"?e.command:"",r=typeof e.title=="string"&&e.title.trim()?e.title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",s=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:t?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${t}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";this.emitEvent({state:"approval-pending",approval:{title:r,content:s,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"}})}async killProcess(e=!1){const t=this.process;if(this.appServerReady=null,this.activeTurnId=null,this.managedRoomTools.reset(),e||this.clearConfiguredManagedRoomContext(),!t){this.rejectAllPending(new Error("codex app-server stopped"));return}this.process=null,this.clearForceCloseTimer(),t.kill("SIGTERM"),await new Promise(r=>{t.on("close",r),setTimeout(()=>{t.kill("SIGKILL"),r()},3e3)}),this.rejectAllPending(new Error("codex app-server stopped"))}rejectAllPending(e){for(const[t,r]of this.pendingRequests.entries())clearTimeout(r.timer),r.reject(e),this.pendingRequests.delete(t)}handleProcessClose(e,t){const r=k(t);if(e!==0&&e!==null){const s=r||`codex exited with code ${e}`;this.emitErrorIfOpen(s)}else ne(r)?this.emitErrorIfOpen(r):this.emitFinalIfOpen();this.pendingUsage=void 0}emitFinalIfOpen(){this.terminalState==="open"&&(this.terminalState="final",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"final",usage:this.pendingUsage,agentSessionId:this.agentSessionId??void 0}),this.killProcess().catch(()=>{}))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.managedTurnReplay=null,this.managedRoomTools.deactivateTurn(),this.clearConfiguredManagedRoomContext(),this.emitEvent({state:"error",message:j(e)}),this.scheduleProcessClose())}resetRunState(){this.pendingUsage=void 0,this.terminalState="open",this.deltaItemIds.clear(),this.lastTransientStatus="",this.clearForceCloseTimer(),this.resetTextState()}clearConfiguredManagedRoomContext(){this.configuredManagedRoomContextToken=null,this.configuredManagedRoomExecutor=null}emitTransientStatus(e){const t=Y(e);!t||t===this.lastTransientStatus||this.terminalState!=="open"||(this.lastTransientStatus=t,this.emitEvent({state:"delta",text:`${t}
10
+ `,thinking:!0}))}resetTextState(){this.hasEmittedText=!1,this.textTail=""}emitText(e,t="delta"){if(!e)return;let r=ae(e);r&&(t==="block"&&this.hasEmittedText&&!r.startsWith(`
11
11
  `)&&(this.textTail.endsWith(`
12
12
  `)?r=`
13
13
  ${r}`:this.textTail.endsWith(`
14
14
 
15
15
  `)||(r=`
16
16
 
17
- ${r}`)),this.hasEmittedText=!0,this.textTail=(this.textTail+r).slice(-4),this.emitEvent({state:"delta",text:r}))}scheduleProcessClose(){const e=this.process;!e||this.forceCloseTimer||(this.forceCloseTimer=setTimeout(()=>{this.forceCloseTimer=null,this.process===e&&(e.kill("SIGTERM"),setTimeout(()=>{this.process===e&&e.kill("SIGKILL")},1e3))},250))}clearForceCloseTimer(){this.forceCloseTimer&&(clearTimeout(this.forceCloseTimer),this.forceCloseTimer=null)}}D("codex",()=>new ye);export{ye as CodexAdapter,fe as buildCodexQueueArgs,ge as buildCodexQueuedText,P as isCodexActiveWriterError,de as isCodexExcludeTurnsUnsupportedError,ae as isCodexPaginatedHistoryUnsupportedError,le as isCodexProjectApiUnsupportedError,Ne as isCodexUnsupportedEffortError,De as isMissingCodexRolloutError,Le as normalizeCodexModelId,Fe as normalizeCodexReasoningEffort,ce as selectCodexProjectIdForWorkDir};
17
+ ${r}`)),this.hasEmittedText=!0,this.textTail=(this.textTail+r).slice(-4),this.emitEvent({state:"delta",text:r}))}scheduleProcessClose(){const e=this.process;!e||this.forceCloseTimer||(this.forceCloseTimer=setTimeout(()=>{this.forceCloseTimer=null,this.process===e&&(e.kill("SIGTERM"),setTimeout(()=>{this.process===e&&e.kill("SIGKILL")},1e3))},250))}clearForceCloseTimer(){this.forceCloseTimer&&(clearTimeout(this.forceCloseTimer),this.forceCloseTimer=null)}}L("codex",()=>new ye);export{ye as CodexAdapter,fe as buildCodexQueueArgs,ge as buildCodexQueuedText,P as isCodexActiveWriterError,le as isCodexExcludeTurnsUnsupportedError,de as isCodexPaginatedHistoryUnsupportedError,ce as isCodexProjectApiUnsupportedError,Ne as isCodexUnsupportedEffortError,De as isMissingCodexRolloutError,Le as normalizeCodexModelId,Fe as normalizeCodexReasoningEffort,ue as selectCodexProjectIdForWorkDir};
@@ -1,8 +1,10 @@
1
1
  import type { ChatAttachmentMeta, ExternalChannelSessionStatus } from '@shennian/wire';
2
- import { AgentAdapter, type AgentSendContext } from './adapter.js';
2
+ import { AgentAdapter, type AgentActiveInput, type AgentSendContext } from './adapter.js';
3
3
  import { type CompiledManagedAgentPolicy } from '../security/managed-agent-policy.js';
4
4
  export declare class PiCodingAgentAdapter extends AgentAdapter {
5
5
  readonly type: "pi-coding-agent";
6
+ get supportsActiveInput(): boolean;
7
+ injectActiveInput(input: AgentActiveInput): Promise<void>;
6
8
  get recoveryCapabilities(): {
7
9
  inspectTerminal: boolean;
8
10
  reattachRun: boolean;