@voybio/ace-swarm 0.2.5 → 2.4.1

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 (144) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/README.md +21 -13
  3. package/assets/.agents/ACE/agent-qa/instructions.md +11 -0
  4. package/assets/agent-state/EVIDENCE_LOG.md +1 -1
  5. package/assets/agent-state/MODULES/roles/capability-framework.json +41 -0
  6. package/assets/agent-state/MODULES/roles/capability-git.json +33 -0
  7. package/assets/agent-state/MODULES/roles/capability-safety.json +37 -0
  8. package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +21 -0
  9. package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +43 -0
  10. package/assets/agent-state/MODULES/schemas/RUNTIME_TOOL_SPEC_REGISTRY.schema.json +43 -0
  11. package/assets/agent-state/MODULES/schemas/WORKSPACE_SESSION_REGISTRY.schema.json +11 -0
  12. package/assets/agent-state/STATUS.md +2 -2
  13. package/assets/agent-state/runtime-tool-specs.json +70 -2
  14. package/assets/instructions/ACE_Coder.instructions.md +13 -0
  15. package/assets/instructions/ACE_UI.instructions.md +11 -0
  16. package/assets/scripts/ace-hook-dispatch.mjs +70 -6
  17. package/assets/scripts/render-mcp-configs.sh +19 -5
  18. package/dist/ace-context.js +91 -11
  19. package/dist/ace-internal-tools.d.ts +3 -1
  20. package/dist/ace-internal-tools.js +10 -2
  21. package/dist/ace-server-instructions.js +3 -3
  22. package/dist/ace-state-resolver.js +5 -3
  23. package/dist/agent-runtime/role-adapters.d.ts +18 -1
  24. package/dist/agent-runtime/role-adapters.js +49 -5
  25. package/dist/astgrep-index.d.ts +57 -1
  26. package/dist/astgrep-index.js +140 -4
  27. package/dist/cli.js +232 -35
  28. package/dist/discovery-runtime-wrappers.d.ts +108 -0
  29. package/dist/discovery-runtime-wrappers.js +615 -0
  30. package/dist/handoff-registry.js +5 -5
  31. package/dist/helpers/artifacts.d.ts +19 -0
  32. package/dist/helpers/artifacts.js +152 -0
  33. package/dist/helpers/bootstrap.d.ts +24 -0
  34. package/dist/helpers/bootstrap.js +894 -0
  35. package/dist/helpers/constants.d.ts +53 -0
  36. package/dist/helpers/constants.js +295 -0
  37. package/dist/helpers/drift.d.ts +13 -0
  38. package/dist/helpers/drift.js +45 -0
  39. package/dist/helpers/path-utils.d.ts +24 -0
  40. package/dist/helpers/path-utils.js +123 -0
  41. package/dist/helpers/store-resolution.d.ts +19 -0
  42. package/dist/helpers/store-resolution.js +305 -0
  43. package/dist/helpers/workspace-root.d.ts +3 -0
  44. package/dist/helpers/workspace-root.js +80 -0
  45. package/dist/helpers.d.ts +8 -125
  46. package/dist/helpers.js +8 -1768
  47. package/dist/job-scheduler.js +33 -7
  48. package/dist/json-sanitizer.d.ts +16 -0
  49. package/dist/json-sanitizer.js +26 -0
  50. package/dist/local-model-policy.d.ts +27 -0
  51. package/dist/local-model-policy.js +84 -0
  52. package/dist/local-model-runtime.d.ts +6 -0
  53. package/dist/local-model-runtime.js +33 -21
  54. package/dist/model-bridge.d.ts +13 -1
  55. package/dist/model-bridge.js +410 -23
  56. package/dist/orchestrator-supervisor.d.ts +56 -0
  57. package/dist/orchestrator-supervisor.js +179 -1
  58. package/dist/plan-proposal.d.ts +115 -0
  59. package/dist/plan-proposal.js +1073 -0
  60. package/dist/run-ledger.js +3 -3
  61. package/dist/runtime-command.d.ts +8 -0
  62. package/dist/runtime-command.js +38 -6
  63. package/dist/runtime-executor.d.ts +20 -1
  64. package/dist/runtime-executor.js +737 -172
  65. package/dist/runtime-profile.d.ts +32 -0
  66. package/dist/runtime-profile.js +89 -13
  67. package/dist/runtime-tool-specs.d.ts +39 -0
  68. package/dist/runtime-tool-specs.js +144 -28
  69. package/dist/safe-edit.d.ts +7 -0
  70. package/dist/safe-edit.js +163 -37
  71. package/dist/schemas.js +48 -1
  72. package/dist/server.js +51 -0
  73. package/dist/shared.d.ts +3 -2
  74. package/dist/shared.js +2 -0
  75. package/dist/status-events.js +9 -6
  76. package/dist/store/ace-packed-store.d.ts +3 -2
  77. package/dist/store/ace-packed-store.js +188 -110
  78. package/dist/store/bootstrap-store.d.ts +2 -1
  79. package/dist/store/bootstrap-store.js +102 -83
  80. package/dist/store/cache-workspace.js +11 -5
  81. package/dist/store/materializers/context-snapshot-materializer.js +6 -2
  82. package/dist/store/materializers/hook-context-materializer.d.ts +6 -9
  83. package/dist/store/materializers/hook-context-materializer.js +11 -21
  84. package/dist/store/materializers/host-file-materializer.js +6 -0
  85. package/dist/store/materializers/projection-manager.d.ts +0 -1
  86. package/dist/store/materializers/projection-manager.js +5 -13
  87. package/dist/store/materializers/scheduler-projection-materializer.js +1 -1
  88. package/dist/store/materializers/vericify-projector.d.ts +7 -7
  89. package/dist/store/materializers/vericify-projector.js +11 -11
  90. package/dist/store/repositories/local-model-runtime-repository.d.ts +120 -3
  91. package/dist/store/repositories/local-model-runtime-repository.js +242 -6
  92. package/dist/store/repositories/vericify-repository.d.ts +1 -1
  93. package/dist/store/skills-install.d.ts +4 -0
  94. package/dist/store/skills-install.js +21 -12
  95. package/dist/store/state-reader.d.ts +2 -0
  96. package/dist/store/state-reader.js +20 -0
  97. package/dist/store/store-artifacts.d.ts +7 -0
  98. package/dist/store/store-artifacts.js +27 -1
  99. package/dist/store/store-authority-audit.d.ts +18 -1
  100. package/dist/store/store-authority-audit.js +115 -5
  101. package/dist/store/store-snapshot.d.ts +3 -0
  102. package/dist/store/store-snapshot.js +22 -2
  103. package/dist/store/workspace-store-paths.d.ts +39 -0
  104. package/dist/store/workspace-store-paths.js +94 -0
  105. package/dist/store/write-coordinator.d.ts +65 -0
  106. package/dist/store/write-coordinator.js +386 -0
  107. package/dist/todo-state.js +5 -5
  108. package/dist/tools-agent.d.ts +20 -0
  109. package/dist/tools-agent.js +789 -25
  110. package/dist/tools-discovery.js +136 -1
  111. package/dist/tools-files.d.ts +7 -0
  112. package/dist/tools-files.js +1002 -11
  113. package/dist/tools-framework.js +105 -66
  114. package/dist/tools-handoff.js +2 -2
  115. package/dist/tools-lifecycle.js +4 -4
  116. package/dist/tools-memory.js +6 -6
  117. package/dist/tools-todo.js +2 -2
  118. package/dist/tracker-adapters.d.ts +1 -1
  119. package/dist/tracker-adapters.js +13 -18
  120. package/dist/tracker-sync.js +5 -3
  121. package/dist/tui/agent-runner.js +3 -1
  122. package/dist/tui/chat.js +103 -7
  123. package/dist/tui/dashboard.d.ts +1 -0
  124. package/dist/tui/dashboard.js +43 -0
  125. package/dist/tui/index.js +10 -1
  126. package/dist/tui/layout.d.ts +20 -0
  127. package/dist/tui/layout.js +31 -1
  128. package/dist/tui/local-model-contract.d.ts +6 -2
  129. package/dist/tui/local-model-contract.js +16 -3
  130. package/dist/tui/ollama.d.ts +8 -1
  131. package/dist/tui/ollama.js +53 -12
  132. package/dist/tui/openai-compatible.d.ts +13 -0
  133. package/dist/tui/openai-compatible.js +305 -5
  134. package/dist/tui/provider-discovery.d.ts +1 -0
  135. package/dist/tui/provider-discovery.js +35 -11
  136. package/dist/vericify-bridge.d.ts +6 -1
  137. package/dist/vericify-bridge.js +27 -3
  138. package/dist/workspace-manager.d.ts +30 -3
  139. package/dist/workspace-manager.js +257 -27
  140. package/package.json +1 -2
  141. package/dist/internal-tool-runtime.d.ts +0 -21
  142. package/dist/internal-tool-runtime.js +0 -136
  143. package/dist/store/workspace-snapshot.d.ts +0 -26
  144. package/dist/store/workspace-snapshot.js +0 -107
