@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
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file pr-request.mjs - write and validate the PR request an unattended
|
|
4
|
+
* Phase 4 leaves for the autopilot runner.
|
|
5
|
+
*
|
|
6
|
+
* Under MULTI_AGENT_UNATTENDED=1 the run does not push and does not open a PR:
|
|
7
|
+
* agent-guard blocks both. Phase 4 calls `write` instead, and the runner, after
|
|
8
|
+
* the run exits, calls `validate`, checks the branch it can see, pushes it and
|
|
9
|
+
* opens the PR as a draft. The run never hand-writes the JSON, so the file is
|
|
10
|
+
* always well-formed and always passed the outbound gate.
|
|
11
|
+
*
|
|
12
|
+
* Rules beyond pr-request.schema.json:
|
|
13
|
+
* - branch and base are ref names that do not start with `-` and hold no
|
|
14
|
+
* `..`, so neither can be read as an option or a range where it is passed
|
|
15
|
+
* on;
|
|
16
|
+
* - the branch is not main, master or develop, and is not the base;
|
|
17
|
+
* - which base is acceptable is the runner's decision, not the request's:
|
|
18
|
+
* autopilot-publish.mjs accepts the configured `baseBranch`, else the
|
|
19
|
+
* remote's default branch, plus any base listed in `allowedBases`;
|
|
20
|
+
* - no auto-close keyword (Closes / Fixes / Resolves #N) in title or body,
|
|
21
|
+
* because issues are closed by people;
|
|
22
|
+
* - title and body pass lib/outbound-gate.mjs: a certain finding (a token
|
|
23
|
+
* shape) exits 7 and nothing is written. Findings are reported by rule and
|
|
24
|
+
* line, never by value.
|
|
25
|
+
*
|
|
26
|
+
* Usage:
|
|
27
|
+
* node pr-request.mjs write --branch <b> --base <b> --title <t> --body-file <f> --repo <owner/name> [--out <path>]
|
|
28
|
+
* node pr-request.mjs validate --file <path>
|
|
29
|
+
*
|
|
30
|
+
* `write` puts the file at lib/pr-request-location.mjs prRequestPath(), named
|
|
31
|
+
* for MULTI_AGENT_SESSION_ID, unless --out is given. Mode 0600 in a 0700
|
|
32
|
+
* directory, written through a temp file and a rename.
|
|
33
|
+
*
|
|
34
|
+
* Output: one JSON object on stdout. Exit: 0 ok, 1 invalid, 2 usage, 7 secret.
|
|
35
|
+
*
|
|
36
|
+
* @module pipeline/scripts/pr-request
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
40
|
+
import { dirname } from "node:path";
|
|
41
|
+
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
42
|
+
import { scan } from "../lib/outbound-gate.mjs";
|
|
43
|
+
import { prRequestPath } from "../lib/pr-request-location.mjs";
|
|
44
|
+
|
|
45
|
+
export const FIELDS = ["branch", "base", "title", "body", "draft", "repo"];
|
|
46
|
+
export const PROTECTED_BRANCHES = ["main", "master", "develop"];
|
|
47
|
+
const REF = /^[A-Za-z0-9._/-]+$/;
|
|
48
|
+
const REPO = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
|
|
49
|
+
const AUTO_CLOSE = /\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s*:?\s+(?:[\w.-]+\/[\w.-]+)?#\d+/i;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The request object `write` produces. draft is always true.
|
|
53
|
+
*
|
|
54
|
+
* @param {{branch:string, base:string, title:string, body:string, repo:string}} f
|
|
55
|
+
*/
|
|
56
|
+
export function buildPrRequest(f) {
|
|
57
|
+
return {
|
|
58
|
+
branch: f.branch,
|
|
59
|
+
base: f.base,
|
|
60
|
+
title: f.title,
|
|
61
|
+
body: f.body,
|
|
62
|
+
draft: true,
|
|
63
|
+
repo: f.repo,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const str = (v, min, max) => typeof v === "string" && v.length >= min && v.length <= max;
|
|
68
|
+
|
|
69
|
+
/** A branch name that cannot be read as an option (`-x`) or a range (`a..b`). */
|
|
70
|
+
const isRef = (v) => str(v, 1, 255) && REF.test(v) && !v.startsWith("-") && !v.includes("..");
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* @param {unknown} req
|
|
74
|
+
* @returns {{errors: string[], secrets: {rule:string, line:number, field:string}[]}}
|
|
75
|
+
*/
|
|
76
|
+
export function validatePrRequest(req) {
|
|
77
|
+
const errors = [];
|
|
78
|
+
if (!req || typeof req !== "object" || Array.isArray(req)) {
|
|
79
|
+
return { errors: ["the request is not a JSON object"], secrets: [] };
|
|
80
|
+
}
|
|
81
|
+
for (const k of Object.keys(req)) if (!FIELDS.includes(k)) errors.push(`unknown field: ${k}`);
|
|
82
|
+
for (const k of FIELDS) if (!(k in req)) errors.push(`missing field: ${k}`);
|
|
83
|
+
if ("branch" in req && !isRef(req.branch)) errors.push("branch is not a ref name");
|
|
84
|
+
if ("base" in req && !isRef(req.base)) errors.push("base is not a ref name");
|
|
85
|
+
if ("title" in req && !str(req.title, 1, 256)) errors.push("title must be 1-256 characters");
|
|
86
|
+
if ("body" in req && !str(req.body, 1, 65536)) errors.push("body must be 1-65536 characters");
|
|
87
|
+
if ("draft" in req && req.draft !== true) errors.push("draft must be true");
|
|
88
|
+
if ("repo" in req && !(typeof req.repo === "string" && REPO.test(req.repo)))
|
|
89
|
+
errors.push("repo must be owner/name");
|
|
90
|
+
if (typeof req.branch === "string" && PROTECTED_BRANCHES.includes(req.branch))
|
|
91
|
+
errors.push(`branch ${req.branch} is protected; the run's work belongs on its own branch`);
|
|
92
|
+
if (typeof req.branch === "string" && req.branch === req.base)
|
|
93
|
+
errors.push("branch and base are the same");
|
|
94
|
+
for (const k of ["title", "body"]) {
|
|
95
|
+
if (typeof req[k] === "string" && AUTO_CLOSE.test(req[k]))
|
|
96
|
+
errors.push(`${k} carries an auto-close keyword; use Ref: #N`);
|
|
97
|
+
}
|
|
98
|
+
const secrets = [];
|
|
99
|
+
for (const k of ["title", "body"]) {
|
|
100
|
+
if (typeof req[k] !== "string") continue;
|
|
101
|
+
for (const f of scan(req[k])) {
|
|
102
|
+
if (f.certain) secrets.push({ rule: f.rule, line: f.line, field: k });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { errors, secrets };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function arg(args, name) {
|
|
109
|
+
const i = args.indexOf(name);
|
|
110
|
+
return i === -1 ? undefined : args[i + 1];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function emit(obj, code) {
|
|
114
|
+
process.stdout.write(`${JSON.stringify(obj)}\n`);
|
|
115
|
+
process.exitCode = code;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function writeAtomic(path, text) {
|
|
119
|
+
const dir = dirname(path);
|
|
120
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
121
|
+
chmodSync(dir, 0o700);
|
|
122
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
123
|
+
writeFileSync(tmp, text, { mode: 0o600 });
|
|
124
|
+
chmodSync(tmp, 0o600);
|
|
125
|
+
renameSync(tmp, path);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function cmdWrite(args) {
|
|
129
|
+
const need = ["--branch", "--base", "--title", "--body-file", "--repo"];
|
|
130
|
+
const missing = need.filter((n) => !arg(args, n));
|
|
131
|
+
if (missing.length) return emit({ ok: false, usage: `missing ${missing.join(", ")}` }, 2);
|
|
132
|
+
let body;
|
|
133
|
+
try {
|
|
134
|
+
body = readFileSync(arg(args, "--body-file"), "utf8");
|
|
135
|
+
} catch (err) {
|
|
136
|
+
return emit({ ok: false, usage: `cannot read --body-file: ${err.code || err.message}` }, 2);
|
|
137
|
+
}
|
|
138
|
+
let out = arg(args, "--out");
|
|
139
|
+
if (!out) {
|
|
140
|
+
try {
|
|
141
|
+
out = prRequestPath(process.env.MULTI_AGENT_SESSION_ID || "");
|
|
142
|
+
} catch {
|
|
143
|
+
return emit(
|
|
144
|
+
{ ok: false, usage: "MULTI_AGENT_SESSION_ID is not a session id and no --out was given" },
|
|
145
|
+
2,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const req = buildPrRequest({
|
|
150
|
+
branch: arg(args, "--branch"),
|
|
151
|
+
base: arg(args, "--base"),
|
|
152
|
+
title: arg(args, "--title"),
|
|
153
|
+
body,
|
|
154
|
+
repo: arg(args, "--repo"),
|
|
155
|
+
});
|
|
156
|
+
const { errors, secrets } = validatePrRequest(req);
|
|
157
|
+
if (secrets.length) return emit({ ok: false, written: false, secrets }, 7);
|
|
158
|
+
if (errors.length) return emit({ ok: false, written: false, errors }, 1);
|
|
159
|
+
writeAtomic(out, `${JSON.stringify(req, null, 2)}\n`);
|
|
160
|
+
return emit({ ok: true, written: true, path: out }, 0);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function cmdValidate(args) {
|
|
164
|
+
const file = arg(args, "--file");
|
|
165
|
+
if (!file) return emit({ ok: false, usage: "validate needs --file" }, 2);
|
|
166
|
+
let req;
|
|
167
|
+
try {
|
|
168
|
+
req = JSON.parse(readFileSync(file, "utf8"));
|
|
169
|
+
} catch (err) {
|
|
170
|
+
return emit({ ok: false, errors: [`unreadable: ${err.code || "not JSON"}`] }, 1);
|
|
171
|
+
}
|
|
172
|
+
const { errors, secrets } = validatePrRequest(req);
|
|
173
|
+
if (secrets.length) return emit({ ok: false, errors, secrets }, 7);
|
|
174
|
+
return emit({ ok: errors.length === 0, errors }, errors.length ? 1 : 0);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function main() {
|
|
178
|
+
const [sub, ...args] = process.argv.slice(2);
|
|
179
|
+
if (sub === "write") return cmdWrite(args);
|
|
180
|
+
if (sub === "validate") return cmdValidate(args);
|
|
181
|
+
process.stderr.write(
|
|
182
|
+
"usage: pr-request.mjs write --branch <b> --base <b> --title <t> --body-file <f> --repo <owner/name> [--out <path>]\n" +
|
|
183
|
+
" pr-request.mjs validate --file <path>\n",
|
|
184
|
+
);
|
|
185
|
+
process.exitCode = 2;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (invokedDirectly(import.meta.url)) main();
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
set -uo pipefail
|
|
16
16
|
|
|
17
|
+
PRE_COMMIT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
# shellcheck source=../lib/unattended.sh
|
|
19
|
+
if [ -f "$PRE_COMMIT_DIR/../lib/unattended.sh" ]; then . "$PRE_COMMIT_DIR/../lib/unattended.sh"; fi
|
|
20
|
+
command -v ma_unattended >/dev/null 2>&1 || ma_unattended() { [ "${MULTI_AGENT_UNATTENDED:-}" = "1" ]; }
|
|
21
|
+
|
|
17
22
|
# Hook-mode fast exit. The Claude Code PreToolUse matcher is the tool name
|
|
18
23
|
# ("Bash"), so this script now fires for EVERY Bash call and receives JSON on
|
|
19
24
|
# stdin: {"tool_name":"Bash","tool_input":{"command":"..."}}. Extract the
|
|
@@ -22,6 +27,9 @@ set -uo pipefail
|
|
|
22
27
|
# fall through to the full scan. Extraction failure also falls through - the
|
|
23
28
|
# only cost is an unnecessary scan, never a skipped one on a real commit.
|
|
24
29
|
SCAN_UNSTAGED=0
|
|
30
|
+
# Set only when this is the hook firing on a real `git commit`. A direct run
|
|
31
|
+
# (Phase 2 Gate 4, the smokes) is the secret scan and nothing else.
|
|
32
|
+
IS_COMMIT_HOOK=0
|
|
25
33
|
# --scan-file <path>: run the detectors over ONE file that git knows nothing
|
|
26
34
|
# about, then exit on the result. It exists so callers outside the commit path
|
|
27
35
|
# can reuse these patterns instead of copying them - learn-from-transcripts.mjs
|
|
@@ -40,8 +48,21 @@ if [ "${1:-}" = "--scan-file" ]; then
|
|
|
40
48
|
SCAN_FILE_TARGET="${2:-}"
|
|
41
49
|
[ -f "$SCAN_FILE_TARGET" ] || { echo "ERR: --scan-file needs an existing path" >&2; exit 1; }
|
|
42
50
|
fi
|
|
51
|
+
# --scan-range <base>..<head>: run the detectors over the lines each commit in
|
|
52
|
+
# the range added, file by file, the way a commit of the whole range would have
|
|
53
|
+
# been scanned. The autopilot runner calls it on a branch before it pushes,
|
|
54
|
+
# outside the run that made the commits (autopilot-publish.mjs), so a commit
|
|
55
|
+
# that reached the branch without passing through this hook is still scanned.
|
|
56
|
+
SCAN_RANGE=""
|
|
57
|
+
if [ "${1:-}" = "--scan-range" ]; then
|
|
58
|
+
SCAN_RANGE="${2:-}"
|
|
59
|
+
case "$SCAN_RANGE" in
|
|
60
|
+
?*..?*) ;;
|
|
61
|
+
*) echo "ERR: --scan-range needs <base>..<head>" >&2; exit 1 ;;
|
|
62
|
+
esac
|
|
63
|
+
fi
|
|
43
64
|
|
|
44
|
-
if [ -z "$SCAN_FILE_TARGET" ] && [ ! -t 0 ]; then
|
|
65
|
+
if [ -z "$SCAN_FILE_TARGET" ] && [ -z "$SCAN_RANGE" ] && [ ! -t 0 ]; then
|
|
45
66
|
HOOK_INPUT="$(cat 2>/dev/null || true)"
|
|
46
67
|
if [ -n "$HOOK_INPUT" ]; then
|
|
47
68
|
HOOK_COMMAND=""
|
|
@@ -65,10 +86,30 @@ process.stdin.on("end", () => {
|
|
|
65
86
|
' 2>/dev/null || true)"
|
|
66
87
|
fi
|
|
67
88
|
if [ -n "$HOOK_COMMAND" ]; then
|
|
68
|
-
|
|
89
|
+
# Commit detection is a tokenizer, not a regex: agent-guard.py shares its
|
|
90
|
+
# shell parser through `--git-subcommand`, so an absolute git path, a
|
|
91
|
+
# quoted or case-folded name, an alias and the other commands that write a
|
|
92
|
+
# commit (commit-tree, merge, cherry-pick, revert, am) are all seen the
|
|
93
|
+
# same way the guard sees them. A regex over the raw string missed every
|
|
94
|
+
# one of those. If the helper is unavailable the scan runs anyway.
|
|
95
|
+
GUARD_PY="$PRE_COMMIT_DIR/agent-guard.py"
|
|
96
|
+
GIT_SUBS=""
|
|
97
|
+
HELPER_RAN=0
|
|
98
|
+
if command -v python3 >/dev/null 2>&1 && [ -f "$GUARD_PY" ]; then
|
|
99
|
+
if GIT_SUBS="$(printf '%s' "$HOOK_INPUT" | python3 "$GUARD_PY" --git-subcommand 2>/dev/null)"; then
|
|
100
|
+
HELPER_RAN=1
|
|
101
|
+
fi
|
|
102
|
+
fi
|
|
103
|
+
if [ "$HELPER_RAN" = "1" ]; then
|
|
104
|
+
if ! printf '%s\n' "$GIT_SUBS" \
|
|
105
|
+
| grep -qxE 'commit|commit-tree|merge|cherry-pick|revert|am'; then
|
|
106
|
+
exit 0
|
|
107
|
+
fi
|
|
108
|
+
elif ! printf '%s\n' "$HOOK_COMMAND" \
|
|
69
109
|
| grep -qE '(^|[^[:alnum:]_./-])git[[:space:]]+([^|&;]*[[:space:]])?commit([^[:alnum:]_-]|$)'; then
|
|
70
110
|
exit 0
|
|
71
111
|
fi
|
|
112
|
+
IS_COMMIT_HOOK=1
|
|
72
113
|
# PreToolUse fires BEFORE the tool runs, so a compound command like
|
|
73
114
|
# `git add -A && git commit -m ...` reaches this point with NOTHING
|
|
74
115
|
# staged yet from either half - `git diff --cached` alone sees an
|
|
@@ -76,8 +117,9 @@ process.stdin.on("end", () => {
|
|
|
76
117
|
# it exists to gate. When the same command also runs `git add`, widen
|
|
77
118
|
# the scan to the working tree (tracked-unstaged + untracked), not
|
|
78
119
|
# just the index, so that case is still caught.
|
|
79
|
-
if printf '%s\n' "$
|
|
80
|
-
|
|
120
|
+
if printf '%s\n' "$GIT_SUBS" | grep -qxF 'add' \
|
|
121
|
+
|| printf '%s\n' "$HOOK_COMMAND" \
|
|
122
|
+
| grep -qE '(^|[^[:alnum:]_./-])git[[:space:]]+add([^[:alnum:]_-]|$)'; then
|
|
81
123
|
SCAN_UNSTAGED=1
|
|
82
124
|
fi
|
|
83
125
|
fi
|
|
@@ -87,6 +129,14 @@ fi
|
|
|
87
129
|
# Staged paths from `git diff --cached --name-only` are repo-root-relative, so
|
|
88
130
|
# the `-f` tests below only see them from the repo root. Hooks fire with the
|
|
89
131
|
# caller's cwd, which is often a subdirectory.
|
|
132
|
+
# A `cd <dir>` or `git -C <dir>` earlier on the line moves the commit into
|
|
133
|
+
# another checkout; that checkout is the one scanned.
|
|
134
|
+
if [ "$IS_COMMIT_HOOK" = "1" ] && command -v python3 >/dev/null 2>&1 && [ -f "${GUARD_PY:-}" ]; then
|
|
135
|
+
COMMIT_DIR="$(printf '%s' "$HOOK_INPUT" | python3 "$GUARD_PY" --commit-dir 2>/dev/null || true)"
|
|
136
|
+
if [ -n "$COMMIT_DIR" ] && [ -d "$COMMIT_DIR" ]; then
|
|
137
|
+
cd "$COMMIT_DIR" || exit 0
|
|
138
|
+
fi
|
|
139
|
+
fi
|
|
90
140
|
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
|
91
141
|
if [ -n "$REPO_ROOT" ]; then
|
|
92
142
|
cd "$REPO_ROOT" || exit 0
|
|
@@ -275,6 +325,52 @@ if [ -n "$SCAN_FILE_TARGET" ]; then
|
|
|
275
325
|
exit 0
|
|
276
326
|
fi
|
|
277
327
|
|
|
328
|
+
if [ -n "$SCAN_RANGE" ]; then
|
|
329
|
+
git rev-parse --verify --quiet "${SCAN_RANGE%%..*}^{commit}" >/dev/null \
|
|
330
|
+
&& git rev-parse --verify --quiet "${SCAN_RANGE##*..}^{commit}" >/dev/null \
|
|
331
|
+
|| { echo "ERR: --scan-range: $SCAN_RANGE does not name two commits" >&2; exit 1; }
|
|
332
|
+
# Every commit in the range is pushed, so each one is scanned on its own,
|
|
333
|
+
# from the commit object rather than the working tree: a key added in one
|
|
334
|
+
# commit and removed in a later one is still in the pushed history.
|
|
335
|
+
range_commits=$(git rev-list --reverse "$SCAN_RANGE" 2>/dev/null) \
|
|
336
|
+
|| { echo "ERR: --scan-range: cannot list commits in $SCAN_RANGE" >&2; exit 1; }
|
|
337
|
+
# The repository's own .gitattributes can mark any path `-diff` or `binary`,
|
|
338
|
+
# which would make the diff say "Binary files differ" and hide added lines
|
|
339
|
+
# from the scan. Neutralise it: GIT_ATTR_NOSYSTEM drops the system file,
|
|
340
|
+
# core.attributesFile=/dev/null drops the user file, and --attr-source with an
|
|
341
|
+
# empty tree (the empty-tree hash) drops the in-tree .gitattributes. --text
|
|
342
|
+
# forces a textual diff, and numstat's binary marker ('-') is scanned from the
|
|
343
|
+
# blob rather than skipped. GIT_LITERAL_PATHSPECS stops a crafted filename
|
|
344
|
+
# from being read as a pathspec magic prefix.
|
|
345
|
+
EMPTY_TREE=$(git hash-object -t tree /dev/null 2>/dev/null)
|
|
346
|
+
gitscan() {
|
|
347
|
+
GIT_ATTR_NOSYSTEM=1 GIT_LITERAL_PATHSPECS=1 \
|
|
348
|
+
git -c core.attributesFile=/dev/null -c core.quotePath=false \
|
|
349
|
+
${EMPTY_TREE:+-c "diff.attributesSource=$EMPTY_TREE"} "$@"
|
|
350
|
+
}
|
|
351
|
+
for commit in $range_commits; do
|
|
352
|
+
while IFS= read -r -d '' file; do
|
|
353
|
+
[ -z "$file" ] && continue
|
|
354
|
+
content=$(gitscan diff-tree --no-commit-id -p --root -m --first-parent \
|
|
355
|
+
--no-ext-diff --no-textconv --text ${EMPTY_TREE:+--attr-source="$EMPTY_TREE"} \
|
|
356
|
+
"$commit" -- "$file" 2>/dev/null | grep "^+" | grep -v "^+++" || true)
|
|
357
|
+
if [ -z "$content" ]; then
|
|
358
|
+
# A file git still treats as binary yields no +lines; scan the whole
|
|
359
|
+
# blob at this commit so a NUL-laden file cannot hide a key.
|
|
360
|
+
content=$(gitscan show --text --no-textconv "${commit}:${file}" 2>/dev/null || true)
|
|
361
|
+
fi
|
|
362
|
+
scan_file "$file" "$content"
|
|
363
|
+
done < <(gitscan diff-tree --no-commit-id -r --root -m --first-parent \
|
|
364
|
+
--name-only -z --diff-filter=d "$commit" 2>/dev/null)
|
|
365
|
+
done
|
|
366
|
+
if [ "$FOUND" -eq 1 ]; then
|
|
367
|
+
echo "" >&2
|
|
368
|
+
echo "Secret check failed on $SCAN_RANGE." >&2
|
|
369
|
+
exit 2
|
|
370
|
+
fi
|
|
371
|
+
exit 0
|
|
372
|
+
fi
|
|
373
|
+
|
|
278
374
|
# NUL-delimited so filenames with spaces are scanned (a space-split loop would
|
|
279
375
|
# silently skip them - a secret false-negative).
|
|
280
376
|
|
|
@@ -316,4 +412,19 @@ if [ $FOUND -eq 1 ]; then
|
|
|
316
412
|
exit 2
|
|
317
413
|
fi
|
|
318
414
|
|
|
415
|
+
# Unattended commit: the verification gates must have passed for this HEAD.
|
|
416
|
+
# The environment is the hook's own, inherited from the process the launcher
|
|
417
|
+
# started, so the run cannot talk its way past it by editing its state. An
|
|
418
|
+
# attended commit skips this entirely.
|
|
419
|
+
if [ "$IS_COMMIT_HOOK" = "1" ] && ma_unattended; then
|
|
420
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
421
|
+
echo "BLOCKED: unattended commit, and node is not available to check the gate ledger." >&2
|
|
422
|
+
exit 2
|
|
423
|
+
fi
|
|
424
|
+
if ! node "$PRE_COMMIT_DIR/gate-ledger.mjs" check --repo "${REPO_ROOT:-$PWD}" >/dev/null; then
|
|
425
|
+
echo "BLOCKED: unattended commit without a passing gate ledger for HEAD (see above)." >&2
|
|
426
|
+
exit 2
|
|
427
|
+
fi
|
|
428
|
+
fi
|
|
429
|
+
|
|
319
430
|
exit 0
|
|
@@ -22,9 +22,16 @@
|
|
|
22
22
|
# second copy is a second place for the answer to drift.
|
|
23
23
|
#
|
|
24
24
|
# Usage:
|
|
25
|
-
# probe-evidence-capability.sh --platform <ios|android|web> [--repo <path>]
|
|
26
|
-
# [--changed <f>[,<f>...]]
|
|
27
|
-
# [--json-out <path>] [--only all|device]
|
|
25
|
+
# probe-evidence-capability.sh --platform <ios|android|web|auto> [--repo <path>]
|
|
26
|
+
# [--stack-root <path>] [--changed <f>[,<f>...]]
|
|
27
|
+
# [--json] [--json-out <path>] [--only all|device]
|
|
28
|
+
#
|
|
29
|
+
# --platform auto reads the repo's stacks with lib/stack-detect.sh (from
|
|
30
|
+
# --stack-root, default --repo) and probes the first of ios, android, web. A repo
|
|
31
|
+
# with none of them has no device to probe: the output is platform `other` with
|
|
32
|
+
# a skippedReason ("no device platform in stacks [backend]") and exit 0, the
|
|
33
|
+
# outcome visual-evidence.md section 1a records. Phase 0 calls it this way so the
|
|
34
|
+
# choice is one command, not a shell `case` the unattended guard refuses.
|
|
28
35
|
#
|
|
29
36
|
# Output: KEY='VALUE' lines (eval-able; every value is shell-quoted), or a JSON object with --json (shaped for
|
|
30
37
|
# state.evidenceCapability). --json-out writes that JSON to a file while stdout
|
|
@@ -40,12 +47,13 @@
|
|
|
40
47
|
set -uo pipefail
|
|
41
48
|
|
|
42
49
|
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
43
|
-
PLATFORM=""; REPO="$PWD"; CHANGED=""; AS_JSON=0; JSON_OUT=""; ONLY="all"
|
|
50
|
+
PLATFORM=""; REPO="$PWD"; CHANGED=""; AS_JSON=0; JSON_OUT=""; ONLY="all"; STACK_ROOT=""
|
|
44
51
|
|
|
45
52
|
while [ "$#" -gt 0 ]; do
|
|
46
53
|
case "$1" in
|
|
47
54
|
--platform) PLATFORM="${2:-}"; shift 2 ;;
|
|
48
55
|
--repo) REPO="${2:-}"; shift 2 ;;
|
|
56
|
+
--stack-root) STACK_ROOT="${2:-}"; shift 2 ;;
|
|
49
57
|
--changed) CHANGED="${CHANGED:+$CHANGED,}${2:-}"; shift 2 ;;
|
|
50
58
|
--json) AS_JSON=1; shift ;;
|
|
51
59
|
--json-out) JSON_OUT="${2:-}"; shift 2 ;;
|
|
@@ -57,8 +65,39 @@ case "$ONLY" in all | device) ;; *)
|
|
|
57
65
|
echo "probe-evidence-capability: --only takes 'all' or 'device'" >&2; exit 2 ;;
|
|
58
66
|
esac
|
|
59
67
|
|
|
68
|
+
if [ "$PLATFORM" = "auto" ]; then
|
|
69
|
+
STACK_DETECT="$HERE/../lib/stack-detect.sh"
|
|
70
|
+
[ -f "$STACK_DETECT" ] || { echo "probe-evidence-capability: stack-detect.sh not found at $STACK_DETECT" >&2; exit 2; }
|
|
71
|
+
# shellcheck source=../lib/stack-detect.sh
|
|
72
|
+
. "$STACK_DETECT"
|
|
73
|
+
ma_stack_detect "${STACK_ROOT:-$REPO}" || true
|
|
74
|
+
PLATFORM=""
|
|
75
|
+
case " $MA_STACKS " in
|
|
76
|
+
*" ios "*) PLATFORM=ios ;;
|
|
77
|
+
*" android "*) PLATFORM=android ;;
|
|
78
|
+
*" web "*) PLATFORM=web ;;
|
|
79
|
+
esac
|
|
80
|
+
if [ -z "$PLATFORM" ]; then
|
|
81
|
+
SKIPPED="no device platform in stacks [$MA_STACKS]"
|
|
82
|
+
SKIP_JSON=$(SKIPPED="$SKIPPED" node -e '
|
|
83
|
+
process.stdout.write(JSON.stringify({ platform: "other", skippedReason: process.env.SKIPPED }, null, 2) + "\n");
|
|
84
|
+
')
|
|
85
|
+
if [ -n "$JSON_OUT" ]; then
|
|
86
|
+
mkdir -p "$(dirname "$JSON_OUT")" 2>/dev/null || true
|
|
87
|
+
printf '%s\n' "$SKIP_JSON" > "$JSON_OUT" || { echo "probe-evidence-capability: could not write $JSON_OUT" >&2; exit 2; }
|
|
88
|
+
fi
|
|
89
|
+
if [ "$AS_JSON" -eq 1 ]; then
|
|
90
|
+
printf '%s\n' "$SKIP_JSON"
|
|
91
|
+
else
|
|
92
|
+
printf "EVIDENCE_PLATFORM='other'\n"
|
|
93
|
+
printf "EVIDENCE_SKIPPED_REASON='%s'\n" "$(printf '%s' "$SKIPPED" | sed "s/'/'\\\\''/g")"
|
|
94
|
+
fi
|
|
95
|
+
exit 0
|
|
96
|
+
fi
|
|
97
|
+
fi
|
|
98
|
+
|
|
60
99
|
case "$PLATFORM" in ios | android | web) ;; *)
|
|
61
|
-
echo "usage: probe-evidence-capability.sh --platform <ios|android|web> [--repo <path>] [--changed <f>] [--json]" >&2
|
|
100
|
+
echo "usage: probe-evidence-capability.sh --platform <ios|android|web|auto> [--repo <path>] [--changed <f>] [--json]" >&2
|
|
62
101
|
exit 2 ;;
|
|
63
102
|
esac
|
|
64
103
|
[ -d "$REPO" ] || { echo "probe-evidence-capability: no such repo directory: $REPO" >&2; exit 2; }
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* record-phase.mjs - move `state.currentPhase` to a phase that just completed.
|
|
4
|
+
*
|
|
5
|
+
* `currentPhase` is the last completed phase, and resume re-enters at
|
|
6
|
+
* `currentPhase + 1`. The tracker records every phase transition in its own
|
|
7
|
+
* file, so phase-tracker.sh calls this on each `update <id> completed` to keep
|
|
8
|
+
* the run state in step. The value only moves forward: a review loop that
|
|
9
|
+
* completes Phase 2 again after Phase 3 leaves it at 3.
|
|
10
|
+
*
|
|
11
|
+
* A non-numeric phase id (a sub-phase such as `3a`) or a run with no state
|
|
12
|
+
* file is a quiet no-op, because the tracker runs in contexts with no run.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* node record-phase.mjs --task-id <id> --phase <n>
|
|
16
|
+
*
|
|
17
|
+
* Exit: 0 recorded or nothing to do · 2 usage
|
|
18
|
+
*
|
|
19
|
+
* @module pipeline/scripts/record-phase
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
23
|
+
import { resolveRunFile } from "./_run-paths.mjs";
|
|
24
|
+
import { updateState } from "./gate-ledger.mjs";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} taskId
|
|
28
|
+
* @param {string} phase
|
|
29
|
+
* @returns {Promise<boolean>} true when the state was changed
|
|
30
|
+
*/
|
|
31
|
+
export async function recordPhase(taskId, phase) {
|
|
32
|
+
if (!/^\d+$/.test(String(phase))) return false;
|
|
33
|
+
const path = resolveRunFile(taskId, "agent-state.json");
|
|
34
|
+
if (!path) return false;
|
|
35
|
+
const n = Number(phase);
|
|
36
|
+
let changed = false;
|
|
37
|
+
await updateState(path, (s) => {
|
|
38
|
+
const current = Number.isInteger(s.currentPhase) ? s.currentPhase : -1;
|
|
39
|
+
if (n <= current) return s;
|
|
40
|
+
changed = true;
|
|
41
|
+
return { ...s, currentPhase: n };
|
|
42
|
+
});
|
|
43
|
+
return changed;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function main(argv) {
|
|
47
|
+
const opts = {};
|
|
48
|
+
for (let i = 0; i < argv.length; i++) {
|
|
49
|
+
if (argv[i] === "--task-id" || argv[i] === "--phase") {
|
|
50
|
+
if (argv[i + 1] === undefined) return 2;
|
|
51
|
+
opts[argv[i].slice(2)] = argv[++i];
|
|
52
|
+
} else {
|
|
53
|
+
process.stderr.write(`record-phase: unexpected argument ${argv[i]}\n`);
|
|
54
|
+
return 2;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (!opts["task-id"] || opts.phase === undefined) {
|
|
58
|
+
process.stderr.write("record-phase: --task-id and --phase are required\n");
|
|
59
|
+
return 2;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
await recordPhase(opts["task-id"], opts.phase);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
process.stderr.write(`record-phase: ${err.message}\n`);
|
|
65
|
+
}
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (invokedDirectly(import.meta.url)) {
|
|
70
|
+
main(process.argv.slice(2)).then((code) => process.exit(code));
|
|
71
|
+
}
|
|
@@ -11,7 +11,12 @@
|
|
|
11
11
|
# via prefs.global.reportContent.costSummary.
|
|
12
12
|
#
|
|
13
13
|
# Usage:
|
|
14
|
-
# render-agent-log-cost.sh <task-id> [--otel-spans <path>]
|
|
14
|
+
# render-agent-log-cost.sh <task-id> [--otel-spans <path>] [--append <agent-log.md>]
|
|
15
|
+
#
|
|
16
|
+
# --append adds the rendered section to the end of that file, after a blank
|
|
17
|
+
# line, and prints nothing; with no data (exit 2) the file is left alone. Phase 5
|
|
18
|
+
# runs it this way so the step is one command, not a substitution plus a shell
|
|
19
|
+
# redirect into a path the unattended guard cannot check.
|
|
15
20
|
#
|
|
16
21
|
# Exit codes:
|
|
17
22
|
# 0 - section rendered (empty section still prints with placeholder row)
|
|
@@ -23,22 +28,32 @@ set -euo pipefail
|
|
|
23
28
|
# (nested <root>/<project>/<id>/ and flat <root>/<id>/) and every id spelling.
|
|
24
29
|
_MA_RP_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
30
|
# shellcheck source=/dev/null
|
|
26
|
-
|
|
31
|
+
if [ -f "$_MA_RP_HERE/../lib/run-paths.sh" ]; then . "$_MA_RP_HERE/../lib/run-paths.sh"; else . "$HOME/.claude/lib/run-paths.sh"; fi
|
|
27
32
|
|
|
28
33
|
|
|
29
34
|
TASK_ID="${1:?usage: render-agent-log-cost.sh <task-id> [--otel-spans <path>]}"
|
|
30
35
|
shift || true
|
|
31
36
|
|
|
32
37
|
SPANS_FILE=""
|
|
38
|
+
APPEND_TO=""
|
|
33
39
|
while [ $# -gt 0 ]; do
|
|
34
40
|
case "$1" in
|
|
35
41
|
--otel-spans)
|
|
36
42
|
[ $# -ge 2 ] || { echo "render-agent-log-cost: --otel-spans needs a path" >&2; exit 1; }
|
|
37
43
|
SPANS_FILE="$2"; shift 2 ;;
|
|
44
|
+
--append)
|
|
45
|
+
[ $# -ge 2 ] || { echo "render-agent-log-cost: --append needs a path" >&2; exit 1; }
|
|
46
|
+
APPEND_TO="$2"; shift 2 ;;
|
|
38
47
|
*) shift ;;
|
|
39
48
|
esac
|
|
40
49
|
done
|
|
41
50
|
|
|
51
|
+
if [ -n "$APPEND_TO" ]; then
|
|
52
|
+
block=$(bash "${BASH_SOURCE[0]}" "$TASK_ID" ${SPANS_FILE:+--otel-spans "$SPANS_FILE"}) || exit $?
|
|
53
|
+
printf '\n%s\n' "$block" >> "$APPEND_TO"
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
42
57
|
# cost-table.json/cost-lib.sh ship as siblings of this script both in the
|
|
43
58
|
# repo (pipeline/scripts/) and once installed (~/.claude/scripts/) - a
|
|
44
59
|
# repo-root-relative path (../../pipeline/scripts/...) only resolves in the
|
|
@@ -17,7 +17,7 @@ set -euo pipefail
|
|
|
17
17
|
# (nested <root>/<project>/<id>/ and flat <root>/<id>/) and every id spelling.
|
|
18
18
|
_MA_RP_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
19
19
|
# shellcheck source=/dev/null
|
|
20
|
-
|
|
20
|
+
if [ -f "$_MA_RP_HERE/../lib/run-paths.sh" ]; then . "$_MA_RP_HERE/../lib/run-paths.sh"; else . "$HOME/.claude/lib/run-paths.sh"; fi
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
TASK_ID="${1:?usage: render-cost-summary.sh <task-id> [--otel-spans <path>]}"
|
|
@@ -44,7 +44,7 @@ set -euo pipefail
|
|
|
44
44
|
# (nested <root>/<project>/<id>/ and flat <root>/<id>/) and every id spelling.
|
|
45
45
|
_MA_RP_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
46
46
|
# shellcheck source=/dev/null
|
|
47
|
-
|
|
47
|
+
if [ -f "$_MA_RP_HERE/../lib/run-paths.sh" ]; then . "$_MA_RP_HERE/../lib/run-paths.sh"; else . "$HOME/.claude/lib/run-paths.sh"; fi
|
|
48
48
|
|
|
49
49
|
|
|
50
50
|
TASK_ID="${1:?usage: render-work-summary.sh <task-id>}"
|
|
@@ -39,6 +39,9 @@ CHECK="$HERE/update-check.sh"
|
|
|
39
39
|
[ -f "$CHECK" ] || CHECK="$HOME/.claude/scripts/update-check.sh"
|
|
40
40
|
[ -f "$CHECK" ] || exit 0 # no checker installed -> nothing to enforce
|
|
41
41
|
|
|
42
|
+
# shellcheck source=/dev/null
|
|
43
|
+
if [ -f "$HERE/../lib/user-facing.sh" ]; then . "$HERE/../lib/user-facing.sh"; else . "$HOME/.claude/lib/user-facing.sh"; fi
|
|
44
|
+
|
|
42
45
|
out=$(bash "$CHECK" "$@" 2>/dev/null) || exit 0
|
|
43
46
|
case "$out" in
|
|
44
47
|
*"|force") ;;
|
|
@@ -64,7 +67,7 @@ cat >&2 <<MSG
|
|
|
64
67
|
This release line is required, not optional.
|
|
65
68
|
Installed: v${local_v} Required: v${required_v} or newer Latest: v${latest_v}
|
|
66
69
|
|
|
67
|
-
Run
|
|
70
|
+
Run $(ma_command update), then start this command again.
|
|
68
71
|
|
|
69
72
|
MSG
|
|
70
73
|
exit 3
|