@fitlab-ai/agent-infra 0.9.9 → 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 +55 -4
- package/dist/lib/agent-client.js +0 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +17 -10
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-context.js +11 -31
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +15 -33
- 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/opencode-sandbox.js +0 -4
- package/dist/lib/agent-clients/adapters/traecli.js +65 -0
- 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 +7 -17
- package/dist/lib/agent-clients/types.js +2 -1
- package/dist/lib/decide.js +14 -30
- package/dist/lib/defaults.json +9 -0
- package/dist/lib/init.js +2 -2
- package/dist/lib/internal/codex-lifecycle.js +2 -2
- package/dist/lib/internal/codex-sandbox-controller.js +4 -3
- package/dist/lib/internal/release-workflow.js +0 -1
- package/dist/lib/internal/sandbox-control.js +2 -2
- 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/{task/commands/validate.js → internal/task-validate.js} +77 -43
- 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/run/tui.js +5 -2
- 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/controller-registration.js +4 -2
- package/dist/lib/sandbox/control/executor.js +135 -40
- 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 +32 -35
- 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/delegation-receipts.js +8 -7
- package/dist/lib/task/events.js +11 -5
- package/dist/lib/task/finalization.js +72 -46
- package/dist/lib/task/index.js +19 -29
- 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 +51 -14
- 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 -18
- 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/codex-lifecycle/build-identity.ts +25 -10
- package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +16 -33
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +16 -35
- package/lib/agent-clients/adapters/codex-sandbox.ts +89 -14
- package/lib/agent-clients/adapters/index.ts +3 -1
- package/lib/agent-clients/adapters/opencode-sandbox.ts +0 -5
- package/lib/agent-clients/adapters/traecli.ts +66 -0
- 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 +7 -20
- package/lib/agent-clients/types.ts +2 -1
- package/lib/decide.ts +12 -22
- package/lib/defaults.json +9 -0
- package/lib/init.ts +2 -2
- package/lib/internal/codex-lifecycle.ts +2 -2
- package/lib/internal/codex-sandbox-controller.ts +4 -3
- package/lib/internal/release-workflow.ts +0 -1
- package/lib/internal/sandbox-control.ts +2 -2
- 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/{task/commands/validate.ts → internal/task-validate.ts} +77 -41
- package/lib/merge.ts +236 -120
- package/lib/process-data/normalize.ts +2 -8
- package/lib/run/host.ts +63 -14
- package/lib/run/tui.ts +5 -3
- 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/controller-registration.ts +8 -3
- package/lib/sandbox/control/executor.ts +156 -53
- 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 +40 -45
- 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/delegation-receipts.ts +8 -6
- package/lib/task/events.ts +10 -5
- package/lib/task/finalization.ts +84 -42
- package/lib/task/index.ts +19 -28
- 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 +42 -16
- package/lib/task/review-artifacts.ts +53 -15
- package/lib/task/review-finalization.ts +33 -7
- package/lib/task/verification-engine.ts +33 -21
- 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/QUICKSTART.en.md +2 -3
- package/templates/.agents/QUICKSTART.zh-CN.md +2 -3
- package/templates/.agents/README.en.md +5 -3
- package/templates/.agents/README.zh-CN.md +5 -3
- 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 +40 -0
- package/templates/.agents/rules/compatibility-policy.zh-CN.md +40 -0
- 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/lifecycle-orchestration.en.md +4 -4
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +4 -4
- 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 +2 -2
- package/templates/.agents/rules/pr-sync.github.en.md +3 -2
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +3 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +2 -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/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 +1 -2
- package/templates/.agents/rules/task-management.zh-CN.md +1 -2
- package/templates/.agents/skills/analyze-task/SKILL.en.md +4 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +4 -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 +4 -3
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +5 -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 +15 -11
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +15 -11
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +46 -0
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +46 -0
- 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 +5 -4
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -4
- 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 +9 -6
- package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +9 -6
- 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 +7 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +7 -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 -2
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +6 -2
- 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/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 +159 -104
- 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/.traecli/commands/update-agent-infra.en.md +7 -0
- package/templates/.traecli/commands/update-agent-infra.zh-CN.md +7 -0
- package/dist/lib/builtin-tuis.js +0 -40
- package/lib/builtin-tuis.ts +0 -56
package/dist/lib/task/ledger.js
CHANGED
|
@@ -12,18 +12,25 @@ const LEDGER_TERMINAL = new Set(['confirmed', 'closed', 'human-decided']);
|
|
|
12
12
|
// Statuses that represent a decision row awaiting or carrying a human ruling.
|
|
13
13
|
const HUMAN_DECISION_STATUSES = new Set(['needs-human-decision', 'human-decided']);
|
|
14
14
|
const FINDING_STATUSES = new Set(['open', 'accepted', 'adjusted', 'refuted', 'cannot-judge', 'confirmed', 'needs-human-decision', 'closed', 'human-decided']);
|
|
15
|
+
const LEDGER_SECTION_MISSING_CODE = 'LEDGER_SECTION_MISSING';
|
|
16
|
+
const LEDGER_SECTION_MISSING_MESSAGE = 'review disagreement ledger section is missing';
|
|
15
17
|
function isReviewStage(stage) {
|
|
16
18
|
return stage === 'analysis' || stage === 'plan' || stage === 'code';
|
|
17
19
|
}
|
|
18
20
|
// Parse all rows of the disagreement ledger table. Skips the heading, the
|
|
19
21
|
// header row (`| id | ... |`) and the `|---|` separator; ignores non-`|` lines.
|
|
20
22
|
// Rows with fewer than 6 columns are skipped (mirrors the JS gate parser).
|
|
21
|
-
function
|
|
23
|
+
function parseLedgerDocument(content) {
|
|
22
24
|
const table = parseTable(content, { sectionAliases: LEDGER_HEADINGS, columns: LEDGER_COLUMNS });
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
if (!table)
|
|
26
|
+
return { present: false, rows: [] };
|
|
27
|
+
return {
|
|
28
|
+
present: true,
|
|
29
|
+
rows: table.rows.map(({ values, sourceLine }) => ({
|
|
30
|
+
id: values.id, stage: values.stage, round: values.round, severity: values.severity,
|
|
31
|
+
status: values.status, evidence: values.evidence, sourceLine
|
|
32
|
+
}))
|
|
33
|
+
};
|
|
27
34
|
}
|
|
28
35
|
function validateLedgerRows(rows) {
|
|
29
36
|
const seen = new Set();
|
|
@@ -104,5 +111,5 @@ function nextHdId(rows) {
|
|
|
104
111
|
}
|
|
105
112
|
return `HD-${max + 1}`;
|
|
106
113
|
}
|
|
107
|
-
export { LEDGER_HEADINGS, LEDGER_COLUMNS,
|
|
114
|
+
export { LEDGER_HEADINGS, LEDGER_COLUMNS, parseLedgerDocument, nextHdId, isReviewStage, validateLedgerRows, summarizeLedgerStage, LEDGER_TERMINAL, HUMAN_DECISION_STATUSES, LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE };
|
|
108
115
|
//# sourceMappingURL=ledger.js.map
|
|
@@ -7,6 +7,8 @@ import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
|
7
7
|
import { locateHotTaskDirs, resolveTaskRef, TASK_ID_RE } from './resolve-ref.js';
|
|
8
8
|
import { configuredShortIdLength, executeShortIdCommand, loadShortIdByTaskId, mutateShortIdRegistry } from './short-id.js';
|
|
9
9
|
import { captureTaskWriteMetadata, writeTask } from './write.js';
|
|
10
|
+
import { validateCurrentTaskContract } from './current-contract.js';
|
|
11
|
+
import { isValidAgentInfraVersion } from '../version.js';
|
|
10
12
|
const lifecycleIntentCatalog = [
|
|
11
13
|
'block', 'activate', 'cancel', 'complete', 'close-codescan', 'close-dependabot', 'restore'
|
|
12
14
|
];
|
|
@@ -57,6 +59,9 @@ function failed(request, error, extra = {}) {
|
|
|
57
59
|
error, ...extra
|
|
58
60
|
};
|
|
59
61
|
}
|
|
62
|
+
export function taskLifecycleFailure(request, error, taskId = null) {
|
|
63
|
+
return failed(request, error, { taskId });
|
|
64
|
+
}
|
|
60
65
|
function normalizedRequest(request) {
|
|
61
66
|
if (!request || typeof request !== 'object' || !lifecycleIntentCatalog.includes(request.intent)) {
|
|
62
67
|
return { code: 'LIFECYCLE_PAYLOAD_INVALID', message: 'intent is not in the lifecycle catalog' };
|
|
@@ -366,6 +371,11 @@ function applyTaskLifecycle(requestInput, options = {}) {
|
|
|
366
371
|
return failed(request, { code: 'LIFECYCLE_IDENTITY_INVALID', message: 'task.md id does not match its lifecycle task id' }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
|
|
367
372
|
if (!locateActivityLog(content) && !allowsManualOverride(options, 'LIFECYCLE_LOG_MISSING'))
|
|
368
373
|
return failed(request, { code: 'LIFECYCLE_LOG_MISSING', message: 'task has no unique Activity Log section' }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
|
|
374
|
+
if (spec.target === 'active') {
|
|
375
|
+
const contract = validateCurrentTaskContract(content);
|
|
376
|
+
if (!contract.ok)
|
|
377
|
+
return failed(request, { code: 'LIFECYCLE_DOCUMENT_INVALID', message: contract.message }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
|
|
378
|
+
}
|
|
369
379
|
const registryRequest = executeShortIdCommand({
|
|
370
380
|
operation: 'list', activeDir: path.join(repoRoot, '.agents', 'workspace', 'active'),
|
|
371
381
|
shortIdLength: configuredShortIdLength(repoRoot)
|
|
@@ -394,6 +404,9 @@ function applyTaskLifecycle(requestInput, options = {}) {
|
|
|
394
404
|
}
|
|
395
405
|
if (journal.taskId !== taskId || journal.intent !== request.intent)
|
|
396
406
|
return failed(request, { code: 'LIFECYCLE_INTENT_CONFLICT', message: 'an in-progress lifecycle journal belongs to a different request' }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath: initialJournalPath });
|
|
407
|
+
if (spec.target === 'active' && !isValidAgentInfraVersion(journal.metadata.agentInfraVersion)) {
|
|
408
|
+
return failed(request, { code: 'LIFECYCLE_DOCUMENT_INVALID', message: `journal metadata agentInfraVersion must be a valid v-prefixed semver (received ${journal.metadata.agentInfraVersion})` }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath: initialJournalPath });
|
|
409
|
+
}
|
|
397
410
|
if (request.dryRun) {
|
|
398
411
|
if (!journal.failure)
|
|
399
412
|
return failed(request, { code: 'LIFECYCLE_JOURNAL_INVALID', message: 'existing lifecycle journal has no durable failure evidence for a read-only probe' }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath, journalPath: initialJournalPath });
|
|
@@ -411,6 +424,9 @@ function applyTaskLifecycle(requestInput, options = {}) {
|
|
|
411
424
|
catch (error) {
|
|
412
425
|
return failed(request, { code: 'LIFECYCLE_METADATA_FAILED', message: String(error) }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
|
|
413
426
|
}
|
|
427
|
+
if (spec.target === 'active' && !isValidAgentInfraVersion(metadata.agentInfraVersion)) {
|
|
428
|
+
return failed(request, { code: 'LIFECYCLE_DOCUMENT_INVALID', message: `metadata agentInfraVersion must be a valid v-prefixed semver (received ${metadata.agentInfraVersion})` }, { taskId, sourceState, targetState: spec.target, sourcePath, targetPath });
|
|
429
|
+
}
|
|
414
430
|
journal = { version: 1, taskId, intent: request.intent, intentDigest: digest, sourceState, targetState: spec.target, metadata, completedSteps: [] };
|
|
415
431
|
if (request.dryRun) {
|
|
416
432
|
const plannedMutations = mutationsFor(request, content, metadata, restoredFiles, allowsManualOverride(options, 'LIFECYCLE_LOG_MISSING'));
|
|
@@ -2,9 +2,10 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
4
|
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
5
|
-
import {
|
|
5
|
+
import { validateCurrentTaskContract } from './current-contract.js';
|
|
6
|
+
import { parseReviewSummary, resolveCanonicalVerdict } from './review-artifacts.js';
|
|
6
7
|
import { inspectArtifactDirectory } from './artifact-lifecycle.js';
|
|
7
|
-
import {
|
|
8
|
+
import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
|
|
8
9
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
9
10
|
import { activateDelegation, abortPreparedDelegation, completeDelegationStage, consumeDelegation, dispatchDelegation, foldBlankToNull, isDelegationReceipt, managedDelegationRole, prepareDelegation, sealDelegation } from './delegation-receipts.js';
|
|
10
11
|
import { normalizeAgentClients } from '../agent-clients/config.js';
|
|
@@ -25,7 +26,7 @@ function supportsLifecycleDelegation(client) {
|
|
|
25
26
|
function orchestrationPath(taskDir) {
|
|
26
27
|
return path.join(taskDir, 'orchestration.json');
|
|
27
28
|
}
|
|
28
|
-
const ORCHESTRATION_STATE_INVALID_MESSAGE = 'orchestration.json does not match the current runtime structure;
|
|
29
|
+
const ORCHESTRATION_STATE_INVALID_MESSAGE = 'orchestration.json does not match the current runtime structure; the file was left unchanged; rebuild the sandbox or manually repair the state before retrying';
|
|
29
30
|
class OrchestrationStateError extends Error {
|
|
30
31
|
code = 'ORCHESTRATION_STATE_INVALID';
|
|
31
32
|
taskId;
|
|
@@ -350,9 +351,21 @@ function hasReviewAfterArtifact(taskDir, family, reviewFamily) {
|
|
|
350
351
|
function latestReviewApproved(taskDir, family) {
|
|
351
352
|
const round = highestRound(taskDir, family);
|
|
352
353
|
if (round === 0)
|
|
353
|
-
return false;
|
|
354
|
-
|
|
355
|
-
|
|
354
|
+
return { approved: false, error: null };
|
|
355
|
+
let content;
|
|
356
|
+
try {
|
|
357
|
+
content = fs.readFileSync(path.join(taskDir, artifactName(family, round)), 'utf8');
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
return { approved: false, error: String(error) };
|
|
361
|
+
}
|
|
362
|
+
const parsed = parseReviewSummary(content);
|
|
363
|
+
if (!parsed.ok)
|
|
364
|
+
return { approved: false, error: `${parsed.code}: ${parsed.message}` };
|
|
365
|
+
const verdict = resolveCanonicalVerdict(parsed.summary);
|
|
366
|
+
if (!verdict.ok)
|
|
367
|
+
return { approved: false, error: `${verdict.code}: ${verdict.message}` };
|
|
368
|
+
return { approved: verdict.verdict === 'Approved', error: null };
|
|
356
369
|
}
|
|
357
370
|
function routeFromFacts(taskDir) {
|
|
358
371
|
const analysisRound = highestRound(taskDir, 'analysis');
|
|
@@ -369,7 +382,10 @@ function routeFromFacts(taskDir) {
|
|
|
369
382
|
const round = analysisReviewRound + 1;
|
|
370
383
|
return { action: 'review-analysis', role: 'reviewer', stage: 'review-analysis', round, artifact: artifactName('review-analysis', round) };
|
|
371
384
|
}
|
|
372
|
-
|
|
385
|
+
const analysisVerdict = latestReviewApproved(taskDir, 'review-analysis');
|
|
386
|
+
if (analysisVerdict.error)
|
|
387
|
+
return { error: analysisVerdict.error };
|
|
388
|
+
if (!analysisVerdict.approved) {
|
|
373
389
|
const round = analysisRound + 1;
|
|
374
390
|
return { action: 'analyze-task', role: 'executor', stage: 'analysis', round, artifact: artifactName('analysis', round) };
|
|
375
391
|
}
|
|
@@ -381,7 +397,10 @@ function routeFromFacts(taskDir) {
|
|
|
381
397
|
const round = planReviewRound + 1;
|
|
382
398
|
return { action: 'review-plan', role: 'reviewer', stage: 'review-plan', round, artifact: artifactName('review-plan', round) };
|
|
383
399
|
}
|
|
384
|
-
|
|
400
|
+
const planVerdict = latestReviewApproved(taskDir, 'review-plan');
|
|
401
|
+
if (planVerdict.error)
|
|
402
|
+
return { error: planVerdict.error };
|
|
403
|
+
if (!planVerdict.approved) {
|
|
385
404
|
const round = planRound + 1;
|
|
386
405
|
return { action: 'plan-task', role: 'executor', stage: 'plan', round, artifact: artifactName('plan', round) };
|
|
387
406
|
}
|
|
@@ -393,7 +412,10 @@ function routeFromFacts(taskDir) {
|
|
|
393
412
|
const round = codeReviewRound + 1;
|
|
394
413
|
return { action: 'review-code', role: 'reviewer', stage: 'review-code', round, artifact: artifactName('review-code', round) };
|
|
395
414
|
}
|
|
396
|
-
|
|
415
|
+
const codeVerdict = latestReviewApproved(taskDir, 'review-code');
|
|
416
|
+
if (codeVerdict.error)
|
|
417
|
+
return { error: codeVerdict.error };
|
|
418
|
+
if (!codeVerdict.approved) {
|
|
397
419
|
const round = codeRound + 1;
|
|
398
420
|
return { action: 'code-task', role: 'executor', stage: 'code', round, artifact: artifactName('code', round) };
|
|
399
421
|
}
|
|
@@ -418,13 +440,25 @@ function routeOrchestration(taskRef, options = {}) {
|
|
|
418
440
|
return failed('ORCHESTRATION_TASK_READ_FAILED', String(error), resolved.taskId);
|
|
419
441
|
}
|
|
420
442
|
let metadata;
|
|
421
|
-
|
|
422
|
-
|
|
443
|
+
let currentLedger = null;
|
|
444
|
+
if (resolved.state === 'active') {
|
|
445
|
+
const contract = validateCurrentTaskContract(content);
|
|
446
|
+
if (!contract.ok)
|
|
447
|
+
return failed('ORCHESTRATION_CURRENT_CONTRACT_INVALID', contract.message, resolved.taskId);
|
|
448
|
+
metadata = contract.metadata;
|
|
449
|
+
currentLedger = contract.ledger;
|
|
423
450
|
}
|
|
424
|
-
|
|
425
|
-
|
|
451
|
+
else {
|
|
452
|
+
try {
|
|
453
|
+
metadata = parseTypedTaskFrontmatter(content);
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
return failed('ORCHESTRATION_TASK_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
|
|
457
|
+
}
|
|
426
458
|
}
|
|
427
459
|
const routed = routeFromFacts(resolved.taskDir);
|
|
460
|
+
if (routed && 'error' in routed)
|
|
461
|
+
return failed('ORCHESTRATION_REVIEW_INVALID', routed.error, resolved.taskId);
|
|
428
462
|
if (!routed)
|
|
429
463
|
return failed('ORCHESTRATION_ROUTE_UNKNOWN', 'cannot determine a unique lifecycle action', resolved.taskId);
|
|
430
464
|
const run = readRun(resolved.taskDir);
|
|
@@ -440,7 +474,10 @@ function routeOrchestration(taskRef, options = {}) {
|
|
|
440
474
|
if (!review.ok || review.summary.manualValidation === null) {
|
|
441
475
|
return failed('ORCHESTRATION_REVIEW_INVALID', 'latest code review has no numeric manual-validation count', resolved.taskId);
|
|
442
476
|
}
|
|
443
|
-
const
|
|
477
|
+
const ledger = currentLedger ?? parseLedgerDocument(content);
|
|
478
|
+
if (!ledger.present)
|
|
479
|
+
return failed('ORCHESTRATION_CURRENT_CONTRACT_INVALID', `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`, resolved.taskId);
|
|
480
|
+
const rows = ledger.rows;
|
|
444
481
|
const ledgerError = validateLedgerRows(rows);
|
|
445
482
|
if (ledgerError)
|
|
446
483
|
return failed('ORCHESTRATION_LEDGER_INVALID', ledgerError.message, resolved.taskId);
|
|
@@ -159,27 +159,46 @@ function finalizeReviewSummaryContent(content, counts) {
|
|
|
159
159
|
content: content.slice(0, parsed.findingsStart) + line + content.slice(parsed.findingsEnd)
|
|
160
160
|
};
|
|
161
161
|
}
|
|
162
|
+
function resolveCanonicalVerdict(summary) {
|
|
163
|
+
if (summary.counts === null) {
|
|
164
|
+
return {
|
|
165
|
+
ok: false,
|
|
166
|
+
verdict: null,
|
|
167
|
+
code: 'REVIEW_FINDING_COUNTS_NOT_FINALIZED',
|
|
168
|
+
message: 'review summary finding counts are not finalized'
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
if (summary.verdict === 'Approved' && !equalCounts(summary.counts, { blocker: 0, major: 0, minor: 0 })) {
|
|
172
|
+
return {
|
|
173
|
+
ok: false,
|
|
174
|
+
verdict: null,
|
|
175
|
+
code: 'REVIEW_VERDICT_FINDING_MISMATCH',
|
|
176
|
+
message: 'Approved verdict requires zero finalized findings'
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return { ok: true, verdict: summary.verdict };
|
|
180
|
+
}
|
|
162
181
|
function parseVerdict(reviewPath) {
|
|
163
182
|
if (!fs.existsSync(reviewPath)) {
|
|
164
|
-
return { ok: false, verdict: null, message: `Review artifact not found: ${path.basename(reviewPath)}` };
|
|
183
|
+
return { ok: false, verdict: null, code: 'REVIEW_ARTIFACT_NOT_FOUND', message: `Review artifact not found: ${path.basename(reviewPath)}` };
|
|
184
|
+
}
|
|
185
|
+
let content;
|
|
186
|
+
try {
|
|
187
|
+
content = fs.readFileSync(reviewPath, 'utf8');
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
return { ok: false, verdict: null, code: 'REVIEW_ARTIFACT_READ_FAILED', message: `Review artifact could not be read: ${String(error)}` };
|
|
165
191
|
}
|
|
166
|
-
const parsed = parseReviewSummary(
|
|
192
|
+
const parsed = parseReviewSummary(content);
|
|
167
193
|
if (!parsed.ok) {
|
|
168
194
|
return {
|
|
169
195
|
ok: false,
|
|
170
196
|
verdict: null,
|
|
197
|
+
code: parsed.code === 'REVIEW_SUMMARY_PLACEHOLDER_INVALID' ? parsed.code : 'REVIEW_SUMMARY_NOT_FOUND',
|
|
171
198
|
message: `cannot parse review summary in ${path.basename(reviewPath)}: ${parsed.message}`
|
|
172
199
|
};
|
|
173
200
|
}
|
|
174
|
-
|
|
175
|
-
if (verdict !== 'Approved')
|
|
176
|
-
return { ok: true, verdict };
|
|
177
|
-
return {
|
|
178
|
-
ok: true,
|
|
179
|
-
verdict: counts && equalCounts(counts, { blocker: 0, major: 0, minor: 0 })
|
|
180
|
-
? 'Approved'
|
|
181
|
-
: 'Approved-with-issues'
|
|
182
|
-
};
|
|
201
|
+
return resolveCanonicalVerdict(parsed.summary);
|
|
183
202
|
}
|
|
184
|
-
export { artifactName, equalCounts, escapeRegExp, extractSection, finalizeReviewSummaryContent, maxRound, normalizeVerdict, parseReviewSummary, parseVerdict };
|
|
203
|
+
export { artifactName, equalCounts, escapeRegExp, extractSection, finalizeReviewSummaryContent, maxRound, normalizeVerdict, parseReviewSummary, parseVerdict, resolveCanonicalVerdict };
|
|
185
204
|
//# sourceMappingURL=review-artifacts.js.map
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import { locateActivityLog, pairEntries } from './activity-log.js';
|
|
4
|
+
import { locateActivityLog, pairEntries, startedBackedRows } from './activity-log.js';
|
|
5
5
|
import { parseArtifactName, validateCompletedArtifact } from './artifact-lifecycle.js';
|
|
6
|
-
import {
|
|
6
|
+
import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
|
|
7
7
|
import { finalizeReviewSummaryContent } from './review-artifacts.js';
|
|
8
|
+
import { inspectDecisionDetailDuplicates, repairDecisionDetailDuplicates } from './decision-details.js';
|
|
8
9
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
9
10
|
import { validateLifecycleExecution } from './lifecycle-execution.js';
|
|
10
11
|
import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
|
|
@@ -40,7 +41,7 @@ function openReviewRound(content, action, round) {
|
|
|
40
41
|
if (!section)
|
|
41
42
|
return false;
|
|
42
43
|
const expected = `${action} (Round ${round})`;
|
|
43
|
-
return pairEntries(section.entries).filter((row) => (row.step === expected &&
|
|
44
|
+
return startedBackedRows(pairEntries(section.entries)).filter((row) => (row.step === expected && !row.done)).length === 1;
|
|
44
45
|
}
|
|
45
46
|
function cleanupTemp(fileSystem, tempPath) {
|
|
46
47
|
try {
|
|
@@ -103,7 +104,11 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
|
|
|
103
104
|
}
|
|
104
105
|
let rows;
|
|
105
106
|
try {
|
|
106
|
-
|
|
107
|
+
const ledger = parseLedgerDocument(taskContent);
|
|
108
|
+
if (!ledger.present) {
|
|
109
|
+
return failed(request, 'REVIEW_LEDGER_INVALID', `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`, resolved.taskId);
|
|
110
|
+
}
|
|
111
|
+
rows = ledger.rows;
|
|
107
112
|
}
|
|
108
113
|
catch (error) {
|
|
109
114
|
return failed(request, 'REVIEW_LEDGER_INVALID', String(error), resolved.taskId);
|
|
@@ -113,11 +118,19 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
|
|
|
113
118
|
return failed(request, 'REVIEW_LEDGER_INVALID', `${ledgerError.code}: ${ledgerError.message}`, resolved.taskId);
|
|
114
119
|
}
|
|
115
120
|
const stageStatus = summarizeLedgerStage(rows, stage);
|
|
116
|
-
const
|
|
121
|
+
const repaired = repairDecisionDetailDuplicates(artifactContent);
|
|
122
|
+
if (!repaired.ok) {
|
|
123
|
+
return failed(request, 'REVIEW_DECISION_DETAIL_INVALID', `${repaired.code}: ${repaired.message}`, resolved.taskId, stageStatus);
|
|
124
|
+
}
|
|
125
|
+
const detailInspection = inspectDecisionDetailDuplicates(repaired.content);
|
|
126
|
+
if (!detailInspection.ok) {
|
|
127
|
+
return failed(request, 'REVIEW_DECISION_DETAIL_INVALID', `${detailInspection.code}: ${detailInspection.message}`, resolved.taskId, stageStatus);
|
|
128
|
+
}
|
|
129
|
+
const transformed = finalizeReviewSummaryContent(repaired.content, stageStatus.unresolvedFindingCounts);
|
|
117
130
|
if (!transformed.ok) {
|
|
118
131
|
return failed(request, transformed.code, transformed.message, resolved.taskId, stageStatus);
|
|
119
132
|
}
|
|
120
|
-
if (!transformed.changed) {
|
|
133
|
+
if (!repaired.changed && !transformed.changed) {
|
|
121
134
|
return {
|
|
122
135
|
...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus),
|
|
123
136
|
status: 'no-op',
|
|
@@ -12,8 +12,10 @@ import { resolveMaterializedReviewedHeadRelation } from "../platform/change-requ
|
|
|
12
12
|
import { resolveReviewedHeadRelation } from "../platform/merged-pr-equivalence.js";
|
|
13
13
|
import { resolveLocalReviewedCommitRelation } from "../git/reviewed-commit-equivalence.js";
|
|
14
14
|
import { parseTypedTaskFrontmatter } from "./frontmatter.js";
|
|
15
|
-
import {
|
|
15
|
+
import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.js";
|
|
16
|
+
import { isValidAgentInfraVersion } from "../version.js";
|
|
16
17
|
import { equalCounts, parseReviewSummary } from "./review-artifacts.js";
|
|
18
|
+
import { inspectDecisionDetailDuplicates } from "./decision-details.js";
|
|
17
19
|
import { loadVerificationConfig } from "./verification-config.js";
|
|
18
20
|
import { snapshotReview } from "../git/review-snapshot.js";
|
|
19
21
|
import { OrchestrationStateError, readRun } from "./orchestration.js";
|
|
@@ -34,7 +36,6 @@ const DEFAULT_REQUIRED_FIELDS = [
|
|
|
34
36
|
"assigned_to"
|
|
35
37
|
];
|
|
36
38
|
const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
|
|
37
|
-
const AGENT_INFRA_VERSION_PATTERN = /^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
38
39
|
const ACTIVITY_LOG_PATTERN = /^- (\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?) — \*\*(.+?)\*\* by (.+?) — (.+)$/;
|
|
39
40
|
// Start markers (action suffixed with ` [started]`) are excluded from the
|
|
40
41
|
// "latest action" / freshness computation so a step's in-flight marker never
|
|
@@ -89,6 +90,8 @@ function runCheck(type, context, shared) {
|
|
|
89
90
|
return checkTaskMeta(context);
|
|
90
91
|
case "artifact":
|
|
91
92
|
return checkArtifact(context);
|
|
93
|
+
case "decision-details":
|
|
94
|
+
return checkDecisionDetails(context);
|
|
92
95
|
case "implementation-input":
|
|
93
96
|
return checkImplementationInput(context);
|
|
94
97
|
case "activity-log":
|
|
@@ -308,9 +311,6 @@ function checkOrchestrationEvidence({ taskDir }) {
|
|
|
308
311
|
if (!provenance
|
|
309
312
|
|| (activatedCodex && (host?.kind !== 'codex-lifecycle-v2'
|
|
310
313
|
|| host.protocolVersion !== provenance.protocolVersion
|
|
311
|
-
|| host.packageVersion !== provenance.packageVersion
|
|
312
|
-
|| host.internalExecutableBuildHash !== provenance.internalExecutableBuildHash
|
|
313
|
-
|| host.lifecycleContractHash !== provenance.lifecycleContractHash
|
|
314
314
|
|| host.hookDefinitionHash !== provenance.hookDefinitionHash
|
|
315
315
|
|| host.hookSource !== provenance.hookSource
|
|
316
316
|
|| host.hookSourcePathDigest !== provenance.hookSourcePathDigest
|
|
@@ -355,18 +355,17 @@ function checkTaskMeta({ taskDir, config }) {
|
|
|
355
355
|
const metadata = task.metadata;
|
|
356
356
|
const requiredFields = config.required_fields || DEFAULT_REQUIRED_FIELDS;
|
|
357
357
|
const missingFields = requiredFields.filter((field) => isBlank(metadata[field]));
|
|
358
|
-
const
|
|
358
|
+
const currentTask = metadata.status === 'active';
|
|
359
|
+
const blockingMissingFields = missingFields.filter((field) => field !== "agent_infra_version" || currentTask);
|
|
359
360
|
const warnings = [];
|
|
360
|
-
if (missingFields.includes("agent_infra_version")) {
|
|
361
|
+
if (missingFields.includes("agent_infra_version") && !currentTask) {
|
|
361
362
|
warnings.push("field 'agent_infra_version' missing — historical task or skipped version stamp");
|
|
362
363
|
}
|
|
363
364
|
if (blockingMissingFields.length > 0) {
|
|
364
365
|
return failResult("task-meta", `Missing required fields: ${blockingMissingFields.join(", ")}`);
|
|
365
366
|
}
|
|
366
|
-
if (!
|
|
367
|
-
metadata.agent_infra_version
|
|
368
|
-
!AGENT_INFRA_VERSION_PATTERN.test(metadata.agent_infra_version)) {
|
|
369
|
-
return failResult("task-meta", `Invalid agent_infra_version: ${metadata.agent_infra_version}`);
|
|
367
|
+
if (currentTask && !isValidAgentInfraVersion(metadata.agent_infra_version)) {
|
|
368
|
+
return failResult("task-meta", `Invalid agent_infra_version: ${String(metadata.agent_infra_version ?? 'missing')}`);
|
|
370
369
|
}
|
|
371
370
|
const invalidDates = ["created_at", "updated_at", "completed_at", "blocked_at", "cancelled_at"]
|
|
372
371
|
.filter((field) => !isBlank(metadata[field]) && !DATE_TIME_PATTERN.test(metadata[field]));
|
|
@@ -530,6 +529,21 @@ function checkArtifact({ taskDir, config, artifactFile }) {
|
|
|
530
529
|
}
|
|
531
530
|
return passResult("artifact", `${path.basename(artifactPath)} passed (${requiredSections.length} sections)`);
|
|
532
531
|
}
|
|
532
|
+
function checkDecisionDetails({ taskDir, artifactFile }) {
|
|
533
|
+
const resolvedArtifact = resolveArtifactPath(taskDir, "", artifactFile);
|
|
534
|
+
if (!resolvedArtifact.ok)
|
|
535
|
+
return failResult("decision-details", resolvedArtifact.message);
|
|
536
|
+
const artifactPath = resolvedArtifact.path;
|
|
537
|
+
const stat = safeStat(artifactPath);
|
|
538
|
+
if (!stat?.isFile())
|
|
539
|
+
return failResult("decision-details", `Artifact not found: ${path.basename(artifactPath)}`);
|
|
540
|
+
if (stat.size === 0)
|
|
541
|
+
return passResult("decision-details", `${path.basename(artifactPath)} contains no decision details`);
|
|
542
|
+
const inspection = inspectDecisionDetailDuplicates(fs.readFileSync(artifactPath, "utf8"));
|
|
543
|
+
if (!inspection.ok)
|
|
544
|
+
return failResult("decision-details", `${path.basename(artifactPath)}: ${inspection.message}`);
|
|
545
|
+
return passResult("decision-details", `${path.basename(artifactPath)} has no duplicate decision detail ids`);
|
|
546
|
+
}
|
|
533
547
|
function checkReviewSummary({ taskDir, config, artifactFile }) {
|
|
534
548
|
const stage = String(config.stage || "");
|
|
535
549
|
if (!["analysis", "plan", "code"].includes(stage)) {
|
|
@@ -550,7 +564,10 @@ function checkReviewSummary({ taskDir, config, artifactFile }) {
|
|
|
550
564
|
return failResult("review-summary", task.message);
|
|
551
565
|
let rows;
|
|
552
566
|
try {
|
|
553
|
-
|
|
567
|
+
const ledger = parseLedgerDocument(task.content);
|
|
568
|
+
if (!ledger.present)
|
|
569
|
+
return failResult("review-summary", `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
|
|
570
|
+
rows = ledger.rows;
|
|
554
571
|
}
|
|
555
572
|
catch (error) {
|
|
556
573
|
return failResult("review-summary", `Invalid disagreement ledger: ${String(error)}`);
|
|
@@ -820,13 +837,12 @@ function checkReviewLedger({ taskDir, config }) {
|
|
|
820
837
|
if (!task.ok) {
|
|
821
838
|
return failResult("review-ledger", task.message);
|
|
822
839
|
}
|
|
823
|
-
const section = getSectionContent(task.content, LEDGER_SECTION_NAMES);
|
|
824
|
-
if (!section.trim()) {
|
|
825
|
-
return passResult("review-ledger", "No disagreement ledger section; treated as no open disagreements");
|
|
826
|
-
}
|
|
827
840
|
let rows;
|
|
828
841
|
try {
|
|
829
|
-
|
|
842
|
+
const ledger = parseLedgerDocument(task.content);
|
|
843
|
+
if (!ledger.present)
|
|
844
|
+
return failResult("review-ledger", `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
|
|
845
|
+
rows = ledger.rows.map((row) => [
|
|
830
846
|
row.id, row.stage, row.round, row.severity, row.status, row.evidence
|
|
831
847
|
]);
|
|
832
848
|
}
|
|
@@ -1071,7 +1087,11 @@ function formatPostReviewExemptions(exemptions) {
|
|
|
1071
1087
|
}
|
|
1072
1088
|
function resolvePostReviewExemption(content) {
|
|
1073
1089
|
try {
|
|
1074
|
-
const
|
|
1090
|
+
const ledger = parseLedgerDocument(content);
|
|
1091
|
+
if (!ledger.present) {
|
|
1092
|
+
return { ok: false, code: "POST_REVIEW_EXEMPTION_INVALID", message: `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}` };
|
|
1093
|
+
}
|
|
1094
|
+
const rows = ledger.rows;
|
|
1075
1095
|
const invalid = validateLedgerRows(rows);
|
|
1076
1096
|
if (invalid) {
|
|
1077
1097
|
return {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { extractReviewBaseline, extractReviewDiffBase, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, loadPostReviewConfig, parseReviewVerdict, resolvePostReviewGlobs } from './review-fingerprint.js';
|
|
2
|
-
export {
|
|
2
|
+
export { parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
|
|
3
3
|
//# sourceMappingURL=verification-review.js.map
|
|
@@ -26,12 +26,6 @@ function captureWorktreeTree(repoRoot, forcedPath) {
|
|
|
26
26
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
function captureLegacyWorkspaceSnapshot(repoRoot, taskId) {
|
|
30
|
-
const workspaceRelative = taskId
|
|
31
|
-
? `.agents/workspace/active/${taskId}`
|
|
32
|
-
: '.agents/workspace/active';
|
|
33
|
-
return captureWorktreeTree(repoRoot, workspaceRelative);
|
|
34
|
-
}
|
|
35
29
|
function taskFileFingerprints(stateRoot, taskId) {
|
|
36
30
|
const activeRoot = path.join(stateRoot, '.agents', 'workspace', 'active');
|
|
37
31
|
const roots = taskId ? [path.join(activeRoot, taskId)] : [activeRoot];
|
|
@@ -46,6 +40,8 @@ function taskFileFingerprints(stateRoot, taskId) {
|
|
|
46
40
|
}
|
|
47
41
|
if (!stat.isFile() && !stat.isSymbolicLink())
|
|
48
42
|
return;
|
|
43
|
+
if (relative.startsWith('.agents/workspace/active/') && path.posix.basename(relative) === 'orchestration.json')
|
|
44
|
+
return;
|
|
49
45
|
const content = stat.isSymbolicLink()
|
|
50
46
|
? Buffer.from(fs.readlinkSync(absolute))
|
|
51
47
|
: fs.readFileSync(absolute);
|
|
@@ -81,13 +77,11 @@ function decodeWorkspaceFingerprint(value) {
|
|
|
81
77
|
throw new Error(`ORCHESTRATION_SNAPSHOT_FAILED: ${error instanceof Error ? error.message : String(error)}`);
|
|
82
78
|
}
|
|
83
79
|
}
|
|
84
|
-
function captureWorkspaceSnapshot(
|
|
85
|
-
if (typeof contextOrRoot === 'string')
|
|
86
|
-
return captureLegacyWorkspaceSnapshot(contextOrRoot, taskId ?? null);
|
|
80
|
+
function captureWorkspaceSnapshot(context) {
|
|
87
81
|
return encodeWorkspaceFingerprint({
|
|
88
82
|
version: 2,
|
|
89
|
-
gitTree: captureWorktreeTree(
|
|
90
|
-
taskFiles: taskFileFingerprints(
|
|
83
|
+
gitTree: captureWorktreeTree(context.gitRoot, null),
|
|
84
|
+
taskFiles: taskFileFingerprints(context.stateRoot, context.taskId)
|
|
91
85
|
});
|
|
92
86
|
}
|
|
93
87
|
function captureRepositorySnapshot(repoRoot) {
|
package/dist/lib/task/write.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { VERSION } from '../version.js';
|
|
3
|
+
import { isValidAgentInfraVersion, VERSION } from '../version.js';
|
|
4
4
|
import { parseTypedTaskFrontmatter, updateTaskFrontmatter } from './frontmatter.js';
|
|
5
5
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
6
6
|
import { allowsManualOverride } from './guard-override.js';
|
|
7
7
|
import { mutateTableRow, upsertSection } from './sections.js';
|
|
8
|
+
import { validateCurrentTaskContract } from './current-contract.js';
|
|
8
9
|
const DEFAULT_FILE_SYSTEM = {
|
|
9
10
|
readFileSync: (file) => fs.readFileSync(file, 'utf8'),
|
|
10
11
|
statModeSync: (file) => fs.statSync(file).mode,
|
|
@@ -84,6 +85,12 @@ function writeTask(request, options = {}) {
|
|
|
84
85
|
catch (error) {
|
|
85
86
|
return failure(request, identity, 'TASK_READ_FAILED', error instanceof Error ? error.message : String(error));
|
|
86
87
|
}
|
|
88
|
+
if (resolved.state === 'active') {
|
|
89
|
+
const contract = validateCurrentTaskContract(original);
|
|
90
|
+
if (!contract.ok) {
|
|
91
|
+
return failure(request, identity, contract.code, contract.message);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
87
94
|
let candidate = original;
|
|
88
95
|
const operations = [];
|
|
89
96
|
try {
|
|
@@ -154,6 +161,9 @@ function writeTask(request, options = {}) {
|
|
|
154
161
|
catch (error) {
|
|
155
162
|
return failure(request, identity, 'METADATA_CAPTURE_FAILED', error instanceof Error ? error.message : String(error), operations);
|
|
156
163
|
}
|
|
164
|
+
if (resolved.state === 'active' && !isValidAgentInfraVersion(metadata.agentInfraVersion)) {
|
|
165
|
+
return failure(request, identity, 'TASK_CURRENT_CONTRACT_INVALID', `metadata agentInfraVersion must be a valid v-prefixed semver (received ${metadata.agentInfraVersion})`, operations, metadata);
|
|
166
|
+
}
|
|
157
167
|
if (candidate === original) {
|
|
158
168
|
return {
|
|
159
169
|
status: 'no-op',
|
package/dist/lib/update.js
CHANGED
|
@@ -8,27 +8,9 @@ import { renderFile, copySkillDir } from './render.js';
|
|
|
8
8
|
const defaults = JSON.parse(fs.readFileSync(new URL('./defaults.json', import.meta.url), 'utf8'));
|
|
9
9
|
const CONFIG_DIR = '.agents';
|
|
10
10
|
const CONFIG_PATH = path.join(CONFIG_DIR, '.airc.json');
|
|
11
|
-
|
|
12
|
-
// `prFlow` preference. `true` (the old default / "PR flow on") maps to the
|
|
13
|
-
// strong constraint `required`; `false` maps to `disabled`. A missing or
|
|
14
|
-
// already-migrated config is left untouched (idempotent). Returns the new
|
|
15
|
-
// prFlow value when a migration happened, otherwise null.
|
|
16
|
-
function migratePrFlow(config) {
|
|
17
|
-
if (config.requiresPullRequest === true) {
|
|
18
|
-
delete config.requiresPullRequest;
|
|
19
|
-
config.prFlow = 'required';
|
|
20
|
-
return 'required';
|
|
21
|
-
}
|
|
22
|
-
if (config.requiresPullRequest === false) {
|
|
23
|
-
delete config.requiresPullRequest;
|
|
24
|
-
config.prFlow = 'disabled';
|
|
25
|
-
return 'disabled';
|
|
26
|
-
}
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
async function cmdUpdate() {
|
|
11
|
+
async function cmdSync() {
|
|
30
12
|
console.log('');
|
|
31
|
-
console.log(' ai
|
|
13
|
+
console.log(' ai sync');
|
|
32
14
|
console.log(' ==================================');
|
|
33
15
|
console.log('');
|
|
34
16
|
// check config exists
|
|
@@ -61,7 +43,6 @@ async function cmdUpdate() {
|
|
|
61
43
|
const sandboxAdded = !config.sandbox;
|
|
62
44
|
const taskAdded = !config.task;
|
|
63
45
|
const labelsAdded = !config.labels;
|
|
64
|
-
const prFlowMigrated = migratePrFlow(config);
|
|
65
46
|
if (platformAdded)
|
|
66
47
|
config.platform = structuredClone(defaults.platform);
|
|
67
48
|
if (sandboxAdded)
|
|
@@ -78,19 +59,13 @@ async function cmdUpdate() {
|
|
|
78
59
|
platformType,
|
|
79
60
|
language
|
|
80
61
|
});
|
|
81
|
-
info(`
|
|
62
|
+
info(`Syncing seed files for: ${project}`);
|
|
82
63
|
console.log('');
|
|
83
64
|
// update skill
|
|
84
65
|
copySkillDir(path.join(templateDir, '.agents', 'skills', 'update-agent-infra'), path.join('.agents', 'skills', 'update-agent-infra'), replacements, language, platformType);
|
|
85
66
|
ok('Updated .agents/skills/update-agent-infra/');
|
|
86
67
|
renderFile(path.join(templateDir, '.agents', 'scripts', 'lib', 'agent-infra-package.js'), path.join('.agents', 'scripts', 'lib', 'agent-infra-package.js'), replacements);
|
|
87
68
|
ok('Updated .agents/scripts/lib/agent-infra-package.js');
|
|
88
|
-
try {
|
|
89
|
-
fs.unlinkSync(path.join('.agents', 'skills', 'update-agent-infra', 'scripts', 'sync-templates.cjs'));
|
|
90
|
-
}
|
|
91
|
-
catch {
|
|
92
|
-
// Ignore missing legacy script from pre-ESM installs.
|
|
93
|
-
}
|
|
94
69
|
const added = {
|
|
95
70
|
managed: workflowPlan.projectAssets.registry.managed.filter((entry) => !currentRegistry.managed.includes(entry)),
|
|
96
71
|
merged: workflowPlan.projectAssets.registry.merged.filter((entry) => !currentRegistry.merged.includes(entry))
|
|
@@ -110,7 +85,7 @@ async function cmdUpdate() {
|
|
|
110
85
|
ok(` merged: ${entry}`);
|
|
111
86
|
}
|
|
112
87
|
}
|
|
113
|
-
else if (platformAdded || sandboxAdded || taskAdded || labelsAdded
|
|
88
|
+
else if (platformAdded || sandboxAdded || taskAdded || labelsAdded) {
|
|
114
89
|
if (platformAdded) {
|
|
115
90
|
info(`Default platform config added to ${CONFIG_PATH}.`);
|
|
116
91
|
}
|
|
@@ -123,9 +98,6 @@ async function cmdUpdate() {
|
|
|
123
98
|
if (labelsAdded) {
|
|
124
99
|
info(`Default labels.in config added to ${CONFIG_PATH}.`);
|
|
125
100
|
}
|
|
126
|
-
if (prFlowMigrated) {
|
|
127
|
-
info(`Migrated legacy requiresPullRequest to prFlow="${prFlowMigrated}" in ${CONFIG_PATH}.`);
|
|
128
|
-
}
|
|
129
101
|
}
|
|
130
102
|
else {
|
|
131
103
|
info(`File registry changed in ${CONFIG_PATH}.`);
|
|
@@ -142,14 +114,11 @@ async function cmdUpdate() {
|
|
|
142
114
|
if (hasNewEntries && platformAdded) {
|
|
143
115
|
info(`Default platform config added to ${CONFIG_PATH}.`);
|
|
144
116
|
}
|
|
145
|
-
if (hasNewEntries && prFlowMigrated) {
|
|
146
|
-
info(`Migrated legacy requiresPullRequest to prFlow="${prFlowMigrated}" in ${CONFIG_PATH}.`);
|
|
147
|
-
}
|
|
148
117
|
ok(`Updated ${CONFIG_PATH}`);
|
|
149
118
|
}
|
|
150
119
|
// done
|
|
151
120
|
console.log('');
|
|
152
|
-
ok('Seed files
|
|
121
|
+
ok('Seed files synced successfully!');
|
|
153
122
|
console.log('');
|
|
154
123
|
if (workflowPlan.nextSteps.length === 0) {
|
|
155
124
|
console.log(' No Agent Client project integration enabled.');
|
|
@@ -165,5 +134,5 @@ async function cmdUpdate() {
|
|
|
165
134
|
console.log('');
|
|
166
135
|
}
|
|
167
136
|
}
|
|
168
|
-
export {
|
|
137
|
+
export { cmdSync };
|
|
169
138
|
//# sourceMappingURL=update.js.map
|