@fitlab-ai/agent-infra 0.8.5 → 0.9.1
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 +6 -1
- package/README.zh-CN.md +5 -1
- package/bin/cli.ts +2 -2
- package/dist/bin/cli.js +2 -2
- package/dist/bin/internal-cli.js +103 -0
- package/dist/lib/decide.js +81 -90
- package/dist/lib/defaults.json +1 -0
- package/dist/lib/git/review-snapshot.js +79 -0
- package/dist/lib/git/workflow.js +101 -0
- package/dist/lib/internal/git-workflow.js +42 -0
- package/dist/lib/internal/platform-checks.js +119 -0
- package/dist/lib/internal/platform-comment.js +129 -0
- package/dist/lib/internal/platform-context.js +46 -0
- package/dist/lib/internal/platform-issue.js +142 -0
- package/dist/lib/internal/platform-pr.js +146 -0
- package/dist/lib/internal/platform-release-notes.js +53 -0
- package/dist/lib/internal/release-workflow.js +320 -0
- package/dist/lib/internal/task-artifact.js +67 -0
- package/dist/lib/internal/task-context.js +43 -0
- package/dist/lib/internal/task-event.js +70 -0
- package/dist/lib/internal/task-ledger.js +114 -0
- package/dist/lib/internal/task-lifecycle.js +58 -0
- package/dist/lib/internal/task-short-id.js +83 -0
- package/dist/lib/internal/task-snapshot.js +47 -0
- package/dist/lib/internal/task-verify.js +50 -0
- package/dist/lib/internal/task-warning.js +74 -0
- package/dist/lib/platform/adapters.js +14 -0
- package/dist/lib/platform/context.js +146 -0
- package/dist/lib/platform/github-client.js +124 -0
- package/dist/lib/platform/github-release-notes.js +96 -0
- package/dist/lib/platform/issue-comments.js +409 -0
- package/dist/lib/platform/issue-metadata.js +183 -0
- package/dist/lib/platform/issues.js +619 -0
- package/dist/lib/platform/merged-pr-equivalence.js +54 -0
- package/dist/lib/platform/metadata-labels.js +28 -0
- package/dist/lib/platform/pr-checks.js +216 -0
- package/dist/lib/platform/pr-summary.js +88 -0
- package/dist/lib/platform/pull-request-metadata.js +38 -0
- package/dist/lib/platform/pull-requests.js +340 -0
- package/dist/lib/platform/release-notes.js +143 -0
- package/dist/lib/platform/releases.js +82 -0
- package/dist/lib/platform/types.js +22 -0
- package/dist/lib/platform/verification-required.js +102 -0
- package/dist/lib/platform/verification-sync.js +1014 -0
- package/dist/lib/platform/verification.js +6 -0
- package/dist/lib/release/channels.js +31 -0
- package/dist/lib/release/workflow.js +32 -0
- package/dist/lib/render.js +3 -2
- package/dist/lib/run/index.js +24 -7
- package/dist/lib/sandbox/build-proxy.js +63 -0
- package/dist/lib/sandbox/capture.js +25 -3
- package/dist/lib/sandbox/commands/create.js +93 -31
- package/dist/lib/sandbox/commands/enter.js +34 -11
- package/dist/lib/sandbox/commands/list-running.js +10 -8
- package/dist/lib/sandbox/commands/rebuild.js +24 -7
- package/dist/lib/sandbox/commands/show.js +2 -2
- package/dist/lib/sandbox/commands/start.js +53 -15
- package/dist/lib/sandbox/image-build.js +2 -1
- package/dist/lib/sandbox/index.js +6 -6
- package/dist/lib/sandbox/mounts.js +36 -0
- package/dist/lib/sandbox/recovery.js +562 -0
- package/dist/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
- package/dist/lib/sandbox/runtimes/base.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/java17.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/java21.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/node20.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/node22.dockerfile +8 -1
- package/dist/lib/sandbox/runtimes/python3.dockerfile +8 -1
- package/dist/lib/sandbox/shell.js +2 -1
- package/dist/lib/sandbox/task-resolver.js +5 -1
- package/dist/lib/sandbox/tools.js +19 -0
- package/dist/lib/server/protocol.js +5 -5
- package/dist/lib/task/activity-log.js +61 -0
- package/dist/lib/task/artifact-lifecycle.js +427 -0
- package/dist/lib/task/command-options.js +30 -0
- package/dist/lib/task/commands/cat.js +36 -6
- package/dist/lib/task/commands/decisions.js +80 -46
- package/dist/lib/task/commands/files.js +21 -7
- package/dist/lib/task/commands/grep.js +55 -7
- package/dist/lib/task/commands/issue-body.js +33 -19
- package/dist/lib/task/commands/log.js +27 -70
- package/dist/lib/task/commands/show.js +20 -7
- package/dist/lib/task/commands/status.js +18 -8
- package/dist/lib/task/decision-intents.js +154 -0
- package/dist/lib/task/decision-items.js +53 -0
- package/dist/lib/task/events.js +318 -0
- package/dist/lib/task/frontmatter.js +159 -1
- package/dist/lib/task/implementation-inputs.js +117 -0
- package/dist/lib/task/index.js +12 -9
- package/dist/lib/task/issue-form.js +21 -6
- package/dist/lib/task/ledger-intents.js +185 -0
- package/dist/lib/task/ledger.js +65 -35
- package/dist/lib/task/lifecycle.js +484 -0
- package/dist/lib/task/resolve-ref.js +152 -32
- package/dist/lib/task/review-artifacts.js +101 -0
- package/dist/lib/task/review-fingerprint.js +55 -0
- package/dist/lib/task/sections.js +358 -4
- package/dist/lib/task/short-id.js +292 -7
- package/dist/lib/task/snapshot.js +95 -0
- package/dist/lib/task/verification-checks.js +8 -0
- package/dist/lib/task/verification-config.js +14 -0
- package/dist/lib/task/verification-engine.js +923 -0
- package/dist/lib/task/verification-review.js +3 -0
- package/dist/lib/task/verification-types.js +2 -0
- package/dist/lib/task/verification.js +113 -0
- package/dist/lib/task/workflow-warning-intents.js +131 -0
- package/dist/lib/task/workflow-warnings.js +10 -78
- package/dist/lib/task/write.js +241 -0
- package/lib/decide.ts +57 -97
- package/lib/defaults.json +1 -0
- package/lib/git/review-snapshot.ts +73 -0
- package/lib/git/workflow.ts +101 -0
- package/lib/internal/git-workflow.ts +37 -0
- package/lib/internal/platform-checks.ts +101 -0
- package/lib/internal/platform-comment.ts +99 -0
- package/lib/internal/platform-context.ts +33 -0
- package/lib/internal/platform-issue.ts +116 -0
- package/lib/internal/platform-pr.ts +119 -0
- package/lib/internal/platform-release-notes.ts +55 -0
- package/lib/internal/release-workflow.ts +288 -0
- package/lib/internal/task-artifact.ts +47 -0
- package/lib/internal/task-context.ts +35 -0
- package/lib/internal/task-event.ts +51 -0
- package/lib/internal/task-ledger.ts +86 -0
- package/lib/internal/task-lifecycle.ts +41 -0
- package/lib/internal/task-short-id.ts +55 -0
- package/lib/internal/task-snapshot.ts +32 -0
- package/lib/internal/task-verify.ts +33 -0
- package/lib/internal/task-warning.ts +50 -0
- package/lib/platform/adapters.ts +30 -0
- package/lib/platform/context.ts +164 -0
- package/lib/platform/github-client.ts +146 -0
- package/lib/platform/github-release-notes.ts +132 -0
- package/lib/platform/issue-comments.ts +479 -0
- package/lib/platform/issue-metadata.ts +250 -0
- package/lib/platform/issues.ts +693 -0
- package/lib/platform/merged-pr-equivalence.ts +70 -0
- package/lib/platform/metadata-labels.ts +33 -0
- package/lib/platform/pr-checks.ts +247 -0
- package/lib/platform/pr-summary.ts +90 -0
- package/lib/platform/pull-request-metadata.ts +69 -0
- package/lib/platform/pull-requests.ts +386 -0
- package/lib/platform/release-notes.ts +167 -0
- package/lib/platform/releases.ts +71 -0
- package/lib/platform/types.ts +74 -0
- package/lib/platform/verification-required.ts +109 -0
- package/{runtime/platform-adapters/platform-sync.github.js → lib/platform/verification-sync.ts} +198 -367
- package/lib/platform/verification.ts +11 -0
- package/lib/release/channels.ts +30 -0
- package/lib/release/workflow.ts +31 -0
- package/lib/render.ts +3 -2
- package/lib/run/index.ts +25 -7
- package/lib/sandbox/build-proxy.ts +94 -0
- package/lib/sandbox/capture.ts +29 -3
- package/lib/sandbox/commands/create.ts +120 -36
- package/lib/sandbox/commands/enter.ts +38 -11
- package/lib/sandbox/commands/list-running.ts +10 -8
- package/lib/sandbox/commands/rebuild.ts +29 -7
- package/lib/sandbox/commands/show.ts +2 -2
- package/lib/sandbox/commands/start.ts +50 -16
- package/lib/sandbox/image-build.ts +4 -1
- package/lib/sandbox/index.ts +6 -6
- package/lib/sandbox/mounts.ts +55 -0
- package/lib/sandbox/recovery.ts +828 -0
- package/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
- package/lib/sandbox/runtimes/base.dockerfile +8 -1
- package/lib/sandbox/runtimes/java17.dockerfile +8 -1
- package/lib/sandbox/runtimes/java21.dockerfile +8 -1
- package/lib/sandbox/runtimes/node20.dockerfile +8 -1
- package/lib/sandbox/runtimes/node22.dockerfile +8 -1
- package/lib/sandbox/runtimes/python3.dockerfile +8 -1
- package/lib/sandbox/shell.ts +3 -1
- package/lib/sandbox/task-resolver.ts +5 -1
- package/lib/sandbox/tools.ts +31 -0
- package/lib/server/protocol.ts +5 -5
- package/lib/task/activity-log.ts +62 -0
- package/lib/task/artifact-lifecycle.ts +484 -0
- package/lib/task/command-options.ts +32 -0
- package/lib/task/commands/cat.ts +22 -9
- package/lib/task/commands/decisions.ts +49 -47
- package/lib/task/commands/files.ts +14 -6
- package/lib/task/commands/grep.ts +34 -7
- package/lib/task/commands/issue-body.ts +26 -21
- package/lib/task/commands/log.ts +17 -70
- package/lib/task/commands/show.ts +14 -6
- package/lib/task/commands/status.ts +17 -7
- package/lib/task/decision-intents.ts +163 -0
- package/lib/task/decision-items.ts +64 -0
- package/lib/task/events.ts +320 -0
- package/lib/task/frontmatter.ts +202 -2
- package/lib/task/implementation-inputs.ts +137 -0
- package/lib/task/index.ts +12 -9
- package/lib/task/issue-form.ts +24 -6
- package/lib/task/ledger-intents.ts +201 -0
- package/lib/task/ledger.ts +77 -31
- package/lib/task/lifecycle.ts +458 -0
- package/lib/task/resolve-ref.ts +197 -36
- package/{templates/.agents/scripts/lib/review-artifacts.js → lib/task/review-artifacts.ts} +11 -12
- package/{templates/.agents/scripts/lib/post-review-commit.js → lib/task/review-fingerprint.ts} +26 -12
- package/lib/task/sections.ts +486 -4
- package/lib/task/short-id.ts +403 -9
- package/lib/task/snapshot.ts +143 -0
- package/lib/task/verification-checks.ts +9 -0
- package/lib/task/verification-config.ts +20 -0
- package/{templates/.agents/scripts/validate-artifact.js → lib/task/verification-engine.ts} +230 -421
- package/lib/task/verification-review.ts +10 -0
- package/lib/task/verification-types.ts +29 -0
- package/lib/task/verification.ts +156 -0
- package/lib/task/workflow-warning-intents.ts +142 -0
- package/lib/task/workflow-warnings.ts +10 -78
- package/lib/task/write.ts +468 -0
- package/package.json +4 -2
- package/templates/.agents/README.en.md +4 -3
- package/templates/.agents/README.zh-CN.md +4 -3
- package/templates/.agents/rules/README.en.md +6 -5
- package/templates/.agents/rules/README.zh-CN.md +6 -5
- package/templates/.agents/rules/create-issue.en.md +1 -1
- package/templates/.agents/rules/create-issue.github.en.md +5 -184
- package/templates/.agents/rules/create-issue.github.zh-CN.md +12 -178
- package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
- package/templates/.agents/rules/human-decision-context.en.md +36 -0
- package/templates/.agents/rules/human-decision-context.zh-CN.md +36 -0
- package/templates/.agents/rules/issue-fields.github.en.md +4 -148
- package/templates/.agents/rules/issue-fields.github.zh-CN.md +9 -144
- package/templates/.agents/rules/issue-pr-commands.en.md +43 -3
- package/templates/.agents/rules/issue-pr-commands.github.en.md +15 -220
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +23 -213
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +45 -3
- package/templates/.agents/rules/issue-sync.en.md +1 -1
- package/templates/.agents/rules/issue-sync.github.en.md +14 -301
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +36 -287
- package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
- package/templates/.agents/rules/milestone-inference.en.md +1 -1
- package/templates/.agents/rules/milestone-inference.github.en.md +7 -119
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +8 -108
- package/templates/.agents/rules/milestone-inference.zh-CN.md +1 -1
- package/templates/.agents/rules/next-step-output.en.md +12 -11
- package/templates/.agents/rules/next-step-output.zh-CN.md +12 -11
- package/templates/.agents/rules/no-mid-flow-questions.en.md +3 -3
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.en.md +16 -3
- package/templates/.agents/rules/pr-checks-commands.github.en.md +10 -54
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +19 -47
- package/templates/.agents/rules/pr-checks-commands.zh-CN.md +30 -3
- package/templates/.agents/rules/pr-sync.en.md +30 -3
- package/templates/.agents/rules/pr-sync.github.en.md +12 -115
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +26 -104
- package/templates/.agents/rules/pr-sync.zh-CN.md +43 -3
- package/templates/.agents/rules/release-commands.en.md +2 -2
- package/templates/.agents/rules/release-commands.github.en.md +10 -40
- package/templates/.agents/rules/release-commands.github.zh-CN.md +9 -39
- package/templates/.agents/rules/release-commands.zh-CN.md +2 -2
- package/templates/.agents/rules/review-handshake.en.md +10 -6
- package/templates/.agents/rules/review-handshake.zh-CN.md +10 -6
- package/templates/.agents/rules/task-management.en.md +11 -2
- package/templates/.agents/rules/task-management.zh-CN.md +11 -3
- package/templates/.agents/rules/task-short-id.en.md +25 -29
- package/templates/.agents/rules/task-short-id.zh-CN.md +20 -23
- package/templates/.agents/rules/testing-discipline.en.md +20 -2
- package/templates/.agents/rules/testing-discipline.zh-CN.md +20 -2
- package/templates/.agents/scripts/lib/agent-infra-package.js +1 -9
- package/templates/.agents/scripts/task-short-id.js +71 -533
- package/templates/.agents/skills/analyze-task/SKILL.en.md +26 -56
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +30 -60
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -3
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/block-task/SKILL.en.md +21 -47
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +23 -47
- package/templates/.agents/skills/block-task/config/verify.json +1 -2
- package/templates/.agents/skills/cancel-task/SKILL.en.md +16 -45
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +16 -45
- package/templates/.agents/skills/cancel-task/config/verify.json +1 -2
- package/templates/.agents/skills/check-task/SKILL.en.md +6 -3
- package/templates/.agents/skills/check-task/SKILL.zh-CN.md +6 -3
- package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -24
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -24
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -24
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -24
- package/templates/.agents/skills/code-task/SKILL.en.md +22 -35
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +28 -44
- package/templates/.agents/skills/code-task/config/verify.en.json +3 -3
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -3
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +13 -9
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +13 -9
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +11 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +11 -1
- package/templates/.agents/skills/commit/SKILL.en.md +13 -11
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +13 -11
- package/templates/.agents/skills/commit/config/verify.json +1 -2
- package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -11
- package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -11
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +4 -8
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +4 -8
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +6 -18
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +5 -17
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +13 -0
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +13 -0
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +13 -36
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +13 -36
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -3
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +10 -54
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +10 -79
- package/templates/.agents/skills/complete-task/SKILL.en.md +59 -63
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +59 -63
- package/templates/.agents/skills/complete-task/config/verify.en.json +10 -7
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +10 -7
- package/templates/.agents/skills/create-pr/SKILL.en.md +19 -44
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +19 -43
- package/templates/.agents/skills/create-pr/config/verify.json +1 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +8 -12
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +7 -11
- package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -38
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +16 -37
- package/templates/.agents/skills/create-task/SKILL.en.md +16 -13
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +16 -13
- package/templates/.agents/skills/create-task/config/verify.json +1 -2
- package/templates/.agents/skills/create-task/reference/context-capture.en.md +29 -0
- package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +29 -0
- package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/import-codescan/config/verify.json +1 -2
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/import-dependabot/config/verify.json +1 -2
- package/templates/.agents/skills/import-issue/SKILL.en.md +9 -13
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +10 -14
- package/templates/.agents/skills/import-issue/config/verify.json +1 -2
- package/templates/.agents/skills/plan-task/SKILL.en.md +17 -42
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +22 -49
- package/templates/.agents/skills/plan-task/config/verify.en.json +1 -3
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/post-release/SKILL.en.md +11 -81
- package/templates/.agents/skills/post-release/SKILL.zh-CN.md +8 -78
- package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
- package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/release/SKILL.en.md +16 -163
- package/templates/.agents/skills/release/SKILL.zh-CN.md +15 -162
- package/templates/.agents/skills/restore-task/SKILL.en.md +11 -29
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +11 -29
- package/templates/.agents/skills/restore-task/config/verify.json +1 -2
- package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -25
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +13 -33
- package/templates/.agents/skills/review-analysis/config/verify.en.json +3 -4
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +3 -4
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +9 -12
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +9 -12
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +9 -2
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +9 -2
- package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +7 -0
- package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +7 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +22 -36
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +23 -41
- package/templates/.agents/skills/review-code/config/verify.en.json +3 -4
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +3 -4
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +56 -18
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +56 -18
- package/templates/.agents/skills/review-code/reference/report-template.en.md +11 -4
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +11 -4
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +7 -0
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +7 -0
- package/templates/.agents/skills/review-plan/SKILL.en.md +13 -25
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +13 -33
- package/templates/.agents/skills/review-plan/config/verify.en.json +3 -4
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +3 -4
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +9 -12
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +9 -12
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +9 -2
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +9 -2
- package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +7 -0
- package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +7 -0
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -2
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +3 -15
- package/templates/.agents/skills/watch-pr/SKILL.en.md +24 -14
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +25 -15
- package/templates/.agents/skills/watch-pr/config/verify.json +1 -2
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +2 -2
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +2 -2
- package/templates/.agents/templates/task.en.md +24 -1
- package/templates/.agents/templates/task.zh-CN.md +24 -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 -0
- package/templates/.claude/commands/commit.zh-CN.md +1 -0
- 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/watch-pr.en.md +1 -1
- package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
- package/templates/.gemini/commands/_project_/analyze-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/block-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/cancel-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/check-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/code-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/commit.en.toml +4 -0
- package/templates/.gemini/commands/_project_/commit.zh-CN.toml +4 -0
- package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +2 -0
- package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/complete-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/create-pr.en.toml +2 -0
- package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/plan-task.en.toml +2 -0
- package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/review-analysis.en.toml +2 -0
- package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/review-code.en.toml +2 -0
- package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/review-plan.en.toml +2 -0
- package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +2 -0
- package/templates/.gemini/commands/_project_/watch-pr.en.toml +2 -0
- package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +2 -0
- package/templates/.git-hooks/check-large-files.cjs +92 -0
- package/templates/.git-hooks/check-version-format.sh +5 -1
- package/templates/.git-hooks/pre-commit +1 -0
- package/templates/.opencode/commands/analyze-task.en.md +1 -1
- package/templates/.opencode/commands/analyze-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/check-task.en.md +1 -1
- package/templates/.opencode/commands/check-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/code-task.en.md +1 -1
- package/templates/.opencode/commands/code-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/commit.en.md +2 -0
- package/templates/.opencode/commands/commit.zh-CN.md +2 -0
- package/templates/.opencode/commands/complete-task.en.md +1 -1
- package/templates/.opencode/commands/complete-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/plan-task.en.md +1 -1
- package/templates/.opencode/commands/plan-task.zh-CN.md +1 -1
- package/templates/.opencode/commands/review-analysis.en.md +1 -1
- package/templates/.opencode/commands/review-analysis.zh-CN.md +1 -1
- package/templates/.opencode/commands/review-code.en.md +1 -1
- package/templates/.opencode/commands/review-code.zh-CN.md +1 -1
- package/templates/.opencode/commands/review-plan.en.md +1 -1
- package/templates/.opencode/commands/review-plan.zh-CN.md +1 -1
- package/templates/.agents/scripts/platform-adapters/platform-sync.github.js +0 -40
- package/templates/.agents/scripts/platform-adapters/platform-sync.js +0 -13
- package/templates/.agents/scripts/review-diff-fingerprint.js +0 -170
- package/templates/.agents/scripts/workflow-warnings.js +0 -290
- package/templates/.agents/skills/code-task/scripts/detect-mode.js +0 -257
- package/templates/.agents/skills/release/scripts/manage-milestones.github.sh +0 -80
- package/templates/.agents/skills/release/scripts/manage-milestones.sh +0 -6
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { appendActivityEntry, locateActivityLog, pairEntries } from './activity-log.js';
|
|
3
|
+
import { buildArtifactLinkSection, artifactName, parseArtifactName, resolveArtifactContext, validateCompletedArtifact } from './artifact-lifecycle.js';
|
|
4
|
+
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
5
|
+
import { consumeImplementationInput, IMPLEMENTATION_INPUT_ALIASES, parseImplementationInputs, renderImplementationInputs } from './implementation-inputs.js';
|
|
6
|
+
import { resolveTaskRef } from './resolve-ref.js';
|
|
7
|
+
import { findSectionHeading } from './sections.js';
|
|
8
|
+
import { captureTaskWriteMetadata, writeTask } from './write.js';
|
|
9
|
+
const eventCatalog = [
|
|
10
|
+
'analyze.started', 'analyze.awaiting-input', 'analyze.completed',
|
|
11
|
+
'review-analysis.started', 'review-analysis.completed',
|
|
12
|
+
'plan.started', 'plan.completed',
|
|
13
|
+
'review-plan.started', 'review-plan.completed',
|
|
14
|
+
'code.started', 'code.completed',
|
|
15
|
+
'review-code.started', 'review-code.completed',
|
|
16
|
+
'manual-validation.started', 'manual-validation.completed'
|
|
17
|
+
];
|
|
18
|
+
const BASE_FIELDS = new Set(['taskRef', 'event', 'agent', 'dryRun']);
|
|
19
|
+
const SCHEMAS = {
|
|
20
|
+
'analyze.started': { optional: ['round'] },
|
|
21
|
+
'analyze.awaiting-input': { required: ['question'] },
|
|
22
|
+
'analyze.completed': { required: ['artifact'], optional: ['round'] },
|
|
23
|
+
'review-analysis.started': { optional: ['round'] },
|
|
24
|
+
'review-analysis.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
|
|
25
|
+
'plan.started': { optional: ['round'] },
|
|
26
|
+
'plan.completed': { required: ['artifact'], optional: ['round'] },
|
|
27
|
+
'review-plan.started': { optional: ['round'] },
|
|
28
|
+
'review-plan.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
|
|
29
|
+
'code.started': { optional: ['round', 'fixFor', 'implementationInput'] },
|
|
30
|
+
'code.completed': { required: ['artifact'], optional: ['round', 'fixFor', 'implementationInput', 'filesModified', 'testsPassed', 'blockers', 'major', 'minor', 'manualValidation'] },
|
|
31
|
+
'review-code.started': { optional: ['round'] },
|
|
32
|
+
'review-code.completed': { required: ['artifact', 'verdict', 'blockers', 'major', 'minor', 'manualValidation'], optional: ['round'] },
|
|
33
|
+
'manual-validation.started': { optional: ['round'] },
|
|
34
|
+
'manual-validation.completed': { required: ['artifact', 'summaryResult'], optional: ['round'] }
|
|
35
|
+
};
|
|
36
|
+
function validateTaskEventRequest(request) {
|
|
37
|
+
if (!eventCatalog.includes(request.event))
|
|
38
|
+
return { code: 'EVENT_UNKNOWN', message: `unknown task event '${request.event}'` };
|
|
39
|
+
if (!request.taskRef || !request.agent)
|
|
40
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: 'taskRef and agent are required' };
|
|
41
|
+
const schema = SCHEMAS[request.event];
|
|
42
|
+
const required = schema.required ?? [];
|
|
43
|
+
const allowed = new Set([...BASE_FIELDS, ...required, ...(schema.optional ?? [])]);
|
|
44
|
+
for (const [key, value] of Object.entries(request)) {
|
|
45
|
+
if (value !== undefined && !allowed.has(key))
|
|
46
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: `${request.event} does not accept '${key}'` };
|
|
47
|
+
}
|
|
48
|
+
for (const key of required)
|
|
49
|
+
if (request[key] === undefined)
|
|
50
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: `${request.event} requires '${key}'` };
|
|
51
|
+
for (const key of ['round', 'question', 'blockers', 'major', 'minor', 'manualValidation', 'filesModified', 'testsPassed']) {
|
|
52
|
+
const value = request[key];
|
|
53
|
+
if (value !== undefined && (!Number.isInteger(value) || value < (key === 'round' || key === 'question' ? 1 : 0)))
|
|
54
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: `'${key}' must be a ${key === 'round' || key === 'question' ? 'positive' : 'non-negative'} integer` };
|
|
55
|
+
}
|
|
56
|
+
if (request.verdict && !['approved', 'changes-requested', 'rejected'].includes(request.verdict))
|
|
57
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: 'verdict is invalid' };
|
|
58
|
+
if (request.event === 'code.completed') {
|
|
59
|
+
const fix = request.fixFor !== undefined || ['blockers', 'major', 'minor', 'manualValidation'].some((key) => request[key] !== undefined);
|
|
60
|
+
const modeRequired = fix ? ['fixFor', 'blockers', 'major', 'minor', 'manualValidation'] : ['filesModified', 'testsPassed'];
|
|
61
|
+
const forbidden = fix ? ['filesModified', 'testsPassed'] : ['fixFor', 'blockers', 'major', 'minor', 'manualValidation'];
|
|
62
|
+
if (modeRequired.some((key) => request[key] === undefined) || forbidden.some((key) => request[key] !== undefined))
|
|
63
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: 'code.completed requires either initial or fix completion payload' };
|
|
64
|
+
}
|
|
65
|
+
if (request.fixFor && !/^review-code(?:-r(?:[2-9]|[1-9]\d+))?\.md$/.test(request.fixFor))
|
|
66
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: 'fixFor must reference a canonical review-code artifact' };
|
|
67
|
+
if (request.implementationInput && !/^II-[1-9]\d*$/.test(request.implementationInput))
|
|
68
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: 'implementationInput must be a canonical II-N id' };
|
|
69
|
+
if (request.fixFor && request.implementationInput)
|
|
70
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: 'fixFor and implementationInput are mutually exclusive' };
|
|
71
|
+
if (request.summaryResult !== undefined && (!request.summaryResult.trim() || /[\r\n]/.test(request.summaryResult)))
|
|
72
|
+
return { code: 'EVENT_PAYLOAD_INVALID', message: 'summaryResult must be a non-empty single line' };
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const FAMILY = {
|
|
76
|
+
analyze: { artifact: 'analysis', started: ['requirement-analysis', 'requirement-analysis-review', 'code'], completed: ['requirement-analysis', 'requirement-analysis-review', 'code'], target: 'requirement-analysis', label: 'Analyze Task' },
|
|
77
|
+
'review-analysis': { artifact: 'review-analysis', started: ['requirement-analysis', 'requirement-analysis-review'], completed: ['requirement-analysis', 'requirement-analysis-review'], target: 'requirement-analysis-review', label: 'Review Analysis' },
|
|
78
|
+
plan: { artifact: 'plan', started: ['requirement-analysis-review', 'technical-design-review'], completed: ['requirement-analysis-review', 'technical-design-review'], target: 'technical-design', label: 'Plan Task' },
|
|
79
|
+
'review-plan': { artifact: 'review-plan', started: ['technical-design', 'technical-design-review'], completed: ['technical-design', 'technical-design-review'], target: 'technical-design-review', label: 'Review Plan' },
|
|
80
|
+
code: { artifact: 'code', started: ['technical-design-review', 'code-review'], completed: ['technical-design-review', 'code-review'], target: 'code', label: 'Code Task' },
|
|
81
|
+
'review-code': { artifact: 'review-code', started: ['code', 'code-review', 'commit'], completed: ['code', 'code-review', 'commit'], target: 'code-review', label: 'Review Code' },
|
|
82
|
+
'manual-validation': { artifact: 'manual-validation', started: ['code-review', 'commit'], completed: ['code-review', 'commit'], target: null, label: 'Complete Manual Validation' }
|
|
83
|
+
};
|
|
84
|
+
function eventParts(event) {
|
|
85
|
+
const [family, suffix] = event.split('.');
|
|
86
|
+
return { family, phase: suffix === 'started' ? 'started' : suffix === 'awaiting-input' ? 'waiting' : 'completed' };
|
|
87
|
+
}
|
|
88
|
+
function identity(request) {
|
|
89
|
+
const { family, phase } = eventParts(request.event);
|
|
90
|
+
if (phase === 'waiting')
|
|
91
|
+
return { family, phase, action: 'Analyze Task (Brainstorming)', note: `Asked Q${request.question}, awaiting answer`, target: FAMILY.analyze.target };
|
|
92
|
+
const spec = FAMILY[family];
|
|
93
|
+
if (family === 'manual-validation') {
|
|
94
|
+
return {
|
|
95
|
+
family, phase, action: spec.label,
|
|
96
|
+
note: phase === 'started' ? 'started' : `Manual validation passed → ${request.artifact}; ${request.summaryResult}`,
|
|
97
|
+
target: null
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const qualifier = request.fixFor
|
|
101
|
+
? `, fix for ${request.fixFor}`
|
|
102
|
+
: request.implementationInput ? `, decision ${request.implementationInput}` : '';
|
|
103
|
+
const action = `${spec.label} (Round ${request.round}${qualifier})`;
|
|
104
|
+
if (phase === 'started')
|
|
105
|
+
return { family, phase, action, note: 'started', target: null };
|
|
106
|
+
let note = '';
|
|
107
|
+
if (family === 'analyze')
|
|
108
|
+
note = `Analysis completed → ${request.artifact}`;
|
|
109
|
+
else if (family === 'plan')
|
|
110
|
+
note = `Plan completed, awaiting human review → ${request.artifact}`;
|
|
111
|
+
else if (family === 'code' && request.fixFor)
|
|
112
|
+
note = `Fixed ${request.blockers} blockers, ${request.major} major, ${request.minor} minor issues${request.manualValidation ? `, skipped ${request.manualValidation} manual-validation` : ''} → ${request.artifact}`;
|
|
113
|
+
else if (family === 'code')
|
|
114
|
+
note = `Code implemented, ${request.filesModified} files modified, ${request.testsPassed} tests passed → ${request.artifact}`;
|
|
115
|
+
else {
|
|
116
|
+
const verdict = request.verdict === 'approved' ? 'Approved' : request.verdict === 'changes-requested' ? 'Changes Requested' : 'Rejected';
|
|
117
|
+
note = `Verdict: ${verdict}, blockers: ${request.blockers}, major: ${request.major}, minor: ${request.minor}, Manual-validation: ${request.manualValidation} → ${request.artifact}`;
|
|
118
|
+
}
|
|
119
|
+
return { family, phase, action, note, target: spec.target };
|
|
120
|
+
}
|
|
121
|
+
function failed(request, error, extra = {}) {
|
|
122
|
+
return {
|
|
123
|
+
status: 'failed', changed: false, event: request.event, requestRef: request.taskRef,
|
|
124
|
+
taskId: null, taskMdPath: null, fromStep: null, toStep: null, action: null,
|
|
125
|
+
phase: null, round: request.round ?? null, artifact: request.artifact ?? null,
|
|
126
|
+
fixFor: request.fixFor ?? null, implementationInput: request.implementationInput ?? null,
|
|
127
|
+
artifactContext: null, timestamp: null,
|
|
128
|
+
agentInfraVersion: null, operations: [], error, ...extra
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function normalizeStarted(request, repoRoot) {
|
|
132
|
+
const family = eventParts(request.event).family;
|
|
133
|
+
const context = resolveArtifactContext(request.taskRef, FAMILY[family].artifact, { repoRoot });
|
|
134
|
+
if (context.status !== 'ready' || !context.next) {
|
|
135
|
+
return { error: { code: context.error?.code ?? 'EVENT_ARTIFACT_CONFLICT', message: context.error?.message ?? context.codeMode?.message ?? 'artifact context is not writable' }, context };
|
|
136
|
+
}
|
|
137
|
+
const round = context.next.round;
|
|
138
|
+
if (request.round !== undefined && request.round !== round)
|
|
139
|
+
return { error: { code: 'EVENT_ARTIFACT_CONFLICT', message: `round ${request.round} conflicts with expected round ${round}` }, context };
|
|
140
|
+
const expectedFix = family === 'code' && context.codeMode?.mode === 'fix' ? context.codeMode.reviewArtifact ?? undefined : undefined;
|
|
141
|
+
const expectedImplementation = family === 'code' && context.codeMode?.mode === 'decision'
|
|
142
|
+
? context.codeMode.implementationInput ?? undefined : undefined;
|
|
143
|
+
if (request.fixFor !== undefined && request.fixFor !== expectedFix)
|
|
144
|
+
return { error: { code: 'EVENT_ARTIFACT_CONFLICT', message: `fixFor '${request.fixFor}' conflicts with artifact context` }, context };
|
|
145
|
+
if (request.implementationInput !== expectedImplementation)
|
|
146
|
+
return { error: { code: 'EVENT_ARTIFACT_CONFLICT', message: `implementationInput '${request.implementationInput ?? ''}' conflicts with artifact context` }, context };
|
|
147
|
+
return { request: { ...request, round, artifact: context.next.name, fixFor: expectedFix, implementationInput: expectedImplementation }, context };
|
|
148
|
+
}
|
|
149
|
+
function openStartedIdentity(rows, family) {
|
|
150
|
+
const spec = FAMILY[family];
|
|
151
|
+
if (family === 'manual-validation') {
|
|
152
|
+
const row = rows.filter((item) => item.step === spec.label && item.started && !item.done).at(-1);
|
|
153
|
+
const completed = rows.filter((item) => item.step === spec.label && item.done).length;
|
|
154
|
+
return row ? { row, round: completed + 1, fixFor: undefined, implementationInput: undefined } : null;
|
|
155
|
+
}
|
|
156
|
+
const escaped = spec.label.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
157
|
+
const pattern = new RegExp(`^${escaped} \\(Round (\\d+)(?:(?:, fix for (review-code(?:-r\\d+)?\\.md))|(?:, decision (II-[1-9]\\d*)))?\\)$`);
|
|
158
|
+
const matches = rows.flatMap((row) => {
|
|
159
|
+
if (!row.started || row.done)
|
|
160
|
+
return [];
|
|
161
|
+
const match = pattern.exec(row.step);
|
|
162
|
+
return match ? [{ row, round: Number(match[1]), fixFor: match[2], implementationInput: match[3] }] : [];
|
|
163
|
+
});
|
|
164
|
+
return matches.length === 1 ? matches[0] : matches.length > 1 ? { conflict: true } : null;
|
|
165
|
+
}
|
|
166
|
+
function applyTaskEvent(request, options = {}) {
|
|
167
|
+
const invalid = validateTaskEventRequest(request);
|
|
168
|
+
if (invalid)
|
|
169
|
+
return failed(request, invalid);
|
|
170
|
+
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
171
|
+
if (!resolved.ok)
|
|
172
|
+
return failed(request, { code: resolved.code, message: resolved.message }, { taskId: resolved.taskId });
|
|
173
|
+
if (resolved.state !== 'active')
|
|
174
|
+
return failed(request, { code: 'TASK_STATE_MISMATCH', message: `task ${resolved.taskId} is ${resolved.state}, expected active` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
175
|
+
let content;
|
|
176
|
+
try {
|
|
177
|
+
content = fs.readFileSync(resolved.taskMdPath, 'utf8');
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
return failed(request, { code: 'TASK_READ_FAILED', message: String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
181
|
+
}
|
|
182
|
+
let frontmatter;
|
|
183
|
+
try {
|
|
184
|
+
frontmatter = parseTypedTaskFrontmatter(content);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
return failed(request, { code: 'TASK_DOCUMENT_INVALID', message: error instanceof Error ? error.message : String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
188
|
+
}
|
|
189
|
+
const section = locateActivityLog(content);
|
|
190
|
+
if (!section)
|
|
191
|
+
return failed(request, { code: 'EVENT_LOG_MISSING', message: 'task has no unique Activity Log section' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
192
|
+
const rows = pairEntries(section.entries);
|
|
193
|
+
let normalized = request;
|
|
194
|
+
let artifactContext = null;
|
|
195
|
+
const initialParts = eventParts(request.event);
|
|
196
|
+
if (initialParts.phase === 'started') {
|
|
197
|
+
const openIdentity = openStartedIdentity(rows, initialParts.family);
|
|
198
|
+
if (openIdentity && 'conflict' in openIdentity)
|
|
199
|
+
return failed(request, { code: 'EVENT_LOG_CONFLICT', message: 'artifact family has more than one open started event' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
200
|
+
if (openIdentity) {
|
|
201
|
+
if (openIdentity.row.agent !== request.agent)
|
|
202
|
+
return failed(request, { code: 'EVENT_LOG_CONFLICT', message: 'open started event has a different agent' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
203
|
+
if (request.round !== undefined && request.round !== openIdentity.round)
|
|
204
|
+
return failed(request, { code: 'EVENT_ARTIFACT_CONFLICT', message: `round ${request.round} conflicts with open round ${openIdentity.round}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
205
|
+
if (request.fixFor !== undefined && request.fixFor !== openIdentity.fixFor)
|
|
206
|
+
return failed(request, { code: 'EVENT_ARTIFACT_CONFLICT', message: `fixFor '${request.fixFor}' conflicts with open event` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
207
|
+
if (request.implementationInput !== openIdentity.implementationInput)
|
|
208
|
+
return failed(request, { code: 'EVENT_ARTIFACT_CONFLICT', message: `implementationInput '${request.implementationInput ?? ''}' conflicts with open event` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
209
|
+
normalized = { ...request, round: openIdentity.round, artifact: artifactName(FAMILY[initialParts.family].artifact, openIdentity.round), fixFor: openIdentity.fixFor, implementationInput: openIdentity.implementationInput };
|
|
210
|
+
return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, typeof frontmatter.current_step === 'string' ? frontmatter.current_step : '', identity(normalized), openIdentity.row.started, frontmatter, null);
|
|
211
|
+
}
|
|
212
|
+
const result = normalizeStarted(request, resolved.repoRoot);
|
|
213
|
+
artifactContext = result.context;
|
|
214
|
+
if ('error' in result)
|
|
215
|
+
return failed(request, result.error, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, artifactContext });
|
|
216
|
+
normalized = result.request;
|
|
217
|
+
}
|
|
218
|
+
else if (initialParts.phase === 'completed') {
|
|
219
|
+
const identity = request.artifact ? parseArtifactName(request.artifact) : null;
|
|
220
|
+
if (identity?.family === FAMILY[initialParts.family].artifact)
|
|
221
|
+
normalized = { ...request, round: identity.round };
|
|
222
|
+
}
|
|
223
|
+
const eventIdentity = identity(normalized);
|
|
224
|
+
const currentStep = typeof frontmatter.current_step === 'string' ? frontmatter.current_step : '';
|
|
225
|
+
const matchingRows = rows.filter((item) => item.step === eventIdentity.action);
|
|
226
|
+
const manual = eventIdentity.family === 'manual-validation';
|
|
227
|
+
if (!manual && matchingRows.length > 1)
|
|
228
|
+
return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'event identity appears more than once' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
|
|
229
|
+
const openRows = matchingRows.filter((item) => item.started && !item.done);
|
|
230
|
+
const completedRows = matchingRows.filter((item) => item.done);
|
|
231
|
+
const row = manual ? openRows.at(-1) : matchingRows[0];
|
|
232
|
+
let completedArtifact = null;
|
|
233
|
+
if (eventIdentity.phase === 'started' && row) {
|
|
234
|
+
if (row.agent !== normalized.agent)
|
|
235
|
+
return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'open started event has a different agent' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
236
|
+
return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, row.started, frontmatter, artifactContext);
|
|
237
|
+
}
|
|
238
|
+
if (eventIdentity.phase === 'started' && !manual && completedRows.length > 0)
|
|
239
|
+
return failed(normalized, { code: 'EVENT_ALREADY_COMPLETED', message: 'event identity is already completed' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
240
|
+
const done = completedRows.find((item) => item.note === eventIdentity.note);
|
|
241
|
+
if (eventIdentity.phase === 'completed' && done)
|
|
242
|
+
return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, done.done, frontmatter, artifactContext);
|
|
243
|
+
if (eventIdentity.phase === 'completed' && completedRows.length > 0 && openRows.length === 0)
|
|
244
|
+
return failed(normalized, { code: 'EVENT_LOG_CONFLICT', message: 'event identity is already completed with a different payload' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
245
|
+
if (eventIdentity.phase === 'completed' && !row?.started)
|
|
246
|
+
return failed(normalized, { code: 'EVENT_START_MISSING', message: 'completion requires one open matching started event' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
247
|
+
if (eventIdentity.phase === 'completed') {
|
|
248
|
+
const validated = validateCompletedArtifact(resolved.taskDir, FAMILY[eventIdentity.family].artifact, normalized.artifact, normalized.round);
|
|
249
|
+
if (!validated.ok)
|
|
250
|
+
return failed(normalized, validated.error, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
251
|
+
completedArtifact = validated.artifact;
|
|
252
|
+
}
|
|
253
|
+
if (eventIdentity.phase === 'waiting' && section.entries.some((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note)) {
|
|
254
|
+
const existing = section.entries.find((entry) => entry.step === eventIdentity.action && entry.note === eventIdentity.note);
|
|
255
|
+
return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, existing.time, frontmatter, artifactContext);
|
|
256
|
+
}
|
|
257
|
+
const allowed = FAMILY[eventIdentity.family][eventIdentity.phase === 'started' ? 'started' : 'completed'];
|
|
258
|
+
if (!allowed.includes(currentStep))
|
|
259
|
+
return failed(normalized, { code: 'EVENT_TRANSITION_INVALID', message: `${normalized.event} is not allowed from '${currentStep}'` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
260
|
+
let metadata;
|
|
261
|
+
try {
|
|
262
|
+
metadata = (options.metadataProvider ?? captureTaskWriteMetadata)();
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
return failed(normalized, { code: 'METADATA_CAPTURE_FAILED', message: String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
266
|
+
}
|
|
267
|
+
const step = eventIdentity.phase === 'started' || eventIdentity.target === null ? currentStep : eventIdentity.target;
|
|
268
|
+
const logStep = eventIdentity.phase === 'started' ? `${eventIdentity.action} [started]` : eventIdentity.action;
|
|
269
|
+
const body = appendActivityEntry(section, { time: metadata.timestamp, step: logStep, agent: normalized.agent, note: eventIdentity.note });
|
|
270
|
+
const frontmatterSet = { current_step: step, assigned_to: normalized.agent };
|
|
271
|
+
if (eventIdentity.phase === 'started' && normalized.implementationInput)
|
|
272
|
+
frontmatterSet.last_reviewed_commit = '';
|
|
273
|
+
const mutations = [
|
|
274
|
+
{ kind: 'frontmatter', set: frontmatterSet }
|
|
275
|
+
];
|
|
276
|
+
if (completedArtifact) {
|
|
277
|
+
const link = buildArtifactLinkSection(content, completedArtifact);
|
|
278
|
+
mutations.push({ kind: 'section', aliases: link.aliases, heading: link.heading, body: link.body });
|
|
279
|
+
}
|
|
280
|
+
if (eventIdentity.phase === 'completed' && normalized.implementationInput) {
|
|
281
|
+
let implementationRows;
|
|
282
|
+
try {
|
|
283
|
+
implementationRows = consumeImplementationInput(parseImplementationInputs(content).rows, normalized.implementationInput, normalized.artifact);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: error instanceof Error ? error.message : String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
287
|
+
}
|
|
288
|
+
mutations.push({
|
|
289
|
+
kind: 'section', aliases: IMPLEMENTATION_INPUT_ALIASES,
|
|
290
|
+
heading: findSectionHeading(content, [...IMPLEMENTATION_INPUT_ALIASES]),
|
|
291
|
+
body: renderImplementationInputs(implementationRows)
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
|
|
295
|
+
const result = writeTask({ taskRef: normalized.taskRef, expectedState: 'active', dryRun: normalized.dryRun, mutations }, { ...options, metadataProvider: () => metadata });
|
|
296
|
+
if (result.status === 'failed')
|
|
297
|
+
return failed(normalized, result.error, { taskId: result.taskId, taskMdPath: result.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, timestamp: result.timestamp, agentInfraVersion: result.agentInfraVersion, operations: result.operations, artifactContext });
|
|
298
|
+
return {
|
|
299
|
+
status: result.status, changed: result.changed, event: normalized.event,
|
|
300
|
+
requestRef: normalized.taskRef, taskId: result.taskId, taskMdPath: result.taskMdPath,
|
|
301
|
+
fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase,
|
|
302
|
+
round: normalized.round ?? null, artifact: normalized.artifact ?? null,
|
|
303
|
+
fixFor: normalized.fixFor ?? null, implementationInput: normalized.implementationInput ?? null,
|
|
304
|
+
artifactContext, timestamp: result.timestamp,
|
|
305
|
+
agentInfraVersion: result.agentInfraVersion, operations: result.operations, error: null
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function successNoOp(request, taskId, taskMdPath, currentStep, eventIdentity, timestamp, frontmatter, artifactContext) {
|
|
309
|
+
return {
|
|
310
|
+
...failed(request, { code: 'EVENT_LOG_CONFLICT', message: '' }), status: 'no-op', error: null,
|
|
311
|
+
taskId, taskMdPath, fromStep: currentStep, toStep: currentStep,
|
|
312
|
+
action: eventIdentity.action, phase: eventIdentity.phase, timestamp,
|
|
313
|
+
agentInfraVersion: typeof frontmatter.agent_infra_version === 'string' ? frontmatter.agent_infra_version : null,
|
|
314
|
+
artifactContext
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
export { eventCatalog, validateTaskEventRequest, applyTaskEvent };
|
|
318
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -1,3 +1,58 @@
|
|
|
1
|
+
import { parse, stringify } from 'yaml';
|
|
2
|
+
class FrontmatterError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(code, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'FrontmatterError';
|
|
7
|
+
this.code = code;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function locateFrontmatter(content) {
|
|
11
|
+
const opening = /^---(\r?\n)/.exec(content);
|
|
12
|
+
if (!opening) {
|
|
13
|
+
throw new FrontmatterError('TASK_DOCUMENT_INVALID', 'task.md frontmatter is missing');
|
|
14
|
+
}
|
|
15
|
+
const eol = opening[1];
|
|
16
|
+
const bodyStart = opening[0].length;
|
|
17
|
+
const closing = /^---\r?$/gm;
|
|
18
|
+
closing.lastIndex = bodyStart;
|
|
19
|
+
const match = closing.exec(content);
|
|
20
|
+
if (!match) {
|
|
21
|
+
throw new FrontmatterError('TASK_DOCUMENT_INVALID', 'task.md frontmatter is unclosed');
|
|
22
|
+
}
|
|
23
|
+
return { eol, bodyStart, bodyEnd: match.index };
|
|
24
|
+
}
|
|
25
|
+
function parseFrontmatterLines(content, block) {
|
|
26
|
+
const body = content.slice(block.bodyStart, block.bodyEnd);
|
|
27
|
+
const lines = body.split(block.eol);
|
|
28
|
+
return lines.map((raw, index) => {
|
|
29
|
+
if (!raw.trim() || raw.trimStart().startsWith('#')) {
|
|
30
|
+
return { raw, index, key: null, value: null };
|
|
31
|
+
}
|
|
32
|
+
const match = /^([^\s:#][^:]*):(?:[ \t]*(.*))?$/.exec(raw);
|
|
33
|
+
if (!match || !match[1]) {
|
|
34
|
+
throw new FrontmatterError('TASK_DOCUMENT_INVALID', `unsupported frontmatter structure on line ${index + 2}`);
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
raw,
|
|
38
|
+
index,
|
|
39
|
+
key: match[1].trim(),
|
|
40
|
+
value: match[2] ?? ''
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
function serializeScalar(value) {
|
|
45
|
+
if (typeof value === 'number' && !Number.isFinite(value)) {
|
|
46
|
+
throw new FrontmatterError('MUTATION_INVALID', 'frontmatter numbers must be finite');
|
|
47
|
+
}
|
|
48
|
+
if (value === '')
|
|
49
|
+
return '';
|
|
50
|
+
const serialized = stringify(value).trimEnd();
|
|
51
|
+
if (serialized.includes('\n') || serialized.includes('\r')) {
|
|
52
|
+
throw new FrontmatterError('MUTATION_INVALID', 'frontmatter values must be scalar');
|
|
53
|
+
}
|
|
54
|
+
return serialized;
|
|
55
|
+
}
|
|
1
56
|
function parseTaskFrontmatter(content) {
|
|
2
57
|
const result = {};
|
|
3
58
|
if (!content.startsWith('---'))
|
|
@@ -20,6 +75,109 @@ function parseTaskFrontmatter(content) {
|
|
|
20
75
|
}
|
|
21
76
|
return result;
|
|
22
77
|
}
|
|
78
|
+
function parseTypedTaskFrontmatter(content) {
|
|
79
|
+
const block = locateFrontmatter(content);
|
|
80
|
+
const result = {};
|
|
81
|
+
for (const line of parseFrontmatterLines(content, block)) {
|
|
82
|
+
if (!line.key || line.value === null)
|
|
83
|
+
continue;
|
|
84
|
+
if (Object.hasOwn(result, line.key)) {
|
|
85
|
+
throw new FrontmatterError('TASK_DOCUMENT_INVALID', `duplicate frontmatter key '${line.key}'`);
|
|
86
|
+
}
|
|
87
|
+
if (line.value === '') {
|
|
88
|
+
result[line.key] = '';
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
let value;
|
|
92
|
+
try {
|
|
93
|
+
value = parse(line.value);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
throw new FrontmatterError('TASK_DOCUMENT_INVALID', `frontmatter key '${line.key}' is not a valid scalar`);
|
|
97
|
+
}
|
|
98
|
+
if (value !== null &&
|
|
99
|
+
typeof value !== 'string' &&
|
|
100
|
+
typeof value !== 'number' &&
|
|
101
|
+
typeof value !== 'boolean') {
|
|
102
|
+
throw new FrontmatterError('TASK_DOCUMENT_INVALID', `frontmatter key '${line.key}' is not a scalar`);
|
|
103
|
+
}
|
|
104
|
+
if (typeof value === 'number' && !Number.isFinite(value)) {
|
|
105
|
+
throw new FrontmatterError('TASK_DOCUMENT_INVALID', `frontmatter key '${line.key}' is not a finite scalar`);
|
|
106
|
+
}
|
|
107
|
+
result[line.key] = value;
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
function updateTaskFrontmatter(content, set, remove = []) {
|
|
112
|
+
if (!set || typeof set !== 'object' || Array.isArray(set)) {
|
|
113
|
+
throw new FrontmatterError('MUTATION_INVALID', 'frontmatter set must be an object');
|
|
114
|
+
}
|
|
115
|
+
const entries = Object.entries(set);
|
|
116
|
+
if (!Array.isArray(remove)) {
|
|
117
|
+
throw new FrontmatterError('MUTATION_INVALID', 'frontmatter remove must be an array');
|
|
118
|
+
}
|
|
119
|
+
const removeSet = new Set(remove);
|
|
120
|
+
if (removeSet.size !== remove.length) {
|
|
121
|
+
throw new FrontmatterError('MUTATION_INVALID', 'frontmatter remove keys must be unique');
|
|
122
|
+
}
|
|
123
|
+
for (const [key, value] of entries) {
|
|
124
|
+
if (!key || /[\r\n:]/.test(key)) {
|
|
125
|
+
throw new FrontmatterError('MUTATION_INVALID', `invalid frontmatter key '${key}'`);
|
|
126
|
+
}
|
|
127
|
+
if (value !== null &&
|
|
128
|
+
typeof value !== 'string' &&
|
|
129
|
+
typeof value !== 'number' &&
|
|
130
|
+
typeof value !== 'boolean') {
|
|
131
|
+
throw new FrontmatterError('MUTATION_INVALID', `invalid scalar for '${key}'`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const key of remove) {
|
|
135
|
+
if (!key || /[\r\n:]/.test(key)) {
|
|
136
|
+
throw new FrontmatterError('MUTATION_INVALID', `invalid frontmatter key '${key}'`);
|
|
137
|
+
}
|
|
138
|
+
if (Object.hasOwn(set, key)) {
|
|
139
|
+
throw new FrontmatterError('MUTATION_INVALID', `frontmatter key '${key}' cannot be set and removed together`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const block = locateFrontmatter(content);
|
|
143
|
+
const lines = parseFrontmatterLines(content, block);
|
|
144
|
+
const indexes = new Map();
|
|
145
|
+
for (const line of lines) {
|
|
146
|
+
if (!line.key)
|
|
147
|
+
continue;
|
|
148
|
+
const positions = indexes.get(line.key) ?? [];
|
|
149
|
+
positions.push(line.index);
|
|
150
|
+
indexes.set(line.key, positions);
|
|
151
|
+
}
|
|
152
|
+
for (const key of [...entries.map(([entryKey]) => entryKey), ...remove]) {
|
|
153
|
+
if ((indexes.get(key)?.length ?? 0) > 1) {
|
|
154
|
+
throw new FrontmatterError('TASK_DOCUMENT_INVALID', `duplicate frontmatter key '${key}'`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const nextLines = lines.map((line) => line.raw);
|
|
158
|
+
const additions = [];
|
|
159
|
+
for (const [key, value] of entries) {
|
|
160
|
+
const serialized = serializeScalar(value);
|
|
161
|
+
const replacement = serialized === '' ? `${key}:` : `${key}: ${serialized}`;
|
|
162
|
+
const index = indexes.get(key)?.[0];
|
|
163
|
+
if (index === undefined)
|
|
164
|
+
additions.push(replacement);
|
|
165
|
+
else
|
|
166
|
+
nextLines[index] = replacement;
|
|
167
|
+
}
|
|
168
|
+
const retainedLines = nextLines.filter((_, index) => {
|
|
169
|
+
const key = lines[index]?.key;
|
|
170
|
+
return !key || !removeSet.has(key);
|
|
171
|
+
});
|
|
172
|
+
if (additions.length > 0) {
|
|
173
|
+
if (retainedLines.at(-1) === '')
|
|
174
|
+
retainedLines.splice(-1, 0, ...additions);
|
|
175
|
+
else
|
|
176
|
+
retainedLines.push(...additions);
|
|
177
|
+
}
|
|
178
|
+
const body = retainedLines.join(block.eol);
|
|
179
|
+
return content.slice(0, block.bodyStart) + body + content.slice(block.bodyEnd);
|
|
180
|
+
}
|
|
23
181
|
function extractTitle(content) {
|
|
24
182
|
for (const line of content.split('\n')) {
|
|
25
183
|
const m = /^#\s+(?:任务[::]?\s*)?(.+)$/.exec(line.trim());
|
|
@@ -28,5 +186,5 @@ function extractTitle(content) {
|
|
|
28
186
|
}
|
|
29
187
|
return '';
|
|
30
188
|
}
|
|
31
|
-
export { parseTaskFrontmatter, extractTitle };
|
|
189
|
+
export { parseTaskFrontmatter, parseTypedTaskFrontmatter, updateTaskFrontmatter, extractTitle };
|
|
32
190
|
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { parseTable } from './sections.js';
|
|
2
|
+
const SECTION_ALIASES = ['实现输入', 'Implementation Inputs'];
|
|
3
|
+
const COLUMNS = [
|
|
4
|
+
'id', 'ledger_id', 'decision_evidence', 'stage', 'needs_implementation',
|
|
5
|
+
'decided_at', 'status', 'consumed_by'
|
|
6
|
+
];
|
|
7
|
+
const TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}$/;
|
|
8
|
+
const ARTIFACT_RE = /^code(?:-r(?:[2-9]|[1-9]\d+))?\.md$/;
|
|
9
|
+
function validateInput(row) {
|
|
10
|
+
if (!/^II-[1-9]\d*$/.test(row.id))
|
|
11
|
+
throw new Error(`implementation input id '${row.id}' is invalid`);
|
|
12
|
+
if (!row.ledgerId || !row.decisionEvidence || /[\r\n]/.test(row.ledgerId) || /[\r\n]/.test(row.decisionEvidence))
|
|
13
|
+
throw new Error(`implementation input ${row.id} has incomplete decision identity`);
|
|
14
|
+
if (row.stage !== 'code')
|
|
15
|
+
throw new Error(`implementation input ${row.id} has invalid stage`);
|
|
16
|
+
if (!TIMESTAMP_RE.test(row.decidedAt) || !Number.isFinite(Date.parse(row.decidedAt.replace(' ', 'T')))) {
|
|
17
|
+
throw new Error(`implementation input ${row.id} has invalid decided_at`);
|
|
18
|
+
}
|
|
19
|
+
const valid = (row.needsImplementation && row.status === 'pending' && row.consumedBy === '') ||
|
|
20
|
+
(!row.needsImplementation && row.status === 'not-required' && row.consumedBy === '') ||
|
|
21
|
+
(row.needsImplementation && row.status === 'consumed' && ARTIFACT_RE.test(row.consumedBy));
|
|
22
|
+
if (!valid)
|
|
23
|
+
throw new Error(`implementation input ${row.id} has an invalid state combination`);
|
|
24
|
+
}
|
|
25
|
+
function parseImplementationInputs(content) {
|
|
26
|
+
const table = parseTable(content, { sectionAliases: SECTION_ALIASES, columns: COLUMNS });
|
|
27
|
+
if (!table)
|
|
28
|
+
return { sectionFound: false, rows: [] };
|
|
29
|
+
const rows = [];
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
for (const { values } of table.rows) {
|
|
32
|
+
const id = values.id;
|
|
33
|
+
const ledgerId = values.ledger_id;
|
|
34
|
+
const decisionEvidence = values.decision_evidence;
|
|
35
|
+
const stage = values.stage;
|
|
36
|
+
const needs = values.needs_implementation;
|
|
37
|
+
const decidedAt = values.decided_at;
|
|
38
|
+
const status = values.status;
|
|
39
|
+
const consumedBy = values.consumed_by;
|
|
40
|
+
if (needs !== 'true' && needs !== 'false')
|
|
41
|
+
throw new Error(`implementation input ${id} has invalid needs_implementation`);
|
|
42
|
+
const row = {
|
|
43
|
+
id: id, ledgerId: ledgerId, decisionEvidence: decisionEvidence, stage: stage,
|
|
44
|
+
needsImplementation: needs === 'true', decidedAt: decidedAt,
|
|
45
|
+
status: status, consumedBy: consumedBy
|
|
46
|
+
};
|
|
47
|
+
validateInput(row);
|
|
48
|
+
if (seen.has(row.id))
|
|
49
|
+
throw new Error(`duplicate implementation input id '${row.id}'`);
|
|
50
|
+
seen.add(row.id);
|
|
51
|
+
rows.push(row);
|
|
52
|
+
}
|
|
53
|
+
return { sectionFound: true, rows };
|
|
54
|
+
}
|
|
55
|
+
function nextId(rows) {
|
|
56
|
+
let max = 0;
|
|
57
|
+
for (const row of rows)
|
|
58
|
+
max = Math.max(max, Number.parseInt(row.id.slice(3), 10));
|
|
59
|
+
return `II-${max + 1}`;
|
|
60
|
+
}
|
|
61
|
+
function createImplementationInput(rows, draft) {
|
|
62
|
+
const row = {
|
|
63
|
+
id: nextId(rows), ledgerId: draft.ledgerId, decisionEvidence: draft.decisionEvidence,
|
|
64
|
+
stage: 'code', needsImplementation: draft.needsImplementation, decidedAt: draft.decidedAt,
|
|
65
|
+
status: draft.needsImplementation ? 'pending' : 'not-required', consumedBy: ''
|
|
66
|
+
};
|
|
67
|
+
validateInput(row);
|
|
68
|
+
return row;
|
|
69
|
+
}
|
|
70
|
+
function selectPendingImplementationInput(rows, reviewCompletedAt) {
|
|
71
|
+
const reviewEpoch = Date.parse(reviewCompletedAt.replace(' ', 'T'));
|
|
72
|
+
if (!Number.isFinite(reviewEpoch))
|
|
73
|
+
throw new Error('latest review completion time is invalid');
|
|
74
|
+
const pending = rows.filter((row) => row.needsImplementation && row.status === 'pending');
|
|
75
|
+
const stale = pending.find((row) => Date.parse(row.decidedAt.replace(' ', 'T')) <= reviewEpoch);
|
|
76
|
+
if (stale)
|
|
77
|
+
throw new Error(`implementation input ${stale.id} is not later than the latest approved review`);
|
|
78
|
+
return [...pending].sort((left, right) => {
|
|
79
|
+
const time = Date.parse(left.decidedAt.replace(' ', 'T')) - Date.parse(right.decidedAt.replace(' ', 'T'));
|
|
80
|
+
return time || Number.parseInt(left.id.slice(3), 10) - Number.parseInt(right.id.slice(3), 10);
|
|
81
|
+
})[0] ?? null;
|
|
82
|
+
}
|
|
83
|
+
function consumeImplementationInput(rows, id, artifact) {
|
|
84
|
+
if (!ARTIFACT_RE.test(artifact))
|
|
85
|
+
throw new Error(`implementation input artifact '${artifact}' is invalid`);
|
|
86
|
+
let found = false;
|
|
87
|
+
const next = rows.map((row) => {
|
|
88
|
+
if (row.id !== id)
|
|
89
|
+
return row;
|
|
90
|
+
found = true;
|
|
91
|
+
if (row.status !== 'pending' || !row.needsImplementation) {
|
|
92
|
+
throw new Error(`implementation input ${id} is not pending`);
|
|
93
|
+
}
|
|
94
|
+
return { ...row, status: 'consumed', consumedBy: artifact };
|
|
95
|
+
});
|
|
96
|
+
if (!found)
|
|
97
|
+
throw new Error(`implementation input ${id} was not found`);
|
|
98
|
+
next.forEach(validateInput);
|
|
99
|
+
return next;
|
|
100
|
+
}
|
|
101
|
+
function renderImplementationInputs(rows) {
|
|
102
|
+
rows.forEach(validateInput);
|
|
103
|
+
const ids = new Set(rows.map((row) => row.id));
|
|
104
|
+
if (ids.size !== rows.length)
|
|
105
|
+
throw new Error('implementation input ids must be unique');
|
|
106
|
+
return [
|
|
107
|
+
`| ${COLUMNS.join(' | ')} |`,
|
|
108
|
+
'|----|-----------|-------------------|-------|----------------------|------------|--------|-------------|',
|
|
109
|
+
...rows.map((row) => {
|
|
110
|
+
const cells = [row.id, row.ledgerId, row.decisionEvidence, 'code', String(row.needsImplementation), row.decidedAt, row.status, row.consumedBy]
|
|
111
|
+
.map((value) => value.replace(/\\/g, '\\\\').replace(/\|/g, '\\|'));
|
|
112
|
+
return `| ${cells.join(' | ')} |`;
|
|
113
|
+
})
|
|
114
|
+
].join('\n');
|
|
115
|
+
}
|
|
116
|
+
export { SECTION_ALIASES as IMPLEMENTATION_INPUT_ALIASES, createImplementationInput, consumeImplementationInput, parseImplementationInputs, renderImplementationInputs, selectPendingImplementationInput };
|
|
117
|
+
//# sourceMappingURL=implementation-inputs.js.map
|
package/dist/lib/task/index.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
const USAGE = `Usage: ai task <command> [options]
|
|
2
2
|
|
|
3
3
|
Commands:
|
|
4
|
-
cat <ref> <artifact | N>
|
|
5
|
-
decisions, d <ref> [
|
|
6
|
-
files <ref>
|
|
7
|
-
grep <pattern> [ref]
|
|
8
|
-
issue-body <ref> [--template
|
|
9
|
-
log <ref>
|
|
4
|
+
cat [--task <ref>] <artifact | N> Print a task artifact (by name or number)
|
|
5
|
+
decisions, d [--task <ref>] [-i item] List review decisions, or show one item's detail
|
|
6
|
+
files [--task <ref>] List artifacts in a task dir (numbered)
|
|
7
|
+
grep <pattern> [--current|--task <ref>] Literal search across task artifacts (global by default)
|
|
8
|
+
issue-body [--task <ref>] [--template] Print a deterministic Issue body from task.md
|
|
9
|
+
log [--task <ref>] Render a task's activity log as a timeline
|
|
10
10
|
ls [--all | --blocked | --completed] List tasks (default: active)
|
|
11
|
-
show <
|
|
12
|
-
status <ref>
|
|
11
|
+
show [--task <ref>] Print a task.md
|
|
12
|
+
status [--task <ref>] Aggregated status view (metadata / artifacts / git / platform)
|
|
13
13
|
|
|
14
14
|
Examples:
|
|
15
15
|
ai task cat 11 analysis
|
|
16
|
+
ai task cat analysis
|
|
16
17
|
ai task cat 11 3
|
|
17
18
|
ai task decisions 11
|
|
18
|
-
ai task
|
|
19
|
+
ai task decisions --item 1
|
|
20
|
+
ai task d 11 PL-3 --format markdown
|
|
19
21
|
ai task files 11
|
|
20
22
|
ai task grep resolveArtifact
|
|
23
|
+
ai task grep resolveArtifact --current
|
|
21
24
|
ai task grep resolveArtifact 11
|
|
22
25
|
ai task issue-body 11
|
|
23
26
|
ai task issue-body 11 --template .github/ISSUE_TEMPLATE/05_other.yml
|