@fitlab-ai/agent-infra 0.9.10 → 0.9.11
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 +13 -3
- package/README.zh-CN.md +13 -3
- package/bin/cli.ts +17 -4
- package/dist/bin/cli.js +19 -4
- package/dist/bin/internal-cli.js +50 -4
- package/dist/lib/agent-client.js +0 -1
- package/dist/lib/agent-clients/adapters/opencode-sandbox.js +0 -4
- package/dist/lib/agent-clients/adapters/traecli.js +7 -8
- package/dist/lib/agent-clients/config.js +14 -99
- package/dist/lib/agent-clients/reconcile.js +1 -11
- package/dist/lib/agent-clients/schema.js +5 -4
- package/dist/lib/agent-clients/tokens.js +5 -15
- package/dist/lib/decide.js +14 -30
- package/dist/lib/defaults.json +4 -0
- package/dist/lib/init.js +2 -2
- package/dist/lib/internal/release-workflow.js +0 -1
- package/dist/lib/internal/task-finalization.js +19 -9
- package/dist/lib/internal/task-ledger.js +8 -2
- package/dist/lib/internal/task-lifecycle.js +17 -93
- package/dist/lib/internal/task-orchestration.js +30 -216
- package/dist/lib/internal/task-validate.js +2 -1
- package/dist/lib/merge.js +205 -103
- package/dist/lib/process-data/normalize.js +2 -9
- package/dist/lib/run/host.js +46 -16
- package/dist/lib/sandbox/agent-client-reconciler.js +4 -12
- package/dist/lib/sandbox/commands/create.js +3 -3
- package/dist/lib/sandbox/commands/enter.js +18 -4
- package/dist/lib/sandbox/config.js +3 -12
- package/dist/lib/sandbox/control/executor.js +131 -39
- package/dist/lib/sandbox/control/lifecycle.js +29 -20
- package/dist/lib/sandbox/control/server.js +18 -16
- package/dist/lib/sandbox/mounts.js +3 -2
- package/dist/lib/sandbox/recovery.js +123 -22
- package/dist/lib/sandbox/workspace-identity.js +14 -0
- package/dist/lib/sandbox/workspace-view.js +8 -9
- package/dist/lib/self-update.js +278 -0
- package/dist/lib/server/protocol.js +5 -5
- package/dist/lib/task/activity-log.js +4 -1
- package/dist/lib/task/artifact-lifecycle.js +4 -2
- package/dist/lib/task/codex-orchestration.js +1 -1
- package/dist/lib/task/command-options.js +1 -3
- package/dist/lib/task/commands/cat.js +0 -5
- package/dist/lib/task/commands/decisions.js +76 -92
- package/dist/lib/task/commands/files.js +6 -6
- package/dist/lib/task/commands/grep.js +25 -61
- package/dist/lib/task/commands/issue-body.js +6 -6
- package/dist/lib/task/commands/log.js +25 -10
- package/dist/lib/task/commands/show.js +5 -6
- package/dist/lib/task/commands/status.js +8 -8
- package/dist/lib/task/commit-operation.js +21 -25
- package/dist/lib/task/commit-policy.js +1 -1
- package/dist/lib/task/control-authority.js +431 -0
- package/dist/lib/task/create.js +6 -1
- package/dist/lib/task/current-contract.js +35 -0
- package/dist/lib/task/decision-details.js +263 -0
- package/dist/lib/task/decision-intents.js +5 -2
- package/dist/lib/task/events.js +11 -5
- package/dist/lib/task/index.js +19 -20
- package/dist/lib/task/ledger-intents.js +8 -9
- package/dist/lib/task/ledger.js +13 -6
- package/dist/lib/task/lifecycle.js +16 -0
- package/dist/lib/task/orchestration.js +50 -13
- package/dist/lib/task/review-artifacts.js +31 -12
- package/dist/lib/task/review-finalization.js +19 -6
- package/dist/lib/task/verification-engine.js +38 -15
- package/dist/lib/task/verification-review.js +1 -1
- package/dist/lib/task/workspace-snapshot.js +5 -11
- package/dist/lib/task/write.js +11 -1
- package/dist/lib/update.js +6 -37
- package/dist/lib/version.js +5 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +0 -1
- package/lib/agent-clients/adapters/opencode-sandbox.ts +0 -5
- package/lib/agent-clients/adapters/traecli.ts +7 -8
- package/lib/agent-clients/config.ts +14 -144
- package/lib/agent-clients/reconcile.ts +1 -12
- package/lib/agent-clients/schema.ts +5 -4
- package/lib/agent-clients/tokens.ts +5 -18
- package/lib/decide.ts +12 -22
- package/lib/defaults.json +4 -0
- package/lib/init.ts +2 -2
- package/lib/internal/release-workflow.ts +0 -1
- package/lib/internal/task-finalization.ts +27 -13
- package/lib/internal/task-ledger.ts +8 -2
- package/lib/internal/task-lifecycle.ts +33 -76
- package/lib/internal/task-orchestration.ts +33 -190
- package/lib/internal/task-validate.ts +3 -2
- package/lib/merge.ts +236 -120
- package/lib/process-data/normalize.ts +2 -8
- package/lib/run/host.ts +63 -14
- package/lib/sandbox/agent-client-reconciler.ts +5 -15
- package/lib/sandbox/commands/create.ts +4 -4
- package/lib/sandbox/commands/enter.ts +24 -4
- package/lib/sandbox/config.ts +2 -14
- package/lib/sandbox/control/container-identity.ts +2 -2
- package/lib/sandbox/control/executor.ts +148 -51
- package/lib/sandbox/control/lifecycle.ts +34 -28
- package/lib/sandbox/control/protocol.ts +1 -3
- package/lib/sandbox/control/server.ts +15 -12
- package/lib/sandbox/control/state.ts +7 -7
- package/lib/sandbox/mounts.ts +4 -3
- package/lib/sandbox/recovery.ts +162 -34
- package/lib/sandbox/tools.ts +1 -1
- package/lib/sandbox/workspace-identity.ts +28 -0
- package/lib/sandbox/workspace-view.ts +14 -10
- package/lib/self-update.ts +341 -0
- package/lib/server/protocol.ts +5 -5
- package/lib/task/activity-log.ts +6 -1
- package/lib/task/artifact-lifecycle.ts +5 -3
- package/lib/task/codex-orchestration.ts +2 -1
- package/lib/task/command-options.ts +1 -2
- package/lib/task/commands/cat.ts +0 -4
- package/lib/task/commands/decisions.ts +80 -75
- package/lib/task/commands/files.ts +6 -6
- package/lib/task/commands/grep.ts +23 -51
- package/lib/task/commands/issue-body.ts +6 -6
- package/lib/task/commands/log.ts +22 -10
- package/lib/task/commands/show.ts +5 -6
- package/lib/task/commands/status.ts +8 -8
- package/lib/task/commit-operation.ts +25 -30
- package/lib/task/commit-policy.ts +1 -2
- package/lib/task/control-authority.ts +563 -0
- package/lib/task/create.ts +6 -1
- package/lib/task/current-contract.ts +49 -0
- package/lib/task/decision-details.ts +340 -0
- package/lib/task/decision-intents.ts +7 -2
- package/lib/task/events.ts +10 -5
- package/lib/task/index.ts +19 -20
- package/lib/task/ledger-intents.ts +6 -8
- package/lib/task/ledger.ts +17 -7
- package/lib/task/lifecycle.ts +20 -0
- package/lib/task/orchestration.ts +40 -15
- package/lib/task/review-artifacts.ts +53 -15
- package/lib/task/review-finalization.ts +33 -7
- package/lib/task/verification-engine.ts +33 -18
- package/lib/task/verification-review.ts +1 -1
- package/lib/task/workspace-snapshot.ts +4 -13
- package/lib/task/write.ts +20 -1
- package/lib/update.ts +6 -40
- package/lib/version.ts +6 -1
- package/package.json +1 -1
- package/templates/.agents/README.en.md +5 -3
- package/templates/.agents/README.zh-CN.md +5 -3
- package/templates/.agents/rules/compatibility-policy.en.md +5 -4
- package/templates/.agents/rules/compatibility-policy.zh-CN.md +5 -4
- package/templates/.agents/rules/create-issue.github.en.md +1 -1
- package/templates/.agents/rules/create-issue.github.zh-CN.md +1 -1
- package/templates/.agents/rules/human-decision-context.en.md +9 -7
- package/templates/.agents/rules/human-decision-context.zh-CN.md +9 -7
- package/templates/.agents/rules/issue-fields.github.en.md +1 -1
- package/templates/.agents/rules/issue-fields.github.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-pr-commands.en.md +1 -1
- package/templates/.agents/rules/issue-pr-commands.github.en.md +1 -1
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/issue-sync.github.en.md +1 -1
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +2 -2
- package/templates/.agents/rules/milestone-inference.github.en.md +1 -1
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +1 -1
- package/templates/.agents/rules/next-step-output.en.md +3 -3
- package/templates/.agents/rules/next-step-output.zh-CN.md +3 -3
- package/templates/.agents/rules/no-mid-flow-questions.en.md +1 -1
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +1 -1
- package/templates/.agents/rules/pr-sync.en.md +1 -1
- package/templates/.agents/rules/pr-sync.github.en.md +1 -1
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +1 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
- package/templates/.agents/rules/release-commands.github.en.md +6 -0
- package/templates/.agents/rules/release-commands.github.zh-CN.md +6 -0
- package/templates/.agents/rules/review-handshake.en.md +1 -1
- package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
- package/templates/.agents/rules/task-management.en.md +1 -2
- package/templates/.agents/rules/task-management.zh-CN.md +1 -2
- 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/block-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/check-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/close-codescan/SKILL.en.md +1 -1
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +1 -1
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +1 -1
- 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/commit/SKILL.en.md +27 -7
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +5 -5
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +5 -5
- 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/create-pr/SKILL.en.md +5 -7
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +5 -7
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +9 -4
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +9 -4
- package/templates/.agents/skills/create-pr/scripts/change-report.mjs +203 -0
- package/templates/.agents/skills/create-release-note/SKILL.en.md +5 -6
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +5 -6
- package/templates/.agents/skills/create-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +1 -1
- 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/restore-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +5 -3
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -0
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -3
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -0
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/review-code/reference/migration-risks.en.md +2 -1
- package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +2 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +5 -3
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -0
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +4 -0
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +4 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +4 -0
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +4 -0
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +2 -2
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +140 -109
- package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -2
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +2 -2
- package/templates/.agents/templates/task.en.md +1 -1
- package/templates/.agents/templates/task.zh-CN.md +1 -1
- package/templates/.claude/commands/analyze-task.en.md +1 -1
- package/templates/.claude/commands/analyze-task.zh-CN.md +1 -1
- package/templates/.claude/commands/block-task.en.md +1 -1
- package/templates/.claude/commands/block-task.zh-CN.md +1 -1
- package/templates/.claude/commands/cancel-task.en.md +1 -1
- package/templates/.claude/commands/cancel-task.zh-CN.md +1 -1
- package/templates/.claude/commands/check-task.en.md +1 -1
- package/templates/.claude/commands/check-task.zh-CN.md +1 -1
- package/templates/.claude/commands/code-task.en.md +1 -1
- package/templates/.claude/commands/code-task.zh-CN.md +1 -1
- package/templates/.claude/commands/commit.en.md +1 -1
- package/templates/.claude/commands/commit.zh-CN.md +1 -1
- package/templates/.claude/commands/complete-manual-validation.en.md +1 -1
- package/templates/.claude/commands/complete-manual-validation.zh-CN.md +1 -1
- package/templates/.claude/commands/complete-task.en.md +1 -1
- package/templates/.claude/commands/complete-task.zh-CN.md +1 -1
- package/templates/.claude/commands/create-pr.en.md +1 -1
- package/templates/.claude/commands/create-pr.zh-CN.md +1 -1
- package/templates/.claude/commands/plan-task.en.md +1 -1
- package/templates/.claude/commands/plan-task.zh-CN.md +1 -1
- package/templates/.claude/commands/review-analysis.en.md +1 -1
- package/templates/.claude/commands/review-analysis.zh-CN.md +1 -1
- package/templates/.claude/commands/review-code.en.md +1 -1
- package/templates/.claude/commands/review-code.zh-CN.md +1 -1
- package/templates/.claude/commands/review-plan.en.md +1 -1
- package/templates/.claude/commands/review-plan.zh-CN.md +1 -1
- package/templates/.claude/commands/run-manual-validation.en.md +1 -1
- package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
- package/templates/.claude/commands/run-task.en.md +1 -1
- package/templates/.claude/commands/run-task.zh-CN.md +1 -1
- package/templates/.claude/commands/watch-pr.en.md +1 -1
- package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
- package/templates/{.trae/skills → .traecli/commands}/update-agent-infra.en.md +0 -1
- package/templates/{.trae/skills → .traecli/commands}/update-agent-infra.zh-CN.md +0 -1
- package/dist/lib/builtin-tuis.js +0 -40
- package/lib/builtin-tuis.ts +0 -56
|
@@ -82,12 +82,12 @@ function boundTask(input, taskId, taskDir, taskMdPath, repoRoot, state) {
|
|
|
82
82
|
function validateCommon(input, branch) {
|
|
83
83
|
if (!input.message.trim())
|
|
84
84
|
return { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Commit message is required' };
|
|
85
|
-
if (input.paths.length === 0 && !input.push)
|
|
86
|
-
return { code: 'GIT_COMMIT_INPUT_INVALID', message: 'At least one explicit path is required unless this is a push-only retry' };
|
|
87
85
|
if (!/^[a-f0-9]{40,64}$/.test(input.expectedHead))
|
|
88
86
|
return { code: 'GIT_HEAD_EXPECTATION_REQUIRED', message: 'A valid expected HEAD is required' };
|
|
89
87
|
if (!/^[a-f0-9]{40,64}$/.test(input.expectedTree))
|
|
90
88
|
return { code: 'GIT_TREE_EXPECTATION_REQUIRED', message: 'A valid expected tree is required' };
|
|
89
|
+
if (!input.push)
|
|
90
|
+
return { code: 'GIT_PUSH_INPUT_INVALID', message: 'Commit delivery requires a push policy' };
|
|
91
91
|
if (input.paths.some((candidate) => !candidate || candidate.startsWith('/') || candidate.split(/[\\/]/).includes('..'))) {
|
|
92
92
|
return { code: 'GIT_COMMIT_INPUT_INVALID', message: 'Commit paths must stay inside the repository' };
|
|
93
93
|
}
|
|
@@ -96,13 +96,11 @@ function validateCommon(input, branch) {
|
|
|
96
96
|
}
|
|
97
97
|
if (branch !== null && branch === '')
|
|
98
98
|
return { code: 'GIT_BRANCH_INVALID', message: 'A named branch is required' };
|
|
99
|
-
if (input.push)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return { code: 'GIT_PUSH_INPUT_INVALID', message: 'Push ref must be the current full heads ref' };
|
|
105
|
-
}
|
|
99
|
+
if (!input.push.remote || input.push.refs.length !== 1)
|
|
100
|
+
return { code: 'GIT_PUSH_INPUT_INVALID', message: 'Push requires one remote and one ref' };
|
|
101
|
+
const ref = input.push.refs[0] ?? '';
|
|
102
|
+
if (!HEAD_REF.test(ref) || HEAD_REF.exec(ref)?.[1] !== branch) {
|
|
103
|
+
return { code: 'GIT_PUSH_INPUT_INVALID', message: 'Push ref must be the current full heads ref' };
|
|
106
104
|
}
|
|
107
105
|
return null;
|
|
108
106
|
}
|
|
@@ -253,22 +251,20 @@ function executeUnlocked(input, task, mode) {
|
|
|
253
251
|
}
|
|
254
252
|
let status = committed.status;
|
|
255
253
|
let result = committed.status === 'applied' ? 'committed' : 'no_op';
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
warnings.push(warning('COMMIT_PUSH_FAILED', pushed.error?.message ?? 'Git push failed', true, 'push', target, 'ACTION_REQUIRED'));
|
|
271
|
-
}
|
|
254
|
+
const target = `${input.push.remote}:${input.push.refs[0]}`;
|
|
255
|
+
const decision = commitPushDecision({ branch }, target);
|
|
256
|
+
if (!decision.shouldPush) {
|
|
257
|
+
warnings.push(decision.warning);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
const pushed = pushGitRefs({
|
|
261
|
+
cwd: input.cwd,
|
|
262
|
+
remote: input.push.remote,
|
|
263
|
+
refs: input.push.refs,
|
|
264
|
+
expectedSha: committed.snapshot?.head ?? gitText(input.cwd, ['rev-parse', 'HEAD'])
|
|
265
|
+
});
|
|
266
|
+
if (pushed.status !== 'applied')
|
|
267
|
+
warnings.push(warning('COMMIT_PUSH_FAILED', pushed.error?.message ?? 'Git push failed', true, 'push', target, 'ACTION_REQUIRED'));
|
|
272
268
|
}
|
|
273
269
|
if (warnings.length > 0) {
|
|
274
270
|
status = 'applied';
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { normalizeAgentToken } from '../agent-clients/tokens.js';
|
|
3
|
+
import { isAgentClientId } from '../agent-clients/types.js';
|
|
4
|
+
import { consumeHumanOverride, failureId, overrideDryRunConflict } from './human-override.js';
|
|
5
|
+
import { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, awaitOrchestrationDelegationActivation, beginOrResumeOrchestration, dispatchOrchestrationDelegation, OrchestrationStateError, pauseOrchestration, prepareOrchestrationDelegation, recoverPreparedOrchestrationDelegation, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration } from './orchestration.js';
|
|
6
|
+
import { prepareCodexOrchestrationDelegation } from './codex-orchestration.js';
|
|
7
|
+
import { applyTaskFinalization } from './finalization.js';
|
|
8
|
+
import { applyTaskLifecycle, taskLifecycleFailure } from './lifecycle.js';
|
|
9
|
+
import { resolveTaskRef, TASK_ID_RE } from './resolve-ref.js';
|
|
10
|
+
import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
|
|
11
|
+
import { verifyTaskEvent } from './verification.js';
|
|
12
|
+
function invalidContext(message) {
|
|
13
|
+
throw new Error(`TASK_CONTROL_CONTEXT_INVALID: ${message}`);
|
|
14
|
+
}
|
|
15
|
+
function absolute(name, value) {
|
|
16
|
+
if (!value || !path.isAbsolute(value))
|
|
17
|
+
invalidContext(`${name} must be absolute`);
|
|
18
|
+
return path.resolve(value);
|
|
19
|
+
}
|
|
20
|
+
function binding(value) {
|
|
21
|
+
if (value === null || value === undefined)
|
|
22
|
+
return value;
|
|
23
|
+
if (!/^[a-f0-9]{64}$/u.test(value.instanceDigest) || !value.controlGeneration) {
|
|
24
|
+
invalidContext('controller binding is invalid');
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
export function createDirectHostExecutionContext(params) {
|
|
29
|
+
return {
|
|
30
|
+
source: 'direct-host',
|
|
31
|
+
mode: 'direct-host',
|
|
32
|
+
repoRoot: absolute('repoRoot', params.repoRoot),
|
|
33
|
+
...(params.runtimeDir === undefined ? {} : { runtimeDir: absolute('runtimeDir', params.runtimeDir) }),
|
|
34
|
+
...(params.controllerBinding === undefined ? {} : { controllerBinding: binding(params.controllerBinding) })
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function createSandboxExecutorExecutionContext(params) {
|
|
38
|
+
if (!/^TASK-\d{8}-\d{6}$/u.test(params.taskId) || !params.generation || !params.requestId) {
|
|
39
|
+
invalidContext('sandbox binding is incomplete');
|
|
40
|
+
}
|
|
41
|
+
const controlRoot = path.dirname(path.resolve(params.manifestPath));
|
|
42
|
+
if (path.resolve(params.runtimeDir) !== path.join(controlRoot, 'runtime')) {
|
|
43
|
+
invalidContext('runtimeDir is not bound to the manifest control root');
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
source: 'sandbox-executor',
|
|
47
|
+
mode: 'task-bound-sandbox',
|
|
48
|
+
repoRoot: absolute('repoRoot', params.repoRoot),
|
|
49
|
+
worktreeRoot: absolute('worktreeRoot', params.worktreeRoot),
|
|
50
|
+
runtimeDir: absolute('runtimeDir', params.runtimeDir),
|
|
51
|
+
taskId: params.taskId,
|
|
52
|
+
generation: params.generation,
|
|
53
|
+
manifestPath: absolute('manifestPath', params.manifestPath),
|
|
54
|
+
requestId: params.requestId,
|
|
55
|
+
...(params.controllerBinding === undefined ? {} : { controllerBinding: binding(params.controllerBinding) })
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function assertTaskControlExecutionContext(context) {
|
|
59
|
+
if (context.source === 'direct-host') {
|
|
60
|
+
if (context.mode !== 'direct-host')
|
|
61
|
+
invalidContext('direct-host mode is inconsistent');
|
|
62
|
+
absolute('repoRoot', context.repoRoot);
|
|
63
|
+
if (context.runtimeDir !== undefined)
|
|
64
|
+
absolute('runtimeDir', context.runtimeDir);
|
|
65
|
+
binding(context.controllerBinding);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (context.mode !== 'task-bound-sandbox' || !/^TASK-\d{8}-\d{6}$/u.test(context.taskId)
|
|
69
|
+
|| !context.generation || !context.requestId) {
|
|
70
|
+
invalidContext('sandbox executor context is incomplete');
|
|
71
|
+
}
|
|
72
|
+
absolute('repoRoot', context.repoRoot);
|
|
73
|
+
absolute('worktreeRoot', context.worktreeRoot);
|
|
74
|
+
absolute('runtimeDir', context.runtimeDir);
|
|
75
|
+
absolute('manifestPath', context.manifestPath);
|
|
76
|
+
if (path.resolve(context.runtimeDir) !== path.join(path.dirname(path.resolve(context.manifestPath)), 'runtime')) {
|
|
77
|
+
invalidContext('runtimeDir is not bound to the manifest control root');
|
|
78
|
+
}
|
|
79
|
+
binding(context.controllerBinding);
|
|
80
|
+
}
|
|
81
|
+
function operationTaskId(context, taskRef) {
|
|
82
|
+
if (context.source === 'sandbox-executor' && taskRef !== context.taskId) {
|
|
83
|
+
throw new Error('TASK_CONTROL_CONTEXT_TASK_MISMATCH: operation task does not match the sandbox manifest');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function domainOptions(context, options) {
|
|
87
|
+
return {
|
|
88
|
+
...options,
|
|
89
|
+
repoRoot: context.repoRoot,
|
|
90
|
+
...(context.source === 'sandbox-executor' ? { gitWorktreeRoot: context.worktreeRoot } : {})
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function lifecycleTaskId(request, repoRoot) {
|
|
94
|
+
if (request.intent === 'restore')
|
|
95
|
+
return TASK_ID_RE.test(request.taskRef) ? request.taskRef : null;
|
|
96
|
+
try {
|
|
97
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot });
|
|
98
|
+
return resolved.ok ? resolved.taskId : null;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function applyLifecycleWithAuthority(context, request) {
|
|
105
|
+
const conflict = overrideDryRunConflict(request);
|
|
106
|
+
if (conflict) {
|
|
107
|
+
return taskLifecycleFailure(request, { code: 'LIFECYCLE_PAYLOAD_INVALID', message: conflict.message });
|
|
108
|
+
}
|
|
109
|
+
const execute = () => {
|
|
110
|
+
const lifecycleResult = applyTaskLifecycle(request, { repoRoot: context.repoRoot });
|
|
111
|
+
if (lifecycleResult.status !== 'failed' || !request.overrideTicket)
|
|
112
|
+
return lifecycleResult;
|
|
113
|
+
if (!request.overrideTarget || !request.overrideScope) {
|
|
114
|
+
return {
|
|
115
|
+
...lifecycleResult,
|
|
116
|
+
error: { code: 'OVERRIDE_PAYLOAD_INVALID', message: 'override ticket requires --override-target and --override-scope' }
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const override = consumeHumanOverride({
|
|
120
|
+
taskRef: request.taskRef,
|
|
121
|
+
ticketId: request.overrideTicket,
|
|
122
|
+
failureId: failureId('lifecycle.apply', lifecycleResult.error?.code ?? 'LIFECYCLE_FAILED'),
|
|
123
|
+
target: request.overrideTarget,
|
|
124
|
+
scope: request.overrideScope,
|
|
125
|
+
intent: request.intent,
|
|
126
|
+
...('alertNumber' in request && request.alertNumber ? { alertNumber: request.alertNumber } : {}),
|
|
127
|
+
...('issueNumber' in request && request.issueNumber ? { issueNumber: request.issueNumber } : {}),
|
|
128
|
+
...('stagingDir' in request && request.stagingDir ? { stagingDir: request.stagingDir } : {})
|
|
129
|
+
}, { repoRoot: context.repoRoot });
|
|
130
|
+
if (override.status === 'failed')
|
|
131
|
+
return { ...lifecycleResult, humanOverride: override };
|
|
132
|
+
return { ...lifecycleResult, ...override, humanOverride: override, error: null };
|
|
133
|
+
};
|
|
134
|
+
const taskId = lifecycleTaskId(request, context.repoRoot);
|
|
135
|
+
if (!taskId)
|
|
136
|
+
return execute();
|
|
137
|
+
try {
|
|
138
|
+
return withTaskExecutionLock(context.repoRoot, taskId, `task-lifecycle.${request.intent}`, execute);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (!(error instanceof TaskExecutionLockError))
|
|
142
|
+
throw error;
|
|
143
|
+
return taskLifecycleFailure(request, { code: error.code, message: error.message }, taskId);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function orchestration(context, operation) {
|
|
147
|
+
operationTaskId(context, operation.taskRef);
|
|
148
|
+
const input = operation.input;
|
|
149
|
+
const options = domainOptions(context, operation.options);
|
|
150
|
+
switch (operation.intent) {
|
|
151
|
+
case 'begin-or-resume':
|
|
152
|
+
return beginOrResumeOrchestration(operation.taskRef, {
|
|
153
|
+
...options,
|
|
154
|
+
client: input.client,
|
|
155
|
+
maxSteps: input.maxSteps,
|
|
156
|
+
modelPolicy: input.modelPolicy
|
|
157
|
+
});
|
|
158
|
+
case 'route': return routeOrchestration(operation.taskRef, options);
|
|
159
|
+
case 'status': return statusOrchestration(operation.taskRef, options);
|
|
160
|
+
case 'prepare': {
|
|
161
|
+
const prepareInput = {
|
|
162
|
+
client: input.client,
|
|
163
|
+
requestedModel: input.requestedModel,
|
|
164
|
+
requestedReasoningEffort: input.requestedReasoningEffort,
|
|
165
|
+
...(input.capabilityToken === undefined ? {} : { capabilityToken: input.capabilityToken })
|
|
166
|
+
};
|
|
167
|
+
if (prepareInput.client === 'codex') {
|
|
168
|
+
return prepareCodexOrchestrationDelegation(operation.taskRef, prepareInput, {
|
|
169
|
+
repoRoot: context.repoRoot,
|
|
170
|
+
orchestrationOptions: options,
|
|
171
|
+
...(context.controllerBinding ? { controllerBinding: context.controllerBinding } : {})
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return prepareOrchestrationDelegation(operation.taskRef, prepareInput, options);
|
|
175
|
+
}
|
|
176
|
+
case 'dispatch': return dispatchOrchestrationDelegation(operation.taskRef, options);
|
|
177
|
+
case 'await-activation':
|
|
178
|
+
return awaitOrchestrationDelegationActivation(operation.taskRef, input.event, options);
|
|
179
|
+
case 'recover-prepared': return recoverPreparedOrchestrationDelegation(operation.taskRef, options);
|
|
180
|
+
case 'hook-start':
|
|
181
|
+
return input.auto === true
|
|
182
|
+
? activateMatchingOrchestrationDelegation(input.client, input.event, options)
|
|
183
|
+
: activateOrchestrationDelegation(operation.taskRef, input.event, options);
|
|
184
|
+
case 'hook-stop':
|
|
185
|
+
return input.auto === true
|
|
186
|
+
? sealMatchingOrchestrationDelegation(input.client, input.event, options)
|
|
187
|
+
: sealOrchestrationDelegation(operation.taskRef, input.event, options);
|
|
188
|
+
case 'advance': return advanceOrchestration(operation.taskRef, options);
|
|
189
|
+
case 'pause':
|
|
190
|
+
return pauseOrchestration(operation.taskRef, input.code, input.message, input.recoverable, options);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function orchestrationFailure(error) {
|
|
194
|
+
if (error instanceof OrchestrationStateError) {
|
|
195
|
+
return {
|
|
196
|
+
status: 'failed', changed: false, taskId: error.taskId, run: null, next: null,
|
|
197
|
+
error: { code: error.code, message: error.message }
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
throw error;
|
|
201
|
+
}
|
|
202
|
+
export function dispatchTaskControlOperation(context, operation) {
|
|
203
|
+
assertTaskControlExecutionContext(context);
|
|
204
|
+
assertTaskControlOperation(operation);
|
|
205
|
+
if (operation.family === 'task-lifecycle') {
|
|
206
|
+
operationTaskId(context, operation.request.taskRef);
|
|
207
|
+
return applyLifecycleWithAuthority(context, operation.request);
|
|
208
|
+
}
|
|
209
|
+
if (operation.family === 'task-finalization') {
|
|
210
|
+
operationTaskId(context, operation.request.taskRef);
|
|
211
|
+
return applyTaskFinalization(operation.request, {
|
|
212
|
+
repoRoot: context.repoRoot,
|
|
213
|
+
preflight: (request, options) => verifyTaskEvent({ ...request, event: 'complete-task.hard-preflight' }, options)
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const result = orchestration(context, operation);
|
|
218
|
+
return result instanceof Promise ? result.catch(orchestrationFailure) : result;
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
return orchestrationFailure(error);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
export function assertTaskControlOperation(operation) {
|
|
225
|
+
if (operation.family === 'task-lifecycle') {
|
|
226
|
+
if (!operation.request.taskRef || !normalizeAgentToken(operation.request.agent)) {
|
|
227
|
+
throw new Error('TASK_CONTROL_OPERATION_INVALID: lifecycle request is invalid');
|
|
228
|
+
}
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (operation.family === 'task-finalization') {
|
|
232
|
+
if (!operation.request.taskRef || !normalizeAgentToken(operation.request.agent)) {
|
|
233
|
+
throw new Error('TASK_CONTROL_OPERATION_INVALID: finalization request is invalid');
|
|
234
|
+
}
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (!operation.taskRef || !operation.intent || !operation.input || typeof operation.input !== 'object' || Array.isArray(operation.input)) {
|
|
238
|
+
throw new Error('TASK_CONTROL_OPERATION_INVALID: orchestration operation is invalid');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function operationInvalid(message) {
|
|
242
|
+
throw new Error(`TASK_CONTROL_OPERATION_INVALID: ${message}`);
|
|
243
|
+
}
|
|
244
|
+
const LIFECYCLE_FLAGS = new Set([
|
|
245
|
+
'--agent', '--reason', '--unblock-condition', '--note', '--alert-number', '--staging-dir', '--issue-number',
|
|
246
|
+
'--override-ticket', '--override-target', '--override-scope', '--dry-run'
|
|
247
|
+
]);
|
|
248
|
+
const FINALIZATION_FLAGS = new Set(['--agent']);
|
|
249
|
+
const ORCHESTRATION_FLAGS = new Set([
|
|
250
|
+
'--agent', '--max-steps', '--executor-model', '--executor-reasoning-effort', '--reviewer-model',
|
|
251
|
+
'--reviewer-reasoning-effort', '--client', '--requested-model', '--requested-reasoning-effort',
|
|
252
|
+
'--capability-token', '--parent-id', '--before-fingerprint', '--stage', '--round', '--artifact', '--role',
|
|
253
|
+
'--native-agent', '--child-id', '--spawn-mode', '--actual-model', '--actual-reasoning-effort',
|
|
254
|
+
'--model-fallback-reason', '--reasoning-effort-fallback-reason', '--exit-code', '--after-fingerprint',
|
|
255
|
+
'--changed-paths', '--code', '--message', '--recoverable', '--git-worktree-root'
|
|
256
|
+
]);
|
|
257
|
+
function parseValues(args, start, flags) {
|
|
258
|
+
const values = {};
|
|
259
|
+
for (let index = start; index < args.length; index += 1) {
|
|
260
|
+
const flag = args[index];
|
|
261
|
+
if (flag === '--dry-run') {
|
|
262
|
+
if (!flags.has(flag))
|
|
263
|
+
operationInvalid(`unknown option '${flag}'`);
|
|
264
|
+
if (values[flag] !== undefined)
|
|
265
|
+
operationInvalid(`duplicate option '${flag}'`);
|
|
266
|
+
values[flag] = true;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (!flags.has(flag))
|
|
270
|
+
operationInvalid(`unknown option '${flag}'`);
|
|
271
|
+
if (values[flag] !== undefined)
|
|
272
|
+
operationInvalid(`duplicate option '${flag}'`);
|
|
273
|
+
const value = args[++index];
|
|
274
|
+
if (!value || value.startsWith('--'))
|
|
275
|
+
operationInvalid(`option '${flag}' requires a value`);
|
|
276
|
+
values[flag] = value;
|
|
277
|
+
}
|
|
278
|
+
return values;
|
|
279
|
+
}
|
|
280
|
+
function value(values, flag) {
|
|
281
|
+
const current = values[flag];
|
|
282
|
+
return typeof current === 'string' ? current : undefined;
|
|
283
|
+
}
|
|
284
|
+
function required(values, flags) {
|
|
285
|
+
const missing = flags.find((flag) => value(values, flag) === undefined);
|
|
286
|
+
if (missing)
|
|
287
|
+
operationInvalid(`option '${missing}' is required`);
|
|
288
|
+
}
|
|
289
|
+
export function parseTaskControlOperation(family, args) {
|
|
290
|
+
if (family === 'task-finalization') {
|
|
291
|
+
if (args.length !== 4 || args[1] !== 'complete' || args[2] !== '--agent' || !args[0] || !args[3]) {
|
|
292
|
+
operationInvalid('task ref, complete intent, and --agent are required');
|
|
293
|
+
}
|
|
294
|
+
const values = parseValues(args, 2, FINALIZATION_FLAGS);
|
|
295
|
+
const agent = normalizeAgentToken(value(values, '--agent') ?? '');
|
|
296
|
+
if (!agent)
|
|
297
|
+
operationInvalid('finalization agent is invalid');
|
|
298
|
+
return { family, request: { taskRef: args[0], intent: 'complete', agent } };
|
|
299
|
+
}
|
|
300
|
+
if (args.length < 2)
|
|
301
|
+
operationInvalid('task ref and intent are required');
|
|
302
|
+
const taskRef = args[0];
|
|
303
|
+
const intent = args[1];
|
|
304
|
+
if (family === 'task-lifecycle') {
|
|
305
|
+
const values = parseValues(args, 2, LIFECYCLE_FLAGS);
|
|
306
|
+
const agent = normalizeAgentToken(value(values, '--agent') ?? '');
|
|
307
|
+
if (!agent)
|
|
308
|
+
operationInvalid('lifecycle agent is invalid');
|
|
309
|
+
const input = {
|
|
310
|
+
taskRef,
|
|
311
|
+
intent,
|
|
312
|
+
agent,
|
|
313
|
+
...(value(values, '--reason') ? { reason: value(values, '--reason') } : {}),
|
|
314
|
+
...(value(values, '--unblock-condition') ? { unblockCondition: value(values, '--unblock-condition') } : {}),
|
|
315
|
+
...(value(values, '--note') ? { note: value(values, '--note') } : {}),
|
|
316
|
+
...(value(values, '--staging-dir') ? { stagingDir: value(values, '--staging-dir') } : {}),
|
|
317
|
+
...(value(values, '--override-ticket') ? { overrideTicket: value(values, '--override-ticket') } : {}),
|
|
318
|
+
...(value(values, '--override-target') ? { overrideTarget: value(values, '--override-target') } : {}),
|
|
319
|
+
...(value(values, '--override-scope') ? { overrideScope: value(values, '--override-scope') } : {}),
|
|
320
|
+
...(value(values, '--alert-number') ? { alertNumber: Number(value(values, '--alert-number')) } : {}),
|
|
321
|
+
...(value(values, '--issue-number') ? { issueNumber: Number(value(values, '--issue-number')) } : {}),
|
|
322
|
+
...(values['--dry-run'] === true ? { dryRun: true } : {})
|
|
323
|
+
};
|
|
324
|
+
return { family, request: input };
|
|
325
|
+
}
|
|
326
|
+
const values = parseValues(args, 2, ORCHESTRATION_FLAGS);
|
|
327
|
+
const orchestrationIntents = new Set([
|
|
328
|
+
'begin-or-resume', 'route', 'prepare', 'dispatch', 'await-activation', 'recover-prepared',
|
|
329
|
+
'hook-start', 'hook-stop', 'advance', 'pause', 'status'
|
|
330
|
+
]);
|
|
331
|
+
if (!orchestrationIntents.has(intent)) {
|
|
332
|
+
operationInvalid(`unknown orchestration intent '${intent}'`);
|
|
333
|
+
}
|
|
334
|
+
const client = value(values, '--client');
|
|
335
|
+
if (client !== undefined && !isAgentClientId(client))
|
|
336
|
+
operationInvalid(`unknown client '${client}'`);
|
|
337
|
+
const parsedIntent = intent;
|
|
338
|
+
const input = {};
|
|
339
|
+
if (parsedIntent === 'begin-or-resume' || parsedIntent === 'prepare') {
|
|
340
|
+
required(values, ['--client']);
|
|
341
|
+
if (!client || !isAgentClientId(client))
|
|
342
|
+
operationInvalid(`unknown client '${client ?? ''}'`);
|
|
343
|
+
input.client = client;
|
|
344
|
+
}
|
|
345
|
+
if (parsedIntent === 'begin-or-resume') {
|
|
346
|
+
const maxSteps = value(values, '--max-steps');
|
|
347
|
+
if (maxSteps !== undefined) {
|
|
348
|
+
const parsed = Number(maxSteps);
|
|
349
|
+
if (!Number.isInteger(parsed) || parsed < 1)
|
|
350
|
+
operationInvalid('--max-steps must be a positive integer');
|
|
351
|
+
input.maxSteps = parsed;
|
|
352
|
+
}
|
|
353
|
+
const policyFlags = ['--executor-model', '--executor-reasoning-effort', '--reviewer-model', '--reviewer-reasoning-effort'];
|
|
354
|
+
const hasPolicy = policyFlags.some((flag) => value(values, flag) !== undefined);
|
|
355
|
+
if (hasPolicy && policyFlags.some((flag) => value(values, flag) === undefined)) {
|
|
356
|
+
operationInvalid('explicit model policy requires executor/reviewer model and reasoning effort');
|
|
357
|
+
}
|
|
358
|
+
if (hasPolicy) {
|
|
359
|
+
input.modelPolicy = {
|
|
360
|
+
executor: { model: value(values, '--executor-model'), reasoningEffort: value(values, '--executor-reasoning-effort') },
|
|
361
|
+
reviewer: { model: value(values, '--reviewer-model'), reasoningEffort: value(values, '--reviewer-reasoning-effort') }
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (parsedIntent === 'prepare') {
|
|
366
|
+
input.requestedModel = value(values, '--requested-model');
|
|
367
|
+
input.requestedReasoningEffort = value(values, '--requested-reasoning-effort');
|
|
368
|
+
input.capabilityToken = value(values, '--capability-token');
|
|
369
|
+
}
|
|
370
|
+
if (parsedIntent === 'await-activation') {
|
|
371
|
+
required(values, ['--stage', '--round', '--artifact', '--role']);
|
|
372
|
+
const round = Number(value(values, '--round'));
|
|
373
|
+
if (!Number.isSafeInteger(round) || round < 1)
|
|
374
|
+
operationInvalid('--round must be a positive integer');
|
|
375
|
+
const role = value(values, '--role');
|
|
376
|
+
if (role !== 'executor' && role !== 'reviewer')
|
|
377
|
+
operationInvalid('--role must be executor or reviewer');
|
|
378
|
+
input.event = { stage: value(values, '--stage'), round, artifact: value(values, '--artifact'), role };
|
|
379
|
+
}
|
|
380
|
+
if (parsedIntent === 'hook-start') {
|
|
381
|
+
required(values, ['--native-agent', '--child-id', '--parent-id']);
|
|
382
|
+
if (taskRef === 'auto')
|
|
383
|
+
required(values, ['--client']);
|
|
384
|
+
input.auto = taskRef === 'auto';
|
|
385
|
+
input.client = value(values, '--client');
|
|
386
|
+
input.event = {
|
|
387
|
+
nativeAgent: value(values, '--native-agent'), childId: value(values, '--child-id'), parentId: value(values, '--parent-id'),
|
|
388
|
+
spawnMode: value(values, '--spawn-mode'), actualModel: value(values, '--actual-model'),
|
|
389
|
+
actualReasoningEffort: value(values, '--actual-reasoning-effort'), modelFallbackReason: value(values, '--model-fallback-reason'),
|
|
390
|
+
reasoningEffortFallbackReason: value(values, '--reasoning-effort-fallback-reason')
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
if (parsedIntent === 'hook-stop') {
|
|
394
|
+
input.auto = taskRef === 'auto';
|
|
395
|
+
if (input.auto) {
|
|
396
|
+
required(values, ['--client', '--native-agent', '--child-id']);
|
|
397
|
+
input.client = value(values, '--client');
|
|
398
|
+
input.event = {
|
|
399
|
+
nativeAgent: value(values, '--native-agent'), childId: value(values, '--child-id'), actualModel: value(values, '--actual-model'),
|
|
400
|
+
actualReasoningEffort: value(values, '--actual-reasoning-effort'), modelFallbackReason: value(values, '--model-fallback-reason'),
|
|
401
|
+
reasoningEffortFallbackReason: value(values, '--reasoning-effort-fallback-reason')
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
required(values, ['--child-id', '--exit-code', '--after-fingerprint']);
|
|
406
|
+
const exitCode = Number(value(values, '--exit-code'));
|
|
407
|
+
if (!Number.isInteger(exitCode))
|
|
408
|
+
operationInvalid('--exit-code must be an integer');
|
|
409
|
+
input.event = {
|
|
410
|
+
childId: value(values, '--child-id'), exitCode, afterFingerprint: value(values, '--after-fingerprint'),
|
|
411
|
+
changedPaths: value(values, '--changed-paths')?.split(',').filter(Boolean) ?? [], actualModel: value(values, '--actual-model'),
|
|
412
|
+
actualReasoningEffort: value(values, '--actual-reasoning-effort'), modelFallbackReason: value(values, '--model-fallback-reason'),
|
|
413
|
+
reasoningEffortFallbackReason: value(values, '--reasoning-effort-fallback-reason')
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (parsedIntent === 'pause') {
|
|
418
|
+
required(values, ['--code', '--message', '--recoverable']);
|
|
419
|
+
const recoverable = value(values, '--recoverable');
|
|
420
|
+
if (recoverable !== 'true' && recoverable !== 'false')
|
|
421
|
+
operationInvalid('--recoverable must be true or false');
|
|
422
|
+
input.code = value(values, '--code');
|
|
423
|
+
input.message = value(values, '--message');
|
|
424
|
+
input.recoverable = recoverable === 'true';
|
|
425
|
+
}
|
|
426
|
+
const options = value(values, '--git-worktree-root') === undefined
|
|
427
|
+
? undefined
|
|
428
|
+
: { gitWorktreeRoot: value(values, '--git-worktree-root') };
|
|
429
|
+
return { family, taskRef, intent: parsedIntent, input, ...(options ? { options } : {}) };
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=control-authority.js.map
|
package/dist/lib/task/create.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { isValidAgentInfraVersion, VERSION } from '../version.js';
|
|
4
5
|
import { loadShortIdByTaskId, mutateShortIdRegistry } from './short-id.js';
|
|
5
6
|
import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
|
|
6
7
|
const AGENTS = ['claude', 'codex', 'antigravity', 'opencode', 'cursor'];
|
|
@@ -258,6 +259,10 @@ function recoverPublishedTask(activeRoot, repoRoot, keyDigest, candidateDigest)
|
|
|
258
259
|
}
|
|
259
260
|
function createLocalTask(value, options) {
|
|
260
261
|
const candidate = validateTaskCreateCandidate(value);
|
|
262
|
+
const agentInfraVersion = options.agentInfraVersion ?? VERSION;
|
|
263
|
+
if (!isValidAgentInfraVersion(agentInfraVersion)) {
|
|
264
|
+
throw new Error('TASK_CREATE_VERSION_INVALID: agentInfraVersion must be a valid v-prefixed semver');
|
|
265
|
+
}
|
|
261
266
|
const repoRoot = fs.realpathSync.native(options.repoRoot);
|
|
262
267
|
const workspaceRoot = path.join(repoRoot, '.agents', 'workspace');
|
|
263
268
|
const activeRoot = path.join(workspaceRoot, 'active');
|
|
@@ -308,7 +313,7 @@ function createLocalTask(value, options) {
|
|
|
308
313
|
throw new Error('TASK_CREATE_TEMPLATE_INVALID');
|
|
309
314
|
const rendered = renderTask({
|
|
310
315
|
template: fs.readFileSync(templatePath, 'utf8'), candidate, taskId, project, timestamp,
|
|
311
|
-
agentInfraVersion
|
|
316
|
+
agentInfraVersion, keyDigest, candidateDigest
|
|
312
317
|
});
|
|
313
318
|
const temporary = path.join(workspaceRoot, `.task-create.tmp.${process.pid}.${randomUUID()}`);
|
|
314
319
|
fs.mkdirSync(temporary, { mode: 0o700 });
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { isValidAgentInfraVersion } from '../version.js';
|
|
2
|
+
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
3
|
+
import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, validateLedgerRows } from './ledger.js';
|
|
4
|
+
function validateCurrentTaskContract(content) {
|
|
5
|
+
let metadata;
|
|
6
|
+
try {
|
|
7
|
+
metadata = parseTypedTaskFrontmatter(content);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
return { ok: false, code: 'TASK_DOCUMENT_INVALID', message: error instanceof Error ? error.message : String(error) };
|
|
11
|
+
}
|
|
12
|
+
if (!isValidAgentInfraVersion(metadata.agent_infra_version)) {
|
|
13
|
+
return {
|
|
14
|
+
ok: false,
|
|
15
|
+
code: 'TASK_CURRENT_CONTRACT_INVALID',
|
|
16
|
+
message: `agent_infra_version must be a valid v-prefixed semver (received ${String(metadata.agent_infra_version ?? 'missing')})`
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
let ledger;
|
|
20
|
+
try {
|
|
21
|
+
ledger = parseLedgerDocument(content);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return { ok: false, code: 'TASK_DOCUMENT_INVALID', message: error instanceof Error ? error.message : String(error) };
|
|
25
|
+
}
|
|
26
|
+
if (!ledger.present) {
|
|
27
|
+
return { ok: false, code: 'TASK_CURRENT_CONTRACT_INVALID', message: `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}` };
|
|
28
|
+
}
|
|
29
|
+
const invalid = validateLedgerRows(ledger.rows);
|
|
30
|
+
if (invalid)
|
|
31
|
+
return { ok: false, code: 'TASK_CURRENT_CONTRACT_INVALID', message: `${invalid.code}: ${invalid.message}` };
|
|
32
|
+
return { ok: true, metadata, ledger };
|
|
33
|
+
}
|
|
34
|
+
export { validateCurrentTaskContract };
|
|
35
|
+
//# sourceMappingURL=current-contract.js.map
|