evolcore 0.0.11 → 0.0.13

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 (164) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/bin/codex-managed-hook.mjs +80 -0
  3. package/bin/ec-safe-output.js +26 -7
  4. package/dist/agents/claude-runner.js +86 -7
  5. package/dist/agents/codex-app-server-client.js +174 -20
  6. package/dist/agents/codex-runner.js +375 -92
  7. package/dist/agents/ecagent-runner.js +39 -4
  8. package/dist/agents/gemini-runner.js +1 -0
  9. package/dist/aun/aid/client.js +11 -21
  10. package/dist/aun/aid/control-aid.js +36 -13
  11. package/dist/aun/aid/managed-operation.js +107 -0
  12. package/dist/aun/aid/store.js +13 -7
  13. package/dist/aun/group-fs-download.js +56 -0
  14. package/dist/aun/group-identity.js +1 -2
  15. package/dist/aun/msg/group.js +91 -44
  16. package/dist/aun/msg/index.js +1 -2
  17. package/dist/aun/msg/managed-operation.js +865 -0
  18. package/dist/aun/msg/mention-schema.js +20 -0
  19. package/dist/aun/msg/p2p.js +7 -0
  20. package/dist/aun/msg/upload.js +16 -1
  21. package/dist/aun/outbox.js +31 -2
  22. package/dist/aun/rpc/client.js +66 -0
  23. package/dist/aun/rpc/index.js +1 -2
  24. package/dist/aun/storage/{upload.js → client.js} +11 -2
  25. package/dist/aun/storage/index.js +1 -2
  26. package/dist/channels/aun.js +655 -240
  27. package/dist/channels/daemon.js +13 -0
  28. package/dist/cli/agent-command.js +56 -8
  29. package/dist/cli/agent.js +108 -31
  30. package/dist/cli/aun-commands.js +270 -69
  31. package/dist/cli/bench.js +12 -3
  32. package/dist/cli/cli-argv.js +10 -0
  33. package/dist/cli/config.js +9 -17
  34. package/dist/cli/ctl-command.js +1 -1
  35. package/dist/cli/daemon-commands.js +70 -55
  36. package/dist/cli/fs-command.js +79 -10
  37. package/dist/cli/handoff-command.js +3 -0
  38. package/dist/cli/index.js +30 -2
  39. package/dist/cli/init.js +77 -8
  40. package/dist/cli/managed-command-guard.js +41 -0
  41. package/dist/cli/model.js +11 -4
  42. package/dist/cli/queue-command.js +53 -1
  43. package/dist/cli/response.js +71 -0
  44. package/dist/cli/restart-monitor.js +7 -32
  45. package/dist/cli/trigger-command.js +11 -0
  46. package/dist/config/access-policy.js +1 -2
  47. package/dist/config/builtin-roles.js +9 -0
  48. package/dist/config/config-manager.js +21 -1
  49. package/dist/config/contact-book-store.js +11 -3
  50. package/dist/config/contact-request-service.js +161 -15
  51. package/dist/config/mention-mode.js +8 -24
  52. package/dist/config/peer-role-resolver.js +6 -2
  53. package/dist/config/role-migration-startup.js +53 -0
  54. package/dist/config/role-store.js +1 -1
  55. package/dist/core/auth/agent-delegation.js +1 -2
  56. package/dist/core/auth/auth-gateway.js +29 -1
  57. package/dist/core/auth/authorization-audit.js +15 -0
  58. package/dist/core/auth/operation-authorizer.js +31 -7
  59. package/dist/core/auth/operation-catalog.js +196 -25
  60. package/dist/core/bootstrap-messages.js +25 -0
  61. package/dist/core/bootstrap-service.js +64 -4
  62. package/dist/core/capability/providers/claude-capability-provider.js +9 -31
  63. package/dist/core/capability/providers/codex-capability-provider.js +4 -15
  64. package/dist/core/capability/skill-discovery.js +55 -0
  65. package/dist/core/channel-loader.js +1 -1
  66. package/dist/core/command/cli-intent-parser.js +9 -0
  67. package/dist/core/command/command-handler.js +650 -42
  68. package/dist/core/command/connect-menu.js +15 -0
  69. package/dist/core/command/group-menu.js +4 -4
  70. package/dist/core/command/menu-catalog.js +370 -0
  71. package/dist/core/command/menu-handler.js +230 -51
  72. package/dist/core/command/menu-protocol.js +94 -2
  73. package/dist/core/command/slash-gate.js +5 -2
  74. package/dist/core/command/slash-handler.js +99 -31
  75. package/dist/core/daemon-file-cache.js +2 -1
  76. package/dist/core/data-migration.js +9 -2
  77. package/dist/core/event-catalog.js +6 -0
  78. package/dist/core/evolagent.js +4 -2
  79. package/dist/core/handoff/dispatcher.js +5 -2
  80. package/dist/core/handoff/runtime.js +157 -22
  81. package/dist/core/handoff/store.js +29 -1
  82. package/dist/core/handoff/types.js +1 -0
  83. package/dist/core/interaction-router.js +10 -0
  84. package/dist/core/message/im-renderer.js +19 -0
  85. package/dist/core/message/logical-queue-bridge.js +1 -0
  86. package/dist/core/message/mention-schema.js +126 -0
  87. package/dist/core/message/message-bridge.js +298 -88
  88. package/dist/core/message/message-log.js +3 -0
  89. package/dist/core/message/message-queue.js +268 -39
  90. package/dist/core/message/message-utils.js +81 -4
  91. package/dist/core/message/response-engine.js +161 -77
  92. package/dist/core/message/stream-debouncer.js +10 -2
  93. package/dist/core/permission/approval-gateway.js +1 -0
  94. package/dist/core/permission/ec-command-parser.js +243 -18
  95. package/dist/core/permission/index.js +1 -1
  96. package/dist/core/permission/mode.js +15 -0
  97. package/dist/core/permission/readonly-shell-query.js +148 -8
  98. package/dist/core/permission/sandbox-runtime.js +43 -1
  99. package/dist/core/permission/tool-policy.js +322 -57
  100. package/dist/core/protected-paths.js +114 -4
  101. package/dist/core/session/session-manager.js +42 -4
  102. package/dist/core/session/session-mapper.js +20 -1
  103. package/dist/eck/detect.js +18 -1
  104. package/dist/eck/group-rules-sync.js +15 -44
  105. package/dist/eck/manifest-engine.js +39 -13
  106. package/dist/index.js +541 -180
  107. package/dist/ipc.js +232 -10
  108. package/dist/paths.js +3 -0
  109. package/dist/response-system/coordinator.js +6 -4
  110. package/dist/response-system/engines/v1/proactive-flow.js +26 -8
  111. package/dist/response-system/modes/single-session/index.js +14 -1
  112. package/dist/response-system/selector.js +6 -5
  113. package/dist/trigger/anomaly-store.js +4 -0
  114. package/dist/trigger/feedback.js +64 -11
  115. package/dist/trigger/manager.js +21 -1
  116. package/dist/trigger/parser.js +14 -2
  117. package/dist/trigger/scheduler.js +1 -0
  118. package/dist/trigger/script-executor.js +1 -0
  119. package/dist/trigger/validation.js +67 -6
  120. package/dist/utils/codex-app-server-registry.js +90 -0
  121. package/dist/utils/codex-cli.js +5 -1
  122. package/dist/utils/cross-platform.js +15 -0
  123. package/dist/utils/ecweb-supervisor.js +332 -0
  124. package/dist/utils/error-utils.js +10 -0
  125. package/dist/utils/npm-ops.js +5 -12
  126. package/dist/utils/tool-summary.js +11 -0
  127. package/kits/docs/channels/aun.md +1 -1
  128. package/kits/docs/context-assembly.md +2 -2
  129. package/kits/docs/evolcore/agent.md +11 -6
  130. package/kits/docs/evolcore/aid.md +14 -0
  131. package/kits/docs/evolcore/trigger.md +17 -1
  132. package/kits/docs/prompt-loading-architecture.md +1 -2
  133. package/kits/docs/venues/group.md +1 -1
  134. package/kits/eck_manifest.json +0 -12
  135. package/kits/migrations/migrate-contact-book-v2.mjs +1 -2
  136. package/kits/rules/04-relation.md +1 -1
  137. package/kits/rules/05-venue.md +2 -2
  138. package/kits/schemas/role-config.schema.1.json +1 -0
  139. package/kits/schemas/single-session.schema.1.json +3 -3
  140. package/kits/schemas/single-session.schema.2.json +3 -3
  141. package/kits/templates/roles/admin.json +27 -0
  142. package/kits/templates/roles/member.json +34 -1
  143. package/kits/templates/roles/visitor.json +35 -3
  144. package/kits/templates/system-fragments/bootstrap.md +1 -1
  145. package/kits/templates/system-fragments/channel.md +1 -1
  146. package/kits/templates/system-fragments/session.md +1 -1
  147. package/package.json +2 -2
  148. package/dist/aun/msg/payload-type.js +0 -27
  149. package/dist/aun/rpc/caller.js +0 -42
  150. package/dist/aun/rpc/connection.js +0 -25
  151. package/dist/aun/storage/manage.js +0 -10
  152. package/dist/config/access-policy-domain.js +0 -18
  153. package/dist/config/config-batch-get.js +0 -11
  154. package/dist/config/owner-policy.js +0 -4
  155. package/dist/config/role-config-v4-startup.js +0 -32
  156. package/dist/config/role-config-v5-startup.js +0 -27
  157. package/dist/core/auth/trigger-authorization.js +0 -15
  158. package/dist/core/command/evol-menu-version-gate.js +0 -39
  159. package/dist/core/interaction-registration.js +0 -10
  160. package/dist/core/permission/execution-sandbox.js +0 -16
  161. package/dist/core/relation/peer-key.js +0 -1
  162. package/dist/core/session/session-key.js +0 -24
  163. package/dist/eck/baseagent-caps.js +0 -18
  164. package/dist/eck/rules-loader.js +0 -28
