evolcore 0.0.32 → 0.0.34

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 (214) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/bin/ec.js +3 -2
  3. package/bin/install-codex-managed-hooks.mjs +135 -37
  4. package/dist/agents/baseagent-availability.js +20 -36
  5. package/dist/agents/claude-runner.js +111 -15
  6. package/dist/agents/codex/app-server-client.js +3 -0
  7. package/dist/agents/codex/diagnostics.js +112 -54
  8. package/dist/agents/codex-runner.js +241 -63
  9. package/dist/agents/ecagent-runner.js +78 -33
  10. package/dist/agents/runner-types.js +5 -6
  11. package/dist/aun/aid/identity.js +1 -1
  12. package/dist/aun/group/operations.js +0 -1
  13. package/dist/aun/msg/history.js +1 -0
  14. package/dist/aun/msg/p2p.js +0 -1
  15. package/dist/aun/outbox.js +50 -1
  16. package/dist/channels/aun.js +44 -8
  17. package/dist/channels/daemon.js +261 -3
  18. package/dist/cli/agent-command.js +58 -24
  19. package/dist/cli/agent.js +1 -1
  20. package/dist/cli/aun-commands.js +368 -31
  21. package/dist/cli/contact.js +8 -2
  22. package/dist/cli/ctl-command.js +3 -1
  23. package/dist/cli/daemon-commands.js +197 -27
  24. package/dist/cli/debug-mode.js +154 -0
  25. package/dist/cli/fs-command.js +2 -1
  26. package/dist/cli/handoff-command.js +3 -0
  27. package/dist/cli/index.js +98 -67
  28. package/dist/cli/init.js +2 -2
  29. package/dist/cli/integrity-command.js +196 -0
  30. package/dist/cli/managed-command-guard.js +5 -0
  31. package/dist/cli/memory-command.js +166 -146
  32. package/dist/cli/queue-command.js +9 -4
  33. package/dist/cli/session-command.js +194 -0
  34. package/dist/cli/skill-command.js +78 -2
  35. package/dist/cli/task-context.js +1 -0
  36. package/dist/cli/thread-command.js +622 -0
  37. package/dist/cli/trigger-command.js +10 -3
  38. package/dist/config/builtin-roles.js +1 -0
  39. package/dist/config/config-field-policy.js +6 -3
  40. package/dist/config/config-manager.js +26 -2
  41. package/dist/config/contact-book-store.js +5 -0
  42. package/dist/config/resolved-config-op.js +3 -0
  43. package/dist/config/role-service.js +13 -0
  44. package/dist/config/runtime-env.js +16 -0
  45. package/dist/config-store.js +45 -0
  46. package/dist/core/audit/log-integrity.js +3 -1
  47. package/dist/core/auth/agent-delegation.js +133 -36
  48. package/dist/core/auth/debug-context.js +139 -0
  49. package/dist/core/auth/delegation-diagnostics.js +414 -0
  50. package/dist/core/auth/operation-authorizer.js +25 -2
  51. package/dist/core/auth/operation-catalog.js +49 -0
  52. package/dist/core/background-session/session-cleanup.js +212 -0
  53. package/dist/core/background-session/types.js +10 -0
  54. package/dist/core/bootstrap-messages.js +1 -1
  55. package/dist/core/bootstrap-service.js +6 -3
  56. package/dist/core/command/agent-control.js +18 -26
  57. package/dist/core/command/command-handler.js +197 -27
  58. package/dist/core/command/daemon-diagnostics.js +1 -0
  59. package/dist/core/command/memory-slash.js +6 -2
  60. package/dist/core/command/menu-catalog.js +51 -1
  61. package/dist/core/command/menu-handler.js +114 -23
  62. package/dist/core/command/menu-protocol.js +25 -1
  63. package/dist/core/command/skill-slash.js +322 -0
  64. package/dist/core/command/slash-gate.js +6 -4
  65. package/dist/core/command/slash-handler.js +195 -13
  66. package/dist/core/command/topic-slash.js +528 -0
  67. package/dist/core/daemon-bootstrap.js +4 -7
  68. package/dist/core/evolagent-registry.js +20 -5
  69. package/dist/core/file-integrity/read.js +61 -0
  70. package/dist/core/file-integrity/store.js +262 -0
  71. package/dist/core/handoff/runtime.js +5 -11
  72. package/dist/core/handoff/store.js +5 -0
  73. package/dist/core/ipc-registration.js +175 -3
  74. package/dist/core/memory/batch-meta.js +132 -0
  75. package/dist/core/memory/consolidation-context.js +83 -29
  76. package/dist/core/memory/consolidation-ops-records.js +49 -16
  77. package/dist/core/memory/consolidation-queue-format.js +21 -0
  78. package/dist/core/memory/consolidation.js +264 -205
  79. package/dist/core/memory/index-manager.js +19 -28
  80. package/dist/core/memory/memory-admin.js +19 -14
  81. package/dist/core/memory/memory-document.js +53 -9
  82. package/dist/core/memory/memory-writer.js +30 -15
  83. package/dist/core/message/aun-ipc-sender.js +161 -6
  84. package/dist/core/message/im-renderer.js +169 -10
  85. package/dist/core/message/message-bridge.js +15 -4
  86. package/dist/core/message/message-log.js +1 -0
  87. package/dist/core/message/peer-mode.js +6 -1
  88. package/dist/core/message/response-engine.js +929 -110
  89. package/dist/core/message/subtask-tool-projection.js +140 -0
  90. package/dist/core/model/catalog-service.js +17 -12
  91. package/dist/core/permission/ec-command-parser.js +217 -9
  92. package/dist/core/permission/protected-paths.js +5 -1
  93. package/dist/core/permission/readonly-shell-query.js +43 -5
  94. package/dist/core/permission/session-path-grants.js +334 -0
  95. package/dist/core/permission/tool-canonical.js +226 -0
  96. package/dist/core/permission/tool-policy.js +30 -62
  97. package/dist/core/role/runtime-policy.js +21 -10
  98. package/dist/core/session/session-fs-store.js +123 -8
  99. package/dist/core/session/session-idle-monitor.js +249 -22
  100. package/dist/core/session/session-manager.js +129 -14
  101. package/dist/core/skill/command-parser.js +13 -0
  102. package/dist/core/skill/index-generator.js +21 -4
  103. package/dist/core/skill/startup.js +41 -0
  104. package/dist/core/skill/switch-resolver.js +55 -29
  105. package/dist/core/system-session/grants.js +40 -0
  106. package/dist/core/system-session/memory.js +222 -0
  107. package/dist/core/system-session/registry.js +74 -0
  108. package/dist/core/system-session/types.js +14 -0
  109. package/dist/core/thread/command-parser.js +125 -0
  110. package/dist/core/thread/index.js +1 -0
  111. package/dist/core/thread/ipc-operation.js +95 -0
  112. package/dist/core/thread/thread-context-storage.js +131 -0
  113. package/dist/core/thread/thread-operation.js +258 -0
  114. package/dist/core/thread/thread-route.js +33 -0
  115. package/dist/core/thread/thread-service.js +770 -0
  116. package/dist/core/thread/types.js +1 -0
  117. package/dist/eck/kit-renderer.js +7 -2
  118. package/dist/eck/manifest-engine.js +24 -4
  119. package/dist/eck/message-renderer.js +35 -0
  120. package/dist/index.js +19 -7
  121. package/dist/ipc.js +140 -50
  122. package/dist/paths.js +93 -0
  123. package/dist/response-system/engines/v1/proactive-flow.js +169 -80
  124. package/dist/stats/billing.js +20 -8
  125. package/dist/trigger/authorization.js +57 -28
  126. package/dist/trigger/feedback.js +13 -2
  127. package/dist/trigger/parser.js +70 -1
  128. package/dist/trigger/system-definitions.js +3 -3
  129. package/dist/trigger/validation.js +14 -0
  130. package/dist/utils/cross-platform.js +11 -2
  131. package/dist/utils/error-dict.json +18 -4
  132. package/dist/utils/error-utils.js +143 -1
  133. package/dist/utils/instance-registry.js +13 -8
  134. package/dist/utils/log-writer.js +12 -0
  135. package/dist/utils/process-introspect.js +11 -0
  136. package/kits/docs/context-assembly.md +1 -1
  137. package/kits/docs/evolcore/INDEX.md +1 -0
  138. package/kits/docs/evolcore/agent-create.md +40 -28
  139. package/kits/docs/evolcore/agent.md +21 -6
  140. package/kits/docs/evolcore/config.md +2 -2
  141. package/kits/docs/evolcore/ctl.md +2 -2
  142. package/kits/docs/evolcore/ec-capabilities.md +5 -1
  143. package/kits/docs/evolcore/fs-architecture.md +4 -5
  144. package/kits/docs/evolcore/fs.md +1 -1
  145. package/kits/docs/evolcore/group-collaboration.md +4 -6
  146. package/kits/docs/evolcore/group.md +11 -12
  147. package/kits/docs/evolcore/memory-architecture.md +4 -5
  148. package/kits/docs/evolcore/memory-consolidation.md +19 -15
  149. package/kits/docs/evolcore/memory-tags.md +3 -1
  150. package/kits/docs/evolcore/memory.md +24 -12
  151. package/kits/docs/evolcore/menu-exec-schema-commands.md +2 -2
  152. package/kits/docs/evolcore/menu-protocol.md +7 -0
  153. package/kits/docs/evolcore/model.md +16 -0
  154. package/kits/docs/evolcore/msg.md +8 -11
  155. package/kits/docs/evolcore/thread-chain.md +267 -0
  156. package/kits/docs/prompt-loading-architecture.md +1 -1
  157. package/kits/eck_manifest.json +55 -40
  158. package/kits/eck_manifest.memory.json +0 -12
  159. package/kits/eck_message_manifest.json +169 -10
  160. package/kits/rules/01-overview.md +11 -0
  161. package/kits/rules/03-identity.md +6 -3
  162. package/kits/rules/05-venue.md +1 -1
  163. package/kits/rules/06-channel.md +1 -1
  164. package/kits/rules/07-memory-and-thread.md +199 -0
  165. package/kits/schemas/_meta.json +7 -1
  166. package/kits/schemas/agent-config.schema.13.json +1 -1
  167. package/kits/schemas/daemon.schema.7.json +140 -0
  168. package/kits/schemas/relation-config.schema.9.json +18 -3
  169. package/kits/schemas/role-config.schema.1.json +6 -6
  170. package/kits/schemas/single-session.schema.1.json +6 -6
  171. package/kits/schemas/single-session.schema.2.json +6 -6
  172. package/kits/schemas/single-session.schema.3.json +6 -6
  173. package/kits/skills/.switches.json +12 -1
  174. package/kits/skills/ec-group/SKILL.md +234 -0
  175. package/kits/skills/ec-skill/SKILL.md +10 -1
  176. package/kits/skills/ec-skill/scripts/cli.mjs +16 -2
  177. package/kits/skills/ec-skill/scripts/skill.mjs +1 -1
  178. package/kits/skills/scrapling-article-fetch/SKILL.md +128 -0
  179. package/kits/skills/scrapling-article-fetch/scripts/check_python_env.py +54 -0
  180. package/kits/skills/scrapling-article-fetch/scripts/render_markdown_reply.py +35 -0
  181. package/kits/skills/scrapling-article-fetch/scripts/run_pipeline.sh +16 -0
  182. package/kits/skills/scrapling-article-fetch/scripts/scrapling_fetch.py +344 -0
  183. package/kits/skills/thread-ops/SKILL.md +492 -0
  184. package/kits/skills/wechat-article-media-download/SKILL.md +65 -0
  185. package/kits/skills/wechat-article-media-download/scripts/download.py +163 -0
  186. package/kits/skills/wechat-article-reader/SKILL.md +97 -0
  187. package/kits/skills/wechat-article-reader/scripts/fetch.mjs +256 -0
  188. package/kits/templates/bootstrap-welcome.md +7 -7
  189. package/kits/templates/memory-consolidation/forget.md +7 -2
  190. package/kits/templates/memory-consolidation/generalize.md +9 -4
  191. package/kits/templates/memory-consolidation/notes.md +11 -11
  192. package/kits/templates/memory-consolidation/profile.md +8 -3
  193. package/kits/templates/memory-consolidation/promote.md +8 -3
  194. package/kits/templates/memory-consolidation/workflow.md +6 -6
  195. package/kits/templates/message-fragments/handoff-request-to-target.md +1 -1
  196. package/kits/templates/message-fragments/item.md +2 -1
  197. package/kits/templates/message-fragments/thread-context.md +6 -0
  198. package/kits/templates/message-fragments/trigger-session.md +2 -0
  199. package/kits/templates/message-fragments/trigger-thread-check.md +2 -0
  200. package/kits/templates/roles/member.json +2 -0
  201. package/kits/templates/roles/visitor.json +2 -0
  202. package/kits/templates/system-fragments/bootstrap.md +67 -72
  203. package/kits/templates/system-fragments/channel.md +3 -6
  204. package/kits/templates/system-fragments/commands.md +1 -0
  205. package/kits/templates/system-fragments/managed-runtime.md +15 -0
  206. package/kits/templates/system-fragments/memory.md +16 -9
  207. package/kits/templates/system-fragments/reply.md +7 -6
  208. package/kits/templates/system-fragments/session.md +5 -14
  209. package/package.json +6 -3
  210. package/dist/core/memory/memory-session-policy.js +0 -41
  211. package/dist/core/memory/memory-signature.js +0 -257
  212. package/kits/docs/evolcore/group-fs.md +0 -17
  213. package/kits/docs/venues/aun-group.md +0 -45
  214. package/kits/docs/venues/group.md +0 -43
