harnery 0.9.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/README.md +1 -0
- package/dist/commander.d.ts.map +1 -1
- package/dist/commander.js +6 -0
- package/dist/commands/agents.d.ts +24 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +244 -13
- package/dist/commands/backup.d.ts +5 -4
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +15 -14
- package/dist/commands/browse.d.ts.map +1 -1
- package/dist/commands/browse.js +27 -1
- package/dist/commands/claude-desktop.d.ts +19 -0
- package/dist/commands/claude-desktop.d.ts.map +1 -0
- package/dist/commands/claude-desktop.js +168 -0
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +149 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +2 -3
- package/dist/commands/eml.d.ts +32 -0
- package/dist/commands/eml.d.ts.map +1 -1
- package/dist/commands/eml.js +16 -3
- package/dist/commands/harness.d.ts +11 -0
- package/dist/commands/harness.d.ts.map +1 -0
- package/dist/commands/harness.js +118 -0
- package/dist/commands/presence.d.ts +9 -4
- package/dist/commands/presence.d.ts.map +1 -1
- package/dist/commands/presence.js +88 -5
- package/dist/commands/relay.d.ts +9 -0
- package/dist/commands/relay.d.ts.map +1 -0
- package/dist/commands/relay.js +143 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +5 -0
- package/dist/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +53 -17
- package/dist/core/agents/canonical-emit.d.ts +15 -0
- package/dist/core/agents/canonical-emit.d.ts.map +1 -1
- package/dist/core/agents/canonical-emit.js +41 -3
- package/dist/core/agents/cli.js +4 -2
- package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
- package/dist/core/agents/render/prompt-context.js +44 -3
- package/dist/core/agents/render/session-context.d.ts.map +1 -1
- package/dist/core/agents/render/session-context.js +26 -1
- package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
- package/dist/core/agents/rules/commit-conflict.js +4 -37
- package/dist/core/agents/session-events.d.ts.map +1 -1
- package/dist/core/agents/session-events.js +16 -43
- package/dist/core/agents/state/heartbeat-projector.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-projector.js +11 -2
- package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
- package/dist/core/agents/state/heartbeat-writer.js +3 -3
- package/dist/core/agents/state/names.d.ts +38 -3
- package/dist/core/agents/state/names.d.ts.map +1 -1
- package/dist/core/agents/state/names.js +46 -7
- package/dist/core/agents/state/pidmap.d.ts +5 -1
- package/dist/core/agents/state/pidmap.d.ts.map +1 -1
- package/dist/core/agents/state/pidmap.js +58 -2
- package/dist/core/agents/state/stale-sweep.d.ts +3 -2
- package/dist/core/agents/state/stale-sweep.d.ts.map +1 -1
- package/dist/core/agents/state/stale-sweep.js +6 -6
- package/dist/core/config.d.ts +68 -11
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +191 -25
- package/dist/core/context/index.d.ts +144 -0
- package/dist/core/context/index.d.ts.map +1 -0
- package/dist/core/context/index.js +380 -0
- package/dist/core/harnesses/bench.d.ts +29 -0
- package/dist/core/harnesses/bench.d.ts.map +1 -0
- package/dist/core/harnesses/bench.js +151 -0
- package/dist/core/harnesses/index.d.ts +9 -0
- package/dist/core/harnesses/index.d.ts.map +1 -0
- package/dist/core/harnesses/index.js +4 -0
- package/dist/core/harnesses/profiles.d.ts +62 -0
- package/dist/core/harnesses/profiles.d.ts.map +1 -0
- package/dist/core/harnesses/profiles.js +115 -0
- package/dist/core/harnesses/registry.d.ts +15 -0
- package/dist/core/harnesses/registry.d.ts.map +1 -0
- package/dist/core/harnesses/registry.js +113 -0
- package/dist/core/harnesses/types.d.ts +64 -0
- package/dist/core/harnesses/types.d.ts.map +1 -0
- package/dist/core/harnesses/types.js +20 -0
- package/dist/core/hooks/cli.js +280 -63
- package/dist/core/hooks/events/schema.d.ts +38 -1
- package/dist/core/hooks/events/schema.d.ts.map +1 -1
- package/dist/core/hooks/harness/events.d.ts.map +1 -1
- package/dist/core/hooks/harness/events.js +3 -0
- package/dist/core/hooks/harness/parse.d.ts +1 -1
- package/dist/core/hooks/harness/parse.d.ts.map +1 -1
- package/dist/core/hooks/harness/parse.js +4 -0
- package/dist/core/presence/blob.d.ts +40 -0
- package/dist/core/presence/blob.d.ts.map +1 -0
- package/dist/core/presence/blob.js +91 -0
- package/dist/core/presence/git.d.ts +68 -0
- package/dist/core/presence/git.d.ts.map +1 -0
- package/dist/core/presence/git.js +173 -0
- package/dist/core/presence/index.d.ts +74 -0
- package/dist/core/presence/index.d.ts.map +1 -0
- package/dist/core/presence/index.js +224 -0
- package/dist/core/presence/relay-client.d.ts +39 -0
- package/dist/core/presence/relay-client.d.ts.map +1 -0
- package/dist/core/presence/relay-client.js +295 -0
- package/dist/core/presence/relay-protocol.d.ts +94 -0
- package/dist/core/presence/relay-protocol.d.ts.map +1 -0
- package/dist/core/presence/relay-protocol.js +169 -0
- package/dist/core/workflow/billing.d.ts +1 -1
- package/dist/core/workflow/billing.d.ts.map +1 -1
- package/dist/core/workflow/billing.js +7 -1
- 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 +164 -16
- package/dist/core/workflow/harnesses.d.ts +3 -3
- package/dist/core/workflow/harnesses.d.ts.map +1 -1
- package/dist/core/workflow/harnesses.js +8 -17
- 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/spawn-claude.d.ts +4 -1
- package/dist/core/workflow/spawn-claude.d.ts.map +1 -1
- package/dist/core/workflow/spawn-claude.js +39 -18
- package/dist/core/workflow/spawn-codex.d.ts +4 -1
- package/dist/core/workflow/spawn-codex.d.ts.map +1 -1
- package/dist/core/workflow/spawn-codex.js +44 -22
- package/dist/core/workflow/spawn-cursor.d.ts +4 -1
- package/dist/core/workflow/spawn-cursor.d.ts.map +1 -1
- package/dist/core/workflow/spawn-cursor.js +35 -16
- package/dist/core/workflow/types.d.ts +156 -2
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/types.js +1 -1
- package/dist/lib/browser/client.d.ts +16 -0
- package/dist/lib/browser/client.d.ts.map +1 -1
- package/dist/lib/browser/client.js +22 -0
- package/dist/lib/browser/index.d.ts +1 -0
- package/dist/lib/browser/index.d.ts.map +1 -1
- package/dist/lib/browser/index.js +1 -0
- package/dist/lib/browser/launch-args.d.ts +21 -0
- package/dist/lib/browser/launch-args.d.ts.map +1 -0
- package/dist/lib/browser/launch-args.js +32 -0
- package/dist/lib/claude-desktop.d.ts +105 -0
- package/dist/lib/claude-desktop.d.ts.map +1 -0
- package/dist/lib/claude-desktop.js +217 -0
- package/dist/lib/docs-lint.d.ts.map +1 -1
- package/dist/lib/docs-lint.js +5 -2
- package/dist/lib/identities/assume.d.ts +51 -0
- package/dist/lib/identities/assume.d.ts.map +1 -0
- package/dist/lib/identities/assume.js +274 -0
- package/dist/lib/identities/index.d.ts +7 -7
- package/dist/lib/identities/index.d.ts.map +1 -1
- package/dist/lib/identities/index.js +24 -24
- package/dist/lib/instructions/templates.d.ts.map +1 -1
- package/dist/lib/instructions/templates.js +15 -2
- package/package.json +22 -6
- package/schemas/config.schema.json +88 -19
- package/src/commander.ts +6 -0
- package/src/commands/agents.ts +280 -14
- package/src/commands/backup.ts +17 -16
- package/src/commands/browse.ts +32 -0
- package/src/commands/claude-desktop.ts +215 -0
- package/src/commands/context.ts +174 -1
- package/src/commands/doctor.ts +2 -3
- package/src/commands/eml.ts +22 -4
- package/src/commands/harness.ts +147 -0
- package/src/commands/presence.ts +111 -5
- package/src/commands/relay.ts +160 -0
- package/src/commands/sync.ts +4 -0
- package/src/commands/workflow.ts +62 -19
- package/src/core/agents/canonical-emit.ts +41 -3
- package/src/core/agents/cli.ts +4 -2
- package/src/core/agents/render/prompt-context.ts +48 -3
- package/src/core/agents/render/session-context.ts +27 -1
- package/src/core/agents/rules/commit-conflict.ts +4 -33
- package/src/core/agents/session-events.ts +15 -39
- package/src/core/agents/state/heartbeat-projector.ts +10 -1
- package/src/core/agents/state/heartbeat-writer.ts +3 -2
- package/src/core/agents/state/names.ts +68 -9
- package/src/core/agents/state/pidmap.ts +59 -2
- package/src/core/agents/state/stale-sweep.ts +6 -11
- package/src/core/config.ts +248 -24
- package/src/core/context/index.ts +575 -0
- package/src/core/harnesses/bench.ts +214 -0
- package/src/core/harnesses/index.ts +31 -0
- package/src/core/harnesses/profiles.ts +141 -0
- package/src/core/harnesses/registry.ts +140 -0
- package/src/core/harnesses/types.ts +90 -0
- package/src/core/hooks/cli.ts +331 -62
- package/src/core/hooks/events/schema.ts +68 -0
- package/src/core/hooks/harness/events.ts +3 -0
- package/src/core/hooks/harness/parse.ts +7 -1
- package/src/core/presence/blob.ts +125 -0
- package/src/core/presence/git.ts +191 -0
- package/src/core/presence/index.ts +274 -0
- package/src/core/presence/relay-client.ts +322 -0
- package/src/core/presence/relay-protocol.ts +246 -0
- package/src/core/workflow/billing.ts +8 -2
- package/src/core/workflow/engine.ts +182 -16
- package/src/core/workflow/harnesses.ts +14 -19
- package/src/core/workflow/index.ts +43 -0
- package/src/core/workflow/proof.ts +434 -0
- package/src/core/workflow/spawn-claude.ts +39 -20
- package/src/core/workflow/spawn-codex.ts +47 -28
- package/src/core/workflow/spawn-cursor.ts +37 -18
- package/src/core/workflow/types.ts +176 -2
- package/src/lib/browser/client.ts +37 -0
- package/src/lib/browser/index.ts +1 -0
- package/src/lib/browser/launch-args.ts +33 -0
- package/src/lib/claude-desktop.ts +293 -0
- package/src/lib/docs-lint.ts +5 -2
- package/src/lib/identities/assume.ts +363 -0
- package/src/lib/identities/index.ts +28 -24
- package/src/lib/instructions/templates.ts +16 -2
|
@@ -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,15 +153,36 @@ 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
|
-
// Call identity for resume: same stage + harness + model + turns + schema
|
|
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.
|
|
126
172
|
const key = agentCallKey(currentStage, harness, agentOpts, prompt);
|
|
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
|
);
|
|
@@ -187,21 +243,33 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
187
243
|
|
|
188
244
|
await acquire();
|
|
189
245
|
try {
|
|
190
|
-
journal("agent.start", {
|
|
246
|
+
journal("agent.start", {
|
|
247
|
+
id,
|
|
248
|
+
label,
|
|
249
|
+
key,
|
|
250
|
+
harness,
|
|
251
|
+
model: agentOpts.model ?? null,
|
|
252
|
+
effort: agentOpts.effort ?? null,
|
|
253
|
+
});
|
|
191
254
|
log(`[${name}] ${currentStage || "(no stage)"} → ${id} [${harness}] ${label}`);
|
|
192
255
|
|
|
193
256
|
let attemptPrompt = prompt;
|
|
194
257
|
let last: SpawnResult | null = null;
|
|
258
|
+
let agentCostUsd = 0;
|
|
195
259
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
196
260
|
last = await spawner({
|
|
197
261
|
prompt: attemptPrompt,
|
|
198
262
|
model: agentOpts.model,
|
|
263
|
+
effort: agentOpts.effort,
|
|
199
264
|
timeoutMs: agentOpts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
200
265
|
maxTurns: agentOpts.maxTurns ?? DEFAULT_MAX_TURNS,
|
|
201
266
|
cwd,
|
|
202
267
|
runId,
|
|
203
268
|
subscriptionOnly: opts.subscriptionOnly,
|
|
204
269
|
});
|
|
270
|
+
agentProof.attempts = attempt;
|
|
271
|
+
agentProof.duration_ms += last.durationMs;
|
|
272
|
+
agentCostUsd += last.costUsd ?? 0;
|
|
205
273
|
costUsd += last.costUsd ?? 0;
|
|
206
274
|
|
|
207
275
|
if (!last.ok) {
|
|
@@ -209,6 +277,11 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
209
277
|
continue; // spawn-level failure: retry with the original prompt
|
|
210
278
|
}
|
|
211
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");
|
|
212
285
|
journal("agent.end", {
|
|
213
286
|
id,
|
|
214
287
|
key,
|
|
@@ -228,6 +301,11 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
228
301
|
? [parsed.error]
|
|
229
302
|
: validateAgainstSchema(parsed.value, agentOpts.schema);
|
|
230
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");
|
|
231
309
|
journal("agent.end", {
|
|
232
310
|
id,
|
|
233
311
|
key,
|
|
@@ -253,8 +331,15 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
253
331
|
const reason = last?.ok
|
|
254
332
|
? `schema validation failed after ${maxAttempts} attempt(s)`
|
|
255
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;
|
|
256
338
|
journal("agent.failed", { id, error: reason });
|
|
257
|
-
throw new Error(`agent ${
|
|
339
|
+
throw new Error(`agent ${proofLabel}: ${reason}`);
|
|
340
|
+
} catch (error) {
|
|
341
|
+
agentProof.error ??= (error as Error).message;
|
|
342
|
+
throw error;
|
|
258
343
|
} finally {
|
|
259
344
|
release();
|
|
260
345
|
}
|
|
@@ -280,12 +365,68 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
280
365
|
log(`[${name}] ── stage: ${title}`);
|
|
281
366
|
};
|
|
282
367
|
|
|
283
|
-
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 };
|
|
284
382
|
|
|
285
383
|
const t0 = Date.now();
|
|
286
|
-
|
|
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
|
+
});
|
|
287
393
|
try {
|
|
288
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
|
+
}
|
|
289
430
|
const report: RunReport = {
|
|
290
431
|
runId,
|
|
291
432
|
name,
|
|
@@ -293,31 +434,55 @@ export async function runWorkflow(scriptPath: string, opts: EngineOpts): Promise
|
|
|
293
434
|
agentsSpawned,
|
|
294
435
|
agentsCached,
|
|
295
436
|
costUsd: round4(costUsd),
|
|
296
|
-
durationMs
|
|
437
|
+
durationMs,
|
|
297
438
|
journalPath,
|
|
439
|
+
proofPath,
|
|
440
|
+
acceptance: proof.acceptance.summary,
|
|
298
441
|
contextTokensPerChildEstimate,
|
|
299
442
|
billing: Array.from(billingProbed.values()).map((p) => ({
|
|
300
443
|
harness: p.harness,
|
|
301
444
|
mode: opts.subscriptionOnly ? "subscription" : p.mode,
|
|
302
445
|
})),
|
|
303
446
|
};
|
|
304
|
-
journal("run.end", {
|
|
305
|
-
ok: true,
|
|
306
|
-
agents: agentsSpawned,
|
|
307
|
-
cached: agentsCached,
|
|
308
|
-
cost_usd: report.costUsd,
|
|
309
|
-
duration_ms: report.durationMs,
|
|
310
|
-
});
|
|
311
447
|
return report;
|
|
312
448
|
} catch (err) {
|
|
449
|
+
if (err instanceof WorkflowRunError) throw err;
|
|
450
|
+
const endedAt = new Date().toISOString();
|
|
451
|
+
const durationMs = Date.now() - t0;
|
|
313
452
|
journal("run.end", {
|
|
314
453
|
ok: false,
|
|
315
454
|
error: (err as Error).message,
|
|
316
455
|
agents: agentsSpawned,
|
|
317
456
|
cached: agentsCached,
|
|
318
457
|
cost_usd: round4(costUsd),
|
|
458
|
+
duration_ms: durationMs,
|
|
319
459
|
});
|
|
320
|
-
|
|
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);
|
|
321
486
|
}
|
|
322
487
|
}
|
|
323
488
|
|
|
@@ -333,6 +498,7 @@ function agentCallKey(
|
|
|
333
498
|
stage,
|
|
334
499
|
harness,
|
|
335
500
|
agentOpts.model ?? null,
|
|
501
|
+
agentOpts.effort ?? null,
|
|
336
502
|
agentOpts.maxTurns ?? DEFAULT_MAX_TURNS,
|
|
337
503
|
agentOpts.schema ?? null,
|
|
338
504
|
prompt,
|
|
@@ -7,32 +7,27 @@
|
|
|
7
7
|
* but they do drift — keep this module the single place they live.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { BUILTIN_HARNESS_PROFILES } from "../harnesses/profiles.ts";
|
|
10
11
|
import type { HarnessName } from "./types.ts";
|
|
11
12
|
|
|
12
|
-
export const HARNESS_BINARIES: Record<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
cursor: "cursor-agent",
|
|
16
|
-
};
|
|
13
|
+
export const HARNESS_BINARIES: Record<string, string> = Object.fromEntries(
|
|
14
|
+
Object.values(BUILTIN_HARNESS_PROFILES).map((profile) => [profile.id, profile.binary]),
|
|
15
|
+
);
|
|
17
16
|
|
|
18
|
-
export const HARNESS_INSTALL_HINTS: Record<
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
cursor: "curl https://cursor.com/install -fsS | bash",
|
|
22
|
-
};
|
|
17
|
+
export const HARNESS_INSTALL_HINTS: Record<string, string> = Object.fromEntries(
|
|
18
|
+
Object.values(BUILTIN_HARNESS_PROFILES).map((profile) => [profile.id, profile.installHint]),
|
|
19
|
+
);
|
|
23
20
|
|
|
24
21
|
/** How to authenticate each CLI with a subscription login (the billing
|
|
25
22
|
* default — see billing.ts). */
|
|
26
|
-
export const HARNESS_LOGIN_HINTS: Record<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
cursor: "cursor-agent login",
|
|
30
|
-
};
|
|
23
|
+
export const HARNESS_LOGIN_HINTS: Record<string, string> = Object.fromEntries(
|
|
24
|
+
Object.values(BUILTIN_HARNESS_PROFILES).map((profile) => [profile.id, profile.loginHint]),
|
|
25
|
+
);
|
|
31
26
|
|
|
32
27
|
/** One-line "it's missing, here's the fix" string for spawn adapters. */
|
|
33
28
|
export function notFoundError(harness: HarnessName): string {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
const binary = HARNESS_BINARIES[harness] ?? harness;
|
|
30
|
+
const install = HARNESS_INSTALL_HINTS[harness] ?? "install the harness CLI";
|
|
31
|
+
const login = HARNESS_LOGIN_HINTS[harness] ?? "authenticate the harness CLI";
|
|
32
|
+
return `${binary} CLI not found on PATH; ` + `install: ${install} then authenticate: ${login}`;
|
|
38
33
|
}
|
|
@@ -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";
|