@mmerterden/multi-agent-pipeline 20.2.1 → 20.3.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/CHANGELOG.md +919 -1
- package/README.md +104 -81
- package/README.tr.md +103 -62
- package/docs/FIGMA_PIPELINE.md +35 -35
- package/docs/adr/0006-skills-core-external-split.md +1 -1
- package/docs/adr/0007-multi-tool-adapter-framework.md +6 -0
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +7 -0
- package/docs/architecture.md +50 -14
- package/docs/best-practices.md +1 -1
- package/docs/ecosystem.md +56 -32
- package/docs/facts.json +10 -10
- package/docs/features.md +97 -5
- package/docs/recovery-guide.md +7 -14
- package/docs/server-readiness.md +31 -24
- package/index.js +1 -1
- package/install/_common.mjs +3 -5
- package/install/_platform-filter.mjs +23 -1
- package/install/_unattended-profile.mjs +321 -75
- package/install/claude.mjs +51 -10
- package/install/codex.mjs +2 -0
- package/install/copilot.mjs +2 -0
- package/install/index.mjs +30 -17
- package/install/templates/claude-hooks.json +16 -5
- package/install/templates/copilot-instructions.md +1 -1
- package/install/templates/multi-agent-autopilot-awake.plist.template +48 -0
- package/install/templates/multi-agent-autopilot.plist.template +12 -5
- package/install/unattended-profile-legacy.json +80 -0
- package/manifest.json +617 -483
- package/package.json +8 -3
- package/pipeline/agents/code-reviewer.md +10 -0
- package/pipeline/agents/plan-critic.md +98 -0
- package/pipeline/agents/security-auditor.md +10 -0
- package/pipeline/agents/task-clarifier.md +10 -0
- package/pipeline/commands/multi-agent/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/analysis/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +12 -1
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/autopilot-off/SKILL.md +36 -6
- package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +77 -12
- package/pipeline/commands/multi-agent/autopilot-status/SKILL.md +29 -8
- package/pipeline/commands/multi-agent/build-optimize/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/channels/SKILL.md +9 -9
- package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/create-jira/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/design-check/SKILL.md +16 -11
- package/pipeline/commands/multi-agent/diff-explain/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/doctor/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/feedback/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/forget/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/graph/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/help/SKILL.md +37 -39
- package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/issue/SKILL.md +7 -1
- package/pipeline/commands/multi-agent/jira/SKILL.md +7 -1
- package/pipeline/commands/multi-agent/kill/SKILL.md +9 -3
- package/pipeline/commands/multi-agent/language/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/log/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +5 -0
- package/pipeline/commands/multi-agent/model/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/prune-logs/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/prune-prompts/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/purge/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/refactor/SKILL.md +5 -0
- package/pipeline/commands/multi-agent/research/SKILL.md +49 -0
- package/pipeline/commands/multi-agent/resume/SKILL.md +29 -6
- package/pipeline/commands/multi-agent/review/SKILL.md +28 -9
- package/pipeline/commands/multi-agent/review-analysis/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/review-issue/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/review-jira/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-off/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-on/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-status/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/routines/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/save/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/scaffold/SKILL.md +47 -0
- package/pipeline/commands/multi-agent/scan/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/search/SKILL.md +12 -8
- package/pipeline/commands/multi-agent/security-review/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/serve/SKILL.md +62 -0
- package/pipeline/commands/multi-agent/setup/SKILL.md +27 -36
- package/pipeline/commands/multi-agent/stack/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/status/SKILL.md +10 -9
- package/pipeline/commands/multi-agent/steer/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/store-ready/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/sync/SKILL.md +13 -13
- package/pipeline/commands/multi-agent/test/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-accessibility/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-dark-mode/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-dynamic-type/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-screenshots/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/uninstall/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/update/SKILL.md +4 -0
- package/pipeline/contract/CHANGELOG.md +74 -0
- package/pipeline/contract/README.md +126 -0
- package/pipeline/contract/build.mjs +427 -0
- package/pipeline/contract/fixtures/answer-result.json +11 -0
- package/pipeline/contract/fixtures/error-invalid-request.json +8 -0
- package/pipeline/contract/fixtures/error-unauthorized.json +5 -0
- package/pipeline/contract/fixtures/error-unsigned.json +5 -0
- package/pipeline/contract/fixtures/issues-empty.json +18 -0
- package/pipeline/contract/fixtures/launch-plan.json +31 -0
- package/pipeline/contract/fixtures/runs-awaiting-question.json +70 -0
- package/pipeline/contract/fixtures/runs-empty.json +6 -0
- package/pipeline/contract/fixtures/runs-failed.json +84 -0
- package/pipeline/contract/fixtures/runs-old-schema.json +70 -0
- package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +101 -0
- package/pipeline/contract/fixtures/runs-pr-opened.json +106 -0
- package/pipeline/contract/fixtures/runs-running.json +84 -0
- package/pipeline/contract/fixtures/worktrees-empty.json +4 -0
- package/pipeline/contract/frozen/toolbox.json +107 -0
- package/pipeline/contract/manifest.json +263 -0
- package/pipeline/contract/types/index.d.ts +343 -0
- package/pipeline/lib/_jira-auth.sh +6 -2
- package/pipeline/lib/account-resolver.sh +1 -1
- package/pipeline/lib/autopilot-state.sh +19 -0
- package/pipeline/lib/context-link-extractor.sh +12 -5
- package/pipeline/lib/credential-inventory.sh +12 -5
- package/pipeline/lib/credential-store.sh +116 -185
- package/pipeline/lib/fetch-confluence.sh +44 -3
- package/pipeline/lib/fetch-document.sh +3 -4
- package/pipeline/lib/fetch-fortify.sh +1 -1
- package/pipeline/lib/figma-mcp-refresh.sh +2 -2
- package/pipeline/lib/figma-token.sh +5 -1
- package/pipeline/lib/issue-fetcher.sh +233 -16
- package/pipeline/lib/json-file-lock.mjs +172 -0
- package/pipeline/lib/model-dispatch.sh +21 -12
- package/pipeline/lib/model-rung.sh +6 -1
- package/pipeline/lib/multi-repo-pipeline.sh +1 -1
- package/pipeline/lib/outbound-gate.mjs +46 -16
- package/pipeline/lib/parse-complaints.sh +14 -7
- package/pipeline/lib/plan-todos.sh +3 -3
- package/pipeline/lib/post-pr-review.sh +9 -9
- package/pipeline/lib/pr-request-location.mjs +85 -0
- package/pipeline/lib/regular-file.mjs +153 -0
- package/pipeline/lib/repo-hygiene.sh +17 -0
- package/pipeline/lib/route-state.sh +5 -1
- package/pipeline/lib/run-paths.sh +3 -2
- package/pipeline/lib/stack-detect.sh +19 -1
- package/pipeline/lib/unattended-profile-check.mjs +178 -0
- package/pipeline/lib/unattended-settings-location.mjs +28 -0
- package/pipeline/lib/unattended.mjs +76 -0
- package/pipeline/lib/unattended.sh +32 -0
- package/pipeline/lib/untrusted.mjs +76 -0
- package/pipeline/lib/usage-endpoint.mjs +33 -0
- package/pipeline/lib/user-facing.mjs +82 -0
- package/pipeline/lib/user-facing.sh +58 -0
- package/pipeline/multi-agent-refs/_dev-context.md +1 -1
- package/pipeline/multi-agent-refs/analysis/evidence.md +4 -0
- package/pipeline/multi-agent-refs/analysis/locked.md +2 -2
- package/pipeline/multi-agent-refs/analysis/render.md +4 -3
- package/pipeline/multi-agent-refs/analysis/resolve.md +3 -1
- package/pipeline/multi-agent-refs/analysis/synthesis.md +4 -5
- package/pipeline/multi-agent-refs/analysis-template.md +10 -17
- package/pipeline/multi-agent-refs/channels/jira.md +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +3 -3
- package/pipeline/multi-agent-refs/conventions-defaults.md +32 -32
- package/pipeline/multi-agent-refs/cross-cli-contract.md +10 -17
- package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +37 -9
- package/pipeline/multi-agent-refs/features/autopilot-operations.md +277 -0
- package/pipeline/multi-agent-refs/features/constitution.md +196 -0
- package/pipeline/multi-agent-refs/features/doctor.md +6 -3
- package/pipeline/multi-agent-refs/features/external-context-injection.md +6 -1
- package/pipeline/multi-agent-refs/features/jira-context.md +1 -1
- package/pipeline/multi-agent-refs/features/maturity-followup.md +43 -23
- package/pipeline/multi-agent-refs/features/model-fallback.md +9 -0
- package/pipeline/multi-agent-refs/features/phone-api.md +306 -0
- package/pipeline/multi-agent-refs/features/plan-critic.md +159 -0
- package/pipeline/multi-agent-refs/features/research.md +150 -0
- package/pipeline/multi-agent-refs/features/review-decision.md +185 -0
- package/pipeline/multi-agent-refs/features/scaffold.md +160 -0
- package/pipeline/multi-agent-refs/features/security-audit.md +6 -2
- package/pipeline/multi-agent-refs/features/skill-conformance.md +4 -1
- package/pipeline/multi-agent-refs/features/stack-adapters.md +116 -0
- package/pipeline/multi-agent-refs/features/unattended-gates.md +316 -0
- package/pipeline/multi-agent-refs/features/unattended-security.md +731 -0
- package/pipeline/multi-agent-refs/features/url-enrichment.md +2 -2
- package/pipeline/multi-agent-refs/features/usage-reporting.md +127 -35
- package/pipeline/multi-agent-refs/features/verify-by-test.md +1 -1
- package/pipeline/multi-agent-refs/features/visual-evidence.md +7 -7
- package/pipeline/multi-agent-refs/keychain.md +6 -11
- package/pipeline/multi-agent-refs/payload-contracts.md +2 -2
- package/pipeline/multi-agent-refs/phases/log-format.md +2 -3
- package/pipeline/multi-agent-refs/phases/modes.md +10 -12
- package/pipeline/multi-agent-refs/phases/operations.md +11 -5
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +73 -81
- package/pipeline/multi-agent-refs/phases/phase-1-plan.md +22 -22
- package/pipeline/multi-agent-refs/phases/phase-2-dev.md +42 -66
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +45 -79
- package/pipeline/multi-agent-refs/phases/phase-4-commit.md +28 -38
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +27 -25
- package/pipeline/multi-agent-refs/phases.md +1 -1
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/progress-contract.md +13 -16
- package/pipeline/multi-agent-refs/readiness-review.md +1 -1
- package/pipeline/multi-agent-refs/research/engine.md +91 -0
- package/pipeline/multi-agent-refs/rules.md +6 -4
- package/pipeline/multi-agent-refs/setup/repo-discovery.md +2 -2
- package/pipeline/multi-agent-refs/tracker-contract.md +2 -2
- package/pipeline/multi-agent-refs/unattended-contract.md +68 -16
- package/pipeline/rules/figma-pipeline.md +12 -12
- package/pipeline/schemas/agent-state.schema.json +480 -18
- package/pipeline/schemas/analysis-spec.schema.json +4 -4
- package/pipeline/schemas/answer-request.schema.json +24 -0
- package/pipeline/schemas/answer-result.schema.json +28 -0
- package/pipeline/schemas/autopilot-config.schema.json +111 -13
- package/pipeline/schemas/command-parameters.schema.json +99 -0
- package/pipeline/schemas/constitution.schema.json +56 -0
- package/pipeline/schemas/contract-error.schema.json +52 -0
- package/pipeline/schemas/design-check-config.schema.json +5 -1
- package/pipeline/schemas/issues.schema.json +61 -0
- package/pipeline/schemas/launch-plan.schema.json +46 -0
- package/pipeline/schemas/launch-request.schema.json +45 -0
- package/pipeline/schemas/launch.json +61 -0
- package/pipeline/schemas/launch.schema.json +84 -0
- package/pipeline/schemas/phases.json +2 -2
- package/pipeline/schemas/phases.schema.json +68 -0
- package/pipeline/schemas/phone-devices.schema.json +61 -0
- package/pipeline/schemas/phone-signed-request.schema.json +67 -0
- package/pipeline/schemas/plan-critique.schema.json +99 -0
- package/pipeline/schemas/plan-todos.schema.json +7 -7
- package/pipeline/schemas/planning-output.schema.json +5 -0
- package/pipeline/schemas/pr-request.schema.json +46 -0
- package/pipeline/schemas/prefs.schema.json +79 -8
- package/pipeline/schemas/research-output.schema.json +118 -0
- package/pipeline/schemas/review-file-exclusions.schema.json +25 -0
- package/pipeline/schemas/reviewer-output.schema.json +40 -4
- package/pipeline/schemas/run-questions.json +392 -0
- package/pipeline/schemas/run-questions.schema.json +118 -0
- package/pipeline/schemas/runs-index.schema.json +189 -0
- package/pipeline/schemas/scaffold-manifest.schema.json +43 -0
- package/pipeline/schemas/secret-patterns.schema.json +28 -0
- package/pipeline/schemas/stack-adapters.json +527 -0
- package/pipeline/schemas/stack-adapters.schema.json +184 -0
- package/pipeline/schemas/token-budget.json +1 -1
- package/pipeline/schemas/token-budget.schema.json +26 -0
- package/pipeline/schemas/triage-output.schema.json +64 -3
- package/pipeline/schemas/unattended-policy.json +139 -0
- package/pipeline/schemas/unattended-policy.schema.json +73 -0
- package/pipeline/schemas/unattended-profile.json +248 -0
- package/pipeline/schemas/unattended-profile.schema.json +198 -0
- package/pipeline/schemas/worktrees.schema.json +51 -0
- package/pipeline/scripts/README.md +1 -0
- package/pipeline/scripts/_autopilot-config.mjs +130 -0
- package/pipeline/scripts/_autopilot-ops.mjs +567 -0
- package/pipeline/scripts/_autopilot-outcomes.mjs +174 -0
- package/pipeline/scripts/_command-contract.mjs +384 -0
- package/pipeline/scripts/_cost.mjs +40 -0
- package/pipeline/scripts/_notices.mjs +160 -0
- package/pipeline/scripts/_phone-auth.mjs +485 -0
- package/pipeline/scripts/_pre-existing.mjs +294 -0
- package/pipeline/scripts/_redact.mjs +77 -0
- package/pipeline/scripts/_run-paths.mjs +4 -2
- package/pipeline/scripts/_stack-adapter.mjs +678 -0
- package/pipeline/scripts/_stack-routing.mjs +1 -1
- package/pipeline/scripts/agent-guard.py +348 -37
- package/pipeline/scripts/agent-guard.sh +41 -13
- package/pipeline/scripts/analysis-story-tree.mjs +79 -3
- package/pipeline/scripts/answer-question.mjs +181 -0
- package/pipeline/scripts/audit-log-rotate.sh +1 -4
- package/pipeline/scripts/audit-log.sh +4 -4
- package/pipeline/scripts/autopilot-arming.mjs +389 -21
- package/pipeline/scripts/autopilot-awake.mjs +255 -0
- package/pipeline/scripts/autopilot-intake.mjs +137 -36
- package/pipeline/scripts/autopilot-menubar.swift +156 -44
- package/pipeline/scripts/autopilot-publish.mjs +1625 -0
- package/pipeline/scripts/autopilot-runner.mjs +1678 -222
- package/pipeline/scripts/autopilot-status.sh +198 -33
- package/pipeline/scripts/build-lock.sh +120 -0
- package/pipeline/scripts/build-references.mjs +4 -1
- package/pipeline/scripts/build-stack-plugins.mjs +59 -22
- package/pipeline/scripts/capture-flush.sh +1 -1
- package/pipeline/scripts/capture-resume.sh +13 -9
- package/pipeline/scripts/check-derived-drift.mjs +52 -11
- package/pipeline/scripts/commands.mjs +88 -0
- package/pipeline/scripts/constitution.mjs +362 -0
- package/pipeline/scripts/contract-server.mjs +776 -0
- package/pipeline/scripts/cost-analyze.mjs +89 -39
- package/pipeline/scripts/diff-explain.mjs +12 -1
- package/pipeline/scripts/doctor.mjs +77 -28
- package/pipeline/scripts/evidence-gate.mjs +192 -12
- package/pipeline/scripts/feedback-send.mjs +4 -2
- package/pipeline/scripts/gate-ledger.mjs +449 -0
- package/pipeline/scripts/gc-abandoned.sh +132 -13
- package/pipeline/scripts/gen-facts.mjs +31 -15
- package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
- package/pipeline/scripts/github-ssh-setup.sh +140 -29
- package/pipeline/scripts/graph-mermaid.mjs +4 -1
- package/pipeline/scripts/issues.mjs +236 -0
- package/pipeline/scripts/jira-attach.sh +6 -2
- package/pipeline/scripts/jira-search.sh +4 -3
- package/pipeline/scripts/keychain-save.sh +125 -24
- package/pipeline/scripts/keychain.py +63 -93
- package/pipeline/scripts/launch-request.mjs +747 -0
- package/pipeline/scripts/localize-commands.mjs +4 -10
- package/pipeline/scripts/log-metric.sh +6 -5
- package/pipeline/scripts/maturity-followup.mjs +13 -4
- package/pipeline/scripts/memory-save.sh +25 -0
- package/pipeline/scripts/migrate-prefs.mjs +4 -3
- package/pipeline/scripts/open-questions-gate.mjs +276 -0
- package/pipeline/scripts/phase-tracker.sh +41 -27
- package/pipeline/scripts/phase0-exit-gate.mjs +22 -4
- package/pipeline/scripts/phone-devices.mjs +224 -0
- package/pipeline/scripts/plan-coverage-gate.mjs +200 -66
- package/pipeline/scripts/plan-critique-gate.mjs +591 -0
- package/pipeline/scripts/pr-request.mjs +188 -0
- package/pipeline/scripts/pre-commit-check.sh +115 -4
- package/pipeline/scripts/probe-evidence-capability.sh +44 -5
- package/pipeline/scripts/record-phase.mjs +71 -0
- package/pipeline/scripts/render-agent-log-cost.sh +17 -2
- package/pipeline/scripts/render-cost-summary.sh +1 -1
- package/pipeline/scripts/render-work-summary.sh +1 -1
- package/pipeline/scripts/require-supported-version.sh +4 -1
- package/pipeline/scripts/research-gate.mjs +704 -0
- package/pipeline/scripts/review-decision-gate.mjs +403 -0
- package/pipeline/scripts/routine-registry.mjs +5 -2
- package/pipeline/scripts/runs-index.mjs +135 -27
- package/pipeline/scripts/scaffold-gate.mjs +393 -0
- package/pipeline/scripts/skill-conformance.mjs +25 -8
- package/pipeline/scripts/skill-siblings.mjs +2 -1
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +32 -6
- package/pipeline/scripts/smoke-schema-validation.sh +6 -2
- package/pipeline/scripts/spec-consistency-gate.mjs +469 -0
- package/pipeline/scripts/symbol-existence-gate.mjs +450 -0
- package/pipeline/scripts/test-gap-scan.mjs +40 -2
- package/pipeline/scripts/test-integrity-gate.mjs +20 -4
- package/pipeline/scripts/test-strength.mjs +484 -0
- package/pipeline/scripts/test-summary.mjs +651 -0
- package/pipeline/scripts/triage-memory.mjs +49 -9
- package/pipeline/scripts/unattended_policy.py +2786 -0
- package/pipeline/scripts/uninstall.mjs +10 -10
- package/pipeline/scripts/update-issue-progress.sh +1 -1
- package/pipeline/scripts/usage-identity.mjs +288 -0
- package/pipeline/scripts/usage-register.mjs +187 -67
- package/pipeline/scripts/usage-report.mjs +232 -67
- package/pipeline/scripts/validate-complaint-doc.mjs +28 -10
- package/pipeline/scripts/validate-planning.mjs +6 -0
- package/pipeline/scripts/verify-citations.mjs +151 -38
- package/pipeline/scripts/verify.mjs +58 -18
- package/pipeline/scripts/worktree-prepare.sh +126 -0
- package/pipeline/scripts/worktrees.mjs +124 -0
- package/pipeline/scripts/write-state.mjs +48 -17
- package/pipeline/skills/.skill-manifest.json +222 -226
- package/pipeline/skills/.skills-index.json +77 -88
- package/pipeline/skills/shared/README.md +44 -45
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +3 -2
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +10 -9
- package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +6 -5
- package/pipeline/skills/shared/core/multi-agent-analysis-jira/SKILL.md +11 -3
- package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +4 -3
- package/pipeline/skills/shared/core/multi-agent-autopilot-off/SKILL.md +32 -6
- package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +66 -8
- package/pipeline/skills/shared/core/multi-agent-autopilot-status/SKILL.md +27 -9
- package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +7 -4
- package/pipeline/skills/shared/core/multi-agent-complaint-analysis/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-doctor/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-feedback/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +7 -4
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-prune-prompts/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-research/SKILL.md +35 -0
- package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +7 -3
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-review-analysis/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-scaffold/SKILL.md +30 -0
- package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +4 -3
- package/pipeline/skills/shared/core/multi-agent-security-review/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-serve/SKILL.md +60 -0
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +8 -8
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +7 -8
- package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +10 -10
- package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-accessibility/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-dark-mode/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-dynamic-type/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-screenshots/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -1
- package/pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md +46 -0
- package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +9 -3
- package/pipeline/skills/shared/external/NOTICE-paul-hudson-skills.md +54 -0
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +9 -11
- package/pipeline/skills/shared/external/NOTICE-vibeship-spawner-skills.md +203 -0
- package/pipeline/skills/shared/external/NOTICE-xcode-build-skills.md +10 -3
- package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +131 -25
- package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -3
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +85 -76
- package/pipeline/skills/shared/external/android-build-quality-gates/SKILL.md +51 -3
- package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +9 -0
- package/pipeline/skills/shared/external/android-datastore/SKILL.md +4 -3
- package/pipeline/skills/shared/external/android-design-tokens-codegen/SKILL.md +4 -3
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +106 -181
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +147 -0
- package/pipeline/skills/shared/external/android-mvi-viewmodel/SKILL.md +45 -4
- package/pipeline/skills/shared/external/android-performance/SKILL.md +27 -2
- package/pipeline/skills/shared/external/android-performance/references/patterns.md +37 -37
- package/pipeline/skills/shared/external/api-patterns/SKILL.md +111 -67
- package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +128 -0
- package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +136 -186
- package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +140 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +207 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/operations.md +66 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +175 -0
- package/pipeline/skills/shared/external/app-clips/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-intents/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +4 -3
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +2 -0
- package/pipeline/skills/shared/external/architecture/SKILL.md +106 -39
- package/pipeline/skills/shared/external/architecture/references/adr-and-review.md +76 -0
- package/pipeline/skills/shared/external/authentication/SKILL.md +2 -0
- package/pipeline/skills/shared/external/avkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/background-processing/SKILL.md +2 -1
- package/pipeline/skills/shared/external/backlog/SKILL.md +3 -2
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +2 -0
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +3 -2
- package/pipeline/skills/shared/external/clean-code/SKILL.md +192 -90
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +2 -1
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/compose-components/SKILL.md +4 -4
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +22 -22
- package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +10 -10
- package/pipeline/skills/shared/external/compose-testing/SKILL.md +13 -6
- package/pipeline/skills/shared/external/compose-testing/references/patterns.md +59 -59
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +2 -0
- package/pipeline/skills/shared/external/context-compression/SKILL.md +118 -250
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-data/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-motion/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +2 -0
- package/pipeline/skills/shared/external/coreml/SKILL.md +2 -1
- package/pipeline/skills/shared/external/council/SKILL.md +2 -1
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/css-modern/SKILL.md +3 -2
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +2 -0
- package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +130 -20
- package/pipeline/skills/shared/external/debugging-strategies/references/hard-cases.md +54 -0
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +2 -0
- package/pipeline/skills/shared/external/docker-expert/SKILL.md +137 -381
- package/pipeline/skills/shared/external/docker-expert/references/patterns.md +98 -0
- package/pipeline/skills/shared/external/energykit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +3 -1
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +116 -185
- package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +235 -0
- package/pipeline/skills/shared/external/fastapi-pro/references/testing-and-deployment.md +69 -0
- package/pipeline/skills/shared/external/firebase/SKILL.md +4 -3
- package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +151 -293
- package/pipeline/skills/shared/external/github-actions-templates/references/patterns.md +96 -0
- package/pipeline/skills/shared/external/healthkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/hig-components-content/SKILL.md +69 -72
- package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +111 -0
- package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +77 -86
- package/pipeline/skills/shared/external/hig-components-layout/references/containers.md +98 -0
- package/pipeline/skills/shared/external/hig-components-status/SKILL.md +150 -78
- package/pipeline/skills/shared/external/hig-components-system/SKILL.md +76 -97
- package/pipeline/skills/shared/external/hig-components-system/references/surfaces.md +98 -0
- package/pipeline/skills/shared/external/hig-foundations/SKILL.md +48 -76
- package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +132 -0
- package/pipeline/skills/shared/external/hig-inputs/SKILL.md +147 -106
- package/pipeline/skills/shared/external/hig-patterns/SKILL.md +61 -77
- package/pipeline/skills/shared/external/hig-patterns/references/patterns.md +92 -0
- package/pipeline/skills/shared/external/hig-platforms/SKILL.md +147 -77
- package/pipeline/skills/shared/external/hig-technologies/SKILL.md +61 -121
- package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +108 -0
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +2 -0
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +3 -2
- package/pipeline/skills/shared/external/humanizer/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +14 -2
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
- package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +4 -3
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +8 -6
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +11 -11
- package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +2 -0
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +102 -193
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +103 -0
- package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -2
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +7 -9
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +3 -3
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +2 -2
- package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +4 -3
- package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +5 -3
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +2 -0
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +2 -0
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +149 -46
- package/pipeline/skills/shared/external/monorepo-architect/references/patterns.md +70 -0
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +2 -0
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/natural-language/SKILL.md +2 -0
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +3 -2
- package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +91 -21
- package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +247 -0
- package/pipeline/skills/shared/external/nodejs-backend-patterns/references/testing-and-frameworks.md +57 -0
- package/pipeline/skills/shared/external/observability-engineer/SKILL.md +155 -232
- package/pipeline/skills/shared/external/observability-engineer/references/patterns.md +75 -0
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +2 -0
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +18 -18
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +2 -1
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +2 -0
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +3 -2
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +2 -2
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +3 -2
- package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +7 -7
- package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +69 -69
- package/pipeline/skills/shared/external/room-database/references/patterns.md +126 -126
- package/pipeline/skills/shared/external/search-first/SKILL.md +2 -1
- package/pipeline/skills/shared/external/security-review/SKILL.md +4 -3
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +2 -2
- package/pipeline/skills/shared/external/signal-community/SKILL.md +1 -1
- package/pipeline/skills/shared/external/skill-creator/SKILL.md +2 -1
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +2 -1
- package/pipeline/skills/shared/external/spm-build-analysis/SKILL.md +2 -0
- package/pipeline/skills/shared/external/storekit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swift-concurrency-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swift-security/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +10 -0
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftdata-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swiftui-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +4 -3
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +3 -2
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +3 -2
- package/pipeline/skills/shared/external/tipkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -0
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +3 -2
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +3 -2
- package/pipeline/skills/shared/external/web-performance/SKILL.md +3 -2
- package/pipeline/skills/shared/external/web-testing/SKILL.md +3 -2
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +1 -1
- package/pipeline/skills/shared/external/xcode-build-benchmark/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-build-fixer/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-build-orchestrator/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-compilation-analyzer/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-project-analyzer/SKILL.md +2 -0
- package/pipeline/skills/skills-index.md +40 -41
- package/docs/token-budget-history.md +0 -24
- package/pipeline/skills/shared/external/agentflow/SKILL.md +0 -199
- package/pipeline/skills/shared/external/android-ui-verification/SKILL.md +0 -66
- package/pipeline/skills/shared/external/api-security-best-practices/references/auth.md +0 -299
- package/pipeline/skills/shared/external/api-security-best-practices/references/input-validation.md +0 -255
- package/pipeline/skills/shared/external/api-security-best-practices/references/rate-limiting.md +0 -167
- package/pipeline/skills/shared/external/closed-loop-delivery/SKILL.md +0 -116
- package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -216
|
@@ -52,6 +52,8 @@ import { join } from "path";
|
|
|
52
52
|
import { homedir } from "os";
|
|
53
53
|
import { pathToFileURL } from "url";
|
|
54
54
|
|
|
55
|
+
import { gatesActive } from "../lib/unattended.mjs";
|
|
56
|
+
|
|
55
57
|
const FIGMA_URL = /figma\.com\/(design|make|file)\//i;
|
|
56
58
|
|
|
57
59
|
/** Fields that can carry the user's original request text. */
|
|
@@ -106,9 +108,11 @@ export function inputTextOf(state) {
|
|
|
106
108
|
*
|
|
107
109
|
* @param {object|null} state - parsed agent-state.json, or null when absent
|
|
108
110
|
* @param {string} extraInput - input text supplied on the command line
|
|
111
|
+
* @param {{env?: Record<string, string|undefined>}} [opts] - the environment; with
|
|
112
|
+
* state.autopilot it decides autopilot mode (lib/unattended.mjs, gatesActive)
|
|
109
113
|
* @returns {{ok: boolean, failures: string[], taskType: string|undefined, figmaSeen: boolean}}
|
|
110
114
|
*/
|
|
111
|
-
export function evaluate(state, extraInput = "") {
|
|
115
|
+
export function evaluate(state, extraInput = "", { env = process.env } = {}) {
|
|
112
116
|
const failures = [];
|
|
113
117
|
|
|
114
118
|
if (state === null) {
|
|
@@ -188,7 +192,9 @@ export function evaluate(state, extraInput = "") {
|
|
|
188
192
|
`branch the user chose from one the run picked and announced.`,
|
|
189
193
|
);
|
|
190
194
|
}
|
|
191
|
-
|
|
195
|
+
// Autopilot mode is the launcher's MULTI_AGENT_UNATTENDED or the run's own
|
|
196
|
+
// `autopilot: true` (a terminal /multi-agent:autopilot run), lib/unattended.mjs.
|
|
197
|
+
const isAutopilot = gatesActive(state, env);
|
|
192
198
|
const AUTOPILOT_ONLY_SOURCES = ["remembered", "default", "derived"];
|
|
193
199
|
if (!isAutopilot && AUTOPILOT_ONLY_SOURCES.includes(branchSource)) {
|
|
194
200
|
failures.push(
|
|
@@ -255,8 +261,9 @@ export function evaluate(state, extraInput = "") {
|
|
|
255
261
|
// whether anyone decided: `false` is both "the user chose a worktree" and
|
|
256
262
|
// "nothing asked and the default stood". Same shape as baseBranchSource, and
|
|
257
263
|
// the same reason - an autopilot run resolves it rather than asking, so
|
|
258
|
-
// `autopilot` is a legal source there and nowhere else.
|
|
259
|
-
|
|
264
|
+
// `autopilot` is a legal source there and nowhere else. `request` is a
|
|
265
|
+
// launch request that answered the picker before the run started.
|
|
266
|
+
const WORKSPACE_SOURCES = ["asked", "command", "autopilot", "request"];
|
|
260
267
|
const workspaceSource =
|
|
261
268
|
typeof state.workspaceSource === "string" ? state.workspaceSource.trim() : "";
|
|
262
269
|
if (!WORKSPACE_SOURCES.includes(workspaceSource)) {
|
|
@@ -274,6 +281,17 @@ export function evaluate(state, extraInput = "") {
|
|
|
274
281
|
);
|
|
275
282
|
}
|
|
276
283
|
|
|
284
|
+
// A request is validated before Phase 0 applies it, and local under autopilot
|
|
285
|
+
// is one of the answers it rejects. The gate holds the outcome to the same
|
|
286
|
+
// rule, so a state that reached this point some other way still stops here.
|
|
287
|
+
if (isAutopilot && state.localMode === true) {
|
|
288
|
+
failures.push(
|
|
289
|
+
`localMode=true on an autopilot run (workspaceSource="${workspaceSource || "<unset>"}"). ` +
|
|
290
|
+
`An unattended run always gets a worktree; a launch request asking for local under ` +
|
|
291
|
+
`autopilot is rejected by launch-request.mjs, never applied.`,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
277
295
|
// Step 2b's dev-context picker writes siblings[], empty included. The empty array is
|
|
278
296
|
// the record that it ran; absent, a multi-repo task silently became a single-repo one
|
|
279
297
|
// and Phase 4's parity cross-check lost its fourth counterpart source.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file phone-devices.mjs - enrol, list and revoke the phones allowed to
|
|
4
|
+
* reach the phone routes of contract-server.mjs, and switch phone launch on or
|
|
5
|
+
* off.
|
|
6
|
+
*
|
|
7
|
+
* Enrolment is local on purpose: there is no HTTP route that adds a device,
|
|
8
|
+
* so reaching the server is never enough to be let into it. A device is its
|
|
9
|
+
* Ed25519 public key plus the scopes it may use. The private key stays on the
|
|
10
|
+
* phone; this file never sees it and refuses a PEM block that holds one.
|
|
11
|
+
*
|
|
12
|
+
* read GET /v1/phone/runs, GET /v1/phone/runs/{id}
|
|
13
|
+
* answer POST /v1/phone/runs/{id}/answer
|
|
14
|
+
* launch POST /v1/phone/launch, and only while `launch on` is set
|
|
15
|
+
*
|
|
16
|
+
* The registry is <autopilot root>/phone/devices.json (0600, directory 0700;
|
|
17
|
+
* phone-devices.schema.json). An unattended run may not change it: every
|
|
18
|
+
* subcommand but `list` refuses under MULTI_AGENT_UNATTENDED=1, and the guard
|
|
19
|
+
* blocks the same subcommands by name (unattended-policy.json).
|
|
20
|
+
*
|
|
21
|
+
* Usage:
|
|
22
|
+
* node phone-devices.mjs add --name <name> --public-key <base64url | PEM> --scopes read[,answer][,launch]
|
|
23
|
+
* node phone-devices.mjs add --name <name> --public-key-file <path.pem> --scopes ...
|
|
24
|
+
* node phone-devices.mjs list [--json]
|
|
25
|
+
* node phone-devices.mjs revoke <device-id>
|
|
26
|
+
* node phone-devices.mjs launch on|off
|
|
27
|
+
*
|
|
28
|
+
* Output: `add` prints {id, name, fingerprint, scopes}; `list --json` prints
|
|
29
|
+
* {launchEnabled, devices[]} without keys.
|
|
30
|
+
* Exit: 0 done, 1 refused (unknown device, already revoked), 2 usage,
|
|
31
|
+
* 3 unattended.
|
|
32
|
+
*
|
|
33
|
+
* @module pipeline/scripts/phone-devices
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { readFileSync } from "node:fs";
|
|
37
|
+
import { runMain } from "../lib/fatal.mjs";
|
|
38
|
+
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
39
|
+
import { isUnattended } from "../lib/unattended.mjs";
|
|
40
|
+
import {
|
|
41
|
+
DEVICE_ID,
|
|
42
|
+
SCOPES,
|
|
43
|
+
fingerprint,
|
|
44
|
+
newDeviceId,
|
|
45
|
+
parsePublicKey,
|
|
46
|
+
readRegistry,
|
|
47
|
+
registryPath,
|
|
48
|
+
writeRegistry,
|
|
49
|
+
} from "./_phone-auth.mjs";
|
|
50
|
+
|
|
51
|
+
const NAME = /^[\p{L}\p{N} ._'-]{1,64}$/u;
|
|
52
|
+
const USAGE =
|
|
53
|
+
"usage: phone-devices.mjs add --name <name> --public-key <key> | --public-key-file <pem> --scopes <read,answer,launch>\n" +
|
|
54
|
+
" phone-devices.mjs list [--json] | revoke <device-id> | launch on|off\n";
|
|
55
|
+
|
|
56
|
+
class Usage extends Error {}
|
|
57
|
+
|
|
58
|
+
function options(argv) {
|
|
59
|
+
const out = {};
|
|
60
|
+
for (let i = 0; i < argv.length; i++) {
|
|
61
|
+
const a = argv[i];
|
|
62
|
+
const value = () => {
|
|
63
|
+
const v = argv[++i];
|
|
64
|
+
if (v === undefined) throw new Usage(`${a} needs a value`);
|
|
65
|
+
return v;
|
|
66
|
+
};
|
|
67
|
+
if (a === "--name") out.name = value();
|
|
68
|
+
else if (a === "--public-key") out.key = value();
|
|
69
|
+
else if (a === "--public-key-file") out.keyFile = value();
|
|
70
|
+
else if (a === "--scopes") out.scopes = value();
|
|
71
|
+
else if (a === "--json") out.json = true;
|
|
72
|
+
else out.rest = [...(out.rest ?? []), a];
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function registryForWrite() {
|
|
78
|
+
const reg = readRegistry();
|
|
79
|
+
if (reg.insecure) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`${registryPath()} is ${reg.insecure === "registry-insecure" ? "writable by other users" : "unreadable"}; fix or remove it first`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return reg;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function add(o) {
|
|
88
|
+
if (!o.name || !NAME.test(o.name))
|
|
89
|
+
throw new Usage("--name is 1 to 64 letters, digits, spaces or ._'-");
|
|
90
|
+
if (Boolean(o.key) === Boolean(o.keyFile))
|
|
91
|
+
throw new Usage("give one of --public-key or --public-key-file");
|
|
92
|
+
const scopes = String(o.scopes ?? "")
|
|
93
|
+
.split(",")
|
|
94
|
+
.map((s) => s.trim())
|
|
95
|
+
.filter(Boolean);
|
|
96
|
+
if (!scopes.length) throw new Usage(`--scopes is one or more of ${SCOPES.join(", ")}`);
|
|
97
|
+
const unknown = scopes.filter((s) => !SCOPES.includes(s));
|
|
98
|
+
if (unknown.length)
|
|
99
|
+
throw new Usage(`unknown scope ${unknown.join(", ")}; known: ${SCOPES.join(", ")}`);
|
|
100
|
+
let publicKey;
|
|
101
|
+
try {
|
|
102
|
+
publicKey = parsePublicKey(o.key ?? readFileSync(o.keyFile, "utf8"));
|
|
103
|
+
} catch (err) {
|
|
104
|
+
throw new Usage(`--public-key: ${err.message}`);
|
|
105
|
+
}
|
|
106
|
+
const reg = registryForWrite();
|
|
107
|
+
if (reg.devices.some((d) => d.publicKey === publicKey && !d.revokedAt)) {
|
|
108
|
+
throw new Usage("that key is already enrolled");
|
|
109
|
+
}
|
|
110
|
+
const device = {
|
|
111
|
+
id: newDeviceId(),
|
|
112
|
+
name: o.name,
|
|
113
|
+
publicKey,
|
|
114
|
+
scopes: SCOPES.filter((s) => scopes.includes(s)),
|
|
115
|
+
addedAt: new Date().toISOString(),
|
|
116
|
+
revokedAt: null,
|
|
117
|
+
};
|
|
118
|
+
writeRegistry({ ...reg, devices: [...reg.devices, device] });
|
|
119
|
+
return {
|
|
120
|
+
id: device.id,
|
|
121
|
+
name: device.name,
|
|
122
|
+
fingerprint: fingerprint(publicKey),
|
|
123
|
+
scopes: device.scopes,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function list() {
|
|
128
|
+
const reg = readRegistry();
|
|
129
|
+
return {
|
|
130
|
+
launchEnabled: reg.launchEnabled,
|
|
131
|
+
...(reg.insecure ? { problem: reg.insecure } : {}),
|
|
132
|
+
devices: reg.devices.map((d) => ({
|
|
133
|
+
id: d.id,
|
|
134
|
+
name: d.name,
|
|
135
|
+
fingerprint: fingerprint(d.publicKey),
|
|
136
|
+
scopes: d.scopes,
|
|
137
|
+
addedAt: d.addedAt,
|
|
138
|
+
revokedAt: d.revokedAt ?? null,
|
|
139
|
+
})),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function main(argv) {
|
|
144
|
+
const [cmd, ...rest] = argv;
|
|
145
|
+
let o;
|
|
146
|
+
try {
|
|
147
|
+
o = options(rest);
|
|
148
|
+
} catch (err) {
|
|
149
|
+
process.stderr.write(`phone-devices: ${err.message}\n${USAGE}`);
|
|
150
|
+
return 2;
|
|
151
|
+
}
|
|
152
|
+
if (!["add", "list", "revoke", "launch"].includes(cmd)) {
|
|
153
|
+
process.stderr.write(USAGE);
|
|
154
|
+
return 2;
|
|
155
|
+
}
|
|
156
|
+
if (cmd !== "list" && isUnattended()) {
|
|
157
|
+
process.stderr.write(
|
|
158
|
+
"phone-devices: an unattended run may not change which devices reach this machine\n",
|
|
159
|
+
);
|
|
160
|
+
return 3;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
if (cmd === "add") {
|
|
164
|
+
if (o.rest?.length) throw new Usage(`unknown argument ${o.rest[0]}`);
|
|
165
|
+
process.stdout.write(JSON.stringify(add(o)) + "\n");
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
if (cmd === "list") {
|
|
169
|
+
const out = list();
|
|
170
|
+
if (o.json) {
|
|
171
|
+
process.stdout.write(JSON.stringify(out) + "\n");
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
const lines = [`launch: ${out.launchEnabled ? "on" : "off"}`];
|
|
175
|
+
if (out.problem) lines.push(`problem: ${out.problem}`);
|
|
176
|
+
for (const d of out.devices) {
|
|
177
|
+
lines.push(
|
|
178
|
+
`${d.id} ${d.fingerprint} ${d.scopes.join(",").padEnd(18)} ${d.revokedAt ? `revoked ${d.revokedAt}` : "active"} ${d.name}`,
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
process.stdout.write(lines.join("\n") + "\n");
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
if (cmd === "revoke") {
|
|
185
|
+
const id = o.rest?.[0];
|
|
186
|
+
if (!id || o.rest.length !== 1 || !DEVICE_ID.test(id))
|
|
187
|
+
throw new Usage("revoke takes one device id");
|
|
188
|
+
const reg = registryForWrite();
|
|
189
|
+
const d = reg.devices.find((x) => x.id === id);
|
|
190
|
+
if (!d) {
|
|
191
|
+
process.stderr.write(`phone-devices: no device ${id}\n`);
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
if (d.revokedAt) {
|
|
195
|
+
process.stderr.write(`phone-devices: ${id} was revoked at ${d.revokedAt}\n`);
|
|
196
|
+
return 1;
|
|
197
|
+
}
|
|
198
|
+
d.revokedAt = new Date().toISOString();
|
|
199
|
+
writeRegistry(reg);
|
|
200
|
+
process.stdout.write(JSON.stringify({ id, revokedAt: d.revokedAt }) + "\n");
|
|
201
|
+
return 0;
|
|
202
|
+
}
|
|
203
|
+
const v = o.rest?.[0];
|
|
204
|
+
if (o.rest?.length !== 1 || (v !== "on" && v !== "off"))
|
|
205
|
+
throw new Usage("launch takes on or off");
|
|
206
|
+
const reg = registryForWrite();
|
|
207
|
+
writeRegistry({ ...reg, launchEnabled: v === "on" });
|
|
208
|
+
process.stdout.write(JSON.stringify({ launchEnabled: v === "on" }) + "\n");
|
|
209
|
+
return 0;
|
|
210
|
+
} catch (err) {
|
|
211
|
+
if (err instanceof Usage) {
|
|
212
|
+
process.stderr.write(`phone-devices: ${err.message}\n${USAGE}`);
|
|
213
|
+
return 2;
|
|
214
|
+
}
|
|
215
|
+
process.stderr.write(`phone-devices: ${err.message}\n`);
|
|
216
|
+
return 1;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (invokedDirectly(import.meta.url)) {
|
|
221
|
+
runMain("phone-devices", () => {
|
|
222
|
+
process.exitCode = main(process.argv.slice(2));
|
|
223
|
+
});
|
|
224
|
+
}
|
|
@@ -23,15 +23,40 @@
|
|
|
23
23
|
// `in_progress` is the gap this exists to catch: not "we decided not to do it"
|
|
24
24
|
// but "nobody noticed it was still open".
|
|
25
25
|
//
|
|
26
|
+
// With no plan todos (prefs.global.planTodos off) there is no step list to
|
|
27
|
+
// audit. An attended run reports that as not-applicable.
|
|
28
|
+
//
|
|
29
|
+
// While the quality gates are active (lib/unattended.mjs, gatesActive) Phase 1
|
|
30
|
+
// always writes plan todos, and a run with no todos falls back to the analysis
|
|
31
|
+
// Section 14 `Add new` rows, the one promise every analysed plan carries. With
|
|
32
|
+
// neither, a run that had a Plan phase (`state.analysis.docStatus` recorded, or
|
|
33
|
+
// `state.phases["1"]` entered) is a gap: it planned work and left nothing to
|
|
34
|
+
// check it against. Only a run with no Plan phase, the pipeline tail, is
|
|
35
|
+
// not-applicable. Those verdicts are appended to state.gates[] as
|
|
36
|
+
// `plan-coverage`.
|
|
37
|
+
//
|
|
26
38
|
// Usage:
|
|
27
39
|
// plan-coverage-gate.mjs --state <agent-state.json> [--analysis <doc.md>] [--root <dir>] [--json]
|
|
28
40
|
// plan-coverage-gate.mjs --todos <plan-todos.json> [--analysis <doc.md>] [--root <dir>] [--json]
|
|
29
41
|
//
|
|
30
|
-
//
|
|
42
|
+
// --analysis-from-state adds one --analysis per entry of the state's
|
|
43
|
+
// analysis.docPath[] (one per platform), and --json-out <file> writes the --json
|
|
44
|
+
// result to that file instead of stdout. Together they make the Phase 4 step
|
|
45
|
+
// one command, with no shell array built from jq output.
|
|
46
|
+
//
|
|
47
|
+
// Exit codes, gates active: 0 clean, 1 coverage gap (a zero-step plan and a
|
|
48
|
+
// planned run with no coverage source included), 2 not-applicable (no Plan
|
|
49
|
+
// phase), 3 usage or unreadable input.
|
|
50
|
+
// Attended: 0 clean, 1 gap, 2 everything else - not-applicable (verdict
|
|
51
|
+
// `not-applicable` in --json), a zero-step plan (verdict `unusable`), usage or
|
|
52
|
+
// unreadable input (no verdict). Phase 4 reads only exit 2 with verdict
|
|
53
|
+
// `not-applicable` as not-applicable.
|
|
31
54
|
|
|
32
|
-
import { readFileSync, existsSync, writeFileSync } from "node:fs";
|
|
33
|
-
import { join, isAbsolute } from "node:path";
|
|
34
|
-
|
|
55
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
56
|
+
import { dirname, join, isAbsolute } from "node:path";
|
|
57
|
+
|
|
58
|
+
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
59
|
+
import { gateContext, recordQuietly } from "./gate-ledger.mjs";
|
|
35
60
|
|
|
36
61
|
export function auditTodos(todos) {
|
|
37
62
|
const gaps = [];
|
|
@@ -90,9 +115,48 @@ function readJson(path) {
|
|
|
90
115
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
91
116
|
}
|
|
92
117
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Promised files across every analysis document.
|
|
120
|
+
* @returns {{rows: string[], missing: string[], verdict: string}}
|
|
121
|
+
*/
|
|
122
|
+
function auditFiles(analysisPaths, root) {
|
|
123
|
+
const allRows = [];
|
|
124
|
+
const docsWithoutSection = [];
|
|
125
|
+
for (const docPath of analysisPaths) {
|
|
126
|
+
const rows = filesToAdd(readFileSync(docPath, "utf8"));
|
|
127
|
+
if (rows === null) docsWithoutSection.push(docPath);
|
|
128
|
+
else allRows.push(...rows);
|
|
129
|
+
}
|
|
130
|
+
const rows = [...new Set(allRows)];
|
|
131
|
+
const missing = rows.filter((p) => !existsSync(isAbsolute(p) ? p : join(root, p)));
|
|
132
|
+
const docNote = docsWithoutSection.length
|
|
133
|
+
? `; ${docsWithoutSection.length} doc(s) carried no Section 14`
|
|
134
|
+
: "";
|
|
135
|
+
const verdict = rows.length
|
|
136
|
+
? `${rows.length - missing.length}/${rows.length} promised files present across ${analysisPaths.length} doc(s)${docNote}`
|
|
137
|
+
: `no Section 14 rows in ${analysisPaths.length} doc(s)${docNote}`;
|
|
138
|
+
return { rows, missing, verdict };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Did this run have a Plan phase? Phase 1 Step 4 always records
|
|
143
|
+
* `analysis.docStatus`; the phase tracker records `phases["1"]`.
|
|
144
|
+
*
|
|
145
|
+
* @param {object|null} state
|
|
146
|
+
* @returns {boolean}
|
|
147
|
+
*/
|
|
148
|
+
export function planPhaseRan(state) {
|
|
149
|
+
if (!state || typeof state !== "object" || state.mode === "analysis") return false;
|
|
150
|
+
const p1 = state.phases?.["1"];
|
|
151
|
+
if (p1 && typeof p1 === "object" && p1.status && !["pending", "skipped"].includes(p1.status)) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
return typeof state.analysis?.docStatus === "string";
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const LEDGER = { clean: "pass", gap: "fail", unusable: "fail", "not-applicable": "not-applicable" };
|
|
158
|
+
|
|
159
|
+
async function main(args) {
|
|
96
160
|
const flag = (name) => {
|
|
97
161
|
const i = args.indexOf(name);
|
|
98
162
|
return i === -1 ? undefined : args[i + 1];
|
|
@@ -117,86 +181,150 @@ if (isMain) {
|
|
|
117
181
|
"Fails when a plan step never reached a terminal status, when a skip or",
|
|
118
182
|
"failure carries no reason, or when an analysis Section 14 `Add new` file",
|
|
119
183
|
"is missing from the tree. Run before Phase 4 commit.",
|
|
184
|
+
"Exit: 0 clean, 1 gap, 2 not-applicable, 3 usage or unreadable input.",
|
|
120
185
|
"",
|
|
121
186
|
].join("\n"),
|
|
122
187
|
);
|
|
123
|
-
|
|
188
|
+
return args.includes("--help") ? 0 : 2;
|
|
124
189
|
}
|
|
125
190
|
|
|
126
191
|
const statePath = flag("--state");
|
|
127
192
|
const todosPath = flag("--todos");
|
|
128
193
|
const analysisPaths = flagAll("--analysis");
|
|
194
|
+
if (statePath && args.includes("--analysis-from-state")) {
|
|
195
|
+
try {
|
|
196
|
+
const docs = readJson(statePath)?.analysis?.docPath;
|
|
197
|
+
if (Array.isArray(docs)) {
|
|
198
|
+
analysisPaths.push(...docs.filter((d) => typeof d === "string" && d !== ""));
|
|
199
|
+
}
|
|
200
|
+
} catch {
|
|
201
|
+
/* an unreadable state is reported below, where the plan is read */
|
|
202
|
+
}
|
|
203
|
+
}
|
|
129
204
|
const root = flag("--root") ?? process.cwd();
|
|
130
|
-
const
|
|
205
|
+
const jsonOut = flag("--json-out");
|
|
206
|
+
const asJson = args.includes("--json") || jsonOut !== undefined;
|
|
207
|
+
const writeJson = (obj) => {
|
|
208
|
+
const text = `${JSON.stringify(obj, null, 2)}\n`;
|
|
209
|
+
if (jsonOut === undefined) {
|
|
210
|
+
writeFileSync(1, text);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
mkdirSync(dirname(jsonOut), { recursive: true });
|
|
214
|
+
writeFileSync(jsonOut, text);
|
|
215
|
+
};
|
|
216
|
+
// The quality gates run for an unattended run and for a run in autopilot
|
|
217
|
+
// mode (lib/unattended.mjs, gatesActive); neither has a person to ask.
|
|
218
|
+
const gatesOn = gateContext({ statePath: statePath ?? null, repo: root }).active;
|
|
219
|
+
// Attended runs keep the base exit contract: every non-verdict is exit 2.
|
|
220
|
+
const UNREADABLE = gatesOn ? 3 : 2;
|
|
221
|
+
const ZERO_STEPS = gatesOn ? 1 : 2;
|
|
222
|
+
|
|
223
|
+
const finish = async (code, result, detail = {}) => {
|
|
224
|
+
if (gatesOn) {
|
|
225
|
+
await recordQuietly(
|
|
226
|
+
"plan-coverage",
|
|
227
|
+
LEDGER[result.verdict] ?? "fail",
|
|
228
|
+
{ verdict: result.verdict, ...detail },
|
|
229
|
+
{ repo: root, statePath: statePath ?? null },
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
return code;
|
|
233
|
+
};
|
|
131
234
|
|
|
132
235
|
if (!statePath && !todosPath) {
|
|
133
236
|
process.stderr.write("plan-coverage-gate: pass --state or --todos\n");
|
|
134
|
-
|
|
237
|
+
return UNREADABLE;
|
|
135
238
|
}
|
|
136
239
|
|
|
137
240
|
let todos;
|
|
241
|
+
let state = null;
|
|
138
242
|
try {
|
|
139
243
|
if (todosPath) {
|
|
140
244
|
const parsed = readJson(todosPath);
|
|
141
245
|
todos = parsed?.todos ?? parsed;
|
|
142
246
|
} else {
|
|
143
|
-
|
|
247
|
+
state = readJson(statePath);
|
|
144
248
|
todos = state?.plan?.todos ?? state?.plan?.todoList?.todos ?? null;
|
|
145
249
|
}
|
|
146
250
|
} catch (e) {
|
|
147
251
|
process.stderr.write(`plan-coverage-gate: cannot read the plan: ${e.message}\n`);
|
|
148
|
-
|
|
252
|
+
return finish(UNREADABLE, { verdict: "unusable" }, { reason: `unreadable plan: ${e.message}` });
|
|
149
253
|
}
|
|
150
254
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
// stdout is a pipe.
|
|
164
|
-
if (asJson)
|
|
165
|
-
writeFileSync(1, `${JSON.stringify({ verdict: "unusable", reason: msg }, null, 2)}\n`);
|
|
166
|
-
else process.stderr.write(`plan-coverage-gate: ${msg}\n`);
|
|
167
|
-
process.exit(2);
|
|
255
|
+
let files = null;
|
|
256
|
+
if (analysisPaths.length) {
|
|
257
|
+
try {
|
|
258
|
+
files = auditFiles(analysisPaths, root);
|
|
259
|
+
} catch (e) {
|
|
260
|
+
process.stderr.write(`plan-coverage-gate: cannot read the analysis doc: ${e.message}\n`);
|
|
261
|
+
return finish(
|
|
262
|
+
UNREADABLE,
|
|
263
|
+
{ verdict: "unusable" },
|
|
264
|
+
{ reason: `unreadable analysis: ${e.message}` },
|
|
265
|
+
);
|
|
266
|
+
}
|
|
168
267
|
}
|
|
169
268
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
269
|
+
// No step list. Attended: nothing to audit. Unattended: the promised files
|
|
270
|
+
// are the coverage source when there are any.
|
|
271
|
+
if (!Array.isArray(todos)) {
|
|
272
|
+
if (gatesOn && files && files.rows.length) {
|
|
273
|
+
const failed = files.missing.length > 0;
|
|
274
|
+
const result = {
|
|
275
|
+
verdict: failed ? "gap" : "clean",
|
|
276
|
+
source: "analysis-section-14",
|
|
277
|
+
todos: { total: 0, accounted: 0, gaps: [] },
|
|
278
|
+
filesToAdd: { verdict: files.verdict, missing: files.missing },
|
|
279
|
+
};
|
|
280
|
+
if (asJson) writeJson(result);
|
|
281
|
+
else if (failed) {
|
|
282
|
+
writeFileSync(
|
|
283
|
+
2,
|
|
284
|
+
`${[
|
|
285
|
+
`plan coverage (from analysis Section 14, no plan todos): ${files.missing.length} missing file(s)`,
|
|
286
|
+
...files.missing.map((f) => ` missing file promised by analysis Section 14: ${f}`),
|
|
287
|
+
].join("\n")}\n`,
|
|
288
|
+
);
|
|
289
|
+
} else writeFileSync(1, `plan coverage (from analysis Section 14): ${files.verdict}\n`);
|
|
290
|
+
return finish(failed ? 1 : 0, result, {
|
|
291
|
+
source: result.source,
|
|
292
|
+
missing: files.missing.length,
|
|
293
|
+
});
|
|
187
294
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
295
|
+
if (gatesOn && planPhaseRan(state)) {
|
|
296
|
+
const reason =
|
|
297
|
+
"the run had a Plan phase and left no plan todos and no analysis Section 14 `Add new` row to check it against";
|
|
298
|
+
const result = { verdict: "gap", reason, todos: { total: 0, accounted: 0, gaps: [] } };
|
|
299
|
+
if (asJson) writeJson(result);
|
|
300
|
+
else process.stderr.write(`plan-coverage-gate: ${reason}\n`);
|
|
301
|
+
return finish(1, result, { reason });
|
|
302
|
+
}
|
|
303
|
+
const reason = gatesOn
|
|
304
|
+
? "no Plan phase in this run, so no plan todos and no analysis Section 14 row to cover"
|
|
305
|
+
: "no plan todos found - this mode has no step list to audit";
|
|
306
|
+
const result = { verdict: "not-applicable", reason };
|
|
307
|
+
// fd 1 synchronously: process.exit() follows, and a pipe would keep only
|
|
308
|
+
// what fit in its buffer.
|
|
309
|
+
if (asJson) writeJson(result);
|
|
310
|
+
else process.stderr.write(`plan-coverage-gate: not-applicable: ${reason}\n`);
|
|
311
|
+
return finish(2, result, { reason });
|
|
198
312
|
}
|
|
199
313
|
|
|
314
|
+
// An empty step list is not a clean one: a Phase 2 that produced no steps, or
|
|
315
|
+
// a state whose todos got cleared, would otherwise read as "0/0 accounted for"
|
|
316
|
+
// and let the commit through.
|
|
317
|
+
if (todos.length === 0) {
|
|
318
|
+
const reason = "the plan has zero steps - that is an unusable plan, not a clean one";
|
|
319
|
+
if (asJson) writeJson({ verdict: "unusable", reason });
|
|
320
|
+
else process.stderr.write(`plan-coverage-gate: ${reason}\n`);
|
|
321
|
+
return finish(ZERO_STEPS, { verdict: "unusable" }, { reason });
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const { gaps, accounted } = auditTodos(todos);
|
|
325
|
+
const missingFiles = files ? files.missing : [];
|
|
326
|
+
const filesVerdict = files ? files.verdict : "skipped (no --analysis given)";
|
|
327
|
+
|
|
200
328
|
const failed = gaps.length > 0 || missingFiles.length > 0;
|
|
201
329
|
const result = {
|
|
202
330
|
verdict: failed ? "gap" : "clean",
|
|
@@ -204,21 +332,27 @@ if (isMain) {
|
|
|
204
332
|
filesToAdd: { verdict: filesVerdict, missing: missingFiles },
|
|
205
333
|
};
|
|
206
334
|
|
|
335
|
+
// Same rule as above: every verdict goes to its fd synchronously.
|
|
207
336
|
if (asJson) {
|
|
208
|
-
|
|
337
|
+
writeJson(result);
|
|
209
338
|
} else if (failed) {
|
|
210
|
-
|
|
211
|
-
`plan coverage: ${gaps.length} unaccounted step(s), ${missingFiles.length} missing file(s)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
339
|
+
const lines = [
|
|
340
|
+
`plan coverage: ${gaps.length} unaccounted step(s), ${missingFiles.length} missing file(s)`,
|
|
341
|
+
...gaps.map((g) => ` ${g.id} [${g.status}] ${g.task} - ${g.why}`),
|
|
342
|
+
...missingFiles.map((f) => ` missing file promised by analysis Section 14: ${f}`),
|
|
343
|
+
` files-to-add: ${filesVerdict}`,
|
|
344
|
+
];
|
|
345
|
+
writeFileSync(2, `${lines.join("\n")}\n`);
|
|
217
346
|
} else {
|
|
218
347
|
// spec-kit's rule: a clean pass says one line and writes nothing.
|
|
219
|
-
|
|
348
|
+
writeFileSync(
|
|
349
|
+
1,
|
|
220
350
|
`plan coverage: ${accounted.length}/${todos.length} steps accounted for; files-to-add: ${filesVerdict}\n`,
|
|
221
351
|
);
|
|
222
352
|
}
|
|
223
|
-
|
|
353
|
+
return finish(failed ? 1 : 0, result, { gaps: gaps.length, missing: missingFiles.length });
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (invokedDirectly(import.meta.url)) {
|
|
357
|
+
main(process.argv.slice(2)).then((code) => process.exit(code));
|
|
224
358
|
}
|