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