evolcore 0.0.10 → 0.0.12

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 (131) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +3 -3
  3. package/bin/codex-managed-hook.mjs +80 -0
  4. package/dist/agents/baseagent.js +4 -0
  5. package/dist/agents/claude-runner.js +158 -44
  6. package/dist/agents/codex-app-server-client.js +153 -23
  7. package/dist/agents/codex-runner.js +331 -43
  8. package/dist/agents/ecagent-runner.js +53 -6
  9. package/dist/agents/gemini-runner.js +1 -0
  10. package/dist/agents/request-identity.js +55 -0
  11. package/dist/aun/aid/client.js +11 -21
  12. package/dist/aun/aid/managed-operation.js +107 -0
  13. package/dist/aun/msg/group.js +81 -12
  14. package/dist/aun/msg/managed-operation.js +804 -0
  15. package/dist/aun/msg/mention-schema.js +20 -0
  16. package/dist/aun/msg/p2p.js +7 -0
  17. package/dist/aun/outbox.js +28 -31
  18. package/dist/channels/aun.js +418 -235
  19. package/dist/channels/daemon.js +13 -0
  20. package/dist/cli/agent-command.js +72 -17
  21. package/dist/cli/agent.js +249 -22
  22. package/dist/cli/aun-commands.js +270 -69
  23. package/dist/cli/bench.js +12 -3
  24. package/dist/cli/daemon-commands.js +52 -33
  25. package/dist/cli/fs-command.js +60 -0
  26. package/dist/cli/handoff-command.js +3 -0
  27. package/dist/cli/index.js +106 -63
  28. package/dist/cli/init-cancel.js +208 -0
  29. package/dist/cli/init-channel.js +343 -195
  30. package/dist/cli/init.js +21 -9
  31. package/dist/cli/managed-command-guard.js +41 -0
  32. package/dist/cli/model.js +11 -4
  33. package/dist/cli/queue-command.js +11 -1
  34. package/dist/cli/response.js +71 -0
  35. package/dist/cli/restart-monitor.js +4 -18
  36. package/dist/cli/trigger-command.js +4 -0
  37. package/dist/config/builtin-roles.js +5 -0
  38. package/dist/config/contact-book-store.js +11 -3
  39. package/dist/config/contact-request-service.js +161 -15
  40. package/dist/config/gateway-config.js +26 -10
  41. package/dist/config/mention-mode.js +8 -24
  42. package/dist/core/agent-reload-coordinator.js +53 -0
  43. package/dist/core/auth/agent-delegation.js +0 -1
  44. package/dist/core/auth/operation-authorizer.js +62 -154
  45. package/dist/core/auth/operation-catalog.js +264 -22
  46. package/dist/core/bootstrap-messages.js +68 -0
  47. package/dist/core/bootstrap-service.js +144 -10
  48. package/dist/core/capability/providers/claude-capability-provider.js +9 -31
  49. package/dist/core/capability/providers/codex-capability-provider.js +4 -15
  50. package/dist/core/capability/skill-discovery.js +55 -0
  51. package/dist/core/channel-loader.js +24 -7
  52. package/dist/core/command/agent-control.js +14 -11
  53. package/dist/core/command/cli-intent-parser.js +9 -0
  54. package/dist/core/command/command-handler.js +467 -6
  55. package/dist/core/command/connect-menu.js +15 -0
  56. package/dist/core/command/group-menu.js +4 -4
  57. package/dist/core/command/menu-catalog.js +366 -0
  58. package/dist/core/command/menu-handler.js +213 -110
  59. package/dist/core/command/menu-protocol.js +71 -0
  60. package/dist/core/command/slash-gate.js +5 -2
  61. package/dist/core/command/slash-handler.js +45 -25
  62. package/dist/core/daemon-file-cache.js +2 -1
  63. package/dist/core/data-migration.js +9 -2
  64. package/dist/core/evolagent-registry.js +125 -35
  65. package/dist/core/evolagent.js +12 -5
  66. package/dist/core/handoff/dispatcher.js +5 -2
  67. package/dist/core/handoff/runtime.js +145 -21
  68. package/dist/core/handoff/store.js +24 -0
  69. package/dist/core/handoff/types.js +1 -0
  70. package/dist/core/inference/text-inference.js +38 -4
  71. package/dist/core/message/logical-queue-bridge.js +1 -0
  72. package/dist/core/message/mention-schema.js +126 -0
  73. package/dist/core/message/message-bridge.js +237 -79
  74. package/dist/core/message/message-log.js +23 -0
  75. package/dist/core/message/message-queue.js +20 -4
  76. package/dist/core/message/response-engine.js +54 -36
  77. package/dist/core/model/model-catalog.js +143 -24
  78. package/dist/core/model/model-diagnostics.js +28 -10
  79. package/dist/core/permission/ec-command-parser.js +156 -10
  80. package/dist/core/permission/index.js +1 -0
  81. package/dist/core/permission/readonly-shell-query.js +532 -0
  82. package/dist/core/permission/sandbox-runtime.js +22 -1
  83. package/dist/core/permission/shell-environment.js +46 -0
  84. package/dist/core/permission/tool-policy.js +292 -111
  85. package/dist/core/protected-paths.js +17 -9
  86. package/dist/core/runner-reload-transaction.js +57 -0
  87. package/dist/core/session/session-manager.js +21 -2
  88. package/dist/eck/manifest-engine.js +39 -13
  89. package/dist/index.js +644 -180
  90. package/dist/ipc.js +246 -19
  91. package/dist/response-system/coordinator.js +6 -4
  92. package/dist/response-system/engines/v1/proactive-flow.js +26 -8
  93. package/dist/response-system/modes/single-session/index.js +14 -1
  94. package/dist/response-system/selector.js +6 -5
  95. package/dist/trigger/anomaly-store.js +4 -0
  96. package/dist/trigger/script-executor.js +1 -0
  97. package/dist/utils/aid-bind.js +3 -8
  98. package/dist/utils/codex-app-server-registry.js +90 -0
  99. package/dist/utils/codex-cli.js +5 -1
  100. package/dist/utils/cross-platform.js +15 -0
  101. package/dist/utils/log-writer.js +6 -10
  102. package/dist/utils/logger.js +5 -5
  103. package/dist/utils/npm-ops.js +5 -12
  104. package/dist/utils/tool-summary.js +11 -0
  105. package/kits/docs/channels/aun.md +1 -1
  106. package/kits/docs/context-assembly.md +2 -2
  107. package/kits/docs/evolcore/agent.md +11 -6
  108. package/kits/docs/evolcore/aid.md +14 -0
  109. package/kits/docs/evolcore/msg.md +13 -0
  110. package/kits/docs/prompt-loading-architecture.md +1 -2
  111. package/kits/docs/venues/group.md +1 -1
  112. package/kits/eck_manifest.json +0 -12
  113. package/kits/rules/01-overview.md +9 -0
  114. package/kits/rules/04-relation.md +1 -1
  115. package/kits/rules/05-venue.md +2 -2
  116. package/kits/schemas/agent-config.schema.3.json +1 -1
  117. package/kits/schemas/agent-config.schema.4.json +1 -1
  118. package/kits/schemas/relation-config.schema.2.json +1 -1
  119. package/kits/schemas/role-config.schema.1.json +1 -1
  120. package/kits/schemas/single-session.schema.1.json +3 -3
  121. package/kits/schemas/single-session.schema.2.json +3 -3
  122. package/kits/templates/roles/admin.json +27 -0
  123. package/kits/templates/roles/member.json +44 -0
  124. package/kits/templates/roles/visitor.json +40 -2
  125. package/kits/templates/system-fragments/bootstrap.md +12 -6
  126. package/kits/templates/system-fragments/channel.md +6 -0
  127. package/kits/templates/system-fragments/session.md +2 -0
  128. package/package.json +3 -2
  129. package/skills/eclink/SKILL.md +15 -3
  130. package/skills/eclink/agents/openai.yaml +3 -3
  131. package/dist/core/command/evol-menu-version-gate.js +0 -39