@@ -5,6 +5,11 @@ import { buildHClassGuardCommand } from '../core/permission/sandbox-runtime.js';
5
5
  import { resolveCodexLaunchCommand } from '../utils/codex-cli.js';
6
6
  import { createHash } from 'crypto';
7
7
  import { sanitizeShellExecutionEnvironment } from '../core/permission/shell-environment.js';
8
+ import fs from 'fs';
9
+ import os from 'os';
10
+ import path from 'path';
11
+ import { getPackageRoot, resolvePaths } from '../paths.js';
12
+ import { registerCodexAppServerProcess, unregisterCodexAppServerProcess, } from '../utils/codex-app-server-registry.js';
8
13
  const BUILT_IN_CODEX_PROVIDER_IDS = new Set(['openai']);
9
14
  function tomlProviderKey(value) {
10
15
  if (!value || /[\0\r\n]/.test(value)) {
@@ -25,6 +30,22 @@ function runtimeProviderId(baseUrl) {
25
30
  const digest = createHash('sha256').update(baseUrl || 'default').digest('hex').slice(0, 12);
26
31
  return `evolcore_runtime_${digest}`;
27
32
  }
33
+ function stableJson(value) {
34
+ if (Array.isArray(value))
35
+ return `[${value.map(stableJson).join(',')}]`;
36
+ if (value && typeof value === 'object') {
37
+ return `{${Object.entries(value)
38
+ .sort(([left], [right]) => left.localeCompare(right))
39
+ .map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)
40
+ .join(',')}}`;
41
+ }
42
+ return JSON.stringify(value) ?? 'undefined';
43
+ }
44
+ function serverRequestFingerprint(request) {
45
+ return createHash('sha256')
46
+ .update(`${request.method}\n${stableJson(request.params)}`)
47
+ .digest('hex');
48
+ }
28
49
  function hasPermissionProfile(config) {
29
50
  if (!config || typeof config.default_permissions !== 'string' || !config.default_permissions)
30
51
  return false;
@@ -36,11 +57,14 @@ export class CodexAppServerClient {
36
57
  options;
37
58
  proc = null;
38
59
  pending = new Map();
60
+ serverRequestReplays = new Map();
39
61
  notificationHandlers = new Set();
40
62
  nextId = 1;
41
63
  initialized = false;
42
64
  initializing = null;
43
65
  stderrBuffer = [];
66
+ managedHookRuntimeDir = null;
67
+ processRegistrationPath = null;
44
68
  constructor(options) {
45
69
  this.options = options;
46
70
  }
@@ -298,25 +322,34 @@ export class CodexAppServerClient {
298
322
  pending.reject(new Error('Codex app-server closed'));
299
323
  }
300
324
  this.pending.clear();
301
- if (!proc)
325
+ this.serverRequestReplays.clear();
326
+ if (!proc) {
327
+ this.cleanupManagedHookRuntime();
302
328
  return;
329
+ }
303
330
  // 优雅关闭:先关闭 stdin,然后发送 SIGTERM,等待进程退出
304
331
  proc.stdin.end();
305
332
  proc.kill('SIGTERM');
306
333
  // 等待进程退出,最多等待 5 秒
307
334
  await new Promise((resolve) => {
335
+ let exited = false;
308
336
  const timeout = setTimeout(() => {
309
- if (!proc.killed) {
310
- logger.warn('[CodexAppServer] Process did not exit after SIGTERM, sending SIGKILL');
337
+ if (exited)
338
+ return;
339
+ logger.warn('[CodexAppServer] Process did not exit after SIGTERM, sending SIGKILL');
340
+ try {
311
341
  proc.kill('SIGKILL');
312
342
  }
343
+ catch { }
313
344
  resolve();
314
345
  }, 5000);
315
346
  proc.once('exit', () => {
347
+ exited = true;
316
348
  clearTimeout(timeout);
317
349
  resolve();
318
350
  });
319
351
  });
352
+ this.cleanupManagedHookRuntime();
320
353
  }
321
354
  async ensureStarted() {
322
355
  if (this.initialized)
@@ -352,22 +385,56 @@ export class CodexAppServerClient {
352
385
  const launchCommand = resolveCodexLaunchCommand(args);
353
386
  if (!launchCommand)
354
387
  throw new Error('Codex CLI not found');
355
- const guardedCommand = buildHClassGuardCommand(launchCommand.command, launchCommand.args);
356
- if (process.platform === 'linux' && !guardedCommand) {
357
- throw new Error('Codex 缺少 EvolCore H 类路径隔离运行时,已拒绝启动 app-server');
358
- }
359
- this.proc = spawn(guardedCommand?.command ?? launchCommand.command, guardedCommand?.args ?? launchCommand.args, {
360
- cwd: this.options.cwd,
361
- env,
362
- stdio: ['pipe', 'pipe', 'pipe'],
388
+ try {
389
+ let command = launchCommand.command;
390
+ let commandArgs = launchCommand.args;
391
+ if (process.platform === 'linux') {
392
+ const managedRequirements = this.ensureManagedHookRuntime();
393
+ const guardedCommand = buildHClassGuardCommand(command, commandArgs, undefined, {
394
+ managedCodexRequirements: managedRequirements,
395
+ });
396
+ if (!guardedCommand) {
397
+ throw new Error('Codex 缺少 EvolCore managed-hook 隔离运行时,已拒绝启动 app-server');
398
+ }
399
+ command = guardedCommand.command;
400
+ commandArgs = guardedCommand.args;
401
+ }
402
+ this.proc = spawn(command, commandArgs, {
403
+ cwd: this.options.cwd,
404
+ env,
405
+ stdio: ['pipe', 'pipe', 'pipe'],
406
+ windowsHide: process.platform === 'win32',
407
+ });
408
+ try {
409
+ this.processRegistrationPath = registerCodexAppServerProcess(this.proc.pid);
410
+ }
411
+ catch (error) {
412
+ logger.warn(`[CodexAppServer] failed to register owned process pid=${this.proc.pid ?? '<unknown>'}: ${error}`);
413
+ }
414
+ }
415
+ catch (error) {
416
+ this.cleanupManagedHookRuntime();
417
+ throw error;
418
+ }
419
+ const proc = this.proc;
420
+ const processRegistrationPath = this.processRegistrationPath;
421
+ proc.once('error', error => {
422
+ unregisterCodexAppServerProcess(processRegistrationPath);
423
+ if (this.processRegistrationPath === processRegistrationPath) {
424
+ this.processRegistrationPath = null;
425
+ }
426
+ this.failAll(error);
363
427
  });
364
- this.proc.once('error', error => this.failAll(error));
365
- this.proc.once('exit', (code, signal) => {
428
+ proc.once('exit', (code, signal) => {
429
+ unregisterCodexAppServerProcess(processRegistrationPath);
430
+ if (this.processRegistrationPath === processRegistrationPath) {
431
+ this.processRegistrationPath = null;
432
+ }
366
433
  this.failAll(new Error(`Codex app-server exited: code=${code ?? 'null'} signal=${signal ?? 'null'}`));
367
434
  });
368
- const rl = readline.createInterface({ input: this.proc.stdout, crlfDelay: Infinity });
435
+ const rl = readline.createInterface({ input: proc.stdout, crlfDelay: Infinity });
369
436
  rl.on('line', line => this.handleLine(line));
370
- this.proc.stderr.on('data', chunk => {
437
+ proc.stderr.on('data', chunk => {
371
438
  const text = String(chunk).trim();
372
439
  if (!text)
373
440
  return;
@@ -377,6 +444,62 @@ export class CodexAppServerClient {
377
444
  logger.debug(`[CodexAppServer] ${text}`);
378
445
  });
379
446
  }
447
+ ensureManagedHookRuntime() {
448
+ if (this.managedHookRuntimeDir) {
449
+ return path.join(this.managedHookRuntimeDir, 'requirements.toml');
450
+ }
451
+ const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'evolcore-codex-hooks-'));
452
+ try {
453
+ fs.chmodSync(directory, 0o700);
454
+ const hookPath = path.join(directory, 'pre-tool-use.mjs');
455
+ const sourcePath = path.join(getPackageRoot(), 'bin', 'codex-managed-hook.mjs');
456
+ fs.copyFileSync(sourcePath, hookPath, fs.constants.COPYFILE_EXCL);
457
+ fs.chmodSync(hookPath, 0o500);
458
+ const command = `${this.shellQuote(process.execPath)} ${this.shellQuote(hookPath)} ${this.shellQuote(resolvePaths().instanceSocket)}`;
459
+ const requirementsPath = path.join(directory, 'requirements.toml');
460
+ fs.writeFileSync(requirementsPath, [
461
+ 'allow_managed_hooks_only = true',
462
+ '',
463
+ '[features]',
464
+ 'hooks = true',
465
+ '',
466
+ '[hooks]',
467
+ `managed_dir = ${JSON.stringify(directory)}`,
468
+ '',
469
+ '[[hooks.PreToolUse]]',
470
+ 'matcher = "*"',
471
+ '',
472
+ '[[hooks.PreToolUse.hooks]]',
473
+ 'type = "command"',
474
+ `command = ${JSON.stringify(command)}`,
475
+ 'timeout = 3',
476
+ 'statusMessage = "Checking EvolCore session policy"',
477
+ '',
478
+ ].join('\n'), { mode: 0o400, flag: 'wx' });
479
+ this.managedHookRuntimeDir = directory;
480
+ return requirementsPath;
481
+ }
482
+ catch (error) {
483
+ try {
484
+ fs.rmSync(directory, { recursive: true, force: true });
485
+ }
486
+ catch { }
487
+ throw error;
488
+ }
489
+ }
490
+ shellQuote(value) {
491
+ return `'${value.replace(/'/g, `'"'"'`)}'`;
492
+ }
493
+ cleanupManagedHookRuntime() {
494
+ const directory = this.managedHookRuntimeDir;
495
+ this.managedHookRuntimeDir = null;
496
+ if (!directory || !path.basename(directory).startsWith('evolcore-codex-hooks-'))
497
+ return;
498
+ try {
499
+ fs.rmSync(directory, { recursive: true, force: true });
500
+ }
501
+ catch { }
502
+ }
380
503
  buildProcessEnvironment() {
381
504
  const env = sanitizeShellExecutionEnvironment({
382
505
  ...process.env,
@@ -522,15 +645,44 @@ export class CodexAppServerClient {
522
645
  this.respondError(request.id, new Error('Unsupported Codex app-server request: ' + request.method));
523
646
  return;
524
647
  }
525
- Promise.resolve(handler(request))
648
+ const replayKey = String(request.id);
649
+ const fingerprint = serverRequestFingerprint(request);
650
+ const previous = this.serverRequestReplays.get(replayKey);
651
+ if (previous) {
652
+ if (previous.fingerprint !== fingerprint) {
653
+ const conflict = new Error(`Conflicting Codex app-server request payload for id=${request.id}`);
654
+ logger.warn(`[CodexAppServer] server request ID conflict id=${request.id} method=${request.method}`);
655
+ this.respondError(request.id, conflict);
656
+ return;
657
+ }
658
+ // A retry must receive a response too, but must never invoke the
659
+ // approval handler a second time.
660
+ this.respondFromPromise(request.id, request.method, previous.response);
661
+ return;
662
+ }
663
+ let response;
664
+ try {
665
+ // Invoke synchronously so existing app-server latency stays unchanged,
666
+ // while the explicit catch still turns a synchronous handler throw into
667
+ // the same replayable rejected response as an async failure.
668
+ response = Promise.resolve(handler(request));
669
+ }
670
+ catch (error) {
671
+ response = Promise.reject(error);
672
+ }
673
+ this.serverRequestReplays.set(replayKey, { fingerprint, response });
674
+ this.respondFromPromise(request.id, request.method, response);
675
+ }
676
+ respondFromPromise(id, method, response) {
677
+ response
526
678
  .then(result => {
527
- logger.info(`[CodexAppServer] server response id=${request.id} method=${request.method} result=${JSON.stringify(result ?? null)}`);
528
- this.respond(request.id, result ?? null);
679
+ logger.info(`[CodexAppServer] server response id=${id} method=${method} result=${JSON.stringify(result ?? null)}`);
680
+ this.respond(id, result ?? null);
529
681
  })
530
682
  .catch(error => {
531
683
  const err = error instanceof Error ? error : new Error(String(error));
532
- logger.warn(`[CodexAppServer] server request failed id=${request.id} method=${request.method}: ${err.message}`);
533
- this.respondError(request.id, err);
684
+ logger.warn(`[CodexAppServer] server request failed id=${id} method=${method}: ${err.message}`);
685
+ this.respondError(id, err);
534
686
  });
535
687
  }
536
688
  emitNotification(notification) {
@@ -571,5 +723,7 @@ export class CodexAppServerClient {
571
723
  pending.reject(error);
572
724
  }
573
725
  this.pending.clear();
726
+ this.serverRequestReplays.clear();
727
+ this.cleanupManagedHookRuntime();
574
728
  }
575
729
  }