@fitlab-ai/agent-infra 0.9.2 → 0.9.4
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 +12 -9
- package/README.zh-CN.md +12 -9
- package/bin/cli.ts +12 -0
- package/dist/bin/cli.js +14 -0
- package/dist/bin/internal-cli.js +134 -108
- package/dist/lib/agent-clients/adapter.js +137 -4
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +64 -0
- package/dist/lib/{sandbox/credentials.js → agent-clients/adapters/claude-code-credentials.js} +4 -14
- package/dist/lib/agent-clients/adapters/claude-code-refresh.js +85 -0
- package/dist/lib/agent-clients/adapters/claude-code-sandbox.js +247 -0
- package/dist/lib/agent-clients/adapters/claude-code.js +27 -4
- package/dist/lib/agent-clients/adapters/codex.js +9 -0
- package/dist/lib/agent-clients/adapters/index.js +2 -2
- package/dist/lib/agent-clients/adapters/opencode-sandbox.js +108 -0
- package/dist/lib/agent-clients/adapters/opencode.js +24 -3
- package/dist/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
- package/dist/lib/agent-clients/config.js +42 -4
- package/dist/lib/agent-clients/next-steps.js +11 -2
- package/dist/lib/agent-clients/reconcile.js +2 -1
- package/dist/lib/agent-clients/registry.js +16 -2
- package/dist/lib/agent-clients/schema.js +18 -0
- package/dist/lib/agent-clients/tokens.js +49 -0
- package/dist/lib/agent-clients/types.js +1 -1
- package/dist/lib/defaults.json +1 -1
- package/dist/lib/git/workflow.js +54 -1
- package/dist/lib/internal/agent-client.js +61 -4
- package/dist/lib/internal/git-workflow.js +6 -1
- package/dist/lib/internal/platform-checks.js +3 -3
- package/dist/lib/internal/platform-comment.js +29 -2
- package/dist/lib/internal/platform-issue.js +7 -0
- package/dist/lib/internal/platform-pr-review.js +132 -0
- package/dist/lib/internal/platform-pr.js +20 -2
- package/dist/lib/internal/platform-release-notes.js +52 -16
- package/dist/lib/internal/pr-review-grade.js +140 -0
- package/dist/lib/internal/release-workflow.js +13 -6
- package/dist/lib/internal/sandbox-control.js +24 -0
- package/dist/lib/internal/task-activity.js +105 -0
- package/dist/lib/internal/task-event.js +17 -1
- package/dist/lib/internal/task-ledger.js +12 -3
- package/dist/lib/internal/task-lifecycle.js +26 -1
- package/dist/lib/internal/task-orchestration.js +167 -18
- package/dist/lib/internal/task-review.js +8 -3
- package/dist/lib/platform/adapters.js +8 -1
- package/dist/lib/platform/completion-backfill.js +122 -0
- package/dist/lib/platform/github-client.js +19 -2
- package/dist/lib/platform/issue-comments.js +3 -2
- package/dist/lib/platform/merged-pr-equivalence.js +115 -5
- package/dist/lib/platform/pr-checks.js +65 -42
- package/dist/lib/platform/pr-review.js +166 -0
- package/dist/lib/platform/pull-requests.js +371 -4
- package/dist/lib/platform/release-notes.js +85 -3
- package/dist/lib/platform/releases.js +13 -5
- package/dist/lib/pr-review/evidence-grading.js +229 -0
- package/dist/lib/process-data/index.js +239 -0
- package/dist/lib/process-data/normalize.js +198 -0
- package/dist/lib/process-data/privacy.js +33 -0
- package/dist/lib/process-data/reconcile.js +95 -0
- package/dist/lib/process-data/repair.js +58 -0
- package/dist/lib/process-data/sources.js +345 -0
- package/dist/lib/process-data/store.js +282 -0
- package/dist/lib/process-data/types.js +2 -0
- package/dist/lib/run/index.js +4 -3
- package/dist/lib/run/tui.js +10 -13
- package/dist/lib/sandbox/agent-client-reconciler.js +26 -2
- package/dist/lib/sandbox/capture.js +7 -2
- package/dist/lib/sandbox/commands/create.js +109 -248
- package/dist/lib/sandbox/commands/enter.js +15 -47
- package/dist/lib/sandbox/commands/list-running.js +16 -6
- package/dist/lib/sandbox/commands/ls.js +10 -6
- package/dist/lib/sandbox/commands/rebuild.js +4 -3
- package/dist/lib/sandbox/commands/refresh.js +4 -84
- package/dist/lib/sandbox/commands/rm.js +24 -3
- package/dist/lib/sandbox/commands/show.js +13 -4
- package/dist/lib/sandbox/commands/start.js +7 -4
- package/dist/lib/sandbox/config.js +2 -0
- package/dist/lib/sandbox/constants.js +6 -0
- package/dist/lib/sandbox/control/client.js +44 -0
- package/dist/lib/sandbox/control/protocol.js +35 -0
- package/dist/lib/sandbox/control/server.js +109 -0
- package/dist/lib/sandbox/dockerfile.js +36 -13
- package/dist/lib/sandbox/mounts.js +17 -4
- package/dist/lib/sandbox/recovery.js +128 -5
- package/dist/lib/sandbox/redaction.js +12 -0
- package/dist/lib/sandbox/runtimes/base.dockerfile +24 -74
- package/dist/lib/sandbox/workspace-identity.js +95 -0
- package/dist/lib/sandbox/workspace-view.js +103 -0
- package/dist/lib/task/activity-intent.js +307 -0
- package/dist/lib/task/artifact-lifecycle.js +2 -1
- package/dist/lib/task/commands/log.js +15 -14
- package/dist/lib/task/commit-finalization.js +267 -0
- package/dist/lib/task/commit-intent.js +165 -0
- package/dist/lib/task/decision-intents.js +31 -17
- package/dist/lib/task/delegation-receipts.js +25 -4
- package/dist/lib/task/events.js +67 -28
- package/dist/lib/task/finalization-artifacts.js +35 -0
- package/dist/lib/task/implementation-inputs.js +54 -7
- package/dist/lib/task/ledger-intents.js +35 -1
- package/dist/lib/task/lifecycle-execution.js +46 -0
- package/dist/lib/task/orchestration.js +753 -54
- package/dist/lib/task/resolve-ref.js +41 -1
- package/dist/lib/task/review-finalization.js +29 -9
- package/dist/lib/task/task-execution-lock.js +231 -0
- package/dist/lib/task/verification-checks.js +1 -1
- package/dist/lib/task/verification-engine.js +218 -2
- package/dist/lib/task/verification.js +4 -3
- package/dist/lib/task/workspace-snapshot.js +17 -5
- package/lib/agent-clients/adapter.ts +201 -4
- package/lib/agent-clients/adapters/antigravity-cli.ts +65 -0
- package/lib/{sandbox/credentials.ts → agent-clients/adapters/claude-code-credentials.ts} +3 -18
- package/lib/agent-clients/adapters/claude-code-refresh.ts +128 -0
- package/lib/agent-clients/adapters/claude-code-sandbox.ts +295 -0
- package/lib/agent-clients/adapters/claude-code.ts +31 -4
- package/lib/agent-clients/adapters/codex.ts +9 -0
- package/lib/agent-clients/adapters/index.ts +2 -2
- package/lib/agent-clients/adapters/opencode-sandbox.ts +136 -0
- package/lib/agent-clients/adapters/opencode.ts +27 -3
- package/lib/agent-clients/adapters/runtimes/claude-code.dockerfile +65 -0
- package/lib/agent-clients/config.ts +49 -4
- package/lib/agent-clients/next-steps.ts +15 -2
- package/lib/agent-clients/reconcile.ts +2 -1
- package/lib/agent-clients/registry.ts +19 -1
- package/lib/agent-clients/schema.ts +18 -0
- package/lib/agent-clients/tokens.ts +53 -0
- package/lib/agent-clients/types.ts +15 -1
- package/lib/defaults.json +1 -1
- package/lib/git/workflow.ts +66 -2
- package/lib/internal/agent-client.ts +59 -4
- package/lib/internal/git-workflow.ts +5 -1
- package/lib/internal/platform-checks.ts +4 -4
- package/lib/internal/platform-comment.ts +17 -2
- package/lib/internal/platform-issue.ts +4 -0
- package/lib/internal/platform-pr-review.ts +104 -0
- package/lib/internal/platform-pr.ts +14 -1
- package/lib/internal/platform-release-notes.ts +59 -16
- package/lib/internal/pr-review-grade.ts +130 -0
- package/lib/internal/release-workflow.ts +13 -6
- package/lib/internal/sandbox-control.ts +24 -0
- package/lib/internal/task-activity.ts +91 -0
- package/lib/internal/task-event.ts +9 -1
- package/lib/internal/task-ledger.ts +12 -3
- package/lib/internal/task-lifecycle.ts +26 -1
- package/lib/internal/task-orchestration.ts +123 -14
- package/lib/internal/task-review.ts +8 -3
- package/lib/platform/adapters.ts +29 -2
- package/lib/platform/completion-backfill.ts +134 -0
- package/lib/platform/github-client.ts +20 -2
- package/lib/platform/issue-comments.ts +3 -2
- package/lib/platform/merged-pr-equivalence.ts +127 -5
- package/lib/platform/pr-checks.ts +73 -46
- package/lib/platform/pr-review.ts +201 -0
- package/lib/platform/pull-requests.ts +444 -3
- package/lib/platform/release-notes.ts +100 -4
- package/lib/platform/releases.ts +16 -4
- package/lib/pr-review/evidence-grading.ts +318 -0
- package/lib/process-data/index.ts +224 -0
- package/lib/process-data/normalize.ts +202 -0
- package/lib/process-data/privacy.ts +41 -0
- package/lib/process-data/reconcile.ts +110 -0
- package/lib/process-data/repair.ts +64 -0
- package/lib/process-data/sources.ts +354 -0
- package/lib/process-data/store.ts +315 -0
- package/lib/process-data/types.ts +135 -0
- package/lib/run/index.ts +5 -3
- package/lib/run/tui.ts +14 -12
- package/lib/sandbox/agent-client-reconciler.ts +44 -2
- package/lib/sandbox/capture.ts +9 -2
- package/lib/sandbox/commands/create.ts +126 -280
- package/lib/sandbox/commands/enter.ts +13 -59
- package/lib/sandbox/commands/list-running.ts +23 -6
- package/lib/sandbox/commands/ls.ts +22 -6
- package/lib/sandbox/commands/rebuild.ts +4 -3
- package/lib/sandbox/commands/refresh.ts +4 -126
- package/lib/sandbox/commands/rm.ts +24 -3
- package/lib/sandbox/commands/show.ts +30 -4
- package/lib/sandbox/commands/start.ts +6 -4
- package/lib/sandbox/config.ts +4 -0
- package/lib/sandbox/constants.ts +8 -0
- package/lib/sandbox/control/client.ts +55 -0
- package/lib/sandbox/control/protocol.ts +75 -0
- package/lib/sandbox/control/server.ts +117 -0
- package/lib/sandbox/dockerfile.ts +66 -13
- package/lib/sandbox/mounts.ts +24 -4
- package/lib/sandbox/recovery.ts +163 -6
- package/lib/sandbox/redaction.ts +14 -0
- package/lib/sandbox/runtimes/base.dockerfile +24 -74
- package/lib/sandbox/tool-types.ts +16 -0
- package/lib/sandbox/workspace-identity.ts +123 -0
- package/lib/sandbox/workspace-view.ts +143 -0
- package/lib/server/server.schema.json +2 -2
- package/lib/task/activity-intent.ts +417 -0
- package/lib/task/artifact-lifecycle.ts +2 -1
- package/lib/task/commands/log.ts +15 -14
- package/lib/task/commit-finalization.ts +356 -0
- package/lib/task/commit-intent.ts +230 -0
- package/lib/task/decision-intents.ts +32 -12
- package/lib/task/delegation-receipts.ts +34 -5
- package/lib/task/events.ts +75 -30
- package/lib/task/finalization-artifacts.ts +58 -0
- package/lib/task/implementation-inputs.ts +62 -8
- package/lib/task/ledger-intents.ts +43 -3
- package/lib/task/lifecycle-execution.ts +106 -0
- package/lib/task/orchestration.ts +1019 -72
- package/lib/task/resolve-ref.ts +46 -1
- package/lib/task/review-finalization.ts +40 -9
- package/lib/task/task-execution-lock.ts +296 -0
- package/lib/task/verification-checks.ts +1 -1
- package/lib/task/verification-engine.ts +249 -2
- package/lib/task/verification.ts +5 -3
- package/lib/task/workspace-snapshot.ts +26 -5
- package/package.json +3 -3
- package/templates/.agents/QUICKSTART.en.md +25 -8
- package/templates/.agents/QUICKSTART.zh-CN.md +25 -8
- package/templates/.agents/README.en.md +10 -7
- package/templates/.agents/README.zh-CN.md +10 -7
- package/templates/.agents/hooks/lifecycle-delegation.js +15 -4
- package/templates/.agents/rules/README.en.md +1 -1
- package/templates/.agents/rules/README.zh-CN.md +1 -1
- package/templates/.agents/rules/create-issue.github.en.md +4 -2
- package/templates/.agents/rules/create-issue.github.zh-CN.md +4 -2
- package/templates/.agents/rules/human-decision-context.en.md +11 -2
- package/templates/.agents/rules/human-decision-context.zh-CN.md +11 -2
- package/templates/.agents/rules/issue-fields.github.en.md +3 -1
- package/templates/.agents/rules/issue-fields.github.zh-CN.md +3 -1
- package/templates/.agents/rules/issue-pr-commands.en.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.github.en.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +5 -3
- package/templates/.agents/rules/issue-pr-commands.zh-CN.md +5 -3
- package/templates/.agents/rules/issue-sync.github.en.md +7 -3
- package/templates/.agents/rules/issue-sync.github.zh-CN.md +8 -4
- package/templates/.agents/rules/lifecycle-orchestration.en.md +5 -2
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +5 -2
- package/templates/.agents/rules/milestone-inference.github.en.md +4 -2
- package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -2
- package/templates/.agents/rules/next-step-output.en.md +3 -1
- package/templates/.agents/rules/next-step-output.zh-CN.md +3 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +17 -0
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +17 -0
- package/templates/.agents/rules/pr-checks-commands.en.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.github.en.md +2 -2
- package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-checks-commands.zh-CN.md +3 -3
- package/templates/.agents/rules/pr-sync.en.md +3 -1
- package/templates/.agents/rules/pr-sync.github.en.md +11 -1
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +11 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +3 -1
- package/templates/.agents/rules/release-commands.en.md +1 -1
- package/templates/.agents/rules/release-commands.github.en.md +12 -2
- package/templates/.agents/rules/release-commands.github.zh-CN.md +12 -2
- package/templates/.agents/rules/release-commands.zh-CN.md +1 -1
- package/templates/.agents/rules/review-handshake.zh-CN.md +1 -1
- package/templates/.agents/rules/task-management.en.md +13 -0
- package/templates/.agents/rules/task-management.zh-CN.md +13 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +10 -7
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +10 -7
- package/templates/.agents/skills/block-task/SKILL.en.md +7 -5
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +7 -5
- package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -4
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -4
- package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -1
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -1
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +10 -7
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +12 -9
- package/templates/.agents/skills/commit/SKILL.en.md +23 -11
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +29 -11
- package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +49 -0
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +55 -0
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +4 -4
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +4 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +6 -4
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +6 -4
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +22 -7
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +22 -7
- package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +17 -0
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +17 -0
- package/templates/.agents/skills/create-pr/SKILL.en.md +7 -5
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +7 -5
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
- package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -16
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -16
- package/templates/.agents/skills/create-task/SKILL.en.md +5 -3
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/create-task/reference/context-capture.en.md +34 -0
- package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +34 -0
- package/templates/.agents/skills/import-issue/SKILL.en.md +5 -3
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -3
- package/templates/.agents/skills/plan-task/SKILL.en.md +8 -5
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +8 -5
- package/templates/.agents/skills/post-release/SKILL.en.md +2 -0
- package/templates/.agents/skills/post-release/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/release/SKILL.en.md +16 -10
- package/templates/.agents/skills/release/SKILL.zh-CN.md +16 -10
- package/templates/.agents/skills/restore-task/SKILL.en.md +4 -1
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +7 -4
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-code/SKILL.en.md +11 -8
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +11 -8
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +1 -1
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +1 -1
- package/templates/.agents/skills/review-plan/SKILL.en.md +7 -4
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +7 -4
- package/templates/.agents/skills/review-pr/SKILL.en.md +186 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +186 -0
- package/templates/.agents/skills/review-pr/config/verify.en.json +37 -0
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +37 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +65 -0
- package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +65 -0
- package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +18 -0
- package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +18 -0
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +85 -0
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +85 -0
- package/templates/.agents/skills/run-task/SKILL.en.md +8 -8
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/run-task/config/verify.en.json +2 -1
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +2 -1
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +20 -0
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +20 -0
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +98 -107
- package/templates/.agents/skills/watch-pr/SKILL.en.md +13 -13
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +13 -13
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +27 -6
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +26 -5
- package/templates/.agents/templates/task.en.md +2 -2
- package/templates/.agents/templates/task.zh-CN.md +2 -2
- package/templates/.agents/workflows/bug-fix.en.yaml +3 -3
- package/templates/.agents/workflows/bug-fix.zh-CN.yaml +3 -3
- package/templates/.agents/workflows/code-review.en.yaml +1 -1
- package/templates/.agents/workflows/code-review.zh-CN.yaml +1 -1
- package/templates/.agents/workflows/feature-development.en.yaml +4 -4
- package/templates/.agents/workflows/feature-development.zh-CN.yaml +4 -4
- package/templates/.agents/workflows/refactoring.en.yaml +3 -3
- package/templates/.agents/workflows/refactoring.zh-CN.yaml +3 -3
- package/templates/.claude/commands/post-release.en.md +1 -0
- package/templates/.claude/commands/post-release.zh-CN.md +1 -0
- package/templates/.claude/commands/review-pr.en.md +8 -0
- package/templates/.claude/commands/review-pr.zh-CN.md +8 -0
- package/templates/.claude/commands/watch-pr.en.md +1 -1
- package/templates/.claude/commands/watch-pr.zh-CN.md +1 -1
- package/templates/.claude/rules/tool-preferences.en.md +20 -0
- package/templates/.claude/rules/tool-preferences.zh-CN.md +20 -0
- package/templates/.opencode/commands/post-release.en.md +2 -0
- package/templates/.opencode/commands/post-release.zh-CN.md +2 -0
- package/templates/.opencode/commands/review-pr.en.md +11 -0
- package/templates/.opencode/commands/review-pr.zh-CN.md +11 -0
- package/templates/.opencode/commands/watch-pr.en.md +1 -1
- package/templates/.opencode/commands/watch-pr.zh-CN.md +1 -1
- package/dist/lib/agent-clients/adapters/gemini-cli.js +0 -64
- package/lib/agent-clients/adapters/gemini-cli.ts +0 -65
- package/templates/.gemini/commands/_project_/analyze-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/archive-tasks.en.toml +0 -10
- package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/block-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/cancel-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/check-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/close-codescan.en.toml +0 -8
- package/templates/.gemini/commands/_project_/close-codescan.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/close-dependabot.en.toml +0 -8
- package/templates/.gemini/commands/_project_/close-dependabot.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/code-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/commit.en.toml +0 -10
- package/templates/.gemini/commands/_project_/commit.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/create-pr.en.toml +0 -10
- package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/create-release-note.en.toml +0 -8
- package/templates/.gemini/commands/_project_/create-release-note.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/create-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/create-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-codescan.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-codescan.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-dependabot.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-dependabot.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/import-issue.en.toml +0 -8
- package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/init-labels.en.toml +0 -8
- package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/init-milestones.en.toml +0 -10
- package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/plan-task.en.toml +0 -10
- package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/post-release.en.toml +0 -6
- package/templates/.gemini/commands/_project_/post-release.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/refine-title.en.toml +0 -8
- package/templates/.gemini/commands/_project_/refine-title.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/release.en.toml +0 -8
- package/templates/.gemini/commands/_project_/release.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/restore-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/review-analysis.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/review-code.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/review-plan.en.toml +0 -10
- package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +0 -10
- package/templates/.gemini/commands/_project_/run-task.en.toml +0 -8
- package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/test-integration.en.toml +0 -6
- package/templates/.gemini/commands/_project_/test-integration.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/test.en.toml +0 -6
- package/templates/.gemini/commands/_project_/test.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/update-agent-infra.en.toml +0 -6
- package/templates/.gemini/commands/_project_/update-agent-infra.zh-CN.toml +0 -6
- package/templates/.gemini/commands/_project_/upgrade-dependency.en.toml +0 -8
- package/templates/.gemini/commands/_project_/upgrade-dependency.zh-CN.toml +0 -8
- package/templates/.gemini/commands/_project_/watch-pr.en.toml +0 -10
- package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +0 -10
- package/templates/.gemini/settings.json +0 -3
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { parseTaskFrontmatter } from '../task/frontmatter.js';
|
|
4
|
+
export class HostResolutionError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
constructor(code, message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = 'HostResolutionError';
|
|
9
|
+
this.code = code;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function toPositiveNumber(value) {
|
|
13
|
+
const n = Number(value);
|
|
14
|
+
return Number.isInteger(n) && n > 0 ? n : null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse the PR body for closing-issue references. Handles the conventional
|
|
18
|
+
* `Closes #1` / `Fixes: #2, #3` shapes (case-insensitive, comma/space
|
|
19
|
+
* separated, optional keyword list on the same logical line).
|
|
20
|
+
*/
|
|
21
|
+
export function extractClosingIssueNumbers(body) {
|
|
22
|
+
const result = [];
|
|
23
|
+
const seen = new Set();
|
|
24
|
+
const linePattern = /(?:^|\n)[^\n]*\b(?:close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\b[^\n]*/gi;
|
|
25
|
+
let lineMatch;
|
|
26
|
+
while ((lineMatch = linePattern.exec(body)) !== null) {
|
|
27
|
+
const line = lineMatch[0];
|
|
28
|
+
for (const numMatch of line.matchAll(/#(\d+)/g)) {
|
|
29
|
+
const n = Number(numMatch[1]);
|
|
30
|
+
if (Number.isInteger(n) && n > 0 && !seen.has(n)) {
|
|
31
|
+
seen.add(n);
|
|
32
|
+
result.push(n);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Scan `.agents/workspace/active/{task-id}/task.md` files for tasks bound to the
|
|
40
|
+
* PR number or to one of the PR's closing issues. A task is emitted at most once;
|
|
41
|
+
* a direct `pr_number` hit takes priority over the issue-number reverse lookup.
|
|
42
|
+
*/
|
|
43
|
+
export function collectHostCandidates(input) {
|
|
44
|
+
const activeRoot = path.join(input.workspaceRoot, '.agents', 'workspace', 'active');
|
|
45
|
+
const candidates = [];
|
|
46
|
+
let entries;
|
|
47
|
+
try {
|
|
48
|
+
entries = fs.readdirSync(activeRoot, { withFileTypes: true });
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
if (!entry.isDirectory())
|
|
55
|
+
continue;
|
|
56
|
+
const taskDir = path.join(activeRoot, entry.name);
|
|
57
|
+
const taskMdPath = path.join(taskDir, 'task.md');
|
|
58
|
+
let content;
|
|
59
|
+
try {
|
|
60
|
+
content = fs.readFileSync(taskMdPath, 'utf8');
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const frontmatter = parseTaskFrontmatter(content);
|
|
66
|
+
const issueNumber = toPositiveNumber(frontmatter.issue_number);
|
|
67
|
+
const prNumber = toPositiveNumber(frontmatter.pr_number);
|
|
68
|
+
if (prNumber === input.prNumber) {
|
|
69
|
+
candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
|
|
70
|
+
}
|
|
71
|
+
else if (issueNumber !== null && input.closingIssues.includes(issueNumber)) {
|
|
72
|
+
candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return candidates;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Collapse a candidate list into a typed HostResolution. Zero candidates ->
|
|
79
|
+
* none; exactly one -> unique; more than one (no stable selection rule) ->
|
|
80
|
+
* ambiguous (fail closed, AN-6).
|
|
81
|
+
*/
|
|
82
|
+
export function resolveHostFromCandidates(candidates) {
|
|
83
|
+
if (candidates.length === 0)
|
|
84
|
+
return { kind: 'none' };
|
|
85
|
+
if (candidates.length === 1) {
|
|
86
|
+
const candidate = candidates[0];
|
|
87
|
+
return {
|
|
88
|
+
kind: 'unique',
|
|
89
|
+
taskId: candidate.taskId,
|
|
90
|
+
taskDir: candidate.taskDir,
|
|
91
|
+
issueNumber: candidate.issueNumber ?? 0,
|
|
92
|
+
prNumber: candidate.prNumber ?? 0
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
kind: 'ambiguous',
|
|
97
|
+
candidates: candidates.map((candidate) => ({ taskId: candidate.taskId, issueNumber: candidate.issueNumber ?? 0 }))
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function hasNoLifecycleArtifacts(presence) {
|
|
101
|
+
return !presence.hasAnalysis && !presence.hasPlan && !presence.hasCode &&
|
|
102
|
+
!presence.hasReviewAnalysis && !presence.hasReviewPlan && !presence.hasReviewCode &&
|
|
103
|
+
!presence.hasPriorPrReview;
|
|
104
|
+
}
|
|
105
|
+
function hasFullArtifacts(presence) {
|
|
106
|
+
return presence.hasAnalysis && presence.hasPlan && presence.hasCode &&
|
|
107
|
+
presence.hasReviewAnalysis && presence.hasReviewPlan && presence.hasReviewCode;
|
|
108
|
+
}
|
|
109
|
+
function isTrusted(head) {
|
|
110
|
+
return head.issueNumberBound && head.taskIssueMatches && (!head.prNumberBound || head.taskPrMatches);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Derive the S1(a) trust factor `taskIssueMatches` (PL-3) mechanically from
|
|
114
|
+
* resolved data: a unique host is trusted on the issue dimension only when the
|
|
115
|
+
* task's bound issue_number is among the PR's closing issues. Ambiguous/none
|
|
116
|
+
* hosts and tasks without a positive issue_number cannot be confirmed -> false
|
|
117
|
+
* (fail closed to S2/audit). `resolve-host` emits this value so the prompt layer
|
|
118
|
+
* does not derive the trust factor ad hoc (CD-2).
|
|
119
|
+
*/
|
|
120
|
+
export function deriveTaskIssueMatches(host, closingIssues) {
|
|
121
|
+
return host.kind === 'unique' && host.issueNumber > 0 && closingIssues.includes(host.issueNumber);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* S1 -> S2 -> S3 classification (analysis §6.1). The ambiguous host is rejected
|
|
125
|
+
* before classification (AN-6 fail closed). S3(a) is host.kind === 'none';
|
|
126
|
+
* S3(b) is a unique task with no lifecycle artifacts and no prior pr-review
|
|
127
|
+
* (PL-5/PL-9 symmetric: any review-only task falls to S2).
|
|
128
|
+
*/
|
|
129
|
+
export function classifyScenario(host, presence, head) {
|
|
130
|
+
if (host.kind === 'ambiguous') {
|
|
131
|
+
throw new HostResolutionError('HOST_AMBIGUOUS', 'multiple candidate hosts; resolve before evidence classification');
|
|
132
|
+
}
|
|
133
|
+
if (host.kind === 'none')
|
|
134
|
+
return 'S3';
|
|
135
|
+
if (hasNoLifecycleArtifacts(presence))
|
|
136
|
+
return 'S3';
|
|
137
|
+
const priorHeadMatches = presence.hasPriorPrReview && head.priorHeadSha !== null && head.priorHeadSha === head.currentHeadSha;
|
|
138
|
+
if (hasFullArtifacts(presence) && priorHeadMatches && isTrusted(head))
|
|
139
|
+
return 'S1';
|
|
140
|
+
return 'S2';
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Freshness is benchmarked against the prior `pr-review*` reviewed head SHA
|
|
144
|
+
* (analysis §6.2, AN-7). No prior review -> n/a/n/a (first-review special case).
|
|
145
|
+
*/
|
|
146
|
+
export function evaluateHead(head) {
|
|
147
|
+
if (head.priorHeadSha === null)
|
|
148
|
+
return { freshness: 'n/a', alignment: 'n/a' };
|
|
149
|
+
const freshness = head.priorHeadSha === head.currentHeadSha ? 'fresh' : 'stale';
|
|
150
|
+
const aligned = freshness === 'fresh' && isTrusted(head);
|
|
151
|
+
return { freshness, alignment: aligned ? 'aligned' : 'misaligned' };
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Pure-evidence risk aggregation (analysis §6.3, AN-5): any priority factor
|
|
155
|
+
* (sensitivity / sourceCredibility) HIGH -> HIGH; otherwise any HIGH -> MEDIUM;
|
|
156
|
+
* all LOW -> LOW. Identity factors are structurally absent from the input type.
|
|
157
|
+
*/
|
|
158
|
+
export function gradeRisk(factors) {
|
|
159
|
+
const priority = [factors.sensitivity, factors.sourceCredibility];
|
|
160
|
+
if (priority.includes('HIGH'))
|
|
161
|
+
return 'HIGH';
|
|
162
|
+
const values = Object.values(factors);
|
|
163
|
+
if (values.includes('HIGH'))
|
|
164
|
+
return 'MEDIUM';
|
|
165
|
+
return 'LOW';
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* verify / audit / reconstruct selection matrix (analysis §6.4). S3 ->
|
|
169
|
+
* reconstruct; S2 -> audit; S1 fresh+aligned -> verify (LOW/MEDIUM risk) or
|
|
170
|
+
* audit (HIGH risk); any other S1 combination falls back to audit.
|
|
171
|
+
*/
|
|
172
|
+
export function selectMode(scenario, freshness, alignment, risk) {
|
|
173
|
+
if (scenario === 'S3')
|
|
174
|
+
return 'reconstruct';
|
|
175
|
+
if (scenario === 'S2')
|
|
176
|
+
return 'audit';
|
|
177
|
+
if (freshness === 'fresh' && alignment === 'aligned') {
|
|
178
|
+
return risk === 'HIGH' ? 'audit' : 'verify';
|
|
179
|
+
}
|
|
180
|
+
return 'audit';
|
|
181
|
+
}
|
|
182
|
+
function buildReason(input) {
|
|
183
|
+
const pieces = [];
|
|
184
|
+
if (input.firstReview)
|
|
185
|
+
pieces.push('first review (no prior pr-review head)');
|
|
186
|
+
if (input.hasPriorPrReview)
|
|
187
|
+
pieces.push(`prior head ${input.freshness}`);
|
|
188
|
+
if (input.freshness === 'fresh')
|
|
189
|
+
pieces.push(`alignment ${input.alignment}`);
|
|
190
|
+
pieces.push(`evidence scenario ${input.scenario}`);
|
|
191
|
+
pieces.push(`risk ${input.risk}`);
|
|
192
|
+
pieces.push(`mode ${input.mode}`);
|
|
193
|
+
return pieces.join('; ');
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Full decision pipeline: classify -> freshness/alignment -> risk -> mode,
|
|
197
|
+
* producing a traceable DecisionRecord (AC3). Ambiguous hosts are rejected
|
|
198
|
+
* before any classification runs (AN-6).
|
|
199
|
+
*/
|
|
200
|
+
export function decide(input) {
|
|
201
|
+
if (input.host.kind === 'ambiguous') {
|
|
202
|
+
throw new HostResolutionError('HOST_AMBIGUOUS', 'ambiguous host; resolve before evidence classification');
|
|
203
|
+
}
|
|
204
|
+
const scenario = classifyScenario(input.host, input.presence, input.head);
|
|
205
|
+
const { freshness, alignment } = evaluateHead(input.head);
|
|
206
|
+
const risk = gradeRisk(input.riskFactors);
|
|
207
|
+
const mode = selectMode(scenario, freshness, alignment, risk);
|
|
208
|
+
const firstReview = !input.presence.hasPriorPrReview;
|
|
209
|
+
return {
|
|
210
|
+
host: input.host,
|
|
211
|
+
scenario,
|
|
212
|
+
freshness,
|
|
213
|
+
alignment,
|
|
214
|
+
risk,
|
|
215
|
+
mode,
|
|
216
|
+
firstReview,
|
|
217
|
+
reason: buildReason({
|
|
218
|
+
scenario,
|
|
219
|
+
freshness,
|
|
220
|
+
alignment,
|
|
221
|
+
risk,
|
|
222
|
+
mode,
|
|
223
|
+
firstReview,
|
|
224
|
+
hasPriorPrReview: input.presence.hasPriorPrReview
|
|
225
|
+
})
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
export { hasFullArtifacts, hasNoLifecycleArtifacts, isTrusted };
|
|
229
|
+
//# sourceMappingURL=evidence-grading.js.map
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { detectRepoRoot } from '../task/resolve-ref.js';
|
|
5
|
+
import { normalizeObjects } from './normalize.js';
|
|
6
|
+
import { reconcileRecords } from './reconcile.js';
|
|
7
|
+
import { readAppliedOverlays, repairSnapshot } from './repair.js';
|
|
8
|
+
import { collectGitHubObjects, collectLocalObjects } from './sources.js';
|
|
9
|
+
import { canonicalJsonBytes, createObjectStore, publishSnapshot, verifySnapshot } from './store.js';
|
|
10
|
+
const USAGE = `Usage: ai data <command> [options]
|
|
11
|
+
|
|
12
|
+
Commands:
|
|
13
|
+
capture [--source all|local|github] [--root <dir>] [--include-excerpts]
|
|
14
|
+
verify <snapshot-id> [--root <dir>]
|
|
15
|
+
audit <snapshot-id> [--root <dir>] [--format json|text]
|
|
16
|
+
repair <snapshot-id> [--root <dir>] [--apply]
|
|
17
|
+
export <snapshot-id> [--root <dir>] [--repairs none|applied] [--output <file|->]
|
|
18
|
+
`;
|
|
19
|
+
function parseArgs(args, valueOptions, booleanOptions) {
|
|
20
|
+
const positionals = [];
|
|
21
|
+
const options = new Map();
|
|
22
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
23
|
+
const arg = args[index];
|
|
24
|
+
if (!arg.startsWith('--')) {
|
|
25
|
+
positionals.push(arg);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (booleanOptions.has(arg)) {
|
|
29
|
+
if (options.has(arg))
|
|
30
|
+
throw new Error(`duplicate option: ${arg}`);
|
|
31
|
+
options.set(arg, true);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (!valueOptions.has(arg))
|
|
35
|
+
throw new Error(`unknown option: ${arg}`);
|
|
36
|
+
const value = args[index + 1];
|
|
37
|
+
if (!value || value.startsWith('--'))
|
|
38
|
+
throw new Error(`missing value for ${arg}`);
|
|
39
|
+
if (options.has(arg))
|
|
40
|
+
throw new Error(`duplicate option: ${arg}`);
|
|
41
|
+
options.set(arg, value);
|
|
42
|
+
index += 1;
|
|
43
|
+
}
|
|
44
|
+
return { positionals, options };
|
|
45
|
+
}
|
|
46
|
+
function dataRoot(repoRoot, requested) {
|
|
47
|
+
const workspace = path.resolve(repoRoot, '.agents', 'workspace');
|
|
48
|
+
const resolved = path.resolve(repoRoot, requested ?? path.join('.agents', 'workspace', 'process-data'));
|
|
49
|
+
const relative = path.relative(repoRoot, resolved);
|
|
50
|
+
if (!relative || relative.startsWith('..') || path.isAbsolute(relative))
|
|
51
|
+
throw new Error('data root must be inside the repository');
|
|
52
|
+
const taskRoots = ['active', 'blocked', 'completed', 'archive'].map((state) => path.join(workspace, state));
|
|
53
|
+
if (resolved === workspace || taskRoots.some((taskRoot) => resolved === taskRoot || resolved.startsWith(`${taskRoot}${path.sep}`))) {
|
|
54
|
+
throw new Error('data root cannot be the workspace root or a task directory');
|
|
55
|
+
}
|
|
56
|
+
let current = resolved;
|
|
57
|
+
while (current !== repoRoot) {
|
|
58
|
+
if (fs.existsSync(current) && fs.lstatSync(current).isSymbolicLink())
|
|
59
|
+
throw new Error('data root cannot traverse a symlink');
|
|
60
|
+
current = path.dirname(current);
|
|
61
|
+
}
|
|
62
|
+
return resolved;
|
|
63
|
+
}
|
|
64
|
+
function repositoryIdentity(repoRoot) {
|
|
65
|
+
try {
|
|
66
|
+
return execFileSync('git', ['config', '--get', 'remote.origin.url'], { cwd: repoRoot, encoding: 'utf8' }).trim() || path.basename(repoRoot);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return path.basename(repoRoot);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function writeJson(value) {
|
|
73
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
74
|
+
}
|
|
75
|
+
function optionString(parsed, name) {
|
|
76
|
+
const value = parsed.options.get(name);
|
|
77
|
+
return typeof value === 'string' ? value : undefined;
|
|
78
|
+
}
|
|
79
|
+
function capture(args) {
|
|
80
|
+
const parsed = parseArgs(args, new Set(['--source', '--root']), new Set(['--include-excerpts']));
|
|
81
|
+
if (parsed.positionals.length > 0)
|
|
82
|
+
throw new Error('capture does not accept positional arguments');
|
|
83
|
+
const scope = optionString(parsed, '--source') ?? 'all';
|
|
84
|
+
if (!['all', 'local', 'github'].includes(scope))
|
|
85
|
+
throw new Error('--source must be all, local, or github');
|
|
86
|
+
const repoRoot = detectRepoRoot();
|
|
87
|
+
const root = dataRoot(repoRoot, optionString(parsed, '--root'));
|
|
88
|
+
const observedFrom = new Date().toISOString();
|
|
89
|
+
const objects = [];
|
|
90
|
+
const endpoints = [];
|
|
91
|
+
let repository = repositoryIdentity(repoRoot);
|
|
92
|
+
if (scope === 'all' || scope === 'local') {
|
|
93
|
+
const local = collectLocalObjects(repoRoot, { includeExcerpts: parsed.options.has('--include-excerpts') });
|
|
94
|
+
if (!local.ok) {
|
|
95
|
+
writeJson({ ok: false, error: local.error });
|
|
96
|
+
return 2;
|
|
97
|
+
}
|
|
98
|
+
objects.push(...local.value);
|
|
99
|
+
}
|
|
100
|
+
if (scope === 'all' || scope === 'github') {
|
|
101
|
+
const github = collectGitHubObjects(repoRoot);
|
|
102
|
+
if (!github.ok) {
|
|
103
|
+
writeJson({ ok: false, error: github.error });
|
|
104
|
+
return 2;
|
|
105
|
+
}
|
|
106
|
+
objects.push(...github.value.objects);
|
|
107
|
+
endpoints.push(...github.value.endpoints);
|
|
108
|
+
repository = github.value.repository;
|
|
109
|
+
}
|
|
110
|
+
const store = createObjectStore(root);
|
|
111
|
+
for (const object of objects) {
|
|
112
|
+
if (object.content !== undefined && object.disposition?.state === 'included') {
|
|
113
|
+
const stored = store.put(Buffer.from(object.content, 'utf8'));
|
|
114
|
+
if (stored.sha256 !== object.sha256)
|
|
115
|
+
throw new Error(`source hash mismatch: ${object.sourceIdentity}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const records = normalizeObjects(objects);
|
|
119
|
+
const reconciliation = reconcileRecords(records, scope);
|
|
120
|
+
const observedTo = new Date().toISOString();
|
|
121
|
+
const published = publishSnapshot(root, {
|
|
122
|
+
scope: scope,
|
|
123
|
+
repository,
|
|
124
|
+
observedFrom,
|
|
125
|
+
observedTo,
|
|
126
|
+
objects: objects.map(({ content: _content, ...object }) => object),
|
|
127
|
+
endpoints,
|
|
128
|
+
excerptsEnabled: parsed.options.has('--include-excerpts'),
|
|
129
|
+
records,
|
|
130
|
+
quality: reconciliation.findings,
|
|
131
|
+
repairs: reconciliation.repairs
|
|
132
|
+
});
|
|
133
|
+
writeJson({ ok: true, snapshotId: published.snapshotId, scope, created: published.created, objects: objects.length, records: records.length });
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
function verify(args) {
|
|
137
|
+
const parsed = parseArgs(args, new Set(['--root']), new Set());
|
|
138
|
+
if (parsed.positionals.length !== 1)
|
|
139
|
+
throw new Error('verify requires one snapshot id');
|
|
140
|
+
const repoRoot = detectRepoRoot();
|
|
141
|
+
const result = verifySnapshot(dataRoot(repoRoot, optionString(parsed, '--root')), parsed.positionals[0]);
|
|
142
|
+
writeJson(result);
|
|
143
|
+
return result.ok ? 0 : 1;
|
|
144
|
+
}
|
|
145
|
+
function audit(args) {
|
|
146
|
+
const parsed = parseArgs(args, new Set(['--root', '--format']), new Set());
|
|
147
|
+
if (parsed.positionals.length !== 1)
|
|
148
|
+
throw new Error('audit requires one snapshot id');
|
|
149
|
+
const format = optionString(parsed, '--format') ?? 'text';
|
|
150
|
+
if (!['json', 'text'].includes(format))
|
|
151
|
+
throw new Error('--format must be json or text');
|
|
152
|
+
const repoRoot = detectRepoRoot();
|
|
153
|
+
const root = dataRoot(repoRoot, optionString(parsed, '--root'));
|
|
154
|
+
const verified = verifySnapshot(root, parsed.positionals[0]);
|
|
155
|
+
if (!verified.ok || !verified.snapshotPath || !verified.manifest) {
|
|
156
|
+
writeJson(verified);
|
|
157
|
+
return 1;
|
|
158
|
+
}
|
|
159
|
+
const quality = JSON.parse(fs.readFileSync(path.join(verified.snapshotPath, 'quality.json'), 'utf8'));
|
|
160
|
+
const records = fs.readFileSync(path.join(verified.snapshotPath, 'normalized.jsonl'), 'utf8').split('\n').filter(Boolean).map((line) => {
|
|
161
|
+
const { schema: _schema, ...record } = JSON.parse(line);
|
|
162
|
+
return record;
|
|
163
|
+
});
|
|
164
|
+
const recomputed = reconcileRecords(records, verified.manifest.scope);
|
|
165
|
+
if (!canonicalJsonBytes(recomputed.findings).equals(canonicalJsonBytes(quality.findings))) {
|
|
166
|
+
writeJson({ ok: false, error: { code: 'QUALITY_MISMATCH', message: 'stored quality baseline does not match recomputed findings' } });
|
|
167
|
+
return 1;
|
|
168
|
+
}
|
|
169
|
+
if (format === 'json')
|
|
170
|
+
writeJson({ ok: true, snapshotId: parsed.positionals[0], findings: recomputed.findings });
|
|
171
|
+
else
|
|
172
|
+
process.stdout.write(`Snapshot ${parsed.positionals[0]}: ${quality.findings.length} findings\n`);
|
|
173
|
+
return 0;
|
|
174
|
+
}
|
|
175
|
+
function repair(args) {
|
|
176
|
+
const parsed = parseArgs(args, new Set(['--root']), new Set(['--apply']));
|
|
177
|
+
if (parsed.positionals.length !== 1)
|
|
178
|
+
throw new Error('repair requires one snapshot id');
|
|
179
|
+
const repoRoot = detectRepoRoot();
|
|
180
|
+
const result = repairSnapshot(dataRoot(repoRoot, optionString(parsed, '--root')), parsed.positionals[0], parsed.options.has('--apply'));
|
|
181
|
+
writeJson({ ok: true, ...result });
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
function exportSnapshot(args) {
|
|
185
|
+
const parsed = parseArgs(args, new Set(['--root', '--repairs', '--output']), new Set());
|
|
186
|
+
if (parsed.positionals.length !== 1)
|
|
187
|
+
throw new Error('export requires one snapshot id');
|
|
188
|
+
const repairMode = optionString(parsed, '--repairs') ?? 'none';
|
|
189
|
+
if (!['none', 'applied'].includes(repairMode))
|
|
190
|
+
throw new Error('--repairs must be none or applied');
|
|
191
|
+
const output = optionString(parsed, '--output') ?? '-';
|
|
192
|
+
const repoRoot = detectRepoRoot();
|
|
193
|
+
const root = dataRoot(repoRoot, optionString(parsed, '--root'));
|
|
194
|
+
const verified = verifySnapshot(root, parsed.positionals[0]);
|
|
195
|
+
if (!verified.ok || !verified.snapshotPath) {
|
|
196
|
+
writeJson(verified);
|
|
197
|
+
return 1;
|
|
198
|
+
}
|
|
199
|
+
let content = fs.readFileSync(path.join(verified.snapshotPath, 'normalized.jsonl'), 'utf8');
|
|
200
|
+
if (repairMode === 'applied')
|
|
201
|
+
content += readAppliedOverlays(root, parsed.positionals[0]);
|
|
202
|
+
if (output === '-')
|
|
203
|
+
process.stdout.write(content);
|
|
204
|
+
else {
|
|
205
|
+
const destination = path.resolve(repoRoot, output);
|
|
206
|
+
const relative = path.relative(repoRoot, destination);
|
|
207
|
+
if (!relative || relative.startsWith('..') || path.isAbsolute(relative))
|
|
208
|
+
throw new Error('export output must be inside the repository');
|
|
209
|
+
fs.writeFileSync(destination, content, { flag: 'wx', mode: 0o600 });
|
|
210
|
+
writeJson({ ok: true, snapshotId: parsed.positionals[0], output: relative });
|
|
211
|
+
}
|
|
212
|
+
return 0;
|
|
213
|
+
}
|
|
214
|
+
async function cmdData(args) {
|
|
215
|
+
const [command, ...rest] = args;
|
|
216
|
+
if (!command || command === '--help' || command === '-h' || command === 'help') {
|
|
217
|
+
process.stdout.write(USAGE);
|
|
218
|
+
return command ? 0 : 1;
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
switch (command) {
|
|
222
|
+
case 'capture': return capture(rest);
|
|
223
|
+
case 'verify': return verify(rest);
|
|
224
|
+
case 'audit': return audit(rest);
|
|
225
|
+
case 'repair': return repair(rest);
|
|
226
|
+
case 'export': return exportSnapshot(rest);
|
|
227
|
+
default:
|
|
228
|
+
process.stderr.write(`Unknown data command: ${command}\n`);
|
|
229
|
+
process.stdout.write(USAGE);
|
|
230
|
+
return 1;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
writeJson({ ok: false, error: { code: 'DATA_COMMAND_FAILED', message: error instanceof Error ? error.message : String(error) } });
|
|
235
|
+
return 1;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
export { cmdData, dataRoot };
|
|
239
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { sha256 } from './store.js';
|
|
2
|
+
const TASK_ID_RE = /TASK-\d{8}-\d{6}/;
|
|
3
|
+
const ACTIVITY_RE = /^- (\d{4}-\d{2}-\d{2} [^ ]+) — \*\*(.+?)\*\* by ([^ ]+) — (.+)$/gm;
|
|
4
|
+
const LEDGER_RE = /^\|\s*((?:AN|PL|CD)-\d+)\s*\|\s*(analysis|plan|code)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|$/gm;
|
|
5
|
+
const RULING_RE = /^###\s+(HDR-\d+)\s*$([\s\S]*?)(?=^###\s+|^##\s+|(?![\s\S]))/gm;
|
|
6
|
+
const CONFLICT_STATUSES = new Set(['open', 'accepted', 'adjusted', 'refuted', 'cannot-judge', 'needs-human-decision']);
|
|
7
|
+
function recordId(kind, identity, suffix = '') {
|
|
8
|
+
return `${kind}:${sha256(`${identity}\0${suffix}`).slice(0, 24)}`;
|
|
9
|
+
}
|
|
10
|
+
function canonicalActor(raw) {
|
|
11
|
+
const lowered = raw.toLowerCase();
|
|
12
|
+
const aliases = {
|
|
13
|
+
'claude-code': 'claude',
|
|
14
|
+
'antigravity-cli': 'antigravity',
|
|
15
|
+
'gemini-cli': 'gemini',
|
|
16
|
+
gemini: 'gemini'
|
|
17
|
+
};
|
|
18
|
+
if (['claude', 'codex', 'antigravity', 'opencode', 'cursor', 'human'].includes(lowered))
|
|
19
|
+
return lowered;
|
|
20
|
+
return aliases[lowered] ?? null;
|
|
21
|
+
}
|
|
22
|
+
function nextOccurrence(occurrences, identity) {
|
|
23
|
+
const occurrence = (occurrences.get(identity) ?? 0) + 1;
|
|
24
|
+
occurrences.set(identity, occurrence);
|
|
25
|
+
return occurrence === 1 ? '' : `occurrence=${occurrence}`;
|
|
26
|
+
}
|
|
27
|
+
function normalizePlatformPage(object) {
|
|
28
|
+
if (!object.content)
|
|
29
|
+
return [];
|
|
30
|
+
try {
|
|
31
|
+
const page = JSON.parse(object.content);
|
|
32
|
+
if (!Array.isArray(page))
|
|
33
|
+
return [];
|
|
34
|
+
return page.map((entry, index) => {
|
|
35
|
+
const value = entry;
|
|
36
|
+
const identity = String(value.id ?? value.node_id ?? value.sha ?? value.number ?? `${object.sourceIdentity}:${index}`);
|
|
37
|
+
const platformIdentity = /\/issues\?/.test(object.sourceIdentity) && typeof value.number === 'number'
|
|
38
|
+
? `issue:${value.number}`
|
|
39
|
+
: /\/pulls\?/.test(object.sourceIdentity) && typeof value.number === 'number'
|
|
40
|
+
? `pr:${value.number}`
|
|
41
|
+
: /\/issues\/\d+\/comments/.test(object.sourceIdentity)
|
|
42
|
+
? `issue-comment:${identity}`
|
|
43
|
+
: /\/pulls\/\d+\/reviews/.test(object.sourceIdentity)
|
|
44
|
+
? `review:${identity}`
|
|
45
|
+
: /\/pulls\/\d+\/commits/.test(object.sourceIdentity)
|
|
46
|
+
? `commit:${identity}`
|
|
47
|
+
: `platform:${identity}`;
|
|
48
|
+
const binding = typeof value.body === 'string' ? value.body.match(TASK_ID_RE)?.[0] : undefined;
|
|
49
|
+
return {
|
|
50
|
+
recordId: recordId('platform-resource', object.sourceIdentity, identity),
|
|
51
|
+
kind: 'platform-resource',
|
|
52
|
+
sourceIdentity: platformIdentity,
|
|
53
|
+
sourceSha256: object.sha256,
|
|
54
|
+
...(binding ? { binding } : {}),
|
|
55
|
+
data: entry
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function normalizeObjects(objects) {
|
|
64
|
+
const records = [];
|
|
65
|
+
for (const object of objects) {
|
|
66
|
+
if (object.disposition?.state && object.disposition.state !== 'included') {
|
|
67
|
+
records.push({
|
|
68
|
+
recordId: recordId('missing', object.sourceIdentity),
|
|
69
|
+
kind: 'missing',
|
|
70
|
+
sourceIdentity: object.sourceIdentity,
|
|
71
|
+
sourceSha256: object.sha256,
|
|
72
|
+
data: object.disposition.state === 'excluded-sensitive'
|
|
73
|
+
? { reason: 'privacy-excluded', ruleId: object.disposition.ruleId }
|
|
74
|
+
: { reason: object.disposition.reason }
|
|
75
|
+
});
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (object.sourceKind === 'github-rest') {
|
|
79
|
+
records.push(...normalizePlatformPage(object));
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (object.sourceKind === 'operational-report') {
|
|
83
|
+
records.push({
|
|
84
|
+
recordId: recordId('operational-report', object.sourceIdentity),
|
|
85
|
+
kind: 'operational-report',
|
|
86
|
+
sourceIdentity: object.sourceIdentity,
|
|
87
|
+
sourceSha256: object.sha256
|
|
88
|
+
});
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (object.sourceKind === 'structured-telemetry') {
|
|
92
|
+
let data = { availability: 'unknown' };
|
|
93
|
+
try {
|
|
94
|
+
data = JSON.parse(object.content ?? '{}');
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
data = { availability: 'unavailable', reason: 'invalid receipt JSON' };
|
|
98
|
+
}
|
|
99
|
+
records.push({
|
|
100
|
+
recordId: recordId('telemetry', object.sourceIdentity),
|
|
101
|
+
kind: 'telemetry',
|
|
102
|
+
sourceIdentity: object.sourceIdentity,
|
|
103
|
+
sourceSha256: object.sha256,
|
|
104
|
+
data
|
|
105
|
+
});
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const taskId = object.sourceIdentity.match(TASK_ID_RE)?.[0];
|
|
109
|
+
if (/\/task\.md$/.test(object.sourceIdentity) && taskId) {
|
|
110
|
+
const activityOccurrences = new Map();
|
|
111
|
+
const findingOccurrences = new Map();
|
|
112
|
+
const issueNumber = object.content?.match(/^issue_number:\s*(\d+)$/m)?.[1];
|
|
113
|
+
const agentInfraVersion = object.content?.match(/^agent_infra_version:\s*(\S+)$/m)?.[1];
|
|
114
|
+
records.push({
|
|
115
|
+
recordId: recordId('task', taskId),
|
|
116
|
+
kind: 'task',
|
|
117
|
+
sourceIdentity: taskId,
|
|
118
|
+
sourceSha256: object.sha256,
|
|
119
|
+
...(issueNumber ? { binding: `issue:${issueNumber}` } : {}),
|
|
120
|
+
data: {
|
|
121
|
+
agentInfraVersion: agentInfraVersion
|
|
122
|
+
? { state: 'known', value: agentInfraVersion }
|
|
123
|
+
: { state: 'unknown', reason: 'legacy-task-missing-agent-infra-version' }
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
for (const match of object.content?.matchAll(ACTIVITY_RE) ?? []) {
|
|
127
|
+
const rawActor = match[3];
|
|
128
|
+
const identity = `${match[1]}:${match[2]}`;
|
|
129
|
+
const occurrence = nextOccurrence(activityOccurrences, identity);
|
|
130
|
+
records.push({
|
|
131
|
+
recordId: recordId('lifecycle-event', taskId, occurrence ? `${identity}\0${occurrence}` : identity),
|
|
132
|
+
kind: 'lifecycle-event',
|
|
133
|
+
sourceIdentity: `${taskId}#activity=${match[1]}`,
|
|
134
|
+
sourceSha256: object.sha256,
|
|
135
|
+
data: {
|
|
136
|
+
timestamp: match[1],
|
|
137
|
+
action: match[2],
|
|
138
|
+
actorRaw: rawActor,
|
|
139
|
+
actorCanonical: canonicalActor(rawActor),
|
|
140
|
+
note: match[4]
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
for (const match of object.content?.matchAll(LEDGER_RE) ?? []) {
|
|
145
|
+
const findingId = match[1].trim();
|
|
146
|
+
const stage = match[2].trim();
|
|
147
|
+
const round = match[3].trim();
|
|
148
|
+
const severity = match[4].trim();
|
|
149
|
+
const status = match[5].trim();
|
|
150
|
+
const evidence = match[6].trim();
|
|
151
|
+
const identity = `${taskId}#finding=${findingId}`;
|
|
152
|
+
const occurrence = nextOccurrence(findingOccurrences, identity);
|
|
153
|
+
const data = { findingId, stage, round, severity, status, evidence };
|
|
154
|
+
records.push({
|
|
155
|
+
recordId: recordId('review-finding', identity, occurrence),
|
|
156
|
+
kind: 'review-finding',
|
|
157
|
+
sourceIdentity: identity,
|
|
158
|
+
sourceSha256: object.sha256,
|
|
159
|
+
binding: taskId,
|
|
160
|
+
data
|
|
161
|
+
});
|
|
162
|
+
if (status && CONFLICT_STATUSES.has(status)) {
|
|
163
|
+
records.push({
|
|
164
|
+
recordId: recordId('conflict', identity, occurrence),
|
|
165
|
+
kind: 'conflict',
|
|
166
|
+
sourceIdentity: `${identity}#status=${status}`,
|
|
167
|
+
sourceSha256: object.sha256,
|
|
168
|
+
binding: taskId,
|
|
169
|
+
data
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
for (const match of object.content?.matchAll(RULING_RE) ?? []) {
|
|
174
|
+
const rulingId = match[1];
|
|
175
|
+
const identity = `${taskId}#ruling=${rulingId}`;
|
|
176
|
+
records.push({
|
|
177
|
+
recordId: recordId('human-ruling', identity),
|
|
178
|
+
kind: 'human-ruling',
|
|
179
|
+
sourceIdentity: identity,
|
|
180
|
+
sourceSha256: object.sha256,
|
|
181
|
+
binding: taskId,
|
|
182
|
+
data: { rulingId, evidence: match[2].trim() }
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
records.push({
|
|
188
|
+
recordId: recordId('artifact', object.sourceIdentity),
|
|
189
|
+
kind: 'artifact',
|
|
190
|
+
sourceIdentity: object.sourceIdentity,
|
|
191
|
+
sourceSha256: object.sha256,
|
|
192
|
+
...(taskId ? { binding: taskId } : {})
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return records.sort((left, right) => left.recordId.localeCompare(right.recordId));
|
|
196
|
+
}
|
|
197
|
+
export { normalizeObjects };
|
|
198
|
+
//# sourceMappingURL=normalize.js.map
|