@fitlab-ai/agent-infra 0.9.5 → 0.9.7
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/bin/internal-cli.js +8 -3
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +171 -20
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +162 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +244 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +14 -2
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +370 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +68 -8
- package/dist/lib/agent-clients/adapters/codex.js +1 -1
- package/dist/lib/defaults.json +10 -2
- package/dist/lib/git/workflow.js +30 -4
- package/dist/lib/internal/codex-lifecycle.js +169 -3
- package/dist/lib/internal/codex-sandbox-controller.js +106 -0
- package/dist/lib/internal/release-workflow.js +108 -11
- package/dist/lib/internal/sandbox-control.js +43 -6
- package/dist/lib/internal/task-create.js +12 -4
- package/dist/lib/internal/task-orchestration.js +40 -7
- package/dist/lib/platform/context.js +6 -4
- package/dist/lib/platform/github-client.js +55 -2
- package/dist/lib/platform/issue-comments.js +2 -1
- package/dist/lib/process-data/checkpoint.js +319 -0
- package/dist/lib/process-data/index.js +128 -60
- package/dist/lib/process-data/materialize.js +84 -0
- package/dist/lib/process-data/normalize.js +34 -1
- package/dist/lib/process-data/reconcile.js +55 -1
- package/dist/lib/process-data/sources.js +422 -1
- package/dist/lib/process-data/store.js +341 -11
- package/dist/lib/release/workflow.js +29 -21
- package/dist/lib/sandbox/commands/create.js +111 -60
- package/dist/lib/sandbox/commands/prune.js +40 -16
- package/dist/lib/sandbox/commands/rm.js +372 -94
- package/dist/lib/sandbox/commands/start.js +4 -3
- package/dist/lib/sandbox/control/client.js +138 -22
- package/dist/lib/sandbox/control/container-identity.js +64 -0
- package/dist/lib/sandbox/control/executor.js +142 -0
- package/dist/lib/sandbox/control/lifecycle.js +557 -0
- package/dist/lib/sandbox/control/protocol.js +69 -26
- package/dist/lib/sandbox/control/server.js +395 -99
- package/dist/lib/sandbox/control/state.js +191 -0
- package/dist/lib/sandbox/control/timing.js +8 -0
- package/dist/lib/sandbox/index.js +2 -2
- package/dist/lib/sandbox/managed-fs.js +14 -2
- package/dist/lib/sandbox/mounts.js +22 -19
- package/dist/lib/sandbox/recovery.js +284 -50
- package/dist/lib/sandbox/workspace-view.js +90 -10
- package/dist/lib/sandbox/worktree-safety.js +196 -0
- package/dist/lib/server/daemon.js +1 -1
- package/dist/lib/server/process-control.js +17 -1
- package/dist/lib/server/process-state.js +57 -20
- package/dist/lib/task/artifact-lifecycle.js +87 -15
- package/dist/lib/task/artifact-receipts.js +128 -0
- package/dist/lib/task/codex-orchestration.js +236 -0
- package/dist/lib/task/commands/status.js +3 -0
- package/dist/lib/task/commands/validate.js +289 -0
- package/dist/lib/task/commit-finalization.js +36 -9
- package/dist/lib/task/create.js +10 -2
- package/dist/lib/task/delegation-receipts.js +109 -2
- package/dist/lib/task/events.js +149 -6
- package/dist/lib/task/finalization-artifacts.js +2 -1
- package/dist/lib/task/implementation-inputs.js +1 -7
- package/dist/lib/task/index.js +9 -0
- package/dist/lib/task/ledger.js +13 -1
- package/dist/lib/task/orchestration.js +365 -15
- package/dist/lib/task/sections.js +5 -1
- package/dist/lib/task/task-execution-lock.js +5 -4
- package/dist/lib/task/verification-engine.js +78 -14
- package/dist/lib/task/verification.js +1 -0
- package/dist/lifecycle-build-manifest.json +6 -0
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +202 -18
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +227 -0
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +321 -0
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +19 -3
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +26 -0
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +453 -0
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +83 -6
- package/lib/agent-clients/adapters/codex.ts +1 -1
- package/lib/defaults.json +10 -2
- package/lib/git/workflow.ts +25 -3
- package/lib/internal/codex-lifecycle.ts +175 -4
- package/lib/internal/codex-sandbox-controller.ts +109 -0
- package/lib/internal/release-workflow.ts +107 -11
- package/lib/internal/sandbox-control.ts +38 -6
- package/lib/internal/task-create.ts +16 -4
- package/lib/internal/task-orchestration.ts +34 -7
- package/lib/platform/context.ts +8 -5
- package/lib/platform/github-client.ts +61 -3
- package/lib/platform/issue-comments.ts +2 -1
- package/lib/process-data/checkpoint.ts +335 -0
- package/lib/process-data/index.ts +112 -60
- package/lib/process-data/materialize.ts +83 -0
- package/lib/process-data/normalize.ts +29 -1
- package/lib/process-data/reconcile.ts +64 -2
- package/lib/process-data/sources.ts +449 -2
- package/lib/process-data/store.ts +304 -11
- package/lib/process-data/types.ts +124 -2
- package/lib/release/workflow.ts +69 -20
- package/lib/sandbox/commands/create.ts +70 -25
- package/lib/sandbox/commands/prune.ts +53 -15
- package/lib/sandbox/commands/rm.ts +423 -108
- package/lib/sandbox/commands/start.ts +4 -3
- package/lib/sandbox/control/client.ts +152 -28
- package/lib/sandbox/control/container-identity.ts +93 -0
- package/lib/sandbox/control/executor.ts +167 -0
- package/lib/sandbox/control/lifecycle.ts +573 -0
- package/lib/sandbox/control/protocol.ts +121 -68
- package/lib/sandbox/control/server.ts +398 -109
- package/lib/sandbox/control/state.ts +213 -0
- package/lib/sandbox/control/timing.ts +12 -0
- package/lib/sandbox/index.ts +2 -2
- package/lib/sandbox/managed-fs.ts +17 -2
- package/lib/sandbox/mounts.ts +16 -8
- package/lib/sandbox/recovery.ts +335 -65
- package/lib/sandbox/workspace-view.ts +102 -11
- package/lib/sandbox/worktree-safety.ts +234 -0
- package/lib/server/daemon.ts +1 -1
- package/lib/server/process-control.ts +24 -3
- package/lib/server/process-state.ts +82 -27
- package/lib/task/artifact-lifecycle.ts +78 -14
- package/lib/task/artifact-receipts.ts +161 -0
- package/lib/task/codex-orchestration.ts +319 -0
- package/lib/task/commands/status.ts +2 -0
- package/lib/task/commands/validate.ts +282 -0
- package/lib/task/commit-finalization.ts +52 -9
- package/lib/task/create.ts +11 -2
- package/lib/task/delegation-receipts.ts +208 -7
- package/lib/task/events.ts +131 -5
- package/lib/task/finalization-artifacts.ts +2 -1
- package/lib/task/implementation-inputs.ts +1 -5
- package/lib/task/index.ts +8 -0
- package/lib/task/ledger.ts +16 -1
- package/lib/task/orchestration.ts +552 -18
- package/lib/task/sections.ts +6 -2
- package/lib/task/task-execution-lock.ts +11 -9
- package/lib/task/verification-engine.ts +93 -24
- package/lib/task/verification.ts +2 -1
- package/package.json +1 -1
- package/templates/.agents/README.en.md +7 -0
- package/templates/.agents/README.zh-CN.md +5 -0
- package/templates/.agents/hooks/lifecycle-delegation.js +72 -12
- package/templates/.agents/rules/lifecycle-orchestration.en.md +8 -2
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +8 -2
- package/templates/.agents/rules/no-mid-flow-questions.en.md +1 -0
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +1 -0
- package/templates/.agents/rules/pr-checks-commands.github.en.md +1 -1
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +1 -1
- package/templates/.agents/rules/review-handshake.en.md +3 -1
- package/templates/.agents/rules/review-handshake.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +3 -1
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +3 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +4 -0
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +4 -0
- package/templates/.agents/skills/post-release/SKILL.en.md +32 -6
- package/templates/.agents/skills/post-release/SKILL.zh-CN.md +32 -6
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +42 -0
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +42 -0
- package/templates/.agents/skills/run-manual-validation/config/verify.en.json +25 -0
- package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +25 -0
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +67 -0
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +67 -0
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +69 -0
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +69 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +9 -7
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +9 -7
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +5 -3
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +5 -3
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +75 -3
- package/templates/.claude/commands/run-manual-validation.en.md +9 -0
- package/templates/.claude/commands/run-manual-validation.zh-CN.md +9 -0
- package/templates/.codex/hooks.json +8 -8
- package/templates/.opencode/commands/run-manual-validation.en.md +11 -0
- package/templates/.opencode/commands/run-manual-validation.zh-CN.md +11 -0
- package/templates/.agents/workspace/README.en.md +0 -26
- package/templates/.agents/workspace/README.zh-CN.md +0 -26
|
@@ -1,48 +1,88 @@
|
|
|
1
1
|
import { validateTaskCreateCandidate, type TaskCreateCandidateV1 } from '../../task/create.ts';
|
|
2
|
+
import type { ProcessIdentity } from '../../server/process-state.ts';
|
|
2
3
|
|
|
3
4
|
export const SANDBOX_CONTROL_MAX_BYTES = 64 * 1024;
|
|
5
|
+
export const SANDBOX_CONTROL_ADMISSION_WINDOW_MS = 2_000;
|
|
6
|
+
export const SANDBOX_CONTROL_STATUS_INTERVAL_MS = 250;
|
|
7
|
+
export const SANDBOX_CONTROL_STATUS_STALE_MS = 1_500;
|
|
8
|
+
export const SANDBOX_CONTROL_FUTURE_SKEW_MS = 1_000;
|
|
4
9
|
export const SANDBOX_CONTROL_FAMILIES = ['task-lifecycle', 'task-orchestration', 'task-create'] as const;
|
|
10
|
+
export type SandboxControlTimingPolicy = Readonly<{
|
|
11
|
+
controlTickMs: number;
|
|
12
|
+
parkedBindingInitialMs: number;
|
|
13
|
+
slowCheckMs: number;
|
|
14
|
+
containerHeartbeatMs: number;
|
|
15
|
+
quiesceDeadlineMs: number;
|
|
16
|
+
}>;
|
|
17
|
+
export const DEFAULT_SANDBOX_CONTROL_TIMING: SandboxControlTimingPolicy = Object.freeze({
|
|
18
|
+
controlTickMs: 250,
|
|
19
|
+
parkedBindingInitialMs: 1_000,
|
|
20
|
+
slowCheckMs: 5_000,
|
|
21
|
+
containerHeartbeatMs: 5_000,
|
|
22
|
+
quiesceDeadlineMs: 7_000
|
|
23
|
+
} as const);
|
|
5
24
|
|
|
6
25
|
export type SandboxControlFamily = typeof SANDBOX_CONTROL_FAMILIES[number];
|
|
7
|
-
|
|
26
|
+
export type SandboxControlContainerIdentity = Readonly<{
|
|
27
|
+
id: string;
|
|
28
|
+
labels: Readonly<Record<string, string>>;
|
|
29
|
+
}>;
|
|
8
30
|
export type SandboxControlManifest = Readonly<{
|
|
9
|
-
version:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
container: string;
|
|
14
|
-
branch: string;
|
|
15
|
-
mode: 'task-bound' | 'branch-only';
|
|
16
|
-
taskId: string | null;
|
|
17
|
-
token: string;
|
|
18
|
-
channelDir: string;
|
|
31
|
+
version: 4; engine: string; repoRoot: string; worktreeRoot: string; project: string; container: string;
|
|
32
|
+
containerIdentity: SandboxControlContainerIdentity;
|
|
33
|
+
branch: string; mode: 'task-bound' | 'branch-only'; taskId: string | null; token: string;
|
|
34
|
+
generation: string; channelDir: string; publicStatusDir: string; processingDir: string;
|
|
19
35
|
}>;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
id: string;
|
|
36
|
+
export type SandboxControlBrokerOwner = ProcessIdentity & Readonly<{
|
|
37
|
+
version: 3;
|
|
38
|
+
brokerId: string;
|
|
24
39
|
token: string;
|
|
25
|
-
|
|
26
|
-
args: string[];
|
|
40
|
+
generation: string;
|
|
27
41
|
}>;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
type RequestBase = Readonly<{
|
|
43
|
+
version: 2; id: string; token: string; generation: string; issuedAt: number; expiresAt: number;
|
|
44
|
+
}>;
|
|
45
|
+
export type SandboxTaskCommandRequest = RequestBase & Readonly<{
|
|
46
|
+
family: 'task-lifecycle' | 'task-orchestration'; args: string[];
|
|
47
|
+
}>;
|
|
48
|
+
export type SandboxTaskCreateRequest = RequestBase & Readonly<{
|
|
49
|
+
family: 'task-create'; candidate: TaskCreateCandidateV1;
|
|
35
50
|
}>;
|
|
36
|
-
|
|
37
51
|
export type SandboxControlRequest = SandboxTaskCommandRequest | SandboxTaskCreateRequest;
|
|
38
|
-
|
|
52
|
+
export type SandboxControlError = Readonly<{ code: string; message: string; retryable: boolean }>;
|
|
39
53
|
export type SandboxControlResponse = Readonly<{
|
|
40
|
-
version:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
version: 2; id: string; phase: 'accepted' | 'completed' | 'rejected'; exitCode: number | null;
|
|
55
|
+
stdout: string; stderr: string; error: SandboxControlError | null;
|
|
56
|
+
}>;
|
|
57
|
+
export type SandboxControlStatus = Readonly<{
|
|
58
|
+
version: 2; generation: string; broker: ProcessIdentity & { brokerId: string };
|
|
59
|
+
state: 'starting' | 'healthy' | 'busy' | 'parked'; reasonCode: string | null;
|
|
60
|
+
activeRequestId: string | null; updatedAt: number;
|
|
45
61
|
}>;
|
|
62
|
+
export type SandboxControlLease = Readonly<{
|
|
63
|
+
version: 2; generation: string; nonce: string; owner: ProcessIdentity;
|
|
64
|
+
issuedAt: number; expiresAt: number; taskId: string | null; branch: string; reason: string;
|
|
65
|
+
}>;
|
|
66
|
+
export type SandboxControlExecution = Readonly<{
|
|
67
|
+
version: 2; generation: string; requestId: string; nonce: string;
|
|
68
|
+
child: ProcessIdentity & { processGroupId: number | null };
|
|
69
|
+
phase: 'prepared' | 'running' | 'terminating'; updatedAt: number;
|
|
70
|
+
}>;
|
|
71
|
+
|
|
72
|
+
export class SandboxControlProtocolError extends Error {
|
|
73
|
+
readonly code: string;
|
|
74
|
+
readonly retryable: boolean;
|
|
75
|
+
constructor(code: string, message: string, retryable = false) {
|
|
76
|
+
super(`${code}: ${message}`);
|
|
77
|
+
this.name = 'SandboxControlProtocolError';
|
|
78
|
+
this.code = code;
|
|
79
|
+
this.retryable = retryable;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function fail(code: string, message: string, retryable = false): never {
|
|
84
|
+
throw new SandboxControlProtocolError(code, message, retryable);
|
|
85
|
+
}
|
|
46
86
|
|
|
47
87
|
export function isSandboxControlFamily(value: string): value is SandboxControlFamily {
|
|
48
88
|
return SANDBOX_CONTROL_FAMILIES.includes(value as SandboxControlFamily);
|
|
@@ -50,61 +90,74 @@ export function isSandboxControlFamily(value: string): value is SandboxControlFa
|
|
|
50
90
|
|
|
51
91
|
export function validateSandboxControlRequest(
|
|
52
92
|
value: unknown,
|
|
53
|
-
manifest: SandboxControlManifest
|
|
93
|
+
manifest: SandboxControlManifest,
|
|
94
|
+
options: { now?: number } = {}
|
|
54
95
|
): SandboxControlRequest {
|
|
55
96
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
56
|
-
|
|
97
|
+
fail('SANDBOX_CONTROL_REQUEST_INVALID', 'request must be an object');
|
|
57
98
|
}
|
|
58
99
|
const request = value as Record<string, unknown>;
|
|
59
100
|
if (
|
|
60
|
-
request.version !==
|
|
61
|
-
||
|
|
62
|
-
||
|
|
63
|
-
|| request.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
101
|
+
request.version !== 2 || typeof request.id !== 'string'
|
|
102
|
+
|| !/^[a-f0-9-]{16,64}$/.test(request.id) || request.token !== manifest.token
|
|
103
|
+
|| typeof request.family !== 'string' || !isSandboxControlFamily(request.family)
|
|
104
|
+
|| !Number.isSafeInteger(request.issuedAt) || !Number.isSafeInteger(request.expiresAt)
|
|
105
|
+
) fail('SANDBOX_CONTROL_REQUEST_INVALID', 'request schema or authorization is invalid');
|
|
106
|
+
if (request.generation !== manifest.generation) {
|
|
107
|
+
fail('SANDBOX_CONTROL_GENERATION_INVALID', 'request generation does not match the broker');
|
|
108
|
+
}
|
|
109
|
+
const issuedAt = request.issuedAt as number;
|
|
110
|
+
const expiresAt = request.expiresAt as number;
|
|
111
|
+
const now = options.now ?? Date.now();
|
|
112
|
+
if (expiresAt <= issuedAt || expiresAt - issuedAt > SANDBOX_CONTROL_ADMISSION_WINDOW_MS || issuedAt > now + SANDBOX_CONTROL_FUTURE_SKEW_MS) {
|
|
113
|
+
fail('SANDBOX_CONTROL_REQUEST_DEADLINE_INVALID', 'request admission deadline is invalid');
|
|
68
114
|
}
|
|
115
|
+
if (now > expiresAt) fail('SANDBOX_CONTROL_REQUEST_EXPIRED', 'request admission deadline has passed', true);
|
|
69
116
|
if (Buffer.byteLength(JSON.stringify(request), 'utf8') > SANDBOX_CONTROL_MAX_BYTES) {
|
|
70
|
-
|
|
117
|
+
fail('SANDBOX_CONTROL_REQUEST_TOO_LARGE', 'request exceeds the control limit');
|
|
71
118
|
}
|
|
72
119
|
if (request.family === 'task-create') {
|
|
73
|
-
const
|
|
74
|
-
if (keys
|
|
75
|
-
|
|
120
|
+
const expected = ['candidate', 'expiresAt', 'family', 'generation', 'id', 'issuedAt', 'token', 'version'];
|
|
121
|
+
if (Object.keys(request).sort().join(',') !== expected.sort().join(',')) {
|
|
122
|
+
fail('SANDBOX_CONTROL_REQUEST_INVALID', 'request schema or authorization is invalid');
|
|
76
123
|
}
|
|
77
124
|
return { ...request, candidate: validateTaskCreateCandidate(request.candidate) } as SandboxTaskCreateRequest;
|
|
78
125
|
}
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|| !request.args.every((arg) => typeof arg === 'string')
|
|
84
|
-
) {
|
|
85
|
-
throw new Error('SANDBOX_CONTROL_REQUEST_INVALID: request schema or authorization is invalid');
|
|
126
|
+
const expected = ['args', 'expiresAt', 'family', 'generation', 'id', 'issuedAt', 'token', 'version'];
|
|
127
|
+
if (Object.keys(request).sort().join(',') !== expected.sort().join(',')
|
|
128
|
+
|| !Array.isArray(request.args) || !request.args.every((arg) => typeof arg === 'string')) {
|
|
129
|
+
fail('SANDBOX_CONTROL_REQUEST_INVALID', 'request schema or authorization is invalid');
|
|
86
130
|
}
|
|
87
131
|
if (manifest.mode !== 'task-bound' || !manifest.taskId) {
|
|
88
|
-
|
|
132
|
+
fail(
|
|
133
|
+
'SANDBOX_CONTROL_BRANCH_ONLY',
|
|
134
|
+
"branch-only sandboxes cannot coordinate tasks; return to the host and run 'ai sandbox start --recreate <task-ref-or-correct-branch>'"
|
|
135
|
+
);
|
|
89
136
|
}
|
|
90
|
-
if (
|
|
91
|
-
request.
|
|
92
|
-
|
|
93
|
-
) {
|
|
94
|
-
throw new Error('SANDBOX_CONTROL_REQUEST_INVALID: worktree binding is reserved for the control broker');
|
|
137
|
+
if (request.family === 'task-orchestration'
|
|
138
|
+
&& request.args.some((arg) => arg === '--git-worktree-root' || arg.startsWith('--git-worktree-root='))) {
|
|
139
|
+
fail('SANDBOX_CONTROL_REQUEST_INVALID', 'worktree binding is reserved for the control broker');
|
|
95
140
|
}
|
|
96
141
|
return request as SandboxTaskCommandRequest;
|
|
97
142
|
}
|
|
98
143
|
|
|
99
|
-
export function bindSandboxControlTask(
|
|
100
|
-
request
|
|
101
|
-
|
|
102
|
-
): string[] {
|
|
103
|
-
if (request.family === 'task-create') {
|
|
104
|
-
throw new Error('SANDBOX_CONTROL_REQUEST_INVALID: task-create requests do not bind a current task');
|
|
105
|
-
}
|
|
106
|
-
if (request.args.length === 0) {
|
|
107
|
-
throw new Error('SANDBOX_CONTROL_REQUEST_INVALID: command arguments are required');
|
|
108
|
-
}
|
|
144
|
+
export function bindSandboxControlTask(request: SandboxControlRequest, taskId: string): string[] {
|
|
145
|
+
if (request.family === 'task-create') fail('SANDBOX_CONTROL_REQUEST_INVALID', 'task-create requests do not bind a current task');
|
|
146
|
+
if (request.args.length === 0) fail('SANDBOX_CONTROL_REQUEST_INVALID', 'command arguments are required');
|
|
109
147
|
return [taskId, ...request.args.slice(1)];
|
|
110
148
|
}
|
|
149
|
+
|
|
150
|
+
export function controlError(error: unknown): SandboxControlError {
|
|
151
|
+
if (error instanceof SandboxControlProtocolError) {
|
|
152
|
+
return { code: error.code, message: error.message, retryable: error.retryable };
|
|
153
|
+
}
|
|
154
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
155
|
+
const code = /^([A-Z][A-Z0-9_]+)/.exec(message)?.[1] ?? 'SANDBOX_CONTROL_INTERNAL_ERROR';
|
|
156
|
+
const retryable = new Set([
|
|
157
|
+
'SANDBOX_CONTROL_BUSY',
|
|
158
|
+
'SANDBOX_CONTROL_HANDOFF_ACTIVE',
|
|
159
|
+
'SANDBOX_CONTROL_REQUEST_EXPIRED',
|
|
160
|
+
'SANDBOX_WORKTREE_BINDING_LOST'
|
|
161
|
+
]).has(code);
|
|
162
|
+
return { code, message, retryable };
|
|
163
|
+
}
|