@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
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
* Spend. A rolling 24-hour total from the attempt log against
|
|
11
11
|
* `costCeilingUsd`. Past the ceiling, dispatch refuses and says so. Work
|
|
12
12
|
* already running is NEVER killed mid-item: stopping between a commit and a
|
|
13
|
-
* PR leaves a branch nobody asked for, and the money is already spent.
|
|
13
|
+
* PR leaves a branch nobody asked for, and the money is already spent. A run
|
|
14
|
+
* in the window whose cost was not measured (`usd: null`) blocks too, as
|
|
15
|
+
* `cost-unknown`: the ceiling cannot be checked against a total with a hole.
|
|
14
16
|
*
|
|
15
17
|
* Credentials. `prefs.global.serviceStatus.<service>` must not be a recorded
|
|
16
18
|
* failure for the service an item needs. Without this, an expired Jira token
|
|
@@ -22,35 +24,157 @@
|
|
|
22
24
|
* run yet on this machine, and refusing on absence would mean the queue never
|
|
23
25
|
* starts. Only a recorded `ok: false` blocks.
|
|
24
26
|
*
|
|
27
|
+
* Readable, not only recorded. `probe` asks every credential the configured
|
|
28
|
+
* repos need whether it can be read right now without a prompt: `gh auth
|
|
29
|
+
* status` for GitHub, and `credential-store.sh probe` for the logical keys a
|
|
30
|
+
* source reads from `prefs.global.keychainMapping` (Jira today). The value is
|
|
31
|
+
* never read into this process - the store answers one word. autopilot-on runs
|
|
32
|
+
* it before the schedule is offered, and every tick runs the item's own half
|
|
33
|
+
* through `check --probe`, because a tick runs in the background session, where
|
|
34
|
+
* a keychain that locked on sleep answers differently from the terminal that
|
|
35
|
+
* armed it. A missing, unmapped or locked credential refuses; a keychain set to
|
|
36
|
+
* lock on sleep or after a timeout is a warning, since it is readable now.
|
|
37
|
+
*
|
|
38
|
+
* A check that cannot finish answers `armed: false` with `blockedBy:
|
|
39
|
+
* "internal"`. This verdict stands between an unattended queue and money, so
|
|
40
|
+
* the absence of an answer has to cost nothing rather than read as yes.
|
|
41
|
+
*
|
|
25
42
|
* Usage:
|
|
26
43
|
* autopilot-arming.mjs check [--source github|jira] KEY=VALUE lines, exit 0
|
|
27
44
|
* autopilot-arming.mjs check --json
|
|
45
|
+
* autopilot-arming.mjs check --source jira --probe --json also probe the item's credential
|
|
46
|
+
* autopilot-arming.mjs check --source jira --repo <owner/name> --probe --json
|
|
47
|
+
* and the repo's publish credential
|
|
48
|
+
* autopilot-arming.mjs probe [--json] every credential the config needs
|
|
28
49
|
*
|
|
29
50
|
* Exit: 0 whether or not it is armed - "not armed" is an answer. 2 on usage.
|
|
30
51
|
*/
|
|
31
52
|
|
|
53
|
+
import { spawnSync } from "node:child_process";
|
|
32
54
|
import { existsSync, readFileSync } from "node:fs";
|
|
33
55
|
import { join } from "node:path";
|
|
34
56
|
import { homedir } from "node:os";
|
|
35
57
|
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
58
|
+
import { attemptSpend } from "./_cost.mjs";
|
|
59
|
+
import { configRefusal } from "./_autopilot-config.mjs";
|
|
60
|
+
import { hostCommand, messages as languageHalf } from "../lib/user-facing.mjs";
|
|
36
61
|
|
|
37
62
|
const ROOT = process.env.MA_AUTOPILOT_ROOT || join(homedir(), ".claude", "autopilot");
|
|
63
|
+
// `$MULTI_AGENT_PREFS` is the name every other shipped script honours, so a test
|
|
64
|
+
// that points one half of a status line at a fixture points the other half at
|
|
65
|
+
// the same one. `$MA_PREFS_FILE` stays readable for callers that already set it.
|
|
38
66
|
const PREFS =
|
|
39
|
-
process.env.
|
|
67
|
+
process.env.MULTI_AGENT_PREFS ||
|
|
68
|
+
process.env.MA_PREFS_FILE ||
|
|
69
|
+
join(homedir(), ".claude", "multi-agent-preferences.json");
|
|
70
|
+
|
|
71
|
+
// Beside this script in every install, as lib/ sits beside scripts/.
|
|
72
|
+
const STORE =
|
|
73
|
+
process.env.MA_AP_CREDENTIAL_STORE ||
|
|
74
|
+
join(import.meta.dirname, "..", "lib", "credential-store.sh");
|
|
75
|
+
// A store that has not answered in this long is waiting on a prompt nobody can
|
|
76
|
+
// answer from a background session.
|
|
77
|
+
const PROBE_TIMEOUT_MS = Number(process.env.MA_AP_PROBE_TIMEOUT_MS || 20000);
|
|
40
78
|
|
|
41
79
|
/** Which service an item from this source cannot proceed without. */
|
|
42
80
|
export const SOURCE_SERVICE = { github: "github", jira: "jira" };
|
|
43
81
|
|
|
82
|
+
/**
|
|
83
|
+
* A blocked queue explains itself in `prefs.global.outputLanguage`, the same
|
|
84
|
+
* preference every other human-facing surface reads; English is the default and
|
|
85
|
+
* the fallback for a language this table does not carry.
|
|
86
|
+
*/
|
|
87
|
+
const MESSAGES = {
|
|
88
|
+
en: {
|
|
89
|
+
credential: (svc, at, cmd) =>
|
|
90
|
+
`the ${svc} credential is not valid (${at}) - refresh it with ${cmd}`,
|
|
91
|
+
cost: (spent, ceiling) =>
|
|
92
|
+
`$${spent} spent in the last 24 hours, ceiling $${ceiling} - work in flight is finished, no new item is taken`,
|
|
93
|
+
costUnknown: (runs) =>
|
|
94
|
+
`${runs} run(s) in the last 24 hours have a cost that was not measured, so the spend ceiling cannot be checked - no new item is taken until they leave the window`,
|
|
95
|
+
internal: (detail) =>
|
|
96
|
+
`the arming check could not finish (${detail}) - no new item is taken until it can`,
|
|
97
|
+
config: (detail) => `${detail} - no new item is taken until config.json is corrected`,
|
|
98
|
+
ghMissing: () => "GitHub: gh is not installed - install it, then run gh auth login",
|
|
99
|
+
ghUnauth: () =>
|
|
100
|
+
"GitHub: gh is not authenticated for a non-interactive session - run gh auth login",
|
|
101
|
+
unmapped: (key, cmd) =>
|
|
102
|
+
`credential "${key}": prefs.global.keychainMapping.${key} is not set - save the token with ${cmd}`,
|
|
103
|
+
noHost: (key, cmd) =>
|
|
104
|
+
`credential "${key}": prefs.global.hosts.${key} is not set - record the host with ${cmd}`,
|
|
105
|
+
missing: (key, item, cmd) =>
|
|
106
|
+
`credential "${key}" (stored as "${item}") is not in the credential store - save it with ${cmd}`,
|
|
107
|
+
locked: (key) =>
|
|
108
|
+
`credential "${key}" cannot be read without a prompt: the keychain is locked for this session - unlock it (security unlock-keychain), or stop it locking on sleep and after a timeout`,
|
|
109
|
+
noAnswer: (key, sec) =>
|
|
110
|
+
`credential "${key}": the credential store did not answer in ${sec}s - it is most likely waiting on a keychain prompt nobody can answer in the background; unlock the keychain`,
|
|
111
|
+
storeError: (key) =>
|
|
112
|
+
`credential "${key}": the credential store could not be read - run credential-store.sh doctor`,
|
|
113
|
+
lockWarning: (when) =>
|
|
114
|
+
`the login keychain locks ${when}; a background tick after that finds it locked and refuses items until it is unlocked - Keychain Access > login > Change Settings, or security set-keychain-settings with no options`,
|
|
115
|
+
afterSleep: "after sleep",
|
|
116
|
+
afterIdle: (min) => `after ${min} min idle`,
|
|
117
|
+
and: " and ",
|
|
118
|
+
},
|
|
119
|
+
tr: {
|
|
120
|
+
credential: (svc, at, cmd) => `${svc} kimlik bilgisi geçersiz (${at}) - ${cmd} ile yenile`,
|
|
121
|
+
cost: (spent, ceiling) =>
|
|
122
|
+
`son 24 saatte $${spent} harcandı, tavan $${ceiling} - koşan iş bitirilir, yeni madde alınmaz`,
|
|
123
|
+
costUnknown: (runs) =>
|
|
124
|
+
`son 24 saatte ${runs} koşunun maliyeti ölçülmedi, harcama tavanı denetlenemiyor - bu koşular pencereden çıkana kadar yeni madde alınmaz`,
|
|
125
|
+
internal: (detail) =>
|
|
126
|
+
`hazırlık denetimi tamamlanamadı (${detail}) - tamamlanana kadar yeni madde alınmaz`,
|
|
127
|
+
config: (detail) => `${detail} - config.json düzeltilene kadar yeni madde alınmaz`,
|
|
128
|
+
ghMissing: () => "GitHub: gh kurulu değil - kur, sonra gh auth login çalıştır",
|
|
129
|
+
ghUnauth: () => "GitHub: gh etkileşimsiz oturum için giriş yapmamış - gh auth login çalıştır",
|
|
130
|
+
unmapped: (key, cmd) =>
|
|
131
|
+
`"${key}" kimlik bilgisi: prefs.global.keychainMapping.${key} tanımlı değil - token'ı ${cmd} ile kaydet`,
|
|
132
|
+
noHost: (key, cmd) =>
|
|
133
|
+
`"${key}" kimlik bilgisi: prefs.global.hosts.${key} tanımlı değil - host'u ${cmd} ile kaydet`,
|
|
134
|
+
missing: (key, item, cmd) =>
|
|
135
|
+
`"${key}" kimlik bilgisi ("${item}" adıyla) kimlik deposunda yok - ${cmd} ile kaydet`,
|
|
136
|
+
locked: (key) =>
|
|
137
|
+
`"${key}" kimlik bilgisi sorusuz okunamıyor: anahtar zinciri bu oturum için kilitli - kilidi aç (security unlock-keychain) ya da uykuda ve zaman aşımında kilitlenmesini kapat`,
|
|
138
|
+
noAnswer: (key, sec) =>
|
|
139
|
+
`"${key}" kimlik bilgisi: kimlik deposu ${sec}sn içinde cevap vermedi - büyük olasılıkla arka planda kimsenin cevaplayamayacağı bir anahtar zinciri sorusunu bekliyor; kilidi aç`,
|
|
140
|
+
storeError: (key) =>
|
|
141
|
+
`"${key}" kimlik bilgisi: kimlik deposu okunamadı - credential-store.sh doctor çalıştır`,
|
|
142
|
+
lockWarning: (when) =>
|
|
143
|
+
`giriş anahtar zinciri ${when} kilitleniyor; sonrasındaki arka plan turu onu kilitli bulur ve kilit açılana kadar madde almaz - Anahtar Zinciri Erişimi > login > Ayarları Değiştir, ya da seçeneksiz security set-keychain-settings`,
|
|
144
|
+
afterSleep: "uykudan sonra",
|
|
145
|
+
afterIdle: (min) => `${min} dk boşta kaldıktan sonra`,
|
|
146
|
+
and: " ve ",
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Every key in the table resolves, whatever the preference says.
|
|
152
|
+
*
|
|
153
|
+
* The half comes from an own-property lookup, so a code that spells an
|
|
154
|
+
* inherited name is a language this table does not carry rather than a
|
|
155
|
+
* function. English is then laid underneath it, so a key carried by one half
|
|
156
|
+
* and not the other renders in English instead of arriving as `undefined`
|
|
157
|
+
* where the caller expects a sentence.
|
|
158
|
+
*/
|
|
159
|
+
export function messages(language) {
|
|
160
|
+
return { ...MESSAGES.en, ...languageHalf(MESSAGES, language) };
|
|
161
|
+
}
|
|
162
|
+
|
|
44
163
|
/**
|
|
45
164
|
* Spend inside the trailing window. Reads the append-only attempt log rather
|
|
46
165
|
* than a running total in a file: a counter can be lost, double-counted, or
|
|
47
166
|
* left behind by a crash, and the log is the thing that already has to be
|
|
48
167
|
* written for retry to work at all.
|
|
168
|
+
*
|
|
169
|
+
* `usd` is cumulative per run, so a run recorded twice counts once, at its
|
|
170
|
+
* largest figure (_cost.mjs attemptSpend). A run whose cost was never measured
|
|
171
|
+
* (`usd: null`) is counted in `unknown`, never as 0. A row with no `usd` at all
|
|
172
|
+
* is one where nothing ran - an arming refusal, a checkout that is not there -
|
|
173
|
+
* and costs nothing.
|
|
49
174
|
*/
|
|
50
175
|
export function spendWindow(lines, { now = Date.now() / 1000, windowSeconds = 86400 } = {}) {
|
|
51
176
|
const cutoff = now - windowSeconds;
|
|
52
|
-
|
|
53
|
-
let items = 0;
|
|
177
|
+
const rows = [];
|
|
54
178
|
for (const raw of lines) {
|
|
55
179
|
const s = raw.trim();
|
|
56
180
|
if (!s) continue;
|
|
@@ -60,18 +184,33 @@ export function spendWindow(lines, { now = Date.now() / 1000, windowSeconds = 86
|
|
|
60
184
|
} catch {
|
|
61
185
|
continue;
|
|
62
186
|
}
|
|
63
|
-
if ((rec.at || 0) < cutoff) continue;
|
|
64
|
-
|
|
65
|
-
items += 1;
|
|
187
|
+
if (!rec || typeof rec !== "object" || (rec.at || 0) < cutoff) continue;
|
|
188
|
+
rows.push(rec);
|
|
66
189
|
}
|
|
67
|
-
|
|
190
|
+
const { usd, unknown } = attemptSpend(rows);
|
|
191
|
+
return { usd: Math.round(usd * 100) / 100, items: rows.length, unknown };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The service the runner publishes a repo's verified branch with, when it is a
|
|
196
|
+
* credential this script can probe: `gh` for a GitHub-hosted repo (the default
|
|
197
|
+
* host). A Bitbucket push goes through the operator's git credential helper,
|
|
198
|
+
* which has no probe that answers without a network round trip.
|
|
199
|
+
*
|
|
200
|
+
* @returns {string|null}
|
|
201
|
+
*/
|
|
202
|
+
export function publishService(config, repo) {
|
|
203
|
+
if (!repo) return null;
|
|
204
|
+
const cfg = (config?.repos || []).find((r) => r && r.nameWithOwner === repo);
|
|
205
|
+
if (!cfg) return null;
|
|
206
|
+
return (cfg.host ?? "github") === "github" ? "github" : null;
|
|
68
207
|
}
|
|
69
208
|
|
|
70
209
|
/**
|
|
71
210
|
* @returns {{ok: boolean, reason: string|null}} - `reason` is written for a
|
|
72
211
|
* human to read in the menu bar, so it says what to do, not what failed.
|
|
73
212
|
*/
|
|
74
|
-
export function credentialGate(serviceStatus, source) {
|
|
213
|
+
export function credentialGate(serviceStatus, source, language = "en") {
|
|
75
214
|
const svc = SOURCE_SERVICE[source];
|
|
76
215
|
if (!svc) return { ok: true, reason: null };
|
|
77
216
|
const rec = serviceStatus?.[svc];
|
|
@@ -79,22 +218,187 @@ export function credentialGate(serviceStatus, source) {
|
|
|
79
218
|
if (rec.ok) return { ok: true, reason: null };
|
|
80
219
|
return {
|
|
81
220
|
ok: false,
|
|
82
|
-
reason:
|
|
221
|
+
reason: messages(language).credential(svc, rec.checkedAt || "?", hostCommand("setup")),
|
|
83
222
|
};
|
|
84
223
|
}
|
|
85
224
|
|
|
86
|
-
|
|
87
|
-
|
|
225
|
+
/**
|
|
226
|
+
* The services the configured repos cannot run without. GitHub for a repo that
|
|
227
|
+
* takes GitHub issues or publishes to GitHub (the default host); Jira for a repo
|
|
228
|
+
* that takes Jira items. A repo with no `sources` takes GitHub issues.
|
|
229
|
+
*/
|
|
230
|
+
export function requiredServices(config) {
|
|
231
|
+
const need = new Set();
|
|
232
|
+
for (const r of config?.repos || []) {
|
|
233
|
+
const sources = Array.isArray(r?.sources) && r.sources.length ? r.sources : ["github"];
|
|
234
|
+
for (const s of sources) if (SOURCE_SERVICE[s]) need.add(SOURCE_SERVICE[s]);
|
|
235
|
+
if ((r?.host ?? "github") === "github") need.add("github");
|
|
236
|
+
}
|
|
237
|
+
return [...need].sort();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function timedOut(r) {
|
|
241
|
+
return r.error?.code === "ETIMEDOUT" || (r.status === null && Boolean(r.signal));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* One service, answered without its value: `gh auth status` for GitHub, the
|
|
246
|
+
* store's `probe` for a mapped key. Nothing either prints is kept.
|
|
247
|
+
*
|
|
248
|
+
* @returns {{service:string, key?:string, status:string, message?:string}}
|
|
249
|
+
*/
|
|
250
|
+
export function probeService(service, { prefs, env = process.env, language = "en" } = {}) {
|
|
251
|
+
const m = messages(language);
|
|
252
|
+
if (service === "github") {
|
|
253
|
+
const gh = env.MA_AP_GH_BIN || "gh";
|
|
254
|
+
const r = spawnSync(gh, ["auth", "status"], {
|
|
255
|
+
env,
|
|
256
|
+
stdio: "ignore",
|
|
257
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
258
|
+
});
|
|
259
|
+
if (r.error?.code === "ENOENT")
|
|
260
|
+
return { service, status: "missing-tool", message: m.ghMissing() };
|
|
261
|
+
if (timedOut(r)) {
|
|
262
|
+
return {
|
|
263
|
+
service,
|
|
264
|
+
status: "no-answer",
|
|
265
|
+
message: m.noAnswer("github", PROBE_TIMEOUT_MS / 1000),
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
return r.status === 0
|
|
269
|
+
? { service, status: "readable" }
|
|
270
|
+
: { service, status: "unauthenticated", message: m.ghUnauth() };
|
|
271
|
+
}
|
|
272
|
+
const key = service;
|
|
273
|
+
const setup = hostCommand("setup");
|
|
274
|
+
const item = prefs?.global?.keychainMapping?.[key];
|
|
275
|
+
if (typeof item !== "string" || !item.trim()) {
|
|
276
|
+
return { service, key, status: "unmapped", message: m.unmapped(key, setup) };
|
|
277
|
+
}
|
|
278
|
+
const host = prefs?.global?.hosts?.[key];
|
|
279
|
+
if (typeof host !== "string" || !host.trim()) {
|
|
280
|
+
return { service, key, status: "no-host", message: m.noHost(key, setup) };
|
|
281
|
+
}
|
|
282
|
+
const r = spawnSync("bash", [STORE, "probe", key], {
|
|
283
|
+
env: { ...env, MULTI_AGENT_PREFS: PREFS },
|
|
284
|
+
encoding: "utf-8",
|
|
285
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
286
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
287
|
+
});
|
|
288
|
+
if (timedOut(r)) {
|
|
289
|
+
return { service, key, status: "no-answer", message: m.noAnswer(key, PROBE_TIMEOUT_MS / 1000) };
|
|
290
|
+
}
|
|
291
|
+
const word = String(r.stdout || "").trim();
|
|
292
|
+
if (r.status === 0 && word === "readable") return { service, key, status: "readable" };
|
|
293
|
+
if (r.status === 5 || word === "locked") {
|
|
294
|
+
return { service, key, status: "locked", message: m.locked(key) };
|
|
295
|
+
}
|
|
296
|
+
if (r.status === 1 || word === "missing") {
|
|
297
|
+
return { service, key, status: "missing", message: m.missing(key, item.trim(), setup) };
|
|
298
|
+
}
|
|
299
|
+
return { service, key, status: "error", message: m.storeError(key) };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* The login keychain's lock settings, read with `security show-keychain-info`.
|
|
304
|
+
* Only macOS has them. A keychain that locks on sleep or after a timeout is
|
|
305
|
+
* readable from the terminal that armed the mode and locked for the tick that
|
|
306
|
+
* fires after the machine slept.
|
|
307
|
+
*
|
|
308
|
+
* @returns {{locked:boolean, lockOnSleep:boolean, timeoutSec:number|null}|null}
|
|
309
|
+
*/
|
|
310
|
+
export function keychainLock({ env = process.env, platform } = {}) {
|
|
311
|
+
if ((platform || env.MA_AP_PLATFORM || process.platform) !== "darwin") return null;
|
|
312
|
+
const r = spawnSync(env.MA_AP_SECURITY_BIN || "/usr/bin/security", ["show-keychain-info"], {
|
|
313
|
+
env,
|
|
314
|
+
encoding: "utf-8",
|
|
315
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
316
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
317
|
+
});
|
|
318
|
+
if (r.error) return null;
|
|
319
|
+
const text = `${r.stdout || ""}${r.stderr || ""}`;
|
|
320
|
+
if (r.status === 36 || /interaction is not allowed/i.test(text)) {
|
|
321
|
+
return { locked: true, lockOnSleep: false, timeoutSec: null };
|
|
322
|
+
}
|
|
323
|
+
if (r.status !== 0) return null;
|
|
324
|
+
const t = /timeout=(\d+)s/.exec(text);
|
|
325
|
+
return {
|
|
326
|
+
locked: false,
|
|
327
|
+
lockOnSleep: /lock-on-sleep/.test(text),
|
|
328
|
+
timeoutSec: t ? Number(t[1]) : null,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Every credential the config needs, probed. `ready` is false when any one is
|
|
334
|
+
* missing, unmapped, locked or unanswered; lock settings are warnings.
|
|
335
|
+
*/
|
|
336
|
+
export function probeCredentials({ config, prefs, env = process.env, platform } = {}) {
|
|
337
|
+
const language = prefs?.global?.outputLanguage ?? "en";
|
|
338
|
+
const m = messages(language);
|
|
339
|
+
const checked = requiredServices(config).map((svc) =>
|
|
340
|
+
probeService(svc, { prefs, env, language }),
|
|
341
|
+
);
|
|
342
|
+
const problems = checked.filter((c) => c.status !== "readable");
|
|
343
|
+
const keychain = keychainLock({ env, platform });
|
|
344
|
+
const warnings = [];
|
|
345
|
+
if (keychain && (keychain.lockOnSleep || keychain.timeoutSec)) {
|
|
346
|
+
const when = [
|
|
347
|
+
keychain.lockOnSleep ? m.afterSleep : null,
|
|
348
|
+
keychain.timeoutSec ? m.afterIdle(Math.round(keychain.timeoutSec / 60)) : null,
|
|
349
|
+
]
|
|
350
|
+
.filter(Boolean)
|
|
351
|
+
.join(m.and);
|
|
352
|
+
warnings.push(m.lockWarning(when));
|
|
353
|
+
}
|
|
354
|
+
return { ready: problems.length === 0, checked, problems, warnings, keychain };
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export function arming({ lines, prefs, config, source, now, probe = null }) {
|
|
358
|
+
const raw = config?.costCeilingUsd === undefined ? 25 : config.costCeilingUsd;
|
|
88
359
|
const spend = spendWindow(lines, { now });
|
|
89
|
-
const
|
|
360
|
+
const language = prefs?.global?.outputLanguage ?? "en";
|
|
361
|
+
// Every comparison with NaN is false, so a ceiling that is not a number would
|
|
362
|
+
// read as no ceiling at all. It is refused instead, and named.
|
|
363
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || raw < 0) {
|
|
364
|
+
return {
|
|
365
|
+
armed: false,
|
|
366
|
+
blockedBy: "config",
|
|
367
|
+
reason: messages(language).config(
|
|
368
|
+
`costCeilingUsd must be a number >= 0, got ${JSON.stringify(config?.costCeilingUsd)}`,
|
|
369
|
+
),
|
|
370
|
+
spend,
|
|
371
|
+
ceiling: 0,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const ceiling = raw;
|
|
375
|
+
const cred = credentialGate(prefs?.global?.serviceStatus, source, language);
|
|
90
376
|
|
|
91
377
|
if (!cred.ok)
|
|
92
378
|
return { armed: false, blockedBy: "credential", reason: cred.reason, spend, ceiling };
|
|
379
|
+
// A credential recorded as fine can still be unreadable here: the tick runs in
|
|
380
|
+
// the background session, and a keychain that locked on sleep is locked there.
|
|
381
|
+
const unreadable = [probe].flat().find((p) => p && p.status !== "readable");
|
|
382
|
+
if (unreadable) {
|
|
383
|
+
return { armed: false, blockedBy: "credential", reason: unreadable.message, spend, ceiling };
|
|
384
|
+
}
|
|
93
385
|
if (spend.usd >= ceiling) {
|
|
94
386
|
return {
|
|
95
387
|
armed: false,
|
|
96
388
|
blockedBy: "cost",
|
|
97
|
-
reason:
|
|
389
|
+
reason: messages(language).cost(spend.usd.toFixed(2), ceiling.toFixed(2)),
|
|
390
|
+
spend,
|
|
391
|
+
ceiling,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
// A ceiling checked against a total with holes in it reads as protection and
|
|
395
|
+
// is not: an unmeasured run may have cost more than the whole ceiling. Refuse
|
|
396
|
+
// until the unmeasured runs leave the window, rather than counting them as 0.
|
|
397
|
+
if (spend.unknown > 0) {
|
|
398
|
+
return {
|
|
399
|
+
armed: false,
|
|
400
|
+
blockedBy: "cost-unknown",
|
|
401
|
+
reason: messages(language).costUnknown(spend.unknown),
|
|
98
402
|
spend,
|
|
99
403
|
ceiling,
|
|
100
404
|
};
|
|
@@ -102,6 +406,8 @@ export function arming({ lines, prefs, config, source, now }) {
|
|
|
102
406
|
return { armed: true, blockedBy: null, reason: null, spend, ceiling };
|
|
103
407
|
}
|
|
104
408
|
|
|
409
|
+
class ConfigRefused extends Error {}
|
|
410
|
+
|
|
105
411
|
function readJson(path, fallback) {
|
|
106
412
|
if (!existsSync(path)) return fallback;
|
|
107
413
|
try {
|
|
@@ -111,20 +417,81 @@ function readJson(path, fallback) {
|
|
|
111
417
|
}
|
|
112
418
|
}
|
|
113
419
|
|
|
420
|
+
function probeMain(args) {
|
|
421
|
+
const prefs = readJson(PREFS, {});
|
|
422
|
+
const language = prefs?.global?.outputLanguage ?? "en";
|
|
423
|
+
let result;
|
|
424
|
+
try {
|
|
425
|
+
result = probeCredentials({ config: readJson(join(ROOT, "config.json"), {}), prefs });
|
|
426
|
+
} catch (e) {
|
|
427
|
+
const reason = messages(language).internal(e?.message || String(e));
|
|
428
|
+
result = {
|
|
429
|
+
ready: false,
|
|
430
|
+
checked: [],
|
|
431
|
+
problems: [{ status: "error", message: reason }],
|
|
432
|
+
warnings: [],
|
|
433
|
+
keychain: null,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
if (args.includes("--json")) {
|
|
437
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
438
|
+
return 0;
|
|
439
|
+
}
|
|
440
|
+
const out = [`PROBE_READY=${result.ready}`];
|
|
441
|
+
for (const p of result.problems) out.push(`PROBE_PROBLEM=${p.message}`);
|
|
442
|
+
for (const w of result.warnings) out.push(`PROBE_WARNING=${w}`);
|
|
443
|
+
process.stdout.write(out.join("\n") + "\n");
|
|
444
|
+
return 0;
|
|
445
|
+
}
|
|
446
|
+
|
|
114
447
|
function main(argv) {
|
|
115
448
|
const args = argv.slice(2);
|
|
449
|
+
if (args[0] === "probe") return probeMain(args);
|
|
116
450
|
if (args[0] !== "check") {
|
|
117
|
-
process.stderr.write(
|
|
451
|
+
process.stderr.write(
|
|
452
|
+
"usage: autopilot-arming.mjs check [--source github|jira] [--repo <owner/name>] [--probe] [--json] | probe [--json]\n",
|
|
453
|
+
);
|
|
118
454
|
return 2;
|
|
119
455
|
}
|
|
120
456
|
const source = args.includes("--source") ? args[args.indexOf("--source") + 1] : null;
|
|
457
|
+
const repo = args.includes("--repo") ? args[args.indexOf("--repo") + 1] : null;
|
|
121
458
|
const attempts = join(ROOT, "attempted.jsonl");
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
459
|
+
const prefs = readJson(PREFS, {});
|
|
460
|
+
const language = prefs?.global?.outputLanguage ?? "en";
|
|
461
|
+
|
|
462
|
+
// An arming check that cannot finish is not an armed queue. This verdict is
|
|
463
|
+
// the last thing between the queue and money, so the answer to "I could not
|
|
464
|
+
// work it out" is the one that spends nothing and says why.
|
|
465
|
+
let result;
|
|
466
|
+
try {
|
|
467
|
+
const config = readJson(join(ROOT, "config.json"), {});
|
|
468
|
+
const refusal = existsSync(join(ROOT, "config.json")) ? configRefusal(config) : null;
|
|
469
|
+
if (refusal) throw new ConfigRefused(refusal);
|
|
470
|
+
// The item's source credential, and the one its repo publishes with: an
|
|
471
|
+
// expired gh stops a Jira item in a GitHub repo at the push, after the run
|
|
472
|
+
// has been paid for, unless it is asked here first.
|
|
473
|
+
const services = args.includes("--probe")
|
|
474
|
+
? [...new Set([SOURCE_SERVICE[source], publishService(config, repo)].filter(Boolean))]
|
|
475
|
+
: [];
|
|
476
|
+
result = arming({
|
|
477
|
+
lines: existsSync(attempts) ? readFileSync(attempts, "utf-8").split("\n") : [],
|
|
478
|
+
prefs,
|
|
479
|
+
config,
|
|
480
|
+
source,
|
|
481
|
+
probe: services.map((svc) => probeService(svc, { prefs, language })),
|
|
482
|
+
});
|
|
483
|
+
} catch (e) {
|
|
484
|
+
const refused = e instanceof ConfigRefused;
|
|
485
|
+
result = {
|
|
486
|
+
armed: false,
|
|
487
|
+
blockedBy: refused ? "config" : "internal",
|
|
488
|
+
reason: refused
|
|
489
|
+
? messages(language).config(e.message)
|
|
490
|
+
: messages(language).internal(e?.message || String(e)),
|
|
491
|
+
spend: { usd: 0, items: 0, unknown: 0 },
|
|
492
|
+
ceiling: 0,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
128
495
|
|
|
129
496
|
if (args.includes("--json")) {
|
|
130
497
|
process.stdout.write(JSON.stringify(result) + "\n");
|
|
@@ -137,6 +504,7 @@ function main(argv) {
|
|
|
137
504
|
`ARM_REASON=${result.reason ?? ""}`,
|
|
138
505
|
`ARM_SPEND_USD=${result.spend.usd}`,
|
|
139
506
|
`ARM_SPEND_ITEMS=${result.spend.items}`,
|
|
507
|
+
`ARM_SPEND_UNKNOWN=${result.spend.unknown ?? 0}`,
|
|
140
508
|
`ARM_CEILING_USD=${result.ceiling}`,
|
|
141
509
|
].join("\n") + "\n",
|
|
142
510
|
);
|