@@ -13,9 +13,10 @@
13
13
  */
14
14
  import { resolvePaths } from '../paths.js';
15
15
  import { ipcQuery } from '../ipc.js';
16
- import { isHelpFlag, wantsHelp } from './help.js';
16
+ import { isHelpFlag, wantsHelp, getArgValue } from './help.js';
17
17
  import { readDelegationCredential } from '../core/auth/agent-delegation.js';
18
18
  import { canonicalizeEvolcoreCommandArgv } from '../core/permission/ec-command-parser.js';
19
+ import { formatQueueDetails } from '../core/memory/consolidation-queue-format.js';
19
20
  export const MEMORY_MODES = ['notes', 'generalize', 'promote', 'profile', 'forget'];
20
21
  const MEMORY_HELP = `用法: ec memory <command> [选项]
21
22
 
@@ -27,20 +28,23 @@ const MEMORY_HELP = `用法: ec memory <command> [选项]
27
28
  demote 把记忆降级回上一层(agent→relation,owner→agent)
28
29
  consolidate 触发记忆整理(启动整理会话)
29
30
 
30
- ec memory note --slug <slug> [--tags <tag1,tag2,...>] <content>
31
+ ec memory note --slug <slug> [--tags '<tag1>,<tag2>'] '<content>'
31
32
 
