harnery 0.22.1 → 0.23.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/commands/workflow.d.ts.map +1 -1
- package/dist/commands/workflow.js +91 -2
- package/dist/core/work/state.d.ts +7 -0
- package/dist/core/work/state.d.ts.map +1 -1
- package/dist/core/work/state.js +112 -23
- package/dist/core/workflow/child-env.d.ts +10 -6
- package/dist/core/workflow/child-env.d.ts.map +1 -1
- package/dist/core/workflow/child-env.js +15 -7
- package/dist/core/workflow/durable-record.d.ts +7 -0
- package/dist/core/workflow/durable-record.d.ts.map +1 -0
- package/dist/core/workflow/durable-record.js +83 -0
- package/dist/core/workflow/engine.d.ts.map +1 -1
- package/dist/core/workflow/engine.js +208 -29
- package/dist/core/workflow/index.d.ts +2 -0
- package/dist/core/workflow/index.d.ts.map +1 -1
- package/dist/core/workflow/index.js +1 -0
- package/dist/core/workflow/proof.d.ts +4 -0
- package/dist/core/workflow/proof.d.ts.map +1 -1
- package/dist/core/workflow/proof.js +50 -15
- package/dist/core/workflow/run-state.d.ts +3 -0
- package/dist/core/workflow/run-state.d.ts.map +1 -1
- package/dist/core/workflow/run-state.js +25 -13
- package/dist/core/workflow/types.d.ts +10 -0
- package/dist/core/workflow/types.d.ts.map +1 -1
- package/dist/core/workflow/workspaces/attestation-error.d.ts +7 -0
- package/dist/core/workflow/workspaces/attestation-error.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/attestation-error.js +25 -0
- package/dist/core/workflow/workspaces/cancellation.d.ts +8 -0
- package/dist/core/workflow/workspaces/cancellation.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/cancellation.js +95 -0
- package/dist/core/workflow/workspaces/cleanup.d.ts +9 -0
- package/dist/core/workflow/workspaces/cleanup.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/cleanup.js +223 -0
- package/dist/core/workflow/workspaces/execution.d.ts +25 -0
- package/dist/core/workflow/workspaces/execution.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/execution.js +316 -0
- package/dist/core/workflow/workspaces/git.d.ts +25 -0
- package/dist/core/workflow/workspaces/git.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/git.js +102 -0
- package/dist/core/workflow/workspaces/index.d.ts +15 -0
- package/dist/core/workflow/workspaces/index.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/index.js +7 -0
- package/dist/core/workflow/workspaces/inspect.d.ts +85 -0
- package/dist/core/workflow/workspaces/inspect.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/inspect.js +255 -0
- package/dist/core/workflow/workspaces/integration.d.ts +24 -0
- package/dist/core/workflow/workspaces/integration.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/integration.js +617 -0
- package/dist/core/workflow/workspaces/leases.d.ts +37 -0
- package/dist/core/workflow/workspaces/leases.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/leases.js +380 -0
- package/dist/core/workflow/workspaces/lifecycle.d.ts +43 -0
- package/dist/core/workflow/workspaces/lifecycle.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/lifecycle.js +622 -0
- package/dist/core/workflow/workspaces/local-git.d.ts +8 -0
- package/dist/core/workflow/workspaces/local-git.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/local-git.js +1474 -0
- package/dist/core/workflow/workspaces/paths.d.ts +23 -0
- package/dist/core/workflow/workspaces/paths.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/paths.js +191 -0
- package/dist/core/workflow/workspaces/recovery.d.ts +3 -0
- package/dist/core/workflow/workspaces/recovery.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/recovery.js +50 -0
- package/dist/core/workflow/workspaces/state.d.ts +60 -0
- package/dist/core/workflow/workspaces/state.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/state.js +296 -0
- package/dist/core/workflow/workspaces/types.d.ts +445 -0
- package/dist/core/workflow/workspaces/types.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/types.js +2 -0
- package/dist/core/workflow/workspaces/validate.d.ts +14 -0
- package/dist/core/workflow/workspaces/validate.d.ts.map +1 -0
- package/dist/core/workflow/workspaces/validate.js +476 -0
- package/package.json +5 -3
- package/src/commands/workflow.ts +110 -4
- package/src/core/work/state.ts +156 -28
- package/src/core/workflow/child-env.ts +18 -7
- package/src/core/workflow/durable-record.ts +94 -0
- package/src/core/workflow/engine.ts +230 -30
- package/src/core/workflow/index.ts +73 -0
- package/src/core/workflow/proof.ts +70 -22
- package/src/core/workflow/run-state.ts +46 -11
- package/src/core/workflow/types.ts +14 -0
- package/src/core/workflow/workspaces/attestation-error.ts +30 -0
- package/src/core/workflow/workspaces/cancellation.ts +137 -0
- package/src/core/workflow/workspaces/cleanup.ts +308 -0
- package/src/core/workflow/workspaces/execution.ts +412 -0
- package/src/core/workflow/workspaces/git.ts +125 -0
- package/src/core/workflow/workspaces/index.ts +85 -0
- package/src/core/workflow/workspaces/inspect.ts +421 -0
- package/src/core/workflow/workspaces/integration.ts +829 -0
- package/src/core/workflow/workspaces/leases.ts +495 -0
- package/src/core/workflow/workspaces/lifecycle.ts +792 -0
- package/src/core/workflow/workspaces/local-git.ts +1892 -0
- package/src/core/workflow/workspaces/paths.ts +247 -0
- package/src/core/workflow/workspaces/recovery.ts +56 -0
- package/src/core/workflow/workspaces/state.ts +481 -0
- package/src/core/workflow/workspaces/types.ts +517 -0
- package/src/core/workflow/workspaces/validate.ts +595 -0
|
@@ -33,12 +33,16 @@ import { evaluatePolicy, normalizePolicy, PolicyDeniedError, policyDigest, summa
|
|
|
33
33
|
import { assertWorkflowRunId, createWorkflowApproval } from "./approvals.js";
|
|
34
34
|
import { freezeWorkflowAttemptContext } from "./attempt-context.js";
|
|
35
35
|
import { probeBilling } from "./billing.js";
|
|
36
|
+
import { stableDigest } from "./durable-record.js";
|
|
36
37
|
import { buildWorkflowProof, createEvidenceRecord, digestResult, normalizeWorkflowMeta, writeWorkflowProof, } from "./proof.js";
|
|
37
38
|
import { acquireWorkflowResumeLease, assertWorkflowRunResumable, assertWorkflowScriptUnchanged, workflowScriptDigest, writeWorkflowRunManifest, } from "./run-state.js";
|
|
38
39
|
import { normalizeWorkflowSpecialists, resolveSpecialistAssignment } from "./specialists.js";
|
|
39
40
|
import { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.js";
|
|
40
41
|
import { parseStageOutput, validateAgainstSchema } from "./validate.js";
|
|
41
42
|
import { freezeWorkflowWorkContext } from "./work-context.js";
|
|
43
|
+
import { attestTerminal, attestWorkspaceFailure, resolveWorkspaceBinding, } from "./workspaces/execution.js";
|
|
44
|
+
import { appendWorkflowJournalEvent } from "./workspaces/state.js";
|
|
45
|
+
import { isWorkspaceAttestation } from "./workspaces/validate.js";
|
|
42
46
|
const DEFAULT_MAX_AGENTS = 50;
|
|
43
47
|
const DEFAULT_CONCURRENCY = 4;
|
|
44
48
|
const DEFAULT_MAX_ATTEMPTS = 2;
|
|
@@ -136,13 +140,19 @@ export async function runWorkflow(scriptPath, opts) {
|
|
|
136
140
|
}
|
|
137
141
|
}
|
|
138
142
|
async function executeWorkflow(scriptPath, absScript, opts, resumeState, workContext, attemptContext) {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
const frozen = resumeState?.manifest.execution;
|
|
144
|
+
const isolation = frozen?.isolation ?? opts.isolation ?? "shared";
|
|
145
|
+
let sharedWorkflow;
|
|
146
|
+
let sharedMeta;
|
|
147
|
+
if (isolation === "shared") {
|
|
148
|
+
const mod = (await import(__rewriteRelativeImportExtension(pathToFileURL(absScript).href)));
|
|
149
|
+
if (typeof mod.default !== "function") {
|
|
150
|
+
throw new Error(`${scriptPath}: workflow script must \`export default async (ctx) => …\``);
|
|
151
|
+
}
|
|
152
|
+
const fallbackName = scriptPath.replace(/^.*\//, "").replace(/\.[cm]?js$/, "");
|
|
153
|
+
sharedWorkflow = mod.default;
|
|
154
|
+
sharedMeta = normalizeWorkflowMeta(mod.meta, fallbackName);
|
|
142
155
|
}
|
|
143
|
-
const fallbackName = scriptPath.replace(/^.*\//, "").replace(/\.[cm]?js$/, "");
|
|
144
|
-
const meta = normalizeWorkflowMeta(mod.meta, fallbackName);
|
|
145
|
-
const name = meta.name;
|
|
146
156
|
const runId = opts.resumeRunId ??
|
|
147
157
|
opts.runId ??
|
|
148
158
|
`wf-${new Date().toISOString().replace(/[:.]/g, "-")}-${randomBytes(3).toString("hex")}`;
|
|
@@ -150,7 +160,6 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
150
160
|
mkdirSync(runDir, { recursive: true });
|
|
151
161
|
const journalPath = join(runDir, "journal.jsonl");
|
|
152
162
|
const proofPath = join(runDir, "proof.json");
|
|
153
|
-
const frozen = resumeState?.manifest.execution;
|
|
154
163
|
const maxAgents = frozen?.max_agents ?? opts.maxAgents ?? DEFAULT_MAX_AGENTS;
|
|
155
164
|
const concurrency = frozen?.concurrency ?? opts.concurrency ?? DEFAULT_CONCURRENCY;
|
|
156
165
|
assertPositiveWorkflowBound(maxAgents, "maxAgents");
|
|
@@ -159,16 +168,105 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
159
168
|
const log = opts.onLog ?? ((line) => process.stderr.write(`${line}\n`));
|
|
160
169
|
const defaultHarness = frozen?.default_harness ?? opts.defaultHarness ?? "claude-code";
|
|
161
170
|
const specialists = frozen?.specialists ?? (resumeState ? {} : normalizeWorkflowSpecialists(opts.specialists));
|
|
162
|
-
const isolation = frozen?.isolation ?? opts.isolation ?? "shared";
|
|
163
171
|
const networkAccess = frozen?.network_access ?? opts.networkAccess ?? "unknown";
|
|
164
172
|
const policy = frozen?.policy ?? (opts.policy ? normalizePolicy(opts.policy, { baseDir: cwd }) : undefined);
|
|
165
173
|
const approvalMode = frozen?.approval_mode ?? opts.approvalMode ?? "deny";
|
|
166
174
|
const approvalAddressee = frozen?.approval_addressee ?? opts.approvalAddressee ?? "operator";
|
|
167
175
|
const subscriptionOnly = frozen?.subscription_only ?? Boolean(opts.subscriptionOnly);
|
|
168
176
|
const allowApiBilling = frozen?.allow_api_billing ?? Boolean(opts.allowApiBilling);
|
|
169
|
-
const repoBefore = resumeState?.manifest.repository_before ?? snapshotRepo(cwd);
|
|
170
177
|
const startedAt = resumeState?.manifest.started_at ?? new Date().toISOString();
|
|
171
178
|
const t0 = resumeState ? Date.parse(startedAt) : Date.now();
|
|
179
|
+
const scriptSha256 = resumeState?.manifest.script.sha256 ?? workflowScriptDigest(absScript);
|
|
180
|
+
const fallbackName = scriptPath.replace(/^.*\//, "").replace(/\.[cm]?js$/, "");
|
|
181
|
+
const fallbackMeta = normalizeWorkflowMeta(undefined, fallbackName);
|
|
182
|
+
const workspaceProvider = isolation === "shared" ? undefined : opts.workspace?.provider;
|
|
183
|
+
let workspaceBinding;
|
|
184
|
+
let workspaceFallback = resumeState?.manifest.execution.workspace_fallback;
|
|
185
|
+
try {
|
|
186
|
+
workspaceBinding = await resolveWorkspaceBinding({
|
|
187
|
+
opts,
|
|
188
|
+
resumeState,
|
|
189
|
+
runId,
|
|
190
|
+
cwd,
|
|
191
|
+
isolation,
|
|
192
|
+
absScript,
|
|
193
|
+
scriptSha256,
|
|
194
|
+
provider: workspaceProvider,
|
|
195
|
+
workContext,
|
|
196
|
+
attemptContext,
|
|
197
|
+
policy,
|
|
198
|
+
onUnsupportedFallback: (evidence) => {
|
|
199
|
+
workspaceFallback = evidence;
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
const frozenBinding = resumeState?.manifest.execution.workspace_binding;
|
|
205
|
+
if (!resumeState || !frozenBinding)
|
|
206
|
+
throw error;
|
|
207
|
+
const failure = error instanceof Error ? error : new Error(String(error));
|
|
208
|
+
const endedAt = new Date().toISOString();
|
|
209
|
+
const durationMs = Date.now() - t0;
|
|
210
|
+
const failedAttestation = await attestWorkspaceFailure(workspaceProvider, frozenBinding, error);
|
|
211
|
+
appendWorkflowJournalEvent(opts.coordRoot, runId, "run.resume", {
|
|
212
|
+
approval_id: resumeState.approvalId,
|
|
213
|
+
script: absScript,
|
|
214
|
+
resumed_at: new Date().toISOString(),
|
|
215
|
+
});
|
|
216
|
+
appendWorkflowJournalEvent(opts.coordRoot, runId, "workspace.reattach.failed", {
|
|
217
|
+
binding_id: frozenBinding.binding_id,
|
|
218
|
+
provider_id: frozenBinding.provider.id,
|
|
219
|
+
status: failedAttestation.status,
|
|
220
|
+
reason: failure.message,
|
|
221
|
+
attestation_sha256: stableDigest(failedAttestation),
|
|
222
|
+
});
|
|
223
|
+
appendWorkflowJournalEvent(opts.coordRoot, runId, "run.end", {
|
|
224
|
+
ok: false,
|
|
225
|
+
error: failure.message,
|
|
226
|
+
agents: 0,
|
|
227
|
+
cached: 0,
|
|
228
|
+
cost_usd: 0,
|
|
229
|
+
duration_ms: durationMs,
|
|
230
|
+
});
|
|
231
|
+
try {
|
|
232
|
+
const proof = buildWorkflowProof({
|
|
233
|
+
runId,
|
|
234
|
+
workItemId: opts.workItemId ?? resumeState.manifest.work_item_id,
|
|
235
|
+
workContext,
|
|
236
|
+
attemptContext,
|
|
237
|
+
meta: fallbackMeta,
|
|
238
|
+
status: "failed",
|
|
239
|
+
startedAt,
|
|
240
|
+
endedAt,
|
|
241
|
+
durationMs,
|
|
242
|
+
journalPath,
|
|
243
|
+
before: resumeState.manifest.repository_before,
|
|
244
|
+
after: resumeState.manifest.repository_before,
|
|
245
|
+
agents: [],
|
|
246
|
+
evidence: [],
|
|
247
|
+
harnessEvidence: opts.harnessEvidence,
|
|
248
|
+
policy: policy
|
|
249
|
+
? {
|
|
250
|
+
config: policy,
|
|
251
|
+
decisions: [],
|
|
252
|
+
isolation,
|
|
253
|
+
networkAccess,
|
|
254
|
+
}
|
|
255
|
+
: undefined,
|
|
256
|
+
workspaceBinding: frozenBinding,
|
|
257
|
+
workspaceAttestation: failedAttestation,
|
|
258
|
+
error: failure.message,
|
|
259
|
+
});
|
|
260
|
+
writeWorkflowProof(proofPath, proof);
|
|
261
|
+
}
|
|
262
|
+
catch (proofError) {
|
|
263
|
+
throw new WorkflowRunError(`${failure.message}; recovery proof packet write also failed: ${proofError.message}`, runId, proofPath, failure);
|
|
264
|
+
}
|
|
265
|
+
throw new WorkflowRunError(failure.message, runId, proofPath, failure);
|
|
266
|
+
}
|
|
267
|
+
const effectiveIsolation = workspaceFallback?.effective_isolation ?? isolation;
|
|
268
|
+
const executionCwd = workspaceBinding?.active_root ?? cwd;
|
|
269
|
+
const executionRepoBefore = resumeState?.manifest.repository_before ?? snapshotRepo(executionCwd);
|
|
172
270
|
if (!resumeState) {
|
|
173
271
|
writeWorkflowRunManifest({
|
|
174
272
|
coordRoot: opts.coordRoot,
|
|
@@ -178,12 +276,12 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
178
276
|
work_item_id: opts.workItemId,
|
|
179
277
|
work_context: workContext,
|
|
180
278
|
attempt_context: attemptContext,
|
|
181
|
-
name,
|
|
279
|
+
name: sharedMeta?.name ?? fallbackMeta.name,
|
|
182
280
|
started_at: startedAt,
|
|
183
|
-
script: { path: absScript, sha256:
|
|
184
|
-
repository_before:
|
|
281
|
+
script: { path: absScript, sha256: scriptSha256 },
|
|
282
|
+
repository_before: executionRepoBefore,
|
|
185
283
|
execution: {
|
|
186
|
-
cwd,
|
|
284
|
+
cwd: executionCwd,
|
|
187
285
|
default_harness: defaultHarness,
|
|
188
286
|
max_agents: maxAgents,
|
|
189
287
|
concurrency,
|
|
@@ -195,17 +293,70 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
195
293
|
network_access: networkAccess,
|
|
196
294
|
policy: policy ? policy : undefined,
|
|
197
295
|
specialists,
|
|
296
|
+
workspace_binding: workspaceBinding,
|
|
297
|
+
workspace_fallback: workspaceFallback,
|
|
198
298
|
},
|
|
199
299
|
},
|
|
200
300
|
});
|
|
201
301
|
}
|
|
302
|
+
let workflow = sharedWorkflow;
|
|
303
|
+
let meta = sharedMeta ?? fallbackMeta;
|
|
304
|
+
let initializationError;
|
|
305
|
+
let initializationAttestation;
|
|
306
|
+
if (isolation !== "shared") {
|
|
307
|
+
try {
|
|
308
|
+
const mod = (await import(__rewriteRelativeImportExtension(pathToFileURL(absScript).href)));
|
|
309
|
+
if (typeof mod.default !== "function") {
|
|
310
|
+
throw new Error(`${scriptPath}: workflow script must \`export default async (ctx) => …\``);
|
|
311
|
+
}
|
|
312
|
+
workflow = mod.default;
|
|
313
|
+
meta = normalizeWorkflowMeta(mod.meta, fallbackName);
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
initializationError = error instanceof Error ? error : new Error(String(error));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (workspaceBinding && workspaceProvider) {
|
|
320
|
+
try {
|
|
321
|
+
const postImport = await workspaceProvider.reattach(workspaceBinding);
|
|
322
|
+
if (!isWorkspaceAttestation(postImport, workspaceBinding) || postImport.status !== "ok") {
|
|
323
|
+
initializationAttestation = isWorkspaceAttestation(postImport, workspaceBinding)
|
|
324
|
+
? postImport
|
|
325
|
+
: undefined;
|
|
326
|
+
throw new Error("workspace authority changed during workflow module initialization");
|
|
327
|
+
}
|
|
328
|
+
appendWorkflowJournalEvent(opts.coordRoot, runId, "workspace.reattach.module_initialized", {
|
|
329
|
+
binding_id: workspaceBinding.binding_id,
|
|
330
|
+
provider_id: workspaceBinding.provider.id,
|
|
331
|
+
attestation_sha256: stableDigest(postImport),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
const reattachmentError = error instanceof Error ? error : new Error(String(error));
|
|
336
|
+
initializationAttestation ??= await attestWorkspaceFailure(workspaceProvider, workspaceBinding, error);
|
|
337
|
+
initializationError = initializationError
|
|
338
|
+
? new Error(`${initializationError.message}; ${reattachmentError.message}`, {
|
|
339
|
+
cause: reattachmentError,
|
|
340
|
+
})
|
|
341
|
+
: reattachmentError;
|
|
342
|
+
appendWorkflowJournalEvent(opts.coordRoot, runId, "workspace.reattach.module_initialization_failed", {
|
|
343
|
+
binding_id: workspaceBinding.binding_id,
|
|
344
|
+
provider_id: workspaceBinding.provider.id,
|
|
345
|
+
status: initializationAttestation.status,
|
|
346
|
+
reason: reattachmentError.message,
|
|
347
|
+
attestation_sha256: stableDigest(initializationAttestation),
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const name = meta.name;
|
|
352
|
+
let observedWorkspaceAttestation = initializationAttestation;
|
|
202
353
|
// Per-child fixed context overhead: children spawn in `cwd` and load its
|
|
203
354
|
// repo-instructions file into their system prompt, cache-writing it once
|
|
204
355
|
// per child. A fan-out multiplies this, so surface it BEFORE the burn.
|
|
205
|
-
const contextTokensPerChildEstimate = estimateInstructionTokens(
|
|
356
|
+
const contextTokensPerChildEstimate = estimateInstructionTokens(executionCwd);
|
|
206
357
|
if (contextTokensPerChildEstimate > 0) {
|
|
207
358
|
log(`[context] each child cache-writes ~${Math.round(contextTokensPerChildEstimate / 1000)}K tokens of repo ` +
|
|
208
|
-
`instructions from ${
|
|
359
|
+
`instructions from ${executionCwd}; a fan-out multiplies this per agent`);
|
|
209
360
|
}
|
|
210
361
|
// Resume: journaled results of a prior run, keyed by agent-call identity.
|
|
211
362
|
const resumeSource = opts.resumeRunId ?? opts.resumeFrom;
|
|
@@ -434,7 +585,7 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
434
585
|
const estimateRequest = summarizePolicyRequest({
|
|
435
586
|
phase: "dispatch",
|
|
436
587
|
action: "spawn agent",
|
|
437
|
-
path:
|
|
588
|
+
path: executionCwd,
|
|
438
589
|
harness,
|
|
439
590
|
model: agentOpts.model,
|
|
440
591
|
effort: agentOpts.effort,
|
|
@@ -442,7 +593,7 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
442
593
|
max_turns: agentOpts.maxTurns ?? DEFAULT_MAX_TURNS,
|
|
443
594
|
timeout_ms: agentOpts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
444
595
|
prompt_bytes: Buffer.byteLength(dispatchPrompt),
|
|
445
|
-
isolation,
|
|
596
|
+
isolation: effectiveIsolation,
|
|
446
597
|
network_access: networkAccess,
|
|
447
598
|
current_cost_usd: round4(costUsd + reservedCostUsd),
|
|
448
599
|
projected_cost_usd: null,
|
|
@@ -571,7 +722,7 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
571
722
|
effort: agentOpts.effort,
|
|
572
723
|
timeoutMs: agentOpts.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
573
724
|
maxTurns: agentOpts.maxTurns ?? DEFAULT_MAX_TURNS,
|
|
574
|
-
cwd,
|
|
725
|
+
cwd: executionCwd,
|
|
575
726
|
runId,
|
|
576
727
|
subscriptionOnly,
|
|
577
728
|
});
|
|
@@ -689,8 +840,8 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
689
840
|
return authorizePolicyRequest({
|
|
690
841
|
phase: "external_mutation",
|
|
691
842
|
action: input.action,
|
|
692
|
-
path: input.path ? resolve(
|
|
693
|
-
isolation,
|
|
843
|
+
path: input.path ? resolve(executionCwd, input.path) : undefined,
|
|
844
|
+
isolation: effectiveIsolation,
|
|
694
845
|
network_access: network,
|
|
695
846
|
service: input.service,
|
|
696
847
|
target: input.target,
|
|
@@ -728,13 +879,27 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
728
879
|
concurrency,
|
|
729
880
|
specialists: Object.keys(specialists),
|
|
730
881
|
policy: policy ? { name: policy.name, sha256: policyDigest(policy) } : null,
|
|
731
|
-
isolation,
|
|
882
|
+
isolation: effectiveIsolation,
|
|
732
883
|
network_access: networkAccess,
|
|
884
|
+
workspace_binding: workspaceBinding
|
|
885
|
+
? { binding_id: workspaceBinding.binding_id, provider_id: workspaceBinding.provider.id }
|
|
886
|
+
: null,
|
|
733
887
|
});
|
|
734
888
|
}
|
|
735
|
-
|
|
889
|
+
if (initializationError)
|
|
890
|
+
throw initializationError;
|
|
891
|
+
if (!workflow)
|
|
892
|
+
throw new Error("workflow module initialization did not produce an executable");
|
|
893
|
+
const result = await workflow(ctx);
|
|
736
894
|
const endedAt = new Date().toISOString();
|
|
737
895
|
const durationMs = Date.now() - t0;
|
|
896
|
+
const workspaceAttestation = workspaceBinding
|
|
897
|
+
? await attestTerminal(workspaceProvider, workspaceBinding)
|
|
898
|
+
: undefined;
|
|
899
|
+
observedWorkspaceAttestation = workspaceAttestation;
|
|
900
|
+
if (workspaceAttestation && workspaceAttestation.status !== "ok") {
|
|
901
|
+
throw new Error(`terminal workspace attestation ${workspaceAttestation.status}: ${workspaceAttestation.provider_drift.join("; ") || "provider could not prove the workspace"}`);
|
|
902
|
+
}
|
|
738
903
|
journal("run.end", {
|
|
739
904
|
ok: true,
|
|
740
905
|
agents: agentsSpawned,
|
|
@@ -755,8 +920,8 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
755
920
|
endedAt,
|
|
756
921
|
durationMs,
|
|
757
922
|
journalPath,
|
|
758
|
-
before:
|
|
759
|
-
after: snapshotRepo(
|
|
923
|
+
before: executionRepoBefore,
|
|
924
|
+
after: snapshotRepo(executionCwd),
|
|
760
925
|
agents: Array.from(agentProofs.values()),
|
|
761
926
|
evidence: evidenceRecords,
|
|
762
927
|
harnessEvidence: opts.harnessEvidence,
|
|
@@ -764,10 +929,13 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
764
929
|
? {
|
|
765
930
|
config: policy,
|
|
766
931
|
decisions: Array.from(policyDecisions.values()),
|
|
767
|
-
isolation,
|
|
932
|
+
isolation: effectiveIsolation,
|
|
768
933
|
networkAccess,
|
|
769
934
|
}
|
|
770
935
|
: undefined,
|
|
936
|
+
workspaceBinding,
|
|
937
|
+
workspaceAttestation,
|
|
938
|
+
workspaceFallback,
|
|
771
939
|
result,
|
|
772
940
|
});
|
|
773
941
|
writeWorkflowProof(proofPath, proof);
|
|
@@ -793,11 +961,15 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
793
961
|
mode: subscriptionOnly ? "subscription" : p.mode,
|
|
794
962
|
})),
|
|
795
963
|
policy: proof.policy?.summary,
|
|
964
|
+
workspaceBinding,
|
|
796
965
|
};
|
|
797
966
|
return report;
|
|
798
967
|
}
|
|
799
968
|
catch (err) {
|
|
800
|
-
if (err instanceof WorkflowParkedError
|
|
969
|
+
if (err instanceof WorkflowParkedError) {
|
|
970
|
+
throw err;
|
|
971
|
+
}
|
|
972
|
+
if (err instanceof WorkflowRunError)
|
|
801
973
|
throw err;
|
|
802
974
|
const endedAt = new Date().toISOString();
|
|
803
975
|
const durationMs = Date.now() - t0;
|
|
@@ -810,6 +982,10 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
810
982
|
duration_ms: durationMs,
|
|
811
983
|
});
|
|
812
984
|
try {
|
|
985
|
+
const workspaceAttestation = workspaceBinding
|
|
986
|
+
? (observedWorkspaceAttestation ??
|
|
987
|
+
(await attestTerminal(workspaceProvider, workspaceBinding)))
|
|
988
|
+
: undefined;
|
|
813
989
|
const proof = buildWorkflowProof({
|
|
814
990
|
runId,
|
|
815
991
|
workItemId: opts.workItemId ?? resumeState?.manifest.work_item_id,
|
|
@@ -821,8 +997,8 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
821
997
|
endedAt,
|
|
822
998
|
durationMs,
|
|
823
999
|
journalPath,
|
|
824
|
-
before:
|
|
825
|
-
after: snapshotRepo(
|
|
1000
|
+
before: executionRepoBefore,
|
|
1001
|
+
after: snapshotRepo(executionCwd),
|
|
826
1002
|
agents: Array.from(agentProofs.values()),
|
|
827
1003
|
evidence: evidenceRecords,
|
|
828
1004
|
harnessEvidence: opts.harnessEvidence,
|
|
@@ -830,10 +1006,13 @@ async function executeWorkflow(scriptPath, absScript, opts, resumeState, workCon
|
|
|
830
1006
|
? {
|
|
831
1007
|
config: policy,
|
|
832
1008
|
decisions: Array.from(policyDecisions.values()),
|
|
833
|
-
isolation,
|
|
1009
|
+
isolation: effectiveIsolation,
|
|
834
1010
|
networkAccess,
|
|
835
1011
|
}
|
|
836
1012
|
: undefined,
|
|
1013
|
+
workspaceBinding,
|
|
1014
|
+
workspaceAttestation,
|
|
1015
|
+
workspaceFallback,
|
|
837
1016
|
error: err.message,
|
|
838
1017
|
});
|
|
839
1018
|
writeWorkflowProof(proofPath, proof);
|
|
@@ -7,4 +7,6 @@ export type { WorkflowRunManifest } from "./run-state.js";
|
|
|
7
7
|
export { acquireWorkflowResumeLease, assertWorkflowRunResumable, assertWorkflowScriptUnchanged, readWorkflowRunManifest, WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION, workflowRunManifestPath, workflowScriptDigest, writeWorkflowRunManifest, } from "./run-state.js";
|
|
8
8
|
export type { AcceptanceCriterion, AcceptanceResult, AcceptanceStatus, AcceptanceSummary, AgentOpts, EngineOpts, EvidenceKind, EvidenceSource, EvidenceStatus, HarnessEvidenceCapability, HarnessEvidenceCoverage, HarnessName, ResultDigest, RunReport, Spawner, SpawnRequest, SpawnResult, StageSchema, WorkflowAgentProof, WorkflowApprovalMode, WorkflowAttemptContext, WorkflowAttemptFailureCause, WorkflowAttemptPriorContext, WorkflowAttemptUnresolvedCriterion, WorkflowContext, WorkflowEvidenceInput, WorkflowEvidenceRecord, WorkflowMeta, WorkflowModule, WorkflowPolicyProof, WorkflowProof, WorkflowProofUnknown, WorkflowRepoEvidence, WorkflowRepoSnapshot, WorkflowRunStatus, WorkflowSpecialistProfile, WorkflowWorkContext, } from "./types.js";
|
|
9
9
|
export { WORKFLOW_ATTEMPT_CONTEXT_SCHEMA_VERSION, WORKFLOW_PROOF_SCHEMA_VERSION, WORKFLOW_WORK_CONTEXT_SCHEMA_VERSION, } from "./types.js";
|
|
10
|
+
export type { ApplyIntegrationInput, AuthorizedIntegrationPlan, AuthorizedProviderIntegrationInput, CancelWorkspaceInput, CleanupWorkspaceInput, FilesystemIdentity, IntegrationApplyAttempt, IntegrationApplyReceipt, IntegrationAuthorization, IntegrationPlan, IntegrationReviewRecord, IntegrationTarget, LocalGitWorktreeProviderOptions, PrepareIntegrationInput, ProviderIntegrationInput, ProviderIntegrationPreview, ProviderIntegrationResult, ProviderUnknown, ProviderUnsupportedReason, RepositoryBinding, ValidatedFilesystemPath, WorkflowWorkspaceInspection, WorkflowWorkspaceSelection, WorkflowWorkspaceStatus, WorkflowWorkspaceVerification, WorkspaceAllocationRequest, WorkspaceAttestation, WorkspaceBinding, WorkspaceBoundExecutionEvidence, WorkspaceCancellationReceipt, WorkspaceCancellationResult, WorkspaceCleanupAttempt, WorkspaceCleanupIntent, WorkspaceCleanupMode, WorkspaceCleanupReceipt, WorkspaceCleanupResult, WorkspaceCompatibilityExecutionEvidence, WorkspaceExecutionEvidence, WorkspaceIntegrationState, WorkspaceIsolation, WorkspaceLifecycleProjection, WorkspaceLifecycleProjectionInput, WorkspaceLifecycleState, WorkspaceObservation, WorkspaceOwner, WorkspaceProbeInput, WorkspaceProbeResult, WorkspaceProofOutcome, WorkspaceProvider, WorkspaceProviderCapabilities, WorkspaceProviderRef, WorkspaceResourceState, WorkspaceUnsupportedExecutionEvidence, } from "./workspaces/index.js";
|
|
11
|
+
export { applyIntegration, assertWorkspaceLifecycleTransition, cancelWorkspace, cleanupWorkspace, createLocalGitWorktreeProvider, deriveWorkspaceLifecycle, inspectWorkflowWorkspace, isWorkspaceLifecycleState, listWorkflowWorkspaceInspections, prepareIntegration, probeLocalGitWorktreeProvider, readWorkflowWorkspaceStatus, renderWorkflowWorkspaceStatus, validateProviderEventChain, WORKSPACE_BINDING_SCHEMA_VERSION, WORKSPACE_RECEIPT_SCHEMA_VERSION, } from "./workspaces/index.js";
|
|
10
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,2BAA2B,EAC3B,4BAA4B,EAC5B,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,gCAAgC,EAChC,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,4BAA4B,EAC5B,iCAAiC,EACjC,+BAA+B,GAChC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,6BAA6B,EAC7B,uBAAuB,EACvB,oCAAoC,EACpC,uBAAuB,EACvB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,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,oBAAoB,EACpB,sBAAsB,EACtB,2BAA2B,EAC3B,2BAA2B,EAC3B,kCAAkC,EAClC,eAAe,EACf,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,uCAAuC,EACvC,6BAA6B,EAC7B,oCAAoC,GACrC,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,3 +4,4 @@ export { runWorkflow, WorkflowParkedError, WorkflowRunError } from "./engine.js"
|
|
|
4
4
|
export { buildWorkflowProof, createEvidenceRecord, digestResult, normalizeWorkflowMeta, readWorkflowProof, renderWorkflowProof, rollupAcceptance, writeWorkflowProof, } from "./proof.js";
|
|
5
5
|
export { acquireWorkflowResumeLease, assertWorkflowRunResumable, assertWorkflowScriptUnchanged, readWorkflowRunManifest, WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION, workflowRunManifestPath, workflowScriptDigest, writeWorkflowRunManifest, } from "./run-state.js";
|
|
6
6
|
export { WORKFLOW_ATTEMPT_CONTEXT_SCHEMA_VERSION, WORKFLOW_PROOF_SCHEMA_VERSION, WORKFLOW_WORK_CONTEXT_SCHEMA_VERSION, } from "./types.js";
|
|
7
|
+
export { applyIntegration, assertWorkspaceLifecycleTransition, cancelWorkspace, cleanupWorkspace, createLocalGitWorktreeProvider, deriveWorkspaceLifecycle, inspectWorkflowWorkspace, isWorkspaceLifecycleState, listWorkflowWorkspaceInspections, prepareIntegration, probeLocalGitWorktreeProvider, readWorkflowWorkspaceStatus, renderWorkflowWorkspaceStatus, validateProviderEventChain, WORKSPACE_BINDING_SCHEMA_VERSION, WORKSPACE_RECEIPT_SCHEMA_VERSION, } from "./workspaces/index.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RepoSnapshot } from "../context/index.js";
|
|
2
2
|
import type { NormalizedPolicy, PolicyDecision, PolicyIsolation, PolicyNetworkAccess } from "../policy/index.js";
|
|
3
3
|
import type { AcceptanceCriterion, AcceptanceResult, AcceptanceSummary, HarnessEvidenceCapability, ResultDigest, WorkflowAgentProof, WorkflowAttemptContext, WorkflowEvidenceInput, WorkflowEvidenceRecord, WorkflowMeta, WorkflowProof, WorkflowWorkContext } from "./types.js";
|
|
4
|
+
import type { WorkspaceAttestation, WorkspaceBinding, WorkspaceUnsupportedExecutionEvidence } from "./workspaces/index.js";
|
|
4
5
|
export interface NormalizedWorkflowMeta {
|
|
5
6
|
name: string;
|
|
6
7
|
description?: string;
|
|
@@ -29,6 +30,9 @@ export interface BuildWorkflowProofInput {
|
|
|
29
30
|
isolation: PolicyIsolation;
|
|
30
31
|
networkAccess: PolicyNetworkAccess;
|
|
31
32
|
};
|
|
33
|
+
workspaceBinding?: WorkspaceBinding;
|
|
34
|
+
workspaceAttestation?: WorkspaceAttestation;
|
|
35
|
+
workspaceFallback?: WorkspaceUnsupportedExecutionEvidence;
|
|
32
36
|
result?: unknown;
|
|
33
37
|
error?: string;
|
|
34
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proof.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/proof.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"proof.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/proof.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { createHash
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
4
|
import { policyDigest } from "../policy/index.js";
|
|
5
5
|
import { isCanonicalWorkflowAttemptContext } from "./attempt-context.js";
|
|
6
|
+
import { stableDigest, writeImmutableJson } from "./durable-record.js";
|
|
7
|
+
import { readWorkflowRunManifest } from "./run-state.js";
|
|
6
8
|
import { WORKFLOW_PROOF_SCHEMA_VERSION } from "./types.js";
|
|
7
9
|
import { isCanonicalWorkflowWorkContext } from "./work-context.js";
|
|
10
|
+
import { isWorkspaceBoundExecutionEvidence, isWorkspaceExecutionEvidence, isWorkspaceUnsupportedExecutionEvidence, workspaceProofLifecycle, } from "./workspaces/validate.js";
|
|
8
11
|
const MAX_ACCEPTANCE_CRITERIA = 50;
|
|
9
12
|
const MAX_EVIDENCE_RECORDS = 200;
|
|
10
13
|
const MAX_PACKET_BYTES = 512 * 1024;
|
|
@@ -139,6 +142,9 @@ export function buildWorkflowProof(input) {
|
|
|
139
142
|
agents,
|
|
140
143
|
evidence: input.evidence,
|
|
141
144
|
policy: input.policy ? buildPolicyProof(input.policy) : undefined,
|
|
145
|
+
execution: input.workspaceBinding && input.workspaceAttestation
|
|
146
|
+
? buildExecutionEvidence(input.status, input.workspaceBinding, input.workspaceAttestation)
|
|
147
|
+
: input.workspaceFallback,
|
|
142
148
|
repository,
|
|
143
149
|
harnesses,
|
|
144
150
|
unknowns,
|
|
@@ -184,17 +190,7 @@ export function writeWorkflowProof(path, proof) {
|
|
|
184
190
|
if (bytes > MAX_PACKET_BYTES) {
|
|
185
191
|
throw new Error(`workflow proof is ${bytes} bytes; limit is ${MAX_PACKET_BYTES}`);
|
|
186
192
|
}
|
|
187
|
-
|
|
188
|
-
const temporary = `${path}.tmp-${process.pid}-${randomUUID()}`;
|
|
189
|
-
try {
|
|
190
|
-
writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
191
|
-
renameSync(temporary, path);
|
|
192
|
-
chmodSync(path, 0o600);
|
|
193
|
-
}
|
|
194
|
-
finally {
|
|
195
|
-
if (existsSync(temporary))
|
|
196
|
-
unlinkSync(temporary);
|
|
197
|
-
}
|
|
193
|
+
writeImmutableJson(path, proof);
|
|
198
194
|
}
|
|
199
195
|
export function readWorkflowProof(coordRoot, runId) {
|
|
200
196
|
if (!RUN_ID.test(runId))
|
|
@@ -222,11 +218,50 @@ export function readWorkflowProof(coordRoot, runId) {
|
|
|
222
218
|
(proof.run.attempt_context !== undefined &&
|
|
223
219
|
(!proof.run.work_item_id ||
|
|
224
220
|
!proof.run.work_context ||
|
|
225
|
-
!isCanonicalWorkflowAttemptContext(proof.run.attempt_context)))
|
|
221
|
+
!isCanonicalWorkflowAttemptContext(proof.run.attempt_context))) ||
|
|
222
|
+
(proof.execution !== undefined &&
|
|
223
|
+
!isWorkspaceExecutionEvidence(proof.execution, runId, proof.run.status))) {
|
|
226
224
|
throw new Error(`workflow proof at ${path} has an unsupported or mismatched schema`);
|
|
227
225
|
}
|
|
226
|
+
const manifestPath = join(coordRoot, ".harnery", "workflows", runId, "run.json");
|
|
227
|
+
if (proof.execution === undefined && !existsSync(manifestPath))
|
|
228
|
+
return proof;
|
|
229
|
+
const manifest = readWorkflowRunManifest(coordRoot, runId);
|
|
230
|
+
const manifestBinding = manifest.execution.workspace_binding;
|
|
231
|
+
const manifestFallback = manifest.execution.workspace_fallback;
|
|
232
|
+
const proofExecution = proof.execution;
|
|
233
|
+
const executionMatches = manifestBinding !== undefined
|
|
234
|
+
? isWorkspaceBoundExecutionEvidence(proofExecution, runId) &&
|
|
235
|
+
stableDigest(proofExecution.binding) === stableDigest(manifestBinding)
|
|
236
|
+
: manifestFallback !== undefined
|
|
237
|
+
? isWorkspaceUnsupportedExecutionEvidence(proofExecution, runId) &&
|
|
238
|
+
stableDigest(proofExecution) === stableDigest(manifestFallback)
|
|
239
|
+
: proofExecution === undefined;
|
|
240
|
+
if (!executionMatches) {
|
|
241
|
+
throw new Error(`workflow proof at ${path} does not match the frozen execution manifest`);
|
|
242
|
+
}
|
|
228
243
|
return proof;
|
|
229
244
|
}
|
|
245
|
+
function buildExecutionEvidence(workflowStatus, binding, terminalAttestation) {
|
|
246
|
+
return {
|
|
247
|
+
schema_version: 1,
|
|
248
|
+
binding,
|
|
249
|
+
terminal_attestation: terminalAttestation,
|
|
250
|
+
terminal_lifecycle_state: workspaceProofLifecycle(workflowStatus, terminalAttestation),
|
|
251
|
+
drift: [...terminalAttestation.provider_drift],
|
|
252
|
+
unsupported: [...terminalAttestation.unsupported],
|
|
253
|
+
unknowns: [...terminalAttestation.unknowns],
|
|
254
|
+
receipts: {
|
|
255
|
+
request: "workspace-request.json",
|
|
256
|
+
cancellation_outcome: "cancellation/outcome.json",
|
|
257
|
+
integration_plan: "integration/plan.json",
|
|
258
|
+
integration_authorization: "integration/authorization.json",
|
|
259
|
+
integration_apply: "integration/receipt.json",
|
|
260
|
+
cleanup_intent: "cleanup/intent.json",
|
|
261
|
+
cleanup_receipt: "cleanup/receipt.json",
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
}
|
|
230
265
|
export function renderWorkflowProof(proof) {
|
|
231
266
|
const lines = [
|
|
232
267
|
`run ${proof.run.id} (${proof.run.name}): ${proof.run.status}`,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { RepoSnapshot } from "../context/index.js";
|
|
2
2
|
import { type NormalizedPolicy, type PolicyIsolation, type PolicyNetworkAccess } from "../policy/index.js";
|
|
3
3
|
import type { WorkflowAttemptContext, WorkflowSpecialistProfile, WorkflowWorkContext } from "./types.js";
|
|
4
|
+
import type { WorkspaceBinding, WorkspaceUnsupportedExecutionEvidence } from "./workspaces/index.js";
|
|
4
5
|
export declare const WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION: 1;
|
|
5
6
|
export interface WorkflowRunManifest {
|
|
6
7
|
schema_version: typeof WORKFLOW_RUN_MANIFEST_SCHEMA_VERSION;
|
|
@@ -28,6 +29,8 @@ export interface WorkflowRunManifest {
|
|
|
28
29
|
network_access: PolicyNetworkAccess;
|
|
29
30
|
policy?: NormalizedPolicy;
|
|
30
31
|
specialists?: Record<string, WorkflowSpecialistProfile>;
|
|
32
|
+
workspace_binding?: WorkspaceBinding;
|
|
33
|
+
workspace_fallback?: WorkspaceUnsupportedExecutionEvidence;
|
|
31
34
|
};
|
|
32
35
|
}
|
|
33
36
|
export interface WriteWorkflowRunManifestInput {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-state.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/run-state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run-state.d.ts","sourceRoot":"","sources":["../../../src/core/workflow/run-state.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,KAAK,gBAAgB,EAErB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAEzB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,KAAK,EACV,sBAAsB,EACtB,yBAAyB,EACzB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAEV,gBAAgB,EAChB,qCAAqC,EACtC,MAAM,uBAAuB,CAAC;AAO/B,eAAO,MAAM,oCAAoC,EAAG,CAAU,CAAC;AAK/D,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,OAAO,oCAAoC,CAAC;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,iBAAiB,EAAE,YAAY,CAAC;IAChC,SAAS,EAAE;QACT,GAAG,EAAE,MAAM,CAAC;QACZ,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,iBAAiB,EAAE,OAAO,CAAC;QAC3B,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;QAC/B,kBAAkB,EAAE,MAAM,CAAC;QAC3B,SAAS,EAAE,eAAe,CAAC;QAC3B,cAAc,EAAE,mBAAmB,CAAC;QACpC,MAAM,CAAC,EAAE,gBAAgB,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;QACxD,iBAAiB,CAAC,EAAE,gBAAgB,CAAC;QACrC,kBAAkB,CAAC,EAAE,qCAAqC,CAAC;KAC5D,CAAC;CACH;AAED,MAAM,WAAW,6BAA6B;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,mBAAmB,CAAC;CAC/B;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,6BAA6B,GAAG,MAAM,CAgBrF;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,mBAAmB,CAyC7F;AAED,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ;IAAE,QAAQ,EAAE,mBAAmB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CA4BvD;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CASjF;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGhF;AAED,4EAA4E;AAC5E,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,IAAI,CA0CvF"}
|