@fitlab-ai/agent-infra 0.9.15 → 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 +2 -6
- package/README.zh-CN.md +2 -6
- package/bin/internal-cli.sh +0 -13
- package/dist/bin/internal-cli.js +11 -49
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +6 -2
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +43 -3
- package/dist/lib/fs/durable-write.js +2 -0
- package/dist/lib/internal/cli-route-inventory.js +3 -4
- package/dist/lib/internal/manual-validation.js +17 -8
- package/dist/lib/internal/platform-comment.js +60 -2
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-finalization.js +2 -2
- package/dist/lib/internal/task-lifecycle.js +4 -4
- package/dist/lib/internal/task-operation-registry.js +22 -13
- package/dist/lib/internal/task-orchestration.js +2 -2
- package/dist/lib/internal/task-review.js +12 -7
- package/dist/lib/platform/activity-recovery.js +159 -0
- package/dist/lib/platform/issue-comments.js +89 -31
- package/dist/lib/platform/issues.js +1 -1
- package/dist/lib/platform/pr-change-report.js +5 -4
- package/dist/lib/platform/pr-summary.js +64 -32
- package/dist/lib/platform/pull-requests.js +3 -3
- package/dist/lib/platform/task-comment-projection.js +70 -0
- package/dist/lib/platform/task-identities.js +2 -9
- package/dist/lib/platform/task-recovery.js +55 -0
- package/dist/lib/platform/verification-sync.js +45 -7
- package/dist/lib/pr-review/evidence-grading.js +4 -8
- package/dist/lib/sandbox/commands/rm.js +21 -2
- package/dist/lib/sandbox/control/executor.js +4 -2
- package/dist/lib/sandbox/control/server.js +29 -9
- package/dist/lib/sandbox/control/state.js +7 -1
- package/dist/lib/sandbox/control/task-workflow.js +1 -1
- package/dist/lib/sandbox/control/workflow-executor.js +87 -35
- package/dist/lib/sandbox/index.js +1 -2
- package/dist/lib/sandbox/removal.js +116 -1011
- package/dist/lib/sandbox/workspace-identity.js +17 -1
- package/dist/lib/server/process-state.js +17 -5
- package/dist/lib/task/artifact-command.js +11 -30
- package/dist/lib/task/artifact-operations.js +17 -231
- package/dist/lib/task/artifact-recovery.js +476 -0
- package/dist/lib/task/artifact-repair-intent.js +90 -39
- package/dist/lib/task/commit-operation.js +31 -4
- package/dist/lib/task/control-authority.js +39 -8
- package/dist/lib/task/control-recovery.js +14 -2
- package/dist/lib/task/create-service.js +1 -8
- package/dist/lib/task/delegation-receipts.js +64 -3
- package/dist/lib/task/events.js +165 -23
- package/dist/lib/task/human-override.js +5 -8
- package/dist/lib/task/intermediate-cleanup.js +91 -8
- package/dist/lib/task/lifecycle-recovery.js +549 -0
- package/dist/lib/task/lifecycle.js +12 -3
- package/dist/lib/task/local-artifact-finalization.js +212 -123
- package/dist/lib/task/manual-validation-receipt.js +5 -1
- package/dist/lib/task/orchestration.js +52 -2
- package/dist/lib/task/pr-delivery-fact.js +12 -56
- package/dist/lib/task/recovery-warning.js +19 -0
- package/dist/lib/task/review-command.js +3 -2
- package/dist/lib/task/review-finalization.js +294 -74
- package/dist/lib/{host-control → task}/secure-fs.js +8 -19
- package/dist/lib/task/short-id.js +15 -7
- package/dist/lib/task/task-execution-lock.js +1 -1
- package/dist/lib/task/verification-engine.js +3 -14
- package/dist/lib/task/workflow-command.js +2 -1
- package/dist/lib/task/workflow-dispatch.js +161 -0
- package/dist/lib/version.js +1 -11
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +7 -2
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +55 -3
- package/lib/fs/durable-write.ts +1 -0
- package/lib/internal/cli-route-inventory.ts +3 -4
- package/lib/internal/manual-validation.ts +17 -8
- package/lib/internal/platform-comment.ts +53 -2
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-finalization.ts +1 -1
- package/lib/internal/task-lifecycle.ts +5 -4
- package/lib/internal/task-operation-registry.ts +22 -13
- package/lib/internal/task-orchestration.ts +1 -1
- package/lib/internal/task-review.ts +11 -7
- package/lib/platform/activity-recovery.ts +179 -0
- package/lib/platform/issue-comments.ts +105 -30
- package/lib/platform/issues.ts +1 -1
- package/lib/platform/pr-change-report.ts +7 -5
- package/lib/platform/pr-summary.ts +64 -32
- package/lib/platform/pull-requests.ts +3 -3
- package/lib/platform/task-comment-projection.ts +79 -0
- package/lib/platform/task-identities.ts +3 -14
- package/lib/platform/task-recovery.ts +54 -0
- package/lib/platform/verification-sync.ts +48 -11
- package/lib/pr-review/evidence-grading.ts +4 -9
- package/lib/sandbox/commands/rm.ts +34 -2
- package/lib/sandbox/control/executor.ts +4 -2
- package/lib/sandbox/control/protocol.ts +6 -1
- package/lib/sandbox/control/server.ts +30 -10
- package/lib/sandbox/control/state.ts +9 -1
- package/lib/sandbox/control/task-workflow.ts +1 -1
- package/lib/sandbox/control/workflow-executor.ts +106 -35
- package/lib/sandbox/index.ts +1 -2
- package/lib/sandbox/removal.ts +126 -1128
- package/lib/sandbox/workspace-identity.ts +19 -3
- package/lib/server/process-state.ts +26 -5
- package/lib/task/artifact-command.ts +12 -29
- package/lib/task/artifact-operations.ts +22 -252
- package/lib/task/artifact-recovery.ts +572 -0
- package/lib/task/artifact-repair-intent.ts +126 -51
- package/lib/task/commit-operation.ts +35 -4
- package/lib/task/control-authority.ts +48 -15
- package/lib/task/control-recovery.ts +13 -1
- package/lib/task/create-service.ts +1 -10
- package/lib/task/delegation-receipts.ts +73 -2
- package/lib/task/events.ts +188 -24
- package/lib/task/human-override.ts +5 -8
- package/lib/task/intermediate-cleanup.ts +66 -12
- package/lib/task/lifecycle-recovery.ts +691 -0
- package/lib/task/lifecycle.ts +13 -4
- package/lib/task/local-artifact-finalization.ts +249 -131
- package/lib/task/manual-validation-receipt.ts +5 -1
- package/lib/task/orchestration.ts +65 -0
- package/lib/task/pr-delivery-fact.ts +15 -62
- package/lib/task/recovery-warning.ts +21 -0
- package/lib/task/review-command.ts +2 -1
- package/lib/task/review-finalization.ts +298 -84
- package/lib/{host-control → task}/secure-fs.ts +10 -32
- package/lib/task/short-id.ts +27 -5
- package/lib/task/task-execution-lock.ts +1 -1
- package/lib/task/verification-engine.ts +3 -17
- package/lib/task/verification-types.ts +0 -2
- package/lib/task/workflow-command.ts +2 -1
- package/lib/task/workflow-dispatch.ts +171 -0
- package/lib/version.ts +1 -15
- package/package.json +1 -1
- package/templates/.agents/rules/create-issue.en.md +1 -1
- package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.en.md +12 -2
- package/templates/.agents/rules/issue-sync.zh-CN.md +13 -5
- package/templates/.agents/rules/local-artifact-repair.en.md +47 -39
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +45 -36
- package/templates/.agents/skills/analyze-task/SKILL.en.md +6 -6
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/block-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/block-task/config/verify.json +1 -1
- package/templates/.agents/skills/cancel-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +7 -7
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/code-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-task/config/verify.en.json +2 -2
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +2 -2
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +1 -1
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/SKILL.en.md +2 -2
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/create-pr/config/verify.json +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +2 -2
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +2 -2
- package/templates/.agents/skills/create-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/create-task/config/verify.json +1 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +8 -8
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/import-issue/config/verify.json +2 -2
- package/templates/.agents/skills/plan-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -1
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/restore-task/SKILL.en.md +11 -6
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -6
- package/templates/.agents/skills/restore-task/config/verify.json +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +7 -7
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +6 -6
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -4
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -4
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-code/reference/report-template.en.md +12 -12
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +12 -12
- package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +7 -7
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +7 -7
- package/templates/.agents/skills/review-pr/config/verify.en.json +1 -1
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +3 -3
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +3 -3
- package/templates/.agents/skills/run-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/templates/task.en.md +1 -1
- package/templates/.agents/templates/task.zh-CN.md +1 -1
- package/templates/.claude/commands/import-issue.en.md +1 -1
- package/templates/.claude/commands/import-issue.zh-CN.md +1 -1
- package/templates/.claude/commands/restore-task.en.md +1 -1
- package/templates/.claude/commands/restore-task.zh-CN.md +1 -1
- package/dist/lib/host-control/audit.js +0 -19
- package/dist/lib/host-control/client.js +0 -142
- package/dist/lib/host-control/command.js +0 -49
- package/dist/lib/host-control/path.js +0 -160
- package/dist/lib/host-control/server.js +0 -159
- package/dist/lib/host-control/service.js +0 -112
- package/dist/lib/internal/host-control.js +0 -28
- package/lib/host-control/audit.ts +0 -22
- package/lib/host-control/client.ts +0 -172
- package/lib/host-control/command.ts +0 -60
- package/lib/host-control/path.ts +0 -167
- package/lib/host-control/server.ts +0 -180
- package/lib/host-control/service.ts +0 -133
- package/lib/internal/host-control.ts +0 -28
|
@@ -14,6 +14,7 @@ import { requestAuditFields, resultAuditFields, appendCriticalAudit, appendDiagn
|
|
|
14
14
|
import { parseTaskControlOperation } from '../../task/control-authority.js';
|
|
15
15
|
import { parseControlOutput, classifySandboxControlRecovery, findSandboxControlRecoveryOperation, operationRecoveryBinding, SANDBOX_CONTROL_REQUIRED_COMPLETION_PHASES } from '../../task/control-recovery.js';
|
|
16
16
|
import { readRun } from '../../task/orchestration.js';
|
|
17
|
+
import { readLifecycleRecoveryDomainEvidence } from '../../task/lifecycle-recovery.js';
|
|
17
18
|
import { captureRepositorySnapshot } from '../../task/workspace-snapshot.js';
|
|
18
19
|
import { parseTypedTaskFrontmatter } from '../../task/frontmatter.js';
|
|
19
20
|
import { readLifecycleJournalEvidence } from '../../task/lifecycle.js';
|
|
@@ -256,7 +257,7 @@ function outputMatchesEvidence(output, bytes, sha256) {
|
|
|
256
257
|
return Buffer.byteLength(output, 'utf8') === bytes
|
|
257
258
|
&& createHash('sha256').update(output, 'utf8').digest('hex') === sha256;
|
|
258
259
|
}
|
|
259
|
-
function genericRecoveryResponse(request, exitCode, payload, cause = 'recovery') {
|
|
260
|
+
export function genericRecoveryResponse(request, exitCode, payload, cause = 'recovery', warning = null) {
|
|
260
261
|
const outputUnavailable = request.family === 'task-create' && !payload;
|
|
261
262
|
return {
|
|
262
263
|
version: 2,
|
|
@@ -264,9 +265,11 @@ function genericRecoveryResponse(request, exitCode, payload, cause = 'recovery')
|
|
|
264
265
|
phase: 'completed',
|
|
265
266
|
exitCode,
|
|
266
267
|
stdout: outputUnavailable ? `${JSON.stringify(taskCreateOutputUnavailableResult(request.id))}\n` : '',
|
|
267
|
-
stderr: payload ? '' :
|
|
268
|
-
?
|
|
269
|
-
:
|
|
268
|
+
stderr: payload ? '' : warning
|
|
269
|
+
? `${warning.code}: ${warning.message}\nAction: ${warning.action}\n`
|
|
270
|
+
: cause === 'publish'
|
|
271
|
+
? 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE: output payload was not retained\n'
|
|
272
|
+
: 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE: broker restarted after executor completion\n',
|
|
270
273
|
error: null,
|
|
271
274
|
outputState: payload ? 'available' : 'unavailable',
|
|
272
275
|
payload: payload ? payloadReference(payload) : null
|
|
@@ -365,6 +368,23 @@ function readRecoveryDomain(manifest, manifestPath, request, operation, terminal
|
|
|
365
368
|
return { domain: null };
|
|
366
369
|
}
|
|
367
370
|
if (operation.family === 'task-lifecycle') {
|
|
371
|
+
if (operation.intent === 'recover-started') {
|
|
372
|
+
try {
|
|
373
|
+
if (!('args' in request))
|
|
374
|
+
return { domain: null };
|
|
375
|
+
const parsed = parseTaskControlOperation('task-lifecycle', request.args);
|
|
376
|
+
if (parsed.family !== 'task-lifecycle' || parsed.request.intent !== 'recover-started') {
|
|
377
|
+
return { domain: null };
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
domain: readLifecycleRecoveryDomainEvidence(manifest.repoRoot, parsed.request, terminalResult),
|
|
381
|
+
journal: readLifecycleJournalEvidence(manifest.repoRoot, taskRef)
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return { domain: null };
|
|
386
|
+
}
|
|
387
|
+
}
|
|
368
388
|
if (!taskRef || !terminalResult.targetState)
|
|
369
389
|
return { domain: null };
|
|
370
390
|
const journal = readLifecycleJournalEvidence(manifest.repoRoot, taskRef);
|
|
@@ -441,7 +461,7 @@ function readCommittedCriticalPhases(manifest, requestId) {
|
|
|
441
461
|
}
|
|
442
462
|
});
|
|
443
463
|
}
|
|
444
|
-
function recoveryResponse(manifest, manifestPath, request, evidence, payload, terminalResult) {
|
|
464
|
+
export function recoveryResponse(manifest, manifestPath, request, evidence, payload, terminalResult) {
|
|
445
465
|
const operationName = recoveryOperationKey(request, terminalResult, payload?.stdout);
|
|
446
466
|
const operation = operationName ? findSandboxControlRecoveryOperation(request.family, operationName) : null;
|
|
447
467
|
if (!operation)
|
|
@@ -503,7 +523,7 @@ function recoveryResponse(manifest, manifestPath, request, evidence, payload, te
|
|
|
503
523
|
return null;
|
|
504
524
|
return finalization.response ?? null;
|
|
505
525
|
}
|
|
506
|
-
return genericRecoveryResponse(request, evidence.exitCode, payload);
|
|
526
|
+
return genericRecoveryResponse(request, evidence.exitCode, payload, 'recovery', terminalResult.warning ?? null);
|
|
507
527
|
}
|
|
508
528
|
function terminalMatchesEvidence(manifest, manifestPath, request, response, evidence, payload, payloadInvalid, terminalResult) {
|
|
509
529
|
if (request.family === 'task-finalization' && evidence.exitCode === 0) {
|
|
@@ -538,7 +558,7 @@ function terminalMatchesEvidence(manifest, manifestPath, request, response, evid
|
|
|
538
558
|
if (response.outputState === 'unavailable') {
|
|
539
559
|
const causes = ['recovery', 'publish'];
|
|
540
560
|
const valid = causes.some((cause) => JSON.stringify(response)
|
|
541
|
-
=== JSON.stringify(genericRecoveryResponse(request, evidence.exitCode, null, cause)));
|
|
561
|
+
=== JSON.stringify(genericRecoveryResponse(request, evidence.exitCode, null, cause, terminalResult?.warning ?? null)));
|
|
542
562
|
return { valid, payloadReferenced: false };
|
|
543
563
|
}
|
|
544
564
|
return {
|
|
@@ -550,7 +570,7 @@ function terminalMatchesEvidence(manifest, manifestPath, request, response, evid
|
|
|
550
570
|
}
|
|
551
571
|
function publishExecutionResult(manifest, request, result, broker, brokerOwns) {
|
|
552
572
|
const normalized = sanitizeSandboxControlResult(manifest, result);
|
|
553
|
-
writeSandboxControlTerminalResult(manifest, {
|
|
573
|
+
const terminalResult = writeSandboxControlTerminalResult(manifest, {
|
|
554
574
|
id: request.id,
|
|
555
575
|
family: request.family,
|
|
556
576
|
operation: operationKey(request, normalized.stdout)
|
|
@@ -590,7 +610,7 @@ function publishExecutionResult(manifest, request, result, broker, brokerOwns) {
|
|
|
590
610
|
catch {
|
|
591
611
|
payload = null;
|
|
592
612
|
}
|
|
593
|
-
terminal = genericRecoveryResponse(request, normalized.exitCode, payload, 'publish');
|
|
613
|
+
terminal = genericRecoveryResponse(request, normalized.exitCode, payload, 'publish', terminalResult.warning ?? null);
|
|
594
614
|
}
|
|
595
615
|
}
|
|
596
616
|
if (!brokerOwns())
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isCompletionEvidence } from '../../task/orchestration.js';
|
|
2
2
|
import { parseControlOutput } from '../../task/control-recovery.js';
|
|
3
|
+
import { isRecoveryWarning } from '../../task/recovery-warning.js';
|
|
3
4
|
import { execFileSync } from 'node:child_process';
|
|
4
5
|
import fs from 'node:fs';
|
|
5
6
|
import path from 'node:path';
|
|
@@ -83,6 +84,7 @@ export function createSandboxControlTerminalResult(manifest, request, output) {
|
|
|
83
84
|
? nested.run : null;
|
|
84
85
|
const rawCompletion = nested.completionEvidence ?? run?.completionEvidence;
|
|
85
86
|
const operation = request.operation ?? (typeof nested.intent === 'string' ? nested.intent : null) ?? '';
|
|
87
|
+
const warning = isRecoveryWarning(nested.warning) ? nested.warning : null;
|
|
86
88
|
return {
|
|
87
89
|
version: 1,
|
|
88
90
|
requestId: request.id,
|
|
@@ -92,7 +94,8 @@ export function createSandboxControlTerminalResult(manifest, request, output) {
|
|
|
92
94
|
targetState: typeof nested.targetState === 'string' ? nested.targetState : null,
|
|
93
95
|
status: typeof nested.status === 'string' ? nested.status : 'completed',
|
|
94
96
|
changed: typeof nested.changed === 'boolean' ? nested.changed : null,
|
|
95
|
-
completionEvidence: isCompletionEvidence(rawCompletion) ? rawCompletion : null
|
|
97
|
+
completionEvidence: isCompletionEvidence(rawCompletion) ? rawCompletion : null,
|
|
98
|
+
...(warning ? { warning } : {})
|
|
96
99
|
};
|
|
97
100
|
}
|
|
98
101
|
export function writeSandboxControlTerminalResult(manifest, request, output) {
|
|
@@ -123,6 +126,9 @@ export function readSandboxControlTerminalResult(filePath) {
|
|
|
123
126
|
if (value.completionEvidence !== null && !isCompletionEvidence(value.completionEvidence)) {
|
|
124
127
|
throw new Error('SANDBOX_CONTROL_TERMINAL_RESULT_INVALID');
|
|
125
128
|
}
|
|
129
|
+
if (value.warning !== undefined && value.warning !== null && !isRecoveryWarning(value.warning)) {
|
|
130
|
+
throw new Error('SANDBOX_CONTROL_TERMINAL_RESULT_INVALID');
|
|
131
|
+
}
|
|
126
132
|
if (value.changed === undefined) {
|
|
127
133
|
throw new Error('SANDBOX_CONTROL_TERMINAL_RESULT_INVALID');
|
|
128
134
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import { readStableFile, SecureFileError, writeAtomicFile } from '../../
|
|
4
|
+
import { readStableFile, SecureFileError, writeAtomicFile } from '../../task/secure-fs.js';
|
|
5
5
|
import { TASK_WORKFLOW_COMMANDS, TASK_WORKFLOW_OPERATIONS } from '../../task/workflow-command.js';
|
|
6
6
|
export function validateTaskWorkflowRequest(value) {
|
|
7
7
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
@@ -1,22 +1,46 @@
|
|
|
1
1
|
import { TASK_WORKFLOW_COMMANDS } from '../../task/workflow-command.js';
|
|
2
2
|
import { parseArtifactCommand, executeArtifactCommand } from '../../task/artifact-command.js';
|
|
3
3
|
import { parseReviewCommand } from '../../task/review-command.js';
|
|
4
|
-
import { prepareLocalArtifact, commitLocalArtifactProvenance } from '../../task/local-artifact-finalization.js';
|
|
4
|
+
import { prepareLocalArtifact, preflightLocalArtifact, commitLocalArtifactProvenance } from '../../task/local-artifact-finalization.js';
|
|
5
5
|
import { prepareReviewSummaryCandidate, commitReviewSummaryProvenance } from '../../task/review-finalization.js';
|
|
6
|
+
import { readArtifactRecoveryIntent } from '../../task/artifact-repair-intent.js';
|
|
6
7
|
import { withTaskExecutionLock } from '../../task/task-execution-lock.js';
|
|
7
|
-
import {
|
|
8
|
+
import { dispatchWorkflowCommand } from '../../task/workflow-dispatch.js';
|
|
8
9
|
import { assertSandboxTaskSource } from '../workspace-view.js';
|
|
9
10
|
import { appendDiagnosticAudit } from './audit.js';
|
|
10
|
-
import { readTaskArtifact
|
|
11
|
+
import { readTaskArtifact } from './task-workflow.js';
|
|
11
12
|
import { applyTaskEvent } from '../../task/events.js';
|
|
12
13
|
import { parseTaskEventRequest } from '../../internal/task-event.js';
|
|
13
14
|
function executionResult(result) {
|
|
14
15
|
return { exitCode: result.status === 'failed' || result.status === 'refused' ? 1 : 0, stdout: `${JSON.stringify(result)}\n`, stderr: '' };
|
|
15
16
|
}
|
|
16
17
|
/** The broker already authorized this host executor; domain operations own validation. */
|
|
17
|
-
export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAttestation = null) {
|
|
18
|
-
let
|
|
18
|
+
export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAttestation = null, options = {}) {
|
|
19
|
+
let publicationCommitted = false;
|
|
20
|
+
let recoveryObservation = null;
|
|
21
|
+
const observeRecoveryPublication = () => {
|
|
22
|
+
if (!recoveryObservation || recoveryObservation.wasPassed)
|
|
23
|
+
return;
|
|
24
|
+
const intent = readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, recoveryObservation.family, recoveryObservation.artifact);
|
|
25
|
+
publicationCommitted ||= intent?.state === 'preflight-ready'
|
|
26
|
+
|| intent?.state === 'preflight-commit-started'
|
|
27
|
+
|| intent?.state === 'preflight-passed'
|
|
28
|
+
|| intent?.state === 'passed'
|
|
29
|
+
|| intent?.state === 'commit-started';
|
|
30
|
+
};
|
|
31
|
+
let faultTriggered = false;
|
|
32
|
+
const fault = (window) => {
|
|
33
|
+
if (faultTriggered || options.faultWindow !== window)
|
|
34
|
+
return;
|
|
35
|
+
faultTriggered = true;
|
|
36
|
+
throw new Error(`TASK_WORKFLOW_FAULT_INJECTED:${window}`);
|
|
37
|
+
};
|
|
38
|
+
const response = (result) => {
|
|
39
|
+
fault('before-result-return');
|
|
40
|
+
return executionResult(result);
|
|
41
|
+
};
|
|
19
42
|
try {
|
|
43
|
+
fault('before-call');
|
|
20
44
|
const taskDir = assertSandboxTaskSource(manifest.repoRoot, request.taskId);
|
|
21
45
|
const [command] = TASK_WORKFLOW_COMMANDS[request.operation];
|
|
22
46
|
if (request.operation === 'event') {
|
|
@@ -24,76 +48,104 @@ export async function executeTaskWorkflow(manifest, request, lifecycleRecoveryAt
|
|
|
24
48
|
const boundEventRequest = lifecycleRecoveryAttestation && eventRequest.requestId === undefined
|
|
25
49
|
? { ...eventRequest, requestId: lifecycleRecoveryAttestation.lifecycleRequestId }
|
|
26
50
|
: eventRequest;
|
|
51
|
+
fault('before-domain-write');
|
|
27
52
|
const result = applyTaskEvent(boundEventRequest, {
|
|
28
53
|
repoRoot: manifest.repoRoot,
|
|
29
54
|
lifecycleRecoveryAttestation,
|
|
30
55
|
deferLifecycleRecoveryConsumption: true
|
|
31
56
|
});
|
|
32
|
-
|
|
57
|
+
publicationCommitted = result.changed;
|
|
58
|
+
fault('after-atomic-rename');
|
|
59
|
+
return response(result);
|
|
33
60
|
}
|
|
34
61
|
if (command !== 'task-artifact' && command !== 'task-review') {
|
|
35
|
-
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
62
|
+
// The broker owns this short-lived executor; no global service or worker
|
|
63
|
+
// credential participates in the command's authority or recovery path.
|
|
64
|
+
fault('before-domain-write');
|
|
65
|
+
const result = dispatchWorkflowCommand(manifest.repoRoot, request.operation, request.args);
|
|
66
|
+
publicationCommitted = result.changed === true;
|
|
67
|
+
fault('after-atomic-rename');
|
|
68
|
+
return response(result);
|
|
41
69
|
}
|
|
42
70
|
const input = command === 'task-artifact' ? parseArtifactCommand(request.args) : parseReviewCommand(request.args);
|
|
43
71
|
if (command === 'task-artifact' && 'operation' in input && input.operation === 'inspect') {
|
|
44
|
-
|
|
72
|
+
fault('before-domain-write');
|
|
73
|
+
const result = executeArtifactCommand(input, { repoRoot: manifest.repoRoot });
|
|
74
|
+
publicationCommitted = result.changed === true;
|
|
75
|
+
fault('after-atomic-rename');
|
|
76
|
+
return response(result);
|
|
45
77
|
}
|
|
46
|
-
if ('operation' in input &&
|
|
47
|
-
|
|
78
|
+
if ('operation' in input && input.operation === 'init') {
|
|
79
|
+
fault('before-domain-write');
|
|
80
|
+
const result = executeArtifactCommand(input, { repoRoot: manifest.repoRoot, artifactDir: taskDir });
|
|
81
|
+
publicationCommitted = result.changed === true;
|
|
82
|
+
fault('after-atomic-rename');
|
|
83
|
+
return response(result);
|
|
48
84
|
}
|
|
49
85
|
return await withTaskExecutionLock(manifest.repoRoot, request.taskId, `sandbox-control.${request.operation}`, async () => {
|
|
50
86
|
const artifact = await readTaskArtifact(taskDir, { artifact: input.artifact });
|
|
51
87
|
const content = artifact.bytes.toString('utf8');
|
|
88
|
+
fault('before-domain-write');
|
|
52
89
|
let result;
|
|
53
90
|
if ('operation' in input) {
|
|
54
91
|
const { family } = input;
|
|
55
92
|
if (family !== 'analysis' && family !== 'plan' && family !== 'code')
|
|
56
93
|
throw new Error('ARTIFACT_IDENTITY_INVALID');
|
|
57
|
-
const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot };
|
|
94
|
+
const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot, recoveryId: input.recoveryId, lockAlreadyHeld: true };
|
|
95
|
+
if (input.operation === 'preflight') {
|
|
96
|
+
// Preflight only seals a verified generation. It must not publish the
|
|
97
|
+
// formal artifact, set publicationStarted, or append finalizer audit.
|
|
98
|
+
const result = preflightLocalArtifact(local);
|
|
99
|
+
recoveryObservation = { family, artifact: input.artifact, wasPassed: false };
|
|
100
|
+
observeRecoveryPublication();
|
|
101
|
+
return response(result);
|
|
102
|
+
}
|
|
103
|
+
recoveryObservation = {
|
|
104
|
+
family,
|
|
105
|
+
artifact: input.artifact,
|
|
106
|
+
wasPassed: readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, family, input.artifact)?.state === 'passed'
|
|
107
|
+
};
|
|
58
108
|
const prepared = prepareLocalArtifact(local, content, lifecycleRecoveryAttestation ?? undefined);
|
|
109
|
+
observeRecoveryPublication();
|
|
110
|
+
const commitOptions = { afterPublish: () => fault('after-atomic-rename') };
|
|
59
111
|
if (prepared.result.status === 'failed')
|
|
60
|
-
return executionResult(commitLocalArtifactProvenance(prepared));
|
|
61
|
-
|
|
62
|
-
await writeTaskArtifact(taskDir, {
|
|
63
|
-
artifact: artifact.artifact,
|
|
64
|
-
bytes: artifact.bytes,
|
|
65
|
-
expectedSha256: artifact.sha256
|
|
66
|
-
});
|
|
67
|
-
result = commitLocalArtifactProvenance(prepared);
|
|
112
|
+
return executionResult(commitLocalArtifactProvenance(prepared, commitOptions));
|
|
113
|
+
result = commitLocalArtifactProvenance(prepared, commitOptions);
|
|
68
114
|
}
|
|
69
115
|
else {
|
|
70
116
|
if (input.overrideTicket)
|
|
71
117
|
throw new Error('TASK_WORKFLOW_OVERRIDE_UNSUPPORTED');
|
|
72
|
-
const
|
|
118
|
+
const family = `review-${input.stage}`;
|
|
119
|
+
recoveryObservation = {
|
|
120
|
+
family,
|
|
121
|
+
artifact: input.artifact,
|
|
122
|
+
wasPassed: readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, family, input.artifact)?.state === 'passed'
|
|
123
|
+
};
|
|
124
|
+
const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true, startRecovery: true });
|
|
125
|
+
observeRecoveryPublication();
|
|
73
126
|
if (input.dryRun || prepared.result.status === 'planned')
|
|
74
127
|
return executionResult(prepared.result);
|
|
128
|
+
const commitOptions = { afterPublish: () => fault('after-atomic-rename') };
|
|
75
129
|
if (prepared.result.status === 'failed')
|
|
76
|
-
return executionResult(commitReviewSummaryProvenance(prepared, manifest.repoRoot));
|
|
77
|
-
|
|
78
|
-
await writeTaskArtifact(taskDir, {
|
|
79
|
-
artifact: input.artifact,
|
|
80
|
-
bytes: Buffer.from(prepared.content, 'utf8'),
|
|
81
|
-
expectedSha256: artifact.sha256
|
|
82
|
-
});
|
|
83
|
-
result = commitReviewSummaryProvenance(prepared, manifest.repoRoot);
|
|
130
|
+
return executionResult(commitReviewSummaryProvenance(prepared, manifest.repoRoot, commitOptions));
|
|
131
|
+
result = commitReviewSummaryProvenance(prepared, manifest.repoRoot, commitOptions);
|
|
84
132
|
}
|
|
133
|
+
observeRecoveryPublication();
|
|
134
|
+
publicationCommitted ||= result.changed === true;
|
|
85
135
|
if (result.status !== 'failed')
|
|
86
136
|
appendDiagnosticAudit(manifest, 'task-workflow-artifact-finalized', {
|
|
87
137
|
requestId: request.id, sandboxTaskId: request.taskId, workflowOperation: request.operation,
|
|
88
138
|
artifact: input.artifact, sha256: result.artifactSha256, semanticDigest: result.semanticDigest
|
|
89
139
|
});
|
|
90
|
-
|
|
140
|
+
fault('after-atomic-rename');
|
|
141
|
+
return response(result);
|
|
91
142
|
});
|
|
92
143
|
}
|
|
93
144
|
catch (error) {
|
|
145
|
+
observeRecoveryPublication();
|
|
94
146
|
const message = error instanceof Error ? error.message : String(error);
|
|
95
147
|
const code = error?.code ?? /^([A-Z][A-Z0-9_]+)/u.exec(message)?.[1] ?? 'TASK_WORKFLOW_REQUEST_INVALID';
|
|
96
|
-
return executionResult({ status: 'failed', changed:
|
|
148
|
+
return executionResult({ status: 'failed', changed: publicationCommitted ? null : false, error: { code, message } });
|
|
97
149
|
}
|
|
98
150
|
}
|
|
99
151
|
//# sourceMappingURL=workflow-executor.js.map
|
|
@@ -19,8 +19,7 @@ Commands:
|
|
|
19
19
|
rm <branch | TASK-id> | --unbound | --purge
|
|
20
20
|
Remove one sandbox; use a full TASK-id for task-bound
|
|
21
21
|
cleanup and a branch for branch-only cleanup. --unbound
|
|
22
|
-
removes
|
|
23
|
-
plus verified auxiliary state; active, blocked, and archive tasks are protected.
|
|
22
|
+
removes discovered task-bound and branch-only sandboxes.
|
|
24
23
|
start [--recreate] <branch | TASK-id | N>
|
|
25
24
|
Verify or recover an existing sandbox container;
|
|
26
25
|
optionally replace only the container on failure
|