@fitlab-ai/agent-infra 0.11.13 → 0.11.15
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 +2 -7
- package/dist/lib/agent-clients/adapter.js +0 -3
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +5 -9
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +1 -5
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +1 -5
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +1 -3
- package/dist/lib/agent-clients/adapters/codex.js +0 -2
- package/dist/lib/internal/cli-route-inventory.js +0 -1
- package/dist/lib/internal/task-finalization.js +7 -5
- package/dist/lib/internal/task-lifecycle.js +3 -1
- package/dist/lib/internal/task-operation-registry.js +1 -3
- package/dist/lib/internal/task-validate.js +14 -124
- package/dist/lib/platform/pr-change-report.js +10 -3
- package/dist/lib/platform/release-notes.js +2 -2
- package/dist/lib/process-data/index.js +15 -4
- package/dist/lib/sandbox/commands/control-status.js +0 -1
- package/dist/lib/sandbox/commands/create.js +5 -4
- package/dist/lib/sandbox/config.js +12 -0
- package/dist/lib/sandbox/control/audit.js +1 -2
- package/dist/lib/sandbox/control/client.js +12 -47
- package/dist/lib/sandbox/control/executor.js +6 -10
- package/dist/lib/sandbox/control/host-recovery.js +89 -27
- package/dist/lib/sandbox/control/lifecycle.js +22 -37
- package/dist/lib/sandbox/control/protocol.js +8 -36
- package/dist/lib/sandbox/control/server.js +2 -21
- package/dist/lib/sandbox/environment.js +7 -8
- package/dist/lib/sandbox/mounts.js +71 -59
- package/dist/lib/sandbox/recovery.js +2 -3
- package/dist/lib/sandbox/removal.js +19 -4
- package/dist/lib/sandbox/workspace-identity.js +30 -15
- package/dist/lib/sandbox/workspace-view.js +41 -4
- package/dist/lib/task/control-authority.js +39 -17
- package/dist/lib/task/control-recovery.js +1 -2
- package/dist/lib/task/finalization.js +13 -2
- package/dist/lib/task/lifecycle.js +122 -35
- package/dist/lib/task/short-id.js +2 -2
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapter.ts +0 -27
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +6 -12
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +1 -5
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -7
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +1 -5
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +1 -4
- package/lib/agent-clients/adapters/codex-orchestration.ts +1 -3
- package/lib/agent-clients/adapters/codex.ts +0 -2
- package/lib/internal/cli-route-inventory.ts +0 -1
- package/lib/internal/task-finalization.ts +8 -6
- package/lib/internal/task-lifecycle.ts +3 -1
- package/lib/internal/task-operation-registry.ts +1 -3
- package/lib/internal/task-validate.ts +13 -127
- package/lib/platform/pr-change-report.ts +9 -3
- package/lib/platform/release-notes.ts +2 -2
- package/lib/process-data/index.ts +15 -4
- package/lib/sandbox/commands/control-status.ts +0 -1
- package/lib/sandbox/commands/create.ts +5 -4
- package/lib/sandbox/config.ts +13 -0
- package/lib/sandbox/control/audit.ts +1 -2
- package/lib/sandbox/control/client.ts +13 -61
- package/lib/sandbox/control/executor.ts +7 -13
- package/lib/sandbox/control/host-recovery.ts +94 -21
- package/lib/sandbox/control/lifecycle.ts +22 -37
- package/lib/sandbox/control/protocol.ts +9 -45
- package/lib/sandbox/control/server.ts +2 -17
- package/lib/sandbox/environment.ts +7 -8
- package/lib/sandbox/mounts.ts +92 -75
- package/lib/sandbox/recovery.ts +2 -3
- package/lib/sandbox/removal.ts +16 -4
- package/lib/sandbox/workspace-identity.ts +36 -13
- package/lib/sandbox/workspace-view.ts +40 -5
- package/lib/task/control-authority.ts +40 -26
- package/lib/task/control-recovery.ts +2 -3
- package/lib/task/finalization.ts +15 -2
- package/lib/task/lifecycle.ts +135 -33
- package/lib/task/short-id.ts +5 -2
- package/package.json +1 -1
- package/templates/.agents/rules/lifecycle-orchestration.en.md +3 -4
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +3 -4
- package/templates/.agents/rules/task-short-id.en.md +18 -12
- package/templates/.agents/rules/task-short-id.zh-CN.md +12 -7
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -2
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -2
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +12 -2
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +12 -2
- package/templates/.agents/skills/create-release-note/SKILL.en.md +3 -1
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +5 -5
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +13 -2
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +13 -2
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -0
- 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/skills/watch-pr/SKILL.en.md +19 -2
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +20 -3
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +14 -0
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +15 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-client.js +0 -130
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-context.js +0 -127
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-operation.js +0 -131
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-registration.js +0 -275
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.js +0 -106
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +0 -345
- package/dist/lib/runtime/agent-runtime.js +0 -33
- package/dist/lib/sandbox/control/agent-operation.js +0 -34
- package/dist/lib/task/runtime-paths.js +0 -10
- package/lib/agent-clients/adapters/codex-lifecycle/controller-client.ts +0 -158
- package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +0 -163
- package/lib/agent-clients/adapters/codex-lifecycle/controller-operation.ts +0 -151
- package/lib/agent-clients/adapters/codex-lifecycle/controller-registration.ts +0 -352
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.ts +0 -109
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +0 -437
- package/lib/runtime/agent-runtime.ts +0 -41
- package/lib/sandbox/control/agent-operation.ts +0 -49
- package/lib/task/runtime-paths.ts +0 -12
package/dist/bin/internal-cli.js
CHANGED
|
@@ -17,9 +17,9 @@ const taskWorkflowCommand = command === 'task-artifact'
|
|
|
17
17
|
const taskPlatformRecoveryCommand = command === 'task-platform-recovery';
|
|
18
18
|
const manualValidationWorkflowCommand = command === 'manual-validation';
|
|
19
19
|
const taskControlMarkers = [
|
|
20
|
-
'AGENT_INFRA_TASK_ID', '
|
|
20
|
+
'AGENT_INFRA_TASK_ID', 'AGENT_INFRA_CONTROL_GENERATION',
|
|
21
21
|
'AGENT_INFRA_CONTROL_DIR', 'AGENT_INFRA_CONTROL_STATUS_DIR', 'AGENT_INFRA_RUNTIME_DIR',
|
|
22
|
-
'
|
|
22
|
+
'AGENT_INFRA_EXECUTOR_MANIFEST'
|
|
23
23
|
];
|
|
24
24
|
const markerlessHelp = ['--help', '-h'].includes(process.argv[3] ?? '')
|
|
25
25
|
&& taskControlMarkers.every((key) => !process.env[key]);
|
|
@@ -115,11 +115,6 @@ if (!controlRouted && !taskViewGuardFailed && internalRouteRegistered)
|
|
|
115
115
|
await codexLifecycle(process.argv.slice(3));
|
|
116
116
|
break;
|
|
117
117
|
}
|
|
118
|
-
case 'codex-sandbox-controller': {
|
|
119
|
-
const { codexSandboxController } = await import('../lib/agent-clients/adapters/codex-lifecycle/sandbox-controller-cli.js');
|
|
120
|
-
await codexSandboxController(process.argv.slice(3));
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
118
|
case 'git-workflow': {
|
|
124
119
|
const { gitWorkflow } = await import('../lib/internal/git-workflow.js');
|
|
125
120
|
gitWorkflow(process.argv.slice(3));
|
|
@@ -434,9 +434,6 @@ function defineAgentClientAdapter(candidate) {
|
|
|
434
434
|
...(candidate.orchestrationAdapter === undefined
|
|
435
435
|
? {}
|
|
436
436
|
: { orchestrationAdapter: Object.freeze({ ...candidate.orchestrationAdapter }) }),
|
|
437
|
-
...(candidate.sandboxControlOperation === undefined
|
|
438
|
-
? {}
|
|
439
|
-
: { sandboxControlOperation: Object.freeze({ ...candidate.sandboxControlOperation }) }),
|
|
440
437
|
project: Object.freeze({
|
|
441
438
|
ownedPathPrefixes: Object.freeze(paths),
|
|
442
439
|
...projectAssets,
|
|
@@ -114,7 +114,7 @@ function validateCodexLifecycleHookConfig(value) {
|
|
|
114
114
|
if (!valid)
|
|
115
115
|
throw new Error('CODEX_PREFLIGHT_HOOKS_INVALID: lifecycle hooks are invalid');
|
|
116
116
|
}
|
|
117
|
-
function parseCodexHooksList(value, repoRoot
|
|
117
|
+
function parseCodexHooksList(value, repoRoot) {
|
|
118
118
|
const root = object(value);
|
|
119
119
|
const entries = Array.isArray(root?.data) ? root.data : [];
|
|
120
120
|
const entry = entries.map(object).find((candidate) => candidate?.cwd === repoRoot);
|
|
@@ -145,10 +145,8 @@ function parseCodexHooksList(value, repoRoot, expectedSource = 'direct-host') {
|
|
|
145
145
|
&& hook.currentHash.length > 0
|
|
146
146
|
&& hook.sourcePathDigest.length === 64
|
|
147
147
|
&& hook.pluginId === null
|
|
148
|
-
&& (
|
|
149
|
-
|
|
150
|
-
: (hook.source === 'project' && hook.trustStatus === 'trusted')
|
|
151
|
-
|| hook.isManaged && hook.trustStatus === 'managed')));
|
|
148
|
+
&& (hook.source === 'project' && hook.trustStatus === 'trusted'
|
|
149
|
+
|| hook.isManaged && hook.trustStatus === 'managed')));
|
|
152
150
|
if (!valid)
|
|
153
151
|
throw new Error('CODEX_PREFLIGHT_HOOKS_NOT_LOADED: lifecycle hooks are not loaded for this workspace');
|
|
154
152
|
return Object.freeze(hooks);
|
|
@@ -546,7 +544,7 @@ async function discoverLifecycleHooks(repoRoot) {
|
|
|
546
544
|
let discoveredHooks;
|
|
547
545
|
try {
|
|
548
546
|
await transport.initialize();
|
|
549
|
-
discoveredHooks = parseCodexHooksList(await transport.request('hooks/list', { cwds: [repoRoot] }), repoRoot
|
|
547
|
+
discoveredHooks = parseCodexHooksList(await transport.request('hooks/list', { cwds: [repoRoot] }), repoRoot);
|
|
550
548
|
}
|
|
551
549
|
finally {
|
|
552
550
|
transport.close();
|
|
@@ -564,9 +562,7 @@ async function discoverLifecycleHooks(repoRoot) {
|
|
|
564
562
|
throw new Error('CODEX_PREFLIGHT_HOOK_SOURCE_AMBIGUOUS: lifecycle hooks do not share one exact source');
|
|
565
563
|
}
|
|
566
564
|
const source = [...sources][0];
|
|
567
|
-
const hookSource =
|
|
568
|
-
? 'isolated-user'
|
|
569
|
-
: source === 'managed' ? 'managed' : 'project';
|
|
565
|
+
const hookSource = source === 'managed' ? 'managed' : 'project';
|
|
570
566
|
return {
|
|
571
567
|
discoveredHooks,
|
|
572
568
|
hookProvenance: Object.freeze({
|
|
@@ -4,7 +4,6 @@ import fs from 'node:fs';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { preflightCodexLifecycleEvidence, resolveCodexTerminal, resolveCodexThread } from './app-server.js';
|
|
6
6
|
import { createCodexLifecycleStore } from './store.js';
|
|
7
|
-
import { verifyCodexSandboxControllerContextWithWarnings } from './sandbox-controller.js';
|
|
8
7
|
import { resolveTaskRef } from '../../../task/resolve-ref.js';
|
|
9
8
|
import { resolveTaskContext } from '../../../task/resolve-ref.js';
|
|
10
9
|
import { hasSealableOrchestrationDelegation, readRun } from '../../../task/orchestration.js';
|
|
@@ -78,10 +77,7 @@ function hookDefinitionHash() {
|
|
|
78
77
|
return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
|
79
78
|
}
|
|
80
79
|
function resolveLifecycleTaskContext() {
|
|
81
|
-
const
|
|
82
|
-
const taskId = controllerPath
|
|
83
|
-
? verifyCodexSandboxControllerContextWithWarnings(controllerPath, { repoRoot: process.cwd() }).context.taskId
|
|
84
|
-
: process.env.AGENT_INFRA_TASK_ID;
|
|
80
|
+
const taskId = process.env.AGENT_INFRA_TASK_ID;
|
|
85
81
|
const context = taskId
|
|
86
82
|
? resolveTaskRef(taskId, { repoRoot: process.cwd() })
|
|
87
83
|
: resolveTaskContext(undefined, { repoRoot: process.cwd() });
|
|
@@ -136,14 +136,10 @@ function hostEvidenceMatches(record, receipt, host, start) {
|
|
|
136
136
|
&& host.spawnToolUseId === start.spawnToolUseId
|
|
137
137
|
&& Boolean(host.spawnObservedAt)
|
|
138
138
|
&& host.spawnObservedAt === record.spawnObservedAt
|
|
139
|
-
&& typeof host.controllerInstanceDigest === 'string'
|
|
140
|
-
&& typeof host.controlGeneration === 'string'
|
|
141
139
|
&& hostRevisionMatches(record, receipt, host);
|
|
142
140
|
}
|
|
143
141
|
function hostRevisionMatches(record, receipt, host) {
|
|
144
|
-
return
|
|
145
|
-
&& typeof host.controlGeneration === 'string'
|
|
146
|
-
&& host.startRevision >= 1
|
|
142
|
+
return host.startRevision >= 1
|
|
147
143
|
&& record.revision > host.startRevision
|
|
148
144
|
&& record.state.child?.childThreadId === receipt.childId
|
|
149
145
|
&& record.state.stop?.childThreadId === receipt.childId;
|
|
@@ -215,9 +215,7 @@ async function activateCodexOrchestrationDelegation(childThreadId, options = {})
|
|
|
215
215
|
capabilitySessionId: evidence.parentThreadId,
|
|
216
216
|
capabilityTurnId: evidence.parentTurnId,
|
|
217
217
|
spawnToolUseId: evidence.spawnToolUseId,
|
|
218
|
-
spawnObservedAt: record.spawnObservedAt ?? undefined
|
|
219
|
-
controllerInstanceDigest: null,
|
|
220
|
-
controlGeneration: null
|
|
218
|
+
spawnObservedAt: record.spawnObservedAt ?? undefined
|
|
221
219
|
}
|
|
222
220
|
}
|
|
223
221
|
}, coreOptions(options));
|
|
@@ -3,7 +3,6 @@ import { hostJoin } from '../../sandbox/engines/wsl2-paths.js';
|
|
|
3
3
|
import { codexBeforeContainerCreateHook, codexRecoveryChecks } from './codex-sandbox.js';
|
|
4
4
|
import { parseCodexLifecycleBinding } from './codex-lifecycle/binding.js';
|
|
5
5
|
import { isCodexDelegationReceiptEvidence, isCodexLifecycleActivationEvidence } from './codex-lifecycle/evidence.js';
|
|
6
|
-
import { codexControllerOperation } from './codex-lifecycle/controller-operation.js';
|
|
7
6
|
function codexCarrierError(code) {
|
|
8
7
|
const error = new Error(code);
|
|
9
8
|
error.name = code;
|
|
@@ -72,7 +71,6 @@ const codexAdapter = defineAgentClientAdapter({
|
|
|
72
71
|
return recoverStartedLifecycleFromAdapter(...args);
|
|
73
72
|
}
|
|
74
73
|
},
|
|
75
|
-
sandboxControlOperation: codexControllerOperation,
|
|
76
74
|
project: {
|
|
77
75
|
ownedPathPrefixes: ['.codex/'],
|
|
78
76
|
managed: ['.codex/hooks.json', '.codex/agents/'],
|
|
@@ -35,7 +35,6 @@ export const INTERNAL_HANDLER_ROUTE_SELECTORS = Object.freeze({
|
|
|
35
35
|
'sandbox-control': ['serve', 'execute', 'recover', 'client'],
|
|
36
36
|
'agent-client': ['next-steps', 'model-selection', 'launch-carrier'],
|
|
37
37
|
'codex-lifecycle': ['preflight', 'hook-event', 'resolve-start', 'resolve-stop', 'consume'],
|
|
38
|
-
'codex-sandbox-controller': ['verify-context', 'run'],
|
|
39
38
|
'git-workflow': ['inspect', 'preview-tree', 'snapshot', 'compare-trees', 'commit', 'push-rebased'],
|
|
40
39
|
'task-delivery': ['deliver'],
|
|
41
40
|
'release-workflow': ['inspect', 'prepare', 'publish', 'post-prepare', 'post-publish'],
|
|
@@ -3,8 +3,8 @@ import { createDirectHostExecutionContext, dispatchTaskControlOperation, parseTa
|
|
|
3
3
|
import { applyTaskFinalization } from '../task/finalization.js';
|
|
4
4
|
import { detectRepoRoot, resolveTaskRef } from '../task/resolve-ref.js';
|
|
5
5
|
import { resolveSandboxControlTransport } from './task-operation-registry.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { validateSandboxControlTaskIdentity } from '../sandbox/control/lifecycle.js';
|
|
7
|
+
import { loadSandboxControlLocation } from '../sandbox/config.js';
|
|
8
8
|
import { serializeTaskFinalizationEnvelope } from '../task/finalization-envelope.js';
|
|
9
9
|
import { verifyTaskEvent } from '../task/verification.js';
|
|
10
10
|
import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.js';
|
|
@@ -71,7 +71,8 @@ async function taskFinalization(args = []) {
|
|
|
71
71
|
const taskId = process.env.AGENT_INFRA_TASK_ID;
|
|
72
72
|
const generation = process.env.AGENT_INFRA_CONTROL_GENERATION;
|
|
73
73
|
const controlRootId = process.env.AGENT_INFRA_CONTROL_ROOT_ID;
|
|
74
|
-
|
|
74
|
+
const controlRoot = process.env.AGENT_INFRA_CONTROL_ROOT_DIR;
|
|
75
|
+
if (!statusDir || !taskId || !generation || !controlRootId || !controlRoot || taskId !== resolved.taskId) {
|
|
75
76
|
const detail = { code: 'TASK_CONTROL_TRANSPORT_INVALID', message: 'sandbox task control identity is incomplete', retryable: false };
|
|
76
77
|
process.stdout.write(envelope('failed', false, true, null, detail));
|
|
77
78
|
process.exitCode = 1;
|
|
@@ -82,7 +83,7 @@ async function taskFinalization(args = []) {
|
|
|
82
83
|
beforeLifecycle: async (currentTaskId) => {
|
|
83
84
|
if (currentTaskId !== taskId)
|
|
84
85
|
throw new Error('SANDBOX_CONTROL_IDENTITY_MISMATCH');
|
|
85
|
-
|
|
86
|
+
validateSandboxControlTaskIdentity(controlRoot, { taskId, generation, controlRootId, statusDir });
|
|
86
87
|
},
|
|
87
88
|
preflight: (request, options) => verifyTaskEvent({ ...request, event: 'complete-task.hard-preflight' }, options)
|
|
88
89
|
});
|
|
@@ -92,7 +93,8 @@ async function taskFinalization(args = []) {
|
|
|
92
93
|
process.exitCode = exitCode(status);
|
|
93
94
|
return;
|
|
94
95
|
}
|
|
95
|
-
const
|
|
96
|
+
const controlLocation = loadSandboxControlLocation(repoRoot);
|
|
97
|
+
const result = await dispatchTaskControlOperation(createDirectHostExecutionContext({ repoRoot, ...(controlLocation ?? {}) }), boundOperation);
|
|
96
98
|
if (result.status === 'prepared') {
|
|
97
99
|
const detail = {
|
|
98
100
|
code: 'TASK_FINALIZATION_DIRECT_COMMIT_REQUIRED',
|
|
@@ -2,6 +2,7 @@ import { createDirectHostExecutionContext, dispatchTaskControlOperation, parseTa
|
|
|
2
2
|
import { lifecycleIntentCatalog } from '../task/lifecycle.js';
|
|
3
3
|
import { detectRepoRoot, resolveTaskRef } from '../task/resolve-ref.js';
|
|
4
4
|
import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.js';
|
|
5
|
+
import { loadSandboxControlLocation } from '../sandbox/config.js';
|
|
5
6
|
const USAGE = `Usage: agent-infra-internal task-lifecycle <N | TASK-id> <intent> --agent <agent> [intent flags] [--dry-run]\n\nIntents: ${lifecycleIntentCatalog.filter((intent) => intent !== 'complete').join(', ')}\nrecover-started: --auto\n`;
|
|
6
7
|
function usageFailure(message) {
|
|
7
8
|
process.stdout.write(`${JSON.stringify({ status: 'failed', changed: false, error: { code: 'LIFECYCLE_PAYLOAD_INVALID', message } })}\n`);
|
|
@@ -52,7 +53,8 @@ async function taskLifecycle(args = []) {
|
|
|
52
53
|
}
|
|
53
54
|
repoRoot = resolved.repoRoot;
|
|
54
55
|
}
|
|
55
|
-
const
|
|
56
|
+
const controlLocation = loadSandboxControlLocation(repoRoot);
|
|
57
|
+
const result = await dispatchTaskControlOperation(createDirectHostExecutionContext({ repoRoot, ...(controlLocation ?? {}) }), operation);
|
|
56
58
|
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
57
59
|
if (result.status === 'failed' || result.status === 'owner-unknown' || result.status === 'conflict')
|
|
58
60
|
process.exitCode = 1;
|
|
@@ -25,8 +25,6 @@ function internalTaskRoutes() {
|
|
|
25
25
|
descriptor('internal', 'codex-lifecycle', 'resolve-start', 'conditional', 'progress'),
|
|
26
26
|
descriptor('internal', 'codex-lifecycle', 'resolve-stop', 'conditional', 'progress'),
|
|
27
27
|
descriptor('internal', 'codex-lifecycle', 'consume', 'conditional', 'progress'),
|
|
28
|
-
descriptor('internal', 'codex-sandbox-controller', 'verify-context', 'task-bound', 'diagnostic'),
|
|
29
|
-
descriptor('internal', 'codex-sandbox-controller', 'run', 'task-bound', 'progress'),
|
|
30
28
|
descriptor('internal', 'git-workflow', 'inspect', 'conditional', 'diagnostic'),
|
|
31
29
|
descriptor('internal', 'git-workflow', 'preview-tree', 'conditional', 'diagnostic'),
|
|
32
30
|
descriptor('internal', 'git-workflow', 'snapshot', 'conditional', 'diagnostic'),
|
|
@@ -175,7 +173,7 @@ export const TASK_OPERATION_DESCRIPTORS = Object.freeze([
|
|
|
175
173
|
...PUBLIC_OPERATION_DESCRIPTORS
|
|
176
174
|
]);
|
|
177
175
|
export const INTERNAL_DISPATCHER_ROUTES = Object.freeze([
|
|
178
|
-
'task-create', 'task-qualification', 'sandbox-control', 'agent-client', 'codex-lifecycle',
|
|
176
|
+
'task-create', 'task-qualification', 'sandbox-control', 'agent-client', 'codex-lifecycle',
|
|
179
177
|
'git-workflow', 'task-delivery', 'release-workflow', 'platform-release-notes', 'platform-security', 'platform-metadata', 'platform-context',
|
|
180
178
|
'platform-comment', 'platform-issue', 'platform-pr', 'platform-pr-review', 'pr-review-grade',
|
|
181
179
|
'platform-checks', 'task-context', 'task-ledger', 'task-warning', 'task-activity', 'task-artifact',
|
|
@@ -2,26 +2,15 @@ import { execFileSync, spawnSync } from 'node:child_process';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import { randomUUID } from 'node:crypto';
|
|
6
5
|
import { loadConfig } from '../sandbox/config.js';
|
|
7
|
-
import { detectEngine } from '../sandbox/engine.js';
|
|
8
|
-
import { runEngine } from '../sandbox/shell.js';
|
|
9
|
-
import { sandboxBranchLabel, sandboxLabel } from '../sandbox/constants.js';
|
|
10
|
-
import { fetchSandboxRows, selectSandboxContainer } from '../sandbox/commands/list-running.js';
|
|
11
|
-
import { containerNameCandidates } from '../sandbox/constants.js';
|
|
12
6
|
import { resolveSandboxTarget } from '../sandbox/workspace-identity.js';
|
|
13
|
-
import {
|
|
14
|
-
import { appendSandboxControlAudit, readActiveLease, readSandboxControlStatus } from '../sandbox/control/state.js';
|
|
15
|
-
import { readSandboxControlManifest } from '../sandbox/control/lifecycle.js';
|
|
16
|
-
import { SANDBOX_CONTROL_FUTURE_SKEW_MS, SANDBOX_CONTROL_STATUS_STALE_MS } from '../sandbox/control/protocol.js';
|
|
17
|
-
import { getProcessStartTime } from '../server/process-state.js';
|
|
7
|
+
import { resolveBranchWorktree } from '../git/branch-worktree.js';
|
|
18
8
|
import { assertGitWorktreeBinding } from '../git/worktree-identity.js';
|
|
19
9
|
import { createManualValidationEvidence, manualValidationEvidenceSummary } from '../task/manual-validation-evidence.js';
|
|
20
10
|
import { writeJsonAtomic } from '../task/manual-validation-shared.js';
|
|
21
11
|
import { ensureInternalHandlerRoute, internalHandlerRoute } from './cli-route-inventory.js';
|
|
22
12
|
const USAGE = `Usage: agent-infra-internal task-validate <branch | TASK-id | N> [--scope snapshot|inplace] [--timeout <ms>] [--format text|json] [--evidence-file <path>] -- <command> [args...]`;
|
|
23
13
|
const MAX_TIMEOUT_MS = 60 * 60 * 1000;
|
|
24
|
-
const RECOVERY_GRACE_MS = 30_000;
|
|
25
14
|
export function parseValidateArgs(args) {
|
|
26
15
|
if (args.includes('--help') || args.includes('-h')) {
|
|
27
16
|
return { target: '', scope: 'snapshot', timeoutMs: 300_000, format: 'text', evidenceFile: null, command: [], help: true };
|
|
@@ -100,21 +89,6 @@ function runValidationCommand(command, cwd, scope, timeoutMs, json) {
|
|
|
100
89
|
function git(root, args) {
|
|
101
90
|
return execFileSync('git', args, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
|
|
102
91
|
}
|
|
103
|
-
function waitForState(statusDir, predicate, timeoutMs = 5_000) {
|
|
104
|
-
const deadline = Date.now() + timeoutMs;
|
|
105
|
-
while (Date.now() < deadline) {
|
|
106
|
-
try {
|
|
107
|
-
const status = readSandboxControlStatus(statusDir);
|
|
108
|
-
if (predicate(status))
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
// Atomic status publication may be between renames.
|
|
113
|
-
}
|
|
114
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 25);
|
|
115
|
-
}
|
|
116
|
-
throw new Error('SANDBOX_VALIDATION_BROKER_STATE_TIMEOUT');
|
|
117
|
-
}
|
|
118
92
|
function snapshotValidation(repoRoot, commit, options) {
|
|
119
93
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-infra-validation-'));
|
|
120
94
|
const worktree = path.join(tempRoot, 'worktree');
|
|
@@ -146,117 +120,33 @@ function snapshotValidation(repoRoot, commit, options) {
|
|
|
146
120
|
}
|
|
147
121
|
}
|
|
148
122
|
function inplaceValidation(config, target, options) {
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
base: config.controlBase, repoRoot: config.repoRoot, project: config.project,
|
|
156
|
-
container: row.name, identity: target.workspace
|
|
157
|
-
});
|
|
158
|
-
const manifest = readSandboxControlManifest(control.manifestPath);
|
|
159
|
-
const initial = readSandboxControlStatus(control.statusDir);
|
|
160
|
-
const now = Date.now();
|
|
161
|
-
if (initial.generation !== manifest.generation
|
|
162
|
-
|| now - initial.updatedAt > SANDBOX_CONTROL_STATUS_STALE_MS
|
|
163
|
-
|| initial.updatedAt > now + SANDBOX_CONTROL_FUTURE_SKEW_MS) {
|
|
164
|
-
throw new Error('SANDBOX_VALIDATION_BROKER_STATUS_STALE');
|
|
165
|
-
}
|
|
166
|
-
if (initial.state !== 'healthy' || initial.activeRequestId !== null) {
|
|
167
|
-
throw new Error('SANDBOX_VALIDATION_BROKER_NOT_IDLE');
|
|
168
|
-
}
|
|
169
|
-
const startTime = getProcessStartTime(process.pid);
|
|
170
|
-
if (!startTime)
|
|
171
|
-
throw new Error('SANDBOX_VALIDATION_OWNER_IDENTITY_UNAVAILABLE');
|
|
172
|
-
const leasePath = path.join(control.root, 'lease.json');
|
|
173
|
-
const nonce = randomUUID();
|
|
174
|
-
const issuedAt = Date.now();
|
|
175
|
-
const lease = {
|
|
176
|
-
version: 2, generation: manifest.generation, nonce,
|
|
177
|
-
owner: { pid: process.pid, startTime }, issuedAt,
|
|
178
|
-
expiresAt: issuedAt + Math.min(options.timeoutMs + RECOVERY_GRACE_MS, MAX_TIMEOUT_MS + RECOVERY_GRACE_MS),
|
|
179
|
-
taskId: target.workspace.mode === 'task-bound' ? target.workspace.taskId : null,
|
|
180
|
-
branch: target.branch, reason: 'manual-validation'
|
|
181
|
-
};
|
|
182
|
-
const originalBranch = git(manifest.worktreeRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
|
|
183
|
-
const originalHead = git(manifest.worktreeRoot, ['rev-parse', 'HEAD']);
|
|
184
|
-
fs.writeFileSync(leasePath, `${JSON.stringify(lease)}\n`, { flag: 'wx', mode: 0o600 });
|
|
185
|
-
let stopped = false;
|
|
123
|
+
const targetRoot = resolveBranchWorktree(config.repoRoot, target.branch);
|
|
124
|
+
if (!targetRoot)
|
|
125
|
+
throw new Error(`TASK_VALIDATION_WORKTREE_NOT_FOUND: ${target.branch}`);
|
|
126
|
+
const worktree = assertGitWorktreeBinding(config.repoRoot, targetRoot, target.branch);
|
|
127
|
+
const originalBranch = git(worktree.worktreeRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
|
|
128
|
+
const originalHead = git(worktree.worktreeRoot, ['rev-parse', 'HEAD']);
|
|
186
129
|
let restored = false;
|
|
187
130
|
try {
|
|
188
|
-
|
|
189
|
-
waitForState(control.statusDir, (status) => status.state === 'parked' && status.reasonCode === 'SANDBOX_CONTROL_HANDOFF_ACTIVE');
|
|
190
|
-
if (row.running) {
|
|
191
|
-
runEngine(engine, 'docker', ['stop', row.name]);
|
|
192
|
-
stopped = true;
|
|
193
|
-
}
|
|
194
|
-
const refreshedRows = fetchSandboxRows(engine, sandboxLabel(config), sandboxBranchLabel(config));
|
|
195
|
-
const refreshed = selectSandboxContainer([...refreshedRows.running, ...refreshedRows.nonRunning], containerNameCandidates(config, target.branch));
|
|
196
|
-
if (!refreshed || refreshed.running)
|
|
197
|
-
throw new Error('SANDBOX_VALIDATION_CONTAINER_STILL_RUNNING');
|
|
198
|
-
const activeLease = readActiveLease(manifest);
|
|
199
|
-
if (!activeLease || activeLease.nonce !== nonce)
|
|
200
|
-
throw new Error('SANDBOX_VALIDATION_LEASE_OWNERSHIP_LOST');
|
|
201
|
-
assertGitWorktreeBinding(config.repoRoot, manifest.worktreeRoot, target.branch);
|
|
202
|
-
const result = runValidationCommand(options.command, manifest.worktreeRoot, 'inplace', options.timeoutMs, options.format === 'json');
|
|
131
|
+
const result = runValidationCommand(options.command, worktree.worktreeRoot, 'inplace', options.timeoutMs, options.format === 'json');
|
|
203
132
|
return { ...result, cleanup: () => restored ? 'completed' : 'pending' };
|
|
204
133
|
}
|
|
205
134
|
finally {
|
|
206
|
-
const recoveryErrors = [];
|
|
207
135
|
try {
|
|
208
|
-
const currentBranch = git(
|
|
136
|
+
const currentBranch = git(worktree.worktreeRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
|
|
209
137
|
if (currentBranch !== originalBranch)
|
|
210
|
-
git(
|
|
138
|
+
git(worktree.worktreeRoot, ['switch', originalBranch]);
|
|
211
139
|
}
|
|
212
140
|
catch {
|
|
213
141
|
try {
|
|
214
|
-
git(
|
|
215
|
-
git(
|
|
216
|
-
}
|
|
217
|
-
catch (fallbackError) {
|
|
218
|
-
recoveryErrors.push(`git binding restore failed: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (stopped) {
|
|
222
|
-
try {
|
|
223
|
-
runEngine(engine, 'docker', ['start', row.name]);
|
|
224
|
-
}
|
|
225
|
-
catch (error) {
|
|
226
|
-
recoveryErrors.push(`container start failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
try {
|
|
230
|
-
const currentLease = JSON.parse(fs.readFileSync(leasePath, 'utf8'));
|
|
231
|
-
if (currentLease.nonce !== nonce)
|
|
232
|
-
throw new Error('SANDBOX_VALIDATION_LEASE_OWNERSHIP_LOST');
|
|
233
|
-
}
|
|
234
|
-
catch (error) {
|
|
235
|
-
recoveryErrors.push(error instanceof Error ? error.message : String(error));
|
|
236
|
-
}
|
|
237
|
-
if (recoveryErrors.length === 0) {
|
|
238
|
-
try {
|
|
239
|
-
fs.unlinkSync(leasePath);
|
|
240
|
-
appendSandboxControlAudit(manifest, 'lease-release', { ownerPid: process.pid });
|
|
241
|
-
waitForState(control.statusDir, (status) => status.state === 'healthy');
|
|
242
|
-
restored = true;
|
|
142
|
+
git(worktree.worktreeRoot, ['checkout', '--detach', originalHead]);
|
|
143
|
+
git(worktree.worktreeRoot, ['switch', originalBranch]);
|
|
243
144
|
}
|
|
244
145
|
catch (error) {
|
|
245
|
-
|
|
246
|
-
if (!fs.existsSync(leasePath)) {
|
|
247
|
-
fs.writeFileSync(leasePath, `${JSON.stringify(lease)}\n`, { flag: 'wx', mode: 0o600 });
|
|
248
|
-
}
|
|
249
|
-
appendSandboxControlAudit(manifest, 'lease-release-failed', { ownerPid: process.pid });
|
|
250
|
-
}
|
|
251
|
-
catch (leaseError) {
|
|
252
|
-
recoveryErrors.push(`lease preservation failed: ${leaseError instanceof Error ? leaseError.message : String(leaseError)}`);
|
|
253
|
-
}
|
|
254
|
-
recoveryErrors.push(error instanceof Error ? error.message : String(error));
|
|
146
|
+
throw new Error(`TASK_VALIDATION_WORKTREE_RESTORE_FAILED: ${error instanceof Error ? error.message : String(error)}`);
|
|
255
147
|
}
|
|
256
148
|
}
|
|
257
|
-
|
|
258
|
-
throw new Error(`SANDBOX_VALIDATION_RECOVERY_INCOMPLETE: ${recoveryErrors.join('; ')}; run 'ai sandbox start ${target.branch}'`);
|
|
259
|
-
}
|
|
149
|
+
restored = true;
|
|
260
150
|
}
|
|
261
151
|
}
|
|
262
152
|
function errorCode(message) {
|
|
@@ -379,19 +379,26 @@ function runMechanicalChangeReport(repoRoot, baseSha, headSha) {
|
|
|
379
379
|
throw new Error(`${validated.error.code}: ${validated.error.message}`);
|
|
380
380
|
return validated.value;
|
|
381
381
|
}
|
|
382
|
+
const DOCUMENTATION_CATEGORY = { label: '文档', prefixes: ['docs/'] };
|
|
382
383
|
const CHANGE_CATEGORIES = [
|
|
383
384
|
{ label: '运行时代码', prefixes: ['bin/', 'lib/', 'src/', 'scripts/'] },
|
|
384
385
|
{ label: '测试与校验', prefixes: ['test/', 'tests/'] },
|
|
385
386
|
{ label: '模板与生成内容', prefixes: ['templates/'] },
|
|
386
387
|
{ label: '技能与协作配置', prefixes: ['.agents/'] },
|
|
387
|
-
|
|
388
|
+
DOCUMENTATION_CATEGORY,
|
|
389
|
+
{ label: '其他', prefixes: [] }
|
|
388
390
|
];
|
|
389
391
|
function emptyChangeTotals() {
|
|
390
392
|
return { files: 0, textFiles: 0, binaryFiles: 0, additions: 0, deletions: 0, oldBytes: 0, newBytes: 0, netBytes: 0 };
|
|
391
393
|
}
|
|
392
394
|
function categoryForChangeFile(file) {
|
|
393
395
|
const filePath = file.newPath || file.oldPath || '';
|
|
394
|
-
|
|
396
|
+
const category = CHANGE_CATEGORIES.find((entry) => entry.prefixes.some((prefix) => prefix && filePath.startsWith(prefix)));
|
|
397
|
+
if (category)
|
|
398
|
+
return category;
|
|
399
|
+
if (/\.(?:md|mdx|markdown|rst)$/i.test(filePath))
|
|
400
|
+
return DOCUMENTATION_CATEGORY;
|
|
401
|
+
return CHANGE_CATEGORIES[CHANGE_CATEGORIES.length - 1];
|
|
395
402
|
}
|
|
396
403
|
function summarizeChangeCategories(files) {
|
|
397
404
|
const summaries = new Map();
|
|
@@ -492,7 +499,7 @@ function renderEvidence(evidence) {
|
|
|
492
499
|
function renderPrechecks(checks) {
|
|
493
500
|
return checks.flatMap((check) => [
|
|
494
501
|
`- **${PRECHECK_LABELS[check.id]}(${check.id})**:${check.verdict === 'pass' ? '通过' : '需复核'}。${escapeReportText(check.rationale)}`,
|
|
495
|
-
...check.evidence.
|
|
502
|
+
...check.evidence.map(renderEvidence)
|
|
496
503
|
]);
|
|
497
504
|
}
|
|
498
505
|
function renderCanonicalChangeReport(report) {
|
|
@@ -106,8 +106,8 @@ function configuredPlatform(cwd) {
|
|
|
106
106
|
}
|
|
107
107
|
async function releaseNoteContext(input, options = {}) {
|
|
108
108
|
const historyLimit = input.historyLimit ?? 3;
|
|
109
|
-
if (!input.fromTag || !input.toTag || !input.branch || !Number.isInteger(historyLimit) || historyLimit < 1 || historyLimit >
|
|
110
|
-
return { ...baseResult('failed'), error: { code: 'RELEASE_NOTES_INPUT_INVALID', message: 'from-tag, to-tag, branch, and a history limit from 1 to
|
|
109
|
+
if (!input.fromTag || !input.toTag || !input.branch || !Number.isInteger(historyLimit) || historyLimit < 1 || historyLimit > 100) {
|
|
110
|
+
return { ...baseResult('failed'), error: { code: 'RELEASE_NOTES_INPUT_INVALID', message: 'from-tag, to-tag, branch, and a history limit from 1 to 100 are required', retryable: false } };
|
|
111
111
|
}
|
|
112
112
|
const cwd = path.resolve(options.cwd || process.cwd());
|
|
113
113
|
const platformType = options.platformType ?? configuredPlatform(cwd);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { detectRepoRoot } from '../task/resolve-ref.js';
|
|
4
5
|
import { acquireGitHubCheckpoint, commitGitHubCheckpoint, readGitHubCheckpoint, releaseGitHubCheckpoint } from './checkpoint.js';
|
|
@@ -48,17 +49,27 @@ function parseArgs(args, valueOptions, booleanOptions) {
|
|
|
48
49
|
return { positionals, options };
|
|
49
50
|
}
|
|
50
51
|
function dataRoot(repoRoot, requested) {
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
let boundary = repoRoot;
|
|
53
|
+
let input = requested;
|
|
54
|
+
if (input === undefined) {
|
|
55
|
+
const config = JSON.parse(fs.readFileSync(path.join(repoRoot, '.agents', '.airc.json'), 'utf8'));
|
|
56
|
+
if (typeof config.project !== 'string' || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(config.project)) {
|
|
57
|
+
throw new Error('.agents/.airc.json must contain a valid project name in its project field');
|
|
58
|
+
}
|
|
59
|
+
boundary = path.resolve(os.homedir());
|
|
60
|
+
input = path.join(boundary, '.agent-infra', 'data-store', config.project);
|
|
61
|
+
}
|
|
62
|
+
const resolved = path.resolve(repoRoot, input);
|
|
53
63
|
const relative = path.relative(repoRoot, resolved);
|
|
54
|
-
if (!relative || relative.startsWith('..') || path.isAbsolute(relative))
|
|
64
|
+
if (requested !== undefined && (!relative || relative.startsWith('..') || path.isAbsolute(relative)))
|
|
55
65
|
throw new Error('data root must be inside the repository');
|
|
66
|
+
const workspace = path.resolve(repoRoot, '.agents', 'workspace');
|
|
56
67
|
const taskRoots = ['active', 'blocked', 'completed', 'archive'].map((state) => path.join(workspace, state));
|
|
57
68
|
if (resolved === workspace || taskRoots.some((taskRoot) => resolved === taskRoot || resolved.startsWith(`${taskRoot}${path.sep}`))) {
|
|
58
69
|
throw new Error('data root cannot be the workspace root or a task directory');
|
|
59
70
|
}
|
|
60
71
|
let current = resolved;
|
|
61
|
-
while (current !==
|
|
72
|
+
while (current !== boundary) {
|
|
62
73
|
if (fs.existsSync(current) && fs.lstatSync(current).isSymbolicLink())
|
|
63
74
|
throw new Error('data root cannot traverse a symlink');
|
|
64
75
|
current = path.dirname(current);
|
|
@@ -741,7 +741,6 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
741
741
|
const container = containerName(effectiveConfig, branch);
|
|
742
742
|
const controlPaths = sandboxControlPaths({
|
|
743
743
|
base: effectiveConfig.controlBase,
|
|
744
|
-
repoRoot: effectiveConfig.repoRoot,
|
|
745
744
|
project: effectiveConfig.project,
|
|
746
745
|
container,
|
|
747
746
|
identity: target.workspace
|
|
@@ -1079,6 +1078,7 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
1079
1078
|
shellConfigHostDir: hostShellConfig.hostDir,
|
|
1080
1079
|
workspaceViewRoot: workspaceView.root,
|
|
1081
1080
|
controlDir: control.channelDir,
|
|
1081
|
+
...(target.workspace.mode === 'task-bound' ? { controlRootDir: control.root } : {}),
|
|
1082
1082
|
controlStatusDir: control.statusDir,
|
|
1083
1083
|
...(target.workspace.mode === 'task-bound' ? { runtimeDir: control.runtimeDir } : {}),
|
|
1084
1084
|
...(target.workspace.mode === 'task-bound'
|
|
@@ -1162,8 +1162,6 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
1162
1162
|
]
|
|
1163
1163
|
: []),
|
|
1164
1164
|
'-e',
|
|
1165
|
-
`AGENT_INFRA_CONTROL_TOKEN=${control.token}`,
|
|
1166
|
-
'-e',
|
|
1167
1165
|
`AGENT_INFRA_CONTROL_GENERATION=${control.generation}`,
|
|
1168
1166
|
'-e',
|
|
1169
1167
|
'AGENT_INFRA_CONTROL_DIR=/run/agent-infra/control',
|
|
@@ -1172,7 +1170,10 @@ export async function create(args, { runProjectInitCommand = true, workspace: wo
|
|
|
1172
1170
|
'-e',
|
|
1173
1171
|
`AGENT_INFRA_CONTROL_ROOT_ID=${control.controlRootId}`,
|
|
1174
1172
|
...(target.workspace.mode === 'task-bound'
|
|
1175
|
-
? [
|
|
1173
|
+
? [
|
|
1174
|
+
'-e', 'AGENT_INFRA_CONTROL_ROOT_DIR=/run/agent-infra/control-root',
|
|
1175
|
+
'-e', 'AGENT_INFRA_RUNTIME_DIR=/run/agent-infra/runtime'
|
|
1176
|
+
]
|
|
1176
1177
|
: []),
|
|
1177
1178
|
'--label',
|
|
1178
1179
|
`${sandboxRuntimeCapabilityLabel(effectiveConfig)}=${capabilityPlan.runtimeSignature}`,
|
|
@@ -153,4 +153,16 @@ export function loadConfig({ platformFn = platform, writeStderr = (chunk) => pro
|
|
|
153
153
|
}
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
|
+
export function loadSandboxControlLocation(repoRoot = detectRepoRoot()) {
|
|
157
|
+
const configPath = path.join(repoRoot, '.agents', '.airc.json');
|
|
158
|
+
if (!fs.existsSync(configPath))
|
|
159
|
+
return null;
|
|
160
|
+
const airc = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
161
|
+
if (typeof airc.project !== 'string' || !airc.project)
|
|
162
|
+
return null;
|
|
163
|
+
const home = homedir();
|
|
164
|
+
if (!home)
|
|
165
|
+
throw new Error('sandbox: home directory is required');
|
|
166
|
+
return { controlBase: hostJoin(home, '.agent-infra', 'sandbox-control'), project: airc.project };
|
|
167
|
+
}
|
|
156
168
|
//# sourceMappingURL=config.js.map
|
|
@@ -14,8 +14,7 @@ const SAFE_OPERATION = /^[a-z][a-z0-9.-]{0,96}$/u;
|
|
|
14
14
|
const AUDIT_MAX_BYTES = 1024 * 1024;
|
|
15
15
|
export function requestAuditFields(manifest, request) {
|
|
16
16
|
return {
|
|
17
|
-
requestId: request.id, requestFamily: request.family, sandboxTaskId: manifest.taskId
|
|
18
|
-
requestGeneration: request.generation, requestIssuedAt: request.issuedAt, requestExpiresAt: request.expiresAt
|
|
17
|
+
requestId: request.id, requestFamily: request.family, sandboxTaskId: manifest.taskId
|
|
19
18
|
};
|
|
20
19
|
}
|
|
21
20
|
export function resultAuditFields(result) {
|