evolcore 0.0.22 → 0.0.24

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 (117) hide show
  1. package/CHANGELOG.md +74 -14
  2. package/README.md +4 -0
  3. package/bin/codex-managed-acl.ps1 +160 -0
  4. package/bin/codex-managed-hook.mjs +127 -10
  5. package/bin/ec-safe-output.js +85 -3
  6. package/bin/install-codex-managed-hooks.mjs +384 -95
  7. package/dist/agents/baseagent-availability.js +48 -0
  8. package/dist/agents/baseagent.js +30 -2
  9. package/dist/agents/claude-runner.js +179 -240
  10. package/dist/agents/{codex-app-server-client.js → codex/app-server-client.js} +90 -20
  11. package/dist/{utils/codex-app-server-registry.js → agents/codex/app-server-registry.js} +2 -2
  12. package/dist/agents/codex/catalog.js +70 -0
  13. package/dist/agents/codex/diagnostics.js +369 -0
  14. package/dist/agents/codex-runner.js +839 -192
  15. package/dist/agents/ecagent-runner.js +27 -34
  16. package/dist/agents/gemini-runner.js +62 -8
  17. package/dist/agents/runner-types.js +1 -1
  18. package/dist/aun/aid/managed-operation.js +28 -6
  19. package/dist/aun/aid/store.js +43 -0
  20. package/dist/aun/menu-client.js +272 -0
  21. package/dist/aun/msg/group.js +65 -4
  22. package/dist/aun/msg/index.js +1 -1
  23. package/dist/aun/msg/managed-operation.js +57 -5
  24. package/dist/aun/outbox.js +56 -18
  25. package/dist/aun/rpc/client.js +7 -1
  26. package/dist/channels/aun.js +178 -77
  27. package/dist/channels/daemon.js +7 -1
  28. package/dist/channels/dingtalk.js +1 -0
  29. package/dist/channels/feishu.js +10 -4
  30. package/dist/channels/wechat.js +81 -10
  31. package/dist/channels/wecom.js +2 -1
  32. package/dist/cli/agent-command.js +29 -3
  33. package/dist/cli/agent-create.js +538 -0
  34. package/dist/cli/agent.js +26 -675
  35. package/dist/cli/aun-commands.js +108 -24
  36. package/dist/cli/command-log.js +21 -2
  37. package/dist/cli/ctl-command.js +2 -0
  38. package/dist/cli/daemon-commands.js +289 -61
  39. package/dist/cli/index.js +22 -2
  40. package/dist/cli/init.js +2 -10
  41. package/dist/cli/managed-command-guard.js +3 -0
  42. package/dist/cli/menu-client.js +95 -0
  43. package/dist/cli/model.js +23 -8
  44. package/dist/cli/restart-monitor.js +432 -8
  45. package/dist/cli/stats.js +110 -0
  46. package/dist/cli/task-context.js +12 -2
  47. package/dist/cli/trigger-command.js +9 -1
  48. package/dist/config/builtin-roles.js +2 -0
  49. package/dist/config/schema-migration.js +14 -2
  50. package/dist/core/auth/agent-delegation.js +10 -7
  51. package/dist/core/auth/auth-gateway.js +3 -2
  52. package/dist/core/auth/authorization-audit.js +75 -18
  53. package/dist/core/auth/operation-authorizer.js +63 -3
  54. package/dist/core/auth/operation-catalog.js +14 -2
  55. package/dist/core/auth/remote-access-store.js +136 -0
  56. package/dist/core/baseagent-loader.js +4 -4
  57. package/dist/core/bootstrap-messages.js +39 -18
  58. package/dist/core/bootstrap-service.js +32 -26
  59. package/dist/core/capability/capability-manager.js +8 -4
  60. package/dist/core/capability/providers/codex-capability-provider.js +1 -1
  61. package/dist/core/command/agent-control.js +7 -2
  62. package/dist/core/command/command-handler.js +128 -30
  63. package/dist/core/command/daemon-diagnostics.js +448 -0
  64. package/dist/core/command/menu-catalog.js +6 -1
  65. package/dist/core/command/menu-handler.js +410 -98
  66. package/dist/core/command/menu-protocol.js +123 -0
  67. package/dist/core/command/slash-gate.js +4 -6
  68. package/dist/core/command/slash-handler.js +199 -70
  69. package/dist/core/data-migration.js +5 -15
  70. package/dist/core/event-catalog.js +3 -0
  71. package/dist/core/handoff/runtime.js +3 -1
  72. package/dist/core/handoff/store.js +7 -1
  73. package/dist/core/message/im-renderer.js +13 -6
  74. package/dist/core/message/message-bridge.js +5 -36
  75. package/dist/core/message/message-queue.js +20 -15
  76. package/dist/core/message/message-utils.js +6 -3
  77. package/dist/core/message/response-engine.js +147 -94
  78. package/dist/core/model/catalog-service.js +310 -0
  79. package/dist/core/model/model-catalog.js +134 -334
  80. package/dist/core/model/model-diagnostics.js +4 -5
  81. package/dist/core/model/model-fallback.js +9 -16
  82. package/dist/core/model/model-permission.js +5 -2
  83. package/dist/core/permission/approval-gateway.js +183 -32
  84. package/dist/core/permission/protected-paths.js +63 -4
  85. package/dist/core/permission/sandbox-runtime.js +4 -2
  86. package/dist/core/permission/tool-policy.js +257 -31
  87. package/dist/core/runtime-lock.js +13 -8
  88. package/dist/core/session/adapters/codex-session-file-adapter.js +71 -3
  89. package/dist/core/session/session-manager.js +49 -13
  90. package/dist/core/session/session-renew.js +1 -0
  91. package/dist/index.js +214 -57
  92. package/dist/ipc.js +191 -102
  93. package/dist/paths.js +23 -1
  94. package/dist/stats/billing.js +18 -4
  95. package/dist/trigger/manager.js +3 -1
  96. package/dist/trigger/parser.js +77 -13
  97. package/dist/trigger/patch.js +104 -1
  98. package/dist/utils/atomic-write.js +26 -2
  99. package/dist/utils/cross-platform.js +436 -1
  100. package/dist/utils/ecweb-supervisor.js +11 -2
  101. package/dist/utils/ecweb-utils.js +8 -26
  102. package/dist/utils/error-utils.js +16 -2
  103. package/dist/utils/model-prices.jsonl +23 -20
  104. package/dist/utils/npm-ops.js +70 -15
  105. package/dist/utils/windows-autostart.js +1 -1
  106. package/kits/docs/evolcore/INDEX.md +1 -0
  107. package/kits/docs/evolcore/agent-create.md +13 -0
  108. package/kits/docs/evolcore/group-collaboration.md +7 -2
  109. package/kits/docs/evolcore/menu-client.md +34 -0
  110. package/kits/migrations/migrate-contact-book-v2.mjs +9 -1
  111. package/kits/migrations/migrate-role-config-v4.mjs +11 -5
  112. package/kits/migrations/migrate-role-config-v5.mjs +8 -2
  113. package/kits/templates/roles/admin.json +2 -0
  114. package/kits/templates/roles/visitor.json +1 -0
  115. package/kits/templates/system-fragments/bootstrap.md +8 -1
  116. package/package.json +16 -4
  117. package/dist/utils/codex-cli.js +0 -43
