@fitlab-ai/agent-infra 0.11.1 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/internal/cli-route-inventory.js +1 -1
- package/dist/lib/internal/platform-comment.js +59 -0
- package/dist/lib/internal/sandbox-control.js +4 -131
- package/dist/lib/internal/task-artifact.js +1 -1
- package/dist/lib/internal/task-operation-registry.js +1 -0
- package/dist/lib/internal/task-review.js +5 -5
- package/dist/lib/internal/task-validate.js +0 -6
- package/dist/lib/platform/comment-safety.js +7 -1
- package/dist/lib/platform/github-provider.js +13 -3
- package/dist/lib/platform/issue-comments.js +120 -13
- package/dist/lib/platform/provider-contract.d.ts +2 -0
- package/dist/lib/platform/provider-validation.js +7 -2
- package/dist/lib/platform/verification-sync.js +19 -2
- package/dist/lib/sandbox/control/executor.js +0 -38
- package/dist/lib/sandbox/control/finalization-response.js +10 -2
- package/dist/lib/sandbox/control/task-view.js +3 -1
- package/dist/lib/sandbox/control/workflow-executor.js +28 -43
- package/dist/lib/task/artifact-command.js +6 -6
- package/dist/lib/task/codex-orchestration.js +10 -208
- package/dist/lib/task/commit-operation.js +3 -18
- package/dist/lib/task/control-authority.js +1 -8
- package/dist/lib/task/delegation-receipts.js +14 -76
- package/dist/lib/task/events.js +89 -237
- package/dist/lib/task/finalization-state.js +2 -1
- package/dist/lib/task/finalization.js +273 -49
- package/dist/lib/task/lifecycle-execution.js +2 -11
- package/dist/lib/task/local-artifact-finalization.js +25 -242
- package/dist/lib/task/orchestration.js +0 -18
- package/dist/lib/task/review-command.js +0 -1
- package/dist/lib/task/review-finalization.js +46 -211
- package/dist/lib/task/workflow-command.js +4 -1
- package/dist/lib/task/workflow-dispatch.js +55 -3
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/internal/cli-route-inventory.ts +1 -1
- package/lib/internal/platform-comment.ts +38 -0
- package/lib/internal/sandbox-control.ts +3 -145
- package/lib/internal/task-artifact.ts +1 -1
- package/lib/internal/task-operation-registry.ts +1 -0
- package/lib/internal/task-review.ts +5 -5
- package/lib/internal/task-validate.ts +0 -5
- package/lib/platform/comment-safety.ts +8 -0
- package/lib/platform/github-provider.ts +11 -2
- package/lib/platform/issue-comments.ts +132 -13
- package/lib/platform/provider-contract.ts +2 -0
- package/lib/platform/provider-validation.ts +6 -2
- package/lib/platform/verification-sync.ts +19 -2
- package/lib/sandbox/control/executor.ts +0 -44
- package/lib/sandbox/control/finalization-response.ts +10 -2
- package/lib/sandbox/control/task-view.ts +3 -1
- package/lib/sandbox/control/workflow-executor.ts +23 -50
- package/lib/task/artifact-command.ts +6 -7
- package/lib/task/codex-orchestration.ts +8 -241
- package/lib/task/commit-operation.ts +3 -23
- package/lib/task/control-authority.ts +1 -8
- package/lib/task/delegation-receipts.ts +12 -79
- package/lib/task/events.ts +106 -255
- package/lib/task/finalization-state.ts +2 -1
- package/lib/task/finalization.ts +277 -57
- package/lib/task/lifecycle-execution.ts +10 -21
- package/lib/task/local-artifact-finalization.ts +23 -281
- package/lib/task/orchestration.ts +0 -34
- package/lib/task/review-command.ts +0 -1
- package/lib/task/review-finalization.ts +45 -193
- package/lib/task/workflow-command.ts +4 -1
- package/lib/task/workflow-dispatch.ts +46 -3
- package/package.json +2 -2
- package/templates/.agents/rules/lifecycle-orchestration.en.md +7 -7
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +7 -7
- package/templates/.agents/rules/local-artifact-repair.en.md +14 -60
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +13 -60
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/plan-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-code/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/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
|
@@ -4,9 +4,15 @@ import type { SandboxControlResponse } from './protocol.ts';
|
|
|
4
4
|
export function finalizationTerminalResponse(taskId: string, requestId: string, receipt: TaskFinalizationReceipt): SandboxControlResponse {
|
|
5
5
|
const pendingSteps = [
|
|
6
6
|
receipt.taskComment === 'pending' ? 'task-comment' : null,
|
|
7
|
-
receipt.verification === 'pending' ? 'verification' : null
|
|
7
|
+
receipt.verification === 'pending' ? 'verification' : null,
|
|
8
|
+
receipt.summary === 'pending' ? 'summary' : null,
|
|
9
|
+
receipt.postSummaryVerification === 'pending' ? 'post-summary-verification' : null
|
|
8
10
|
].filter((step): step is string => step !== null);
|
|
9
|
-
const completedSteps = [
|
|
11
|
+
const completedSteps = [
|
|
12
|
+
'lifecycle', receipt.taskComment === 'pending' ? null : 'task-comment',
|
|
13
|
+
receipt.verification === 'pending' ? null : 'verification', receipt.summary === 'pending' ? null : 'summary',
|
|
14
|
+
receipt.postSummaryVerification === 'pending' ? null : 'post-summary-verification'
|
|
15
|
+
]
|
|
10
16
|
.filter((step): step is string => step !== null);
|
|
11
17
|
const warnings = receipt.warnings
|
|
12
18
|
.filter((warning) => warning.status === 'open')
|
|
@@ -16,6 +22,8 @@ export function finalizationTerminalResponse(taskId: string, requestId: string,
|
|
|
16
22
|
lifecycle: { status: 'no-op', changed: false, error: null },
|
|
17
23
|
taskComment: receipt.taskComment === 'pending' ? null : { status: 'no-op', changed: false, error: null },
|
|
18
24
|
verification: receipt.verification === 'pending' ? null : { status: 'no-op', changed: false, error: null },
|
|
25
|
+
summary: receipt.summary === 'pending' ? null : { status: 'no-op', changed: false, error: null },
|
|
26
|
+
postSummaryVerification: receipt.postSummaryVerification === 'pending' ? null : { status: 'no-op', changed: false, error: null },
|
|
19
27
|
completedSteps, pendingSteps,
|
|
20
28
|
result: pendingSteps.length > 0 || receipt.warningProjection === 'pending' || warnings.length > 0
|
|
21
29
|
? 'completed_with_warnings' : 'completed',
|
|
@@ -56,9 +56,11 @@ function receiptIdentity(value: unknown, generation: string, requestId?: string)
|
|
|
56
56
|
const binding = receipt.controlBinding;
|
|
57
57
|
if (!binding || typeof binding !== 'object' || Array.isArray(binding)) return null;
|
|
58
58
|
const controlBinding = binding as Record<string, unknown>;
|
|
59
|
-
if (receipt.version !==
|
|
59
|
+
if (receipt.version !== 3 || typeof receipt.receiptId !== 'string' || receipt.receiptId.length === 0
|
|
60
60
|
|| !Number.isSafeInteger(receipt.revision) || (receipt.revision as number) < 0
|
|
61
61
|
|| receipt.lifecycle !== 'done'
|
|
62
|
+
|| !['pending', 'done', 'skipped'].includes(String(receipt.summary))
|
|
63
|
+
|| !['pending', 'done', 'skipped'].includes(String(receipt.postSummaryVerification))
|
|
62
64
|
|| controlBinding.generation !== generation
|
|
63
65
|
|| typeof controlBinding.requestId !== 'string'
|
|
64
66
|
|| !/^[a-f0-9-]{16,64}$/u.test(controlBinding.requestId)
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
|
|
1
5
|
import { TASK_WORKFLOW_COMMANDS } from '../../task/workflow-command.ts';
|
|
2
6
|
|
|
3
7
|
import { parseArtifactCommand, executeArtifactCommand } from '../../task/artifact-command.ts';
|
|
@@ -5,10 +9,8 @@ import { parseReviewCommand } from '../../task/review-command.ts';
|
|
|
5
9
|
import { prepareLocalArtifact, preflightLocalArtifact, commitLocalArtifactProvenance } from '../../task/local-artifact-finalization.ts';
|
|
6
10
|
import {
|
|
7
11
|
prepareReviewSummaryCandidate,
|
|
8
|
-
commitReviewSummaryProvenance,
|
|
9
12
|
preflightReviewSummary
|
|
10
13
|
} from '../../task/review-finalization.ts';
|
|
11
|
-
import { readArtifactRecoveryIntent } from '../../task/artifact-repair-intent.ts';
|
|
12
14
|
import { withTaskExecutionLock } from '../../task/task-execution-lock.ts';
|
|
13
15
|
import { dispatchWorkflowCommand } from '../../task/workflow-dispatch.ts';
|
|
14
16
|
import { assertSandboxTaskSource } from '../workspace-view.ts';
|
|
@@ -37,6 +39,18 @@ function executionResult(result: Record<string, unknown>): SandboxControlExecuti
|
|
|
37
39
|
return { exitCode: result.status === 'failed' || result.status === 'refused' ? 1 : 0, stdout: `${JSON.stringify(result)}\n`, stderr: '' };
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
function replaceCurrentArtifactAtomically(file: string, content: string): void {
|
|
43
|
+
const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`);
|
|
44
|
+
try {
|
|
45
|
+
fs.writeFileSync(temporary, content, { encoding: 'utf8', flag: 'wx' });
|
|
46
|
+
fs.renameSync(temporary, file);
|
|
47
|
+
} finally {
|
|
48
|
+
try { fs.unlinkSync(temporary); } catch (error) {
|
|
49
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
40
54
|
/** The broker already authorized this host executor; domain operations own validation. */
|
|
41
55
|
export async function executeTaskWorkflow(
|
|
42
56
|
manifest: SandboxControlManifest,
|
|
@@ -45,25 +59,6 @@ export async function executeTaskWorkflow(
|
|
|
45
59
|
options: TaskWorkflowExecutionOptions = {}
|
|
46
60
|
): Promise<SandboxControlExecutionResult> {
|
|
47
61
|
let publicationCommitted = false;
|
|
48
|
-
let recoveryObservation: Readonly<{
|
|
49
|
-
family: 'analysis' | 'plan' | 'code' | 'review-analysis' | 'review-plan' | 'review-code';
|
|
50
|
-
artifact: string;
|
|
51
|
-
wasPassed: boolean;
|
|
52
|
-
}> | null = null;
|
|
53
|
-
const observeRecoveryPublication = (): void => {
|
|
54
|
-
if (!recoveryObservation || recoveryObservation.wasPassed) return;
|
|
55
|
-
const intent = readArtifactRecoveryIntent(
|
|
56
|
-
manifest.repoRoot,
|
|
57
|
-
request.taskId,
|
|
58
|
-
recoveryObservation.family,
|
|
59
|
-
recoveryObservation.artifact
|
|
60
|
-
);
|
|
61
|
-
publicationCommitted ||= intent?.state === 'preflight-ready'
|
|
62
|
-
|| intent?.state === 'preflight-commit-started'
|
|
63
|
-
|| intent?.state === 'preflight-passed'
|
|
64
|
-
|| intent?.state === 'passed'
|
|
65
|
-
|| intent?.state === 'commit-started';
|
|
66
|
-
};
|
|
67
62
|
let faultTriggered = false;
|
|
68
63
|
const fault = (window: TaskWorkflowFaultWindow): void => {
|
|
69
64
|
if (faultTriggered || options.faultWindow !== window) return;
|
|
@@ -125,47 +120,26 @@ export async function executeTaskWorkflow(
|
|
|
125
120
|
if ('operation' in input) {
|
|
126
121
|
const { family } = input;
|
|
127
122
|
if (family !== 'analysis' && family !== 'plan' && family !== 'code') throw new Error('ARTIFACT_IDENTITY_INVALID');
|
|
128
|
-
const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot,
|
|
123
|
+
const local = { taskRef: request.taskId, family, artifact: input.artifact, repoRoot: manifest.repoRoot, lockAlreadyHeld: true } as const;
|
|
129
124
|
if (input.operation === 'preflight') {
|
|
130
|
-
// Preflight only seals a verified generation. It must not publish the
|
|
131
|
-
// formal artifact, set publicationStarted, or append finalizer audit.
|
|
132
125
|
const result = preflightLocalArtifact(local);
|
|
133
|
-
recoveryObservation = { family, artifact: input.artifact, wasPassed: false };
|
|
134
|
-
observeRecoveryPublication();
|
|
135
126
|
return response(result);
|
|
136
127
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
artifact: input.artifact,
|
|
140
|
-
wasPassed: readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, family, input.artifact)?.state === 'passed'
|
|
141
|
-
};
|
|
142
|
-
const prepared = prepareLocalArtifact(local, content, lifecycleRecoveryAttestation ?? undefined);
|
|
143
|
-
observeRecoveryPublication();
|
|
144
|
-
const commitOptions = { afterPublish: () => fault('after-atomic-rename') };
|
|
145
|
-
if (prepared.result.status === 'failed') return executionResult(commitLocalArtifactProvenance(prepared, commitOptions));
|
|
146
|
-
result = commitLocalArtifactProvenance(prepared, commitOptions);
|
|
128
|
+
const prepared = prepareLocalArtifact(local, content);
|
|
129
|
+
result = commitLocalArtifactProvenance(prepared);
|
|
147
130
|
} else {
|
|
148
131
|
if (input.overrideTicket) throw new Error('TASK_WORKFLOW_OVERRIDE_UNSUPPORTED');
|
|
149
132
|
const family = `review-${input.stage}` as 'review-analysis' | 'review-plan' | 'review-code';
|
|
150
133
|
if (request.operation === 'review-preflight') {
|
|
151
134
|
const result = preflightReviewSummary(input, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true });
|
|
152
|
-
recoveryObservation = { family, artifact: input.artifact, wasPassed: false };
|
|
153
|
-
observeRecoveryPublication();
|
|
154
135
|
return response(result);
|
|
155
136
|
}
|
|
156
|
-
|
|
157
|
-
family,
|
|
158
|
-
artifact: input.artifact,
|
|
159
|
-
wasPassed: readArtifactRecoveryIntent(manifest.repoRoot, request.taskId, family, input.artifact)?.state === 'passed'
|
|
160
|
-
};
|
|
161
|
-
const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true, startRecovery: true });
|
|
162
|
-
observeRecoveryPublication();
|
|
137
|
+
const prepared = prepareReviewSummaryCandidate(input, content, { repoRoot: manifest.repoRoot, lockAlreadyHeld: true });
|
|
163
138
|
if (input.dryRun || prepared.result.status === 'planned') return executionResult(prepared.result);
|
|
164
|
-
|
|
165
|
-
if (prepared.result.
|
|
166
|
-
result =
|
|
139
|
+
if (prepared.result.status === 'failed') return executionResult(prepared.result);
|
|
140
|
+
if (prepared.result.changed) replaceCurrentArtifactAtomically(path.join(taskDir, input.artifact), prepared.content);
|
|
141
|
+
result = prepared.result;
|
|
167
142
|
}
|
|
168
|
-
observeRecoveryPublication();
|
|
169
143
|
publicationCommitted ||= result.changed === true;
|
|
170
144
|
if (result.status !== 'failed') appendDiagnosticAudit(manifest, 'task-workflow-artifact-finalized', {
|
|
171
145
|
requestId: request.id, sandboxTaskId: request.taskId, workflowOperation: request.operation,
|
|
@@ -175,7 +149,6 @@ export async function executeTaskWorkflow(
|
|
|
175
149
|
return response(result);
|
|
176
150
|
});
|
|
177
151
|
} catch (error) {
|
|
178
|
-
observeRecoveryPublication();
|
|
179
152
|
const message = error instanceof Error ? error.message : String(error);
|
|
180
153
|
const code = (error as { code?: string })?.code ?? /^([A-Z][A-Z0-9_]+)/u.exec(message)?.[1] ?? 'TASK_WORKFLOW_REQUEST_INVALID';
|
|
181
154
|
return executionResult({ status: 'failed', changed: publicationCommitted ? null : false, error: { code, message } });
|
|
@@ -13,7 +13,6 @@ export type ArtifactCommand = Readonly<{
|
|
|
13
13
|
family: string;
|
|
14
14
|
artifact: string;
|
|
15
15
|
locale?: 'zh-CN' | 'en';
|
|
16
|
-
recoveryId?: string;
|
|
17
16
|
}>;
|
|
18
17
|
|
|
19
18
|
/** One option contract for the CLI and trusted projection executor. */
|
|
@@ -26,8 +25,8 @@ export function parseArtifactCommand(args: readonly string[]): ArtifactCommand {
|
|
|
26
25
|
const allowed = {
|
|
27
26
|
inspect: ['--family'],
|
|
28
27
|
init: ['--family', '--artifact', '--locale'],
|
|
29
|
-
'preflight': ['--family', '--artifact'
|
|
30
|
-
'finalize-local': ['--family', '--artifact'
|
|
28
|
+
'preflight': ['--family', '--artifact'],
|
|
29
|
+
'finalize-local': ['--family', '--artifact']
|
|
31
30
|
}[operation as ArtifactCommand['operation']];
|
|
32
31
|
for (let index = 2; index < args.length; index += 1) {
|
|
33
32
|
const flag = args[index]!;
|
|
@@ -43,7 +42,7 @@ export function parseArtifactCommand(args: readonly string[]): ArtifactCommand {
|
|
|
43
42
|
if (locale !== undefined && locale !== 'zh-CN' && locale !== 'en') throw new Error("option '--locale' must be 'zh-CN' or 'en'");
|
|
44
43
|
return {
|
|
45
44
|
taskRef, operation: operation as ArtifactCommand['operation'], family: fields['--family'],
|
|
46
|
-
artifact: fields['--artifact'] ?? '', locale
|
|
45
|
+
artifact: fields['--artifact'] ?? '', locale
|
|
47
46
|
};
|
|
48
47
|
}
|
|
49
48
|
/** Resolve authoritative task metadata separately from a trusted candidate directory. */
|
|
@@ -51,7 +50,7 @@ export function executeArtifactCommand(
|
|
|
51
50
|
command: ArtifactCommand,
|
|
52
51
|
options: Readonly<{ repoRoot?: string; artifactDir?: string }> = {}
|
|
53
52
|
): Record<string, unknown> {
|
|
54
|
-
const { taskRef, operation, family, artifact, locale
|
|
53
|
+
const { taskRef, operation, family, artifact, locale } = command;
|
|
55
54
|
const fail = (code: string, message: string) => ({ status: 'failed', changed: false, error: { code, message } });
|
|
56
55
|
if (operation === 'inspect') {
|
|
57
56
|
const result = resolveArtifactContext(taskRef, family, { repoRoot: options.repoRoot });
|
|
@@ -82,6 +81,6 @@ export function executeArtifactCommand(
|
|
|
82
81
|
if (family !== 'analysis' && family !== 'plan' && family !== 'code') {
|
|
83
82
|
return fail('ARTIFACT_PAYLOAD_INVALID', "preflight and finalize-local only support 'analysis', 'plan', and 'code'");
|
|
84
83
|
}
|
|
85
|
-
if (operation === 'preflight') return { ...preflightLocalArtifact({ taskRef, family, artifact, repoRoot: resolved.repoRoot
|
|
86
|
-
return { ...finalizeLocalArtifact({ taskRef, family, artifact, repoRoot: resolved.repoRoot
|
|
84
|
+
if (operation === 'preflight') return { ...preflightLocalArtifact({ taskRef, family, artifact, repoRoot: resolved.repoRoot }) };
|
|
85
|
+
return { ...finalizeLocalArtifact({ taskRef, family, artifact, repoRoot: resolved.repoRoot }) };
|
|
87
86
|
}
|
|
@@ -5,21 +5,10 @@ import {
|
|
|
5
5
|
resolveCodexThread
|
|
6
6
|
} from '../agent-clients/adapters/codex-lifecycle/app-server.ts';
|
|
7
7
|
import { createCodexLifecycleStore } from '../agent-clients/adapters/codex-lifecycle/store.ts';
|
|
8
|
-
import {
|
|
9
|
-
createCodexCapabilityStore,
|
|
10
|
-
isCodexCapabilityProvenanceDetail
|
|
11
|
-
} from '../agent-clients/adapters/codex-lifecycle/capability-store.ts';
|
|
12
|
-
import type { CodexCapabilityProvenanceDetail } from '../agent-clients/adapters/codex-lifecycle/capability-store.ts';
|
|
13
8
|
import {
|
|
14
9
|
computeLifecycleBuildIdentity,
|
|
15
|
-
verifyLifecycleBuildIdentity,
|
|
16
10
|
type LifecycleBuildIdentity,
|
|
17
|
-
type LifecycleIdentityWarning
|
|
18
11
|
} from '../agent-clients/adapters/codex-lifecycle/build-identity.ts';
|
|
19
|
-
import { verifyCodexSandboxControllerContextWithWarnings as verifySandboxControllerWithWarnings } from '../agent-clients/adapters/codex-lifecycle/sandbox-controller.ts';
|
|
20
|
-
import {
|
|
21
|
-
verifyCodexSandboxControllerContextWithWarnings as verifyControllerContextFileWithWarnings
|
|
22
|
-
} from '../agent-clients/adapters/codex-lifecycle/controller-context.ts';
|
|
23
12
|
import type { AgentClientId } from '../agent-clients/types.ts';
|
|
24
13
|
import { resolveTaskRef } from './resolve-ref.ts';
|
|
25
14
|
import {
|
|
@@ -29,32 +18,20 @@ import {
|
|
|
29
18
|
OrchestrationStateError,
|
|
30
19
|
pauseMatchingOrchestrationDelegation,
|
|
31
20
|
prepareOrchestrationDelegation,
|
|
32
|
-
routeOrchestration,
|
|
33
21
|
reconcileMatchingOrchestrationDelegation,
|
|
34
22
|
sealMatchingOrchestrationDelegationWithHostEvidence
|
|
35
23
|
} from './orchestration.ts';
|
|
36
|
-
import { randomUUID, createHash } from 'node:crypto';
|
|
37
24
|
import type { OrchestrationOptions, OrchestrationResult } from './orchestration.ts';
|
|
38
|
-
import {
|
|
39
|
-
consumeLifecycleRecoveryAttestation,
|
|
40
|
-
issueLifecycleRecoveryAttestation,
|
|
41
|
-
validateLifecycleRecoveryAttestation,
|
|
42
|
-
type LifecycleRecoveryAttestationV1
|
|
43
|
-
} from './control-authority.ts';
|
|
44
25
|
|
|
45
26
|
type LifecycleStore = ReturnType<typeof createCodexLifecycleStore>;
|
|
46
|
-
type CapabilityStore = ReturnType<typeof createCodexCapabilityStore>;
|
|
47
27
|
type CodexBridgeOptions = Readonly<{
|
|
48
28
|
repoRoot?: string;
|
|
49
29
|
store?: LifecycleStore;
|
|
50
30
|
preflight?: typeof preflightCodexLifecycleEvidence;
|
|
51
31
|
resolveThread?: typeof resolveCodexThread;
|
|
52
32
|
resolveTerminal?: typeof resolveCodexTerminal;
|
|
53
|
-
capabilityStore?: CapabilityStore;
|
|
54
33
|
buildIdentity?: LifecycleBuildIdentity;
|
|
55
34
|
orchestrationOptions?: OrchestrationOptions;
|
|
56
|
-
controllerBinding?: Readonly<{ instanceDigest: string; controlGeneration: string }>;
|
|
57
|
-
deferLifecycleRecoveryConsumption?: boolean;
|
|
58
35
|
}>;
|
|
59
36
|
|
|
60
37
|
type CodexSpawnIdentity = Readonly<{
|
|
@@ -68,35 +45,14 @@ type CodexSpawnIdentity = Readonly<{
|
|
|
68
45
|
requestedReasoningEffort?: string;
|
|
69
46
|
}>;
|
|
70
47
|
|
|
71
|
-
function buildIdentityDigest(value: LifecycleBuildIdentity): string {
|
|
72
|
-
return createHash('sha256').update(JSON.stringify(value), 'utf8').digest('hex');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
48
|
function coreOptions(options: CodexBridgeOptions): OrchestrationOptions {
|
|
76
49
|
return { ...options.orchestrationOptions, repoRoot: options.repoRoot ?? options.orchestrationOptions?.repoRoot };
|
|
77
50
|
}
|
|
78
51
|
|
|
79
|
-
function bridgeFailure(code: string, message: string
|
|
52
|
+
function bridgeFailure(code: string, message: string): OrchestrationResult {
|
|
80
53
|
return {
|
|
81
54
|
status: 'failed', changed: false, taskId: null, run: null, next: null,
|
|
82
|
-
error: { code, message
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function capabilityFailure(error: unknown): NonNullable<OrchestrationResult['error']> {
|
|
87
|
-
const detailValue = error instanceof Error
|
|
88
|
-
? (error as Error & { detail?: unknown }).detail
|
|
89
|
-
: undefined;
|
|
90
|
-
return {
|
|
91
|
-
code: error instanceof Error && error.name.startsWith('CODEX_CAPABILITY_')
|
|
92
|
-
? error.name
|
|
93
|
-
: 'ORCHESTRATION_CLIENT_PREFLIGHT_FAILED',
|
|
94
|
-
message: error instanceof Error ? error.message : String(error),
|
|
95
|
-
...(error instanceof Error
|
|
96
|
-
&& error.name === 'CODEX_CAPABILITY_PROVENANCE_MISMATCH'
|
|
97
|
-
&& isCodexCapabilityProvenanceDetail(detailValue)
|
|
98
|
-
? { detail: detailValue }
|
|
99
|
-
: {})
|
|
55
|
+
error: { code, message }
|
|
100
56
|
};
|
|
101
57
|
}
|
|
102
58
|
|
|
@@ -112,35 +68,12 @@ function requiredStore(options: CodexBridgeOptions): LifecycleStore {
|
|
|
112
68
|
return options.store;
|
|
113
69
|
}
|
|
114
70
|
|
|
115
|
-
function brokerControllerBinding(): Readonly<{ instanceDigest: string; controlGeneration: string }> | null {
|
|
116
|
-
const raw = process.env.AGENT_INFRA_CONTROL_CONTROLLER_BINDING;
|
|
117
|
-
if (!raw) return null;
|
|
118
|
-
let value: unknown;
|
|
119
|
-
try {
|
|
120
|
-
value = JSON.parse(raw);
|
|
121
|
-
} catch {
|
|
122
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_BINDING_INVALID');
|
|
123
|
-
}
|
|
124
|
-
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
125
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_BINDING_INVALID');
|
|
126
|
-
}
|
|
127
|
-
const binding = value as Record<string, unknown>;
|
|
128
|
-
if (Object.keys(binding).sort().join(',') !== 'controlGeneration,instanceDigest'
|
|
129
|
-
|| typeof binding.instanceDigest !== 'string' || !/^[a-f0-9]{64}$/u.test(binding.instanceDigest)
|
|
130
|
-
|| typeof binding.controlGeneration !== 'string' || binding.controlGeneration.length === 0) {
|
|
131
|
-
throw new Error('CODEX_SANDBOX_CONTROLLER_BINDING_INVALID');
|
|
132
|
-
}
|
|
133
|
-
return binding as { instanceDigest: string; controlGeneration: string };
|
|
134
|
-
}
|
|
135
|
-
|
|
136
71
|
async function prepareCodexOrchestrationDelegation(
|
|
137
72
|
taskRef: string,
|
|
138
73
|
input: Readonly<{
|
|
139
74
|
client: AgentClientId;
|
|
140
75
|
requestedModel?: string;
|
|
141
76
|
requestedReasoningEffort?: string;
|
|
142
|
-
capabilityRef?: string;
|
|
143
|
-
lifecycleRecoveryAttestation?: LifecycleRecoveryAttestationV1 | null;
|
|
144
77
|
}>,
|
|
145
78
|
options: CodexBridgeOptions = {}
|
|
146
79
|
): Promise<OrchestrationResult> {
|
|
@@ -149,164 +82,11 @@ async function prepareCodexOrchestrationDelegation(
|
|
|
149
82
|
const repoRoot = options.repoRoot ?? process.cwd();
|
|
150
83
|
const resolved = resolveTaskRef(taskRef, { repoRoot });
|
|
151
84
|
if (!resolved.ok) return bridgeFailure(resolved.code, resolved.message);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (!capabilityRef) {
|
|
155
|
-
return bridgeFailure(
|
|
156
|
-
'ORCHESTRATION_CODEX_CAPABILITY_REQUIRED',
|
|
157
|
-
'Codex prepare requires a current-session capability reference'
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
const buildIdentity = options.buildIdentity ?? computeLifecycleBuildIdentity(repoRoot);
|
|
161
|
-
const brokerController = options.controllerBinding ?? brokerControllerBinding();
|
|
162
|
-
const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
|
|
163
|
-
const contextVerification = contextPath
|
|
164
|
-
? (brokerController
|
|
165
|
-
? verifyControllerContextFileWithWarnings(contextPath, {
|
|
166
|
-
repoRoot,
|
|
167
|
-
generation: process.env.AGENT_INFRA_CONTROL_GENERATION ?? brokerController.controlGeneration
|
|
168
|
-
})
|
|
169
|
-
: verifySandboxControllerWithWarnings(contextPath, { repoRoot }))
|
|
170
|
-
: null;
|
|
171
|
-
const identityWarnings: LifecycleIdentityWarning[] = [...(contextVerification?.warnings ?? [])];
|
|
172
|
-
const localController = contextVerification?.context ?? null;
|
|
173
|
-
if (localController && brokerController
|
|
174
|
-
&& (localController.controllerInstanceDigest !== brokerController.instanceDigest
|
|
175
|
-
|| localController.controlGeneration !== brokerController.controlGeneration)) {
|
|
176
|
-
return bridgeFailure(
|
|
177
|
-
'CODEX_SANDBOX_CONTROLLER_BINDING_MISMATCH',
|
|
178
|
-
'broker and local controller bindings do not match'
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
const controller = brokerController ?? (localController ? {
|
|
182
|
-
instanceDigest: localController.controllerInstanceDigest,
|
|
183
|
-
controlGeneration: localController.controlGeneration
|
|
184
|
-
} : null);
|
|
185
|
-
const capabilityStore = options.capabilityStore ?? createCodexCapabilityStore();
|
|
186
|
-
const attested = capabilityStore.inspectReference(capabilityRef);
|
|
187
|
-
const capabilityIdentity = verifyLifecycleBuildIdentity(attested.buildIdentity, buildIdentity);
|
|
188
|
-
if (!capabilityIdentity.ok) {
|
|
189
|
-
return bridgeFailure(capabilityIdentity.code!, capabilityIdentity.message!);
|
|
190
|
-
}
|
|
191
|
-
identityWarnings.push(...capabilityIdentity.warnings);
|
|
192
|
-
const lifecycleProvenance = {
|
|
193
|
-
...attested.buildIdentity,
|
|
194
|
-
hookDefinitionHash: preflight.hookDefinitionHash,
|
|
195
|
-
...preflight.hookProvenance,
|
|
196
|
-
capabilitySessionId: attested.sessionId!,
|
|
197
|
-
capabilityTurnId: attested.turnId!,
|
|
198
|
-
capabilityToolUseId: attested.toolUseId!,
|
|
199
|
-
controllerInstanceDigest: controller?.instanceDigest ?? null,
|
|
200
|
-
controlGeneration: controller?.controlGeneration ?? null
|
|
201
|
-
};
|
|
202
|
-
const capabilityExpected = {
|
|
203
|
-
taskId: resolved.taskId,
|
|
204
|
-
hookDefinitionHash: preflight.hookDefinitionHash,
|
|
205
|
-
buildIdentity,
|
|
206
|
-
...(controller ? { controller: {
|
|
207
|
-
instanceDigest: controller.instanceDigest,
|
|
208
|
-
controlGeneration: controller.controlGeneration
|
|
209
|
-
} } : {})
|
|
210
|
-
};
|
|
211
|
-
if (input.lifecycleRecoveryAttestation) {
|
|
212
|
-
try { validateLifecycleRecoveryAttestation(input.lifecycleRecoveryAttestation); }
|
|
213
|
-
catch (error) {
|
|
214
|
-
return bridgeFailure(
|
|
215
|
-
'LIFECYCLE_AUTHORITY_ATTESTATION_INVALID',
|
|
216
|
-
error instanceof Error ? error.message : String(error)
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
let lifecycleRecoveryAttestation: LifecycleRecoveryAttestationV1 | null = input.lifecycleRecoveryAttestation ?? null;
|
|
221
|
-
const routed = input.capabilityRef && !lifecycleRecoveryAttestation
|
|
222
|
-
? routeOrchestration(taskRef, coreOptions(options))
|
|
223
|
-
: null;
|
|
224
|
-
if (routed && !routed.next) return routed;
|
|
225
|
-
if (routed?.next && ['analysis', 'plan', 'code'].includes(routed.next.stage)) {
|
|
226
|
-
const recoveryRequest = {
|
|
227
|
-
version: 1 as const,
|
|
228
|
-
requestId: randomUUID(),
|
|
229
|
-
operationId: randomUUID(),
|
|
230
|
-
phase: 'orchestration.prepare' as const,
|
|
231
|
-
taskId: resolved.taskId,
|
|
232
|
-
family: routed.next.stage === 'analysis' ? 'analysis' as const
|
|
233
|
-
: routed.next.stage === 'plan' ? 'plan' as const : 'code' as const,
|
|
234
|
-
artifact: routed.next.artifact,
|
|
235
|
-
round: routed.next.round,
|
|
236
|
-
lifecycleRequestId: randomUUID(),
|
|
237
|
-
authorityRef: capabilityRef,
|
|
238
|
-
expectedControlGeneration: controller?.controlGeneration ?? '',
|
|
239
|
-
expectedControllerInstanceDigest: controller?.instanceDigest ?? '0'.repeat(64),
|
|
240
|
-
expectedBuildIdentityDigest: buildIdentityDigest(buildIdentity),
|
|
241
|
-
expectedHookDefinitionHash: preflight.hookDefinitionHash
|
|
242
|
-
};
|
|
243
|
-
const authority = issueLifecycleRecoveryAttestation(recoveryRequest, {
|
|
244
|
-
capabilityStore,
|
|
245
|
-
...(controller ? { controllerBinding: controller } : {}),
|
|
246
|
-
buildIdentity
|
|
247
|
-
});
|
|
248
|
-
if (authority.status === 'rejected' || !authority.attestation) {
|
|
249
|
-
return bridgeFailure(
|
|
250
|
-
authority.error?.code ?? 'LIFECYCLE_AUTHORITY_REJECTED',
|
|
251
|
-
authority.error?.message ?? 'lifecycle authority was rejected'
|
|
252
|
-
);
|
|
253
|
-
}
|
|
254
|
-
lifecycleRecoveryAttestation = authority.attestation;
|
|
255
|
-
}
|
|
256
|
-
const prepared = prepareOrchestrationDelegation(taskRef, {
|
|
257
|
-
...input,
|
|
258
|
-
lifecycleProvenance,
|
|
259
|
-
lifecycleRecoveryAttestation
|
|
260
|
-
}, {
|
|
261
|
-
...coreOptions(options),
|
|
262
|
-
validateLifecycleCapability: () => {
|
|
263
|
-
try {
|
|
264
|
-
const validated = capabilityStore.validateReference(capabilityRef, capabilityExpected);
|
|
265
|
-
if (validated.sessionId !== attested.sessionId
|
|
266
|
-
|| validated.turnId !== attested.turnId
|
|
267
|
-
|| validated.toolUseId !== attested.toolUseId) {
|
|
268
|
-
return {
|
|
269
|
-
code: 'CODEX_CAPABILITY_IDENTITY_CHANGED',
|
|
270
|
-
message: 'capability identity changed during validation'
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
274
|
-
} catch (error) {
|
|
275
|
-
return capabilityFailure(error);
|
|
276
|
-
}
|
|
277
|
-
},
|
|
278
|
-
consumeLifecycleCapability: () => null
|
|
279
|
-
});
|
|
280
|
-
if (lifecycleRecoveryAttestation && !options.deferLifecycleRecoveryConsumption && prepared.status !== 'failed') {
|
|
281
|
-
try {
|
|
282
|
-
consumeLifecycleRecoveryAttestation(lifecycleRecoveryAttestation);
|
|
283
|
-
} catch (error) {
|
|
284
|
-
return bridgeFailure(
|
|
285
|
-
error instanceof Error ? error.name : 'LIFECYCLE_AUTHORITY_CONSUME_FAILED',
|
|
286
|
-
error instanceof Error ? error.message : String(error)
|
|
287
|
-
);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return identityWarnings.length > 0 && prepared.status !== 'failed'
|
|
291
|
-
? { ...prepared, warnings: Object.freeze(identityWarnings) }
|
|
292
|
-
: prepared;
|
|
85
|
+
await (options.preflight ?? preflightCodexLifecycleEvidence)(repoRoot);
|
|
86
|
+
return prepareOrchestrationDelegation(taskRef, input, coreOptions(options));
|
|
293
87
|
} catch (error) {
|
|
294
88
|
if (error instanceof OrchestrationStateError) return bridgeFailure(error.code, error.message);
|
|
295
|
-
|
|
296
|
-
? (error as Error & { detail?: unknown }).detail
|
|
297
|
-
: undefined;
|
|
298
|
-
const detail = error instanceof Error
|
|
299
|
-
&& error.name === 'CODEX_CAPABILITY_PROVENANCE_MISMATCH'
|
|
300
|
-
&& isCodexCapabilityProvenanceDetail(detailValue)
|
|
301
|
-
? detailValue
|
|
302
|
-
: undefined;
|
|
303
|
-
return bridgeFailure(
|
|
304
|
-
error instanceof Error && error.name.startsWith('CODEX_CAPABILITY_')
|
|
305
|
-
? error.name
|
|
306
|
-
: 'ORCHESTRATION_CLIENT_PREFLIGHT_FAILED',
|
|
307
|
-
error instanceof Error ? error.message : String(error),
|
|
308
|
-
detail
|
|
309
|
-
);
|
|
89
|
+
return bridgeFailure('ORCHESTRATION_CLIENT_PREFLIGHT_FAILED', error instanceof Error ? error.message : String(error));
|
|
310
90
|
}
|
|
311
91
|
}
|
|
312
92
|
|
|
@@ -335,16 +115,6 @@ async function activateCodexOrchestrationDelegation(
|
|
|
335
115
|
toolUseId: evidence.spawnToolUseId
|
|
336
116
|
});
|
|
337
117
|
const buildIdentity = options.buildIdentity ?? computeLifecycleBuildIdentity(repoRoot);
|
|
338
|
-
const contextPath = process.env.AGENT_INFRA_CODEX_CONTROLLER_CONTEXT;
|
|
339
|
-
const contextVerification = contextPath
|
|
340
|
-
? verifySandboxControllerWithWarnings(contextPath, { repoRoot })
|
|
341
|
-
: null;
|
|
342
|
-
const controller = options.controllerBinding
|
|
343
|
-
?? brokerControllerBinding()
|
|
344
|
-
?? (contextVerification?.context ? {
|
|
345
|
-
instanceDigest: contextVerification.context.controllerInstanceDigest,
|
|
346
|
-
controlGeneration: contextVerification.context.controlGeneration
|
|
347
|
-
} : null);
|
|
348
118
|
const activated = activateMatchingOrchestrationDelegation('codex', {
|
|
349
119
|
nativeAgent: evidence.nativeAgent,
|
|
350
120
|
childId: evidence.childThreadId,
|
|
@@ -366,14 +136,11 @@ async function activateCodexOrchestrationDelegation(
|
|
|
366
136
|
capabilityTurnId: evidence.parentTurnId,
|
|
367
137
|
spawnToolUseId: evidence.spawnToolUseId,
|
|
368
138
|
spawnObservedAt: record.spawnObservedAt ?? undefined,
|
|
369
|
-
controllerInstanceDigest:
|
|
370
|
-
controlGeneration:
|
|
139
|
+
controllerInstanceDigest: null,
|
|
140
|
+
controlGeneration: null
|
|
371
141
|
}
|
|
372
142
|
}, coreOptions(options));
|
|
373
|
-
|
|
374
|
-
return warnings.length > 0 && activated.status !== 'failed'
|
|
375
|
-
? { ...activated, warnings: Object.freeze(warnings) }
|
|
376
|
-
: activated;
|
|
143
|
+
return activated;
|
|
377
144
|
} catch (error) {
|
|
378
145
|
if (error instanceof OrchestrationStateError) return bridgeFailure(error.code, error.message);
|
|
379
146
|
return pauseBridge('ORCHESTRATION_CODEX_START_FAILED', error instanceof Error ? error.message : String(error), options);
|
|
@@ -32,8 +32,6 @@ type CommitOperationInput = Readonly<{
|
|
|
32
32
|
agent?: string;
|
|
33
33
|
mode?: CommitExecutionMode;
|
|
34
34
|
round?: number;
|
|
35
|
-
/** Permit one retry to rebase a prepared intent's expected tree while HEAD and intent identity remain unchanged. */
|
|
36
|
-
recoverPreparedIntent?: boolean;
|
|
37
35
|
delivery?: Readonly<{
|
|
38
36
|
mode: 'local' | 'push';
|
|
39
37
|
remote: string;
|
|
@@ -282,20 +280,6 @@ function checkpointTimestamp(): string {
|
|
|
282
280
|
return new Date().toISOString();
|
|
283
281
|
}
|
|
284
282
|
|
|
285
|
-
function samePreparedCheckpointIdentity(
|
|
286
|
-
pending: NonNullable<ReturnType<typeof readCheckpointIntent>>,
|
|
287
|
-
identity: Parameters<typeof checkpointIntentDigest>[0]
|
|
288
|
-
): boolean {
|
|
289
|
-
return pending.state === 'prepared'
|
|
290
|
-
&& pending.taskId === identity.taskId
|
|
291
|
-
&& pending.branch === identity.branch
|
|
292
|
-
&& pending.mode === identity.mode
|
|
293
|
-
&& pending.expectedHead === identity.expectedHead
|
|
294
|
-
&& pending.message === identity.message
|
|
295
|
-
&& pending.round === identity.round
|
|
296
|
-
&& JSON.stringify(pending.paths) === JSON.stringify(identity.paths);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
283
|
function executeUnlocked(input: CommitOperationInput, task: BoundTask | null, mode: CommitExecutionMode): CommitOperationResult {
|
|
300
284
|
const inspected = inspectGitWorkflow(input.cwd);
|
|
301
285
|
if (!inspected.snapshot) return failure(input, mode, task?.taskId ?? null, 'GIT_INSPECT_FAILED', 'Unable to inspect Git repository');
|
|
@@ -330,15 +314,11 @@ function executeUnlocked(input: CommitOperationInput, task: BoundTask | null, mo
|
|
|
330
314
|
};
|
|
331
315
|
}
|
|
332
316
|
if (pendingIntent && !sameCheckpointIntent(pendingIntent, identity)) {
|
|
333
|
-
|
|
334
|
-
status: 'failed' as const, changed: false, snapshot: inspected.snapshot, operations: [],
|
|
335
|
-
error: { code: 'COMMIT_INTENT_CONFLICT', message: 'A different checkpoint intent is still pending for this task' }
|
|
336
|
-
};
|
|
317
|
+
const timestamp = checkpointTimestamp();
|
|
337
318
|
pendingIntent = {
|
|
338
|
-
...
|
|
339
|
-
expectedTree: identity.expectedTree,
|
|
319
|
+
version: 1, ...identity,
|
|
340
320
|
digest: checkpointIntentDigest(identity),
|
|
341
|
-
updatedAt:
|
|
321
|
+
state: 'prepared', committedHead: null, createdAt: timestamp, updatedAt: timestamp
|
|
342
322
|
};
|
|
343
323
|
try { writeCheckpointIntent(task!.repoRoot, pendingIntent); }
|
|
344
324
|
catch (error) {
|
|
@@ -789,17 +789,11 @@ function orchestration(
|
|
|
789
789
|
client: input.client as AgentClientId,
|
|
790
790
|
requestedModel: input.requestedModel as string | undefined,
|
|
791
791
|
requestedReasoningEffort: input.requestedReasoningEffort as string | undefined,
|
|
792
|
-
...(input.capabilityRef === undefined ? {} : { capabilityRef: input.capabilityRef as string }),
|
|
793
|
-
...(context.lifecycleRecoveryAttestation === undefined
|
|
794
|
-
? {}
|
|
795
|
-
: { lifecycleRecoveryAttestation: context.lifecycleRecoveryAttestation })
|
|
796
792
|
};
|
|
797
793
|
if (prepareInput.client === 'codex') {
|
|
798
794
|
return prepareCodexOrchestrationDelegation(operation.taskRef, prepareInput, {
|
|
799
795
|
repoRoot: context.repoRoot,
|
|
800
796
|
orchestrationOptions: options,
|
|
801
|
-
deferLifecycleRecoveryConsumption: context.source === 'sandbox-executor',
|
|
802
|
-
...(context.controllerBinding ? { controllerBinding: context.controllerBinding } : {})
|
|
803
797
|
});
|
|
804
798
|
}
|
|
805
799
|
return prepareOrchestrationDelegation(operation.taskRef, prepareInput, options);
|
|
@@ -912,7 +906,7 @@ const FINALIZATION_FLAGS = new Set(['--agent']);
|
|
|
912
906
|
const ORCHESTRATION_FLAGS = new Set([
|
|
913
907
|
'--agent', '--max-steps', '--executor-model', '--executor-reasoning-effort', '--reviewer-model',
|
|
914
908
|
'--reviewer-reasoning-effort', '--client', '--requested-model', '--requested-reasoning-effort',
|
|
915
|
-
'--
|
|
909
|
+
'--parent-id', '--before-fingerprint', '--stage', '--round', '--artifact', '--role',
|
|
916
910
|
'--native-agent', '--child-id', '--spawn-mode', '--actual-model', '--actual-reasoning-effort',
|
|
917
911
|
'--model-fallback-reason', '--reasoning-effort-fallback-reason', '--exit-code', '--after-fingerprint',
|
|
918
912
|
'--changed-paths', '--code', '--message', '--recoverable', '--git-worktree-root'
|
|
@@ -1049,7 +1043,6 @@ export function parseTaskControlOperation(
|
|
|
1049
1043
|
if (parsedIntent === 'prepare') {
|
|
1050
1044
|
input.requestedModel = value(values, '--requested-model');
|
|
1051
1045
|
input.requestedReasoningEffort = value(values, '--requested-reasoning-effort');
|
|
1052
|
-
input.capabilityRef = value(values, '--capability-ref');
|
|
1053
1046
|
}
|
|
1054
1047
|
if (parsedIntent === 'await-activation') {
|
|
1055
1048
|
required(values, ['--stage', '--round', '--artifact', '--role']);
|