@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
package/dist/model-bridge.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash, randomUUID } from "node:crypto";
|
|
|
2
2
|
import { appendFileSync, existsSync, mkdirSync, writeFileSync, realpathSync } from "node:fs";
|
|
3
3
|
import { dirname, isAbsolute, resolve, sep } from "node:path";
|
|
4
4
|
import { executeAceInternalTool, listAceInternalToolCatalog, } from "./ace-internal-tools.js";
|
|
5
|
-
import {
|
|
5
|
+
import { appendAutomaticVericifyProcessPostSafe, deriveWorkspaceVericifyRunRef, } from "./vericify-bridge.js";
|
|
6
6
|
import { buildToolPlan, renderAceContext } from "./ace-context.js";
|
|
7
7
|
import { appendRunLedgerEntrySafe } from "./run-ledger.js";
|
|
8
8
|
import { appendStatusEventSafe } from "./status-events.js";
|
|
@@ -479,7 +479,7 @@ function isRetryableProviderError(error) {
|
|
|
479
479
|
function formatToolFeedback(results) {
|
|
480
480
|
return [
|
|
481
481
|
"Tool execution results:",
|
|
482
|
-
...results.map((result) => `- ${result.tool}: ${result.ok ? "ok" : "error"} — ${result.summary}`),
|
|
482
|
+
...results.map((result) => `- ${result.tool}: ${result.reason_code === "still_running" ? "still_running" : result.ok ? "ok" : "error"} — ${result.summary}`),
|
|
483
483
|
"Continue with another JSON response.",
|
|
484
484
|
].join("\n");
|
|
485
485
|
}
|
|
@@ -527,31 +527,67 @@ function withUsageTotals(result, usageTotals) {
|
|
|
527
527
|
function contextOverflowSuspected(usage, numCtx) {
|
|
528
528
|
return Boolean(usage && usage.prompt_tokens >= Math.floor(numCtx * 0.98));
|
|
529
529
|
}
|
|
530
|
-
const DEFAULT_TOOL_DEADLINE_MS = 120_000;
|
|
531
530
|
function toolDeadlineMs() {
|
|
532
531
|
const raw = Number(process.env.ACE_TOOL_DEADLINE_MS);
|
|
533
|
-
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) :
|
|
532
|
+
return Number.isFinite(raw) && raw > 0 ? Math.floor(raw) : undefined;
|
|
534
533
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
534
|
+
const pendingToolOperations = new Map();
|
|
535
|
+
function canonicalToolInput(value) {
|
|
536
|
+
if (Array.isArray(value))
|
|
537
|
+
return value.map(canonicalToolInput);
|
|
538
|
+
if (value && typeof value === "object")
|
|
539
|
+
return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, entry]) => [key, canonicalToolInput(entry)]));
|
|
540
|
+
return value;
|
|
541
|
+
}
|
|
542
|
+
/** No implicit cutoff. An explicit deadline requests cancellation; unconfirmed
|
|
543
|
+
* cancellation is reported as still running. Identical retries collect the same
|
|
544
|
+
* operation instead of launching a duplicate side effect. */
|
|
541
545
|
export async function executeToolWithDeadline(tool, args, sessionId, opts, deadlineMs, exec = executeAceInternalTool) {
|
|
546
|
+
const key = JSON.stringify([sessionId, opts.workspace_path, tool, canonicalToolInput(args)]);
|
|
547
|
+
let operation = pendingToolOperations.get(key);
|
|
548
|
+
const collecting = Boolean(operation);
|
|
549
|
+
if (!operation) {
|
|
550
|
+
const controller = new AbortController();
|
|
551
|
+
const forwardAbort = () => controller.abort(opts.signal?.reason);
|
|
552
|
+
if (opts.signal?.aborted)
|
|
553
|
+
forwardAbort();
|
|
554
|
+
else
|
|
555
|
+
opts.signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
556
|
+
const created = { id: randomUUID(), controller, state: "running", promise: Promise.resolve() };
|
|
557
|
+
created.promise = Promise.resolve().then(() => exec(tool, args, sessionId, { ...opts, signal: controller.signal })).then((value) => { created.state = "done"; return value; }, (error) => { created.state = "failed"; throw error; }).finally(() => opts.signal?.removeEventListener("abort", forwardAbort));
|
|
558
|
+
// Keep eventual failures observed while an explicit caller has stopped waiting.
|
|
559
|
+
void created.promise.catch(() => undefined);
|
|
560
|
+
operation = created;
|
|
561
|
+
pendingToolOperations.set(key, operation);
|
|
562
|
+
}
|
|
542
563
|
let timer;
|
|
543
|
-
const
|
|
544
|
-
timer = setTimeout(() => resolve({ rawToolResult: undefined, timedOut: true }), deadlineMs);
|
|
545
|
-
timer.unref?.();
|
|
546
|
-
});
|
|
564
|
+
const pending = Symbol("still-running");
|
|
547
565
|
try {
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
566
|
+
const value = deadlineMs === undefined || deadlineMs <= 0
|
|
567
|
+
? await operation.promise
|
|
568
|
+
: await Promise.race([
|
|
569
|
+
operation.promise,
|
|
570
|
+
new Promise((resolve) => { timer = setTimeout(() => resolve(pending), deadlineMs); timer.unref?.(); }),
|
|
571
|
+
]);
|
|
572
|
+
if (value === pending) {
|
|
573
|
+
operation.controller.abort(new Error(`Explicit tool deadline elapsed after ${deadlineMs}ms`));
|
|
574
|
+
return {
|
|
551
575
|
timedOut: false,
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
576
|
+
stillRunning: true,
|
|
577
|
+
operationId: operation.id,
|
|
578
|
+
rawToolResult: {
|
|
579
|
+
isError: false,
|
|
580
|
+
structuredContent: { status: "still_running", operation_id: operation.id, cancellation_requested: true },
|
|
581
|
+
content: [{ type: "text", text: `Operation ${operation.id} is still running after its explicit deadline; cancellation was requested but is not yet confirmed. Repeat this same tool call to collect its result without starting duplicate work.` }],
|
|
582
|
+
},
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
pendingToolOperations.delete(key);
|
|
586
|
+
return { rawToolResult: value, timedOut: false, operationId: collecting ? operation.id : undefined };
|
|
587
|
+
}
|
|
588
|
+
catch (error) {
|
|
589
|
+
pendingToolOperations.delete(key);
|
|
590
|
+
throw error;
|
|
555
591
|
}
|
|
556
592
|
finally {
|
|
557
593
|
if (timer)
|
|
@@ -727,7 +763,7 @@ export class ModelBridge {
|
|
|
727
763
|
session_id: this.bridgeId,
|
|
728
764
|
role: options.role,
|
|
729
765
|
});
|
|
730
|
-
await
|
|
766
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
731
767
|
run_id: refs.run_id,
|
|
732
768
|
branch_id: refs.branch_id,
|
|
733
769
|
lane_id: refs.lane_id,
|
|
@@ -871,7 +907,7 @@ export class ModelBridge {
|
|
|
871
907
|
// intra-turn runaway is bounded separately by the num_predict output cap.
|
|
872
908
|
const textLoopCounts = new Map();
|
|
873
909
|
try {
|
|
874
|
-
await
|
|
910
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
875
911
|
run_id: refs.run_id,
|
|
876
912
|
branch_id: refs.branch_id,
|
|
877
913
|
lane_id: refs.lane_id,
|
|
@@ -881,7 +917,7 @@ export class ModelBridge {
|
|
|
881
917
|
tool_refs: aceContext.tools.map((tool) => tool.name),
|
|
882
918
|
});
|
|
883
919
|
noteProgress("process_post", { kind: "intent" });
|
|
884
|
-
for (let turn = 1; turn <= options.maxTurns; turn += 1) {
|
|
920
|
+
for (let turn = 1; options.maxTurns === 0 || turn <= options.maxTurns; turn += 1) {
|
|
885
921
|
const compressed = compressConversationHistory(messages, numCtx);
|
|
886
922
|
if (compressed.compressed) {
|
|
887
923
|
messages.splice(0, messages.length, ...compressed.messages);
|
|
@@ -936,7 +972,7 @@ export class ModelBridge {
|
|
|
936
972
|
}
|
|
937
973
|
if (textLoopCount >= 4) {
|
|
938
974
|
const summary = "Bridge blocked after repeating an identical response four times without progress.";
|
|
939
|
-
await
|
|
975
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
940
976
|
run_id: refs.run_id,
|
|
941
977
|
branch_id: refs.branch_id,
|
|
942
978
|
lane_id: refs.lane_id,
|
|
@@ -1020,7 +1056,7 @@ export class ModelBridge {
|
|
|
1020
1056
|
const summary = rawResponse.trim() || "Bridge completed.";
|
|
1021
1057
|
options.onOutput?.(summary);
|
|
1022
1058
|
noteProgress("output", { status: "complete", fallback: "plain_text" });
|
|
1023
|
-
await
|
|
1059
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
1024
1060
|
run_id: refs.run_id,
|
|
1025
1061
|
branch_id: refs.branch_id,
|
|
1026
1062
|
lane_id: refs.lane_id,
|
|
@@ -1077,7 +1113,7 @@ export class ModelBridge {
|
|
|
1077
1113
|
status: "parse_error",
|
|
1078
1114
|
role_contract_violation: isContractViolation,
|
|
1079
1115
|
});
|
|
1080
|
-
await
|
|
1116
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
1081
1117
|
run_id: refs.run_id,
|
|
1082
1118
|
branch_id: refs.branch_id,
|
|
1083
1119
|
lane_id: refs.lane_id,
|
|
@@ -1146,14 +1182,8 @@ export class ModelBridge {
|
|
|
1146
1182
|
noteProgress("tool_start", { tool: toolCall.tool });
|
|
1147
1183
|
const deadlineMs = toolDeadlineMs();
|
|
1148
1184
|
const outcome = await executeToolWithDeadline(toolCall.tool, args, sessionId, { workspace_path: options.workspace }, deadlineMs);
|
|
1149
|
-
const result = outcome.
|
|
1150
|
-
? {
|
|
1151
|
-
tool: toolCall.tool,
|
|
1152
|
-
ok: false,
|
|
1153
|
-
isError: true,
|
|
1154
|
-
summary: `tool_timeout: ${toolCall.tool} exceeded ${deadlineMs}ms deadline`,
|
|
1155
|
-
reason_code: "tool_timeout",
|
|
1156
|
-
}
|
|
1185
|
+
const result = outcome.stillRunning
|
|
1186
|
+
? { tool: toolCall.tool, ok: false, isError: false, summary: summarizeToolText(outcome.rawToolResult), reason_code: "still_running" }
|
|
1157
1187
|
: truncateToolResult({
|
|
1158
1188
|
tool: toolCall.tool,
|
|
1159
1189
|
ok: !Boolean(outcome.rawToolResult?.isError),
|
|
@@ -1161,7 +1191,7 @@ export class ModelBridge {
|
|
|
1161
1191
|
summary: summarizeToolText(outcome.rawToolResult),
|
|
1162
1192
|
}, options.workspace);
|
|
1163
1193
|
options.onToolResult?.(toolCall.tool, result);
|
|
1164
|
-
noteProgress("tool_finish", { tool: toolCall.tool, ok: result.ok });
|
|
1194
|
+
noteProgress(result.reason_code === "still_running" ? "thinking" : "tool_finish", { tool: toolCall.tool, ok: result.ok });
|
|
1165
1195
|
toolResults.push(result);
|
|
1166
1196
|
if (result.ok) {
|
|
1167
1197
|
const pathArg = typeof args.path === "string"
|
|
@@ -1187,6 +1217,8 @@ export class ModelBridge {
|
|
|
1187
1217
|
toolCalls: executed,
|
|
1188
1218
|
});
|
|
1189
1219
|
for (const { toolCall, result } of executedPairs) {
|
|
1220
|
+
if (result.reason_code === "still_running")
|
|
1221
|
+
continue;
|
|
1190
1222
|
const loopKey = toolDoomLoopKey(toolCall, result);
|
|
1191
1223
|
const count = (toolDoomLoopCounts.get(loopKey) ?? 0) + 1;
|
|
1192
1224
|
toolDoomLoopCounts.set(loopKey, count);
|
|
@@ -1205,7 +1237,7 @@ export class ModelBridge {
|
|
|
1205
1237
|
}
|
|
1206
1238
|
if (count >= 4) {
|
|
1207
1239
|
const summary = `Bridge blocked after repeated identical tool result for ${toolCall.tool}.`;
|
|
1208
|
-
await
|
|
1240
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
1209
1241
|
run_id: refs.run_id,
|
|
1210
1242
|
branch_id: refs.branch_id,
|
|
1211
1243
|
lane_id: refs.lane_id,
|
|
@@ -1251,7 +1283,7 @@ export class ModelBridge {
|
|
|
1251
1283
|
const message = readEnvelopeText(envelope.message) || rawResponse.trim();
|
|
1252
1284
|
options.onOutput?.(message);
|
|
1253
1285
|
noteProgress("output", { status: "message" });
|
|
1254
|
-
await
|
|
1286
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
1255
1287
|
run_id: refs.run_id,
|
|
1256
1288
|
branch_id: refs.branch_id,
|
|
1257
1289
|
lane_id: refs.lane_id,
|
|
@@ -1293,7 +1325,7 @@ export class ModelBridge {
|
|
|
1293
1325
|
const message = readEnvelopeText(envelope.message) || "Additional operator input required.";
|
|
1294
1326
|
options.onOutput?.(message);
|
|
1295
1327
|
noteProgress("output", { status: "need_input" });
|
|
1296
|
-
await
|
|
1328
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
1297
1329
|
run_id: refs.run_id,
|
|
1298
1330
|
branch_id: refs.branch_id,
|
|
1299
1331
|
lane_id: refs.lane_id,
|
|
@@ -1348,7 +1380,7 @@ export class ModelBridge {
|
|
|
1348
1380
|
const driftSummary = `[output_drift_violation] ${role}: ${driftViolation}`;
|
|
1349
1381
|
options.onOutput?.(driftSummary);
|
|
1350
1382
|
noteProgress("output", { status: "output_drift_violation" });
|
|
1351
|
-
await
|
|
1383
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
1352
1384
|
run_id: refs.run_id,
|
|
1353
1385
|
branch_id: refs.branch_id,
|
|
1354
1386
|
lane_id: refs.lane_id,
|
|
@@ -1372,7 +1404,7 @@ export class ModelBridge {
|
|
|
1372
1404
|
// Clean output — accept the completion.
|
|
1373
1405
|
options.onOutput?.(summary);
|
|
1374
1406
|
noteProgress("output", { status: "complete" });
|
|
1375
|
-
await
|
|
1407
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
1376
1408
|
run_id: refs.run_id,
|
|
1377
1409
|
branch_id: refs.branch_id,
|
|
1378
1410
|
lane_id: refs.lane_id,
|
|
@@ -1402,7 +1434,7 @@ export class ModelBridge {
|
|
|
1402
1434
|
}
|
|
1403
1435
|
}
|
|
1404
1436
|
const summary = "Bridge stopped after reaching max turns.";
|
|
1405
|
-
await
|
|
1437
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
1406
1438
|
run_id: refs.run_id,
|
|
1407
1439
|
branch_id: refs.branch_id,
|
|
1408
1440
|
lane_id: refs.lane_id,
|
|
@@ -1,7 +1,48 @@
|
|
|
1
|
+
export { getReadyTaskSteps, collectUpstreamOutputs } from "./task-plan-context.js";
|
|
2
|
+
import { type DispatchJobsResult } from "./job-scheduler.js";
|
|
1
3
|
import type { BridgeResult } from "./model-bridge.js";
|
|
2
4
|
import type { LocalModelRuntimeRepository } from "./store/repositories/local-model-runtime-repository.js";
|
|
3
5
|
export type TaskStepStatus = "planned" | "running" | "done" | "failed" | "skipped" | "blocked";
|
|
4
6
|
export type TaskPlanStatus = "planning" | "executing" | "reviewing" | "blocked" | "done" | "failed";
|
|
7
|
+
export interface ObservedRun {
|
|
8
|
+
record_id: string;
|
|
9
|
+
attribution: "Linked" | "Inferred" | "Ambiguous" | "Unknown";
|
|
10
|
+
command: string;
|
|
11
|
+
cwd?: string;
|
|
12
|
+
exit_code: number | null;
|
|
13
|
+
outcome: "ok" | "failed" | "unknown";
|
|
14
|
+
at: string;
|
|
15
|
+
output_tail?: string;
|
|
16
|
+
command_norm: string;
|
|
17
|
+
paths?: string[];
|
|
18
|
+
tool_use_id?: string;
|
|
19
|
+
session_id?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface StepAttempt {
|
|
22
|
+
attempt: number;
|
|
23
|
+
status: "done" | "blocked" | "failed";
|
|
24
|
+
at: string;
|
|
25
|
+
summary: string;
|
|
26
|
+
checks?: Array<{
|
|
27
|
+
command: string;
|
|
28
|
+
cwd: string;
|
|
29
|
+
ok: boolean;
|
|
30
|
+
}>;
|
|
31
|
+
failure_signature?: string;
|
|
32
|
+
failure_excerpt?: string;
|
|
33
|
+
scope_snapshot?: {
|
|
34
|
+
role: string;
|
|
35
|
+
paths: string[];
|
|
36
|
+
task_tags: string[];
|
|
37
|
+
};
|
|
38
|
+
served_context?: {
|
|
39
|
+
items: Array<Pick<import('./learning-serving.js').ServedLearningItem, 'id' | 'kind' | 'scope'>>;
|
|
40
|
+
rendered_bytes: number;
|
|
41
|
+
};
|
|
42
|
+
evidence_refs: string[];
|
|
43
|
+
served?: string[];
|
|
44
|
+
observed_runs?: ObservedRun[];
|
|
45
|
+
}
|
|
5
46
|
export interface TaskStep {
|
|
6
47
|
step_id: string;
|
|
7
48
|
role: string;
|
|
@@ -24,6 +65,8 @@ export interface TaskStep {
|
|
|
24
65
|
expected_artifacts?: Array<{
|
|
25
66
|
path: string;
|
|
26
67
|
required?: boolean;
|
|
68
|
+
/** Required when this step completes, but not a final deliverable. */
|
|
69
|
+
transient?: boolean;
|
|
27
70
|
evidence_ref_kind?: "artifact" | "diff" | "hash" | "test" | "gate";
|
|
28
71
|
}>;
|
|
29
72
|
allowed_tools?: string[];
|
|
@@ -34,6 +77,72 @@ export interface TaskStep {
|
|
|
34
77
|
reason: string;
|
|
35
78
|
evidence_ref: string;
|
|
36
79
|
};
|
|
80
|
+
assignee?: string;
|
|
81
|
+
attempt?: number;
|
|
82
|
+
started_at?: string;
|
|
83
|
+
last_ace_call_at?: string;
|
|
84
|
+
waiting_on?: string;
|
|
85
|
+
result_digest?: string;
|
|
86
|
+
result_response?: unknown;
|
|
87
|
+
attempts_log?: StepAttempt[];
|
|
88
|
+
served_learning?: import('./learning-serving.js').ServedLearning;
|
|
89
|
+
learning_feedback?: Array<{
|
|
90
|
+
id: string;
|
|
91
|
+
helpful: boolean;
|
|
92
|
+
}>;
|
|
93
|
+
loaded_learning?: Array<{
|
|
94
|
+
id: string;
|
|
95
|
+
at: string;
|
|
96
|
+
}>;
|
|
97
|
+
learning_kind?: "meta" | "graduation";
|
|
98
|
+
learning_source?: string;
|
|
99
|
+
learning_trigger?: string;
|
|
100
|
+
learning_inputs?: import('./learning-input-context.js').LearningInputRefs;
|
|
101
|
+
learning_scope?: string;
|
|
102
|
+
learning_opened_at?: string;
|
|
103
|
+
learning_payload?: import('./learned-artifacts.js').LearnedPayload;
|
|
104
|
+
learning_result?: import('./learned-artifacts.js').LearningAcceptance;
|
|
105
|
+
attempt_history?: Array<Pick<TaskStep, 'attempt' | 'assignee' | 'status' | 'result_summary' | 'evidence' | 'artifacts' | 'result_digest' | 'result_response'>>;
|
|
106
|
+
evidence?: Array<{
|
|
107
|
+
ref: string;
|
|
108
|
+
kind: "command" | "artifact" | "diff" | "note";
|
|
109
|
+
provenance: "host" | "ace";
|
|
110
|
+
detail?: string;
|
|
111
|
+
ok?: boolean;
|
|
112
|
+
}>;
|
|
113
|
+
artifacts?: string[];
|
|
114
|
+
todo_id?: string;
|
|
115
|
+
required_observation?: "action" | "command_pass";
|
|
116
|
+
observation?: "available" | "pending" | "unavailable";
|
|
117
|
+
observation_window?: {
|
|
118
|
+
workspace_id: string;
|
|
119
|
+
session_id?: string;
|
|
120
|
+
started_at: string;
|
|
121
|
+
ended_at?: string;
|
|
122
|
+
};
|
|
123
|
+
observation_refs?: Array<{
|
|
124
|
+
id: string;
|
|
125
|
+
attribution: "Linked" | "Inferred" | "Ambiguous" | "Unknown";
|
|
126
|
+
kind: string;
|
|
127
|
+
result?: string;
|
|
128
|
+
run?: ObservedRun;
|
|
129
|
+
}>;
|
|
130
|
+
/** Additive acceptance metadata; saved result_response and original window remain immutable. */
|
|
131
|
+
observation_check?: {
|
|
132
|
+
attempt: number;
|
|
133
|
+
status: "pending" | "passed" | "unmet" | "unsupported";
|
|
134
|
+
deadline_at: string;
|
|
135
|
+
wait_ms: number;
|
|
136
|
+
poll_ms: number;
|
|
137
|
+
reason_code?: string;
|
|
138
|
+
};
|
|
139
|
+
observation_query?: Record<string, unknown>;
|
|
140
|
+
observation_coverage?: Record<string, unknown>;
|
|
141
|
+
verification_failure?: {
|
|
142
|
+
command: string;
|
|
143
|
+
output: string;
|
|
144
|
+
ref: string;
|
|
145
|
+
};
|
|
37
146
|
}
|
|
38
147
|
export interface TaskPlan {
|
|
39
148
|
plan_id: string;
|
|
@@ -137,20 +246,16 @@ export declare function createTaskPlan(input: {
|
|
|
137
246
|
execution_mode?: TaskPlan["execution_mode"];
|
|
138
247
|
vcx_cursor?: string;
|
|
139
248
|
}): TaskPlan;
|
|
140
|
-
export declare function getReadyTaskSteps(plan: TaskPlan): TaskStep[];
|
|
141
249
|
export declare function markTaskStepStatus(plan: TaskPlan, stepId: string, status: TaskStepStatus, patch?: Partial<Omit<TaskStep, "step_id" | "status">>): TaskPlan;
|
|
142
250
|
export declare function applyBridgeResultToStep(plan: TaskPlan, stepId: string, result: BridgeResult): TaskPlan;
|
|
143
251
|
export declare function amendTaskPlan(plan: TaskPlan, amendment: TaskPlanAmendment): TaskPlan;
|
|
144
|
-
export declare function collectUpstreamOutputs(plan: TaskPlan, step: TaskStep): {
|
|
145
|
-
step_id: string;
|
|
146
|
-
result_summary: string;
|
|
147
|
-
evidence_refs: string[];
|
|
148
|
-
}[];
|
|
149
252
|
export declare function applyBridgeResultToStepWithTransition(plan: TaskPlan, stepId: string, result: BridgeResult, repo?: LocalModelRuntimeRepository): Promise<TaskPlan>;
|
|
150
253
|
export declare function amendTaskPlanWithTransition(plan: TaskPlan, amendment: TaskPlanAmendment, repo?: LocalModelRuntimeRepository, reason?: string, reason_code?: string): Promise<TaskPlan>;
|
|
151
254
|
export declare function promoteParallelGroupToScheduler(plan: TaskPlan, parallelGroup: string, owner?: string): Promise<{
|
|
152
255
|
plan: TaskPlan;
|
|
153
256
|
job_ids: string[];
|
|
257
|
+
dispatch?: DispatchJobsResult;
|
|
258
|
+
blocked_reason?: string;
|
|
154
259
|
}>;
|
|
155
260
|
export declare function superviseTaskPlan(inputPlan: TaskPlan, hooks: SupervisorHooks): Promise<SupervisorRunResult>;
|
|
156
261
|
//# sourceMappingURL=orchestrator-supervisor.d.ts.map
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { getReadyTaskSteps, collectUpstreamOutputs } from "./task-plan-context.js";
|
|
2
|
+
export { getReadyTaskSteps, collectUpstreamOutputs } from "./task-plan-context.js";
|
|
1
3
|
import { existsSync } from "node:fs";
|
|
2
4
|
import { dirname } from "node:path";
|
|
3
5
|
import { randomUUID } from "node:crypto";
|
|
4
6
|
import { dispatchJobs, enqueueJob, getJobQueuePath } from "./job-scheduler.js";
|
|
5
|
-
import {
|
|
7
|
+
import { appendAutomaticVericifyProcessPostSafe, deriveWorkspaceVericifyRunRef, } from "./vericify-bridge.js";
|
|
6
8
|
function parseNumericStepId(stepId) {
|
|
7
9
|
const numeric = Number(stepId.replace(/^step-/, ""));
|
|
8
10
|
return Number.isFinite(numeric) && numeric > 0 ? numeric : 0;
|
|
@@ -90,17 +92,6 @@ export function createTaskPlan(input) {
|
|
|
90
92
|
vcx_cursor: input.vcx_cursor,
|
|
91
93
|
});
|
|
92
94
|
}
|
|
93
|
-
export function getReadyTaskSteps(plan) {
|
|
94
|
-
const completed = new Set(plan.steps
|
|
95
|
-
.filter((step) => step.status === "done" || step.status === "skipped")
|
|
96
|
-
.map((step) => step.step_id));
|
|
97
|
-
return plan.steps.filter((step) => {
|
|
98
|
-
if (step.status !== "planned")
|
|
99
|
-
return false;
|
|
100
|
-
const dependencies = step.depends_on ?? [];
|
|
101
|
-
return dependencies.every((dependency) => completed.has(dependency));
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
95
|
export function markTaskStepStatus(plan, stepId, status, patch = {}) {
|
|
105
96
|
return withDerivedStatus({
|
|
106
97
|
...plan,
|
|
@@ -212,25 +203,6 @@ export function amendTaskPlan(plan, amendment) {
|
|
|
212
203
|
vcx_cursor: amendment.vcx_cursor ?? plan.vcx_cursor,
|
|
213
204
|
});
|
|
214
205
|
}
|
|
215
|
-
export function collectUpstreamOutputs(plan, step) {
|
|
216
|
-
const dependencyOutputs = (step.depends_on ?? [])
|
|
217
|
-
.map((depId) => plan.steps.find((s) => s.step_id === depId))
|
|
218
|
-
.filter((dep) => dep?.status === "done")
|
|
219
|
-
.map((dep) => ({
|
|
220
|
-
step_id: dep.step_id,
|
|
221
|
-
result_summary: dep.result_summary ?? "",
|
|
222
|
-
evidence_refs: dep.evidence_refs ?? [],
|
|
223
|
-
}));
|
|
224
|
-
const carriedOutputs = (step.upstream_outputs ?? []).filter((output) => Boolean(output) &&
|
|
225
|
-
typeof output.step_id === "string" &&
|
|
226
|
-
typeof output.result_summary === "string" &&
|
|
227
|
-
Array.isArray(output.evidence_refs));
|
|
228
|
-
const merged = new Map();
|
|
229
|
-
for (const output of [...dependencyOutputs, ...carriedOutputs]) {
|
|
230
|
-
merged.set(output.step_id, output);
|
|
231
|
-
}
|
|
232
|
-
return [...merged.values()];
|
|
233
|
-
}
|
|
234
206
|
export async function applyBridgeResultToStepWithTransition(plan, stepId, result, repo) {
|
|
235
207
|
const updated = applyBridgeResultToStep(plan, stepId, result);
|
|
236
208
|
if (repo && plan.plan_id) {
|
|
@@ -281,7 +253,10 @@ export async function promoteParallelGroupToScheduler(plan, parallelGroup, owner
|
|
|
281
253
|
const jobIds = [];
|
|
282
254
|
const nextSteps = cloneSteps(plan.steps);
|
|
283
255
|
for (const step of readySteps) {
|
|
256
|
+
// Stable identity also makes retrying the original plan safe after a refused tick.
|
|
257
|
+
const requestedJobId = step.job_id ?? `PLANJOB-${plan.plan_id}-${step.step_id}`;
|
|
284
258
|
const enqueued = await enqueueJob({
|
|
259
|
+
job_id: requestedJobId,
|
|
285
260
|
kind: step.role,
|
|
286
261
|
payload: {
|
|
287
262
|
task: step.task,
|
|
@@ -295,7 +270,11 @@ export async function promoteParallelGroupToScheduler(plan, parallelGroup, owner
|
|
|
295
270
|
ref: dependency,
|
|
296
271
|
})) ?? [],
|
|
297
272
|
});
|
|
298
|
-
const
|
|
273
|
+
const existingJob = enqueued.nack?.reason_code === "duplicate_job_id"
|
|
274
|
+
? enqueued.queue.jobs.find((job) => job.job_id === requestedJobId &&
|
|
275
|
+
job.payload.plan_id === plan.plan_id && job.payload.step_id === step.step_id)
|
|
276
|
+
: undefined;
|
|
277
|
+
const jobId = enqueued.ack?.job_id ?? existingJob?.job_id;
|
|
299
278
|
if (!jobId)
|
|
300
279
|
continue;
|
|
301
280
|
jobIds.push(jobId);
|
|
@@ -303,36 +282,70 @@ export async function promoteParallelGroupToScheduler(plan, parallelGroup, owner
|
|
|
303
282
|
if (stepIndex >= 0) {
|
|
304
283
|
nextSteps[stepIndex] = {
|
|
305
284
|
...nextSteps[stepIndex],
|
|
306
|
-
status: "running",
|
|
307
285
|
job_id: jobId,
|
|
308
286
|
};
|
|
309
287
|
}
|
|
310
288
|
}
|
|
289
|
+
let dispatch;
|
|
290
|
+
let blockedReason;
|
|
311
291
|
if (jobIds.length > 0) {
|
|
312
292
|
const refs = deriveWorkspaceVericifyRunRef({
|
|
313
293
|
session_id: plan.plan_id,
|
|
314
294
|
role: "orchestrator",
|
|
315
295
|
});
|
|
316
|
-
await dispatchJobs({ owner });
|
|
317
|
-
|
|
296
|
+
dispatch = await dispatchJobs({ owner });
|
|
297
|
+
blockedReason = dispatch.error;
|
|
298
|
+
const promotedIds = new Set(jobIds);
|
|
299
|
+
for (const step of nextSteps) {
|
|
300
|
+
if (!step.job_id || !promotedIds.has(step.job_id))
|
|
301
|
+
continue;
|
|
302
|
+
const job = dispatch.queue.jobs.find((candidate) => candidate.job_id === step.job_id);
|
|
303
|
+
// A recorded assignment is not proof of dispatch. Keep queued steps retryable.
|
|
304
|
+
switch (job?.status) {
|
|
305
|
+
case "running":
|
|
306
|
+
step.status = "running";
|
|
307
|
+
break;
|
|
308
|
+
case "done":
|
|
309
|
+
step.status = "done";
|
|
310
|
+
break;
|
|
311
|
+
case "failed_terminal":
|
|
312
|
+
step.status = "failed";
|
|
313
|
+
break;
|
|
314
|
+
case "canceled":
|
|
315
|
+
step.status = "skipped";
|
|
316
|
+
break;
|
|
317
|
+
case "unknown_recovery":
|
|
318
|
+
step.status = "blocked";
|
|
319
|
+
break;
|
|
320
|
+
default: step.status = "planned";
|
|
321
|
+
}
|
|
322
|
+
step.blocked_reason = step.status === "planned" || step.status === "blocked"
|
|
323
|
+
? dispatch.error ?? job?.error
|
|
324
|
+
: undefined;
|
|
325
|
+
}
|
|
326
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
318
327
|
run_id: refs.run_id,
|
|
319
328
|
branch_id: refs.branch_id,
|
|
320
329
|
lane_id: refs.lane_id,
|
|
321
330
|
agent_id: "agent-orchestrator",
|
|
322
|
-
kind: "progress",
|
|
323
|
-
summary:
|
|
331
|
+
kind: blockedReason ? "blocker" : "progress",
|
|
332
|
+
summary: blockedReason
|
|
333
|
+
? `Parallel group '${parallelGroup}' queued; ${blockedReason}`
|
|
334
|
+
: `Promoted parallel group '${parallelGroup}' to scheduler: ${jobIds.join(", ")}; running=${nextSteps.filter((step) => step.job_id && promotedIds.has(step.job_id) && step.status === "running").length}`,
|
|
324
335
|
tool_refs: ["enqueue_job", "dispatch_jobs"],
|
|
325
336
|
evidence_refs: jobIds,
|
|
326
337
|
});
|
|
327
338
|
}
|
|
339
|
+
const promotedPlan = withDerivedStatus({
|
|
340
|
+
...plan,
|
|
341
|
+
execution_mode: "scheduled",
|
|
342
|
+
steps: nextSteps,
|
|
343
|
+
});
|
|
328
344
|
return {
|
|
329
|
-
plan:
|
|
330
|
-
...plan,
|
|
331
|
-
execution_mode: "scheduled",
|
|
332
|
-
steps: nextSteps,
|
|
333
|
-
status: "executing",
|
|
334
|
-
}),
|
|
345
|
+
plan: blockedReason ? { ...promotedPlan, status: "blocked" } : promotedPlan,
|
|
335
346
|
job_ids: jobIds,
|
|
347
|
+
dispatch,
|
|
348
|
+
blocked_reason: blockedReason,
|
|
336
349
|
};
|
|
337
350
|
}
|
|
338
351
|
export async function superviseTaskPlan(inputPlan, hooks) {
|
|
@@ -368,6 +381,17 @@ export async function superviseTaskPlan(inputPlan, hooks) {
|
|
|
368
381
|
const promoted = await promoteParallelGroupToScheduler(plan, readyGroup);
|
|
369
382
|
jobIds.push(...promoted.job_ids);
|
|
370
383
|
plan = promoted.plan;
|
|
384
|
+
if (promoted.blocked_reason) {
|
|
385
|
+
await hooks.emitStatusEvent?.({ status: "blocked", summary: promoted.blocked_reason });
|
|
386
|
+
await hooks.contextSnapshot?.(plan);
|
|
387
|
+
return {
|
|
388
|
+
plan,
|
|
389
|
+
handoff_ids: handoffIds,
|
|
390
|
+
job_ids: jobIds,
|
|
391
|
+
circuit_opened: false,
|
|
392
|
+
blocked_reason: promoted.blocked_reason,
|
|
393
|
+
};
|
|
394
|
+
}
|
|
371
395
|
break;
|
|
372
396
|
}
|
|
373
397
|
}
|
package/dist/plan-proposal.js
CHANGED
|
@@ -8,7 +8,7 @@ import { listAceInternalToolCatalog } from "./ace-internal-tools.js";
|
|
|
8
8
|
import { runLocalModelTask } from "./local-model-runtime.js";
|
|
9
9
|
import { listRuntimeToolSpecs } from "./runtime-tool-specs.js";
|
|
10
10
|
import { resolveWorkspaceRoot, safeRead, safeWriteAsync } from "./helpers.js";
|
|
11
|
-
import {
|
|
11
|
+
import { appendAutomaticVericifyProcessPostSafe } from "./vericify-bridge.js";
|
|
12
12
|
import { withLocalModelRuntimeRepository } from "./store/repositories/local-model-runtime-repository.js";
|
|
13
13
|
// ── In-memory proposal cache (plan_id → ProposePlanResult) ────────────────
|
|
14
14
|
const _proposalCache = new Map();
|
|
@@ -1051,8 +1051,8 @@ export async function validatePlan(input) {
|
|
|
1051
1051
|
catch {
|
|
1052
1052
|
// Non-fatal
|
|
1053
1053
|
}
|
|
1054
|
-
//
|
|
1055
|
-
await
|
|
1054
|
+
// Optional legacy summary; native Vericify owns observation capture.
|
|
1055
|
+
await appendAutomaticVericifyProcessPostSafe({
|
|
1056
1056
|
run_id: "workspace:current",
|
|
1057
1057
|
agent_id: "ace-planner",
|
|
1058
1058
|
kind: "plan_quality_assessment",
|
package/dist/playbook-curator.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { calculateJaccard, getShingles } from "./semantic-hash.js";
|
|
2
2
|
import { appendStatusEventSafe } from "./status-events.js";
|
|
3
3
|
function scopeEqualOrBroader(candidate, incoming) {
|
|
4
|
-
return Object.entries(candidate).every(([key, value]) => value === undefined || incoming[key] === value);
|
|
4
|
+
return Object.entries(candidate).every(([key, value]) => value === undefined || JSON.stringify(incoming[key]) === JSON.stringify(value));
|
|
5
5
|
}
|
|
6
6
|
function mergeEvidence(a, b) {
|
|
7
7
|
return [...new Set([...a, ...b])].slice(0, 5);
|
|
@@ -43,7 +43,7 @@ export async function curate(repo, ops, config = {}) {
|
|
|
43
43
|
}
|
|
44
44
|
const incomingShingles = getShingles(op.content, 3);
|
|
45
45
|
const match = repo
|
|
46
|
-
.listBullets({ section: op.section, status: "active" })
|
|
46
|
+
.listBullets({ section: op.section, ...(op.status === "quarantined" ? {} : { status: "active" }) })
|
|
47
47
|
.filter((bullet) => scopeEqualOrBroader(bullet.scope, op.scope))
|
|
48
48
|
.map((bullet) => ({
|
|
49
49
|
bullet,
|
|
@@ -55,6 +55,7 @@ export async function curate(repo, ops, config = {}) {
|
|
|
55
55
|
...match.bullet,
|
|
56
56
|
observed_count: match.bullet.observed_count + 1,
|
|
57
57
|
evidence_refs: mergeEvidence(match.bullet.evidence_refs, op.evidence_refs),
|
|
58
|
+
evidence_snapshots: [...new Map([...(match.bullet.evidence_snapshots ?? []), ...(op.evidence_snapshots ?? [])].map(e => [e.id, e])).values()],
|
|
58
59
|
});
|
|
59
60
|
result.merged += 1;
|
|
60
61
|
}
|
|
@@ -69,13 +70,14 @@ export async function curate(repo, ops, config = {}) {
|
|
|
69
70
|
}
|
|
70
71
|
result.pruned += pruneOverflow(repo, config);
|
|
71
72
|
const eventWorkspaceRoot = config.workspaceRoot ?? repo.root;
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
if (config.emitEvent !== false && Object.values(result).some(n => n > 0))
|
|
74
|
+
await appendStatusEventSafe({
|
|
75
|
+
event_type: "PLAYBOOK_CURATED",
|
|
76
|
+
source_module: "capability-build",
|
|
77
|
+
status: "done",
|
|
78
|
+
summary: `Playbook curated: added=${result.added} merged=${result.merged} tagged=${result.tagged} quarantined=${result.quarantined} pruned=${result.pruned}`,
|
|
79
|
+
payload: { ...result },
|
|
80
|
+
}, eventWorkspaceRoot ? { workspaceRoot: eventWorkspaceRoot } : {});
|
|
79
81
|
return result;
|
|
80
82
|
}
|
|
81
83
|
function pruneOverflow(repo, config) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ProcessIdentity {
|
|
2
|
+
pid: number;
|
|
3
|
+
started_at: string;
|
|
4
|
+
hostname: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function readProcessIdentity(pid: number): ProcessIdentity | undefined;
|
|
7
|
+
export declare function probeProcess(identity: ProcessIdentity): 'alive' | 'dead' | 'unknown';
|
|
8
|
+
//# sourceMappingURL=process-identity.d.ts.map
|