@fitlab-ai/agent-infra 0.9.8 → 0.9.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/bin/internal-cli.js +11 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +58 -21
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +25 -11
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +173 -10
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-context.js +127 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +14 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +63 -92
- package/dist/lib/agent-clients/adapters/codex-sandbox.js +72 -11
- package/dist/lib/agent-clients/adapters/index.js +3 -1
- package/dist/lib/agent-clients/adapters/traecli.js +66 -0
- package/dist/lib/agent-clients/tokens.js +2 -2
- package/dist/lib/agent-clients/types.js +2 -1
- package/dist/lib/defaults.json +5 -0
- package/dist/lib/git/workflow.js +10 -1
- package/dist/lib/internal/codex-lifecycle.js +20 -6
- package/dist/lib/internal/codex-sandbox-controller.js +9 -15
- package/dist/lib/internal/git-workflow.js +5 -7
- package/dist/lib/internal/platform-pr.js +20 -7
- package/dist/lib/internal/release-workflow.js +2 -1
- package/dist/lib/internal/sandbox-control.js +79 -2
- package/dist/lib/internal/task-finalization.js +54 -0
- package/dist/lib/internal/task-orchestration.js +156 -291
- package/dist/lib/{task/commands/validate.js → internal/task-validate.js} +75 -42
- package/dist/lib/platform/pr-summary.js +48 -10
- package/dist/lib/platform/pull-requests.js +205 -41
- package/dist/lib/run/tui.js +5 -2
- package/dist/lib/sandbox/commands/rm.js +316 -55
- package/dist/lib/sandbox/control/client.js +190 -6
- package/dist/lib/sandbox/control/controller-registration.js +275 -0
- package/dist/lib/sandbox/control/executor.js +140 -5
- package/dist/lib/sandbox/control/lifecycle.js +3 -1
- package/dist/lib/sandbox/control/protocol.js +67 -6
- package/dist/lib/sandbox/index.js +5 -3
- package/dist/lib/sandbox/managed-fs.js +5 -0
- package/dist/lib/sandbox/task-resolver.js +50 -6
- package/dist/lib/sandbox/workspace-identity.js +27 -0
- package/dist/lib/sandbox/worktree-safety.js +215 -2
- package/dist/lib/task/codex-orchestration.js +161 -39
- package/dist/lib/task/commands/status.js +59 -1
- package/dist/lib/task/commit-operation.js +335 -0
- package/dist/lib/task/commit-policy.js +18 -0
- package/dist/lib/task/delegation-receipts.js +248 -6
- package/dist/lib/task/finalization.js +593 -0
- package/dist/lib/task/index.js +0 -9
- package/dist/lib/task/operation-outcome.js +33 -0
- package/dist/lib/task/orchestration.js +187 -761
- package/dist/lib/task/short-id.js +59 -1
- package/dist/lib/task/task-execution-lock.js +6 -1
- package/dist/lib/task/verification-engine.js +110 -60
- package/dist/lib/task/verification.js +2 -1
- package/dist/lib/task/workflow-warning-intents.js +50 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +61 -19
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +37 -10
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +276 -12
- package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +163 -0
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +19 -0
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +9 -1
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +91 -118
- package/lib/agent-clients/adapters/codex-sandbox.ts +89 -14
- package/lib/agent-clients/adapters/index.ts +3 -1
- package/lib/agent-clients/adapters/traecli.ts +67 -0
- package/lib/agent-clients/tokens.ts +2 -2
- package/lib/agent-clients/types.ts +2 -1
- package/lib/defaults.json +5 -0
- package/lib/git/workflow.ts +11 -2
- package/lib/internal/codex-lifecycle.ts +19 -6
- package/lib/internal/codex-sandbox-controller.ts +9 -14
- package/lib/internal/git-workflow.ts +5 -6
- package/lib/internal/platform-pr.ts +14 -7
- package/lib/internal/release-workflow.ts +2 -1
- package/lib/internal/sandbox-control.ts +92 -2
- package/lib/internal/task-finalization.ts +68 -0
- package/lib/internal/task-orchestration.ts +20 -103
- package/lib/{task/commands/validate.ts → internal/task-validate.ts} +75 -40
- package/lib/platform/pr-summary.ts +55 -11
- package/lib/platform/pull-requests.ts +211 -41
- package/lib/run/tui.ts +5 -3
- package/lib/sandbox/commands/rm.ts +413 -61
- package/lib/sandbox/control/client.ts +255 -6
- package/lib/sandbox/control/controller-registration.ts +352 -0
- package/lib/sandbox/control/executor.ts +169 -5
- package/lib/sandbox/control/lifecycle.ts +2 -1
- package/lib/sandbox/control/protocol.ts +80 -7
- package/lib/sandbox/index.ts +5 -3
- package/lib/sandbox/managed-fs.ts +5 -0
- package/lib/sandbox/task-resolver.ts +58 -7
- package/lib/sandbox/workspace-identity.ts +50 -2
- package/lib/sandbox/workspace-view.ts +3 -3
- package/lib/sandbox/worktree-safety.ts +236 -2
- package/lib/task/codex-orchestration.ts +168 -40
- package/lib/task/commands/status.ts +78 -1
- package/lib/task/commit-operation.ts +430 -0
- package/lib/task/commit-policy.ts +30 -0
- package/lib/task/delegation-receipts.ts +263 -4
- package/lib/task/finalization.ts +761 -0
- package/lib/task/index.ts +0 -8
- package/lib/task/operation-outcome.ts +48 -0
- package/lib/task/orchestration.ts +218 -982
- package/lib/task/short-id.ts +65 -1
- package/lib/task/task-execution-lock.ts +10 -1
- package/lib/task/verification-engine.ts +115 -63
- package/lib/task/verification.ts +3 -2
- package/lib/task/workflow-warning-intents.ts +57 -2
- package/package.json +2 -2
- package/templates/.agents/QUICKSTART.en.md +3 -4
- package/templates/.agents/QUICKSTART.zh-CN.md +3 -4
- package/templates/.agents/hooks/lifecycle-delegation.js +1 -21
- package/templates/.agents/rules/README.en.md +1 -0
- package/templates/.agents/rules/README.zh-CN.md +1 -0
- package/templates/.agents/rules/compatibility-policy.en.md +39 -0
- package/templates/.agents/rules/compatibility-policy.zh-CN.md +39 -0
- package/templates/.agents/rules/lifecycle-orchestration.en.md +4 -4
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +4 -4
- package/templates/.agents/rules/pr-sync.en.md +1 -1
- package/templates/.agents/rules/pr-sync.github.en.md +2 -1
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +2 -0
- package/templates/.agents/rules/pr-sync.zh-CN.md +1 -0
- package/templates/.agents/rules/review-method.en.md +1 -0
- package/templates/.agents/rules/review-method.zh-CN.md +1 -0
- package/templates/.agents/rules/task-management.en.md +2 -2
- package/templates/.agents/rules/task-management.zh-CN.md +2 -2
- package/templates/.agents/skills/analyze-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/block-task/SKILL.en.md +2 -4
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -4
- 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/close-codescan/SKILL.en.md +6 -2
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -2
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -2
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/commit/SKILL.en.md +41 -125
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +52 -123
- package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +14 -43
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +14 -49
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -35
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -35
- package/templates/.agents/skills/complete-task/SKILL.en.md +31 -38
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +31 -38
- package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
- 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 +17 -9
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +17 -9
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +41 -0
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +41 -0
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +2 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +2 -2
- package/templates/.agents/skills/plan-task/SKILL.en.md +2 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -1
- package/templates/.agents/skills/review-code/reference/migration-risks.en.md +8 -6
- package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +8 -6
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +3 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +1 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +1 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -2
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -2
- package/templates/.agents/skills/run-task/SKILL.en.md +6 -6
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +2 -2
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +2 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +24 -0
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +1 -1
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +1 -1
- package/templates/.codex/hooks.json +4 -4
- package/templates/.trae/skills/update-agent-infra.en.md +8 -0
- package/templates/.trae/skills/update-agent-infra.zh-CN.md +8 -0
- package/dist/lib/task/commit-finalization.js +0 -305
- package/dist/lib/task/commit-intent.js +0 -165
- package/lib/task/commit-finalization.ts +0 -419
- package/lib/task/commit-intent.ts +0 -230
|
@@ -5,25 +5,11 @@ import os from 'node:os';
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import semver from 'semver';
|
|
7
7
|
import * as toml from 'smol-toml';
|
|
8
|
-
import { requestSandboxControl } from '../../../sandbox/control/client.js';
|
|
8
|
+
import { requestCodexControllerClose, requestCodexControllerOpen, requestCodexControllerVerify, requestSandboxControl } from '../../../sandbox/control/client.js';
|
|
9
9
|
import { readSandboxControlStatus } from '../../../sandbox/control/state.js';
|
|
10
|
-
import { getProcessStartTime
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
function digestFiles(files) {
|
|
14
|
-
const hash = crypto.createHash('sha256');
|
|
15
|
-
for (const file of [...files].sort()) {
|
|
16
|
-
const stat = fs.lstatSync(file);
|
|
17
|
-
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
18
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_BUNDLE_MISMATCH');
|
|
19
|
-
}
|
|
20
|
-
hash.update(path.basename(file));
|
|
21
|
-
hash.update('\0');
|
|
22
|
-
hash.update(fs.readFileSync(file));
|
|
23
|
-
hash.update('\0');
|
|
24
|
-
}
|
|
25
|
-
return hash.digest('hex');
|
|
26
|
-
}
|
|
10
|
+
import { getProcessStartTime } from '../../../server/process-state.js';
|
|
11
|
+
import { LIFECYCLE_PROTOCOL_VERSION } from './build-identity.js';
|
|
12
|
+
import { contextFromControllerLease, controllerProofFromContext, verifyCodexSandboxControllerContextWithWarnings as verifyContextFileWithWarnings, writeCodexSandboxControllerContext } from './controller-context.js';
|
|
27
13
|
function copyRegular(source, destination, mode) {
|
|
28
14
|
const stat = fs.lstatSync(source);
|
|
29
15
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
@@ -108,6 +94,30 @@ function verifyControl(taskId, control) {
|
|
|
108
94
|
if (payload.taskId !== taskId)
|
|
109
95
|
throw new Error('CODEX_SANDBOX_CONTROLLER_TASK_BINDING_INVALID');
|
|
110
96
|
}
|
|
97
|
+
function verifyCodexSandboxControllerContextWithWarnings(contextPath, options = {}) {
|
|
98
|
+
const control = options.control ?? controlFromEnvironment();
|
|
99
|
+
const fileVerification = verifyContextFileWithWarnings(contextPath, {
|
|
100
|
+
repoRoot: options.repoRoot,
|
|
101
|
+
now: options.now,
|
|
102
|
+
generation: control.generation,
|
|
103
|
+
probeProcess: options.probeProcess
|
|
104
|
+
});
|
|
105
|
+
const context = fileVerification.context;
|
|
106
|
+
const verified = (options.requestControllerVerify ?? requestCodexControllerVerify)({
|
|
107
|
+
controllerProof: controllerProofFromContext(context),
|
|
108
|
+
...control,
|
|
109
|
+
timeoutMs: 30_000
|
|
110
|
+
});
|
|
111
|
+
if (verified.binding.taskId !== context.taskId
|
|
112
|
+
|| verified.binding.controlGeneration !== context.controlGeneration
|
|
113
|
+
|| verified.binding.controllerInstanceDigest !== context.controllerInstanceDigest) {
|
|
114
|
+
throw new Error('CODEX_SANDBOX_CONTROLLER_CONTEXT_INVALID');
|
|
115
|
+
}
|
|
116
|
+
return Object.freeze({
|
|
117
|
+
context,
|
|
118
|
+
warnings: fileVerification.warnings
|
|
119
|
+
});
|
|
120
|
+
}
|
|
111
121
|
function detectedCodexVersion() {
|
|
112
122
|
const result = spawnSync('codex', ['--version'], { encoding: 'utf8' });
|
|
113
123
|
const version = /codex-cli\s+(\d+\.\d+\.\d+)/u.exec(result.stdout ?? '')?.[1];
|
|
@@ -191,7 +201,6 @@ function prepareCodexSandboxController(input, options = {}) {
|
|
|
191
201
|
const repoRoot = path.resolve(options.repoRoot ?? process.cwd());
|
|
192
202
|
const sourceHome = path.resolve(options.codexHome ?? process.env.CODEX_HOME ?? path.join(os.homedir(), '.codex'));
|
|
193
203
|
const control = options.control ?? controlFromEnvironment();
|
|
194
|
-
(options.verifyTaskBinding ?? verifyControl)(input.taskId, control);
|
|
195
204
|
const version = (options.codexVersion ?? detectedCodexVersion)();
|
|
196
205
|
if (!semver.gte(version, '0.147.0'))
|
|
197
206
|
throw new Error('CODEX_SANDBOX_CONTROLLER_CODEX_UNSUPPORTED');
|
|
@@ -200,48 +209,36 @@ function prepareCodexSandboxController(input, options = {}) {
|
|
|
200
209
|
fs.mkdirSync(runtimeRoot, { recursive: true, mode: 0o700 });
|
|
201
210
|
fs.chmodSync(runtimeRoot, 0o700);
|
|
202
211
|
const key = crypto.createHash('sha256')
|
|
203
|
-
.update(`${
|
|
212
|
+
.update(`${process.pid}\0${control.generation}`)
|
|
204
213
|
.digest('hex');
|
|
205
|
-
const leasePath = path.join(runtimeRoot, `${key}.lease.json`);
|
|
206
|
-
if (fs.existsSync(leasePath)) {
|
|
207
|
-
const lease = JSON.parse(fs.readFileSync(leasePath, 'utf8'));
|
|
208
|
-
if (Number.isSafeInteger(lease.pid) && typeof lease.startTime === 'number'
|
|
209
|
-
&& getProcessStartTime(lease.pid) === lease.startTime) {
|
|
210
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_BUSY');
|
|
211
|
-
}
|
|
212
|
-
fs.unlinkSync(leasePath);
|
|
213
|
-
}
|
|
214
214
|
const parentStartTime = getProcessStartTime(process.pid);
|
|
215
215
|
if (!parentStartTime)
|
|
216
216
|
throw new Error('CODEX_SANDBOX_CONTROLLER_PROCESS_IDENTITY_INVALID');
|
|
217
|
-
const instanceDigest = crypto.randomBytes(32).toString('hex');
|
|
218
|
-
fs.writeFileSync(leasePath, `${JSON.stringify({
|
|
219
|
-
version: 1,
|
|
220
|
-
pid: process.pid,
|
|
221
|
-
startTime: parentStartTime,
|
|
222
|
-
taskId: input.taskId,
|
|
223
|
-
generation: control.generation,
|
|
224
|
-
instanceDigest
|
|
225
|
-
})}\n`, { mode: 0o600, flag: 'wx' });
|
|
226
217
|
const home = fs.mkdtempSync(path.join(runtimeRoot, `${key}-`));
|
|
227
218
|
fs.chmodSync(home, 0o700);
|
|
228
219
|
let cleaned = false;
|
|
220
|
+
let context = null;
|
|
229
221
|
const cleanup = () => {
|
|
230
222
|
if (cleaned)
|
|
231
223
|
return;
|
|
232
224
|
cleaned = true;
|
|
225
|
+
if (context) {
|
|
226
|
+
try {
|
|
227
|
+
(options.closeController ?? requestCodexControllerClose)({
|
|
228
|
+
controllerProcess: context.controllerProcess,
|
|
229
|
+
controllerProof: controllerProofFromContext(context),
|
|
230
|
+
...control,
|
|
231
|
+
timeoutMs: 30_000
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// The wrapper is exiting; dead-process recovery safely handles an unknown close result.
|
|
236
|
+
}
|
|
237
|
+
}
|
|
233
238
|
const relative = path.relative(runtimeRoot, home);
|
|
234
239
|
if (!relative.startsWith('..') && !path.isAbsolute(relative)) {
|
|
235
240
|
fs.rmSync(home, { recursive: true, force: true });
|
|
236
241
|
}
|
|
237
|
-
try {
|
|
238
|
-
const lease = JSON.parse(fs.readFileSync(leasePath, 'utf8'));
|
|
239
|
-
if (lease.instanceDigest === instanceDigest)
|
|
240
|
-
fs.unlinkSync(leasePath);
|
|
241
|
-
}
|
|
242
|
-
catch {
|
|
243
|
-
// A missing or replaced lease is owned by another cleanup path.
|
|
244
|
-
}
|
|
245
242
|
};
|
|
246
243
|
try {
|
|
247
244
|
const auth = path.join(sourceHome, 'auth.json');
|
|
@@ -254,31 +251,26 @@ function prepareCodexSandboxController(input, options = {}) {
|
|
|
254
251
|
copyRegular(hooks, path.join(home, 'hooks.json'), 0o600);
|
|
255
252
|
copyRegular(executor, path.join(home, 'agents', path.basename(executor)), 0o600);
|
|
256
253
|
copyRegular(reviewer, path.join(home, 'agents', path.basename(reviewer)), 0o600);
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
254
|
+
const opened = (options.openController ?? requestCodexControllerOpen)({
|
|
255
|
+
controllerProcess: { pid: process.pid, startTime: parentStartTime },
|
|
256
|
+
...control,
|
|
257
|
+
timeoutMs: 30_000
|
|
258
|
+
});
|
|
259
|
+
const taskId = opened.lease.taskId;
|
|
260
|
+
if (opened.lease.buildIdentity.protocolVersion !== LIFECYCLE_PROTOCOL_VERSION) {
|
|
261
|
+
throw new Error('CODEX_LIFECYCLE_PROTOCOL_MISMATCH: Codex lifecycle protocol version does not match');
|
|
264
262
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const context = Object.freeze({
|
|
268
|
-
version: 1,
|
|
269
|
-
taskId: input.taskId,
|
|
270
|
-
controlGeneration: control.generation,
|
|
271
|
-
controllerInstanceDigest: instanceDigest,
|
|
272
|
-
parentPid: process.pid,
|
|
273
|
-
parentStartTime,
|
|
274
|
-
issuedAt: now,
|
|
275
|
-
expiresAt: now + CONTEXT_TTL_MS,
|
|
276
|
-
buildIdentity,
|
|
277
|
-
hookDefinitionHash: crypto.createHash('sha256').update(fs.readFileSync(hooks)).digest('hex'),
|
|
278
|
-
lifecycleProfilesHash: digestFiles([executor, reviewer])
|
|
263
|
+
context = contextFromControllerLease(opened.lease, {
|
|
264
|
+
hookDefinitionHash: crypto.createHash('sha256').update(fs.readFileSync(hooks)).digest('hex')
|
|
279
265
|
});
|
|
266
|
+
if (opened.lease.controlGeneration !== control.generation
|
|
267
|
+
|| opened.lease.controllerProcess.pid !== process.pid
|
|
268
|
+
|| opened.lease.controllerProcess.startTime !== parentStartTime) {
|
|
269
|
+
throw new Error('SANDBOX_CONTROL_RESULT_INVALID');
|
|
270
|
+
}
|
|
271
|
+
(options.verifyTaskBinding ?? verifyControl)(taskId, control);
|
|
280
272
|
const contextPath = path.join(home, 'controller-context.json');
|
|
281
|
-
|
|
273
|
+
writeCodexSandboxControllerContext(contextPath, context);
|
|
282
274
|
const shimDir = path.join(home, 'bin');
|
|
283
275
|
fs.mkdirSync(shimDir, { mode: 0o700 });
|
|
284
276
|
const internalCli = path.resolve(process.argv[1] ?? path.join(repoRoot, 'bin', 'internal-cli.ts'));
|
|
@@ -292,7 +284,7 @@ function prepareCodexSandboxController(input, options = {}) {
|
|
|
292
284
|
input.reviewerModel ? `--reviewer-model ${input.reviewerModel}` : '',
|
|
293
285
|
input.reviewerReasoningEffort ? `--reviewer-reasoning-effort ${input.reviewerReasoningEffort}` : ''
|
|
294
286
|
].filter(Boolean).join(' ');
|
|
295
|
-
const prompt = `$run-task ${
|
|
287
|
+
const prompt = `$run-task ${taskId}${policy ? ` ${policy}` : ''}`;
|
|
296
288
|
const args = Object.freeze([
|
|
297
289
|
'exec',
|
|
298
290
|
'--enable', 'hooks',
|
|
@@ -303,7 +295,7 @@ function prepareCodexSandboxController(input, options = {}) {
|
|
|
303
295
|
'-C', repoRoot,
|
|
304
296
|
prompt
|
|
305
297
|
]);
|
|
306
|
-
const env = isolatedEnvironment(home, shimDir, contextPath,
|
|
298
|
+
const env = isolatedEnvironment(home, shimDir, contextPath, taskId, control, providerEnvironment, options.environment ?? process.env);
|
|
307
299
|
return Object.freeze({
|
|
308
300
|
command: 'codex',
|
|
309
301
|
args,
|
|
@@ -319,27 +311,6 @@ function prepareCodexSandboxController(input, options = {}) {
|
|
|
319
311
|
throw error;
|
|
320
312
|
}
|
|
321
313
|
}
|
|
322
|
-
function verifyCodexSandboxControllerContext(contextPath, taskId, options = {}) {
|
|
323
|
-
const stat = fs.lstatSync(contextPath);
|
|
324
|
-
if (!stat.isFile() || stat.isSymbolicLink() || (stat.mode & 0o077) !== 0) {
|
|
325
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_CONTEXT_INVALID');
|
|
326
|
-
}
|
|
327
|
-
const context = JSON.parse(fs.readFileSync(contextPath, 'utf8'));
|
|
328
|
-
const generation = options.generation ?? process.env.AGENT_INFRA_CONTROL_GENERATION;
|
|
329
|
-
if (context.version !== 1
|
|
330
|
-
|| context.taskId !== taskId
|
|
331
|
-
|| context.controlGeneration !== generation
|
|
332
|
-
|| context.expiresAt < (options.now ?? Date.now())
|
|
333
|
-
|| getProcessStartTime(context.parentPid) !== context.parentStartTime
|
|
334
|
-
|| !isProcessAlive(context.parentPid)) {
|
|
335
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_CONTEXT_INVALID');
|
|
336
|
-
}
|
|
337
|
-
const current = computeLifecycleBuildIdentity(options.repoRoot ?? process.cwd());
|
|
338
|
-
if (JSON.stringify(current) !== JSON.stringify(context.buildIdentity)) {
|
|
339
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_BUNDLE_MISMATCH');
|
|
340
|
-
}
|
|
341
|
-
return Object.freeze(context);
|
|
342
|
-
}
|
|
343
314
|
async function runCodexSandboxController(input, options = {}) {
|
|
344
315
|
const prepared = prepareCodexSandboxController(input, options);
|
|
345
316
|
try {
|
|
@@ -394,5 +365,5 @@ async function runCodexSandboxController(input, options = {}) {
|
|
|
394
365
|
prepared.cleanup();
|
|
395
366
|
}
|
|
396
367
|
}
|
|
397
|
-
export { prepareCodexSandboxController, runCodexSandboxController,
|
|
368
|
+
export { prepareCodexSandboxController, runCodexSandboxController, verifyCodexSandboxControllerContextWithWarnings, controllerProofFromContext };
|
|
398
369
|
//# sourceMappingURL=sandbox-controller.js.map
|
|
@@ -30,6 +30,8 @@ function resolveHostCatalogPath(value, hostHomeDir) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
const CODEX_DISABLED_FEATURE_FLAGS = ['apps', 'enable_mcp_apps'];
|
|
33
|
+
const SANDBOX_CODEX_HOOKS_PATH = '/workspace/.codex/hooks.json';
|
|
34
|
+
const CODEX_HOOK_TRUST_HASH = /^sha256:[a-f0-9]{64}$/;
|
|
33
35
|
function removeCodexMcpServers(sandboxParsed) {
|
|
34
36
|
if (!Object.hasOwn(sandboxParsed, 'mcp_servers')) {
|
|
35
37
|
return false;
|
|
@@ -61,19 +63,58 @@ function inheritDisabledCodexFeatureFlags(sandboxParsed, hostParsed) {
|
|
|
61
63
|
}
|
|
62
64
|
return changed;
|
|
63
65
|
}
|
|
64
|
-
function
|
|
65
|
-
if (!
|
|
66
|
-
return;
|
|
66
|
+
function inheritCodexHookTrustState(sandboxParsed, hostParsed, hostProjectDir) {
|
|
67
|
+
if (!hostProjectDir) {
|
|
68
|
+
return false;
|
|
67
69
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return;
|
|
70
|
+
if (Object.hasOwn(sandboxParsed, 'hooks') && !isJsonObjectRecord(sandboxParsed.hooks)) {
|
|
71
|
+
return false;
|
|
71
72
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
const sandboxHooks = sandboxParsed.hooks ?? {};
|
|
74
|
+
if (Object.hasOwn(sandboxHooks, 'state') && !isJsonObjectRecord(sandboxHooks.state)) {
|
|
75
|
+
return false;
|
|
75
76
|
}
|
|
76
|
-
|
|
77
|
+
const sandboxState = sandboxHooks.state ?? {};
|
|
78
|
+
const sandboxPrefix = `${SANDBOX_CODEX_HOOKS_PATH}:`;
|
|
79
|
+
const nextState = Object.fromEntries(Object.entries(sandboxState).filter(([key]) => !key.startsWith(sandboxPrefix)));
|
|
80
|
+
const hostState = isJsonObjectRecord(hostParsed.hooks)
|
|
81
|
+
&& isJsonObjectRecord(hostParsed.hooks.state)
|
|
82
|
+
? hostParsed.hooks.state
|
|
83
|
+
: {};
|
|
84
|
+
const hostPrefix = `${path.join(hostProjectDir, '.codex', 'hooks.json')}:`;
|
|
85
|
+
for (const [key, value] of Object.entries(hostState)) {
|
|
86
|
+
if (!key.startsWith(hostPrefix) || !isJsonObjectRecord(value)) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const trustedHash = value.trusted_hash;
|
|
90
|
+
if (typeof trustedHash !== 'string' || !CODEX_HOOK_TRUST_HASH.test(trustedHash)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
nextState[`${sandboxPrefix}${key.slice(hostPrefix.length)}`] = {
|
|
94
|
+
trusted_hash: trustedHash,
|
|
95
|
+
...(typeof value.enabled === 'boolean' ? { enabled: value.enabled } : {})
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (JSON.stringify(sandboxState) === JSON.stringify(nextState)) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (Object.keys(nextState).length > 0) {
|
|
102
|
+
sandboxHooks.state = nextState;
|
|
103
|
+
sandboxParsed.hooks = sandboxHooks;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
delete sandboxHooks.state;
|
|
107
|
+
if (Object.keys(sandboxHooks).length > 0) {
|
|
108
|
+
sandboxParsed.hooks = sandboxHooks;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
delete sandboxParsed.hooks;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
function ensureCodexModelInheritance(toolDir, hostHomeDir, containerCodexDir = '/home/devuser/.codex', hostProjectDir) {
|
|
117
|
+
if (!hostHomeDir) {
|
|
77
118
|
return;
|
|
78
119
|
}
|
|
79
120
|
const sandboxConfigPath = path.join(toolDir, 'config.toml');
|
|
@@ -87,8 +128,25 @@ function ensureCodexModelInheritance(toolDir, hostHomeDir, containerCodexDir = '
|
|
|
87
128
|
return;
|
|
88
129
|
}
|
|
89
130
|
}
|
|
131
|
+
const hostConfigPath = path.join(hostHomeDir, '.codex', 'config.toml');
|
|
132
|
+
let hostParsed = null;
|
|
133
|
+
if (fs.existsSync(hostConfigPath)) {
|
|
134
|
+
try {
|
|
135
|
+
hostParsed = toml.parse(fs.readFileSync(hostConfigPath, 'utf8'));
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// An unavailable host trust source must not leave previously projected trust active.
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (!hostParsed) {
|
|
142
|
+
if (inheritCodexHookTrustState(sandboxParsed, {}, hostProjectDir)) {
|
|
143
|
+
fs.writeFileSync(sandboxConfigPath, `${toml.stringify(sandboxParsed)}\n`, 'utf8');
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
90
147
|
let changed = removeCodexMcpServers(sandboxParsed);
|
|
91
148
|
changed = inheritDisabledCodexFeatureFlags(sandboxParsed, hostParsed) || changed;
|
|
149
|
+
changed = inheritCodexHookTrustState(sandboxParsed, hostParsed, hostProjectDir) || changed;
|
|
92
150
|
const inheritSpecs = [
|
|
93
151
|
['model', 'string'],
|
|
94
152
|
['model_reasoning_effort', 'string'],
|
|
@@ -151,7 +209,10 @@ const codexBeforeContainerCreateHook = {
|
|
|
151
209
|
message: 'Codex sandbox hook requires its resolved tool state.'
|
|
152
210
|
};
|
|
153
211
|
}
|
|
154
|
-
|
|
212
|
+
const hostProjectDir = typeof context.config?.repoRoot === 'string'
|
|
213
|
+
? context.config.repoRoot
|
|
214
|
+
: undefined;
|
|
215
|
+
ensureCodexModelInheritance(entry.dir, create.hostHome, entry.tool.containerMount, hostProjectDir);
|
|
155
216
|
ensureCodexWorkspaceTrust(entry.dir);
|
|
156
217
|
return { status: 'ready' };
|
|
157
218
|
}
|
|
@@ -3,11 +3,13 @@ import { claudeCodeAdapter } from './claude-code.js';
|
|
|
3
3
|
import { codexAdapter } from './codex.js';
|
|
4
4
|
import { antigravityCliAdapter } from './antigravity-cli.js';
|
|
5
5
|
import { opencodeAdapter } from './opencode.js';
|
|
6
|
+
import { traecliAdapter } from './traecli.js';
|
|
6
7
|
const adaptersById = new Map([
|
|
7
8
|
claudeCodeAdapter,
|
|
8
9
|
codexAdapter,
|
|
9
10
|
antigravityCliAdapter,
|
|
10
|
-
opencodeAdapter
|
|
11
|
+
opencodeAdapter,
|
|
12
|
+
traecliAdapter
|
|
11
13
|
].map((adapter) => [adapter.id, adapter]));
|
|
12
14
|
const BUILTIN_AGENT_CLIENT_ADAPTERS = Object.freeze(AGENT_CLIENT_IDS.map((id) => {
|
|
13
15
|
const adapter = adaptersById.get(id);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { defineAgentClientAdapter } from '../adapter.js';
|
|
2
|
+
import { hostJoin } from '../../sandbox/engines/wsl2-paths.js';
|
|
3
|
+
const traecliAdapter = defineAgentClientAdapter({
|
|
4
|
+
id: 'traecli',
|
|
5
|
+
displayName: 'TraeCode CLI',
|
|
6
|
+
invocation: '/${skillName}',
|
|
7
|
+
capabilities: {
|
|
8
|
+
instructions: { level: 'compatible' },
|
|
9
|
+
skills: { level: 'compatible' },
|
|
10
|
+
commands: { level: 'integrated' },
|
|
11
|
+
hooks: { level: 'compatible' },
|
|
12
|
+
subagents: { level: 'experimental' },
|
|
13
|
+
orchestration: { level: 'experimental' },
|
|
14
|
+
sandbox: { level: 'integrated' },
|
|
15
|
+
verification: { level: 'compatible' }
|
|
16
|
+
},
|
|
17
|
+
modelSelection: {
|
|
18
|
+
kind: 'interactive-only',
|
|
19
|
+
command: '/model',
|
|
20
|
+
guidance: 'Use the host model picker for the complete model and reasoning-effort catalog.'
|
|
21
|
+
},
|
|
22
|
+
delegationEvidence: {
|
|
23
|
+
actualModel: 'unavailable',
|
|
24
|
+
actualReasoningEffort: 'unavailable'
|
|
25
|
+
},
|
|
26
|
+
project: {
|
|
27
|
+
ownedPathPrefixes: ['.trae/'],
|
|
28
|
+
managed: ['.trae/skills/'],
|
|
29
|
+
merged: [],
|
|
30
|
+
ejected: [],
|
|
31
|
+
seedCommands: [{
|
|
32
|
+
templates: {
|
|
33
|
+
en: '.trae/skills/update-agent-infra.en.md',
|
|
34
|
+
'zh-CN': '.trae/skills/update-agent-infra.zh-CN.md'
|
|
35
|
+
},
|
|
36
|
+
target: '.trae/skills/update-agent-infra.md'
|
|
37
|
+
}],
|
|
38
|
+
customCommand: {
|
|
39
|
+
target: '.trae/skills/${skillName}.md',
|
|
40
|
+
frontmatter: {},
|
|
41
|
+
includeUsage: true,
|
|
42
|
+
inheritDisableModelInvocation: true
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
sandbox: {
|
|
46
|
+
createTool: ({ home }) => ({
|
|
47
|
+
id: 'traecli',
|
|
48
|
+
name: 'TraeCode CLI',
|
|
49
|
+
install: {
|
|
50
|
+
type: 'shell',
|
|
51
|
+
cmd: 'curl -fsSL https://trae.cn/trae-cli/install_v2.sh | bash'
|
|
52
|
+
},
|
|
53
|
+
sandboxBase: hostJoin(home, '.agent-infra', 'sandboxes', 'traecli'),
|
|
54
|
+
containerMount: '/home/devuser/.trae',
|
|
55
|
+
versionCmd: 'traecli --version',
|
|
56
|
+
setupHint: 'Run traecli login inside the container to authenticate.'
|
|
57
|
+
}),
|
|
58
|
+
aliases: [
|
|
59
|
+
{ name: 'traecli-yolo', command: 'traecli --dangerously-bypass-approvals-and-sandbox; tput ed' },
|
|
60
|
+
{ name: 'ty', command: 'traecli --dangerously-bypass-approvals-and-sandbox; tput ed' }
|
|
61
|
+
],
|
|
62
|
+
hooks: []
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
export { traecliAdapter };
|
|
66
|
+
//# sourceMappingURL=traecli.js.map
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// activity log. Migrated from lib/task/commands/log.ts so that the write-side
|
|
3
3
|
// internal commands and the rendering side share one definition. Historical
|
|
4
4
|
// Gemini tokens remain read-only and are handled by classifyAgent below.
|
|
5
|
-
export const KNOWN_AI_AGENTS = new Set(['claude', 'codex', 'antigravity', 'opencode', 'cursor']);
|
|
5
|
+
export const KNOWN_AI_AGENTS = new Set(['claude', 'codex', 'antigravity', 'opencode', 'cursor', 'traecli']);
|
|
6
6
|
// Long name -> short name mapping (HD-4, decision A): `claude-code` reuses the
|
|
7
7
|
// existing orchestration precedent, and `antigravity-cli` is the active
|
|
8
8
|
// client. `gemini-cli` is intentionally not writable.
|
|
@@ -10,7 +10,7 @@ export const AGENT_LONG_NAMES = {
|
|
|
10
10
|
'claude-code': 'claude',
|
|
11
11
|
'antigravity-cli': 'antigravity'
|
|
12
12
|
};
|
|
13
|
-
export const AGENT_USAGE_HINT = "agent must be a short token (claude/codex/antigravity/opencode/cursor), " +
|
|
13
|
+
export const AGENT_USAGE_HINT = "agent must be a short token (claude/codex/antigravity/opencode/cursor/traecli), " +
|
|
14
14
|
"a long name (claude-code -> claude, antigravity-cli -> antigravity), or 'human'";
|
|
15
15
|
// Read-side historical compatibility for activity-log rendering: `gemini` and
|
|
16
16
|
// `gemini-cli` stay recognizable when displaying old logs, but are never
|
package/dist/lib/defaults.json
CHANGED
package/dist/lib/git/workflow.js
CHANGED
|
@@ -124,7 +124,16 @@ function pushGitRefs(input, runner = defaultRunner) {
|
|
|
124
124
|
}
|
|
125
125
|
const canonical = ref.startsWith('refs/') ? ref : `refs/heads/${ref}`;
|
|
126
126
|
const remoteFact = run(runner, input.cwd, ['ls-remote', '--exit-code', input.remote, canonical]);
|
|
127
|
-
|
|
127
|
+
const remoteSha = remoteFact.status === 0 ? remoteFact.stdout.trim().split(/\s+/)[0] ?? null : null;
|
|
128
|
+
const verified = remoteFact.status === 0 && (!input.expectedSha || remoteSha === input.expectedSha);
|
|
129
|
+
operations.push({
|
|
130
|
+
name: 'push',
|
|
131
|
+
ref,
|
|
132
|
+
status: verified ? 'applied' : 'failed',
|
|
133
|
+
message: verified ? undefined : input.expectedSha
|
|
134
|
+
? `Remote ref verification failed: expected ${input.expectedSha}, received ${remoteSha ?? 'unavailable'}`
|
|
135
|
+
: 'Remote ref verification failed'
|
|
136
|
+
});
|
|
128
137
|
}
|
|
129
138
|
const failures = operations.filter((item) => item.status === 'failed').length;
|
|
130
139
|
return { status: failures === 0 ? 'applied' : failures === operations.length ? 'failed' : 'degraded', changed: failures < operations.length, snapshot: inspectGitWorkflow(input.cwd, runner).snapshot, operations, error: failures ? { code: 'GIT_PUSH_PARTIAL', message: `${failures} ref push operation(s) failed` } : null };
|
|
@@ -6,8 +6,9 @@ import { preflightCodexLifecycleEvidence, resolveCodexTerminal, resolveCodexThre
|
|
|
6
6
|
import { createCodexLifecycleStore } from '../agent-clients/adapters/codex-lifecycle/store.js';
|
|
7
7
|
import { createCodexCapabilityStore } from '../agent-clients/adapters/codex-lifecycle/capability-store.js';
|
|
8
8
|
import { computeLifecycleBuildIdentity } from '../agent-clients/adapters/codex-lifecycle/build-identity.js';
|
|
9
|
-
import {
|
|
9
|
+
import { verifyCodexSandboxControllerContextWithWarnings } from '../agent-clients/adapters/codex-lifecycle/sandbox-controller.js';
|
|
10
10
|
import { resolveTaskRef } from '../task/resolve-ref.js';
|
|
11
|
+
import { hasSealableOrchestrationDelegation } from '../task/orchestration.js';
|
|
11
12
|
import { activateCodexOrchestrationDelegation, activateCodexSpawnDelegation, reconcileCodexOrchestrationDelegation, sealCodexOrchestrationDelegation, sealCodexParentDelegation } from '../task/codex-orchestration.js';
|
|
12
13
|
const USAGE = 'Usage: agent-infra-internal codex-lifecycle <capability-arm|hook-event|resolve-start|resolve-stop|preflight|consume> [options]\n';
|
|
13
14
|
const MANAGED_AGENT = /^agent-infra-lifecycle-(executor|reviewer)$/;
|
|
@@ -80,7 +81,7 @@ function controllerBinding(taskId) {
|
|
|
80
81
|
const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
|
|
81
82
|
if (!contextPath)
|
|
82
83
|
return undefined;
|
|
83
|
-
const context =
|
|
84
|
+
const context = verifyCodexSandboxControllerContextWithWarnings(contextPath, { repoRoot: process.cwd() }).context;
|
|
84
85
|
return {
|
|
85
86
|
instanceDigest: context.controllerInstanceDigest,
|
|
86
87
|
controlGeneration: context.controlGeneration
|
|
@@ -121,7 +122,8 @@ function recordFromPayload(phase, payload) {
|
|
|
121
122
|
sessionId: text('sessionId'),
|
|
122
123
|
turnId: text('turnId'),
|
|
123
124
|
childThreadId: text('childThreadId'),
|
|
124
|
-
nativeAgent: text('nativeAgent')
|
|
125
|
+
nativeAgent: text('nativeAgent'),
|
|
126
|
+
source: 'hook'
|
|
125
127
|
};
|
|
126
128
|
if (phase === 'subagent-stop')
|
|
127
129
|
return {
|
|
@@ -314,8 +316,17 @@ async function codexLifecycle(args = []) {
|
|
|
314
316
|
}
|
|
315
317
|
const result = store.apply(event);
|
|
316
318
|
if (parsed.values['--bridge'] === 'true' && event.type === 'hook-stop') {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
+
if (!hasSealableOrchestrationDelegation('codex', event.childThreadId, { repoRoot: process.cwd() })) {
|
|
320
|
+
output({ status: 'ignored', changed: false, evidence: null, diagnostics: [], error: null });
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
output({
|
|
324
|
+
status: result.state.status,
|
|
325
|
+
changed: true,
|
|
326
|
+
evidence: result.state,
|
|
327
|
+
diagnostics: [],
|
|
328
|
+
error: result.state.error
|
|
329
|
+
});
|
|
319
330
|
return;
|
|
320
331
|
}
|
|
321
332
|
output({ status: result.state.status, changed: true, evidence: result.state, diagnostics: [], error: result.state.error });
|
|
@@ -341,7 +352,10 @@ async function codexLifecycle(args = []) {
|
|
|
341
352
|
return;
|
|
342
353
|
}
|
|
343
354
|
if (parsed.operation === 'resolve-stop') {
|
|
344
|
-
const
|
|
355
|
+
const stopTurnId = store.read(childThreadId).state.stop?.turnId;
|
|
356
|
+
if (!stopTurnId)
|
|
357
|
+
throw new Error('Codex lifecycle stop hook is not available');
|
|
358
|
+
const terminal = await resolveCodexTerminal(childThreadId, stopTurnId);
|
|
345
359
|
const latest = store.apply(terminal);
|
|
346
360
|
if (latest.state.status !== 'stop-ready') {
|
|
347
361
|
throw new Error(`Codex lifecycle stop evidence is not ready (status=${latest.state.status})`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runCodexSandboxController,
|
|
1
|
+
import { runCodexSandboxController, verifyCodexSandboxControllerContextWithWarnings } from '../agent-clients/adapters/codex-lifecycle/sandbox-controller.js';
|
|
2
2
|
const USAGE = 'Usage: agent-infra-internal codex-sandbox-controller <run|verify-context> [options]\n';
|
|
3
3
|
function fail(code, message, exitCode = 1) {
|
|
4
4
|
process.stdout.write(`${JSON.stringify({
|
|
@@ -20,8 +20,6 @@ function parse(args) {
|
|
|
20
20
|
return null;
|
|
21
21
|
}
|
|
22
22
|
const allowed = new Set([
|
|
23
|
-
'--task-id',
|
|
24
|
-
'--task-ref',
|
|
25
23
|
'--context',
|
|
26
24
|
'--executor-model',
|
|
27
25
|
'--executor-reasoning-effort',
|
|
@@ -31,6 +29,11 @@ function parse(args) {
|
|
|
31
29
|
const values = {};
|
|
32
30
|
for (let index = 1; index < args.length; index += 1) {
|
|
33
31
|
const flag = args[index];
|
|
32
|
+
if (flag === '--task-id' || flag.startsWith('--task-id=')
|
|
33
|
+
|| flag === '--task-ref' || flag.startsWith('--task-ref=')) {
|
|
34
|
+
fail('CODEX_SANDBOX_CONTROLLER_IDENTITY_OPTION_UNSUPPORTED', 'controller task identity options are not supported', 2);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
34
37
|
const value = args[++index];
|
|
35
38
|
if (!allowed.has(flag) || Object.hasOwn(values, flag) || !value || value.startsWith('--')) {
|
|
36
39
|
fail('CODEX_SANDBOX_CONTROLLER_PAYLOAD_INVALID', `invalid option '${flag}'`, 2);
|
|
@@ -44,18 +47,14 @@ async function codexSandboxController(args = []) {
|
|
|
44
47
|
const parsed = parse(args);
|
|
45
48
|
if (!parsed || process.exitCode)
|
|
46
49
|
return;
|
|
47
|
-
const taskId = parsed.values['--task-id'];
|
|
48
|
-
if (!taskId) {
|
|
49
|
-
fail('CODEX_SANDBOX_CONTROLLER_PAYLOAD_INVALID', '--task-id is required', 2);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
50
|
try {
|
|
53
51
|
if (parsed.operation === 'verify-context') {
|
|
54
52
|
const contextPath = parsed.values['--context']
|
|
55
53
|
?? process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
|
|
56
54
|
if (!contextPath)
|
|
57
55
|
throw new Error('CODEX_SANDBOX_CONTROLLER_CONTEXT_MISSING');
|
|
58
|
-
const
|
|
56
|
+
const verified = verifyCodexSandboxControllerContextWithWarnings(contextPath);
|
|
57
|
+
const context = verified.context;
|
|
59
58
|
process.stdout.write(`${JSON.stringify({
|
|
60
59
|
status: 'ready',
|
|
61
60
|
changed: false,
|
|
@@ -66,15 +65,12 @@ async function codexSandboxController(args = []) {
|
|
|
66
65
|
expiresAt: context.expiresAt,
|
|
67
66
|
buildIdentity: context.buildIdentity,
|
|
68
67
|
hookDefinitionHash: context.hookDefinitionHash,
|
|
69
|
-
lifecycleProfilesHash: context.lifecycleProfilesHash
|
|
70
68
|
},
|
|
69
|
+
...(verified.warnings.length > 0 ? { warnings: verified.warnings } : {}),
|
|
71
70
|
error: null
|
|
72
71
|
})}\n`);
|
|
73
72
|
return;
|
|
74
73
|
}
|
|
75
|
-
const taskRef = parsed.values['--task-ref'];
|
|
76
|
-
if (!taskRef)
|
|
77
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_TASK_REF_REQUIRED');
|
|
78
74
|
const policy = [
|
|
79
75
|
'--executor-model',
|
|
80
76
|
'--executor-reasoning-effort',
|
|
@@ -86,8 +82,6 @@ async function codexSandboxController(args = []) {
|
|
|
86
82
|
throw new Error('CODEX_SANDBOX_CONTROLLER_MODEL_POLICY_INVALID');
|
|
87
83
|
}
|
|
88
84
|
const exitCode = await runCodexSandboxController({
|
|
89
|
-
taskId,
|
|
90
|
-
taskRef,
|
|
91
85
|
executorModel: parsed.values['--executor-model'],
|
|
92
86
|
executorReasoningEffort: parsed.values['--executor-reasoning-effort'],
|
|
93
87
|
reviewerModel: parsed.values['--reviewer-model'],
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import {
|
|
2
|
+
import { inspectGitWorkflow, pushRebasedBranch } from '../git/workflow.js';
|
|
3
3
|
import { compareReviewTrees, snapshotReview } from '../git/review-snapshot.js';
|
|
4
4
|
import { resolvePostReviewGlobs } from '../task/review-fingerprint.js';
|
|
5
|
+
import { executeCommitOperation } from '../task/commit-operation.js';
|
|
5
6
|
function output(value) { process.stdout.write(`${JSON.stringify(value)}\n`); }
|
|
6
7
|
function gitWorkflow(args = []) {
|
|
7
8
|
const [action, ...rest] = args;
|
|
@@ -16,12 +17,9 @@ function gitWorkflow(args = []) {
|
|
|
16
17
|
else if (action === 'commit') {
|
|
17
18
|
const inputIndex = rest.indexOf('--input');
|
|
18
19
|
const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1], 'utf8')) : null;
|
|
19
|
-
result = input
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const inputIndex = rest.indexOf('--input');
|
|
23
|
-
const input = inputIndex >= 0 && rest[inputIndex + 1] ? JSON.parse(fs.readFileSync(rest[inputIndex + 1], 'utf8')) : null;
|
|
24
|
-
result = input ? pushGitRefs({ cwd: cwd ?? process.cwd(), ...input }) : { status: 'failed', changed: false, error: { code: 'GIT_INPUT_REQUIRED', message: '--input JSON file is required' } };
|
|
20
|
+
result = input
|
|
21
|
+
? executeCommitOperation({ cwd: cwd ?? process.cwd(), ...input })
|
|
22
|
+
: { status: 'failed', changed: false, error: { code: 'GIT_INPUT_REQUIRED', message: '--input JSON file is required' } };
|
|
25
23
|
}
|
|
26
24
|
else if (action === 'push-rebased') {
|
|
27
25
|
const inputIndex = rest.indexOf('--input');
|