@fitlab-ai/agent-infra 0.9.15 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 +1 -1
- package/dist/lib/internal/manual-validation.js +17 -8
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-operation-registry.js +0 -1
- package/dist/lib/internal/task-review.js +4 -4
- package/dist/lib/platform/issue-comments.js +16 -10
- 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-identities.js +2 -9
- package/dist/lib/platform/verification-sync.js +6 -2
- package/dist/lib/pr-review/evidence-grading.js +4 -8
- package/dist/lib/sandbox/commands/rm.js +21 -2
- package/dist/lib/sandbox/control/server.js +29 -9
- package/dist/lib/sandbox/control/state.js +7 -1
- package/dist/lib/sandbox/control/workflow-executor.js +4 -14
- 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/task/artifact-command.js +6 -28
- package/dist/lib/task/artifact-operations.js +16 -230
- package/dist/lib/task/artifact-recovery.js +430 -0
- package/dist/lib/task/artifact-repair-intent.js +73 -39
- package/dist/lib/task/commit-operation.js +31 -4
- package/dist/lib/task/control-authority.js +38 -7
- 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 +164 -22
- package/dist/lib/task/human-override.js +5 -8
- package/dist/lib/task/intermediate-cleanup.js +66 -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 +148 -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 +1 -0
- package/dist/lib/task/review-finalization.js +104 -77
- 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 +0 -1
- 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 +1 -1
- package/lib/internal/manual-validation.ts +17 -8
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-lifecycle.ts +4 -3
- package/lib/internal/task-operation-registry.ts +0 -1
- package/lib/internal/task-review.ts +4 -4
- package/lib/platform/issue-comments.ts +18 -10
- 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-identities.ts +3 -14
- package/lib/platform/verification-sync.ts +6 -2
- package/lib/pr-review/evidence-grading.ts +4 -9
- package/lib/sandbox/commands/rm.ts +34 -2
- package/lib/sandbox/control/protocol.ts +5 -0
- package/lib/sandbox/control/server.ts +30 -10
- package/lib/sandbox/control/state.ts +9 -1
- package/lib/sandbox/control/workflow-executor.ts +4 -14
- package/lib/sandbox/index.ts +1 -2
- package/lib/sandbox/removal.ts +126 -1128
- package/lib/sandbox/workspace-identity.ts +19 -3
- package/lib/task/artifact-command.ts +8 -27
- package/lib/task/artifact-operations.ts +21 -251
- package/lib/task/artifact-recovery.ts +519 -0
- package/lib/task/artifact-repair-intent.ts +99 -51
- package/lib/task/commit-operation.ts +35 -4
- package/lib/task/control-authority.ts +47 -14
- 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 +187 -23
- package/lib/task/human-override.ts +5 -8
- package/lib/task/intermediate-cleanup.ts +50 -12
- package/lib/task/lifecycle-recovery.ts +691 -0
- package/lib/task/lifecycle.ts +13 -4
- package/lib/task/local-artifact-finalization.ts +176 -132
- 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 +1 -0
- package/lib/task/review-finalization.ts +106 -87
- 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 +0 -1
- 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 +4 -2
- package/templates/.agents/rules/issue-sync.zh-CN.md +4 -3
- package/templates/.agents/rules/local-artifact-repair.en.md +46 -39
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +43 -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 +7 -7
- 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 +2 -2
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/restore-task/config/verify.json +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
- 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 +2 -2
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
- 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 +2 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
- 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
|
@@ -2,12 +2,41 @@ import { parseArgs } from 'node:util';
|
|
|
2
2
|
import { loadConfig } from '../config.ts';
|
|
3
3
|
import { createSandboxCapabilityPlan } from '../agent-client-reconciler.ts';
|
|
4
4
|
import { resolveSandboxCleanupTarget } from '../workspace-identity.ts';
|
|
5
|
+
import { detectEngine } from '../engine.ts';
|
|
6
|
+
import {
|
|
7
|
+
sandboxBranchLabel,
|
|
8
|
+
sandboxLabel,
|
|
9
|
+
sandboxTaskIdLabel,
|
|
10
|
+
sandboxWorkspaceModeLabel
|
|
11
|
+
} from '../constants.ts';
|
|
12
|
+
import { fetchSandboxRows } from './list-running.ts';
|
|
5
13
|
import { rmOne, rmPurge, rmUnbound } from '../removal.ts';
|
|
6
14
|
|
|
7
15
|
const USAGE = `Usage:
|
|
8
16
|
ai sandbox rm <branch | TASK-id | short id> Remove one sandbox; use a full TASK-id for a task-bound sandbox and a branch for branch-only sandboxes
|
|
9
|
-
ai sandbox rm --unbound [--dry-run] [--yes] Remove
|
|
17
|
+
ai sandbox rm --unbound [--dry-run] [--yes] Remove discovered task-bound and branch-only sandboxes
|
|
10
18
|
ai sandbox rm --purge Tear down ALL sandboxes for the project (containers, worktrees, image, VM)`;
|
|
19
|
+
|
|
20
|
+
function resolveMissingTaskSandboxBranch(taskId: string, config: ReturnType<typeof loadConfig>): string | null {
|
|
21
|
+
const engine = detectEngine(config);
|
|
22
|
+
const listed = fetchSandboxRows(
|
|
23
|
+
engine,
|
|
24
|
+
sandboxLabel(config),
|
|
25
|
+
sandboxBranchLabel(config),
|
|
26
|
+
{ mode: sandboxWorkspaceModeLabel(config), taskId: sandboxTaskIdLabel(config) }
|
|
27
|
+
);
|
|
28
|
+
const branches = new Set(
|
|
29
|
+
[...listed.running, ...listed.nonRunning]
|
|
30
|
+
.filter((row) => row.workspaceMode === 'task-bound' && row.taskId === taskId && row.branch)
|
|
31
|
+
.map((row) => row.branch)
|
|
32
|
+
);
|
|
33
|
+
if (branches.size === 0) return null;
|
|
34
|
+
if (branches.size > 1) {
|
|
35
|
+
throw new Error(`SANDBOX_CLEANUP_TASK_ID_AMBIGUOUS: task ${taskId} matches multiple sandbox branches`);
|
|
36
|
+
}
|
|
37
|
+
return branches.values().next().value ?? null;
|
|
38
|
+
}
|
|
39
|
+
|
|
11
40
|
export async function rm(args: string[]): Promise<void> {
|
|
12
41
|
const { values, positionals } = parseArgs({
|
|
13
42
|
args,
|
|
@@ -64,6 +93,9 @@ export async function rm(args: string[]): Promise<void> {
|
|
|
64
93
|
return;
|
|
65
94
|
}
|
|
66
95
|
|
|
67
|
-
const cleanupTarget = resolveSandboxCleanupTarget(positionals[0] ?? '', config.repoRoot
|
|
96
|
+
const cleanupTarget = resolveSandboxCleanupTarget(positionals[0] ?? '', config.repoRoot, {
|
|
97
|
+
allowProtected: true,
|
|
98
|
+
resolveMissingTask: (taskId) => resolveMissingTaskSandboxBranch(taskId, config)
|
|
99
|
+
});
|
|
68
100
|
await rmOne(config, tools, cleanupTarget.branch, { cleanupTarget });
|
|
69
101
|
}
|
|
@@ -131,6 +131,11 @@ export type SandboxControlResponse = Readonly<{
|
|
|
131
131
|
outputState?: 'available' | 'unavailable';
|
|
132
132
|
payload?: SandboxControlPayloadReference | null;
|
|
133
133
|
}>;
|
|
134
|
+
export type SandboxControlRecoveryWarning = Readonly<{
|
|
135
|
+
code: string;
|
|
136
|
+
message: string;
|
|
137
|
+
action: string;
|
|
138
|
+
}>;
|
|
134
139
|
export type SandboxControlStatus = Readonly<{
|
|
135
140
|
version: 3; generation: string; broker: ProcessIdentity & { brokerId: string };
|
|
136
141
|
state: 'starting' | 'healthy' | 'busy' | 'parked'; reasonCode: string | null;
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
SANDBOX_CONTROL_MAX_RESPONSE_BYTES,
|
|
13
13
|
SANDBOX_CONTROL_MAX_TERMINAL_RECORD_BYTES,
|
|
14
14
|
type SandboxControlManifest,
|
|
15
|
+
type SandboxControlRecoveryWarning,
|
|
15
16
|
type SandboxControlRequest,
|
|
16
17
|
type SandboxControlResponse,
|
|
17
18
|
type SandboxControlTimingPolicy
|
|
@@ -62,6 +63,7 @@ import {
|
|
|
62
63
|
SANDBOX_CONTROL_REQUIRED_COMPLETION_PHASES
|
|
63
64
|
} from '../../task/control-recovery.ts';
|
|
64
65
|
import { readRun } from '../../task/orchestration.ts';
|
|
66
|
+
import { readLifecycleRecoveryDomainEvidence } from '../../task/lifecycle-recovery.ts';
|
|
65
67
|
import { captureRepositorySnapshot } from '../../task/workspace-snapshot.ts';
|
|
66
68
|
import { parseTypedTaskFrontmatter } from '../../task/frontmatter.ts';
|
|
67
69
|
import { readLifecycleJournalEvidence } from '../../task/lifecycle.ts';
|
|
@@ -368,11 +370,12 @@ function outputMatchesEvidence(output: string, bytes: number, sha256: string): b
|
|
|
368
370
|
&& createHash('sha256').update(output, 'utf8').digest('hex') === sha256;
|
|
369
371
|
}
|
|
370
372
|
|
|
371
|
-
function genericRecoveryResponse(
|
|
373
|
+
export function genericRecoveryResponse(
|
|
372
374
|
request: SandboxControlRequest,
|
|
373
375
|
exitCode: number,
|
|
374
376
|
payload: ReturnType<typeof readSandboxControlPayload> | null,
|
|
375
|
-
cause: 'publish' | 'recovery' = 'recovery'
|
|
377
|
+
cause: 'publish' | 'recovery' = 'recovery',
|
|
378
|
+
warning: SandboxControlRecoveryWarning | null = null
|
|
376
379
|
): SandboxControlResponse {
|
|
377
380
|
const outputUnavailable = request.family === 'task-create' && !payload;
|
|
378
381
|
return {
|
|
@@ -381,9 +384,11 @@ function genericRecoveryResponse(
|
|
|
381
384
|
phase: 'completed',
|
|
382
385
|
exitCode,
|
|
383
386
|
stdout: outputUnavailable ? `${JSON.stringify(taskCreateOutputUnavailableResult(request.id))}\n` : '',
|
|
384
|
-
stderr: payload ? '' :
|
|
385
|
-
?
|
|
386
|
-
:
|
|
387
|
+
stderr: payload ? '' : warning
|
|
388
|
+
? `${warning.code}: ${warning.message}\nAction: ${warning.action}\n`
|
|
389
|
+
: cause === 'publish'
|
|
390
|
+
? 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE: output payload was not retained\n'
|
|
391
|
+
: 'SANDBOX_CONTROL_OUTPUT_UNAVAILABLE: broker restarted after executor completion\n',
|
|
387
392
|
error: null,
|
|
388
393
|
outputState: payload ? 'available' : 'unavailable',
|
|
389
394
|
payload: payload ? payloadReference(payload) : null
|
|
@@ -504,6 +509,21 @@ function readRecoveryDomain(
|
|
|
504
509
|
}
|
|
505
510
|
|
|
506
511
|
if (operation.family === 'task-lifecycle') {
|
|
512
|
+
if (operation.intent === 'recover-started') {
|
|
513
|
+
try {
|
|
514
|
+
if (!('args' in request)) return { domain: null };
|
|
515
|
+
const parsed = parseTaskControlOperation('task-lifecycle', request.args);
|
|
516
|
+
if (parsed.family !== 'task-lifecycle' || parsed.request.intent !== 'recover-started') {
|
|
517
|
+
return { domain: null };
|
|
518
|
+
}
|
|
519
|
+
return {
|
|
520
|
+
domain: readLifecycleRecoveryDomainEvidence(manifest.repoRoot, parsed.request, terminalResult),
|
|
521
|
+
journal: readLifecycleJournalEvidence(manifest.repoRoot, taskRef!)
|
|
522
|
+
};
|
|
523
|
+
} catch {
|
|
524
|
+
return { domain: null };
|
|
525
|
+
}
|
|
526
|
+
}
|
|
507
527
|
if (!taskRef || !terminalResult.targetState) return { domain: null };
|
|
508
528
|
const journal = readLifecycleJournalEvidence(manifest.repoRoot, taskRef);
|
|
509
529
|
try {
|
|
@@ -577,7 +597,7 @@ function readCommittedCriticalPhases(manifest: SandboxControlManifest, requestId
|
|
|
577
597
|
});
|
|
578
598
|
}
|
|
579
599
|
|
|
580
|
-
function recoveryResponse(
|
|
600
|
+
export function recoveryResponse(
|
|
581
601
|
manifest: SandboxControlManifest,
|
|
582
602
|
manifestPath: string,
|
|
583
603
|
request: SandboxControlRequest,
|
|
@@ -637,7 +657,7 @@ function recoveryResponse(
|
|
|
637
657
|
if (finalization?.status !== 'matched') return null;
|
|
638
658
|
return finalization.response ?? null;
|
|
639
659
|
}
|
|
640
|
-
return genericRecoveryResponse(request, evidence.exitCode, payload);
|
|
660
|
+
return genericRecoveryResponse(request, evidence.exitCode, payload, 'recovery', terminalResult.warning ?? null);
|
|
641
661
|
}
|
|
642
662
|
|
|
643
663
|
function terminalMatchesEvidence(
|
|
@@ -681,7 +701,7 @@ function terminalMatchesEvidence(
|
|
|
681
701
|
if (response.outputState === 'unavailable') {
|
|
682
702
|
const causes = ['recovery', 'publish'] as const;
|
|
683
703
|
const valid = causes.some((cause) => JSON.stringify(response)
|
|
684
|
-
=== JSON.stringify(genericRecoveryResponse(request, evidence.exitCode, null, cause)));
|
|
704
|
+
=== JSON.stringify(genericRecoveryResponse(request, evidence.exitCode, null, cause, terminalResult?.warning ?? null)));
|
|
685
705
|
return { valid, payloadReferenced: false };
|
|
686
706
|
}
|
|
687
707
|
return {
|
|
@@ -700,7 +720,7 @@ function publishExecutionResult(
|
|
|
700
720
|
brokerOwns: () => boolean
|
|
701
721
|
): boolean {
|
|
702
722
|
const normalized = sanitizeSandboxControlResult(manifest, result);
|
|
703
|
-
writeSandboxControlTerminalResult(manifest, {
|
|
723
|
+
const terminalResult = writeSandboxControlTerminalResult(manifest, {
|
|
704
724
|
id: request.id,
|
|
705
725
|
family: request.family,
|
|
706
726
|
operation: operationKey(request, normalized.stdout)
|
|
@@ -737,7 +757,7 @@ function publishExecutionResult(
|
|
|
737
757
|
} catch {
|
|
738
758
|
payload = null;
|
|
739
759
|
}
|
|
740
|
-
terminal = genericRecoveryResponse(request, normalized.exitCode, payload, 'publish');
|
|
760
|
+
terminal = genericRecoveryResponse(request, normalized.exitCode, payload, 'publish', terminalResult.warning ?? null);
|
|
741
761
|
}
|
|
742
762
|
}
|
|
743
763
|
if (!brokerOwns()) return false;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isCompletionEvidence, type CleanCompletionEvidence } from '../../task/orchestration.ts';
|
|
2
2
|
import { parseControlOutput } from '../../task/control-recovery.ts';
|
|
3
|
+
import { isRecoveryWarning } from '../../task/recovery-warning.ts';
|
|
3
4
|
import { execFileSync } from 'node:child_process';
|
|
4
5
|
import fs from 'node:fs';
|
|
5
6
|
import path from 'node:path';
|
|
@@ -14,6 +15,7 @@ import type {
|
|
|
14
15
|
SandboxControlPayload,
|
|
15
16
|
SandboxControlReservation,
|
|
16
17
|
SandboxControlResultEvidence,
|
|
18
|
+
SandboxControlRecoveryWarning,
|
|
17
19
|
SandboxControlStatus
|
|
18
20
|
} from './protocol.ts';
|
|
19
21
|
import {
|
|
@@ -113,6 +115,7 @@ export type SandboxControlTerminalResult = Readonly<{
|
|
|
113
115
|
status: string;
|
|
114
116
|
changed: boolean | null;
|
|
115
117
|
completionEvidence: CleanCompletionEvidence | null;
|
|
118
|
+
warning?: SandboxControlRecoveryWarning | null;
|
|
116
119
|
}>;
|
|
117
120
|
|
|
118
121
|
export function terminalResultPath(manifest: SandboxControlManifest, requestId: string): string {
|
|
@@ -130,6 +133,7 @@ export function createSandboxControlTerminalResult(
|
|
|
130
133
|
? nested.run as Record<string, unknown> : null;
|
|
131
134
|
const rawCompletion = nested.completionEvidence ?? run?.completionEvidence;
|
|
132
135
|
const operation = request.operation ?? (typeof nested.intent === 'string' ? nested.intent : null) ?? '';
|
|
136
|
+
const warning = isRecoveryWarning(nested.warning) ? nested.warning : null;
|
|
133
137
|
return {
|
|
134
138
|
version: 1,
|
|
135
139
|
requestId: request.id,
|
|
@@ -139,7 +143,8 @@ export function createSandboxControlTerminalResult(
|
|
|
139
143
|
targetState: typeof nested.targetState === 'string' ? nested.targetState : null,
|
|
140
144
|
status: typeof nested.status === 'string' ? nested.status : 'completed',
|
|
141
145
|
changed: typeof nested.changed === 'boolean' ? nested.changed : null,
|
|
142
|
-
completionEvidence: isCompletionEvidence(rawCompletion) ? rawCompletion : null
|
|
146
|
+
completionEvidence: isCompletionEvidence(rawCompletion) ? rawCompletion : null,
|
|
147
|
+
...(warning ? { warning } : {})
|
|
143
148
|
};
|
|
144
149
|
}
|
|
145
150
|
|
|
@@ -173,6 +178,9 @@ export function readSandboxControlTerminalResult(filePath: string): SandboxContr
|
|
|
173
178
|
if (value.completionEvidence !== null && !isCompletionEvidence(value.completionEvidence)) {
|
|
174
179
|
throw new Error('SANDBOX_CONTROL_TERMINAL_RESULT_INVALID');
|
|
175
180
|
}
|
|
181
|
+
if (value.warning !== undefined && value.warning !== null && !isRecoveryWarning(value.warning)) {
|
|
182
|
+
throw new Error('SANDBOX_CONTROL_TERMINAL_RESULT_INVALID');
|
|
183
|
+
}
|
|
176
184
|
if (value.changed === undefined) {
|
|
177
185
|
throw new Error('SANDBOX_CONTROL_TERMINAL_RESULT_INVALID');
|
|
178
186
|
}
|
|
@@ -9,7 +9,7 @@ import { dispatchHostControlCommand } from '../../host-control/command.ts';
|
|
|
9
9
|
import { assertSandboxTaskSource } from '../workspace-view.ts';
|
|
10
10
|
import { appendDiagnosticAudit } from './audit.ts';
|
|
11
11
|
import {
|
|
12
|
-
readTaskArtifact,
|
|
12
|
+
readTaskArtifact, type TaskWorkflowRequest
|
|
13
13
|
} from './task-workflow.ts';
|
|
14
14
|
import type { SandboxControlManifest } from './protocol.ts';
|
|
15
15
|
import type { SandboxControlExecutionResult } from './executor.ts';
|
|
@@ -55,7 +55,7 @@ export async function executeTaskWorkflow(
|
|
|
55
55
|
if (command === 'task-artifact' && 'operation' in input && input.operation === 'inspect') {
|
|
56
56
|
return executionResult(executeArtifactCommand(input, { repoRoot: manifest.repoRoot }));
|
|
57
57
|
}
|
|
58
|
-
if ('operation' in input &&
|
|
58
|
+
if ('operation' in input && input.operation === 'init') {
|
|
59
59
|
return executionResult(executeArtifactCommand(input, { repoRoot: manifest.repoRoot, artifactDir: taskDir }));
|
|
60
60
|
}
|
|
61
61
|
return await withTaskExecutionLock(manifest.repoRoot, request.taskId, `sandbox-control.${request.operation}`, async () => {
|
|
@@ -65,27 +65,17 @@ export async function executeTaskWorkflow(
|
|
|
65
65
|
if ('operation' in input) {
|
|
66
66
|
const { family } = input;
|
|
67
67
|
if (family !== 'analysis' && family !== 'plan' && family !== 'code') throw new Error('ARTIFACT_IDENTITY_INVALID');
|
|
68
|
-
const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot } as const;
|
|
68
|
+
const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot, recoveryId: input.recoveryId, lockAlreadyHeld: true } as const;
|
|
69
69
|
const prepared = prepareLocalArtifact(local, content, lifecycleRecoveryAttestation ?? undefined);
|
|
70
70
|
if (prepared.result.status === 'failed') return executionResult(commitLocalArtifactProvenance(prepared));
|
|
71
71
|
publicationStarted = true;
|
|
72
|
-
await writeTaskArtifact(taskDir, {
|
|
73
|
-
artifact: artifact.artifact,
|
|
74
|
-
bytes: artifact.bytes,
|
|
75
|
-
expectedSha256: artifact.sha256
|
|
76
|
-
});
|
|
77
72
|
result = commitLocalArtifactProvenance(prepared);
|
|
78
73
|
} else {
|
|
79
74
|
if (input.overrideTicket) throw new Error('TASK_WORKFLOW_OVERRIDE_UNSUPPORTED');
|
|
80
|
-
const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot });
|
|
75
|
+
const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true, startRecovery: true });
|
|
81
76
|
if (input.dryRun || prepared.result.status === 'planned') return executionResult(prepared.result);
|
|
82
77
|
if (prepared.result.status === 'failed') return executionResult(commitReviewSummaryProvenance(prepared, manifest.repoRoot));
|
|
83
78
|
publicationStarted = true;
|
|
84
|
-
await writeTaskArtifact(taskDir, {
|
|
85
|
-
artifact: input.artifact,
|
|
86
|
-
bytes: Buffer.from(prepared.content, 'utf8'),
|
|
87
|
-
expectedSha256: artifact.sha256
|
|
88
|
-
});
|
|
89
79
|
result = commitReviewSummaryProvenance(prepared, manifest.repoRoot);
|
|
90
80
|
}
|
|
91
81
|
if (result.status !== 'failed') appendDiagnosticAudit(manifest, 'task-workflow-artifact-finalized', {
|
package/lib/sandbox/index.ts
CHANGED
|
@@ -20,8 +20,7 @@ Commands:
|
|
|
20
20
|
rm <branch | TASK-id> | --unbound | --purge
|
|
21
21
|
Remove one sandbox; use a full TASK-id for task-bound
|
|
22
22
|
cleanup and a branch for branch-only cleanup. --unbound
|
|
23
|
-
removes
|
|
24
|
-
plus verified auxiliary state; active, blocked, and archive tasks are protected.
|
|
23
|
+
removes discovered task-bound and branch-only sandboxes.
|
|
25
24
|
start [--recreate] <branch | TASK-id | N>
|
|
26
25
|
Verify or recover an existing sandbox container;
|
|
27
26
|
optionally replace only the container on failure
|