harnery 0.10.0 → 0.11.0
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/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +45 -2
- package/dist/core/workflow/engine.d.ts +5 -0
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +153 -14
- package/dist/core/workflow/index.d.ts +5 -0
- package/dist/core/workflow/index.d.ts.map +1 -0
- package/dist/core/workflow/index.js +3 -0
- package/dist/core/workflow/proof.d.ts +42 -0
- package/dist/core/workflow/proof.d.ts.map +1 -0
- package/dist/core/workflow/proof.js +342 -0
- package/dist/core/workflow/types.d.ts +147 -0
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/types.js +1 -1
- package/package.json +11 -6
- package/src/commands/workflow.ts +54 -2
- package/src/core/workflow/engine.ts +171 -14
- package/src/core/workflow/index.ts +43 -0
- package/src/core/workflow/proof.ts +434 -0
- package/src/core/workflow/types.ts +167 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/commands/workflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../src/commands/workflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA8BnD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,GAAG,IAAI,CA+IjF"}
|
|
@@ -9,7 +9,7 @@ export function registerWorkflowCommand(program, emit) {
|
|
|
9
9
|
.description("Run bounded, schema-gated multi-subagent workflow scripts.");
|
|
10
10
|
workflow
|
|
11
11
|
.command("run <script>")
|
|
12
|
-
.description("Execute a workflow script (plain JS: `export default async ({agent, parallel, stage, log}) => …`). " +
|
|
12
|
+
.description("Execute a workflow script (plain JS: `export default async ({agent, parallel, stage, log, evidence}) => …`). " +
|
|
13
13
|
"Subagents spawn as headless harness-CLI subprocesses, coordination-registered.")
|
|
14
14
|
.option("--max-agents <n>", "Total-agent ceiling for the run (default 50)")
|
|
15
15
|
.option("--concurrency <n>", "Concurrent-subagent cap (default 4)")
|
|
@@ -59,6 +59,12 @@ export function registerWorkflowCommand(program, emit) {
|
|
|
59
59
|
maxAgents: opts.maxAgents ? Number.parseInt(opts.maxAgents, 10) : undefined,
|
|
60
60
|
concurrency: opts.concurrency ? Number.parseInt(opts.concurrency, 10) : undefined,
|
|
61
61
|
cwd: opts.cwd,
|
|
62
|
+
harnessEvidence: Object.fromEntries(registry
|
|
63
|
+
.list()
|
|
64
|
+
.map((adapter) => [
|
|
65
|
+
adapter.profile.id,
|
|
66
|
+
{ toolEvidence: adapter.profile.capabilities.toolEvidence },
|
|
67
|
+
])),
|
|
62
68
|
});
|
|
63
69
|
if (opts.json) {
|
|
64
70
|
emit.config({ format: "json" });
|
|
@@ -71,11 +77,48 @@ export function registerWorkflowCommand(program, emit) {
|
|
|
71
77
|
: "";
|
|
72
78
|
emit.text(`run ${report.runId} (${report.name}) finished: ${report.agentsSpawned} agent(s)${cachedPart}, ` +
|
|
73
79
|
`$${report.costUsd.toFixed(4)}, ${Math.round(report.durationMs / 1000)}s\n${billingPart}` +
|
|
80
|
+
`acceptance: ${report.acceptance.satisfied} satisfied, ${report.acceptance.unsatisfied} unsatisfied, ` +
|
|
81
|
+
`${report.acceptance.unknown} unknown\n` +
|
|
74
82
|
`journal: ${report.journalPath}\n` +
|
|
83
|
+
`proof: ${report.proofPath}\n` +
|
|
75
84
|
`result: ${typeof report.result === "string" ? report.result : JSON.stringify(report.result, null, 2)}\n`);
|
|
76
85
|
}
|
|
77
86
|
catch (err) {
|
|
78
|
-
|
|
87
|
+
const proofPath = typeof err === "object" && err !== null && "proofPath" in err
|
|
88
|
+
? String(err.proofPath)
|
|
89
|
+
: undefined;
|
|
90
|
+
emit.error({
|
|
91
|
+
code: "workflow_failed",
|
|
92
|
+
message: `${err.message}${proofPath ? `\nproof: ${proofPath}` : ""}`,
|
|
93
|
+
});
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
workflow
|
|
98
|
+
.command("proof <run-id>")
|
|
99
|
+
.description("Show the bounded proof packet for a completed workflow run.")
|
|
100
|
+
.option("--json", "Emit the stored proof packet as JSON")
|
|
101
|
+
.action(async (runId, opts) => {
|
|
102
|
+
const coordRoot = findCoordRoot();
|
|
103
|
+
if (!coordRoot) {
|
|
104
|
+
emit.error({
|
|
105
|
+
code: "no_coord_root",
|
|
106
|
+
message: "no .harnery/ coordination root found; run `init` first",
|
|
107
|
+
});
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const { readWorkflowProof, renderWorkflowProof } = await import("../core/workflow/proof.js");
|
|
112
|
+
const proof = readWorkflowProof(coordRoot, runId);
|
|
113
|
+
if (opts.json) {
|
|
114
|
+
emit.config({ format: "json" });
|
|
115
|
+
emit.data(proof);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
emit.text(renderWorkflowProof(proof));
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
emit.error({ code: "workflow_proof_failed", message: err.message });
|
|
79
122
|
process.exit(1);
|
|
80
123
|
}
|
|
81
124
|
});
|
|
@@ -17,5 +17,10 @@
|
|
|
17
17
|
* cost, duration, and child session id (the resume + web-UI substrate).
|
|
18
18
|
*/
|
|
19
19
|
import type { EngineOpts, RunReport } from "./types.js";
|
|
20
|
+
export declare class WorkflowRunError extends Error {
|
|
21
|
+
readonly runId: string;
|
|
22
|
+
readonly proofPath: string;
|
|
23
|
+
constructor(message: string, runId: string, proofPath: string, cause?: unknown);
|
|
24
|
+
}
|
|
20
25
|
export declare function runWorkflow(scriptPath: string, opts: EngineOpts): Promise<RunReport>;
|
|
21
26
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAeH,OAAO,KAAK,EAEV,UAAU,EAEV,SAAS,EAOV,MAAM,YAAY,CAAC;AAUpB,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAM/E;AAED,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAqa1F"}
|
|
@@ -28,29 +28,46 @@ import { createHash, randomBytes } from "node:crypto";
|
|
|
28
28
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
|
|
29
29
|
import { isAbsolute, join, resolve } from "node:path";
|
|
30
30
|
import { pathToFileURL } from "node:url";
|
|
31
|
+
import { snapshotRepo } from "../context/index.js";
|
|
31
32
|
import { probeBilling } from "./billing.js";
|
|
33
|
+
import { buildWorkflowProof, createEvidenceRecord, digestResult, normalizeWorkflowMeta, writeWorkflowProof, } from "./proof.js";
|
|
34
|
+
import { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.js";
|
|
32
35
|
import { parseStageOutput, validateAgainstSchema } from "./validate.js";
|
|
33
36
|
const DEFAULT_MAX_AGENTS = 50;
|
|
34
37
|
const DEFAULT_CONCURRENCY = 4;
|
|
35
38
|
const DEFAULT_MAX_ATTEMPTS = 2;
|
|
36
39
|
const DEFAULT_TIMEOUT_MS = 300_000;
|
|
37
40
|
const DEFAULT_MAX_TURNS = 25;
|
|
41
|
+
export class WorkflowRunError extends Error {
|
|
42
|
+
runId;
|
|
43
|
+
proofPath;
|
|
44
|
+
constructor(message, runId, proofPath, cause) {
|
|
45
|
+
super(message, cause === undefined ? undefined : { cause });
|
|
46
|
+
this.name = "WorkflowRunError";
|
|
47
|
+
this.runId = runId;
|
|
48
|
+
this.proofPath = proofPath;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
38
51
|
export async function runWorkflow(scriptPath, opts) {
|
|
39
52
|
const absScript = isAbsolute(scriptPath) ? scriptPath : resolve(process.cwd(), scriptPath);
|
|
40
53
|
const mod = (await import(__rewriteRelativeImportExtension(pathToFileURL(absScript).href)));
|
|
41
54
|
if (typeof mod.default !== "function") {
|
|
42
55
|
throw new Error(`${scriptPath}: workflow script must \`export default async (ctx) => …\``);
|
|
43
56
|
}
|
|
44
|
-
const
|
|
57
|
+
const fallbackName = scriptPath.replace(/^.*\//, "").replace(/\.[cm]?js$/, "");
|
|
58
|
+
const meta = normalizeWorkflowMeta(mod.meta, fallbackName);
|
|
59
|
+
const name = meta.name;
|
|
45
60
|
const runId = `wf-${new Date().toISOString().replace(/[:.]/g, "-")}-${randomBytes(3).toString("hex")}`;
|
|
46
61
|
const runDir = join(opts.coordRoot, ".harnery", "workflows", runId);
|
|
47
62
|
mkdirSync(runDir, { recursive: true });
|
|
48
63
|
const journalPath = join(runDir, "journal.jsonl");
|
|
64
|
+
const proofPath = join(runDir, "proof.json");
|
|
49
65
|
const maxAgents = opts.maxAgents ?? DEFAULT_MAX_AGENTS;
|
|
50
66
|
const concurrency = opts.concurrency ?? DEFAULT_CONCURRENCY;
|
|
51
67
|
const cwd = opts.cwd ?? opts.coordRoot;
|
|
52
68
|
const log = opts.onLog ?? ((line) => process.stderr.write(`${line}\n`));
|
|
53
69
|
const defaultHarness = opts.defaultHarness ?? "claude-code";
|
|
70
|
+
const repoBefore = snapshotRepo(cwd);
|
|
54
71
|
// Per-child fixed context overhead: children spawn in `cwd` and load its
|
|
55
72
|
// repo-instructions file into their system prompt, cache-writing it once
|
|
56
73
|
// per child. A fan-out multiplies this, so surface it BEFORE the burn.
|
|
@@ -68,9 +85,15 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
68
85
|
let costUsd = 0;
|
|
69
86
|
let currentStage = "";
|
|
70
87
|
let agentSeq = 0;
|
|
88
|
+
let evidenceSeq = 0;
|
|
71
89
|
const billingProbed = new Map();
|
|
90
|
+
const agentProofs = new Map();
|
|
91
|
+
const evidenceRecords = [];
|
|
92
|
+
const acceptanceIds = new Set(meta.acceptance.map((criterion) => criterion.id));
|
|
72
93
|
const journal = (event, data) => {
|
|
73
94
|
const line = JSON.stringify({
|
|
95
|
+
schema_version: WORKFLOW_PROOF_SCHEMA_VERSION,
|
|
96
|
+
run_id: runId,
|
|
74
97
|
ts: new Date().toISOString(),
|
|
75
98
|
event,
|
|
76
99
|
stage: currentStage,
|
|
@@ -103,14 +126,35 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
103
126
|
}
|
|
104
127
|
const id = `a${++agentSeq}`;
|
|
105
128
|
const label = agentOpts.label ?? `${prompt.slice(0, 60).replace(/\s+/g, " ")}…`;
|
|
129
|
+
const proofLabel = agentOpts.label ?? id;
|
|
106
130
|
const maxAttempts = agentOpts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
131
|
+
const agentProof = {
|
|
132
|
+
id,
|
|
133
|
+
label: proofLabel,
|
|
134
|
+
stage: currentStage || undefined,
|
|
135
|
+
harness,
|
|
136
|
+
model: agentOpts.model,
|
|
137
|
+
status: "failed",
|
|
138
|
+
attempts: 0,
|
|
139
|
+
duration_ms: 0,
|
|
140
|
+
};
|
|
141
|
+
agentProofs.set(id, agentProof);
|
|
107
142
|
// Call identity for resume: same stage + harness + model + effort + turns + schema
|
|
108
143
|
// + ORIGINAL prompt → same key. Retry-mutated prompts never enter the key.
|
|
109
144
|
const key = agentCallKey(currentStage, harness, agentOpts, prompt);
|
|
110
145
|
const cached = resumeCache.get(key);
|
|
111
146
|
if (cached) {
|
|
112
147
|
agentsCached++;
|
|
113
|
-
|
|
148
|
+
agentProof.status = "cached";
|
|
149
|
+
agentProof.result = digestResult(cached.value, cached.kind);
|
|
150
|
+
journal("agent.cached", {
|
|
151
|
+
id,
|
|
152
|
+
label,
|
|
153
|
+
key,
|
|
154
|
+
harness,
|
|
155
|
+
model: agentOpts.model ?? null,
|
|
156
|
+
kind: cached.kind,
|
|
157
|
+
});
|
|
114
158
|
log(`[${name}] ${currentStage || "(no stage)"} → ${id} ${label} (cached from ${opts.resumeFrom})`);
|
|
115
159
|
return cached.value;
|
|
116
160
|
}
|
|
@@ -154,6 +198,7 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
154
198
|
}
|
|
155
199
|
}
|
|
156
200
|
if (agentsSpawned >= maxAgents) {
|
|
201
|
+
agentProof.error = `workflow agent cap reached (${maxAgents})`;
|
|
157
202
|
throw new Error(`workflow agent cap reached (${maxAgents}); raise --max-agents deliberately if the fan-out is intended`);
|
|
158
203
|
}
|
|
159
204
|
agentsSpawned++;
|
|
@@ -170,6 +215,7 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
170
215
|
log(`[${name}] ${currentStage || "(no stage)"} → ${id} [${harness}] ${label}`);
|
|
171
216
|
let attemptPrompt = prompt;
|
|
172
217
|
let last = null;
|
|
218
|
+
let agentCostUsd = 0;
|
|
173
219
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
174
220
|
last = await spawner({
|
|
175
221
|
prompt: attemptPrompt,
|
|
@@ -181,12 +227,20 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
181
227
|
runId,
|
|
182
228
|
subscriptionOnly: opts.subscriptionOnly,
|
|
183
229
|
});
|
|
230
|
+
agentProof.attempts = attempt;
|
|
231
|
+
agentProof.duration_ms += last.durationMs;
|
|
232
|
+
agentCostUsd += last.costUsd ?? 0;
|
|
184
233
|
costUsd += last.costUsd ?? 0;
|
|
185
234
|
if (!last.ok) {
|
|
186
235
|
journal("agent.attempt_failed", { id, attempt, error: last.error });
|
|
187
236
|
continue; // spawn-level failure: retry with the original prompt
|
|
188
237
|
}
|
|
189
238
|
if (!agentOpts.schema) {
|
|
239
|
+
agentProof.status = "succeeded";
|
|
240
|
+
agentProof.cost_usd =
|
|
241
|
+
agentCostUsd > 0 || last.costUsd !== undefined ? agentCostUsd : undefined;
|
|
242
|
+
agentProof.session_id = last.sessionId;
|
|
243
|
+
agentProof.result = digestResult(last.text, "text");
|
|
190
244
|
journal("agent.end", {
|
|
191
245
|
id,
|
|
192
246
|
key,
|
|
@@ -204,6 +258,11 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
204
258
|
? [parsed.error]
|
|
205
259
|
: validateAgainstSchema(parsed.value, agentOpts.schema);
|
|
206
260
|
if (problems.length === 0) {
|
|
261
|
+
agentProof.status = "succeeded";
|
|
262
|
+
agentProof.cost_usd =
|
|
263
|
+
agentCostUsd > 0 || last.costUsd !== undefined ? agentCostUsd : undefined;
|
|
264
|
+
agentProof.session_id = last.sessionId;
|
|
265
|
+
agentProof.result = digestResult(parsed.value, "json");
|
|
207
266
|
journal("agent.end", {
|
|
208
267
|
id,
|
|
209
268
|
key,
|
|
@@ -227,8 +286,16 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
227
286
|
const reason = last?.ok
|
|
228
287
|
? `schema validation failed after ${maxAttempts} attempt(s)`
|
|
229
288
|
: (last?.error ?? "spawn failed");
|
|
289
|
+
agentProof.cost_usd =
|
|
290
|
+
agentCostUsd > 0 || last?.costUsd !== undefined ? agentCostUsd : undefined;
|
|
291
|
+
agentProof.session_id = last?.sessionId;
|
|
292
|
+
agentProof.error = reason;
|
|
230
293
|
journal("agent.failed", { id, error: reason });
|
|
231
|
-
throw new Error(`agent ${
|
|
294
|
+
throw new Error(`agent ${proofLabel}: ${reason}`);
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
agentProof.error ??= error.message;
|
|
298
|
+
throw error;
|
|
232
299
|
}
|
|
233
300
|
finally {
|
|
234
301
|
release();
|
|
@@ -248,11 +315,62 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
248
315
|
journal("stage.start", { title });
|
|
249
316
|
log(`[${name}] ── stage: ${title}`);
|
|
250
317
|
};
|
|
251
|
-
const
|
|
318
|
+
const evidence = (input) => {
|
|
319
|
+
const record = createEvidenceRecord({
|
|
320
|
+
value: input,
|
|
321
|
+
sequence: evidenceSeq + 1,
|
|
322
|
+
acceptanceIds,
|
|
323
|
+
stage: currentStage || undefined,
|
|
324
|
+
});
|
|
325
|
+
evidenceSeq++;
|
|
326
|
+
evidenceRecords.push(record);
|
|
327
|
+
journal("evidence.recorded", { ...record });
|
|
328
|
+
return record.id;
|
|
329
|
+
};
|
|
330
|
+
const ctx = { agent, parallel, stage, log, evidence };
|
|
252
331
|
const t0 = Date.now();
|
|
253
|
-
|
|
332
|
+
const startedAt = new Date(t0).toISOString();
|
|
333
|
+
journal("run.start", {
|
|
334
|
+
name,
|
|
335
|
+
script: absScript,
|
|
336
|
+
objective: meta.objective ?? null,
|
|
337
|
+
acceptance: meta.acceptance,
|
|
338
|
+
max_agents: maxAgents,
|
|
339
|
+
concurrency,
|
|
340
|
+
});
|
|
254
341
|
try {
|
|
255
342
|
const result = await mod.default(ctx);
|
|
343
|
+
const endedAt = new Date().toISOString();
|
|
344
|
+
const durationMs = Date.now() - t0;
|
|
345
|
+
journal("run.end", {
|
|
346
|
+
ok: true,
|
|
347
|
+
agents: agentsSpawned,
|
|
348
|
+
cached: agentsCached,
|
|
349
|
+
cost_usd: round4(costUsd),
|
|
350
|
+
duration_ms: durationMs,
|
|
351
|
+
});
|
|
352
|
+
let proof;
|
|
353
|
+
try {
|
|
354
|
+
proof = buildWorkflowProof({
|
|
355
|
+
runId,
|
|
356
|
+
meta,
|
|
357
|
+
status: "succeeded",
|
|
358
|
+
startedAt,
|
|
359
|
+
endedAt,
|
|
360
|
+
durationMs,
|
|
361
|
+
journalPath,
|
|
362
|
+
before: repoBefore,
|
|
363
|
+
after: snapshotRepo(cwd),
|
|
364
|
+
agents: Array.from(agentProofs.values()),
|
|
365
|
+
evidence: evidenceRecords,
|
|
366
|
+
harnessEvidence: opts.harnessEvidence,
|
|
367
|
+
result,
|
|
368
|
+
});
|
|
369
|
+
writeWorkflowProof(proofPath, proof);
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
throw new WorkflowRunError(`workflow completed but its proof packet could not be written: ${error.message}`, runId, proofPath, error);
|
|
373
|
+
}
|
|
256
374
|
const report = {
|
|
257
375
|
runId,
|
|
258
376
|
name,
|
|
@@ -260,32 +378,53 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
260
378
|
agentsSpawned,
|
|
261
379
|
agentsCached,
|
|
262
380
|
costUsd: round4(costUsd),
|
|
263
|
-
durationMs
|
|
381
|
+
durationMs,
|
|
264
382
|
journalPath,
|
|
383
|
+
proofPath,
|
|
384
|
+
acceptance: proof.acceptance.summary,
|
|
265
385
|
contextTokensPerChildEstimate,
|
|
266
386
|
billing: Array.from(billingProbed.values()).map((p) => ({
|
|
267
387
|
harness: p.harness,
|
|
268
388
|
mode: opts.subscriptionOnly ? "subscription" : p.mode,
|
|
269
389
|
})),
|
|
270
390
|
};
|
|
271
|
-
journal("run.end", {
|
|
272
|
-
ok: true,
|
|
273
|
-
agents: agentsSpawned,
|
|
274
|
-
cached: agentsCached,
|
|
275
|
-
cost_usd: report.costUsd,
|
|
276
|
-
duration_ms: report.durationMs,
|
|
277
|
-
});
|
|
278
391
|
return report;
|
|
279
392
|
}
|
|
280
393
|
catch (err) {
|
|
394
|
+
if (err instanceof WorkflowRunError)
|
|
395
|
+
throw err;
|
|
396
|
+
const endedAt = new Date().toISOString();
|
|
397
|
+
const durationMs = Date.now() - t0;
|
|
281
398
|
journal("run.end", {
|
|
282
399
|
ok: false,
|
|
283
400
|
error: err.message,
|
|
284
401
|
agents: agentsSpawned,
|
|
285
402
|
cached: agentsCached,
|
|
286
403
|
cost_usd: round4(costUsd),
|
|
404
|
+
duration_ms: durationMs,
|
|
287
405
|
});
|
|
288
|
-
|
|
406
|
+
try {
|
|
407
|
+
const proof = buildWorkflowProof({
|
|
408
|
+
runId,
|
|
409
|
+
meta,
|
|
410
|
+
status: "failed",
|
|
411
|
+
startedAt,
|
|
412
|
+
endedAt,
|
|
413
|
+
durationMs,
|
|
414
|
+
journalPath,
|
|
415
|
+
before: repoBefore,
|
|
416
|
+
after: snapshotRepo(cwd),
|
|
417
|
+
agents: Array.from(agentProofs.values()),
|
|
418
|
+
evidence: evidenceRecords,
|
|
419
|
+
harnessEvidence: opts.harnessEvidence,
|
|
420
|
+
error: err.message,
|
|
421
|
+
});
|
|
422
|
+
writeWorkflowProof(proofPath, proof);
|
|
423
|
+
}
|
|
424
|
+
catch (proofError) {
|
|
425
|
+
throw new WorkflowRunError(`${err.message}; proof packet write also failed: ${proofError.message}`, runId, proofPath, err);
|
|
426
|
+
}
|
|
427
|
+
throw new WorkflowRunError(err.message, runId, proofPath, err);
|
|
289
428
|
}
|
|
290
429
|
}
|
|
291
430
|
/** Stable identity for one agent() call, for the resume cache. The ORIGINAL
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { runWorkflow, WorkflowRunError } from "./engine.js";
|
|
2
|
+
export { buildWorkflowProof, createEvidenceRecord, digestResult, normalizeWorkflowMeta, readWorkflowProof, renderWorkflowProof, rollupAcceptance, writeWorkflowProof, } from "./proof.js";
|
|
3
|
+
export type { AcceptanceCriterion, AcceptanceResult, AcceptanceStatus, AcceptanceSummary, AgentOpts, EngineOpts, EvidenceKind, EvidenceSource, EvidenceStatus, HarnessEvidenceCapability, HarnessEvidenceCoverage, HarnessName, ResultDigest, RunReport, Spawner, SpawnRequest, SpawnResult, StageSchema, WorkflowAgentProof, WorkflowContext, WorkflowEvidenceInput, WorkflowEvidenceRecord, WorkflowMeta, WorkflowModule, WorkflowProof, WorkflowProofUnknown, WorkflowRepoEvidence, WorkflowRepoSnapshot, WorkflowRunStatus, } from "./types.js";
|
|
4
|
+
export { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,YAAY,EACZ,cAAc,EACd,cAAc,EACd,yBAAyB,EACzB,uBAAuB,EACvB,WAAW,EACX,YAAY,EACZ,SAAS,EACT,OAAO,EACP,YAAY,EACZ,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,6BAA6B,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { runWorkflow, WorkflowRunError } from "./engine.js";
|
|
2
|
+
export { buildWorkflowProof, createEvidenceRecord, digestResult, normalizeWorkflowMeta, readWorkflowProof, renderWorkflowProof, rollupAcceptance, writeWorkflowProof, } from "./proof.js";
|
|
3
|
+
export { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.js";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { RepoSnapshot } from "../context/index.js";
|
|
2
|
+
import type { AcceptanceCriterion, AcceptanceResult, AcceptanceSummary, HarnessEvidenceCapability, ResultDigest, WorkflowAgentProof, WorkflowEvidenceInput, WorkflowEvidenceRecord, WorkflowMeta, WorkflowProof } from "./types.js";
|
|
3
|
+
export interface NormalizedWorkflowMeta {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
objective?: string;
|
|
7
|
+
acceptance: AcceptanceCriterion[];
|
|
8
|
+
}
|
|
9
|
+
export interface BuildWorkflowProofInput {
|
|
10
|
+
runId: string;
|
|
11
|
+
meta: NormalizedWorkflowMeta;
|
|
12
|
+
status: "succeeded" | "failed";
|
|
13
|
+
startedAt: string;
|
|
14
|
+
endedAt: string;
|
|
15
|
+
durationMs: number;
|
|
16
|
+
journalPath: string;
|
|
17
|
+
before: RepoSnapshot;
|
|
18
|
+
after: RepoSnapshot;
|
|
19
|
+
agents: WorkflowAgentProof[];
|
|
20
|
+
evidence: WorkflowEvidenceRecord[];
|
|
21
|
+
harnessEvidence?: Readonly<Record<string, HarnessEvidenceCapability | undefined>>;
|
|
22
|
+
result?: unknown;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare function normalizeWorkflowMeta(meta: WorkflowMeta | undefined, fallbackName: string): NormalizedWorkflowMeta;
|
|
26
|
+
export declare function createEvidenceRecord(input: {
|
|
27
|
+
value: WorkflowEvidenceInput;
|
|
28
|
+
sequence: number;
|
|
29
|
+
acceptanceIds: ReadonlySet<string>;
|
|
30
|
+
stage?: string;
|
|
31
|
+
recordedAt?: string;
|
|
32
|
+
}): WorkflowEvidenceRecord;
|
|
33
|
+
export declare function rollupAcceptance(criteria: AcceptanceCriterion[], evidence: WorkflowEvidenceRecord[]): {
|
|
34
|
+
criteria: AcceptanceResult[];
|
|
35
|
+
summary: AcceptanceSummary;
|
|
36
|
+
};
|
|
37
|
+
export declare function digestResult(value: unknown, kind?: "text" | "json"): ResultDigest;
|
|
38
|
+
export declare function buildWorkflowProof(input: BuildWorkflowProofInput): WorkflowProof;
|
|
39
|
+
export declare function writeWorkflowProof(path: string, proof: WorkflowProof): void;
|
|
40
|
+
export declare function readWorkflowProof(coordRoot: string, runId: string): WorkflowProof;
|
|
41
|
+
export declare function renderWorkflowProof(proof: WorkflowProof): string;
|
|
42
|
+
//# sourceMappingURL=proof.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proof.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/proof.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EAEzB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,aAAa,EAId,MAAM,YAAY,CAAC;AAepB,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,mBAAmB,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,sBAAsB,CAAC;IAC7B,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,yBAAyB,GAAG,SAAS,CAAC,CAAC,CAAC;IAClF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,YAAY,GAAG,SAAS,EAC9B,YAAY,EAAE,MAAM,GACnB,sBAAsB,CAqCxB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,KAAK,EAAE,qBAAqB,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,sBAAsB,CA6BzB;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,QAAQ,EAAE,sBAAsB,EAAE,GACjC;IAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,CAuB9D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,CAQjF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,aAAa,CAwChF;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CAe3E;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,CAkBjF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CA8BhE"}
|