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
package/src/commands/workflow.ts
CHANGED
|
@@ -25,6 +25,10 @@ interface WorkflowRunOpts {
|
|
|
25
25
|
json?: boolean;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
interface WorkflowProofOpts {
|
|
29
|
+
json?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
export function registerWorkflowCommand(program: Command, emit: EmitContext): void {
|
|
29
33
|
const registry = createBuiltinHarnessRegistry();
|
|
30
34
|
const harnesses = registry.ids();
|
|
@@ -35,7 +39,7 @@ export function registerWorkflowCommand(program: Command, emit: EmitContext): vo
|
|
|
35
39
|
workflow
|
|
36
40
|
.command("run <script>")
|
|
37
41
|
.description(
|
|
38
|
-
"Execute a workflow script (plain JS: `export default async ({agent, parallel, stage, log}) => …`). " +
|
|
42
|
+
"Execute a workflow script (plain JS: `export default async ({agent, parallel, stage, log, evidence}) => …`). " +
|
|
39
43
|
"Subagents spawn as headless harness-CLI subprocesses, coordination-registered.",
|
|
40
44
|
)
|
|
41
45
|
.option("--max-agents <n>", "Total-agent ceiling for the run (default 50)")
|
|
@@ -99,6 +103,14 @@ export function registerWorkflowCommand(program: Command, emit: EmitContext): vo
|
|
|
99
103
|
maxAgents: opts.maxAgents ? Number.parseInt(opts.maxAgents, 10) : undefined,
|
|
100
104
|
concurrency: opts.concurrency ? Number.parseInt(opts.concurrency, 10) : undefined,
|
|
101
105
|
cwd: opts.cwd,
|
|
106
|
+
harnessEvidence: Object.fromEntries(
|
|
107
|
+
registry
|
|
108
|
+
.list()
|
|
109
|
+
.map((adapter) => [
|
|
110
|
+
adapter.profile.id,
|
|
111
|
+
{ toolEvidence: adapter.profile.capabilities.toolEvidence },
|
|
112
|
+
]),
|
|
113
|
+
),
|
|
102
114
|
});
|
|
103
115
|
if (opts.json) {
|
|
104
116
|
emit.config({ format: "json" });
|
|
@@ -112,11 +124,51 @@ export function registerWorkflowCommand(program: Command, emit: EmitContext): vo
|
|
|
112
124
|
emit.text(
|
|
113
125
|
`run ${report.runId} (${report.name}) finished: ${report.agentsSpawned} agent(s)${cachedPart}, ` +
|
|
114
126
|
`$${report.costUsd.toFixed(4)}, ${Math.round(report.durationMs / 1000)}s\n${billingPart}` +
|
|
127
|
+
`acceptance: ${report.acceptance.satisfied} satisfied, ${report.acceptance.unsatisfied} unsatisfied, ` +
|
|
128
|
+
`${report.acceptance.unknown} unknown\n` +
|
|
115
129
|
`journal: ${report.journalPath}\n` +
|
|
130
|
+
`proof: ${report.proofPath}\n` +
|
|
116
131
|
`result: ${typeof report.result === "string" ? report.result : JSON.stringify(report.result, null, 2)}\n`,
|
|
117
132
|
);
|
|
118
133
|
} catch (err) {
|
|
119
|
-
|
|
134
|
+
const proofPath =
|
|
135
|
+
typeof err === "object" && err !== null && "proofPath" in err
|
|
136
|
+
? String(err.proofPath)
|
|
137
|
+
: undefined;
|
|
138
|
+
emit.error({
|
|
139
|
+
code: "workflow_failed",
|
|
140
|
+
message: `${(err as Error).message}${proofPath ? `\nproof: ${proofPath}` : ""}`,
|
|
141
|
+
});
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
workflow
|
|
147
|
+
.command("proof <run-id>")
|
|
148
|
+
.description("Show the bounded proof packet for a completed workflow run.")
|
|
149
|
+
.option("--json", "Emit the stored proof packet as JSON")
|
|
150
|
+
.action(async (runId: string, opts: WorkflowProofOpts) => {
|
|
151
|
+
const coordRoot = findCoordRoot();
|
|
152
|
+
if (!coordRoot) {
|
|
153
|
+
emit.error({
|
|
154
|
+
code: "no_coord_root",
|
|
155
|
+
message: "no .harnery/ coordination root found; run `init` first",
|
|
156
|
+
});
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const { readWorkflowProof, renderWorkflowProof } = await import(
|
|
161
|
+
"../core/workflow/proof.ts"
|
|
162
|
+
);
|
|
163
|
+
const proof = readWorkflowProof(coordRoot, runId);
|
|
164
|
+
if (opts.json) {
|
|
165
|
+
emit.config({ format: "json" });
|
|
166
|
+
emit.data(proof);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
emit.text(renderWorkflowProof(proof));
|
|
170
|
+
} catch (err) {
|
|
171
|
+
emit.error({ code: "workflow_proof_failed", message: (err as Error).message });
|
|
120
172
|
process.exit(1);
|
|
121
173
|
}
|
|
122
174
|
});
|
|
@@ -21,16 +21,28 @@ import { createHash, randomBytes } from "node:crypto";
|
|
|
21
21
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync } from "node:fs";
|
|
22
22
|
import { isAbsolute, join, resolve } from "node:path";
|
|
23
23
|
import { pathToFileURL } from "node:url";
|
|
24
|
+
import { snapshotRepo } from "../context/index.ts";
|
|
24
25
|
import { type BillingProbe, probeBilling } from "./billing.ts";
|
|
26
|
+
import {
|
|
27
|
+
buildWorkflowProof,
|
|
28
|
+
createEvidenceRecord,
|
|
29
|
+
digestResult,
|
|
30
|
+
normalizeWorkflowMeta,
|
|
31
|
+
writeWorkflowProof,
|
|
32
|
+
} from "./proof.ts";
|
|
25
33
|
import type {
|
|
26
34
|
AgentOpts,
|
|
27
35
|
EngineOpts,
|
|
28
36
|
HarnessName,
|
|
29
37
|
RunReport,
|
|
30
38
|
SpawnResult,
|
|
39
|
+
WorkflowAgentProof,
|
|
31
40
|
WorkflowContext,
|
|
41
|
+
WorkflowEvidenceRecord,
|
|
32
42
|
WorkflowModule,
|
|
43
|
+
WorkflowProof,
|
|
33
44
|
} from "./types.ts";
|
|
45
|
+
import { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.ts";
|
|
34
46
|
import { parseStageOutput, validateAgainstSchema } from "./validate.ts";
|
|
35
47
|
|
|
36
48
|
const DEFAULT_MAX_AGENTS = 50;
|
|
@@ -39,24 +51,40 @@ const DEFAULT_MAX_ATTEMPTS = 2;
|
|
|
39
51
|
const DEFAULT_TIMEOUT_MS = 300_000;
|
|
40
52
|
const DEFAULT_MAX_TURNS = 25;
|
|
41
53
|
|
|
54
|
+
export class WorkflowRunError extends Error {
|
|
55
|
+
readonly runId: string;
|
|
56
|
+
readonly proofPath: string;
|
|
57
|
+
|
|
58
|
+
constructor(message: string, runId: string, proofPath: string, cause?: unknown) {
|
|
59
|
+
super(message, cause === undefined ? undefined : { cause });
|
|
60
|
+
this.name = "WorkflowRunError";
|
|
61
|
+
this.runId = runId;
|
|
62
|
+
this.proofPath = proofPath;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
42
66
|
export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise<RunReport> {
|
|
43
67
|
const absScript = isAbsolute(scriptPath) ? scriptPath : resolve(process.cwd(), scriptPath);
|
|
44
68
|
const mod = (await import(pathToFileURL(absScript).href)) as WorkflowModule;
|
|
45
69
|
if (typeof mod.default !== "function") {
|
|
46
70
|
throw new Error(`${scriptPath}: workflow script must \`export default async (ctx) => …\``);
|
|
47
71
|
}
|
|
48
|
-
const
|
|
72
|
+
const fallbackName = scriptPath.replace(/^.*\//, "").replace(/\.[cm]?js$/, "");
|
|
73
|
+
const meta = normalizeWorkflowMeta(mod.meta, fallbackName);
|
|
74
|
+
const name = meta.name;
|
|
49
75
|
|
|
50
76
|
const runId = `wf-${new Date().toISOString().replace(/[:.]/g, "-")}-${randomBytes(3).toString("hex")}`;
|
|
51
77
|
const runDir = join(opts.coordRoot, ".harnery", "workflows", runId);
|
|
52
78
|
mkdirSync(runDir, { recursive: true });
|
|
53
79
|
const journalPath = join(runDir, "journal.jsonl");
|
|
80
|
+
const proofPath = join(runDir, "proof.json");
|
|
54
81
|
|
|
55
82
|
const maxAgents = opts.maxAgents ?? DEFAULT_MAX_AGENTS;
|
|
56
83
|
const concurrency = opts.concurrency ?? DEFAULT_CONCURRENCY;
|
|
57
84
|
const cwd = opts.cwd ?? opts.coordRoot;
|
|
58
85
|
const log = opts.onLog ?? ((line: string) => process.stderr.write(`${line}\n`));
|
|
59
86
|
const defaultHarness: HarnessName = opts.defaultHarness ?? "claude-code";
|
|
87
|
+
const repoBefore = snapshotRepo(cwd);
|
|
60
88
|
|
|
61
89
|
// Per-child fixed context overhead: children spawn in `cwd` and load its
|
|
62
90
|
// repo-instructions file into their system prompt, cache-writing it once
|
|
@@ -79,10 +107,16 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
79
107
|
let costUsd = 0;
|
|
80
108
|
let currentStage = "";
|
|
81
109
|
let agentSeq = 0;
|
|
110
|
+
let evidenceSeq = 0;
|
|
82
111
|
const billingProbed = new Map<HarnessName, BillingProbe>();
|
|
112
|
+
const agentProofs = new Map<string, WorkflowAgentProof>();
|
|
113
|
+
const evidenceRecords: WorkflowEvidenceRecord[] = [];
|
|
114
|
+
const acceptanceIds = new Set(meta.acceptance.map((criterion) => criterion.id));
|
|
83
115
|
|
|
84
116
|
const journal = (event: string, data: Record<string, unknown>): void => {
|
|
85
117
|
const line = JSON.stringify({
|
|
118
|
+
schema_version: WORKFLOW_PROOF_SCHEMA_VERSION,
|
|
119
|
+
run_id: runId,
|
|
86
120
|
ts: new Date().toISOString(),
|
|
87
121
|
event,
|
|
88
122
|
stage: currentStage,
|
|
@@ -119,7 +153,19 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
119
153
|
}
|
|
120
154
|
const id = `a${++agentSeq}`;
|
|
121
155
|
const label = agentOpts.label ?? `${prompt.slice(0, 60).replace(/\s+/g, " ")}…`;
|
|
156
|
+
const proofLabel = agentOpts.label ?? id;
|
|
122
157
|
const maxAttempts = agentOpts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
158
|
+
const agentProof: WorkflowAgentProof = {
|
|
159
|
+
id,
|
|
160
|
+
label: proofLabel,
|
|
161
|
+
stage: currentStage || undefined,
|
|
162
|
+
harness,
|
|
163
|
+
model: agentOpts.model,
|
|
164
|
+
status: "failed",
|
|
165
|
+
attempts: 0,
|
|
166
|
+
duration_ms: 0,
|
|
167
|
+
};
|
|
168
|
+
agentProofs.set(id, agentProof);
|
|
123
169
|
|
|
124
170
|
// Call identity for resume: same stage + harness + model + effort + turns + schema
|
|
125
171
|
// + ORIGINAL prompt → same key. Retry-mutated prompts never enter the key.
|
|
@@ -127,7 +173,16 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
127
173
|
const cached = resumeCache.get(key);
|
|
128
174
|
if (cached) {
|
|
129
175
|
agentsCached++;
|
|
130
|
-
|
|
176
|
+
agentProof.status = "cached";
|
|
177
|
+
agentProof.result = digestResult(cached.value, cached.kind);
|
|
178
|
+
journal("agent.cached", {
|
|
179
|
+
id,
|
|
180
|
+
label,
|
|
181
|
+
key,
|
|
182
|
+
harness,
|
|
183
|
+
model: agentOpts.model ?? null,
|
|
184
|
+
kind: cached.kind,
|
|
185
|
+
});
|
|
131
186
|
log(
|
|
132
187
|
`[${name}] ${currentStage || "(no stage)"} → ${id} ${label} (cached from ${opts.resumeFrom})`,
|
|
133
188
|
);
|
|
@@ -179,6 +234,7 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
179
234
|
}
|
|
180
235
|
|
|
181
236
|
if (agentsSpawned >= maxAgents) {
|
|
237
|
+
agentProof.error = `workflow agent cap reached (${maxAgents})`;
|
|
182
238
|
throw new Error(
|
|
183
239
|
`workflow agent cap reached (${maxAgents}); raise --max-agents deliberately if the fan-out is intended`,
|
|
184
240
|
);
|
|
@@ -199,6 +255,7 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
199
255
|
|
|
200
256
|
let attemptPrompt = prompt;
|
|
201
257
|
let last: SpawnResult | null = null;
|
|
258
|
+
let agentCostUsd = 0;
|
|
202
259
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
203
260
|
last = await spawner({
|
|
204
261
|
prompt: attemptPrompt,
|
|
@@ -210,6 +267,9 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
210
267
|
runId,
|
|
211
268
|
subscriptionOnly: opts.subscriptionOnly,
|
|
212
269
|
});
|
|
270
|
+
agentProof.attempts = attempt;
|
|
271
|
+
agentProof.duration_ms += last.durationMs;
|
|
272
|
+
agentCostUsd += last.costUsd ?? 0;
|
|
213
273
|
costUsd += last.costUsd ?? 0;
|
|
214
274
|
|
|
215
275
|
if (!last.ok) {
|
|
@@ -217,6 +277,11 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
217
277
|
continue; // spawn-level failure: retry with the original prompt
|
|
218
278
|
}
|
|
219
279
|
if (!agentOpts.schema) {
|
|
280
|
+
agentProof.status = "succeeded";
|
|
281
|
+
agentProof.cost_usd =
|
|
282
|
+
agentCostUsd > 0 || last.costUsd !== undefined ? agentCostUsd : undefined;
|
|
283
|
+
agentProof.session_id = last.sessionId;
|
|
284
|
+
agentProof.result = digestResult(last.text, "text");
|
|
220
285
|
journal("agent.end", {
|
|
221
286
|
id,
|
|
222
287
|
key,
|
|
@@ -236,6 +301,11 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
236
301
|
? [parsed.error]
|
|
237
302
|
: validateAgainstSchema(parsed.value, agentOpts.schema);
|
|
238
303
|
if (problems.length === 0) {
|
|
304
|
+
agentProof.status = "succeeded";
|
|
305
|
+
agentProof.cost_usd =
|
|
306
|
+
agentCostUsd > 0 || last.costUsd !== undefined ? agentCostUsd : undefined;
|
|
307
|
+
agentProof.session_id = last.sessionId;
|
|
308
|
+
agentProof.result = digestResult(parsed.value, "json");
|
|
239
309
|
journal("agent.end", {
|
|
240
310
|
id,
|
|
241
311
|
key,
|
|
@@ -261,8 +331,15 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
261
331
|
const reason = last?.ok
|
|
262
332
|
? `schema validation failed after ${maxAttempts} attempt(s)`
|
|
263
333
|
: (last?.error ?? "spawn failed");
|
|
334
|
+
agentProof.cost_usd =
|
|
335
|
+
agentCostUsd > 0 || last?.costUsd !== undefined ? agentCostUsd : undefined;
|
|
336
|
+
agentProof.session_id = last?.sessionId;
|
|
337
|
+
agentProof.error = reason;
|
|
264
338
|
journal("agent.failed", { id, error: reason });
|
|
265
|
-
throw new Error(`agent ${
|
|
339
|
+
throw new Error(`agent ${proofLabel}: ${reason}`);
|
|
340
|
+
} catch (error) {
|
|
341
|
+
agentProof.error ??= (error as Error).message;
|
|
342
|
+
throw error;
|
|
266
343
|
} finally {
|
|
267
344
|
release();
|
|
268
345
|
}
|
|
@@ -288,12 +365,68 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
288
365
|
log(`[${name}] ── stage: ${title}`);
|
|
289
366
|
};
|
|
290
367
|
|
|
291
|
-
const
|
|
368
|
+
const evidence = (input: Parameters<WorkflowContext["evidence"]>[0]): string => {
|
|
369
|
+
const record = createEvidenceRecord({
|
|
370
|
+
value: input,
|
|
371
|
+
sequence: evidenceSeq + 1,
|
|
372
|
+
acceptanceIds,
|
|
373
|
+
stage: currentStage || undefined,
|
|
374
|
+
});
|
|
375
|
+
evidenceSeq++;
|
|
376
|
+
evidenceRecords.push(record);
|
|
377
|
+
journal("evidence.recorded", { ...record });
|
|
378
|
+
return record.id;
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
const ctx: WorkflowContext = { agent, parallel, stage, log, evidence };
|
|
292
382
|
|
|
293
383
|
const t0 = Date.now();
|
|
294
|
-
|
|
384
|
+
const startedAt = new Date(t0).toISOString();
|
|
385
|
+
journal("run.start", {
|
|
386
|
+
name,
|
|
387
|
+
script: absScript,
|
|
388
|
+
objective: meta.objective ?? null,
|
|
389
|
+
acceptance: meta.acceptance,
|
|
390
|
+
max_agents: maxAgents,
|
|
391
|
+
concurrency,
|
|
392
|
+
});
|
|
295
393
|
try {
|
|
296
394
|
const result = await mod.default(ctx);
|
|
395
|
+
const endedAt = new Date().toISOString();
|
|
396
|
+
const durationMs = Date.now() - t0;
|
|
397
|
+
journal("run.end", {
|
|
398
|
+
ok: true,
|
|
399
|
+
agents: agentsSpawned,
|
|
400
|
+
cached: agentsCached,
|
|
401
|
+
cost_usd: round4(costUsd),
|
|
402
|
+
duration_ms: durationMs,
|
|
403
|
+
});
|
|
404
|
+
let proof: WorkflowProof;
|
|
405
|
+
try {
|
|
406
|
+
proof = buildWorkflowProof({
|
|
407
|
+
runId,
|
|
408
|
+
meta,
|
|
409
|
+
status: "succeeded",
|
|
410
|
+
startedAt,
|
|
411
|
+
endedAt,
|
|
412
|
+
durationMs,
|
|
413
|
+
journalPath,
|
|
414
|
+
before: repoBefore,
|
|
415
|
+
after: snapshotRepo(cwd),
|
|
416
|
+
agents: Array.from(agentProofs.values()),
|
|
417
|
+
evidence: evidenceRecords,
|
|
418
|
+
harnessEvidence: opts.harnessEvidence,
|
|
419
|
+
result,
|
|
420
|
+
});
|
|
421
|
+
writeWorkflowProof(proofPath, proof);
|
|
422
|
+
} catch (error) {
|
|
423
|
+
throw new WorkflowRunError(
|
|
424
|
+
`workflow completed but its proof packet could not be written: ${(error as Error).message}`,
|
|
425
|
+
runId,
|
|
426
|
+
proofPath,
|
|
427
|
+
error,
|
|
428
|
+
);
|
|
429
|
+
}
|
|
297
430
|
const report: RunReport = {
|
|
298
431
|
runId,
|
|
299
432
|
name,
|
|
@@ -301,31 +434,55 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
301
434
|
agentsSpawned,
|
|
302
435
|
agentsCached,
|
|
303
436
|
costUsd: round4(costUsd),
|
|
304
|
-
durationMs
|
|
437
|
+
durationMs,
|
|
305
438
|
journalPath,
|
|
439
|
+
proofPath,
|
|
440
|
+
acceptance: proof.acceptance.summary,
|
|
306
441
|
contextTokensPerChildEstimate,
|
|
307
442
|
billing: Array.from(billingProbed.values()).map((p) => ({
|
|
308
443
|
harness: p.harness,
|
|
309
444
|
mode: opts.subscriptionOnly ? "subscription" : p.mode,
|
|
310
445
|
})),
|
|
311
446
|
};
|
|
312
|
-
journal("run.end", {
|
|
313
|
-
ok: true,
|
|
314
|
-
agents: agentsSpawned,
|
|
315
|
-
cached: agentsCached,
|
|
316
|
-
cost_usd: report.costUsd,
|
|
317
|
-
duration_ms: report.durationMs,
|
|
318
|
-
});
|
|
319
447
|
return report;
|
|
320
448
|
} catch (err) {
|
|
449
|
+
if (err instanceof WorkflowRunError) throw err;
|
|
450
|
+
const endedAt = new Date().toISOString();
|
|
451
|
+
const durationMs = Date.now() - t0;
|
|
321
452
|
journal("run.end", {
|
|
322
453
|
ok: false,
|
|
323
454
|
error: (err as Error).message,
|
|
324
455
|
agents: agentsSpawned,
|
|
325
456
|
cached: agentsCached,
|
|
326
457
|
cost_usd: round4(costUsd),
|
|
458
|
+
duration_ms: durationMs,
|
|
327
459
|
});
|
|
328
|
-
|
|
460
|
+
try {
|
|
461
|
+
const proof = buildWorkflowProof({
|
|
462
|
+
runId,
|
|
463
|
+
meta,
|
|
464
|
+
status: "failed",
|
|
465
|
+
startedAt,
|
|
466
|
+
endedAt,
|
|
467
|
+
durationMs,
|
|
468
|
+
journalPath,
|
|
469
|
+
before: repoBefore,
|
|
470
|
+
after: snapshotRepo(cwd),
|
|
471
|
+
agents: Array.from(agentProofs.values()),
|
|
472
|
+
evidence: evidenceRecords,
|
|
473
|
+
harnessEvidence: opts.harnessEvidence,
|
|
474
|
+
error: (err as Error).message,
|
|
475
|
+
});
|
|
476
|
+
writeWorkflowProof(proofPath, proof);
|
|
477
|
+
} catch (proofError) {
|
|
478
|
+
throw new WorkflowRunError(
|
|
479
|
+
`${(err as Error).message}; proof packet write also failed: ${(proofError as Error).message}`,
|
|
480
|
+
runId,
|
|
481
|
+
proofPath,
|
|
482
|
+
err,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
throw new WorkflowRunError((err as Error).message, runId, proofPath, err);
|
|
329
486
|
}
|
|
330
487
|
}
|
|
331
488
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export { runWorkflow, WorkflowRunError } from "./engine.ts";
|
|
2
|
+
export {
|
|
3
|
+
buildWorkflowProof,
|
|
4
|
+
createEvidenceRecord,
|
|
5
|
+
digestResult,
|
|
6
|
+
normalizeWorkflowMeta,
|
|
7
|
+
readWorkflowProof,
|
|
8
|
+
renderWorkflowProof,
|
|
9
|
+
rollupAcceptance,
|
|
10
|
+
writeWorkflowProof,
|
|
11
|
+
} from "./proof.ts";
|
|
12
|
+
export type {
|
|
13
|
+
AcceptanceCriterion,
|
|
14
|
+
AcceptanceResult,
|
|
15
|
+
AcceptanceStatus,
|
|
16
|
+
AcceptanceSummary,
|
|
17
|
+
AgentOpts,
|
|
18
|
+
EngineOpts,
|
|
19
|
+
EvidenceKind,
|
|
20
|
+
EvidenceSource,
|
|
21
|
+
EvidenceStatus,
|
|
22
|
+
HarnessEvidenceCapability,
|
|
23
|
+
HarnessEvidenceCoverage,
|
|
24
|
+
HarnessName,
|
|
25
|
+
ResultDigest,
|
|
26
|
+
RunReport,
|
|
27
|
+
Spawner,
|
|
28
|
+
SpawnRequest,
|
|
29
|
+
SpawnResult,
|
|
30
|
+
StageSchema,
|
|
31
|
+
WorkflowAgentProof,
|
|
32
|
+
WorkflowContext,
|
|
33
|
+
WorkflowEvidenceInput,
|
|
34
|
+
WorkflowEvidenceRecord,
|
|
35
|
+
WorkflowMeta,
|
|
36
|
+
WorkflowModule,
|
|
37
|
+
WorkflowProof,
|
|
38
|
+
WorkflowProofUnknown,
|
|
39
|
+
WorkflowRepoEvidence,
|
|
40
|
+
WorkflowRepoSnapshot,
|
|
41
|
+
WorkflowRunStatus,
|
|
42
|
+
} from "./types.ts";
|
|
43
|
+
export { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.ts";
|