@@ -21,6 +21,82 @@ const CONFIG_MANAGEMENT_OPERATIONS = [
21
21
  description,
22
22
  sources: ['menu.cli', 'agent-tool', 'control'],
23
23
  }));
24
+ const GROUP_MANAGEMENT_OPERATIONS = [
25
+ ['ec.group.list', 'read', ['agent'], 'List groups joined by the current Agent'],
26
+ ['ec.group.info', 'read', ['relation', 'agent'], 'Read group information'],
27
+ ['ec.group.pull', 'read', ['relation', 'agent'], 'Pull group messages'],
28
+ ['ec.group.members', 'read', ['relation', 'agent'], 'List group members'],
29
+ ['ec.group.online', 'read', ['relation', 'agent'], 'List online group members'],
30
+ ['ec.group.rules.get', 'read', ['relation', 'agent'], 'Read the published group rules file'],
31
+ ['ec.group.rules.read', 'read', ['relation', 'agent'], 'Read legacy group join rules'],
32
+ ['ec.group.create', 'write-agent', ['agent'], 'Create a group as the current Agent'],
33
+ ['ec.group.ack', 'write-agent', ['agent'], 'Advance the current Agent group cursor'],
34
+ ['ec.group.update', 'write-agent', ['agent'], 'Update group metadata'],
35
+ ['ec.group.dissolve', 'write-agent', ['agent'], 'Dissolve a group'],
36
+ ['ec.group.suspend', 'write-agent', ['agent'], 'Suspend a group'],
37
+ ['ec.group.resume', 'write-agent', ['agent'], 'Resume a group'],
38
+ ['ec.group.join', 'write-agent', ['agent'], 'Request to join a group'],
39
+ ['ec.group.leave', 'write-agent', ['agent'], 'Leave a group'],
40
+ ['ec.group.invite', 'write-agent', ['agent'], 'Invite group members'],
41
+ ['ec.group.kick', 'write-agent', ['agent'], 'Remove a group member'],
42
+ ['ec.group.role', 'write-agent', ['agent'], 'Change a group member role'],
43
+ ['ec.group.owner', 'write-agent', ['agent'], 'Transfer group ownership'],
44
+ ['ec.group.ban', 'write-agent', ['agent'], 'Read or update the group ban list'],
45
+ ['ec.group.unban', 'write-agent', ['agent'], 'Remove a group ban'],
46
+ ['ec.group.rules.set', 'write-agent', ['agent'], 'Upload and publish group rules content'],
47
+ ['ec.group.rules.publish', 'write-agent', ['agent'], 'Publish the current group rules file'],
48
+ ['ec.group.rules.update', 'write-agent', ['agent'], 'Update group join rules'],
49
+ ].map(([id, category, defaultScopes, description]) => ({
50
+ id,
51
+ category,
52
+ dangerous: false,
53
+ defaultScopes,
54
+ description,
55
+ sources: ['agent-tool'],
56
+ }));
57
+ const MSG_READ_OPERATIONS = [
58
+ ['ec.msg.history', 'Read message history for an AUN private relation'],
59
+ ['ec.msg.online', 'Read online status for an AUN private relation'],
60
+ ].map(([id, description]) => ({
61
+ id,
62
+ category: 'read',
63
+ dangerous: false,
64
+ defaultScopes: ['relation', 'agent'],
65
+ description,
66
+ sources: ['agent-tool'],
67
+ }));
68
+ const GROUP_FS_READ_OPERATIONS = ['ls', 'stat', 'lstat', 'cat', 'find', 'df'].map(kind => ({
69
+ id: `ec.fs.${kind}`,
70
+ category: 'read',
71
+ dangerous: false,
72
+ defaultScopes: ['relation', 'agent'],
73
+ description: `Read current group filesystem (${kind})`,
74
+ sources: ['agent-tool'],
75
+ }));
76
+ const HANDOFF_READ_OPERATIONS = ['status', 'list', 'trace'].map(kind => ({
77
+ id: `ec.handoff.${kind}`,
78
+ category: 'read',
79
+ dangerous: false,
80
+ defaultScopes: ['relation', 'agent'],
81
+ description: `Read handoff ${kind}`,
82
+ sources: ['agent-tool'],
83
+ }));
84
+ const HANDOFF_WRITE_OPERATIONS = [{
85
+ id: 'ec.handoff.return',
86
+ category: 'write-own',
87
+ dangerous: false,
88
+ defaultScopes: ['relation', 'agent'],
89
+ description: 'Return the current handoff result',
90
+ sources: ['agent-tool'],
91
+ }];
92
+ const QUEUE_OPERATIONS = [['read', 'Read the current Agent message queue'], ['clear', 'Clear the current Agent message queue'], ['cancel', 'Cancel a current Agent queued message'], ['interrupt', 'Interrupt a current Agent session']].map(([kind, description]) => ({
93
+ id: `ec.queue.${kind}`,
94
+ category: kind === 'read' ? 'read' : 'write-agent',
95
+ dangerous: false,
96
+ defaultScopes: ['agent'],
97
+ description,
98
+ sources: ['agent-tool'],
99
+ }));
24
100
  /**
25
101
  * Operation Catalog - 所有命令操作的元数据定义
26
102
  *
@@ -34,7 +110,7 @@ const OPERATIONS = [
34
110
  dangerous: false,
35
111
  defaultScopes: ['relation', 'role', 'agent'],
36
112
  description: '列出可用模型',
37
- sources: ['slash', 'menu', 'menu.cli'],
113
+ sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
38
114
  },
39
115
  {
40
116
  id: 'model.current',
@@ -42,7 +118,15 @@ const OPERATIONS = [
42
118
  dangerous: false,
43
119
  defaultScopes: ['relation', 'role', 'agent'],
44
120
  description: '查询当前使用的模型',
45
- sources: ['slash', 'menu', 'menu.cli'],
121
+ sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
122
+ },
123
+ {
124
+ id: 'model.effort.current',
125
+ category: 'read',
126
+ dangerous: false,
127
+ defaultScopes: ['relation', 'role', 'agent'],
128
+ description: '查询当前推理努力度',
129
+ sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
46
130
  },
47
131
  {
48
132
  id: 'model.info',
@@ -66,7 +150,7 @@ const OPERATIONS = [
66
150
  dangerous: false,
67
151
  defaultScopes: ['relation', 'role', 'agent'],
68
152
  description: '切换使用的模型',
69
- sources: ['slash', 'menu', 'menu.cli'],
153
+ sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
70
154
  },
71
155
  {
72
156
  id: 'model.effort',
@@ -74,7 +158,7 @@ const OPERATIONS = [
74
158
  dangerous: false,
75
159
  defaultScopes: ['relation', 'role', 'agent'],
76
160
  description: '设置推理努力度',
77
- sources: ['slash', 'menu', 'menu.cli'],
161
+ sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
78
162
  },
79
163
  {
80
164
  id: 'model.reset',
@@ -181,6 +265,30 @@ const OPERATIONS = [
181
265
  description: '列出会话',
182
266
  sources: ['slash', 'menu'],
183
267
  },
268
+ {
269
+ id: 'session.current',
270
+ category: 'read',
271
+ dangerous: false,
272
+ defaultScopes: ['relation'],
273
+ description: '查看当前会话状态',
274
+ sources: ['slash', 'menu', 'agent-tool'],
275
+ },
276
+ {
277
+ id: 'session.topic.current',
278
+ category: 'read',
279
+ dangerous: false,
280
+ defaultScopes: ['relation'],
281
+ description: '查看当前关系下的话题会话状态',
282
+ sources: ['menu'],
283
+ },
284
+ {
285
+ id: 'session.topic.list',
286
+ category: 'read',
287
+ dangerous: false,
288
+ defaultScopes: ['relation'],
289
+ description: '列出当前关系下的话题会话',
290
+ sources: ['menu'],
291
+ },
184
292
  {
185
293
  id: 'session.create',
186
294
  category: 'write-own',
@@ -195,7 +303,7 @@ const OPERATIONS = [
195
303
  dangerous: false,
196
304
  defaultScopes: ['relation'],
197
305
  description: '重命名会话',
198
- sources: ['slash', 'menu'],
306
+ sources: ['slash', 'menu', 'agent-tool'],
199
307
  },
200
308
  {
201
309
  id: 'session.delete',
@@ -206,6 +314,14 @@ const OPERATIONS = [
206
314
  sources: ['slash', 'menu'],
207
315
  },
208
316
  // ── File Operations ──
317
+ {
318
+ id: 'project.current',
319
+ category: 'read',
320
+ dangerous: false,
321
+ defaultScopes: ['relation', 'agent'],
322
+ description: '查看当前项目摘要',
323
+ sources: ['menu', 'agent-tool'],
324
+ },
209
325
  {
210
326
  id: 'file.list',
211
327
  category: 'read',
@@ -425,6 +541,30 @@ const OPERATIONS = [
425
541
  description: '查看 agent 详情(敏感信息)',
426
542
  sources: ['menu', 'menu.cli', 'control'],
427
543
  },
544
+ {
545
+ id: 'agent.baseagent.current',
546
+ category: 'read',
547
+ dangerous: false,
548
+ defaultScopes: ['relation', 'agent', 'control'],
549
+ description: '查看当前 Agent 使用的 BaseAgent',
550
+ sources: ['menu', 'control'],
551
+ },
552
+ {
553
+ id: 'agent.baseagent.list',
554
+ category: 'read',
555
+ dangerous: false,
556
+ defaultScopes: ['agent', 'control'],
557
+ description: '列出当前 Agent 可用的 BaseAgent',
558
+ sources: ['menu', 'control'],
559
+ },
560
+ {
561
+ id: 'agent.baseagent.update',
562
+ category: 'write-agent',
563
+ dangerous: false,
564
+ defaultScopes: ['agent'],
565
+ description: '切换当前 Agent 使用的 BaseAgent',
566
+ sources: ['menu'],
567
+ },
428
568
  {
429
569
  id: 'agent.getConfig',
430
570
  category: 'read',
@@ -449,6 +589,14 @@ const OPERATIONS = [
449
589
  description: '重载 agent 配置',
450
590
  sources: ['slash', 'menu', 'control'],
451
591
  },
592
+ {
593
+ id: 'agent.bootstrapComplete',
594
+ category: 'write-agent',
595
+ dangerous: false,
596
+ defaultScopes: ['agent'],
597
+ description: 'Complete bootstrap for the current Agent',
598
+ sources: ['agent-tool'],
599
+ },
452
600
  {
453
601
  id: 'agent.delete',
454
602
  category: 'dangerous',
@@ -464,7 +612,47 @@ const OPERATIONS = [
464
612
  dangerous: false,
465
613
  defaultScopes: ['process'],
466
614
  description: '查看系统状态(敏感信息)',
467
- sources: ['slash', 'menu', 'menu.cli'],
615
+ sources: ['slash', 'menu', 'menu.cli', 'agent-tool'],
616
+ },
617
+ {
618
+ id: 'activity.current',
619
+ category: 'read',
620
+ dangerous: false,
621
+ defaultScopes: ['relation', 'agent'],
622
+ description: '查看当前中间活动显示策略',
623
+ sources: ['menu'],
624
+ },
625
+ {
626
+ id: 'activity.update',
627
+ category: 'write-agent',
628
+ dangerous: false,
629
+ defaultScopes: ['relation', 'agent'],
630
+ description: '更新中间活动显示策略',
631
+ sources: ['menu'],
632
+ },
633
+ {
634
+ id: 'observable.current',
635
+ category: 'read',
636
+ dangerous: false,
637
+ defaultScopes: ['agent'],
638
+ description: '查看当前 Agent 观察者模式',
639
+ sources: ['menu', 'control'],
640
+ },
641
+ {
642
+ id: 'observable.update',
643
+ category: 'write-agent',
644
+ dangerous: false,
645
+ defaultScopes: ['agent'],
646
+ description: '更新当前 Agent 观察者模式',
647
+ sources: ['menu'],
648
+ },
649
+ {
650
+ id: 'capability.read',
651
+ category: 'read',
652
+ dangerous: false,
653
+ defaultScopes: ['agent'],
654
+ description: '查看当前 Agent 的能力策略摘要',
655
+ sources: ['menu', 'control'],
468
656
  },
469
657
  {
470
658
  id: 'system.restart',
@@ -569,41 +757,41 @@ const OPERATIONS = [
569
757
  id: 'storage.list',
570
758
  category: 'read',
571
759
  dangerous: false,
572
- defaultScopes: ['control'],
760
+ defaultScopes: ['agent', 'control'],
573
761
  description: '列出存储对象(敏感信息)',
574
- sources: ['menu.cli', 'control'],
762
+ sources: ['menu.cli', 'agent-tool', 'control'],
575
763
  },
576
764
  {
577
765
  id: 'storage.quota',
578
766
  category: 'read',
579
767
  dangerous: false,
580
- defaultScopes: ['control'],
768
+ defaultScopes: ['agent', 'control'],
581
769
  description: '查看存储配额(敏感信息)',
582
- sources: ['menu.cli', 'control'],
770
+ sources: ['menu.cli', 'agent-tool', 'control'],
583
771
  },
584
772
  {
585
773
  id: 'storage.upload',
586
774
  category: 'write-agent',
587
775
  dangerous: true,
588
- defaultScopes: ['control'],
776
+ defaultScopes: ['agent', 'control'],
589
777
  description: '上传文件到云存储',
590
- sources: ['menu.cli', 'control'],
778
+ sources: ['menu.cli', 'agent-tool', 'control'],
591
779
  },
592
780
  {
593
781
  id: 'storage.download',
594
782
  category: 'write-agent',
595
783
  dangerous: true,
596
- defaultScopes: ['control'],
784
+ defaultScopes: ['agent', 'control'],
597
785
  description: '从云存储下载文件',
598
- sources: ['menu.cli', 'control'],
786
+ sources: ['menu.cli', 'agent-tool', 'control'],
599
787
  },
600
788
  {
601
789
  id: 'storage.delete',
602
790
  category: 'dangerous',
603
791
  dangerous: true,
604
- defaultScopes: ['control'],
792
+ defaultScopes: ['agent', 'control'],
605
793
  description: '删除云存储对象',
606
- sources: ['menu.cli', 'control'],
794
+ sources: ['menu.cli', 'agent-tool', 'control'],
607
795
  },
608
796
  // ── Gateway & Config Operations ──
609
797
  {
@@ -665,6 +853,52 @@ const OPERATIONS = [
665
853
  // ── EC Command Operations ──
666
854
  // EC daemon 入口根据结构化 IPC 请求构造 operation;Runner 不解析 EC 子命令。
667
855
  ...CONFIG_MANAGEMENT_OPERATIONS,
856
+ ...GROUP_MANAGEMENT_OPERATIONS,
857
+ ...MSG_READ_OPERATIONS,
858
+ ...GROUP_FS_READ_OPERATIONS,
859
+ ...HANDOFF_READ_OPERATIONS,
860
+ ...HANDOFF_WRITE_OPERATIONS,
861
+ ...QUEUE_OPERATIONS,
862
+ {
863
+ id: 'ec.version',
864
+ category: 'read',
865
+ dangerous: false,
866
+ defaultScopes: ['relation', 'agent', 'process'],
867
+ description: 'Read local EvolCore component versions',
868
+ sources: ['menu.cli', 'agent-tool'],
869
+ },
870
+ {
871
+ id: 'ec.aid.show',
872
+ category: 'read',
873
+ dangerous: true,
874
+ defaultScopes: ['relation', 'agent'],
875
+ description: 'Inspect the current Agent local AID identity and signing state',
876
+ sources: ['agent-tool'],
877
+ },
878
+ {
879
+ id: 'ec.aid.lookup',
880
+ category: 'read',
881
+ dangerous: false,
882
+ defaultScopes: ['relation', 'agent'],
883
+ description: 'Look up the current Agent public AID record',
884
+ sources: ['agent-tool'],
885
+ },
886
+ {
887
+ id: 'ec.aid.agentmd.get',
888
+ category: 'read',
889
+ dangerous: false,
890
+ defaultScopes: ['relation', 'agent'],
891
+ description: 'Read and verify the current Agent public agent.md',
892
+ sources: ['agent-tool'],
893
+ },
894
+ {
895
+ id: 'ec.aid.agentmd.put',
896
+ category: 'write-agent',
897
+ dangerous: true,
898
+ defaultScopes: ['agent'],
899
+ description: 'Sign and publish the current Agent local agent.md',
900
+ sources: ['agent-tool'],
901
+ },
668
902
  {
669
903
  id: 'ec.msg.send',
670
904
  category: 'write-own',
@@ -699,20 +933,28 @@ const OPERATIONS = [
699
933
  },
700
934
  {
701
935
  id: 'ec.ctl.send',
702
- category: 'write-agent',
936
+ category: 'write-own',
703
937
  dangerous: false,
704
- defaultScopes: ['control', 'agent'],
705
- description: '通过 ec ctl send 发送控制通道消息',
938
+ defaultScopes: ['relation'],
939
+ description: '通过 ec ctl send 向当前会话发送消息',
706
940
  sources: ['agent-tool'],
707
941
  },
708
942
  {
709
943
  id: 'ec.ctl.file',
710
- category: 'write-agent',
944
+ category: 'write-own',
711
945
  dangerous: false,
712
- defaultScopes: ['control', 'agent'],
713
- description: '通过 ec ctl file 发送控制通道文件',
946
+ defaultScopes: ['relation'],
947
+ description: '通过 ec ctl file 向当前会话发送项目文件',
714
948
  sources: ['agent-tool'],
715
949
  },
950
+ ...['read', 'clear', 'cancel', 'interrupt'].map(action => ({
951
+ id: `ec.ctl.queue.${action}`,
952
+ category: action === 'read' ? 'read' : 'write-own',
953
+ dangerous: false,
954
+ defaultScopes: ['relation'],
955
+ description: `${action} the current managed session queue`,
956
+ sources: ['agent-tool'],
957
+ })),
716
958
  // ── Raw CLI & Shell Execution ──
717
959
  {
718
960
  id: 'cli.exec.raw',
@@ -0,0 +1,68 @@
1
+ import fs from 'fs';
2
+ import { agentMdPath, resolvePaths } from '../paths.js';
3
+ import { parseAgentDisplayName, resolveAgentDisplayName } from '../aun/aid/agentmd.js';
4
+ import { generateWelcomeMessage } from '../utils/welcome.js';
5
+ import * as outbox from '../aun/outbox.js';
6
+ import { chatDirPath } from './session/session-fs-store.js';
7
+ import { hasMessageLogOperation } from './message/message-log.js';
8
+ export const BOOTSTRAP_MESSAGE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
9
+ export function bootstrapInitialMessageOperationId(aid) {
10
+ return `bootstrap-initial:v1:${aid}`;
11
+ }
12
+ export function postBootstrapWelcomeOperationId(aid) {
13
+ return `bootstrap-complete:v1:${aid}`;
14
+ }
15
+ export function renderPostBootstrapWelcome(aid, owner, ownerName) {
16
+ const mdPath = agentMdPath(aid);
17
+ const agentMd = fs.existsSync(mdPath) ? fs.readFileSync(mdPath, 'utf-8') : '';
18
+ const agentName = parseAgentDisplayName(agentMd)
19
+ || resolveAgentDisplayName(aid)
20
+ || aid.split('.')[0];
21
+ const fallbackOwnerName = owner.replace(/^@/, '').split('.')[0];
22
+ return generateWelcomeMessage({
23
+ channelType: 'aun',
24
+ agentName,
25
+ ownerName: ownerName || fallbackOwnerName,
26
+ includeBindingNote: true,
27
+ });
28
+ }
29
+ export function preparePostBootstrapWelcomeOutbox(aid, owner, ownerName) {
30
+ const operationId = postBootstrapWelcomeOperationId(aid);
31
+ const chatDir = chatDirPath(resolvePaths().sessionsDir, 'aun', owner, aid);
32
+ if (hasMessageLogOperation(chatDir, operationId))
33
+ return;
34
+ outbox.enqueue(aid, {
35
+ channelId: owner,
36
+ dedupeKey: operationId,
37
+ critical: true,
38
+ type: 'text',
39
+ text: renderPostBootstrapWelcome(aid, owner, ownerName),
40
+ ttl: BOOTSTRAP_MESSAGE_TTL_MS,
41
+ context: {
42
+ metadata: {
43
+ source: 'daemon',
44
+ chatmode: 'interactive',
45
+ persistRequired: true,
46
+ operationId,
47
+ },
48
+ },
49
+ });
50
+ }
51
+ export function hasPendingPostBootstrapWelcomeOutbox(aid) {
52
+ return !!outbox.findByDedupeKey(aid, postBootstrapWelcomeOperationId(aid));
53
+ }
54
+ /** Bind the durable completion welcome to the fresh post-bootstrap session. */
55
+ export function bindPostBootstrapWelcomeOutboxSession(aid, sessionId) {
56
+ const entry = outbox.findByDedupeKey(aid, postBootstrapWelcomeOperationId(aid));
57
+ if (!entry)
58
+ return false;
59
+ if (entry.context?.sessionId === sessionId)
60
+ return true;
61
+ return outbox.replace(aid, {
62
+ ...entry,
63
+ context: {
64
+ ...(entry.context ?? {}),
65
+ sessionId,
66
+ },
67
+ });
68
+ }
@@ -9,6 +9,95 @@ import { normalizeAgentLifecycle, withLifecycleForWrite } from '../config/lifecy
9
9
  import { renderTemplate } from '../eck/manifest-engine.js';
