@fitlab-ai/agent-infra 0.9.6 → 0.9.8
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 +10 -0
- package/dist/lib/agent-clients/adapters/claude-code.js +3 -3
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +47 -5
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +162 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +245 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +398 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +23 -6
- package/dist/lib/decide.js +68 -14
- package/dist/lib/defaults.json +10 -2
- package/dist/lib/git/workflow.js +30 -3
- package/dist/lib/init.js +1 -1
- package/dist/lib/internal/codex-lifecycle.js +69 -1
- package/dist/lib/internal/codex-sandbox-controller.js +106 -0
- package/dist/lib/internal/release-workflow.js +1 -3
- package/dist/lib/internal/task-activity.js +57 -7
- package/dist/lib/internal/task-event.js +57 -4
- package/dist/lib/internal/task-ledger.js +59 -5
- package/dist/lib/internal/task-lifecycle.js +59 -8
- package/dist/lib/internal/task-orchestration.js +48 -8
- package/dist/lib/internal/task-override.js +131 -0
- package/dist/lib/internal/task-review.js +64 -6
- package/dist/lib/internal/task-verify.js +65 -3
- package/dist/lib/internal/task-warning.js +57 -4
- package/dist/lib/platform/context.js +6 -4
- package/dist/lib/platform/github-client.js +55 -2
- package/dist/lib/platform/pr-summary.js +5 -3
- 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/runtime/agent-runtime.js +56 -0
- package/dist/lib/sandbox/commands/create.js +394 -264
- package/dist/lib/sandbox/commands/rm.js +64 -15
- package/dist/lib/sandbox/commands/start.js +4 -3
- package/dist/lib/sandbox/control/container-identity.js +64 -0
- package/dist/lib/sandbox/control/executor.js +23 -9
- package/dist/lib/sandbox/control/lifecycle.js +590 -61
- package/dist/lib/sandbox/control/protocol.js +7 -0
- package/dist/lib/sandbox/control/server.js +202 -26
- package/dist/lib/sandbox/control/state.js +51 -25
- package/dist/lib/sandbox/control/timing.js +8 -0
- package/dist/lib/sandbox/engine.js +14 -7
- package/dist/lib/sandbox/mounts.js +7 -0
- package/dist/lib/sandbox/recovery.js +135 -50
- package/dist/lib/sandbox/workspace-view.js +59 -20
- package/dist/lib/server/daemon.js +1 -1
- package/dist/lib/server/process-control.js +11 -1
- package/dist/lib/server/process-state.js +107 -20
- package/dist/lib/task/activity-intent.js +4 -1
- package/dist/lib/task/artifact-lifecycle.js +82 -11
- package/dist/lib/task/artifact-receipts.js +128 -0
- package/dist/lib/task/codex-orchestration.js +81 -6
- package/dist/lib/task/commands/validate.js +1 -1
- package/dist/lib/task/create.js +10 -2
- package/dist/lib/task/decision-intents.js +4 -2
- package/dist/lib/task/delegation-receipts.js +120 -17
- package/dist/lib/task/events.js +148 -7
- package/dist/lib/task/guard-override.js +31 -0
- package/dist/lib/task/human-override.js +1240 -0
- package/dist/lib/task/ledger-intents.js +6 -3
- package/dist/lib/task/ledger.js +13 -1
- package/dist/lib/task/lifecycle.js +69 -14
- package/dist/lib/task/orchestration.js +293 -18
- package/dist/lib/task/review-finalization.js +3 -2
- 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 +80 -22
- package/dist/lib/task/verification.js +13 -1
- package/dist/lib/task/workflow-warning-intents.js +4 -2
- package/dist/lib/task/write.js +2 -1
- package/dist/lifecycle-build-manifest.json +6 -0
- package/lib/agent-clients/adapters/claude-code.ts +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +62 -4
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +227 -0
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +322 -0
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +26 -0
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +480 -0
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +35 -5
- package/lib/decide.ts +59 -14
- package/lib/defaults.json +10 -2
- package/lib/git/workflow.ts +25 -2
- package/lib/init.ts +1 -1
- package/lib/internal/codex-lifecycle.ts +68 -1
- package/lib/internal/codex-sandbox-controller.ts +109 -0
- package/lib/internal/release-workflow.ts +1 -3
- package/lib/internal/task-activity.ts +46 -6
- package/lib/internal/task-event.ts +53 -4
- package/lib/internal/task-ledger.ts +48 -4
- package/lib/internal/task-lifecycle.ts +56 -12
- package/lib/internal/task-orchestration.ts +43 -8
- package/lib/internal/task-override.ts +138 -0
- package/lib/internal/task-review.ts +51 -6
- package/lib/internal/task-verify.ts +52 -3
- package/lib/internal/task-warning.ts +44 -3
- package/lib/platform/context.ts +8 -5
- package/lib/platform/github-client.ts +61 -3
- package/lib/platform/pr-summary.ts +10 -3
- 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/runtime/agent-runtime.ts +76 -0
- package/lib/sandbox/commands/create.ts +139 -6
- package/lib/sandbox/commands/rm.ts +64 -14
- package/lib/sandbox/commands/start.ts +4 -3
- package/lib/sandbox/config.ts +2 -1
- package/lib/sandbox/control/container-identity.ts +93 -0
- package/lib/sandbox/control/executor.ts +24 -12
- package/lib/sandbox/control/lifecycle.ts +685 -67
- package/lib/sandbox/control/protocol.ts +35 -6
- package/lib/sandbox/control/server.ts +184 -24
- package/lib/sandbox/control/state.ts +67 -33
- package/lib/sandbox/control/timing.ts +12 -0
- package/lib/sandbox/engine.ts +20 -9
- package/lib/sandbox/mounts.ts +8 -0
- package/lib/sandbox/recovery.ts +159 -49
- package/lib/sandbox/workspace-view.ts +73 -22
- package/lib/server/daemon.ts +1 -1
- package/lib/server/process-control.ts +13 -3
- package/lib/server/process-state.ts +129 -27
- package/lib/task/activity-intent.ts +4 -2
- package/lib/task/artifact-lifecycle.ts +73 -10
- package/lib/task/artifact-receipts.ts +161 -0
- package/lib/task/codex-orchestration.ts +91 -5
- package/lib/task/commands/validate.ts +1 -1
- package/lib/task/create.ts +11 -2
- package/lib/task/decision-intents.ts +4 -2
- package/lib/task/delegation-receipts.ts +205 -25
- package/lib/task/events.ts +132 -6
- package/lib/task/guard-override.ts +50 -0
- package/lib/task/human-override.ts +1503 -0
- package/lib/task/ledger-intents.ts +6 -3
- package/lib/task/ledger.ts +16 -1
- package/lib/task/lifecycle.ts +71 -14
- package/lib/task/orchestration.ts +443 -22
- package/lib/task/review-finalization.ts +6 -2
- package/lib/task/sections.ts +6 -2
- package/lib/task/task-execution-lock.ts +11 -9
- package/lib/task/verification-engine.ts +93 -32
- package/lib/task/verification.ts +15 -1
- package/lib/task/workflow-warning-intents.ts +4 -2
- package/lib/task/write.ts +4 -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 +33 -4
- package/templates/.agents/rules/lifecycle-orchestration.en.md +10 -3
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +10 -3
- 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/run-manual-validation/SKILL.en.md +6 -6
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/run-manual-validation/config/verify.en.json +14 -3
- package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +14 -3
- 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 +25 -0
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +25 -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 -1
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +5 -1
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +75 -3
- package/templates/.agents/workspace/README.en.md +0 -26
- package/templates/.agents/workspace/README.zh-CN.md +0 -26
|
@@ -11,7 +11,8 @@ import { assertManagedPath, removeManagedDir, removeWorktreeDir } from '../manag
|
|
|
11
11
|
import { runEngine, runOk, runOkEngine, runSafe, runSafeEngine } from '../shell.js';
|
|
12
12
|
import { resolveSandboxTarget } from '../workspace-identity.js';
|
|
13
13
|
import { sandboxControlPaths, sandboxWorkspaceViewPaths } from '../workspace-view.js';
|
|
14
|
-
import {
|
|
14
|
+
import { removeSandboxControlRoot, readSandboxControlManifest } from '../control/lifecycle.js';
|
|
15
|
+
import { inspectSandboxControlContainer } from '../control/container-identity.js';
|
|
15
16
|
import { toolConfigDirCandidates, toolProjectDirCandidates } from '../tools.js';
|
|
16
17
|
import { createSandboxCapabilityPlan } from '../agent-client-reconciler.js';
|
|
17
18
|
import { fetchSandboxRows } from './list-running.js';
|
|
@@ -118,10 +119,39 @@ function removeEmptyManagedParent(base, directory) {
|
|
|
118
119
|
}
|
|
119
120
|
assertRemoved(parent, 'Empty sandbox container directory');
|
|
120
121
|
}
|
|
121
|
-
async function
|
|
122
|
+
async function removeExactSandboxContainer(engine, manifest, timeoutMs) {
|
|
123
|
+
const deadlineAt = Date.now() + timeoutMs;
|
|
124
|
+
const remaining = () => Math.max(1, deadlineAt - Date.now());
|
|
125
|
+
const inspect = () => inspectSandboxControlContainer(manifest, { timeoutMs: remaining() });
|
|
126
|
+
const before = await inspect();
|
|
127
|
+
if (before.state === 'unknown')
|
|
128
|
+
throw new Error(`SANDBOX_CONTROL_CONTAINER_UNKNOWN: ${before.reason}`);
|
|
129
|
+
if (before.state === 'absent')
|
|
130
|
+
return;
|
|
131
|
+
if (before.running && !runOkEngine(engine, 'docker', ['stop', manifest.containerIdentity.id], { timeout: remaining() })) {
|
|
132
|
+
const afterStop = await inspect();
|
|
133
|
+
if (afterStop.state !== 'absent' && afterStop.state !== 'found') {
|
|
134
|
+
throw new Error(`SANDBOX_CONTROL_CONTAINER_UNKNOWN: ${afterStop.reason}`);
|
|
135
|
+
}
|
|
136
|
+
if (afterStop.state === 'found' && afterStop.running) {
|
|
137
|
+
throw new Error(`Failed to stop sandbox container: ${manifest.containerIdentity.id}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const afterStop = await inspect();
|
|
141
|
+
if (afterStop.state === 'unknown')
|
|
142
|
+
throw new Error(`SANDBOX_CONTROL_CONTAINER_UNKNOWN: ${afterStop.reason}`);
|
|
143
|
+
if (afterStop.state === 'found' && !runOkEngine(engine, 'docker', ['rm', manifest.containerIdentity.id], { timeout: remaining() })) {
|
|
144
|
+
const afterRemove = await inspect();
|
|
145
|
+
if (afterRemove.state !== 'absent') {
|
|
146
|
+
throw new Error(`Failed to remove sandbox container: ${manifest.containerIdentity.id}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function removeProjectControlRoots(config, engine) {
|
|
151
|
+
const containers = new Set();
|
|
122
152
|
const projectRoot = path.join(config.controlBase, config.project);
|
|
123
153
|
if (!fs.existsSync(projectRoot))
|
|
124
|
-
return;
|
|
154
|
+
return containers;
|
|
125
155
|
assertManagedPath(config.controlBase, projectRoot);
|
|
126
156
|
const projectStat = fs.lstatSync(projectRoot);
|
|
127
157
|
if (!projectStat.isDirectory() || projectStat.isSymbolicLink())
|
|
@@ -133,9 +163,19 @@ async function quiesceProjectControlRoots(config) {
|
|
|
133
163
|
for (const identity of fs.readdirSync(containerRoot, { withFileTypes: true })) {
|
|
134
164
|
if (!identity.isDirectory() || identity.isSymbolicLink())
|
|
135
165
|
continue;
|
|
136
|
-
|
|
166
|
+
const root = path.join(containerRoot, identity.name);
|
|
167
|
+
const manifestPath = path.join(root, 'manifest.json');
|
|
168
|
+
if (!fs.existsSync(manifestPath))
|
|
169
|
+
throw new Error(`SANDBOX_CONTROL_TARGET_EVIDENCE_MISSING: ${root}`);
|
|
170
|
+
const manifest = readSandboxControlManifest(manifestPath);
|
|
171
|
+
containers.add(manifest.container);
|
|
172
|
+
await removeSandboxControlRoot(root, {
|
|
173
|
+
inspectContainer: (timeoutMs) => inspectSandboxControlContainer(manifest, { timeoutMs }),
|
|
174
|
+
removeContainer: (timeoutMs) => removeExactSandboxContainer(engine, manifest, timeoutMs)
|
|
175
|
+
});
|
|
137
176
|
}
|
|
138
177
|
}
|
|
178
|
+
return containers;
|
|
139
179
|
}
|
|
140
180
|
function inspectionBlockers(inspections) {
|
|
141
181
|
return inspections.filter((inspection) => inspection.status !== 'clean');
|
|
@@ -211,25 +251,32 @@ async function rmOne(config, tools, branch, options = {}) {
|
|
|
211
251
|
p.outro('Cancelled');
|
|
212
252
|
return;
|
|
213
253
|
}
|
|
254
|
+
const coordinatedContainers = new Set();
|
|
214
255
|
for (const root of controlRoots.filter((candidate) => fs.existsSync(candidate))) {
|
|
215
256
|
assertLegacyCandidateEvidence(root, config.controlBase, config, effectiveBranch, matchedContainers);
|
|
216
257
|
assertControlRootMatchesTarget(root, effectiveBranch, workspace);
|
|
217
|
-
|
|
258
|
+
const manifest = readSandboxControlManifest(path.join(root, 'manifest.json'));
|
|
259
|
+
coordinatedContainers.add(manifest.container);
|
|
260
|
+
await removeSandboxControlRoot(root, {
|
|
261
|
+
inspectContainer: (timeoutMs) => inspectSandboxControlContainer(manifest, { timeoutMs }),
|
|
262
|
+
removeContainer: (timeoutMs) => removeExactSandboxContainer(engine, manifest, timeoutMs)
|
|
263
|
+
});
|
|
218
264
|
}
|
|
219
|
-
|
|
265
|
+
const uncoordinatedContainers = matchedContainers.filter((name) => !coordinatedContainers.has(name));
|
|
266
|
+
if (uncoordinatedContainers.length > 0) {
|
|
220
267
|
const spinner = p.spinner();
|
|
221
|
-
spinner.start(`Stopping container(s): ${
|
|
222
|
-
for (const name of
|
|
268
|
+
spinner.start(`Stopping container(s): ${uncoordinatedContainers.join(', ')}`);
|
|
269
|
+
for (const name of uncoordinatedContainers) {
|
|
223
270
|
if (!runOkEngine(engine, 'docker', ['stop', name]))
|
|
224
271
|
throw new Error(`Failed to stop sandbox container: ${name}`);
|
|
225
272
|
if (!runOkEngine(engine, 'docker', ['rm', name]))
|
|
226
273
|
throw new Error(`Failed to remove sandbox container: ${name}`);
|
|
227
274
|
}
|
|
228
275
|
const remaining = runEngine(engine, 'docker', ['ps', '-a', '--format', '{{.Names}}']).split('\n').filter(Boolean);
|
|
229
|
-
const leftovers =
|
|
276
|
+
const leftovers = uncoordinatedContainers.filter((name) => remaining.includes(name));
|
|
230
277
|
if (leftovers.length > 0)
|
|
231
278
|
throw new Error(`Sandbox container(s) still exist after removal: ${leftovers.join(', ')}`);
|
|
232
|
-
spinner.stop(pc.green(`Removed container(s): ${
|
|
279
|
+
spinner.stop(pc.green(`Removed container(s): ${uncoordinatedContainers.join(', ')}`));
|
|
233
280
|
}
|
|
234
281
|
else {
|
|
235
282
|
p.log.warn(`No sandbox container found for '${branch}'`);
|
|
@@ -330,7 +377,7 @@ async function rmPurge(config, tools, prompt = {}) {
|
|
|
330
377
|
throw new Error(`Refusing to purge because worktree preflight found blocker(s):\n${blockerMessage(blockers)}`);
|
|
331
378
|
}
|
|
332
379
|
const permits = cleanPermits(inspections);
|
|
333
|
-
await
|
|
380
|
+
const coordinatedContainers = await removeProjectControlRoots(config, engine);
|
|
334
381
|
const containers = runEngine(engine, 'docker', [
|
|
335
382
|
'ps',
|
|
336
383
|
'-a',
|
|
@@ -339,10 +386,11 @@ async function rmPurge(config, tools, prompt = {}) {
|
|
|
339
386
|
'--format',
|
|
340
387
|
'{{.Names}}'
|
|
341
388
|
]);
|
|
342
|
-
|
|
389
|
+
const uncoordinatedContainers = containers.split('\n').filter((name) => name && !coordinatedContainers.has(name));
|
|
390
|
+
if (uncoordinatedContainers.length > 0) {
|
|
343
391
|
const spinner = p.spinner();
|
|
344
392
|
spinner.start('Stopping project sandbox containers...');
|
|
345
|
-
for (const name of
|
|
393
|
+
for (const name of uncoordinatedContainers) {
|
|
346
394
|
if (!runOkEngine(engine, 'docker', ['stop', name]))
|
|
347
395
|
throw new Error(`Failed to stop sandbox container: ${name}`);
|
|
348
396
|
if (!runOkEngine(engine, 'docker', ['rm', name]))
|
|
@@ -351,8 +399,9 @@ async function rmPurge(config, tools, prompt = {}) {
|
|
|
351
399
|
const remaining = runEngine(engine, 'docker', [
|
|
352
400
|
'ps', '-a', '--filter', `label=${sandboxLabel(config)}`, '--format', '{{.Names}}'
|
|
353
401
|
]);
|
|
354
|
-
|
|
355
|
-
|
|
402
|
+
const leftovers = remaining.split('\n').filter((name) => name && !coordinatedContainers.has(name));
|
|
403
|
+
if (leftovers.length > 0)
|
|
404
|
+
throw new Error(`Project sandbox container(s) still exist after removal: ${leftovers.join(', ')}`);
|
|
356
405
|
spinner.stop(pc.green('Project sandbox containers removed'));
|
|
357
406
|
}
|
|
358
407
|
else {
|
|
@@ -8,9 +8,9 @@ const USAGE = `Usage: ai sandbox start [--recreate] <branch | TASK-id | N>
|
|
|
8
8
|
|
|
9
9
|
Start an existing sandbox container that has stopped (for example after the
|
|
10
10
|
Docker daemon was restarted or replaced). The container must already exist:
|
|
11
|
-
if none is found, run 'ai sandbox create <branch>' first.
|
|
12
|
-
already running is checked without modifying healthy runtime
|
|
13
|
-
|
|
11
|
+
if none is found, run 'ai sandbox create <branch>' first. Without --recreate, a
|
|
12
|
+
container that is already running is checked without modifying healthy runtime
|
|
13
|
+
state. --recreate replaces the existing container even when it is healthy.`;
|
|
14
14
|
export function parseStartArgs(args) {
|
|
15
15
|
let recreate = false;
|
|
16
16
|
let help = false;
|
|
@@ -62,6 +62,7 @@ export async function start(args) {
|
|
|
62
62
|
workspace: target.workspace,
|
|
63
63
|
row: found,
|
|
64
64
|
allowRecreate: parsed.recreate,
|
|
65
|
+
forceRecreate: parsed.recreate,
|
|
65
66
|
recreate: async () => {
|
|
66
67
|
const { create } = await import('./create.js');
|
|
67
68
|
await create([target.requestedRef, '--no-refresh']);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { commandForEngine, runEngine, runProbe } from '../shell.js';
|
|
2
|
+
function isAuthoritativeNotFound(error) {
|
|
3
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4
|
+
return /(?:no such (?:container|object)|container .* not found|cannot find container)/i.test(message);
|
|
5
|
+
}
|
|
6
|
+
export function classifySandboxContainerInspection(expected, inspection) {
|
|
7
|
+
if ('notFound' in inspection)
|
|
8
|
+
return { state: 'absent', id: expected.id };
|
|
9
|
+
if ('error' in inspection) {
|
|
10
|
+
return isAuthoritativeNotFound(inspection.error)
|
|
11
|
+
? { state: 'absent', id: expected.id }
|
|
12
|
+
: { state: 'unknown', reason: `container inspection failed: ${inspection.error instanceof Error ? inspection.error.message : String(inspection.error)}` };
|
|
13
|
+
}
|
|
14
|
+
const response = inspection;
|
|
15
|
+
if (typeof response.id !== 'string' || response.id !== expected.id
|
|
16
|
+
|| typeof response.running !== 'boolean' || !response.labels
|
|
17
|
+
|| typeof response.labels !== 'object' || Array.isArray(response.labels)) {
|
|
18
|
+
return { state: 'unknown', reason: 'container inspection response is incomplete' };
|
|
19
|
+
}
|
|
20
|
+
const labels = response.labels;
|
|
21
|
+
for (const [key, value] of Object.entries(expected.labels)) {
|
|
22
|
+
if (labels[key] !== value)
|
|
23
|
+
return { state: 'unknown', reason: 'container labels do not match the manifest' };
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
state: 'found',
|
|
27
|
+
id: response.id,
|
|
28
|
+
running: response.running,
|
|
29
|
+
labels: Object.fromEntries(Object.entries(labels).flatMap(([key, value]) => typeof value === 'string' ? [[key, value]] : []))
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export async function inspectSandboxControlContainer(manifest, options = {}) {
|
|
33
|
+
try {
|
|
34
|
+
const args = ['inspect', '--format', '{{json .}}', manifest.containerIdentity.id];
|
|
35
|
+
let raw;
|
|
36
|
+
if (options.run) {
|
|
37
|
+
raw = options.run(manifest.engine, 'docker', args, options.timeoutMs === undefined ? {} : { timeout: options.timeoutMs });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const command = commandForEngine(manifest.engine, 'docker', args);
|
|
41
|
+
const result = (options.probe ?? runProbe)(command.cmd, command.args, options.timeoutMs === undefined ? {} : { timeout: options.timeoutMs });
|
|
42
|
+
if (result.status !== 0) {
|
|
43
|
+
const stderr = typeof result.stderr === 'string' ? result.stderr : result.stderr?.toString('utf8') ?? '';
|
|
44
|
+
return classifySandboxContainerInspection(manifest.containerIdentity, {
|
|
45
|
+
error: new Error(stderr || `container inspection exited with ${result.status ?? 'unknown'}`)
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
raw = typeof result.stdout === 'string' ? result.stdout : result.stdout?.toString('utf8') ?? '';
|
|
49
|
+
}
|
|
50
|
+
const parsed = JSON.parse(raw);
|
|
51
|
+
const value = Array.isArray(parsed) && parsed.length === 1 ? parsed[0] : parsed;
|
|
52
|
+
if (!value || Array.isArray(value))
|
|
53
|
+
return { state: 'unknown', reason: 'container inspection response is incomplete' };
|
|
54
|
+
return classifySandboxContainerInspection(manifest.containerIdentity, {
|
|
55
|
+
id: value.Id,
|
|
56
|
+
running: value.State?.Running,
|
|
57
|
+
labels: value.Config?.Labels
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return classifySandboxContainerInspection(manifest.containerIdentity, { error });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=container-identity.js.map
|
|
@@ -18,7 +18,7 @@ async function waitForStartTime(pid, timeoutMs = 2_000) {
|
|
|
18
18
|
const deadline = Date.now() + timeoutMs;
|
|
19
19
|
while (Date.now() < deadline) {
|
|
20
20
|
const startTime = getProcessStartTime(pid);
|
|
21
|
-
if (startTime)
|
|
21
|
+
if (startTime !== null)
|
|
22
22
|
return startTime;
|
|
23
23
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
24
24
|
}
|
|
@@ -32,7 +32,11 @@ export async function prepareSandboxControlExecution(params) {
|
|
|
32
32
|
cwd: params.manifest.repoRoot,
|
|
33
33
|
detached: process.platform !== 'win32',
|
|
34
34
|
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
|
35
|
-
env: {
|
|
35
|
+
env: {
|
|
36
|
+
...safeEnv(process.env),
|
|
37
|
+
AGENT_INFRA_EXECUTOR_MANIFEST: params.manifestPath,
|
|
38
|
+
AGENT_INFRA_RUNTIME_DIR: params.manifest.runtimeDir
|
|
39
|
+
}
|
|
36
40
|
});
|
|
37
41
|
if (typeof child.pid !== 'number')
|
|
38
42
|
throw new Error('SANDBOX_CONTROL_EXECUTOR_SPAWN_FAILED');
|
|
@@ -48,7 +52,7 @@ export async function prepareSandboxControlExecution(params) {
|
|
|
48
52
|
});
|
|
49
53
|
const startTime = await waitForStartTime(child.pid);
|
|
50
54
|
const execution = {
|
|
51
|
-
version:
|
|
55
|
+
version: 2,
|
|
52
56
|
generation: params.manifest.generation,
|
|
53
57
|
requestId: params.request.id,
|
|
54
58
|
nonce,
|
|
@@ -63,17 +67,23 @@ export async function prepareSandboxControlExecution(params) {
|
|
|
63
67
|
atomicWriteJson(executionPath(params.manifest, params.request.id), execution);
|
|
64
68
|
return {
|
|
65
69
|
execution,
|
|
66
|
-
start() {
|
|
70
|
+
start(canWrite = () => true) {
|
|
67
71
|
if (!child.connected)
|
|
68
72
|
throw new Error('SANDBOX_CONTROL_EXECUTOR_GATE_CLOSED');
|
|
73
|
+
if (!canWrite())
|
|
74
|
+
throw new Error('SANDBOX_CONTROL_OWNER_LOST');
|
|
69
75
|
atomicWriteJson(executionPath(params.manifest, params.request.id), { ...execution, phase: 'running', updatedAt: Date.now() });
|
|
76
|
+
if (!canWrite())
|
|
77
|
+
throw new Error('SANDBOX_CONTROL_OWNER_LOST');
|
|
70
78
|
child.send({ version: 1, nonce });
|
|
71
79
|
},
|
|
72
80
|
completion,
|
|
73
|
-
terminate() {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
terminate(updateState = true) {
|
|
82
|
+
if (updateState) {
|
|
83
|
+
atomicWriteJson(executionPath(params.manifest, params.request.id), {
|
|
84
|
+
...execution, phase: 'terminating', updatedAt: Date.now()
|
|
85
|
+
});
|
|
86
|
+
}
|
|
77
87
|
return terminateSandboxControlExecution(execution);
|
|
78
88
|
}
|
|
79
89
|
};
|
|
@@ -110,7 +120,11 @@ function executeRequest(manifest, request) {
|
|
|
110
120
|
const boundArgs = bindSandboxControlTask(request, manifest.taskId);
|
|
111
121
|
if (request.family === 'task-orchestration')
|
|
112
122
|
boundArgs.push('--git-worktree-root', manifest.worktreeRoot);
|
|
113
|
-
const result = spawnSync(process.execPath, nodeEntryArgs(process.argv[1], [request.family, ...boundArgs]), {
|
|
123
|
+
const result = spawnSync(process.execPath, nodeEntryArgs(process.argv[1], [request.family, ...boundArgs]), {
|
|
124
|
+
cwd: manifest.repoRoot,
|
|
125
|
+
encoding: 'utf8',
|
|
126
|
+
env: { ...safeEnv(process.env), AGENT_INFRA_RUNTIME_DIR: manifest.runtimeDir }
|
|
127
|
+
});
|
|
114
128
|
return { exitCode: result.status ?? 1, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
|
|
115
129
|
}
|
|
116
130
|
export async function runSandboxControlExecutor(requestPath, nonce) {
|