@voybio/ace-swarm 2.4.8 → 2.4.10
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.
- package/CHANGELOG.md +52 -14
- package/README.md +14 -10
- package/assets/.agents/ACE/ACE_coders/AGENTS.md +23 -30
- package/assets/.agents/ACE/ACE_coders/INSTRUCTIONS.md +21 -30
- package/assets/.agents/skills/landing-review-watcher/SKILL.md +1 -1
- package/assets/.agents/skills/learn-from-work/SKILL.md +41 -0
- package/assets/agent-state/ACE_WORKFLOW.md +25 -2
- package/assets/agent-state/MODULES/schemas/ACE_RUNTIME_PROFILE.schema.json +143 -2
- package/assets/agent-state/MODULES/schemas/RUNTIME_EXECUTOR_SESSION_REGISTRY.schema.json +2 -2
- package/assets/agent-state/MODULES/schemas/SWARM_HANDOFF.schema.json +10 -0
- package/assets/eval-battery/battery.json +1 -1
- package/assets/instructions/ACE_Coder.instructions.md +9 -13
- package/assets/scripts/ace-hook-dispatch.mjs +16 -411
- package/assets/tasks/SWARM_HANDOFF.example_ui_to_coders.json +1 -2
- package/assets/vendor/README.md +9 -0
- package/assets/vendor/vericify-reader.mjs +272 -0
- package/assets/vendor/vericify-reader.provenance.json +10 -0
- package/dist/ace-autonomy.d.ts +58 -0
- package/dist/ace-autonomy.js +211 -6
- package/dist/ace-internal-tools.d.ts +1 -0
- package/dist/ace-internal-tools.js +3 -3
- package/dist/ace-server-instructions.d.ts +3 -3
- package/dist/ace-server-instructions.js +46 -192
- package/dist/cli.js +44 -6
- package/dist/experience-reflector.d.ts +7 -0
- package/dist/experience-reflector.js +39 -0
- package/dist/goal-engine.d.ts +64 -7
- package/dist/goal-engine.js +197 -41
- package/dist/handoff-registry.d.ts +10 -0
- package/dist/handoff-registry.js +59 -0
- package/dist/helpers/artifacts.d.ts +6 -2
- package/dist/helpers/artifacts.js +8 -6
- package/dist/helpers/bootstrap.js +13 -20
- package/dist/helpers/path-utils.js +2 -0
- package/dist/helpers/store-resolution.js +18 -3
- package/dist/helpers/workspace-root.d.ts +2 -0
- package/dist/helpers/workspace-root.js +9 -0
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.js +1 -0
- package/dist/hermes/bridge-protocol.d.ts +1 -1
- package/dist/hermes/session-manager.d.ts +17 -0
- package/dist/hermes/session-manager.js +67 -14
- package/dist/host-goal-engine.d.ts +138 -0
- package/dist/host-goal-engine.js +793 -0
- package/dist/host-goal-status.d.ts +113 -0
- package/dist/host-goal-status.js +175 -0
- package/dist/host-learning.d.ts +68 -0
- package/dist/host-learning.js +115 -0
- package/dist/host-observation.d.ts +12 -0
- package/dist/host-observation.js +91 -0
- package/dist/host-plan-revision.d.ts +14 -0
- package/dist/host-plan-revision.js +101 -0
- package/dist/host-verification-job.d.ts +12 -0
- package/dist/host-verification-job.js +183 -0
- package/dist/host-work-context.d.ts +12 -0
- package/dist/host-work-context.js +8 -0
- package/dist/job-scheduler.d.ts +58 -13
- package/dist/job-scheduler.js +298 -48
- package/dist/job-worker.d.ts +3 -1
- package/dist/job-worker.js +10 -3
- package/dist/kanban.d.ts +4 -1
- package/dist/kanban.js +44 -16
- package/dist/learned-artifacts.d.ts +64 -0
- package/dist/learned-artifacts.js +321 -0
- package/dist/learning-controls.d.ts +142 -0
- package/dist/learning-controls.js +135 -0
- package/dist/learning-input-context.d.ts +9 -0
- package/dist/learning-input-context.js +62 -0
- package/dist/learning-lifecycle.d.ts +10 -0
- package/dist/learning-lifecycle.js +11 -0
- package/dist/learning-overlays.d.ts +3 -0
- package/dist/learning-overlays.js +17 -0
- package/dist/learning-policy.d.ts +40 -0
- package/dist/learning-policy.js +38 -0
- package/dist/learning-records.d.ts +35 -0
- package/dist/learning-records.js +17 -0
- package/dist/learning-scorecard.d.ts +82 -0
- package/dist/learning-scorecard.js +86 -0
- package/dist/learning-serving.d.ts +29 -0
- package/dist/learning-serving.js +134 -0
- package/dist/linked-work.d.ts +9 -0
- package/dist/linked-work.js +28 -0
- package/dist/local-model-runtime.js +1 -1
- package/dist/mcp-command-progress.d.ts +16 -0
- package/dist/mcp-command-progress.js +70 -0
- package/dist/model-bridge.d.ts +14 -13
- package/dist/model-bridge.js +73 -41
- package/dist/orchestrator-supervisor.d.ts +111 -6
- package/dist/orchestrator-supervisor.js +67 -43
- package/dist/plan-proposal.js +3 -3
- package/dist/playbook-curator.d.ts +1 -0
- package/dist/playbook-curator.js +11 -9
- package/dist/process-identity.d.ts +8 -0
- package/dist/process-identity.js +38 -0
- package/dist/progress-command.d.ts +34 -0
- package/dist/progress-command.js +153 -0
- package/dist/prompts.js +15 -15
- package/dist/resources.js +2 -2
- package/dist/runtime-command.d.ts +8 -1
- package/dist/runtime-command.js +48 -7
- package/dist/runtime-executor.js +33 -11
- package/dist/runtime-profile-syntax.d.ts +6 -0
- package/dist/runtime-profile-syntax.js +121 -0
- package/dist/runtime-profile.d.ts +37 -5
- package/dist/runtime-profile.js +36 -129
- package/dist/runtime-tool-specs.js +1 -1
- package/dist/safe-edit.d.ts +7 -3
- package/dist/safe-edit.js +40 -47
- package/dist/schemas.js +4 -2
- package/dist/server.d.ts +2 -16
- package/dist/server.js +14 -20
- package/dist/shared.d.ts +2 -0
- package/dist/shared.js +2 -0
- package/dist/skill-auditor.d.ts +19 -0
- package/dist/skill-auditor.js +32 -2
- package/dist/skill-catalog.d.ts +4 -1
- package/dist/skill-catalog.js +6 -5
- package/dist/store/ace-packed-store.d.ts +5 -1
- package/dist/store/ace-packed-store.js +33 -1
- package/dist/store/bootstrap-store.js +19 -12
- package/dist/store/cache-workspace.d.ts +8 -0
- package/dist/store/cache-workspace.js +94 -27
- package/dist/store/importer.js +11 -20
- package/dist/store/knowledge-bake.d.ts +3 -1
- package/dist/store/knowledge-bake.js +10 -1
- package/dist/store/legacy-vericify-posts.d.ts +8 -0
- package/dist/store/legacy-vericify-posts.js +76 -0
- package/dist/store/materializers/hook-context-materializer.d.ts +2 -1
- package/dist/store/materializers/hook-context-materializer.js +6 -2
- package/dist/store/materializers/host-file-materializer.js +2 -2
- package/dist/store/materializers/projection-manager.d.ts +4 -1
- package/dist/store/materializers/projection-manager.js +10 -3
- package/dist/store/materializers/todo-syncer.d.ts +39 -20
- package/dist/store/materializers/todo-syncer.js +208 -110
- package/dist/store/materializers/vericify-projector.js +15 -26
- package/dist/store/repositories/goal-repository.d.ts +51 -2
- package/dist/store/repositories/goal-repository.js +114 -48
- package/dist/store/repositories/playbook-repository.d.ts +41 -3
- package/dist/store/repositories/playbook-repository.js +61 -5
- package/dist/store/repositories/todo-repository.d.ts +8 -2
- package/dist/store/repositories/todo-repository.js +1 -1
- package/dist/store/repositories/vericify-repository.d.ts +4 -0
- package/dist/store/repositories/vericify-repository.js +46 -0
- package/dist/store/skills-install.d.ts +1 -0
- package/dist/store/skills-install.js +20 -16
- package/dist/store/source-preservation.d.ts +24 -0
- package/dist/store/source-preservation.js +79 -0
- package/dist/store/store-artifacts.js +8 -1
- package/dist/store/test-write-boundary.d.ts +16 -0
- package/dist/store/test-write-boundary.js +175 -0
- package/dist/store/types.d.ts +5 -1
- package/dist/store/write-coordinator.js +16 -0
- package/dist/task-plan-context.d.ts +11 -0
- package/dist/task-plan-context.js +59 -0
- package/dist/todo-state.d.ts +19 -9
- package/dist/todo-state.js +204 -321
- package/dist/tools-agent.d.ts +1 -1
- package/dist/tools-agent.js +38 -62
- package/dist/tools-files.d.ts +0 -3
- package/dist/tools-files.js +21 -11
- package/dist/tools-framework.js +16 -25
- package/dist/tools-goal.d.ts +2 -4
- package/dist/tools-goal.js +119 -16
- package/dist/tools-handoff.d.ts +3 -2
- package/dist/tools-handoff.js +53 -23
- package/dist/tools-lifecycle.js +1 -1
- package/dist/tools-memory.d.ts +0 -3
- package/dist/tools-memory.js +51 -6
- package/dist/tools-scheduler.js +20 -17
- package/dist/tools-todo.js +160 -148
- package/dist/vericify-bridge.d.ts +8 -0
- package/dist/vericify-bridge.js +18 -0
- package/dist/vericify-context.d.ts +4 -0
- package/dist/vericify-context.js +26 -5
- package/dist/vericify-native.d.ts +101 -0
- package/dist/vericify-native.js +221 -0
- package/dist/verification-worker.d.ts +2 -0
- package/dist/verification-worker.js +31 -0
- package/docs/mcp-tool-reference.md +50 -10
- package/docs/troubleshooting.md +29 -0
- package/package.json +19 -6
- package/scripts/dev/run-tests-isolated.mjs +165 -0
- package/scripts/dev/run_hermes_crispr_live.mjs +1 -0
- package/scripts/dev/test-isolation-guard.mjs +20 -0
- package/scripts/dev/test-preload.mjs +153 -0
- package/scripts/dev/test-source-inventory.mjs +31 -0
- package/docs/development.md +0 -46
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertTestWriteAllowed } from "../store/test-write-boundary.js";
|
|
1
2
|
import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, } from "node:fs";
|
|
2
3
|
import { homedir } from "node:os";
|
|
3
4
|
import { basename, dirname, join, resolve } from "node:path";
|
|
@@ -9,6 +10,7 @@ import { resolveWorkspaceRoot } from "./workspace-root.js";
|
|
|
9
10
|
function ensureDir(dirPath, result) {
|
|
10
11
|
if (existsSync(dirPath))
|
|
11
12
|
return;
|
|
13
|
+
assertTestWriteAllowed(dirPath);
|
|
12
14
|
mkdirSync(dirPath, { recursive: true });
|
|
13
15
|
result.created.push(dirPath);
|
|
14
16
|
}
|
|
@@ -25,12 +27,14 @@ function copyTree(srcRoot, destRoot, result, force = false) {
|
|
|
25
27
|
continue;
|
|
26
28
|
}
|
|
27
29
|
if (!existsSync(dest)) {
|
|
30
|
+
assertTestWriteAllowed(dest);
|
|
28
31
|
mkdirSync(dirname(dest), { recursive: true });
|
|
29
32
|
copyFileSync(src, dest);
|
|
30
33
|
result.created.push(dest);
|
|
31
34
|
continue;
|
|
32
35
|
}
|
|
33
36
|
if (force) {
|
|
37
|
+
assertTestWriteAllowed(dest);
|
|
34
38
|
copyFileSync(src, dest);
|
|
35
39
|
result.updated.push(dest);
|
|
36
40
|
}
|
|
@@ -41,12 +45,14 @@ function copyTree(srcRoot, destRoot, result, force = false) {
|
|
|
41
45
|
}
|
|
42
46
|
function writeIfMissingOrForced(path, content, result, force = false) {
|
|
43
47
|
if (!existsSync(path)) {
|
|
48
|
+
assertTestWriteAllowed(path);
|
|
44
49
|
mkdirSync(dirname(path), { recursive: true });
|
|
45
50
|
writeFileSync(path, content, "utf-8");
|
|
46
51
|
result.created.push(path);
|
|
47
52
|
return;
|
|
48
53
|
}
|
|
49
54
|
if (force) {
|
|
55
|
+
assertTestWriteAllowed(path);
|
|
50
56
|
writeFileSync(path, content, "utf-8");
|
|
51
57
|
result.updated.push(path);
|
|
52
58
|
}
|
|
@@ -410,17 +416,6 @@ function buildWorkspaceStateSeedFiles(projectName, generatedAt) {
|
|
|
410
416
|
primary_cta: "",
|
|
411
417
|
}, null, 2),
|
|
412
418
|
},
|
|
413
|
-
{
|
|
414
|
-
path: wsPath("engineering-state", "BUILD_STATUS.md"),
|
|
415
|
-
content: [
|
|
416
|
-
"# BUILD_STATUS",
|
|
417
|
-
"",
|
|
418
|
-
"- Status: not started",
|
|
419
|
-
"- Active owner: ACE-Coders",
|
|
420
|
-
"- Blockers: none recorded",
|
|
421
|
-
`- Last update: ${generatedAt}`,
|
|
422
|
-
].join("\n"),
|
|
423
|
-
},
|
|
424
419
|
{
|
|
425
420
|
path: wsPath("engineering-state", "SPEC_CONTRACT.json"),
|
|
426
421
|
content: JSON.stringify({
|
|
@@ -447,20 +442,12 @@ function buildWorkspaceStateSeedFiles(projectName, generatedAt) {
|
|
|
447
442
|
"- TBD",
|
|
448
443
|
].join("\n"),
|
|
449
444
|
},
|
|
450
|
-
{
|
|
451
|
-
path: wsPath("engineering-state", "TEST_LOG.md"),
|
|
452
|
-
content: [
|
|
453
|
-
"# TEST_LOG",
|
|
454
|
-
"",
|
|
455
|
-
`- ${generatedAt} bootstrap: no tests executed yet.`,
|
|
456
|
-
].join("\n"),
|
|
457
|
-
},
|
|
458
445
|
{
|
|
459
446
|
path: wsPath("engineering-state", "src", "README.md"),
|
|
460
447
|
content: [
|
|
461
448
|
"# Engineering Source",
|
|
462
449
|
"",
|
|
463
|
-
|
|
450
|
+
"Place the main implementation here. Use the project’s existing tests and return their actual results with the work outcome.",
|
|
464
451
|
].join("\n"),
|
|
465
452
|
},
|
|
466
453
|
];
|
|
@@ -595,6 +582,12 @@ export function bootstrapAceWorkspace(options = {}) {
|
|
|
595
582
|
}
|
|
596
583
|
copyTree(DEFAULTS_GITHUB_ROOT, acePath(".github"), result, force);
|
|
597
584
|
copyTree(DEFAULTS_SCRIPTS_ROOT, acePath("scripts", "ace"), result, force);
|
|
585
|
+
const dispatcher = acePath("scripts", "ace", "ace-hook-dispatch.mjs");
|
|
586
|
+
if (result.created.includes(dispatcher) || result.updated.includes(dispatcher)) {
|
|
587
|
+
const moduleUrl = new URL("../ace-autonomy.js", import.meta.url).href;
|
|
588
|
+
assertTestWriteAllowed(dispatcher);
|
|
589
|
+
writeFileSync(dispatcher, readFileSync(dispatcher, "utf8").replace("__ACE_AUTONOMY_MODULE_URL__", moduleUrl));
|
|
590
|
+
}
|
|
598
591
|
const masterPlanPath = wsPath("global-state", "MASTER_PLAN.md");
|
|
599
592
|
writeIfMissingOrForced(masterPlanPath, [
|
|
600
593
|
`# ${projectName} — Master Plan`,
|
|
@@ -3,6 +3,7 @@ import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
|
3
3
|
import { isInside, normalizeRelPath } from "../shared.js";
|
|
4
4
|
import { ACE_MANAGED_PREFIXES, ACE_PROJECTED_WORKSPACE_FILES, ACE_ROOT_REL, SWARM_AGENTS, } from "./constants.js";
|
|
5
5
|
import { resolveWorkspaceRoot } from "./workspace-root.js";
|
|
6
|
+
import { assertTestWriteAllowed } from "../store/test-write-boundary.js";
|
|
6
7
|
export function currentWorkspaceRoot() {
|
|
7
8
|
return resolveWorkspaceRoot();
|
|
8
9
|
}
|
|
@@ -44,6 +45,7 @@ export function isSwarmRole(role) {
|
|
|
44
45
|
}
|
|
45
46
|
export function atomicWrite(filePath, content) {
|
|
46
47
|
const abs = isAbsolute(filePath) ? filePath : resolveWorkspaceWritePath(filePath);
|
|
48
|
+
assertTestWriteAllowed(abs);
|
|
47
49
|
mkdirSync(dirname(abs), { recursive: true });
|
|
48
50
|
const tmpPath = `${abs}.${process.pid}.tmp`;
|
|
49
51
|
writeFileSync(tmpPath, content, "utf-8");
|
|
@@ -5,6 +5,7 @@ import { isInside, normalizeRelPath } from "../shared.js";
|
|
|
5
5
|
import { getWorkspaceStorePath, listStoreKeysSync, parseVirtualStorePath, readStoreBlobSync, readVirtualStorePathSync, toVirtualStorePath, } from "../store/store-snapshot.js";
|
|
6
6
|
import { isOperationalArtifactPath, operationalArtifactKey, writeOperationalArtifactQueued, writeStoreBlobQueued, writeStoreBlobSync, } from "../store/store-artifacts.js";
|
|
7
7
|
import { withStoreWriteCoordinatorSync } from "../store/write-coordinator.js";
|
|
8
|
+
import { assertTestWriteAllowed, captureTestWriteBoundary, withTestWriteBoundary } from "../store/test-write-boundary.js";
|
|
8
9
|
import { ACE_ROOT_REL, ACE_SCRIPTS_ROOT_REL, ACE_SKILLS_ROOT_REL, ACE_TASKS_ROOT_REL, AGENT_FILES, AGENT_MANIFEST_FILES, DEFAULTS_ROOT, KERNEL_FILES, STORE_AGENT_FILES, STORE_KERNEL_FILES, STORE_TASK_FILES, TASK_FILES, } from "./constants.js";
|
|
9
10
|
import { currentWorkspaceRoot, isProjectedAceWorkspacePath, mapAceWorkspaceRelativePath, resolveWorkspaceReadPath, resolveWorkspaceWritePath, } from "./path-utils.js";
|
|
10
11
|
export function formatStorePath(key) {
|
|
@@ -24,9 +25,16 @@ export function listStoreSkillReferences() {
|
|
|
24
25
|
const root = currentWorkspaceRoot();
|
|
25
26
|
const names = new Set();
|
|
26
27
|
for (const key of listStoreKeysSync(root, "knowledge/skills/")) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
if (!key.endsWith('/SKILL.md'))
|
|
29
|
+
continue;
|
|
30
|
+
const name = key.slice('knowledge/skills/'.length, -'/SKILL.md'.length);
|
|
31
|
+
if (name.startsWith('learned/')) {
|
|
32
|
+
const text = readStoreBlobSync(root, key) ?? '';
|
|
33
|
+
if (!/^status: active$/m.test(text))
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (name)
|
|
37
|
+
names.add(name);
|
|
30
38
|
}
|
|
31
39
|
return [...names]
|
|
32
40
|
.sort((a, b) => a.localeCompare(b))
|
|
@@ -249,6 +257,7 @@ export function safeWrite(filePath, content) {
|
|
|
249
257
|
const abs = isAbsolute(filePath) && isInside(root, filePath)
|
|
250
258
|
? filePath
|
|
251
259
|
: resolveWorkspaceWritePath(filePath, root);
|
|
260
|
+
assertTestWriteAllowed(abs);
|
|
252
261
|
mkdirSync(dirname(abs), { recursive: true });
|
|
253
262
|
const tmpPath = `${abs}.${process.pid}.${Date.now()}.tmp`;
|
|
254
263
|
writeFileSync(tmpPath, content, "utf-8");
|
|
@@ -277,15 +286,21 @@ export async function safeWriteAsync(filePath, content) {
|
|
|
277
286
|
const abs = isAbsolute(filePath) && isInside(root, filePath)
|
|
278
287
|
? filePath
|
|
279
288
|
: resolveWorkspaceWritePath(filePath, root);
|
|
289
|
+
const assertBoundary = captureTestWriteBoundary(abs);
|
|
280
290
|
await mkdir(dirname(abs), { recursive: true });
|
|
281
291
|
const tmpPath = `${abs}.${process.pid}.${Date.now()}.tmp`;
|
|
292
|
+
assertBoundary();
|
|
282
293
|
await writeFile(tmpPath, content, "utf-8");
|
|
294
|
+
assertBoundary();
|
|
283
295
|
await rename(tmpPath, abs);
|
|
284
296
|
return abs;
|
|
285
297
|
}
|
|
286
298
|
const _fileLocks = new Map();
|
|
287
299
|
export async function withFileLock(path, fn) {
|
|
288
300
|
const key = resolveWorkspaceWritePath(path);
|
|
301
|
+
return withTestWriteBoundary(key, () => withFileLockInternal(key, fn));
|
|
302
|
+
}
|
|
303
|
+
async function withFileLockInternal(key, fn) {
|
|
289
304
|
const prev = _fileLocks.get(key) ?? Promise.resolve();
|
|
290
305
|
let releaseLock;
|
|
291
306
|
const next = new Promise((r) => { releaseLock = r; });
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Bind an operation and its asynchronous descendants without changing process-wide environment. */
|
|
2
|
+
export declare function withWorkspaceRoot<T>(root: string, fn: () => T): T;
|
|
1
3
|
export declare function resolveWorkspaceRoot(): string;
|
|
2
4
|
export declare const WORKSPACE_ROOT: string;
|
|
3
5
|
//# sourceMappingURL=workspace-root.d.ts.map
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
+
const workspaceScope = new AsyncLocalStorage();
|
|
5
|
+
/** Bind an operation and its asynchronous descendants without changing process-wide environment. */
|
|
6
|
+
export function withWorkspaceRoot(root, fn) {
|
|
7
|
+
return workspaceScope.run(normalizeWorkspaceRootLikePath(root), fn);
|
|
8
|
+
}
|
|
3
9
|
function normalizeWorkspaceRootCandidate(candidate) {
|
|
4
10
|
const trimmed = candidate?.trim();
|
|
5
11
|
if (!trimmed)
|
|
@@ -51,6 +57,9 @@ function pinWorkspaceRoot(root) {
|
|
|
51
57
|
return normalized;
|
|
52
58
|
}
|
|
53
59
|
export function resolveWorkspaceRoot() {
|
|
60
|
+
const scoped = workspaceScope.getStore();
|
|
61
|
+
if (scoped)
|
|
62
|
+
return scoped;
|
|
54
63
|
const explicit = normalizeWorkspaceRootCandidate(process.env.ACE_WORKSPACE_ROOT);
|
|
55
64
|
if (explicit)
|
|
56
65
|
return pinWorkspaceRoot(findNearestInitiatedWorkspaceRoot(explicit) ?? explicit);
|
package/dist/helpers.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { resolveWorkspaceRoot } from "./helpers/workspace-root.js";
|
|
|
2
2
|
export { isInside, isReadError, normalizeRelPath, looksLikeSwarmHandoffPath } from "./shared.js";
|
|
3
3
|
export * from "./helpers/constants.js";
|
|
4
4
|
export { resolveWorkspaceRoot };
|
|
5
|
+
export { withWorkspaceRoot } from "./helpers/workspace-root.js";
|
|
5
6
|
export declare const WORKSPACE_ROOT: string;
|
|
6
7
|
export * from "./helpers/path-utils.js";
|
|
7
8
|
export * from "./helpers/store-resolution.js";
|
package/dist/helpers.js
CHANGED
|
@@ -2,6 +2,7 @@ import { resolveWorkspaceRoot } from "./helpers/workspace-root.js";
|
|
|
2
2
|
export { isInside, isReadError, normalizeRelPath, looksLikeSwarmHandoffPath } from "./shared.js";
|
|
3
3
|
export * from "./helpers/constants.js";
|
|
4
4
|
export { resolveWorkspaceRoot };
|
|
5
|
+
export { withWorkspaceRoot } from "./helpers/workspace-root.js";
|
|
5
6
|
export const WORKSPACE_ROOT = resolveWorkspaceRoot();
|
|
6
7
|
export * from "./helpers/path-utils.js";
|
|
7
8
|
export * from "./helpers/store-resolution.js";
|
|
@@ -4,7 +4,6 @@ declare const bridgeEventSchema: z.ZodObject<{
|
|
|
4
4
|
type: z.ZodEnum<{
|
|
5
5
|
error: "error";
|
|
6
6
|
status: "status";
|
|
7
|
-
tool_start: "tool_start";
|
|
8
7
|
session_open: "session_open";
|
|
9
8
|
turn_run: "turn_run";
|
|
10
9
|
interrupt: "interrupt";
|
|
@@ -12,6 +11,7 @@ declare const bridgeEventSchema: z.ZodObject<{
|
|
|
12
11
|
delta: "delta";
|
|
13
12
|
reasoning: "reasoning";
|
|
14
13
|
assistant_interim: "assistant_interim";
|
|
14
|
+
tool_start: "tool_start";
|
|
15
15
|
tool_progress: "tool_progress";
|
|
16
16
|
tool_complete: "tool_complete";
|
|
17
17
|
final: "final";
|
|
@@ -12,7 +12,14 @@ export interface HermesLocalTurnOptions {
|
|
|
12
12
|
maxTurns: number;
|
|
13
13
|
/** Probed context window for the model; falls back to a conservative default. */
|
|
14
14
|
contextLength?: number;
|
|
15
|
+
/** Explicit total deadline only; omitted or 0 means unlimited. */
|
|
15
16
|
timeoutMs?: number;
|
|
17
|
+
stallTimeoutMs?: number;
|
|
18
|
+
stallWarningMs?: number;
|
|
19
|
+
onStall?: (event: {
|
|
20
|
+
silence_ms: number;
|
|
21
|
+
last_progress_at: number;
|
|
22
|
+
}) => void;
|
|
16
23
|
}
|
|
17
24
|
export interface HermesLocalTurnResult {
|
|
18
25
|
result: BridgeResult;
|
|
@@ -38,14 +45,24 @@ export interface HermesSubprocessExecutorOptions {
|
|
|
38
45
|
command?: readonly string[];
|
|
39
46
|
launchProfile?: HermesLaunchProfile;
|
|
40
47
|
keepTemp?: boolean;
|
|
48
|
+
/** Explicit total deadline only; omitted or 0 means unlimited. */
|
|
41
49
|
timeoutMs?: number;
|
|
50
|
+
stallTimeoutMs?: number;
|
|
51
|
+
stallWarningMs?: number;
|
|
52
|
+
onStall?: (event: {
|
|
53
|
+
silence_ms: number;
|
|
54
|
+
last_progress_at: number;
|
|
55
|
+
}) => void;
|
|
42
56
|
maxOutputBytes?: number;
|
|
43
57
|
}
|
|
44
58
|
export declare class HermesSubprocessExecutor implements HermesLocalExecutor {
|
|
45
59
|
private options;
|
|
46
60
|
private readonly activeChildren;
|
|
61
|
+
private readonly interruptedChildren;
|
|
62
|
+
private readonly killTimers;
|
|
47
63
|
constructor(options?: HermesSubprocessExecutorOptions);
|
|
48
64
|
interrupt(): void;
|
|
65
|
+
private signalChildGroup;
|
|
49
66
|
private interruptChild;
|
|
50
67
|
runTurn(options: HermesLocalTurnOptions): Promise<HermesLocalTurnResult>;
|
|
51
68
|
}
|
|
@@ -66,6 +66,8 @@ function hermesBaseUrl(provider, baseUrl) {
|
|
|
66
66
|
export class HermesSubprocessExecutor {
|
|
67
67
|
options;
|
|
68
68
|
activeChildren = new Set();
|
|
69
|
+
interruptedChildren = new WeakSet();
|
|
70
|
+
killTimers = new WeakMap();
|
|
69
71
|
constructor(options = {}) {
|
|
70
72
|
this.options = options;
|
|
71
73
|
}
|
|
@@ -73,18 +75,39 @@ export class HermesSubprocessExecutor {
|
|
|
73
75
|
for (const child of this.activeChildren)
|
|
74
76
|
this.interruptChild(child);
|
|
75
77
|
}
|
|
78
|
+
signalChildGroup(child, signal) {
|
|
79
|
+
if (!child.pid)
|
|
80
|
+
return;
|
|
81
|
+
try {
|
|
82
|
+
if (process.platform === "win32")
|
|
83
|
+
child.kill(signal);
|
|
84
|
+
else
|
|
85
|
+
process.kill(-child.pid, signal);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code !== "ESRCH")
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
76
92
|
interruptChild(child) {
|
|
77
|
-
if (child
|
|
93
|
+
if (this.interruptedChildren.has(child))
|
|
78
94
|
return;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
child.kill("SIGKILL");
|
|
83
|
-
}
|
|
84
|
-
}, 1_000);
|
|
95
|
+
this.interruptedChildren.add(child);
|
|
96
|
+
this.signalChildGroup(child, "SIGTERM");
|
|
97
|
+
const killTimer = setTimeout(() => this.signalChildGroup(child, "SIGKILL"), 1_000);
|
|
85
98
|
killTimer.unref();
|
|
99
|
+
this.killTimers.set(child, killTimer);
|
|
86
100
|
}
|
|
87
101
|
async runTurn(options) {
|
|
102
|
+
const timeoutMs = options.timeoutMs ?? this.options.timeoutMs;
|
|
103
|
+
const stallTimeoutMs = options.stallTimeoutMs ?? this.options.stallTimeoutMs ?? 60 * 60_000;
|
|
104
|
+
const stallWarningMs = options.stallWarningMs ?? this.options.stallWarningMs ?? Math.min(10 * 60_000, stallTimeoutMs);
|
|
105
|
+
for (const [name, value] of Object.entries({ timeoutMs, stallTimeoutMs, stallWarningMs })) {
|
|
106
|
+
if (value !== undefined && (!Number.isFinite(value) || value < 0))
|
|
107
|
+
throw new Error(`${name} must be finite and nonnegative; 0 disables the limit.`);
|
|
108
|
+
}
|
|
109
|
+
if (stallTimeoutMs > 0 && stallWarningMs > stallTimeoutMs)
|
|
110
|
+
throw new Error("The stall warning must not follow the final silence limit.");
|
|
88
111
|
const sessionId = `hermes-${randomUUID()}`;
|
|
89
112
|
const shadowId = `shadow-${randomUUID()}`;
|
|
90
113
|
const hermesHome = mkdtempSync(resolve(tmpdir(), "ace-hermes-home-"));
|
|
@@ -147,6 +170,7 @@ export class HermesSubprocessExecutor {
|
|
|
147
170
|
ACE_WORKSPACE_ROOT: options.runtime.workspaceRoot,
|
|
148
171
|
},
|
|
149
172
|
stdio: ["pipe", "pipe", "pipe"],
|
|
173
|
+
detached: process.platform !== "win32",
|
|
150
174
|
});
|
|
151
175
|
this.activeChildren.add(child);
|
|
152
176
|
const decoder = new HermesBridgeFrameDecoder();
|
|
@@ -159,6 +183,8 @@ export class HermesSubprocessExecutor {
|
|
|
159
183
|
let finalCompleted;
|
|
160
184
|
let finalCount = 0;
|
|
161
185
|
let outputBytes = 0;
|
|
186
|
+
let lastProgressAt = Date.now();
|
|
187
|
+
let warned = false;
|
|
162
188
|
let outputOverflow = false;
|
|
163
189
|
const maxOutputBytes = this.options.maxOutputBytes ?? 4 * 1024 * 1024;
|
|
164
190
|
// Single per-frame consumer so the live stream and the post-close tail-flush
|
|
@@ -183,6 +209,8 @@ export class HermesSubprocessExecutor {
|
|
|
183
209
|
}
|
|
184
210
|
};
|
|
185
211
|
child.stdout.on("data", (chunk) => {
|
|
212
|
+
lastProgressAt = Date.now();
|
|
213
|
+
warned = false;
|
|
186
214
|
outputBytes += chunk.byteLength;
|
|
187
215
|
if (outputBytes > maxOutputBytes) {
|
|
188
216
|
outputOverflow = true;
|
|
@@ -194,6 +222,8 @@ export class HermesSubprocessExecutor {
|
|
|
194
222
|
}
|
|
195
223
|
});
|
|
196
224
|
child.stderr.on("data", (chunk) => {
|
|
225
|
+
lastProgressAt = Date.now();
|
|
226
|
+
warned = false;
|
|
197
227
|
outputBytes += chunk.byteLength;
|
|
198
228
|
if (outputBytes > maxOutputBytes) {
|
|
199
229
|
outputOverflow = true;
|
|
@@ -215,18 +245,41 @@ export class HermesSubprocessExecutor {
|
|
|
215
245
|
system_prompt: "You are running inside ACE Hermes-local mode. Use only the imported ACE MCP toolset for tool calls. Do not use plain text as executable authority.",
|
|
216
246
|
};
|
|
217
247
|
child.stdin.end(`${JSON.stringify(request)}\n`);
|
|
218
|
-
|
|
248
|
+
let stalled = false;
|
|
249
|
+
const silenceTimer = stallTimeoutMs > 0 ? setInterval(() => {
|
|
250
|
+
const silence = Date.now() - lastProgressAt;
|
|
251
|
+
if (!warned && stallWarningMs > 0 && silence >= stallWarningMs) {
|
|
252
|
+
warned = true;
|
|
253
|
+
try {
|
|
254
|
+
(options.onStall ?? this.options.onStall)?.({ silence_ms: silence, last_progress_at: lastProgressAt });
|
|
255
|
+
}
|
|
256
|
+
catch { /* Warning callback cannot terminate useful work. */ }
|
|
257
|
+
}
|
|
258
|
+
if (silence >= stallTimeoutMs) {
|
|
259
|
+
stalled = true;
|
|
260
|
+
this.interruptChild(child);
|
|
261
|
+
}
|
|
262
|
+
}, Math.max(10, Math.min(1000, stallWarningMs || stallTimeoutMs, stallTimeoutMs))) : undefined;
|
|
263
|
+
silenceTimer?.unref();
|
|
219
264
|
let timedOut = false;
|
|
220
|
-
const timeout = setTimeout(() => {
|
|
265
|
+
const timeout = timeoutMs && timeoutMs > 0 ? setTimeout(() => {
|
|
221
266
|
timedOut = true;
|
|
222
267
|
this.interruptChild(child);
|
|
223
|
-
}, timeoutMs);
|
|
224
|
-
timeout
|
|
268
|
+
}, timeoutMs) : undefined;
|
|
269
|
+
timeout?.unref();
|
|
225
270
|
const exitCode = await new Promise((resolvePromise, reject) => {
|
|
226
271
|
child.on("error", reject);
|
|
227
272
|
child.on("close", resolvePromise);
|
|
228
273
|
}).finally(() => {
|
|
229
|
-
|
|
274
|
+
if (timeout)
|
|
275
|
+
clearTimeout(timeout);
|
|
276
|
+
if (silenceTimer)
|
|
277
|
+
clearInterval(silenceTimer);
|
|
278
|
+
if (this.interruptedChildren.has(child))
|
|
279
|
+
this.signalChildGroup(child, "SIGKILL");
|
|
280
|
+
const killTimer = this.killTimers.get(child);
|
|
281
|
+
if (killTimer)
|
|
282
|
+
clearTimeout(killTimer);
|
|
230
283
|
this.activeChildren.delete(child);
|
|
231
284
|
});
|
|
232
285
|
for (const frame of decoder.push(new Uint8Array(), true)) {
|
|
@@ -252,14 +305,14 @@ export class HermesSubprocessExecutor {
|
|
|
252
305
|
(event.turn_id !== undefined && event.turn_id !== request.turn_id));
|
|
253
306
|
const eventAfterFinal = finalIndex >= 0 && events.slice(finalIndex + 1).some((event) => event.type !== "session_close");
|
|
254
307
|
const protocolInvalid = protocolIdentityInvalid || eventAfterFinal;
|
|
255
|
-
const status = sawError || malformed.length > 0 || exitCode !== 0 || timedOut || outputOverflow || finalCount !== 1 || protocolInvalid
|
|
308
|
+
const status = sawError || malformed.length > 0 || exitCode !== 0 || timedOut || stalled || outputOverflow || finalCount !== 1 || protocolInvalid
|
|
256
309
|
? "failed"
|
|
257
310
|
: finalCompleted === false
|
|
258
311
|
? "blocked"
|
|
259
312
|
: "completed";
|
|
260
313
|
const summary = status === "failed"
|
|
261
314
|
? sawError ||
|
|
262
|
-
`Hermes bridge failed${timedOut ? "; reason_code=hermes_timeout" : ""}${outputOverflow ? "; reason_code=hermes_output_limit" : ""}${finalCount !== 1 ? `; terminal_frames=${finalCount}` : ""}${protocolIdentityInvalid ? "; reason_code=hermes_frame_identity" : ""}${eventAfterFinal ? "; reason_code=hermes_frame_after_final" : ""}${malformed.length ? `; malformed_frames=${malformed.join(",")}` : ""}${stderr.length ? `; stderr=${stderr.join("").slice(0, 500)}` : ""}`
|
|
315
|
+
`Hermes bridge failed${timedOut ? "; reason_code=hermes_timeout" : ""}${stalled ? "; reason_code=hermes_stalled" : ""}${outputOverflow ? "; reason_code=hermes_output_limit" : ""}${finalCount !== 1 ? `; terminal_frames=${finalCount}` : ""}${protocolIdentityInvalid ? "; reason_code=hermes_frame_identity" : ""}${eventAfterFinal ? "; reason_code=hermes_frame_after_final" : ""}${malformed.length ? `; malformed_frames=${malformed.join(",")}` : ""}${stderr.length ? `; stderr=${stderr.join("").slice(0, 500)}` : ""}`
|
|
263
316
|
: status === "blocked"
|
|
264
317
|
? finalText || "Hermes reported completed=false."
|
|
265
318
|
: finalText || "Hermes-local turn completed.";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { type GoalRecord } from './store/repositories/goal-repository.js';
|
|
2
|
+
import { type GoalEngineDeps, type StartGoalOptions, type ResumeGoalOptions } from './goal-engine.js';
|
|
3
|
+
import { type TaskPlan, type TaskStep } from './orchestrator-supervisor.js';
|
|
4
|
+
import { type CurrentWorkItem } from './ace-autonomy.js';
|
|
5
|
+
import type { HostWorkBinding } from './host-work-context.js';
|
|
6
|
+
import { type LearnedPayload, type LearningAcceptance } from './learned-artifacts.js';
|
|
7
|
+
import { type HostRequirementUpdate } from './host-plan-revision.js';
|
|
8
|
+
export interface StepOutcome {
|
|
9
|
+
status: 'done' | 'blocked' | 'failed';
|
|
10
|
+
summary: string;
|
|
11
|
+
evidence?: Array<{
|
|
12
|
+
ref: string;
|
|
13
|
+
kind: 'command' | 'artifact' | 'diff' | 'note';
|
|
14
|
+
detail?: string;
|
|
15
|
+
}>;
|
|
16
|
+
artifacts?: string[];
|
|
17
|
+
follow_ups?: Array<{
|
|
18
|
+
task: string;
|
|
19
|
+
role?: string;
|
|
20
|
+
depends_on?: string[];
|
|
21
|
+
}>;
|
|
22
|
+
waiting_on?: string;
|
|
23
|
+
requirement_updates?: HostRequirementUpdate[];
|
|
24
|
+
learned?: LearnedPayload;
|
|
25
|
+
feedback?: Array<{
|
|
26
|
+
id: string;
|
|
27
|
+
helpful: boolean;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export interface Assignment {
|
|
31
|
+
goal_id: string;
|
|
32
|
+
step_id: string;
|
|
33
|
+
attempt: number;
|
|
34
|
+
assignee: string;
|
|
35
|
+
task_text: string;
|
|
36
|
+
role: string;
|
|
37
|
+
expected_artifacts: string[];
|
|
38
|
+
required_evidence_refs: string[];
|
|
39
|
+
verify_at_goal_end: string[];
|
|
40
|
+
open_blockers: CurrentWorkItem[];
|
|
41
|
+
now: string;
|
|
42
|
+
observation: string;
|
|
43
|
+
started_at?: string;
|
|
44
|
+
learning?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface HostStepResult {
|
|
47
|
+
ok: boolean;
|
|
48
|
+
isError?: boolean;
|
|
49
|
+
reason_code?: string;
|
|
50
|
+
message?: string;
|
|
51
|
+
now: string;
|
|
52
|
+
options?: Array<{
|
|
53
|
+
tool: string;
|
|
54
|
+
args: Record<string, unknown>;
|
|
55
|
+
why: string;
|
|
56
|
+
}>;
|
|
57
|
+
waiting_on?: string[];
|
|
58
|
+
candidates?: unknown[];
|
|
59
|
+
assignment?: Assignment;
|
|
60
|
+
next_ready?: string[];
|
|
61
|
+
goal_id?: string;
|
|
62
|
+
step_id?: string;
|
|
63
|
+
status?: string;
|
|
64
|
+
summary?: string;
|
|
65
|
+
goal_status?: GoalRecord['status'];
|
|
66
|
+
verification?: 'pending';
|
|
67
|
+
view_repair_pending?: string[];
|
|
68
|
+
skipped_follow_ups?: string[];
|
|
69
|
+
learning?: LearningAcceptance;
|
|
70
|
+
reopened?: string[];
|
|
71
|
+
requirement_updates_pending?: HostRequirementUpdate[];
|
|
72
|
+
}
|
|
73
|
+
export declare function hostRefusal(root: string, reason: string, message: string, goalId?: string): HostStepResult;
|
|
74
|
+
export declare function startHostGoal(objective: string, options: StartGoalOptions, deps?: GoalEngineDeps): Promise<{
|
|
75
|
+
ok: boolean;
|
|
76
|
+
goal: GoalRecord;
|
|
77
|
+
assignment: Assignment | undefined;
|
|
78
|
+
now: string;
|
|
79
|
+
view_repair_pending: string[];
|
|
80
|
+
isError?: boolean;
|
|
81
|
+
reason_code?: string;
|
|
82
|
+
message?: string;
|
|
83
|
+
options?: Array<{
|
|
84
|
+
tool: string;
|
|
85
|
+
args: Record<string, unknown>;
|
|
86
|
+
why: string;
|
|
87
|
+
}>;
|
|
88
|
+
waiting_on?: string[];
|
|
89
|
+
candidates?: unknown[];
|
|
90
|
+
next_ready?: string[];
|
|
91
|
+
goal_id?: string;
|
|
92
|
+
step_id?: string;
|
|
93
|
+
status?: string;
|
|
94
|
+
summary?: string;
|
|
95
|
+
goal_status?: GoalRecord["status"];
|
|
96
|
+
verification?: "pending";
|
|
97
|
+
skipped_follow_ups?: string[];
|
|
98
|
+
learning?: LearningAcceptance;
|
|
99
|
+
reopened?: string[];
|
|
100
|
+
requirement_updates_pending?: HostRequirementUpdate[];
|
|
101
|
+
}>;
|
|
102
|
+
export declare function beginStep(goalId: string, options: {
|
|
103
|
+
step_id?: string;
|
|
104
|
+
agent: string;
|
|
105
|
+
session_id?: string;
|
|
106
|
+
}, deps?: GoalEngineDeps): Promise<HostStepResult>;
|
|
107
|
+
export declare function applyHostResultToStep(step: TaskStep, outcome: StepOutcome): void;
|
|
108
|
+
/** The caller holds the existing per-goal coordinator; never changes receipts. */
|
|
109
|
+
export declare function recoverHostBudgetsLocked(goal: GoalRecord, plan: TaskPlan, options: ResumeGoalOptions, now: number): TaskPlan;
|
|
110
|
+
export declare function completeStep(goalId: string, stepId: string, outcome: StepOutcome, options: {
|
|
111
|
+
agent: string;
|
|
112
|
+
attempt: number;
|
|
113
|
+
continue?: boolean;
|
|
114
|
+
}, deps?: GoalEngineDeps): Promise<HostStepResult>;
|
|
115
|
+
export declare function verificationSignature(plan: TaskPlan): string;
|
|
116
|
+
export declare function finishHostVerification(goalId: string, snapshot: {
|
|
117
|
+
goal: GoalRecord;
|
|
118
|
+
planDigest: string;
|
|
119
|
+
}, deps: GoalEngineDeps): Promise<void>;
|
|
120
|
+
/** Explicit restart recovery reruns only the declared checks, never host work. */
|
|
121
|
+
export declare function retryHostVerification(goalId: string, deps?: GoalEngineDeps): Promise<{
|
|
122
|
+
goal: GoalRecord;
|
|
123
|
+
plan: TaskPlan | undefined;
|
|
124
|
+
}>;
|
|
125
|
+
/** Attach only ACE's own result to the exact attempt active when its tool ran. */
|
|
126
|
+
export declare function recordHostContact(binding?: HostWorkBinding): Promise<void>;
|
|
127
|
+
export declare function recordHostToolEvidence(tool: string, result: unknown, binding?: HostWorkBinding): Promise<void>;
|
|
128
|
+
/** Goal -> packed view is the sole lock order. No store callback acquires a goal lease. */
|
|
129
|
+
export declare function withLinkedHandoff<T>(ref: {
|
|
130
|
+
goal_id: string;
|
|
131
|
+
step_id: string;
|
|
132
|
+
}, input: {
|
|
133
|
+
id: string;
|
|
134
|
+
status: string;
|
|
135
|
+
actor: string;
|
|
136
|
+
to: string;
|
|
137
|
+
}, writeView: () => Promise<T>): Promise<T>;
|
|
138
|
+
//# sourceMappingURL=host-goal-engine.d.ts.map
|