32
33
  选项:
33
34
  --slug <slug> 文件名标识,字母/数字/连字符,长度 1-64(必填)
34
- --tags <...> 标签列表,逗号分隔;取值见 \$KITS_DOCS/evolcore/memory-tags.md
35
+ --tags <...> 标签列表,写法固定为单引号包住、逗号分隔;取值见 \$KITS_DOCS/evolcore/memory-tags.md
36
+ --speakers <...> 群聊专用:本条 note 涉及的发言人,写法固定为单引号包住、逗号分隔,
37
+ 如 --speakers '<aid1>,<aid2>';
38
+ 整理会话据此把发言人信息分流写入各自的 relation 记忆
35
39
 
36
- ec memory note update <slug> [--slug <新slug>] [--tags <...>] [<content>]
40
+ ec memory note update <slug> [--slug <新slug>] [--tags '<tag1>,<tag2>'] ['<content>']
37
41
  ec memory note drop <slug>
38
42
  ec memory note list
39
43
 
40
- ec memory create --scope <relation|agent|owner> --slug <slug> --desc <description> \\
41
- --tags <...> [--keywords <...>] [--replaces <path,...>] <content>
44
+ ec memory create --scope <relation|agent|owner> --slug <slug> --desc '<description>' \\
45
+ --tags '<tag1>,<tag2>' [--keywords '<kw1>,<kw2>'] [--replaces '<path1>,<path2>'] '<content>'
42
46
 
43
- ec memory update <path> [--tags <...>] [--touch]
47
+ ec memory update <path> [--tags '<tag1>,<tag2>'] [--touch]
44
48
 
45
49
  ec memory archive <path...>
46
50
 
@@ -50,18 +54,21 @@ ec memory consolidate [--mode <notes|generalize|promote|profile|forget>]
50
54
  --mode 整理模式(默认 notes)
51
55
 
52
56
  公共选项(所有子命令):
57
+ --format json 以 JSON 格式输出:成功时输出 daemon 返回的结果对象,
58
+ 失败时输出 { ok: false, code, error },均写到 stdout
53
59
  --debug <sessionId> 在宿主终端模拟该会话的托管环境(仅开发仓 daemon 支持);
54
60
  会话没有运行中任务时,daemon 从会话文件重建运行时上下文
55
61
 
56
62
  示例:
57
- ec memory note --slug commit-convention --tags "rule,long-term" "commit 消息必须用中文"
58
- ec memory note update commit-convention --tags "rule,done" "commit 消息必须用中文"
63
+ ec memory note --slug commit-convention --tags 'rule,long-term' 'commit 消息必须用中文'
64
+ ec memory note update commit-convention --tags 'rule,done' 'commit 消息必须用中文'
59
65
  ec memory note drop commit-convention
60
66
  ec memory note list
67
+ ec memory note list --format json
61
68
  ec memory consolidate
62
69
  ec memory consolidate --mode promote