package/dist/safe-edit.js CHANGED
@@ -2,10 +2,11 @@
2
2
  * Safe-edit module: copy → modify → validate → swap pattern.
3
3
  * Prevents bricking by never leaving core files in a broken state.
4
4
  */
5
- import { copyFileSync, existsSync, mkdirSync, unlinkSync, writeFileSync, } from "node:fs";
5
+ import { copyFileSync, cpSync, existsSync, mkdtempSync, mkdirSync, readFileSync, renameSync, rmSync, symlinkSync, unlinkSync, writeFileSync, } from "node:fs";
6
6
  import { createHash } from "node:crypto";
7
- import { dirname, resolve } from "node:path";
7
+ import { basename, dirname, relative, resolve } from "node:path";
8
8
  import { spawnSync } from "node:child_process";
9
+ import { tmpdir } from "node:os";
9
10
  import { WORKSPACE_ROOT, safeRead, wsPath } from "./helpers.js";
10
11
  import { isInside, isReadError, normalizeRelPath } from "./shared.js";
11
12
  const STAGING_DIR = ".ace-staging";
@@ -19,14 +20,56 @@ function ensureDir(dirPath) {
19
20
  if (!existsSync(dirPath))
20
21
  mkdirSync(dirPath, { recursive: true });
21
22
  }