10
10
  import { activeBaseagent } from './model/config-scope.js';
11
11
  import { buildEnvelope } from './message/message-utils.js';
12
+ import { BOOTSTRAP_MESSAGE_TTL_MS, bootstrapInitialMessageOperationId } from './bootstrap-messages.js';
13
+ /** Coordinate the write-ahead completion welcome with the lifecycle commit. */
14
+ export async function completeBootstrapWithWelcome(service, aid, welcome, sessions) {
15
+ const lifecycle = service.lifecycleOf(aid);
16
+ if (lifecycle !== 'bootstrapping' && lifecycle !== 'active') {
17
+ const result = service.completeBootstrap(aid);
18
+ return { ...result, reloaded: false };
19
+ }
20
+ if (lifecycle === 'bootstrapping') {
21
+ if (!welcome) {
22
+ return {
23
+ ok: false,
24
+ code: 'WELCOME_CHANNEL_UNAVAILABLE',
25
+ error: `No AUN channel available to persist the post-bootstrap welcome for ${aid}`,
26
+ reloaded: false,
27
+ };
28
+ }
29
+ if (!await welcome.preparePostBootstrapWelcome()) {
30
+ return {
31
+ ok: false,
32
+ code: 'WELCOME_PREPARE_FAILED',
33
+ error: `Failed to persist the post-bootstrap welcome for ${aid}`,
34
+ reloaded: false,
35
+ };
36
+ }
37
+ }
38
+ const welcomePending = welcome
39
+ ? await welcome.hasPendingPostBootstrapWelcome()
40
+ : false;
41
+ const needsMainSessionBoundary = lifecycle === 'bootstrapping' || welcomePending;
42
+ let mainSession;
43
+ if (needsMainSessionBoundary) {
44
+ if (!sessions) {
45
+ return {
46
+ ok: false,
47
+ code: 'MAIN_SESSION_UNAVAILABLE',
48
+ error: `No session coordinator available to create the post-bootstrap main session for ${aid}`,
49
+ reloaded: false,
50
+ };
51
+ }
52
+ try {
53
+ mainSession = await sessions.ensurePostBootstrapMainSession();
54
+ }
55
+ catch (e) {
56
+ return {
57
+ ok: false,
58
+ code: 'MAIN_SESSION_CREATE_FAILED',
59
+ error: e instanceof Error ? e.message : `Failed to create the post-bootstrap main session for ${aid}`,
60
+ reloaded: false,
61
+ };
62
+ }
63
+ if (!mainSession.sessionId) {
64
+ return {
65
+ ok: false,
66
+ code: 'MAIN_SESSION_CREATE_FAILED',
67
+ error: `Failed to create the post-bootstrap main session for ${aid}`,
68
+ reloaded: false,
69
+ };
70
+ }
71
+ if (welcomePending && welcome && !await welcome.bindPostBootstrapWelcomeToSession(mainSession.sessionId)) {
72
+ return {
73
+ ok: false,
74
+ code: 'WELCOME_SESSION_BIND_FAILED',
75
+ error: `Failed to bind the post-bootstrap welcome to session ${mainSession.sessionId}`,
76
+ reloaded: false,
77
+ };
78
+ }
79
+ }
80
+ const result = service.completeBootstrap(aid);
81
+ if (!result.ok)
82
+ return { ...result, reloaded: false };
83
+ if (!welcome) {
84
+ return {
85
+ ...result,
86
+ reloaded: true,
87
+ welcomeQueued: false,
88
+ mainSessionId: mainSession?.sessionId,
89
+ mainSessionCreated: mainSession?.created,
90
+ };
91
+ }
92
+ const welcomeQueued = await welcome.reconcilePostBootstrapWelcome();
93
+ return {
94
+ ...result,
95
+ reloaded: true,
96
+ welcomeQueued,
97
+ mainSessionId: mainSession?.sessionId,
98
+ mainSessionCreated: mainSession?.created,
99
+ };
100
+ }
12
101
  export class BootstrapService {
13
102
  agentRegistry;
14
103
  eventBus;
@@ -29,23 +118,25 @@ export class BootstrapService {
29
118
  return false;
30
119
  this.inFlight.add(key);
31
120
  let lifecycleStarted = false;
32
- const loadedConfig = agent?.config || loadAgent(aid);
121
+ const loadedConfig = loadAgent(aid) || agent?.config;
33
122
  if (!loadedConfig) {
34
123
  this.inFlight.delete(key);
35
124
  return false;
36
125
  }
37
126
  const config = normalizeAgentLifecycle(loadedConfig);
38
- if (config.lifecycle !== 'created') {
127
+ if (config.lifecycle === 'active') {
39
128
  this.inFlight.delete(key);
40
129
  return false;
41
130
  }
131
+ const starting = config.lifecycle === 'created';
42
132
  const channelType = ctx.channelType || this.channelTypeFromKey(ctx.channelKey);
43
- const recipientId = ctx.recipientId || this.resolveConfiguredRecipient(config, ctx.channelKey, channelType);
133
+ const configuredRecipient = this.resolveConfiguredRecipient(config, ctx.channelKey, channelType);
134
+ const recipientId = ctx.recipientId || configuredRecipient;
44
135
  if (!recipientId) {
45
136
  this.inFlight.delete(key);
46
137
  return false;
47
138
  }
48
- if (ctx.recipientId && recipientId !== ctx.recipientId) {
139
+ if (ctx.recipientId && configuredRecipient !== ctx.recipientId) {
49
140
  this.inFlight.delete(key);
50
141
  return false;
51
142
  }
@@ -57,9 +148,11 @@ export class BootstrapService {
57
148
  try {
58
149
  const agentName = this.resolveAgentDisplayName(aid);
59
150
  const baseagent = this.resolveBaseagent(agent, aid);
60
- await this.publishAgentMdIfSupported(ctx.adapter, aid, agentName);
61
- this.setLifecycle(agent, aid, 'bootstrapping');
62
- lifecycleStarted = true;
151
+ if (starting) {
152
+ await this.publishAgentMdIfSupported(ctx.adapter, aid, agentName);
153
+ this.setLifecycle(agent, aid, 'bootstrapping');
154
+ lifecycleStarted = true;
155
+ }
63
156
  const text = this.renderWelcome({
64
157
  agentAid: aid,
65
158
  agentName,
@@ -72,9 +165,23 @@ export class BootstrapService {
72
165
  channel: ctx.adapter.channelKey || ctx.adapter.channelName,
73
166
  channelId,
74
167
  agentName: aid,
168
+ replyContext: {
169
+ metadata: {
170
+ source: 'daemon',
171
+ persistRequired: true,
172
+ operationId: bootstrapInitialMessageOperationId(aid),
173
+ outboxTtl: BOOTSTRAP_MESSAGE_TTL_MS,
174
+ criticalDelivery: true,
175
+ },
176
+ },
75
177
  }), { kind: 'result.text', text, isFinal: true });
76
- this.eventBus.publish({ type: 'agent:bootstrap-started', aid, channel: channelType || ctx.channelKey, timestamp: Date.now() });
77
- logger.info(`[Bootstrap] Started for ${aid} via ${ctx.channelKey} (${ctx.source})`);
178
+ if (starting) {
179
+ this.eventBus.publish({ type: 'agent:bootstrap-started', aid, channel: channelType || ctx.channelKey, timestamp: Date.now() });
180
+ logger.info(`[Bootstrap] Started for ${aid} via ${ctx.channelKey} (${ctx.source})`);
181
+ }
182
+ else {
183
+ logger.info(`[Bootstrap] Reconciled initial message for ${aid} via ${ctx.channelKey} (${ctx.source})`);
184
+ }
78
185
  return true;
79
186
  }
80
187
  catch (e) {
@@ -93,6 +200,33 @@ export class BootstrapService {
93
200
  this.inFlight.delete(key);
94
201
  }
95
202
  }
203
+ completeBootstrap(aid) {
204
+ const agent = this.agentRegistry.get(aid);
205
+ const loadedConfig = loadAgent(aid) || agent?.config;
206
+ if (!loadedConfig)
207
+ return { ok: false, error: `Agent "${aid}" not found` };
208
+ const lifecycle = normalizeAgentLifecycle(loadedConfig).lifecycle;
209
+ if (lifecycle === 'active')
210
+ return { ok: true, aid, transitioned: false };
211
+ if (lifecycle !== 'bootstrapping') {
212
+ return {
213
+ ok: false,
214
+ code: 'INVALID_LIFECYCLE',
215
+ error: `Agent "${aid}" is ${lifecycle}; only a bootstrapping agent can become ready`,
216
+ };
217
+ }
218
+ this.setLifecycle(agent, aid, 'active');
219
+ this.eventBus.publish({ type: 'agent:bootstrap-complete', aid, timestamp: Date.now() });
220
+ logger.info(`[Bootstrap] Completed for ${aid} (previous lifecycle=${lifecycle})`);
221
+ return { ok: true, aid, transitioned: true };
222
+ }
223
+ lifecycleOf(aid) {
224
+ const agent = this.agentRegistry.get(aid);
225
+ const loadedConfig = loadAgent(aid) || agent?.config;
226
+ return loadedConfig
227
+ ? normalizeAgentLifecycle(loadedConfig).lifecycle
228
+ : null;
229
+ }
96
230
  setLifecycle(agent, aid, lifecycle) {
97
231
  if (agent?.setLifecycle) {
98
232
  agent.setLifecycle(lifecycle);
@@ -100,7 +234,7 @@ export class BootstrapService {
100
234
  }
101
235
  const cfg = loadAgent(aid);
102
236
  if (!cfg)
103
- return;
237
+ throw new Error(`Agent "${aid}" disappeared while updating lifecycle`);
104
238
  saveAgent(withLifecycleForWrite(cfg, lifecycle));
105
239
  }
106
240
  resolveConfiguredRecipient(config, _channelKey, _channelType) {