@mmerterden/multi-agent-pipeline 20.2.1 → 20.3.0
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 +912 -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 +616 -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/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 +185 -65
- package/pipeline/scripts/usage-report.mjs +230 -66
- 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
|
@@ -27,9 +27,20 @@
|
|
|
27
27
|
# ma_ap_is_on # exit 0 when configured, 1 otherwise. NO side effects
|
|
28
28
|
# ma_ap_write <file> <- # atomic write from stdin, 0600
|
|
29
29
|
# ma_ap_asset <rel> # resolve a script/lib/template across the 3 host roots
|
|
30
|
+
# ma_ap_command <sub> # the subcommand, spelled the way this host spells it
|
|
30
31
|
|
|
31
32
|
set -uo pipefail
|
|
32
33
|
|
|
34
|
+
# The spelling of a command, and the language a sentence renders in, are one
|
|
35
|
+
# table for the whole pipeline. Sourcing it here is what keeps this file from
|
|
36
|
+
# carrying a second copy of either.
|
|
37
|
+
# shellcheck source=pipeline/lib/user-facing.sh
|
|
38
|
+
if [ -f "$(dirname "${BASH_SOURCE[0]}")/user-facing.sh" ]; then
|
|
39
|
+
. "$(dirname "${BASH_SOURCE[0]}")/user-facing.sh"
|
|
40
|
+
elif [ -f "$HOME/.claude/lib/user-facing.sh" ]; then
|
|
41
|
+
. "$HOME/.claude/lib/user-facing.sh"
|
|
42
|
+
fi
|
|
43
|
+
|
|
33
44
|
MA_AP_ROOT="${MA_AUTOPILOT_ROOT:-$HOME/.claude/autopilot}"
|
|
34
45
|
|
|
35
46
|
ma_ap_root() { printf '%s\n' "$MA_AP_ROOT"; }
|
|
@@ -67,6 +78,14 @@ ma_ap_asset() { # $1 = path relative to a host root, e.g. scripts/autopilot-runn
|
|
|
67
78
|
return 1
|
|
68
79
|
}
|
|
69
80
|
|
|
81
|
+
# The three CLIs spell the same command three ways, and the tree this file was
|
|
82
|
+
# sourced from is the one in front of the user. A status line that names a
|
|
83
|
+
# command names the one this machine can actually type. The table itself is
|
|
84
|
+
# `ma_command` in user-facing.sh - one place, so a fourth host is one edit.
|
|
85
|
+
ma_ap_command() { # $1 = subcommand, e.g. autopilot-off
|
|
86
|
+
ma_command "$1" "$MA_AP_HOST_ROOT"
|
|
87
|
+
}
|
|
88
|
+
|
|
70
89
|
MA_AP_LABEL="${MA_AUTOPILOT_LABEL:-com.multi-agent.autopilot}"
|
|
71
90
|
MA_AP_PLIST="${MA_AUTOPILOT_PLIST:-$HOME/Library/LaunchAgents/$MA_AP_LABEL.plist}"
|
|
72
91
|
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
# [
|
|
35
35
|
# { "type": "confluence", "url": "...", "metadata": { "host": "...", "pageId": "...|null", "spaceKey": "...|null" } },
|
|
36
36
|
# { "type": "swagger", "url": "...", "metadata": { "format": "json|yaml|unknown" } },
|
|
37
|
-
# { "type": "crashlytics","url": "...", "metadata": { "projectId": "...", "platform": "ios|android", "issueId": "...", "sessionId": "...|null" } },
|
|
37
|
+
# { "type": "crashlytics","url": "...", "metadata": { "projectId": "...", "platform": "ios|android", "bundle": "...", "issueId": "...", "sessionId": "...|null" } },
|
|
38
38
|
# { "type": "fortify", "url": "...|null", "metadata": { "host": "...|null", "versionId": "...|null", "instanceId": "...|null", "source": "url|label" } },
|
|
39
39
|
# { "type": "document", "url": "...|null", "metadata": { "path": "...", "format": "docx|pdf|md|txt", "source": "path|url" } },
|
|
40
40
|
# { "type": "graylog", "url": null, "metadata": { "idType": "trx|conversation", "id": "...", "label": "..." } },
|
|
@@ -71,6 +71,13 @@ for m in URL_RE.finditer(text):
|
|
|
71
71
|
RAW_URLS.append(u)
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
def on_domain(netloc: str, *domains: str) -> bool:
|
|
75
|
+
"""True when the URL's host is one of `domains` or a subdomain of one.
|
|
76
|
+
A bare suffix test would also accept look-alikes such as evil-figma.com."""
|
|
77
|
+
host = netloc.rsplit("@", 1)[-1].split(":", 1)[0]
|
|
78
|
+
return any(host == d or host.endswith("." + d) for d in domains)
|
|
79
|
+
|
|
80
|
+
|
|
74
81
|
def classify(url: str):
|
|
75
82
|
"""Return (type, metadata) when the URL matches a known channel; else None."""
|
|
76
83
|
parsed = up.urlparse(url)
|
|
@@ -80,7 +87,7 @@ def classify(url: str):
|
|
|
80
87
|
|
|
81
88
|
# --- Figma --------------------------------------------------------------
|
|
82
89
|
# figma.com/{design|make|board|slides|file}/<fileKey>/...
|
|
83
|
-
if host
|
|
90
|
+
if on_domain(host, "figma.com"):
|
|
84
91
|
parts = [p for p in path.split("/") if p]
|
|
85
92
|
kind = parts[0] if parts else "design"
|
|
86
93
|
# Normalise legacy /file/ to /design/
|
|
@@ -185,7 +192,7 @@ def classify(url: str):
|
|
|
185
192
|
# advisory context - extractor flags them so the orchestrator can decide
|
|
186
193
|
# whether to fetch (Block B work).
|
|
187
194
|
if (
|
|
188
|
-
host
|
|
195
|
+
on_domain(host, "notion.so", "notion.site")
|
|
189
196
|
or host == "docs.google.com"
|
|
190
197
|
or host == "drive.google.com"
|
|
191
198
|
or host == "gist.github.com"
|
|
@@ -221,14 +228,14 @@ for url in RAW_URLS:
|
|
|
221
228
|
# alternation so "trxid" is not shadowed by "trx". The id is alphanumeric plus
|
|
222
229
|
# ._- and long enough (>= 6 chars) to avoid catching stray words.
|
|
223
230
|
GRAYLOG_RE = re.compile(
|
|
224
|
-
r"(?P<label>"
|
|
231
|
+
r"\b(?P<label>"
|
|
225
232
|
r"x[\s_-]*conversation[\s_-]*id"
|
|
226
233
|
r"|conversation[\s_-]*id"
|
|
227
234
|
r"|conv[\s_-]*id"
|
|
228
235
|
r"|transaction[\s_-]*id"
|
|
229
236
|
r"|trx[\s_-]*id"
|
|
230
237
|
r"|trx"
|
|
231
|
-
r")"
|
|
238
|
+
r")(?![A-Za-z0-9])"
|
|
232
239
|
r"\s*[:=#]?\s*"
|
|
233
240
|
r"[\"']?(?P<id>[A-Za-z0-9][A-Za-z0-9._-]{5,})",
|
|
234
241
|
re.IGNORECASE,
|
|
@@ -53,6 +53,10 @@ set -uo pipefail
|
|
|
53
53
|
|
|
54
54
|
PREFS="${MULTI_AGENT_PREFS:-$HOME/.claude/multi-agent-preferences.json}"
|
|
55
55
|
|
|
56
|
+
_MA_CI_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
57
|
+
# shellcheck source=/dev/null
|
|
58
|
+
if [ -f "$_MA_CI_HERE/user-facing.sh" ]; then . "$_MA_CI_HERE/user-facing.sh"; else . "$HOME/.claude/lib/user-facing.sh"; fi
|
|
59
|
+
|
|
56
60
|
STORE=""
|
|
57
61
|
for c in "$HOME/.claude/lib/credential-store.sh" "$HOME/.copilot/lib/credential-store.sh" \
|
|
58
62
|
"$HOME/.codex/lib/credential-store.sh" "$(dirname "$0")/credential-store.sh"; do
|
|
@@ -354,7 +358,7 @@ capability_of() {
|
|
|
354
358
|
fortify) echo "pull a static-analysis finding and its remediation guidance" ;;
|
|
355
359
|
graylog) echo "pull request logs by transaction or conversation id (advisory)" ;;
|
|
356
360
|
graylog_test) echo "pull the same logs from the test environment (falls back to the graylog token when unset)" ;;
|
|
357
|
-
usage_ingest) echo "report pipeline usage counters and send
|
|
361
|
+
usage_ingest) echo "report pipeline usage counters and send $(ma_command feedback)" ;;
|
|
358
362
|
figma|figma_mcp) echo "fetch design context, screenshots and Code Connect mappings" ;;
|
|
359
363
|
jenkins) echo "read build results" ;;
|
|
360
364
|
npm) echo "publish to the npm registry" ;;
|
|
@@ -408,7 +412,7 @@ if [ -n "$QUERY" ]; then
|
|
|
408
412
|
fi
|
|
409
413
|
exit 0 ;;
|
|
410
414
|
2) echo "$QUERY: no credential helper on this host - run the pipeline installer (credential-store.sh missing)" >&2; exit 2 ;;
|
|
411
|
-
*) echo "$QUERY: NOT AVAILABLE - onboard it via
|
|
415
|
+
*) echo "$QUERY: NOT AVAILABLE - onboard it via $(ma_command setup) before relying on it" >&2; exit 1 ;;
|
|
412
416
|
esac
|
|
413
417
|
fi
|
|
414
418
|
|
|
@@ -417,7 +421,7 @@ fi
|
|
|
417
421
|
# tokens that are sitting in the store.
|
|
418
422
|
if [ -z "$STORE" ]; then
|
|
419
423
|
if [ "$MODE" = "json" ]; then
|
|
420
|
-
echo '{"status":"no-backend","reason":"credential-store.sh not found on this host","credentials":[]}'
|
|
424
|
+
echo '{"status":"no-backend","probed":false,"reason":"credential-store.sh not found on this host","credentials":[]}'
|
|
421
425
|
else
|
|
422
426
|
echo "no credential helper on this host - run the pipeline installer (credential-store.sh missing)" >&2
|
|
423
427
|
fi
|
|
@@ -443,10 +447,13 @@ while IFS=$'\t' read -r key mapped; do
|
|
|
443
447
|
done < <(mapping_keys)
|
|
444
448
|
|
|
445
449
|
if [ -z "$ROWS" ]; then
|
|
450
|
+
# status, probed and credentials are in every --json envelope, the short ones
|
|
451
|
+
# included: a decoder that requires them (pipeline/contract/frozen/toolbox.json)
|
|
452
|
+
# would otherwise fail on exactly the machine that has nothing mapped yet.
|
|
446
453
|
if [ "$MODE" = "json" ]; then
|
|
447
|
-
echo '{"status":"empty","reason":"no keychainMapping in preferences","credentials":[]}'
|
|
454
|
+
echo '{"status":"empty","probed":false,"reason":"no keychainMapping in preferences","credentials":[]}'
|
|
448
455
|
else
|
|
449
|
-
echo "no keychainMapping found in $PREFS - run
|
|
456
|
+
echo "no keychainMapping found in $PREFS - run $(ma_command setup)" >&2
|
|
450
457
|
fi
|
|
451
458
|
exit 0
|
|
452
459
|
fi
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
#
|
|
3
3
|
# credential-store.sh
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
4
|
+
# Secret storage wrapper over the macOS Keychain. Every script reads and writes
|
|
5
|
+
# tokens through here rather than calling `security` itself, so key mapping,
|
|
6
|
+
# argv hygiene and the audit trail live in one place.
|
|
7
7
|
#
|
|
8
8
|
# Subcommands:
|
|
9
9
|
# get <key> Read secret value to stdout (empty + exit 1 if missing)
|
|
@@ -12,40 +12,51 @@
|
|
|
12
12
|
# keeps the secret off this script's argv (visible to
|
|
13
13
|
# ps). A literal "-" value cannot be stored this way.
|
|
14
14
|
# delete <key> Remove secret
|
|
15
|
+
# probe <key> Is the secret readable right now, without a prompt?
|
|
16
|
+
# Prints one word - readable | missing | locked - and
|
|
17
|
+
# never the value: the backend's stdout goes to
|
|
18
|
+
# /dev/null and only its exit status and error text
|
|
19
|
+
# are read. Exit 0 readable, 1 missing, 5 locked.
|
|
15
20
|
# list List all keys (one per line)
|
|
16
|
-
# platform Print detected platform: macos |
|
|
21
|
+
# platform Print detected platform: macos | unknown
|
|
17
22
|
# doctor Check backend availability, print remediation if missing
|
|
18
23
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# Windows -> Credential Manager via PowerShell `CredentialManager` module
|
|
22
|
-
# (Install-Module CredentialManager -Scope CurrentUser)
|
|
23
|
-
# Linux -> libsecret via `secret-tool`
|
|
24
|
+
# Backend: the macOS Keychain via `security`. The pipeline is macOS only
|
|
25
|
+
# (ADR-0012); on any other host every subcommand except `platform` exits 2.
|
|
24
26
|
#
|
|
25
|
-
# Returns 0 on success, 1 on missing/empty value, 2 on backend missing
|
|
26
|
-
# 3 on usage error.
|
|
27
|
+
# Returns 0 on success, 1 on missing/empty value, 2 on backend missing or a
|
|
28
|
+
# non-macOS host, 3 on usage error, 5 when `probe` finds the store locked.
|
|
27
29
|
|
|
28
30
|
set -euo pipefail
|
|
29
31
|
|
|
30
32
|
detect_platform() {
|
|
31
33
|
case "$(uname -s 2>/dev/null)" in
|
|
32
34
|
Darwin) echo "macos" ;;
|
|
33
|
-
|
|
34
|
-
MINGW*|MSYS*|CYGWIN*) echo "windows" ;;
|
|
35
|
-
*) [ -n "${WINDIR:-}${OS:-}" ] && echo "windows" || echo "unknown" ;;
|
|
35
|
+
*) echo "unknown" ;;
|
|
36
36
|
esac
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
PLATFORM
|
|
39
|
+
PLATFORM="${CREDENTIAL_STORE_PLATFORM:-$(detect_platform)}"
|
|
40
40
|
CMD="${1:-}"
|
|
41
41
|
shift || true
|
|
42
42
|
|
|
43
|
+
if [ "$PLATFORM" != "macos" ] && [ "$CMD" != "platform" ]; then
|
|
44
|
+
echo "ERR: macOS only, see ADR-0012 (detected: $PLATFORM)" >&2
|
|
45
|
+
exit 2
|
|
46
|
+
fi
|
|
47
|
+
|
|
43
48
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
|
49
|
+
|
|
50
|
+
# CREDENTIAL_STORE_KEYCHAIN scopes every backend call to one keychain file
|
|
51
|
+
# instead of the user's search list. Tests point it at a throwaway keychain so
|
|
52
|
+
# they never write to the login keychain. keychain.py reads the same variable.
|
|
53
|
+
KEYCHAIN_FILE=()
|
|
54
|
+
if [ -n "${CREDENTIAL_STORE_KEYCHAIN:-}" ]; then KEYCHAIN_FILE=("$CREDENTIAL_STORE_KEYCHAIN"); fi
|
|
44
55
|
KEYCHAIN_PY="$SCRIPT_DIR/../scripts/keychain.py"
|
|
45
56
|
|
|
46
57
|
# --- Python delegate --------------------------------------------------------
|
|
47
|
-
#
|
|
48
|
-
# - It writes BOTH -l (label) and -s (service) attributes
|
|
58
|
+
# Prefer the Python helper for deterministic behaviour:
|
|
59
|
+
# - It writes BOTH -l (label) and -s (service) attributes, so items
|
|
49
60
|
# are findable by either convention (personal tokens use -l, this script
|
|
50
61
|
# historically used -s).
|
|
51
62
|
# - It returns clean exit codes (0 ok / 1 missing / 2 backend / 4 error).
|
|
@@ -54,39 +65,12 @@ delegate_to_python() {
|
|
|
54
65
|
[ "${KEYCHAIN_DELEGATE:-1}" != "0" ] || return 1
|
|
55
66
|
command -v python3 >/dev/null 2>&1 || return 1
|
|
56
67
|
[ -f "$KEYCHAIN_PY" ] || return 1
|
|
57
|
-
|
|
58
|
-
macos|linux) return 0 ;;
|
|
59
|
-
*) return 1 ;;
|
|
60
|
-
esac
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
# --- Helpers ----------------------------------------------------------------
|
|
64
|
-
ps_run() {
|
|
65
|
-
# Execute a PowerShell command, suppressing profile load. Reads stdin if any.
|
|
66
|
-
# Windows PowerShell (powershell.exe) is preferred over pwsh: the
|
|
67
|
-
# CredentialManager binary module is built for .NET Framework and users
|
|
68
|
-
# install it via `Install-Module CredentialManager` in Windows PowerShell,
|
|
69
|
-
# so its module path is only guaranteed visible there.
|
|
70
|
-
if command -v powershell.exe >/dev/null 2>&1; then
|
|
71
|
-
powershell.exe -NoProfile -NonInteractive -Command "$1"
|
|
72
|
-
elif command -v pwsh >/dev/null 2>&1; then
|
|
73
|
-
pwsh -NoProfile -NonInteractive -Command "$1"
|
|
74
|
-
else
|
|
75
|
-
return 127
|
|
76
|
-
fi
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
require_cmd() {
|
|
80
|
-
local cmd="$1" hint="$2"
|
|
81
|
-
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
82
|
-
echo "ERR: $cmd not found. $hint" >&2
|
|
83
|
-
exit 2
|
|
84
|
-
fi
|
|
68
|
+
[ "$PLATFORM" = "macos" ]
|
|
85
69
|
}
|
|
86
70
|
|
|
87
71
|
# --- Logical key -> backend key --------------------------------------------
|
|
88
72
|
# Callers pass a LOGICAL key ("github", "jira", "figma_pat"). The actual
|
|
89
|
-
# Keychain
|
|
73
|
+
# Keychain entry is named by
|
|
90
74
|
# prefs.global.keychainMapping, so a lookup that uses the logical key verbatim
|
|
91
75
|
# finds nothing whenever the two differ - silently, because a missing entry and
|
|
92
76
|
# a missing mapping look identical from here. Resolve the mapping first and fall
|
|
@@ -94,13 +78,12 @@ require_cmd() {
|
|
|
94
78
|
# entries whose name already equals the logical key).
|
|
95
79
|
PREFS_FILE="${MULTI_AGENT_PREFS:-$HOME/.claude/multi-agent-preferences.json}"
|
|
96
80
|
|
|
97
|
-
# Reader order is python3 then node, and both are here on purpose. python3 is
|
|
98
|
-
# on
|
|
99
|
-
# installed at all, because the installer IS a
|
|
100
|
-
#
|
|
101
|
-
#
|
|
102
|
-
#
|
|
103
|
-
# mapped name. A missing interpreter must not look like a missing token.
|
|
81
|
+
# Reader order is python3 then node, and both are here on purpose. python3 is not
|
|
82
|
+
# guaranteed on a mac (it arrives with the Command Line Tools or Homebrew); node is
|
|
83
|
+
# guaranteed wherever this pipeline is installed at all, because the installer IS a
|
|
84
|
+
# node program. With a python3-only reader a host without python3 would skip the
|
|
85
|
+
# mapping in silence, look up the LOGICAL key, and report a token as missing while it
|
|
86
|
+
# sits under its mapped name. A missing interpreter must not look like a missing token.
|
|
104
87
|
resolve_key() {
|
|
105
88
|
local logical="$1" mapped=""
|
|
106
89
|
if [ -f "$PREFS_FILE" ]; then
|
|
@@ -171,26 +154,17 @@ do_get() {
|
|
|
171
154
|
return 1
|
|
172
155
|
fi
|
|
173
156
|
local val=""
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
val=$(ps_run "
|
|
186
|
-
\$ErrorActionPreference='SilentlyContinue'
|
|
187
|
-
\$c = Get-StoredCredential -Target '$key_esc'
|
|
188
|
-
if (\$c) { \$c.GetNetworkCredential().Password }
|
|
189
|
-
" 2>/dev/null | tr -d '\r' || true)
|
|
190
|
-
;;
|
|
191
|
-
*)
|
|
192
|
-
echo "ERR: unsupported platform" >&2; exit 2 ;;
|
|
193
|
-
esac
|
|
157
|
+
# `-w` prints a value it considers non-printable (a newline included) as
|
|
158
|
+
# bare hex with no marker. `-g` prints `password: 0x<HEX>` in that case,
|
|
159
|
+
# and the marker is what makes the decoding unambiguous.
|
|
160
|
+
local attrs hex
|
|
161
|
+
attrs=$(security find-generic-password -s "$key" -g ${KEYCHAIN_FILE[@]+"${KEYCHAIN_FILE[@]}"} 2>&1 >/dev/null || true)
|
|
162
|
+
hex=$(printf '%s\n' "$attrs" | sed -n 's/^password: 0x\([0-9A-Fa-f]*\).*/\1/p' | head -n 1)
|
|
163
|
+
if [ -n "$hex" ]; then
|
|
164
|
+
val=$(printf '%s' "$hex" | xxd -r -p; printf x); val=${val%x}
|
|
165
|
+
else
|
|
166
|
+
val=$(security find-generic-password -s "$key" -w ${KEYCHAIN_FILE[@]+"${KEYCHAIN_FILE[@]}"} 2>/dev/null || true)
|
|
167
|
+
fi
|
|
194
168
|
if [ -z "$val" ]; then
|
|
195
169
|
audit_lookup "$logical" false
|
|
196
170
|
return 1
|
|
@@ -208,44 +182,26 @@ do_set() {
|
|
|
208
182
|
if [ "$val" = "-" ]; then
|
|
209
183
|
val=$(cat)
|
|
210
184
|
fi
|
|
211
|
-
#
|
|
212
|
-
#
|
|
213
|
-
#
|
|
214
|
-
if
|
|
185
|
+
# The delegate receives the secret on stdin and hands it to `security -i` on
|
|
186
|
+
# stdin as well, so no argv ever carries it, and it writes both the -l and -s
|
|
187
|
+
# attributes that lookups by either convention expect.
|
|
188
|
+
if delegate_to_python; then
|
|
215
189
|
printf '%s' "$val" | python3 "$KEYCHAIN_PY" set "$key" -
|
|
216
190
|
return $?
|
|
217
191
|
fi
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
require_cmd secret-tool "Install libsecret-tools (see doctor)."
|
|
232
|
-
printf '%s' "$val" | secret-tool store --label="$key" service "$key" >/dev/null
|
|
233
|
-
;;
|
|
234
|
-
windows)
|
|
235
|
-
# Escape single quotes for PowerShell single-quoted strings ('' = literal ').
|
|
236
|
-
local key_esc="${key//\'/\'\'}"
|
|
237
|
-
# The secret is piped via stdin ([Console]::In) so it never appears on
|
|
238
|
-
# the PowerShell argv (visible to process listings).
|
|
239
|
-
printf '%s' "$val" | ps_run "
|
|
240
|
-
\$ErrorActionPreference='Stop'
|
|
241
|
-
\$raw = [Console]::In.ReadToEnd()
|
|
242
|
-
\$pwd = ConvertTo-SecureString \$raw -AsPlainText -Force
|
|
243
|
-
New-StoredCredential -Target '$key_esc' -UserName '${USER:-${USERNAME:-claude}}' -SecurePassword \$pwd -Persist LocalMachine | Out-Null
|
|
244
|
-
" >/dev/null
|
|
245
|
-
;;
|
|
246
|
-
*)
|
|
247
|
-
echo "ERR: unsupported platform" >&2; exit 2 ;;
|
|
248
|
-
esac
|
|
192
|
+
# `security -i` reads the add command from stdin, so the secret never
|
|
193
|
+
# lands on the `security` argv (visible to ps). printf is a bash
|
|
194
|
+
# builtin, so no argv exposure there either. The value goes in as
|
|
195
|
+
# `-X <hex>`: the interactive tokenizer reads one command per line, so a
|
|
196
|
+
# newline inside a quoted `-w` value would end the command early.
|
|
197
|
+
local key_sec val_hex target=""
|
|
198
|
+
key_sec=${key//\\/\\\\}; key_sec=${key_sec//\"/\\\"}
|
|
199
|
+
val_hex=$(printf '%s' "$val" | od -An -v -tx1 | tr -d ' \n')
|
|
200
|
+
if [ -n "${CREDENTIAL_STORE_KEYCHAIN:-}" ]; then
|
|
201
|
+
target=${CREDENTIAL_STORE_KEYCHAIN//\\/\\\\}; target=" \"${target//\"/\\\"}\""
|
|
202
|
+
fi
|
|
203
|
+
printf 'add-generic-password -U -a "%s" -l "%s" -s "%s" -X %s%s\n' \
|
|
204
|
+
"${USER:-claude}" "$key_sec" "$key_sec" "$val_hex" "$target" | security -i >/dev/null 2>&1
|
|
249
205
|
}
|
|
250
206
|
|
|
251
207
|
do_delete() {
|
|
@@ -256,97 +212,72 @@ do_delete() {
|
|
|
256
212
|
python3 "$KEYCHAIN_PY" delete "$key" >/dev/null 2>&1 || true
|
|
257
213
|
return 0
|
|
258
214
|
fi
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
215
|
+
security delete-generic-password -s "$key" ${KEYCHAIN_FILE[@]+"${KEYCHAIN_FILE[@]}"} >/dev/null 2>&1 || true
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
# Readable without a prompt, answered without the value ever leaving the backend.
|
|
219
|
+
#
|
|
220
|
+
# The data is really read - an attribute-only lookup would say "present" for an
|
|
221
|
+
# item whose access control still asks before handing the value over, which is
|
|
222
|
+
# exactly the item a background tick cannot use. `-w` prints the value on
|
|
223
|
+
# stdout, and stdout goes to /dev/null; stderr carries only the backend's error
|
|
224
|
+
# text, and that is what separates a locked keychain (errSecInteractionNotAllowed,
|
|
225
|
+
# exit 36) from a missing item (errSecItemNotFound, exit 44). Both conventions are
|
|
226
|
+
# tried, label then service, as keychain.py reads them.
|
|
227
|
+
do_probe() {
|
|
228
|
+
local key="${1:-}"
|
|
229
|
+
[ -z "$key" ] && { echo "usage: $0 probe <key>" >&2; exit 3; }
|
|
230
|
+
key=$(resolve_key "$key")
|
|
231
|
+
local locked=0 rc err
|
|
232
|
+
local sec="${CREDENTIAL_STORE_SECURITY_BIN:-security}" attr
|
|
233
|
+
for attr in -l -s; do
|
|
234
|
+
rc=0
|
|
235
|
+
err=$("$sec" find-generic-password "$attr" "$key" -w ${KEYCHAIN_FILE[@]+"${KEYCHAIN_FILE[@]}"} 2>&1 >/dev/null) || rc=$?
|
|
236
|
+
if [ "$rc" -eq 0 ]; then echo "readable"; return 0; fi
|
|
237
|
+
case "$rc:$err" in
|
|
238
|
+
36:* | *"nteraction is not allowed"*) locked=1 ;;
|
|
239
|
+
esac
|
|
240
|
+
done
|
|
241
|
+
if [ "$locked" -eq 1 ]; then echo "locked"; return 5; fi
|
|
242
|
+
echo "missing"
|
|
243
|
+
return 1
|
|
264
244
|
}
|
|
265
245
|
|
|
266
246
|
do_list() {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
| awk -F'"' '/"svce"<blob>=/ && NF >= 5 { v = $4; sub(/\\000$/, "", v); if (v != "") print v }' \
|
|
286
|
-
| sort -u
|
|
287
|
-
;;
|
|
288
|
-
linux)
|
|
289
|
-
secret-tool search --all 2>/dev/null \
|
|
290
|
-
| awk -F'= ' '/^attribute\.service/{print $2}' \
|
|
291
|
-
| sort -u
|
|
292
|
-
;;
|
|
293
|
-
windows)
|
|
294
|
-
ps_run "Get-StoredCredential | ForEach-Object { \$_.TargetName }" 2>/dev/null | tr -d '\r'
|
|
295
|
-
;;
|
|
296
|
-
esac
|
|
247
|
+
# Read `svce` - the SERVICE attribute, which is what `set` writes with -s and
|
|
248
|
+
# `get` looks up with -s. This used to read `0x00000007`, which is the LABEL:
|
|
249
|
+
# it happens to match for items written by keychain.py (which stamps both -l and
|
|
250
|
+
# -s), but it is the wrong key in principle and diverges on any item whose label
|
|
251
|
+
# was set independently, listing a name `get` cannot resolve.
|
|
252
|
+
#
|
|
253
|
+
# `dump-keychain` prints the first few attributes under numeric tags and the rest
|
|
254
|
+
# under named ones, and `svce` is in the named group - so the tag to match is
|
|
255
|
+
# `"svce"`, not `0x00000008`.
|
|
256
|
+
#
|
|
257
|
+
# Without `-d` this reads attributes only and does not prompt for access; only
|
|
258
|
+
# the data-dumping form does.
|
|
259
|
+
#
|
|
260
|
+
# A trailing `\000` appears when security prints the value in its hex+C-string
|
|
261
|
+
# form; it is not part of the service name.
|
|
262
|
+
security dump-keychain ${KEYCHAIN_FILE[@]+"${KEYCHAIN_FILE[@]}"} 2>/dev/null \
|
|
263
|
+
| awk -F'"' '/"svce"<blob>=/ && NF >= 5 { v = $4; sub(/\\000$/, "", v); if (v != "") print v }' \
|
|
264
|
+
| sort -u
|
|
297
265
|
}
|
|
298
266
|
|
|
299
267
|
do_doctor() {
|
|
300
268
|
echo "Platform: $PLATFORM"
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
&& echo "Backend: security ✓ (built-in)" \
|
|
305
|
-
|| echo "Backend: security ✗ MISSING (impossible on macOS)"
|
|
306
|
-
;;
|
|
307
|
-
linux)
|
|
308
|
-
if command -v secret-tool >/dev/null 2>&1; then
|
|
309
|
-
echo "Backend: secret-tool ✓"
|
|
310
|
-
else
|
|
311
|
-
echo "Backend: secret-tool ✗ MISSING"
|
|
312
|
-
echo "Install: sudo apt install libsecret-tools # Debian/Ubuntu"
|
|
313
|
-
echo " sudo dnf install libsecret # Fedora/RHEL"
|
|
314
|
-
fi
|
|
315
|
-
;;
|
|
316
|
-
windows)
|
|
317
|
-
if command -v pwsh >/dev/null 2>&1 || command -v powershell.exe >/dev/null 2>&1; then
|
|
318
|
-
echo "Backend: PowerShell ✓"
|
|
319
|
-
local has_mod
|
|
320
|
-
has_mod=$(ps_run "if (Get-Module -ListAvailable -Name CredentialManager) {'yes'} else {'no'}" 2>/dev/null | tr -d '\r' || echo "no")
|
|
321
|
-
if [ "$has_mod" = "yes" ]; then
|
|
322
|
-
echo "Module: CredentialManager ✓"
|
|
323
|
-
else
|
|
324
|
-
echo "Module: CredentialManager ✗ MISSING"
|
|
325
|
-
echo "Install: Install-Module CredentialManager -Scope CurrentUser -Force"
|
|
326
|
-
fi
|
|
327
|
-
else
|
|
328
|
-
echo "Backend: PowerShell ✗ MISSING"
|
|
329
|
-
fi
|
|
330
|
-
;;
|
|
331
|
-
*)
|
|
332
|
-
# This used to advertise an env-var fallback. There isn't one here: `get` on an
|
|
333
|
-
# unrecognised platform exits 2. Individual callers have their own env escape
|
|
334
|
-
# hatches (figma-token.sh honours $FIGMA_PAT, for instance), but this helper
|
|
335
|
-
# does not, and claiming otherwise sent people looking for a mechanism that
|
|
336
|
-
# does not exist.
|
|
337
|
-
echo "Backend: none - unrecognised platform, \`get\` exits 2"
|
|
338
|
-
echo "Workaround: set the credential in the caller's own env var where one"
|
|
339
|
-
echo " exists (e.g. FIGMA_PAT), or run on macOS / Linux / Windows"
|
|
340
|
-
;;
|
|
341
|
-
esac
|
|
269
|
+
command -v security >/dev/null 2>&1 \
|
|
270
|
+
&& echo "Backend: security ✓ (built-in)" \
|
|
271
|
+
|| echo "Backend: security ✗ MISSING (impossible on macOS)"
|
|
342
272
|
}
|
|
343
273
|
|
|
344
274
|
case "$CMD" in
|
|
345
275
|
get) do_get "$@" ;;
|
|
346
276
|
set) do_set "$@" ;;
|
|
347
277
|
delete) do_delete "$@" ;;
|
|
278
|
+
probe) do_probe "$@" ;;
|
|
348
279
|
list) do_list ;;
|
|
349
280
|
platform) echo "$PLATFORM" ;;
|
|
350
281
|
doctor) do_doctor ;;
|
|
351
|
-
*) echo "usage: $0 {get|set|delete|list|platform|doctor} [args]" >&2; exit 3 ;;
|
|
282
|
+
*) echo "usage: $0 {get|set|delete|probe|list|platform|doctor} [args]" >&2; exit 3 ;;
|
|
352
283
|
esac
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
# CONFLUENCE_AUTH_TOKEN_KEY default prefs.global.keychainMapping.confluence
|
|
17
17
|
# fallback "${USER}_Confluence_Access_Token"
|
|
18
18
|
# CONFLUENCE_HOST_OVERRIDE forces the host (overrides URL host extraction)
|
|
19
|
+
# and is the one host trusted without a match
|
|
20
|
+
# against prefs.global.hosts.confluence
|
|
19
21
|
#
|
|
20
22
|
# Output (stdout, single JSON object):
|
|
21
23
|
# {
|
|
@@ -34,6 +36,10 @@
|
|
|
34
36
|
# 2 missing token or auth failure (after Save Flow trigger)
|
|
35
37
|
# 3 network / HTTP error
|
|
36
38
|
# 4 bad usage
|
|
39
|
+
# 6 host refused: the page is not on prefs.global.hosts.confluence
|
|
40
|
+
# (host-not-allowed), or no Confluence host is configured and the page is
|
|
41
|
+
# not on Atlassian Cloud (host-not-configured). Checked before the token
|
|
42
|
+
# is read, so the token never travels to a host the user did not name.
|
|
37
43
|
#
|
|
38
44
|
# Notes on auth:
|
|
39
45
|
# The script reads the Confluence token via credential-store.sh. If the
|
|
@@ -44,7 +50,8 @@
|
|
|
44
50
|
set -euo pipefail
|
|
45
51
|
|
|
46
52
|
URL=""
|
|
47
|
-
|
|
53
|
+
ENV_HOST_OVERRIDE="${CONFLUENCE_HOST_OVERRIDE:-}"
|
|
54
|
+
HOST_OVERRIDE="$ENV_HOST_OVERRIDE"
|
|
48
55
|
PAGE_ID=""
|
|
49
56
|
TIMEOUT="${CONFLUENCE_TIMEOUT_SECONDS:-20}"
|
|
50
57
|
|
|
@@ -87,7 +94,7 @@ space_key = ""
|
|
|
87
94
|
|
|
88
95
|
if url:
|
|
89
96
|
p = up.urlparse(url)
|
|
90
|
-
host = host_override or p.netloc
|
|
97
|
+
host = host_override or p.netloc.rsplit("@", 1)[-1]
|
|
91
98
|
query = up.parse_qs(p.query)
|
|
92
99
|
if not page_id:
|
|
93
100
|
page_id = (query.get("pageId") or [""])[0]
|
|
@@ -113,8 +120,42 @@ if [ -z "$HOST" ]; then
|
|
|
113
120
|
exit 4
|
|
114
121
|
fi
|
|
115
122
|
|
|
116
|
-
#
|
|
123
|
+
# HOST is the exact string curl receives in https://$HOST/..., so it has to be a
|
|
124
|
+
# bare host[:port]. A '/', '#', '?', '@' or '\' would let a value end with the
|
|
125
|
+
# allowed suffix while curl reads the part before it as the host.
|
|
126
|
+
if ! [[ "$HOST" =~ ^[A-Za-z0-9.-]+(:[0-9]{1,5})?$ ]] || { [[ "$HOST" == *:* ]] && [ "${HOST##*:}" -gt 65535 ]; }; then
|
|
127
|
+
printf '%s\n' '{"status":"blocked","reason":"host-malformed","service":"confluence","expected_pref":"global.hosts.confluence"}' >&2
|
|
128
|
+
exit 6
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# The link usually comes from ticket text, so its host is attacker-choosable.
|
|
132
|
+
# The token goes only to the configured host (or a subdomain of it); without a
|
|
133
|
+
# configured host, only to Atlassian Cloud, where the host is the tenant.
|
|
117
134
|
PREFS="$HOME/.claude/multi-agent-preferences.json"
|
|
135
|
+
if [ -z "$ENV_HOST_OVERRIDE" ]; then
|
|
136
|
+
HOST_VERDICT=$(python3 - "$HOST" "$PREFS" <<'PY'
|
|
137
|
+
import json, sys
|
|
138
|
+
host = sys.argv[1].lower().split(":", 1)[0].rstrip(".")
|
|
139
|
+
try:
|
|
140
|
+
with open(sys.argv[2]) as f:
|
|
141
|
+
allowed = (json.load(f).get("global", {}).get("hosts", {}).get("confluence") or "")
|
|
142
|
+
except Exception:
|
|
143
|
+
allowed = ""
|
|
144
|
+
allowed = allowed.lower().strip().rstrip("/").split("://")[-1].split("/")[0].split(":")[0]
|
|
145
|
+
if allowed:
|
|
146
|
+
ok = host == allowed or host.endswith("." + allowed)
|
|
147
|
+
print("ok" if ok else "host-not-allowed")
|
|
148
|
+
else:
|
|
149
|
+
print("ok" if host.endswith(".atlassian.net") else "host-not-configured")
|
|
150
|
+
PY
|
|
151
|
+
)
|
|
152
|
+
if [ "$HOST_VERDICT" != "ok" ]; then
|
|
153
|
+
printf '%s\n' '{"status":"blocked","reason":"'"$HOST_VERDICT"'","service":"confluence","expected_pref":"global.hosts.confluence"}' >&2
|
|
154
|
+
exit 6
|
|
155
|
+
fi
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# Resolve token via keychainMapping with sane fallback.
|
|
118
159
|
TOKEN_KEY="${CONFLUENCE_AUTH_TOKEN_KEY:-}"
|
|
119
160
|
if [ -z "$TOKEN_KEY" ] && [ -f "$PREFS" ]; then
|
|
120
161
|
TOKEN_KEY=$(python3 -c "
|
|
@@ -39,10 +39,9 @@
|
|
|
39
39
|
#
|
|
40
40
|
# .docx needs no external tool: the file is a zip and `word/document.xml` is
|
|
41
41
|
# read with the python3 standard library, which the lib layer already depends
|
|
42
|
-
# on. Requiring pandoc or libreoffice would be the wrong dependency for a
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
# an error - on Windows that absence is the normal case.
|
|
42
|
+
# on. Requiring pandoc or libreoffice would be the wrong dependency for a small
|
|
43
|
+
# reader. PDF has no stdlib path, so `pdftotext` is used when present and its
|
|
44
|
+
# absence is a soft skip rather than an error.
|
|
46
45
|
|
|
47
46
|
set -uo pipefail
|
|
48
47
|
|