22
- function runValidation(validationCmd, testCmd) {
23
+ function resolveWorkspaceTarget(inputPath) {
24
+ const absPath = resolve(WORKSPACE_ROOT, inputPath);
25
+ if (!isInside(WORKSPACE_ROOT, absPath)) {
26
+ return { error: `Path escapes workspace root: ${inputPath}`, absPath };
27
+ }
28
+ return {
29
+ absPath,
30
+ relPath: normalizeRelPath(relative(WORKSPACE_ROOT, absPath)),
31
+ };
32
+ }
33
+ function shouldCopyIntoStaging(src) {
34
+ const rel = normalizeRelPath(relative(WORKSPACE_ROOT, src));
35
+ if (!rel || rel === ".")
36
+ return true;
37
+ const first = rel.split("/")[0];
38
+ return !new Set([".ace-staging", ".git", "node_modules", ".npm-cache"]).has(first);
39
+ }
40
+ function prepareStagedWorkspace(stagingDir) {
41
+ const stagedWorkspace = mkdtempSync(resolve(tmpdir(), "ace-staged-workspace-"));
42
+ rmSync(stagedWorkspace, { recursive: true, force: true });
43
+ mkdirSync(stagedWorkspace, { recursive: true });
44
+ cpSync(WORKSPACE_ROOT, stagedWorkspace, {
45
+ recursive: true,
46
+ dereference: false,
47
+ filter: (src) => shouldCopyIntoStaging(src),
48
+ });
49
+ const rootNodeModules = resolve(WORKSPACE_ROOT, "node_modules");
50
+ if (existsSync(rootNodeModules)) {
51
+ symlinkSync(rootNodeModules, resolve(stagedWorkspace, "node_modules"), "dir");
52
+ }
53
+ writeFileSync(resolve(stagingDir, "workspace-path.txt"), stagedWorkspace, "utf-8");
54
+ return stagedWorkspace;
55
+ }
56
+ function workspacePathIn(root, relPath) {
57
+ return resolve(root, relPath);
58
+ }
59
+ function swapTargetContent(absPath, content) {
60
+ ensureDir(dirname(absPath));
61
+ const swapPath = `${absPath}.ace-swap.${process.pid}.${Date.now()}`;
62
+ writeFileSync(swapPath, content, "utf-8");
63
+ renameSync(swapPath, absPath);
64
+ }
65
+ function runValidation(validationCmd, testCmd, cwd = WORKSPACE_ROOT) {
23
66
  let validation_passed;
24
67
  let validation_output;
25
68
  let test_passed;
26
69
  let test_output;
27
70
  if (validationCmd) {
28
71
  const res = spawnSync("sh", ["-c", validationCmd], {
29
- cwd: WORKSPACE_ROOT,
72
+ cwd,
30
73
  encoding: "utf-8",
31
74
  timeout: 60_000,
32
75
  maxBuffer: 4 * 1024 * 1024,
@@ -36,7 +79,7 @@ function runValidation(validationCmd, testCmd) {
36
79
  }
37
80
  if (testCmd && (validation_passed === undefined || validation_passed)) {
38
81
  const res = spawnSync("sh", ["-c", testCmd], {
39
- cwd: WORKSPACE_ROOT,
82
+ cwd,
40
83
  encoding: "utf-8",
41
84
  timeout: 120_000,
42
85
  maxBuffer: 4 * 1024 * 1024,
@@ -51,84 +94,80 @@ function runValidation(validationCmd, testCmd) {
51
94
  // Safe edit (copy → modify → validate → swap)
52
95
  // ────────────────────────────────────────────────────────────────────
53
96
  export function safeEditFile(input) {
54
- const absPath = resolve(WORKSPACE_ROOT, input.path);
55
- // ── Workspace boundary guard ──────────────────────────────────────
56
- if (!isInside(WORKSPACE_ROOT, absPath)) {
97
+ const target = resolveWorkspaceTarget(input.path);
98
+ if ("error" in target) {
57
99
  return {
58
100
  ok: false,
59
- original_path: absPath,
101
+ original_path: target.absPath,
60
102
  staging_path: "",
61
103
  original_hash: "none",
62
104
  new_hash: "none",
63
- error: `Path escapes workspace root: ${input.path}`,
105
+ error: target.error,
64
106
  restored: false,
65
107
  };
66
108
  }
67
- const relPath = normalizeRelPath(input.path);
109
+ const { absPath, relPath } = target;
68
110
  const timestamp = Date.now();
69
111
  const originalContent = safeRead(input.path);
70
112
  const isNew = isReadError(originalContent);
71
113
  const originalHash = isNew ? "none" : fileHash(originalContent);
72
- const newHash = fileHash(input.content);
114
+ const stagedNewHash = fileHash(input.content);
73
115
  // Step 1: Create staging directory
74
116
  const stagingDir = wsPath(STAGING_DIR, `${timestamp}-${isNew ? "new" : originalHash.slice(0, 8)}`);
75
117
  ensureDir(stagingDir);
76
118
  const flatName = relPath.replace(/\//g, "__");
77
119
  const stagingNew = resolve(stagingDir, `new__${flatName}`);
78
120
  writeFileSync(stagingNew, input.content, "utf-8");
121
+ const stagedWorkspace = prepareStagedWorkspace(stagingDir);
122
+ const stagedTarget = workspacePathIn(stagedWorkspace, relPath);
123
+ ensureDir(dirname(stagedTarget));
124
+ writeFileSync(stagedTarget, input.content, "utf-8");
79
125
  // Step 2: If file exists, copy original to staging + backup
80
126
  let backupPath;
81
127
  if (!isNew) {
82
128
  const stagingOriginal = resolve(stagingDir, `original__${flatName}`);
83
129
  writeFileSync(stagingOriginal, originalContent, "utf-8");
84
- if (input.backup !== false) {
85
- backupPath = `${absPath}.ace-backup.${originalHash.slice(0, 8)}`;
86
- copyFileSync(absPath, backupPath);
87
- }
88
130
  }
89
- // Step 3: Write new content
90
- ensureDir(dirname(absPath));
91
- writeFileSync(absPath, input.content, "utf-8");
92
- // Step 4: Run validation/tests
131
+ // Step 3: Run validation/tests against the staged workspace.
132
+ let check;
93
133
  if (input.validation_command || input.test_command) {
94
- const check = runValidation(input.validation_command, input.test_command);
134
+ check = runValidation(input.validation_command, input.test_command, stagedWorkspace);
95
135
  if (!check.passed) {
96
- // ROLLBACK: restore original content
97
- if (!isNew) {
98
- writeFileSync(absPath, originalContent, "utf-8");
99
- }
100
- else {
101
- // Remove newly created file
102
- try {
103
- unlinkSync(absPath);
104
- }
105
- catch {
106
- /* best effort */
107
- }
108
- }
109
136
  return {
110
137
  ok: false,
111
138
  original_path: absPath,
112
139
  staging_path: stagingDir,
113
140
  backup_path: backupPath,
114
141
  original_hash: originalHash,
115
- new_hash: newHash,
142
+ new_hash: stagedNewHash,
116
143
  validation_passed: check.validation_passed,
117
144
  validation_output: check.validation_output,
118
145
  test_passed: check.test_passed,
119
146
  test_output: check.test_output,
120
- error: "Validation/test failed — original restored",
147
+ error: "Validation/test failed — staged change not promoted",
121
148
  restored: true,
122
149
  };
123
150
  }
124
151
  }
152
+ // Step 4: Promote staged content to the real target only after checks pass.
153
+ if (!isNew && input.backup !== false) {
154
+ backupPath = `${absPath}.ace-backup.${originalHash.slice(0, 8)}`;
155
+ copyFileSync(absPath, backupPath);
156
+ }
157
+ const promotedContent = readFileSync(stagedTarget, "utf-8");
158
+ const promotedHash = fileHash(promotedContent);
159
+ swapTargetContent(absPath, promotedContent);
125
160
  return {
126
161
  ok: true,
127
162
  original_path: absPath,
128
163
  staging_path: stagingDir,
129
164
  backup_path: backupPath,
130
165
  original_hash: originalHash,
131
- new_hash: newHash,
166
+ new_hash: promotedHash,
167
+ validation_passed: check?.validation_passed,
168
+ validation_output: check?.validation_output,
169
+ test_passed: check?.test_passed,
170
+ test_output: check?.test_output,
132
171
  };
133
172
  }
134
173
  // ────────────────────────────────────────────────────────────────────
@@ -252,4 +291,91 @@ export function diffFiles(pathA, pathB) {
252
291
  }
253
292
  return diffContents(contentA, contentB);
254
293
  }
294
+ export function applyPatch(input) {
295
+ const target = resolveWorkspaceTarget(input.path);
296
+ if ("error" in target) {
297
+ return {
298
+ ok: false,
299
+ original_path: target.absPath,
300
+ staging_path: "",
301
+ original_hash: "none",
302
+ new_hash: "none",
303
+ error: target.error,
304
+ restored: false,
305
+ };
306
+ }
307
+ const { absPath, relPath } = target;
308
+ const originalContent = safeRead(input.path);
309
+ const isNew = isReadError(originalContent);
310
+ const originalHash = isNew ? "none" : fileHash(originalContent);
311
+ const timestamp = Date.now();
312
+ const stagingDir = wsPath(STAGING_DIR, `${timestamp}-patch-${isNew ? "new" : originalHash.slice(0, 8)}`);
313
+ ensureDir(stagingDir);
314
+ const stagedWorkspace = prepareStagedWorkspace(stagingDir);
315
+ const stagedTarget = workspacePathIn(stagedWorkspace, relPath);
316
+ ensureDir(dirname(stagedTarget));
317
+ if (isNew && !existsSync(stagedTarget))
318
+ writeFileSync(stagedTarget, "", "utf-8");
319
+ const tmpPatch = resolve(stagingDir, `${basename(relPath)}.${timestamp}.patch`);
320
+ try {
321
+ writeFileSync(tmpPatch, input.patch, "utf8");
322
+ const patchResult = spawnSync("patch", [stagedTarget, tmpPatch], {
323
+ encoding: "utf8",
324
+ cwd: stagedWorkspace,
325
+ });
326
+ if (patchResult.status !== 0) {
327
+ return {
328
+ ok: false,
329
+ original_path: absPath,
330
+ staging_path: stagingDir,
331
+ original_hash: originalHash,
332
+ new_hash: "none",
333
+ error: `patch command failed: ${patchResult.stderr || patchResult.stdout}`,
334
+ restored: true,
335
+ };
336
+ }
337
+ const patchedContent = readFileSync(stagedTarget, "utf-8");
338
+ const newHash = fileHash(patchedContent);
339
+ const check = runValidation(input.validation_command, input.test_command, stagedWorkspace);
340
+ if (!check.passed) {
341
+ return {
342
+ ok: false,
343
+ original_path: absPath,
344
+ staging_path: stagingDir,
345
+ original_hash: originalHash,
346
+ new_hash: newHash,
347
+ validation_passed: check.validation_passed,
348
+ validation_output: check.validation_output,
349
+ test_passed: check.test_passed,
350
+ test_output: check.test_output,
351
+ error: "Validation/test failed — staged patch not promoted",
352
+ restored: true,
353
+ };
354
+ }
355
+ let backupPath;
356
+ if (!isNew) {
357
+ backupPath = `${absPath}.ace-backup.${originalHash.slice(0, 8)}`;
358
+ copyFileSync(absPath, backupPath);
359
+ }
360
+ swapTargetContent(absPath, patchedContent);
361
+ return {
362
+ ok: true,
363
+ original_path: absPath,
364
+ staging_path: stagingDir,
365
+ backup_path: backupPath,
366
+ original_hash: originalHash,
367
+ new_hash: newHash,
368
+ validation_passed: check.validation_passed,
369
+ validation_output: check.validation_output,
370
+ test_passed: check.test_passed,
371
+ test_output: check.test_output,
372
+ };
373
+ }
374
+ finally {
375
+ try {
376
+ unlinkSync(tmpPatch);
377
+ }
378
+ catch { /* ignore */ }
379
+ }
380
+ }
255
381
  //# sourceMappingURL=safe-edit.js.map
package/dist/schemas.js CHANGED
@@ -186,6 +186,8 @@ const workspaceSessionRecordSchema = z
186
186
  last_error: z.string().optional(),
187
187
  created_at: z.string().datetime({ offset: true }),
188
188
  updated_at: z.string().datetime({ offset: true }),
189
+ hook_health: z.enum(["ok", "degraded", "failed"]).optional(),
190
+ hook_summary: z.string().optional(),
189
191
  hooks: z
190
192
  .object({
191
193
  after_create: workspaceHookStateSchema,
@@ -292,6 +294,32 @@ const runtimeToolExecutorSchema = z
292
294
  env: z.record(z.string(), z.string()).optional(),
293
295
  })
294
296
  .strict();
297
+ const runtimeToolMcpServerSchema = z
298
+ .object({
299
+ transport: z.enum(["stdio", "http"]),
300
+ command: z.string().optional(),
301
+ args: z.array(z.string()).optional(),
302
+ url: z.string().url().optional(),
303
+ env: z.record(z.string(), z.string()).optional(),
304
+ tool_allowlist: z.array(z.string()).optional(),
305
+ })
306
+ .strict()
307
+ .superRefine((value, ctx) => {
308
+ if (value.transport === "stdio" && !value.command?.trim()) {
309
+ ctx.addIssue({
310
+ code: z.ZodIssueCode.custom,
311
+ path: ["command"],
312
+ message: "stdio MCP servers require command",
313
+ });
314
+ }
315
+ if (value.transport === "http" && !value.url?.trim()) {
316
+ ctx.addIssue({
317
+ code: z.ZodIssueCode.custom,
318
+ path: ["url"],
319
+ message: "http MCP servers require url",
320
+ });
321
+ }
322
+ });
295
323
  const runtimeToolSpecSchema = z
296
324
  .object({
297
325
  name: NON_EMPTY,
@@ -300,6 +328,7 @@ const runtimeToolSpecSchema = z
300
328
  success_schema: runtimeToolSchemaNodeSchema.optional(),
301
329
  failure_schema: runtimeToolSchemaNodeSchema.optional(),
302
330
  executor: runtimeToolExecutorSchema,
331
+ mcp_server: runtimeToolMcpServerSchema.optional(),
303
332
  })
304
333
  .strict();
305
334
  const runtimeToolSpecRegistrySchema = z
@@ -352,6 +381,15 @@ const unattendedTurnRecordSchema = z
352
381
  stdout: z.string(),
353
382
  stderr: z.string(),
354
383
  tool_calls: z.array(unattendedToolCallRecordSchema),
384
+ turn_outcome: z.enum(["no_op_success", "meaningful_completion", "escalation_blocker"]).optional(),
385
+ outcome_reason: z.string().optional(),
386
+ })
387
+ .strict();
388
+ const runtimeOutputPolicySchema = z
389
+ .object({
390
+ emit_to: z.array(z.enum(["tui", "tracker", "handoff", "vericify"])),
391
+ silent_unless_blocked: z.boolean(),
392
+ require_approval_before_emit: z.boolean(),
355
393
  })
356
394
  .strict();
357
395
  const runtimeExecutorSessionRecordSchema = z
@@ -377,6 +415,8 @@ const runtimeExecutorSessionRecordSchema = z
377
415
  last_error: z.string().optional(),
378
416
  cleanup_error: z.string().optional(),
379
417
  workspace_cleanup_status: z.enum(["pending", "removed", "archived", "failed"]),
418
+ validated_plan_id: z.string().optional(),
419
+ output_policy: runtimeOutputPolicySchema.optional(),
380
420
  turns: z.array(unattendedTurnRecordSchema),
381
421
  })
382
422
  .strict();
@@ -394,7 +434,7 @@ const vericifyProcessPostSchema = z
394
434
  branch_id: z.string().optional(),
395
435
  lane_id: z.string().optional(),
396
436
  agent_id: NON_EMPTY,
397
- kind: z.enum(["intent", "progress", "blocker", "handoff_note", "stale_ack", "completion"]),
437
+ kind: z.enum(["intent", "progress", "blocker", "handoff_note", "stale_ack", "completion", "plan_proposal", "plan_quality_assessment"]),
398
438
  summary: NON_EMPTY,
399
439
  tool_refs: z.array(z.string()),
400
440
  evidence_refs: z.array(z.string()),
@@ -453,6 +493,13 @@ const vericifyBridgeSnapshotSchema = z
453
493
  })
454
494
  .strict(),
455
495
  active_run_refs: z.array(vericifyBridgeActiveRunRefSchema),
496
+ ace_runtime_enrichment: z
497
+ .object({
498
+ live_session_id: z.string().optional(),
499
+ last_turn_outcome: z.string().optional(),
500
+ last_turn_outcome_reason: z.string().optional(),
501
+ })
502
+ .optional(),
456
503
  })
457
504
  .strict();
458
505
  /**
package/dist/server.js CHANGED
@@ -1,7 +1,11 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
3
5
  import { buildServerInstructions, installAceToolGovernance, } from "./ace-server-instructions.js";
4
6
  import { resolveWorkspaceRoot } from "./helpers.js";
7
+ import { openStore } from "./store/ace-packed-store.js";
8
+ import { getWorkspaceStorePath } from "./store/store-snapshot.js";
5
9
  import { registerPrompts } from "./prompts.js";
6
10
  import { registerResources } from "./resources.js";
7
11
  import { registerTools } from "./tools.js";
@@ -24,7 +28,54 @@ export function createAceServer(options = {}) {
24
28
  registerTools(server);
25
29
  return server;
26
30
  }
31
+ function appendEmergencyMcpStatusEvent(workspaceRoot, message) {
32
+ const event = {
33
+ schema_version: "1.0.0",
34
+ event_id: `evt-${Date.now()}-${Math.random().toString(36).slice(2)}`,
35
+ trace_id: `trace-${Date.now()}`,
36
+ timestamp: new Date().toISOString(),
37
+ source_module: "capability-ops",
38
+ event_type: "MCP_BINARY_PARSE_ERROR",
39
+ status: "blocked",
40
+ objective_id: "mcp-stdio-startup",
41
+ payload: {
42
+ reason_code: "mcp_binary_parse_error",
43
+ summary: message,
44
+ },
45
+ };
46
+ const target = join(workspaceRoot, "agent-state", "STATUS_EVENTS.ndjson");
47
+ mkdirSync(dirname(target), { recursive: true });
48
+ writeFileSync(target, `${JSON.stringify(event)}\n`, { flag: "a" });
49
+ }
50
+ async function verifyMcpStoreStartup(workspaceRoot, logStartup) {
51
+ const canonicalStore = getWorkspaceStorePath(workspaceRoot);
52
+ const legacyStore = join(workspaceRoot, ".agents", "ACE", "ace-state.ace");
53
+ const candidates = [canonicalStore, legacyStore].filter((storePath, index, all) => existsSync(storePath) && all.indexOf(storePath) === index);
54
+ if (candidates.length === 0)
55
+ return true;
56
+ const errors = [];
57
+ for (const storePath of candidates) {
58
+ try {
59
+ const store = await openStore(storePath, { readOnly: true });
60
+ await store.close();
61
+ return true;
62
+ }
63
+ catch (error) {
64
+ errors.push(`${storePath}: ${error instanceof Error ? error.message : String(error)}`);
65
+ }
66
+ }
67
+ const message = `ACE MCP startup could not open ace-state.ace as ACEPACK; refusing stdio startup without crashing. ` +
68
+ `reason_code=mcp_binary_parse_error. ${errors.join(" | ")}`;
69
+ appendEmergencyMcpStatusEvent(workspaceRoot, message);
70
+ if (logStartup)
71
+ console.error(message);
72
+ return false;
73
+ }
27
74
  export async function startStdioServer(logStartup = true) {
75
+ const workspaceRoot = resolveWorkspaceRoot();
76
+ if (!(await verifyMcpStoreStartup(workspaceRoot, logStartup))) {
77
+ return;
78
+ }
28
79
  try {
29
80
  const backfill = await backfillHandoffsIntoScheduler();
30
81
  if (logStartup && backfill.scanned > 0) {
package/dist/shared.d.ts CHANGED
@@ -19,10 +19,10 @@ export declare function looksLikeSwarmHandoffPath(path: string): boolean;
19
19
  export declare const ROLE_TITLES: Record<string, string>;
20
20
  export declare function getRoleTitle(role: string): string;
21
21
  export declare const MCP_CLIENT_ENUM: z.ZodEnum<{
22
- claude: "claude";
23
- cursor: "cursor";
24
22
  codex: "codex";
25
23
  vscode: "vscode";
24
+ claude: "claude";
25
+ cursor: "cursor";
26
26
  antigravity: "antigravity";
27
27
  }>;
28
28
  export declare const ROLE_ENUM: z.ZodEnum<{
@@ -43,6 +43,7 @@ export declare const ROLE_ENUM: z.ZodEnum<{
43
43
  observability: "observability";
44
44
  eval: "eval";
45
45
  release: "release";
46
+ planner: "planner";
46
47
  }>;
47
48
  export declare const HANDOFF_VALIDATION_MODE: z.ZodOptional<z.ZodEnum<{
48
49
  "agent-state": "agent-state";
package/dist/shared.js CHANGED
@@ -57,6 +57,7 @@ export const ROLE_TITLES = {
57
57
  observability: "Observability",
58
58
  eval: "Eval",
59
59
  release: "Release",
60
+ planner: "Planner",
60
61
  };
61
62
  export function getRoleTitle(role) {
62
63
  return ROLE_TITLES[role] ?? role.toUpperCase();
@@ -89,6 +90,7 @@ export const ROLE_ENUM = z.enum([
89
90
  "observability",
90
91
  "eval",
91
92
  "release",
93
+ "planner",
92
94
  ]);
93
95
  export const HANDOFF_VALIDATION_MODE = z
94
96
  .enum(["auto", "swarm", "agent-state"])
@@ -8,7 +8,7 @@ import { ProjectionManager } from "./store/materializers/projection-manager.js";
8
8
  import { TrackerRepository } from "./store/repositories/tracker-repository.js";
9
9
  import { getWorkspaceStorePath, listStoreKeysSync, readStoreJsonSync, storeExistsSync, } from "./store/store-snapshot.js";
10
10
  import { operationalArtifactVirtualPath } from "./store/store-artifacts.js";
11
- import { withStoreWriteQueue } from "./store/write-queue.js";
11
+ import { withStoreWriteCoordinator } from "./store/write-coordinator.js";
12
12
  export const STATUS_EVENTS_REL_PATH = "agent-state/STATUS_EVENTS.ndjson";
13
13
  const STATUS_EVENTS_ARCHIVE_REL = "agent-state/STATUS_EVENTS-archive.ndjson";
14
14
  const MAX_EVENT_LINES = 2000;
@@ -94,7 +94,7 @@ async function mirrorStatusEventToStore(root, event) {
94
94
  const storePath = getWorkspaceStorePath(root);
95
95
  if (!existsSync(storePath))
96
96
  return;
97
- await withStoreWriteQueue(storePath, async () => {
97
+ await withStoreWriteCoordinator(storePath, async () => {
98
98
  const store = await openStore(storePath);
99
99
  try {
100
100
  const tracker = new TrackerRepository(store);
@@ -120,7 +120,7 @@ async function mirrorStatusEventToStore(root, event) {
120
120
  finally {
121
121
  await store.close();
122
122
  }
123
- });
123
+ }, { operation_label: "mirrorStatusEventToStore" });
124
124
  }
125
125
  function scheduleStatusEventMirror(event) {
126
126
  const root = workspaceRoot();
@@ -135,7 +135,7 @@ export async function waitForPendingStatusEventMirrors() {
135
135
  }
136
136
  async function appendStatusEventStoreBacked(root, event) {
137
137
  const storePath = getWorkspaceStorePath(root);
138
- return withStoreWriteQueue(storePath, async () => {
138
+ return withStoreWriteCoordinator(storePath, async () => {
139
139
  const store = await openStore(storePath);
140
140
  try {
141
141
  const tracker = new TrackerRepository(store);
@@ -165,9 +165,10 @@ async function appendStatusEventStoreBacked(root, event) {
165
165
  finally {
166
166
  await store.close();
167
167
  }
168
- });
168
+ }, { operation_label: "appendStatusEventStoreBacked" });
169
169
  }
170
170
  export function appendStatusEvent(input) {
171
+ const root = workspaceRoot();
171
172
  const event = buildStatusEvent(input);
172
173
  validateStatusEvent(event);
173
174
  // Atomic append under file lock to prevent lost writes under parallelism
@@ -176,7 +177,9 @@ export function appendStatusEvent(input) {
176
177
  const combined = existing.length > 0 ? `${existing}\n${line}\n` : `${line}\n`;
177
178
  const next = rotateIfNeeded(combined);
178
179
  const path = safeWriteWorkspaceFile(STATUS_EVENTS_REL_PATH, next);
179
- scheduleStatusEventMirror(event);
180
+ if (storeExistsSync(root)) {
181
+ scheduleStatusEventMirror(event);
182
+ }
180
183
  return { path, event };
181
184
  }
182
185
  /**
@@ -59,6 +59,9 @@ export declare class AcePackedStore implements IAcePackedStore {
59
59
  private fh;
60
60
  private kvIndex;
61
61
  private kvChunkEnd;
62
+ private pendingKv;
63
+ private pendingDeletes;
64
+ private dirty;
62
65
  private committed;
63
66
  private pending;
64
67
  private evtBaseId;
@@ -67,8 +70,6 @@ export declare class AcePackedStore implements IAcePackedStore {
67
70
  }): Promise<void>;
68
71
  private _initNew;
69
72
  private _loadExisting;
70
- /** Read a KV blob directly from a loaded file buffer (used during migration). */
71
- private _readKvBlobDirect;
72
73
  commit(): Promise<void>;
73
74
  /**
74
75
  * Compacts the KV chunk region — removes dead space left by overwritten keys.