@@ -122,6 +122,7 @@ export class HandoffStore {
122
122
  request: {
123
123
  payload: clonePayload(input.payload),
124
124
  encrypt: input.encrypt,
125
+ ...(input.contextOnly ? { contextOnly: true } : {}),
125
126
  ...(input.delivery ? { delivery: input.delivery } : {}),
126
127
  },
127
128
  ...(input.originAuthorization
@@ -129,7 +130,12 @@ export class HandoffStore {
129
130
  : {}),
130
131
  causation: normalizeCausation(input.causation),
131
132
  return_policy: input.returnPolicy ?? 'required',
132
- state: 'queued',
133
+ // Local-only requests are already available for the next target-session
134
+ // turn and must never enter the outbound dispatch queue. Keep them in
135
+ // target_sent while waiting for the target turn to bind the context;
136
+ // target_context_pending is reserved for a context-only handoff after
137
+ // it has been consumed by a returnPolicy=none target turn.
138
+ state: input.contextOnly ? 'target_sent' : 'queued',
133
139
  target_message_id: null,
134
140
  response_message_id: null,
135
141
  consumed_at: null,
@@ -227,25 +227,32 @@ export class IMRenderer {
227
227
  durationMs: opts.durationMs,
228
228
  });
229
229
  }
230
- /** 发送不进入 activity/thought 历史的非终态 warning status。 */
231
- async sendWarningStatus(message, subtype, details) {
230
+ /** 发送不进入 activity/thought 历史、也不代表执行活跃的任务级 notice。 */
231
+ async sendStatusNotice(message, severity = 'info', subtype, details) {
232
232
  const payload = {
233
- kind: 'status.progress',
233
+ kind: 'status.notice',
234
234
  metadata: {
235
- activityType: 'progress',
236
235
  message,
237
- severity: 'warn',
236
+ severity,
238
237
  ...(subtype !== undefined && { subtype }),
239
238
  ...(details?.missingItems !== undefined && { missingItems: details.missingItems }),
239
+ ...(details?.idleSec !== undefined && { idleSec: details.idleSec }),
240
+ ...(details?.totalEvents !== undefined && { totalEvents: details.totalEvents }),
241
+ ...(details?.totalToolCalls !== undefined && { totalToolCalls: details.totalToolCalls }),
242
+ ...(details?.lastToolName !== undefined && { lastToolName: details.lastToolName }),
240
243
  },
241
244
  };
242
245
  try {
243
246
  await this.opts.send(payload);
244
247
  }
245
248
  catch (error) {
246
- logger.warn(`[IMRenderer] warning status send failed: ${error instanceof Error ? error.message : String(error)}`);
249
+ logger.warn(`[IMRenderer] status notice send failed: ${error instanceof Error ? error.message : String(error)}`);
247
250
  }
248
251
  }
252
+ /** 兼容旧调用方:发送 warning 级别的任务 notice。 */
253
+ async sendWarningStatus(message, subtype, details) {
254
+ return this.sendStatusNotice(message, 'warn', subtype, details);
255
+ }
249
256
  /** 添加任务生命周期边界事件,复用 activity.batch 投影路径。 */
250
257
  addLifecycle(phase, metadata, text) {
251
258
  const item = {
@@ -680,40 +680,6 @@ export class MessageBridge {
680
680
  }
681
681
  return d;
682
682
  }
683
- availableBaseagentsFor(channelName) {
684
- const owningAgent = this.agentRegistry?.resolveByChannel(channelName);
685
- if (!owningAgent)
686
- return [];
687
- const prefix = `${owningAgent.name}::`;
688
- return this.processor.getAvailableAgents()
689
- .filter(key => key.startsWith(prefix))
690
- .map(key => key.slice(prefix.length));
691
- }
692
- async alignSessionBaseagent(channelName, session) {
693
- const owningAgent = this.agentRegistry?.resolveByChannel(channelName);
694
- if (!owningAgent)
695
- return session;
696
- const available = this.availableBaseagentsFor(channelName);
697
- if (available.length === 0 || available.includes(session.baseagent))
698
- return session;
699
- // A topic's backend binding is fenced by SessionManager and cannot be
700
- // cleared as a side effect of routing alignment. Reassigning the
701
- // baseagent while leaving the old provider's agentSessionId persisted
702
- // would make the new runner resume an incompatible backend. Keep the
703
- // binding intact and let normal baseagent-mismatch handling report it;
704
- // an explicit boundary operation must perform any future migration.
705
- if (session.threadId) {
706
- logger.error(`[MessageBridge] Cannot align topic to another baseagent: `
707
- + `session=${session.id} thread=${session.threadId} current=${session.baseagent} preferred=${owningAgent.baseagent}`);
708
- return session;
709
- }
710
- const preferred = available.includes(owningAgent.baseagent)
711
- ? owningAgent.baseagent
712
- : available[0];
713
- logger.warn(`[MessageBridge] Aligning unavailable session baseagent: session=${session.id} ${session.baseagent} -> ${preferred} agent=${owningAgent.name} available=${available.join(',')}`);
714
- await this.sessionManager.updateSession(session.id, { baseagent: preferred });
715
- return { ...session, baseagent: preferred };
716
- }
717
683
  /**
718
684
  * 为渠道注册消息桥梁:入站处理管线 + 出站命令响应
719
685
  *
@@ -1140,7 +1106,6 @@ export class MessageBridge {
1140
1106
  if (session.threadId && typeof this.messageQueue.reserveSessionIngress === 'function') {
1141
1107
  releaseSessionIngress = this.messageQueue.reserveSessionIngress(session.id);
1142
1108
  }
1143
- session = await this.alignSessionBaseagent(channelName, session);
1144
1109
  const replyToMessageId = typeof msg.replyContext?.metadata?.refMessageId === 'string'
1145
1110
  ? msg.replyContext.metadata.refMessageId
1146
1111
  : msg.replyContext?.replyToMessageId ?? null;
@@ -1163,6 +1128,7 @@ export class MessageBridge {
1163
1128
  content,
1164
1129
  replyToMessageId,
1165
1130
  isNewSession: !hadMainSession,
1131
+ currentBaseagent: owningAgent?.baseagent,
1166
1132
  causation: inboundCausation,
1167
1133
  });
1168
1134
  session = renewResult.session;
@@ -1537,7 +1503,10 @@ export class MessageBridge {
1537
1503
  channelId: msg.channelId,
1538
1504
  args,
1539
1505
  });
1540
- const result = await this.cmdHandler.execMenuUpdate(this.resolveCmd(name, cmd), request.value, channel, execution.channelId, execution.subject.actorId, execution.subject.identity, execution.subject.fromControlChannel, execution.args, execution.subject);
1506
+ const result = await this.cmdHandler.execMenuUpdate(this.resolveCmd(name, cmd), request.value, channel, execution.channelId, execution.subject.actorId, execution.subject.identity, execution.subject.fromControlChannel, execution.args, execution.subject, 'menu', {
1507
+ ...(msg.replyContext ?? {}),
1508
+ ...(msg.threadId ? { threadId: msg.threadId } : {}),
1509
+ });
1541
1510
  if ('error' in result)
1542
1511
  throw result;
1543
1512
  return menuSuccess(header, result.data);
@@ -234,6 +234,7 @@ export class MessageQueue {
234
234
  }
235
235
  const tmp = `${this.dedupPath}.tmp-${process.pid}-${Date.now()}-${this.enqueueSequence}`;
236
236
  let fd;
237
+ let renamed = false;
237
238
  try {
238
239
  fs.mkdirSync(path.dirname(this.dedupPath), { recursive: true });
239
240
  const content = Buffer.from(JSON.stringify({
@@ -253,20 +254,22 @@ export class MessageQueue {
253
254
  fs.closeSync(fd);
254
255
  fd = undefined;
255
256
  fs.renameSync(tmp, this.dedupPath);
256
- const persistedFd = fs.openSync(this.dedupPath, 'r');
257
- try {
258
- fs.fsyncSync(persistedFd);
259
- }
260
- finally {
261
- fs.closeSync(persistedFd);
262
- }
257
+ renamed = true;
263
258
  if (process.platform !== 'win32') {
264
- const directoryFd = fs.openSync(path.dirname(this.dedupPath), 'r');
265
259
  try {
266
- fs.fsyncSync(directoryFd);
260
+ const directoryFd = fs.openSync(path.dirname(this.dedupPath), 'r');
261
+ try {
262
+ fs.fsyncSync(directoryFd);
263
+ }
264
+ finally {
265
+ fs.closeSync(directoryFd);
266
+ }
267
267
  }
268
- finally {
269
- fs.closeSync(directoryFd);
268
+ catch (error) {
269
+ // The file contents were already fsynced before rename. A platform
270
+ // that cannot fsync directory metadata must not make a committed
271
+ // dedup claim look uncommitted to the caller.
272
+ logger.warn(`[Queue] Durable dedup ledger directory fsync unavailable after commit: ${error instanceof Error ? error.message : String(error)}`);
270
273
  }
271
274
  }
272
275
  return true;
@@ -279,11 +282,13 @@ export class MessageQueue {
279
282
  }
280
283
  catch { }
281
284
  }
282
- try {
283
- fs.unlinkSync(tmp);
285
+ if (!renamed) {
286
+ try {
287
+ fs.unlinkSync(tmp);
288
+ }
289
+ catch { }
284
290
  }
285
- catch { }
286
- return false;
291
+ return renamed;
287
292
  }
288
293
  }
289
294
  hasEnqueuedMessage(sessionKey, messageId, selfAID) {
@@ -7,8 +7,9 @@ import { renderCommandCardAsText, renderActionAsText } from '../interaction-rout
7
7
  /** A legacy adapter resolved its send call without providing a structured receipt. */
8
8
  export const LEGACY_INTERACTION_ACCEPTED = 'legacy-accepted';
9
9
  export function isInteractionSendAccepted(result) {
10
- return result === LEGACY_INTERACTION_ACCEPTED
11
- || (result !== false && (result.status === 'sent' || result.status === 'queued'));
10
+ if (result === LEGACY_INTERACTION_ACCEPTED || result === 'sent')
11
+ return true;
12
+ return result !== false && (result.status === 'sent' || result.status === 'queued');
12
13
  }
13
14
  /**
14
15
  * 构造出站消息信封
@@ -148,8 +149,10 @@ export async function sendInteractionPayload(adapter, envelope, interaction, fal
148
149
  try {
149
150
  const enriched = replyCtx ? withEnvelopeReplyContext(envelope, replyCtx) : envelope;
150
151
  const receipt = await adapter.send(enriched, payload);
152
+ // Preserve the historical `sent` result for void-returning adapters while
153
+ // still accepting the newer structured SendReceipt contract.
151
154
  if (!receipt)
152
- return LEGACY_INTERACTION_ACCEPTED;
155
+ return 'sent';
153
156
  if (receipt.status === 'sent' && !(receipt.messageId || receipt.messages[0]?.messageId))
154
157
  return false;
155
158
  return receipt;