63
- ec memory create --scope relation --slug profile --desc "对端画像" --tags "profile" --replaces consolidated/profile.md "(画像正文)"
64
- ec memory update consolidated/commit-convention.md --tags "rule,done"
70
+ ec memory create --scope relation --slug profile --desc '对端画像' --tags 'profile' --replaces consolidated/profile.md '(画像正文)'
71
+ ec memory update consolidated/commit-convention.md --tags 'rule,done'
65
72
  ec memory archive consolidated/obsolete.md`;
66
73
  export async function cmdMemory(args) {
67
74
  args = canonicalizeEvolcoreCommandArgv(['ec', 'memory', ...args]).slice(2);
@@ -69,50 +76,60 @@ export async function cmdMemory(args) {
69
76
  console.log(MEMORY_HELP);
70
77
  return;
71
78
  }
79
+ // --format 的取值先于一切校验:后续任何报错都要按它决定输出 JSON 还是文本
80
+ try {
81
+ assertFormatValues(args);
82
+ }
83
+ catch (e) {
84
+ console.error(`❌ ${e.message}`);
85
+ process.exit(1);
86
+ }
87
+ const json = getArgValue(args, '--format') === 'json';
72
88
  const sub = args[0];
73
89
  if (sub === 'note') {
74
- await cmdMemoryNote(args.slice(1));
90
+ await cmdMemoryNote(args.slice(1), json);
75
91
  }
76
92
  else if (sub === 'consolidate') {
77
- await cmdMemoryConsolidate(args.slice(1));
93
+ await cmdMemoryConsolidate(args.slice(1), json);
78
94
  }
79
95
  else if (sub === 'create') {
80
- await cmdMemoryCreate(args.slice(1));
96
+ await cmdMemoryCreate(args.slice(1), json);
81
97
  }
82
98
  else if (sub === 'update') {
83
- await cmdMemoryConsolidatedUpdate(args.slice(1));
99
+ await cmdMemoryConsolidatedUpdate(args.slice(1), json);
84
100
  }
85
101
  else if (sub === 'archive') {
86
- await cmdMemoryArchive(args.slice(1));
102
+ await cmdMemoryArchive(args.slice(1), json);
87
103
  }
88
104
  else if (sub === 'demote') {
89
- await cmdMemoryDemote(args.slice(1));
90
- }
91
- else if (sub === 'feedback') {
92
- await cmdMemoryFeedback(args.slice(1));
105
+ await cmdMemoryDemote(args.slice(1), json);
93
106
  }
94
107
  else {
95
- console.error(`❌ 未知子命令: ${sub}`);
96
- console.error(MEMORY_HELP);
97
- process.exit(1);
108
+ fail(json, 'INVALID_ARGUMENT', `未知子命令: ${sub}`, { text: `❌ 未知子命令: ${sub}\n${MEMORY_HELP}` });
98
109
  }
99
110
  }
111
+ /** 所有子命令都认的公共参数,不用每处声明。 */
112
+ const COMMON_FLAGS = ['--debug', '--format'];
113
+ /** `--format` 只支持 json;每次出现都检查,避免重复给出时 CLI 与 daemon 各取一个值。 */
114
+ function assertFormatValues(args) {
115
+ args.forEach((a, i) => {
116
+ if (a === '--format' && args[i + 1] !== 'json') {
117
+ throw new Error(`--format 仅支持 json: ${args[i + 1] ?? '(缺少取值)'}`);
118
+ }
119
+ });
120
+ }
100
121
  /**
101
122
  * 解析 `--key value` 与位置参数。未识别的 `--xxx` 一律报错,避免静默忽略。
102
- * `--debug <sessionId>` 是所有子命令的公共参数,不用每处声明。
103
123
  */
104
- function parseArgs(args, known, throwOnUnknown = false) {
124
+ function parseArgs(args, known) {
125
+ assertFormatValues(args);
105
126
  const flags = new Map();
106
127
  const positional = [];
107
128
  for (let i = 0; i < args.length; i++) {
108
129
  const a = args[i];
109
130
  if (a.startsWith('--')) {
110
- if (a !== '--debug' && !known.includes(a)) {
111
- if (throwOnUnknown)
112
- throw new Error(`未知参数: ${a}`);
113
- console.error(`❌ 未知参数: ${a}`);
114
- process.exit(1);
115
- }
131
+ if (!COMMON_FLAGS.includes(a) && !known.includes(a))
132
+ throw new Error(`未知参数: ${a}`);
116
133
  if (i + 1 >= args.length || args[i + 1].startsWith('--')) {
117
134
  // --touch 这类布尔开关不带值
118
135
  flags.set(a, '');
@@ -140,11 +157,15 @@ export function resolveMemoryCommandArgv(argv) {
140
157
  const known = {
141
158
  note: ['--slug', '--tags', '--speakers'], 'note.update': ['--slug', '--tags'],
142
159
  'note.drop': [], 'note.list': [], create: ['--scope', '--slug', '--desc', '--tags', '--keywords', '--replaces', '--peer'],
143
- update: ['--tags', '--touch'], archive: [], demote: ['--scope'], consolidate: ['--mode'], feedback: [],
160
+ update: ['--tags', '--touch'], archive: [], demote: ['--scope'], consolidate: ['--mode'],
144
161
  };
162
+ // feedback 已移除:旧会话/旧文档可能还在调用,给一句能照做的说明而不是泛化的非法命令。
163
+ if (kind === 'feedback') {
164
+ throw new Error('`ec memory feedback` 已移除:整理反馈由会话直接写入任务书给出的反馈文件');
165
+ }
145
166
  if (!Object.prototype.hasOwnProperty.call(known, kind))
146
167
  throw new Error('Invalid memory command');
147
- const { flags, positional } = parseArgs(argv.slice(noteSub ? 3 : 2), known[kind], true);
168
+ const { flags, positional } = parseArgs(argv.slice(noteSub ? 3 : 2), known[kind]);
148
169
  const required = (value, name) => {
149
170
  if (!value)
150
171
  throw new Error(`${name} is required`);
@@ -200,36 +221,55 @@ export function resolveMemoryCommandArgv(argv) {
200
221
  throw new Error('Invalid consolidation mode');
201
222
  return { type, mode };
202
223
  }
203
- return { type, text: required(content, 'feedback') };
224
+ throw new Error(`Unhandled memory command kind: ${kind}`);
204
225
  }
205
226
  /** 各子命令的一行完整用法:缺参报错时附上,模型照抄即可重试。 */
206
227
  const USAGE = {
207
- note: 'ec memory note --slug <slug> [--tags <tag1,tag2>] [--speakers <aid1,aid2>] "<正文>"',
208
- noteUpdate: 'ec memory note update <slug> [--slug <新slug>] [--tags <...>] ["<新正文>"]',
228
+ note: "ec memory note --slug <slug> [--tags '<tag1>,<tag2>'] [--speakers '<aid1>,<aid2>'] '<正文>'",
229
+ noteUpdate: "ec memory note update <slug> [--slug <新slug>] [--tags '<tag1>,<tag2>'] ['<新正文>']",
209
230
  noteDrop: 'ec memory note drop <slug>',
210
- create: 'ec memory create --scope <relation|agent|owner> --slug <slug> --desc "<描述>" --tags <tag1,tag2> [--keywords <...>] [--replaces <路径,...>] [--peer <peerKey>] "<正文>"',
211
- update: 'ec memory update <路径> [--tags <tag1,tag2>] [--touch](至少给一项)',
231
+ create: "ec memory create --scope <relation|agent|owner> --slug <slug> --desc '<描述>' --tags '<tag1>,<tag2>' [--keywords '<kw1>,<kw2>'] [--replaces '<路径1>,<路径2>'] [--peer <peerKey>] '<正文>'",
232
+ update: "ec memory update <路径> [--tags '<tag1>,<tag2>'] [--touch](至少给一项)",
212
233
  archive: 'ec memory archive <路径...>',
213
234
  };
214
- function failWithUsage(message, usage) {
215
- console.error(`❌ ${message}`);
216
- console.error(`用法: ${usage}`);
235
+ /**
236
+ * 统一失败出口。JSON 模式与 `ec fs` / `ec response` 一致:stdout 输出 `{ ok: false, code, error }`;
237
+ * 文本模式默认输出 `❌ <message>`(有 usage 时再加一行用法);`text` 给出时整段原样输出,保留各处既有措辞。
238
+ */
239
+ function fail(json, code, message, opts = {}) {
240
+ if (json) {
241
+ console.log(JSON.stringify({ ok: false, code, error: message, ...(opts.usage ? { usage: opts.usage } : {}) }, null, 2));
242
+ }
243
+ else {
244
+ console.error(opts.text ?? (opts.usage ? `❌ ${message}\n用法: ${opts.usage}` : `❌ ${message}`));
245
+ }
217
246
  process.exit(1);
218
247
  }
248
+ function failWithUsage(json, message, usage) {
249
+ fail(json, 'INVALID_ARGUMENT', message, { usage });
250
+ }
251
+ /** CLI 侧解析:参数错误按输出格式报错退出。 */
252
+ function parseCliArgs(args, known, json) {
253
+ try {
254
+ return parseArgs(args, known);
255
+ }
256
+ catch (e) {
257
+ return fail(json, 'INVALID_ARGUMENT', e.message);
258
+ }
259
+ }
219
260
  /**
220
261
  * 取当前会话。`--debug <sessionId>` 在宿主终端模拟托管环境(仅开发仓 daemon 认);
221
262
  * 否则读 EVOLCORE_SESSION_ID。
222
263
  */
223
- function requireManagedSession(cmd, flags) {
264
+ function requireManagedSession(cmd, flags, json) {
224
265
  const debugSessionId = flags.get('--debug');
225
266
  if (flags.has('--debug') && !debugSessionId) {
226
- console.error(`❌ --debug 需要提供 sessionId(如 --debug meta_20260910_1789013149542)`);
227
- process.exit(1);
267
+ fail(json, 'INVALID_ARGUMENT', '--debug 需要提供 sessionId(如 --debug meta_20260910_1789013149542)');
228
268
  }
229
269
  const sessionId = debugSessionId || process.env.EVOLCORE_SESSION_ID;
230
270
  if (!sessionId) {
231
- console.error(`错误: EVOLCORE_SESSION_ID 未设置(${cmd} 仅在 evolcore 托管环境中可用;调试可加 --debug <sessionId>)`);
232
- process.exit(1);
271
+ const message = `EVOLCORE_SESSION_ID 未设置(${cmd} 仅在 evolcore 托管环境中可用;调试可加 --debug <sessionId>)`;
272
+ fail(json, 'NO_SESSION', message, { text: `错误: ${message}` });
233
273
  }
234
274
  if (debugSessionId)
235
275
  console.error(`[debug] 模拟会话 ${debugSessionId}`);
@@ -241,83 +281,83 @@ function requireManagedSession(cmd, flags) {
241
281
  };
242
282
  }
243
283
  // ── note ───────────────────────────────────────────────────────────────────
244
- async function cmdMemoryNote(args) {
284
+ async function cmdMemoryNote(args, json) {
245
285
  if (wantsHelp(args)) {
246
286
  console.log(MEMORY_HELP);
247
287
  return;
248
288
  }
249
289
  const sub = args[0];
250
290
  if (sub === 'update')
251
- return cmdMemoryNoteUpdate(args.slice(1));
291
+ return cmdMemoryNoteUpdate(args.slice(1), json);
252
292
  if (sub === 'drop')
253
- return cmdMemoryNoteDrop(args.slice(1));
293
+ return cmdMemoryNoteDrop(args.slice(1), json);
254
294
  if (sub === 'list')
255
- return cmdMemoryNoteList(args.slice(1));
256
- return cmdMemoryNoteCreate(args);
295
+ return cmdMemoryNoteList(args.slice(1), json);
296
+ return cmdMemoryNoteCreate(args, json);
257
297
  }
258
- async function cmdMemoryNoteCreate(args) {
259
- const { flags, positional } = parseArgs(args, ['--slug', '--tags', '--speakers']);
298
+ async function cmdMemoryNoteCreate(args, json) {
299
+ const { flags, positional } = parseCliArgs(args, ['--slug', '--tags', '--speakers'], json);
260
300
  const content = positional.join(' ').trim();
261
301
  const slug = flags.get('--slug');
262
302
  const tags = parseTags(flags.get('--tags'));
263
303
  const speakers = parseTags(flags.get('--speakers'));
264
304
  if (!slug)
265
- failWithUsage('必须提供 --slug', USAGE.note);
305
+ failWithUsage(json, '必须提供 --slug', USAGE.note);
266
306
  if (!content)
267
- failWithUsage('必须提供记忆内容(content)', USAGE.note);
268
- const { socketPath, ...session } = requireManagedSession('ec memory note', flags);
307
+ failWithUsage(json, '必须提供记忆内容(content)', USAGE.note);
308
+ const { socketPath, ...session } = requireManagedSession('ec memory note', flags, json);
269
309
  const result = await ipcQuery(socketPath, {
270
310
  type: 'memory.note', argv: ['memory', 'note', ...args], ...session, slug, content, tags,
271
311
  speakers: speakers && speakers.length > 0 ? speakers : undefined,
272
312
  }, 15_000);
273
- reportResult(result, (r) => {
313
+ reportResult(result, json, (r) => {
274
314
  if (r.filePath)
275
315
  console.log(r.filePath);
276
316
  });
277
317
  }
278
- async function cmdMemoryNoteUpdate(args) {
279
- const { flags, positional } = parseArgs(args, ['--slug', '--tags']);
318
+ async function cmdMemoryNoteUpdate(args, json) {
319
+ const { flags, positional } = parseCliArgs(args, ['--slug', '--tags'], json);
280
320
  const slug = positional[0];
281
321
  const content = positional.slice(1).join(' ').trim();
282
322
  const newSlug = flags.get('--slug');
283
323
  const tagsRaw = flags.get('--tags');
284
324
  const tags = parseTags(tagsRaw);
285
325
  if (!slug)
286
- failWithUsage('必须提供要修改的 slug', USAGE.noteUpdate);
326
+ failWithUsage(json, '必须提供要修改的 slug', USAGE.noteUpdate);
287
327
  if (!newSlug && tagsRaw === undefined && !content) {
288
- failWithUsage('至少提供一项要改的内容(--slug / --tags / 正文)', USAGE.noteUpdate);
328
+ failWithUsage(json, '至少提供一项要改的内容(--slug / --tags / 正文)', USAGE.noteUpdate);
289
329
  }
290
- const { socketPath, ...session } = requireManagedSession('ec memory note update', flags);
330
+ const { socketPath, ...session } = requireManagedSession('ec memory note update', flags, json);
291
331
  const result = await ipcQuery(socketPath, {
292
332
  type: 'memory.note.update', argv: ['memory', 'note', 'update', ...args], ...session, slug,
293
333
  newSlug, tags, tagsProvided: tagsRaw !== undefined,
294
334
  content: content || undefined,
295
335
  }, 15_000);
296
- reportResult(result, (r) => {
336
+ reportResult(result, json, (r) => {
297
337
  if (r.filePath)
298
338
  console.log(r.filePath);
299
339
  });
300
340
  }
301
- async function cmdMemoryNoteDrop(args) {
302
- const { flags, positional } = parseArgs(args, []);
341
+ async function cmdMemoryNoteDrop(args, json) {
342
+ const { flags, positional } = parseCliArgs(args, [], json);
303
343
  const slug = positional[0];
304
344
  if (!slug)
305
- failWithUsage('必须提供要撤销的 slug', USAGE.noteDrop);
306
- const { socketPath, ...session } = requireManagedSession('ec memory note drop', flags);
345
+ failWithUsage(json, '必须提供要撤销的 slug', USAGE.noteDrop);
346
+ const { socketPath, ...session } = requireManagedSession('ec memory note drop', flags, json);
307
347
  const result = await ipcQuery(socketPath, {
308
348
  type: 'memory.note.drop', argv: ['memory', 'note', 'drop', ...args], ...session, slug,
309
349
  }, 15_000);
310
- reportResult(result, (r) => {
350
+ reportResult(result, json, (r) => {
311
351
  console.log(`✓ 已撤销: ${r.filePath ?? slug}`);
312
352
  });
313
353
  }
314
- async function cmdMemoryNoteList(args) {
315
- const { flags } = parseArgs(args, []);
316
- const { socketPath, ...session } = requireManagedSession('ec memory note list', flags);
354
+ async function cmdMemoryNoteList(args, json) {
355
+ const { flags } = parseCliArgs(args, [], json);
356
+ const { socketPath, ...session } = requireManagedSession('ec memory note list', flags, json);
317
357
  const result = await ipcQuery(socketPath, {
318
358
  type: 'memory.note.list', argv: ['memory', 'note', 'list', ...args], ...session,
319
359
  }, 15_000);
320
- reportResult(result, (r) => {
360
+ reportResult(result, json, (r) => {
321
361
  const notes = r.notes ?? [];
322
362
  if (notes.length === 0) {
323
363
  console.log('(没有待整理的 note)');
@@ -332,10 +372,10 @@ async function cmdMemoryNoteList(args) {
332
372
  });
333
373
  }
334
374
  // ── create / update / archive(仅整理会话) ─────────────────────────────────
335
- async function cmdMemoryCreate(args) {
336
- const { flags, positional } = parseArgs(args, [
375
+ async function cmdMemoryCreate(args, json) {
376
+ const { flags, positional } = parseCliArgs(args, [
337
377
  '--scope', '--slug', '--desc', '--tags', '--keywords', '--replaces', '--peer',
338
- ]);
378
+ ], json);
339
379
  const content = positional.join(' ').trim();
340
380
  const scope = flags.get('--scope');
341
381
  const slug = flags.get('--slug');
@@ -345,20 +385,20 @@ async function cmdMemoryCreate(args) {
345
385
  const replacesRaw = flags.get('--replaces');
346
386
  const targetPeerKey = flags.get('--peer');
347
387
  if (!scope || !['agent', 'relation', 'owner'].includes(scope)) {
348
- failWithUsage('--scope 必须是 agent / relation / owner 之一', USAGE.create);
388
+ failWithUsage(json, '--scope 必须是 agent / relation / owner 之一', USAGE.create);
349
389
  }
350
390
  if (!slug)
351
- failWithUsage('必须提供 --slug', USAGE.create);
391
+ failWithUsage(json, '必须提供 --slug', USAGE.create);
352
392
  if (!desc)
353
- failWithUsage('必须提供 --desc', USAGE.create);
393
+ failWithUsage(json, '必须提供 --desc', USAGE.create);
354
394
  if (tagsRaw === undefined)
355
- failWithUsage('必须提供 --tags', USAGE.create);
395
+ failWithUsage(json, '必须提供 --tags', USAGE.create);
356
396
  if (!content)
357
- failWithUsage('必须提供记忆内容(content)', USAGE.create);
397
+ failWithUsage(json, '必须提供记忆内容(content)', USAGE.create);
358
398
  if (targetPeerKey !== undefined && scope !== 'relation') {
359
- failWithUsage('--peer 只在 --scope relation 时有效', USAGE.create);
399
+ failWithUsage(json, '--peer 只在 --scope relation 时有效', USAGE.create);
360
400
  }
361
- const { socketPath, ...session } = requireManagedSession('ec memory create', flags);
401
+ const { socketPath, ...session } = requireManagedSession('ec memory create', flags, json);
362
402
  const result = await ipcQuery(socketPath, {
363
403
  type: 'memory.create', argv: ['memory', 'create', ...args], ...session, scope, slug, description: desc,
364
404
  content,
@@ -367,7 +407,7 @@ async function cmdMemoryCreate(args) {
367
407
  replaces: replacesRaw ? replacesRaw.split(',').map(s => s.trim()).filter(Boolean) : undefined,
368
408
  targetPeerKey: targetPeerKey ?? undefined,
369
409
  }, 15_000);
370
- reportResult(result, (r) => {
410
+ reportResult(result, json, (r) => {
371
411
  if (r.filePath)
372
412
  console.log(r.filePath);
373
413
  if (Array.isArray(r.archived) && r.archived.length > 0) {
@@ -375,33 +415,33 @@ async function cmdMemoryCreate(args) {
375
415
  }
376
416
  });
377
417
  }
378
- async function cmdMemoryConsolidatedUpdate(args) {
379
- const { flags, positional } = parseArgs(args, ['--tags', '--touch']);
418
+ async function cmdMemoryConsolidatedUpdate(args, json) {
419
+ const { flags, positional } = parseCliArgs(args, ['--tags', '--touch'], json);
380
420
  const filePath = positional[0];
381
421
  const tagsRaw = flags.get('--tags');
382
422
  const touch = flags.has('--touch');
383
423
  if (!filePath)
384
- failWithUsage('必须提供要修改的记忆文件路径', USAGE.update);
424
+ failWithUsage(json, '必须提供要修改的记忆文件路径', USAGE.update);
385
425
  if (tagsRaw === undefined && !touch)
386
- failWithUsage('至少提供 --tags 或 --touch', USAGE.update);
387
- const { socketPath, ...session } = requireManagedSession('ec memory update', flags);
426
+ failWithUsage(json, '至少提供 --tags 或 --touch', USAGE.update);
427
+ const { socketPath, ...session } = requireManagedSession('ec memory update', flags, json);
388
428
  const result = await ipcQuery(socketPath, {
389
429
  type: 'memory.update', argv: ['memory', 'update', ...args], ...session, filePath,
390
430
  tags: parseTags(tagsRaw), touch,
391
431
  }, 15_000);
392
- reportResult(result, () => {
432
+ reportResult(result, json, () => {
393
433
  console.log(`✓ 已更新: ${filePath}`);
394
434
  });
395
435
  }
396
- async function cmdMemoryArchive(args) {
397
- const { flags, positional } = parseArgs(args, []);
436
+ async function cmdMemoryArchive(args, json) {
437
+ const { flags, positional } = parseCliArgs(args, [], json);
398
438
  if (positional.length === 0)
399
- failWithUsage('必须提供至少一个要归档的文件路径', USAGE.archive);
400
- const { socketPath, ...session } = requireManagedSession('ec memory archive', flags);
439
+ failWithUsage(json, '必须提供至少一个要归档的文件路径', USAGE.archive);
440
+ const { socketPath, ...session } = requireManagedSession('ec memory archive', flags, json);
401
441
  const result = await ipcQuery(socketPath, {
402
442
  type: 'memory.archive', argv: ['memory', 'archive', ...args], ...session, filePaths: positional,
403
443
  }, 15_000);
404
- reportResult(result, (r) => {
444
+ reportResult(result, json, (r) => {
405
445
  const archived = r.archived ?? positional;
406
446
  console.log(`✓ 已归档 ${archived.length} 个文件:`);
407
447
  for (const f of archived)
@@ -409,27 +449,26 @@ async function cmdMemoryArchive(args) {
409
449
  });
410
450
  }
411
451
  // ── consolidate ────────────────────────────────────────────────────────────
412
- async function cmdMemoryDemote(args) {
452
+ async function cmdMemoryDemote(args, json) {
413
453
  if (wantsHelp(args)) {
414
454
  console.log(MEMORY_HELP);
415
455
  return;
416
456
  }
417
- const { flags, positional } = parseArgs(args, ['--scope']);
457
+ const { flags, positional } = parseCliArgs(args, ['--scope'], json);
418
458
  const slug = positional[0];
419
459
  if (!slug) {
420
- console.error('用法: ec memory demote <slug> [--scope agent|owner]');
421
- process.exit(1);
460
+ const usage = 'ec memory demote <slug> [--scope agent|owner]';
461
+ fail(json, 'INVALID_ARGUMENT', '必须提供要降级的 slug', { usage, text: `用法: ${usage}` });
422
462
  }
423
463
  const scope = flags.get('--scope') ?? 'agent';
424
464
  if (scope !== 'agent' && scope !== 'owner') {
425
- console.error('--scope 必须是 agent 或 owner');
426
- process.exit(1);
465
+ fail(json, 'INVALID_ARGUMENT', '--scope 必须是 agent 或 owner', { text: '--scope 必须是 agent 或 owner' });
427
466
  }
428
- const { socketPath, ...session } = requireManagedSession('ec memory demote', flags);
467
+ const { socketPath, ...session } = requireManagedSession('ec memory demote', flags, json);
429
468
  const result = await ipcQuery(socketPath, {
430
469
  type: 'memory.demote', argv: ['memory', 'demote', ...args], ...session, slug, scope,
431
470
  }, 15_000);
432
- reportResult(result, (r) => {
471
+ reportResult(result, json, (r) => {
433
472
  if (r.conflictArchived) {
434
473
  console.log(`⚠ 目标层已有同名文件,当前记忆已归档至:`);
435
474
  console.log(` ${r.conflictArchived}`);
@@ -440,76 +479,57 @@ async function cmdMemoryDemote(args) {
440
479
  }
441
480
  });
442
481
  }
443
- async function cmdMemoryConsolidate(args) {
482
+ async function cmdMemoryConsolidate(args, json) {
444
483
  if (wantsHelp(args)) {
445
484
  console.log(MEMORY_HELP);
446
485
  return;
447
486
  }
448
487
  // 先于通用解析处理已废弃的 --scope,给出可操作的提示而不是「未知参数」
449
488
  if (args.includes('--scope')) {
450
- console.error('❌ `--scope` 已废弃。作用域由模式唯一决定,请改用 `--mode <notes|generalize|promote|profile|forget>`');
451
- process.exit(1);
489
+ fail(json, 'INVALID_ARGUMENT', '`--scope` 已废弃。作用域由模式唯一决定,请改用 `--mode <notes|generalize|promote|profile|forget>`');
452
490
  }
453
- const { flags } = parseArgs(args, ['--mode']);
491
+ const { flags } = parseCliArgs(args, ['--mode'], json);
454
492
  const mode = (flags.get('--mode') ?? 'notes');
455
493
  if (!MEMORY_MODES.includes(mode)) {
456
- console.error(`❌ --mode 必须是 ${MEMORY_MODES.join(' / ')} 之一`);
457
- process.exit(1);
494
+ fail(json, 'INVALID_ARGUMENT', `--mode 必须是 ${MEMORY_MODES.join(' / ')} 之一`);
458
495
  }
459
- const { socketPath, ...session } = requireManagedSession('ec memory consolidate', flags);
460
- console.log(`正在触发记忆整理(mode=${mode})...`);
496
+ const { socketPath, ...session } = requireManagedSession('ec memory consolidate', flags, json);
497
+ // JSON 模式下 stdout 只留结果对象
498
+ if (!json)
499
+ console.log(`正在触发记忆整理(mode=${mode})...`);
461
500
  const result = await ipcQuery(socketPath, {
462
501
  type: 'memory.consolidate', argv: ['memory', 'consolidate', ...args], ...session, mode,
463
502
  }, 30_000);
464
- reportResult(result, (r) => {
503
+ reportResult(result, json, (r) => {
504
+ if (r.queued) {
505
+ console.log(`⏳ 整理请求已入队(${mode} 模式),前一个整理会话结束后自动启动`);
506
+ for (const line of formatQueueDetails(r.queued))
507
+ console.log(` ${line}`);
508
+ console.log('启动后整理结果会反馈到发起会话。');
509
+ return;
510
+ }
465
511
  console.log(`✓ 整理会话已启动(${mode} 模式)`);
466
512
  if (r.triggerId)
467
513
  console.log(` triggerId: ${r.triggerId}`);
468
514
  if (r.executionSessionId)
469
515
  console.log(` sessionId: ${r.executionSessionId}`);
470
- console.log(` agentSessionId: ${r.agentSessionId ?? '(会话仍在初始化,稍后用 sessionId 查)'}`);
471
516
  if (r.contextFilePath)
472
517
  console.log(` context: ${r.contextFilePath}`);
473
518
  console.log('整理会话在后台继续运行。');
474
519
  });
475
520
  }
476
- // ── feedback(整理会话反馈)─────────────────────────────────────────────────
477
- /**
478
- * 整理会话用 `ec memory feedback "<文本>"` 记录本次整理的反馈内容。
479
- * 文本写入批次目录的 ops.jsonl(op=feedback-set),收尾时据此投递回发起会话。
480
- * 未调用则不写,收尾回退到默认统计模板。
481
- */
482
- async function cmdMemoryFeedback(args) {
483
- if (wantsHelp(args)) {
484
- console.log(MEMORY_HELP);
485
- return;
486
- }
487
- const { flags, positional } = parseArgs(args, []);
488
- const text = positional.join(' ').trim();
489
- if (!text) {
490
- console.error('用法: ec memory feedback "<反馈文本>"');
491
- process.exit(1);
492
- }
493
- const { socketPath, ...session } = requireManagedSession('ec memory feedback', flags);
494
- const result = await ipcQuery(socketPath, {
495
- type: 'memory.feedback', argv: ['memory', 'feedback', ...args], ...session, text,
496
- }, 15_000);
497
- reportResult(result, () => {
498
- console.log('✓ 已记录反馈内容');
499
- });
500
- }
501
521
  // ── 结果输出 ───────────────────────────────────────────────────────────────
502
- function reportResult(result, ok) {
522
+ function reportResult(result, json, ok) {
503
523
  if (!result) {
504
- console.error('错误: 无法连接 evolcore 服务');
505
- process.exit(1);
524
+ fail(json, 'DAEMON_UNAVAILABLE', '无法连接 evolcore 服务', { text: '错误: 无法连接 evolcore 服务' });
506
525
  }
507
526
  const r = result;
508
- if (r.ok) {
509
- ok(r);
510
- }
511
- else {
512
- console.error(r.error || '操作失败');
513
- process.exit(1);
527
+ if (!r.ok) {
528
+ const message = r.error || '操作失败';
529
+ fail(json, r.code || 'MEMORY_OPERATION_FAILED', message, { text: message });
514
530
  }
531
+ if (json)
532
+ console.log(JSON.stringify(r, null, 2));
533
+ else
534
+ ok(r);
515
535
  }
@@ -158,12 +158,17 @@ export function parseQueueOperationArgv(argv) {
158
158
  const valueFlags = new Set(['--agent', '--cancel', '--sessionkey', '--after', '--before', '--format']);
159
159
  for (let index = 1; index < argv.length; index++) {
160
160
  const flag = argv[index];
161
- if (booleanFlags.has(flag))
161
+ if (booleanFlags.has(flag)) {
162
162
  flags.set(flag, 'true');
163
- else if (valueFlags.has(flag) && argv[index + 1] && !argv[index + 1].startsWith('--'))
164
- flags.set(flag, argv[++index]);
165
- else
163
+ }
164
+ else if (valueFlags.has(flag) && argv[index + 1] && !argv[index + 1].startsWith('--')) {
165
+ if (!flags.has(flag))
166
+ flags.set(flag, argv[index + 1]);
167
+ index++;
168
+ }
169
+ else {
166
170
  throw new Error(`Invalid queue option: ${flag}`);
171
+ }
167
172
  }
168
173
  const agent = flags.get('--agent');
169
174
  if (!agent)