@mmerterden/multi-agent-pipeline 20.2.0 → 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 +923 -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 -31
- 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 +82 -7
- 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 -63
- 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
package/docs/server-readiness.md
CHANGED
|
@@ -40,27 +40,32 @@ npx @mmerterden/multi-agent-pipeline install --unattended --dry-run # see it f
|
|
|
40
40
|
npx @mmerterden/multi-agent-pipeline install --unattended # write it
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
It prints the whole profile with a reason per line before writing anything,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
43
|
+
It prints the whole profile with a reason per line before writing anything,
|
|
44
|
+
and writes it to `~/.claude/multi-agent-unattended.settings.json`, which the
|
|
45
|
+
autopilot runner passes to each run with `claude --settings`.
|
|
46
|
+
`~/.claude/settings.json`, the posture of every attended session, is not changed.
|
|
47
|
+
The profile (`pipeline/schemas/unattended-profile.json`) is
|
|
48
|
+
`permissions.defaultMode: "dontAsk"`, a narrow allow list (`Bash(git *)`,
|
|
49
|
+
`Bash(xcodebuild *)`, `Bash(xcrun simctl *)`, `Edit`, `Write` and the rest,
|
|
50
|
+
each with its reason), deny
|
|
51
|
+
rules for merging, pushing and reading `~/.ssh`, `~/.aws`, `~/.gnupg` and
|
|
52
|
+
`~/Library/Keychains`, and the toolkit's strict URL policy. `--unattended-sandbox`
|
|
53
|
+
adds an OS sandbox block (`sandbox.enabled`, `failIfUnavailable`,
|
|
54
|
+
`allowUnsandboxedCommands: false`, a network allowlist, `denyRead` for `~/.ssh`
|
|
55
|
+
and `~/.aws`).
|
|
56
|
+
|
|
57
|
+
It is additive over the profile file: an entry already there survives, a
|
|
58
|
+
narrower `Bash(...)` rule is kept alongside without standing in for the
|
|
59
|
+
profile's own entry, and a second run changes nothing. Permission lists merge
|
|
60
|
+
across settings files, so a whole-`Bash` allow in `settings.json` still reaches
|
|
61
|
+
an unattended run; the installer reports it and doctor warns, and neither
|
|
62
|
+
removes it. If an earlier install wrote the profile into `settings.json`, the
|
|
63
|
+
installer prints the move and removes exactly those entries from it. A profile
|
|
64
|
+
file that does not parse is refused rather than overwritten.
|
|
65
|
+
|
|
66
|
+
The permission list is the second line. The guard hook under
|
|
67
|
+
`MULTI_AGENT_UNATTENDED=1` and a separate macOS user are the first and the
|
|
68
|
+
boundary: `pipeline/multi-agent-refs/features/unattended-security.md`.
|
|
64
69
|
|
|
65
70
|
`doctor --profile=server` reports this as `unattended-permissions`, against the
|
|
66
71
|
same rule the writer applies.
|
|
@@ -142,8 +147,10 @@ empty and the ledger is a list of identical failures with no indication which
|
|
|
142
147
|
came first. After `MA_AP_BREAKER_LIMIT` consecutive attempts that produced
|
|
143
148
|
nothing (3 by default, 0 disables), the runner stops taking new work, writes the
|
|
144
149
|
reason into `queue.json` so `autopilot-status` shows it, and says what to check.
|
|
145
|
-
One successful attempt clears it. A run waiting for a person (`needs-input
|
|
146
|
-
an item arming refused (`blocked-*`)
|
|
150
|
+
One successful attempt clears it. A run waiting for a person (`needs-input`,
|
|
151
|
+
`awaiting-answer`), an item arming refused (`blocked-*`), a run the runner lost
|
|
152
|
+
across a restart (`died`) and a rate limit (which has its own backoff) are
|
|
153
|
+
deliberately not failures.
|
|
147
154
|
|
|
148
155
|
**Telemetry.** `ticks.jsonl` gets one JSON line per tick. The human log answers
|
|
149
156
|
"what happened just now"; a server is only ever asked "how has this been
|
|
@@ -183,6 +190,6 @@ single-owner machine, not on a shared one.
|
|
|
183
190
|
## What this page does NOT cover
|
|
184
191
|
|
|
185
192
|
- Turning any of it on. Every step here is the operator's to take.
|
|
186
|
-
-
|
|
193
|
+
- Any host other than macOS, and containers. Out of scope and staying there (ADR-0012).
|
|
187
194
|
- Multi-user servers. Everything above assumes one account owns the install,
|
|
188
195
|
the keychain and the queue.
|
package/index.js
CHANGED
|
@@ -92,7 +92,7 @@ if (command === "--version" || command === "-v" || command === "version") {
|
|
|
92
92
|
npx @mmerterden/multi-agent-pipeline install --index-only Ship only the skills index (dynamic skill loading)
|
|
93
93
|
npx @mmerterden/multi-agent-pipeline install --prune-external Also remove pre-v15 catalog copies that differ from the shipped catalog
|
|
94
94
|
|
|
95
|
-
Uninstall (token-preserving - Keychain
|
|
95
|
+
Uninstall (token-preserving - Keychain untouched):
|
|
96
96
|
npx @mmerterden/multi-agent-pipeline uninstall Interactive: remove from all installed targets
|
|
97
97
|
npx @mmerterden/multi-agent-pipeline uninstall --yes Skip prompt
|
|
98
98
|
npx @mmerterden/multi-agent-pipeline uninstall --dry-run Report what would be removed
|
package/install/_common.mjs
CHANGED
|
@@ -184,9 +184,7 @@ export function copyDir(src, dest, opts = {}) {
|
|
|
184
184
|
// user-owned trees (rules/) so an update adds new baseline files but preserves
|
|
185
185
|
// the user's locally-evolved copies. cpSync with force:false + errorOnExist:false
|
|
186
186
|
// silently skips existing files.
|
|
187
|
-
|
|
188
|
-
// also match on win32, where cpSync hands back backslash paths.
|
|
189
|
-
const relOf = (source) => source.slice(src.length).split("\\").join("/").replace(/^\//, "");
|
|
187
|
+
const relOf = (source) => source.slice(src.length).replace(/^\//, "");
|
|
190
188
|
// Junk is filtered on EVERY path, including the two that take no exclude
|
|
191
189
|
// list: the point is that the caller never has to remember it.
|
|
192
190
|
const filter = (source) => {
|
|
@@ -571,8 +569,8 @@ export function atomicWrite(path, content) {
|
|
|
571
569
|
}
|
|
572
570
|
|
|
573
571
|
/**
|
|
574
|
-
* Count files in a directory tree (pure fs recursion -
|
|
575
|
-
*
|
|
572
|
+
* Count files in a directory tree (pure fs recursion - avoids a subprocess
|
|
573
|
+
* per call). A plain-file path
|
|
576
574
|
* counts as 1, matching the old `find <path> -type f` behavior relied on by
|
|
577
575
|
* the DEV_ONLY_SCRIPTS exclusion accounting.
|
|
578
576
|
* @param {string} dir
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
import { readdirSync, writeFileSync } from "fs";
|
|
13
13
|
import { join } from "path";
|
|
14
|
-
import { isDryRun } from "./_common.mjs";
|
|
14
|
+
import { copyFile, isDryRun } from "./_common.mjs";
|
|
15
15
|
import { routeSkill } from "../pipeline/scripts/_stack-routing.mjs";
|
|
16
16
|
|
|
17
17
|
/** Uninstall reads this to know exactly which external skill dirs are ours to remove. */
|
|
@@ -71,3 +71,25 @@ export function writeExternalSkillsManifest(dest, names) {
|
|
|
71
71
|
/* best-effort - a missing manifest just means uninstall falls back */
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Copy every NOTICE-*.md from the external catalog into `dest`, beside the
|
|
77
|
+
* skill dirs, unchanged. Each one attributes a set of vendored skills to its
|
|
78
|
+
* upstream, so a host that receives the catalog locally carries the notices
|
|
79
|
+
* with it. All of them are copied whatever the stack filter kept: a notice
|
|
80
|
+
* costs nothing on disk and never enters a skills block. Uninstall removes
|
|
81
|
+
* them together with the manifest-listed dirs.
|
|
82
|
+
*
|
|
83
|
+
* @param {string} externalSrc - absolute path to `pipeline/skills/shared/external/`
|
|
84
|
+
* @param {string} dest - the installed skills directory
|
|
85
|
+
* @returns {number} files copied
|
|
86
|
+
*/
|
|
87
|
+
export function copyExternalNotices(externalSrc, dest) {
|
|
88
|
+
let n = 0;
|
|
89
|
+
for (const e of readdirSync(externalSrc, { withFileTypes: true })) {
|
|
90
|
+
if (!e.isFile() || !/^NOTICE-.*\.md$/.test(e.name)) continue;
|
|
91
|
+
copyFile(join(externalSrc, e.name), join(dest, e.name));
|
|
92
|
+
n++;
|
|
93
|
+
}
|
|
94
|
+
return n;
|
|
95
|
+
}
|
|
@@ -1,113 +1,359 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* _unattended-profile.mjs - the
|
|
3
|
-
*
|
|
2
|
+
* _unattended-profile.mjs - the posture a machine with nobody at the keyboard
|
|
3
|
+
* needs, written only when asked for.
|
|
4
4
|
*
|
|
5
5
|
* autopilot spawns its child with `--permission-prompts none`. That stops Claude
|
|
6
6
|
* Code from ASKING; it grants nothing. The tools the child then calls still have
|
|
7
7
|
* to be allowed somewhere, and on a fresh machine they are not - so the run
|
|
8
8
|
* stops at the first tool call, silently, with no prompt anywhere for a person
|
|
9
|
-
* to answer.
|
|
9
|
+
* to answer.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
11
|
+
* The profile is `permissions.defaultMode: "dontAsk"` (a call that would prompt
|
|
12
|
+
* is denied, not left waiting; any other mode already in the file is replaced),
|
|
13
|
+
* a narrow allow list, deny rules for what no unattended run does, the
|
|
14
|
+
* toolkit's strict URL policy and index deny list, and an OS sandbox block. The
|
|
15
|
+
* entries and their reasons live in pipeline/schemas/unattended-profile.json;
|
|
16
|
+
* lib/unattended-profile-check.mjs judges a file against it for this
|
|
17
|
+
* installer, for doctor and for the autopilot runner, which will not launch a
|
|
18
|
+
* child unless the file still holds the posture.
|
|
17
19
|
*
|
|
18
|
-
* The
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
20
|
+
* The sandbox is the boundary: Seatbelt on macOS, enforced for every Bash
|
|
21
|
+
* command and every process it starts, with writes limited to the working
|
|
22
|
+
* directory, the session temp directory and the unattended run directory, and
|
|
23
|
+
* egress limited to the listed hosts. The file tools and MCP tools are outside
|
|
24
|
+
* it; the Edit and Read deny rules cover the file tools, and agent-guard.sh
|
|
25
|
+
* under MULTI_AGENT_UNATTENDED=1 is a second layer over all of them
|
|
26
|
+
* (multi-agent-refs/features/unattended-security.md).
|
|
27
|
+
*
|
|
28
|
+
* It is written to its own file, ~/.claude/multi-agent-unattended.settings.json
|
|
29
|
+
* (pipeline/lib/unattended-settings-location.mjs), which the autopilot runner
|
|
30
|
+
* hands to each child with `claude --settings`. ~/.claude/settings.json is the
|
|
31
|
+
* attended posture and is not touched, with one exception: when it carries the
|
|
32
|
+
* profile the v20.2.1 install wrote there (install/unattended-profile-legacy.json),
|
|
33
|
+
* exactly those entries are removed from it.
|
|
34
|
+
*
|
|
35
|
+
* Opt-in, printed in full with a reason per line BEFORE anything is written.
|
|
36
|
+
* Allow and deny rules are additive; a sandbox block already in the file is
|
|
37
|
+
* corrected to the shipped one, keeping its extra deny entries and dropping
|
|
38
|
+
* whatever widens it.
|
|
23
39
|
*
|
|
24
40
|
* @module install/_unattended-profile
|
|
25
41
|
*/
|
|
26
42
|
|
|
27
43
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
28
|
-
import { join } from "node:path";
|
|
44
|
+
import { dirname, join } from "node:path";
|
|
45
|
+
import { fileURLToPath } from "node:url";
|
|
46
|
+
|
|
47
|
+
import { unattendedSettingsPath } from "../pipeline/lib/unattended-settings-location.mjs";
|
|
48
|
+
import { prefsHosts, profileGaps } from "../pipeline/lib/unattended-profile-check.mjs";
|
|
49
|
+
|
|
50
|
+
const PROFILE_PATH = join(
|
|
51
|
+
dirname(dirname(fileURLToPath(import.meta.url))),
|
|
52
|
+
"pipeline",
|
|
53
|
+
"schemas",
|
|
54
|
+
"unattended-profile.json",
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
/** The profile data, as shipped. */
|
|
58
|
+
export function loadUnattendedProfile(path = PROFILE_PATH) {
|
|
59
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const PROFILE = loadUnattendedProfile();
|
|
63
|
+
const LEGACY = JSON.parse(
|
|
64
|
+
readFileSync(
|
|
65
|
+
join(dirname(fileURLToPath(import.meta.url)), "unattended-profile-legacy.json"),
|
|
66
|
+
"utf-8",
|
|
67
|
+
),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
/** Allow rules and their reasons: [rule, why][]. */
|
|
71
|
+
export const UNATTENDED_ALLOW = PROFILE.allow;
|
|
72
|
+
/** Deny rules and their reasons: [rule, why][]. */
|
|
73
|
+
export const UNATTENDED_DENY = PROFILE.deny;
|
|
74
|
+
/** Env entries: [key, value, why][]. */
|
|
75
|
+
export const UNATTENDED_ENV = PROFILE.env;
|
|
76
|
+
|
|
77
|
+
const hasRule = (list, rule) => list.some((a) => String(a) === rule);
|
|
78
|
+
|
|
79
|
+
function readSettingsFile(path) {
|
|
80
|
+
if (!existsSync(path)) return {};
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(readFileSync(path, "utf-8")) || {};
|
|
83
|
+
} catch (err) {
|
|
84
|
+
// A settings file that does not parse is not ours to rewrite: overwriting
|
|
85
|
+
// it would lose whatever is in there.
|
|
86
|
+
throw new Error(`${path} is not valid JSON, so it will not be modified: ${err.message}`, {
|
|
87
|
+
cause: err,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The profile entries an earlier install wrote into settings.json, when it
|
|
94
|
+
* carries that install's signature: the profile's defaultMode and its whole
|
|
95
|
+
* deny set. Returns the labels to remove, [] when the signature is absent.
|
|
96
|
+
*/
|
|
97
|
+
function legacyEntries(settings) {
|
|
98
|
+
const perms = settings.permissions || {};
|
|
99
|
+
const allow = Array.isArray(perms.allow) ? perms.allow.map(String) : [];
|
|
100
|
+
const deny = Array.isArray(perms.deny) ? perms.deny.map(String) : [];
|
|
101
|
+
const signed =
|
|
102
|
+
perms.defaultMode === LEGACY.defaultMode && LEGACY.deny.every((rule) => deny.includes(rule));
|
|
103
|
+
if (!signed) return [];
|
|
104
|
+
const env = settings.env || {};
|
|
105
|
+
return [
|
|
106
|
+
`defaultMode:${LEGACY.defaultMode}`,
|
|
107
|
+
...LEGACY.allow.filter((r) => allow.includes(r)),
|
|
108
|
+
...LEGACY.deny.map((r) => `deny:${r}`),
|
|
109
|
+
...LEGACY.env.filter(([k, v]) => env[k] === v).map(([k, v]) => `env:${k}=${v}`),
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const union = (a, b) => [...new Set([...(Array.isArray(a) ? a.map(String) : []), ...b])];
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The sandbox block to write: the shipped one, with the extra deny entries
|
|
117
|
+
* and other keys of a block already in the file kept, and everything that
|
|
118
|
+
* would widen it (an excluded command, an extra write path or domain, a
|
|
119
|
+
* re-opened read, a lifted protection) dropped.
|
|
120
|
+
*
|
|
121
|
+
* @param {object|undefined} existing
|
|
122
|
+
* @param {string[]} extraHosts
|
|
123
|
+
*/
|
|
124
|
+
function sandboxBlock(existing, extraHosts) {
|
|
125
|
+
const { $comment: _omit, ...want } = PROFILE.sandbox;
|
|
126
|
+
const cur = existing && typeof existing === "object" ? existing : {};
|
|
127
|
+
const {
|
|
128
|
+
excludedCommands: _ex,
|
|
129
|
+
allowAppleEvents: _ae,
|
|
130
|
+
enableWeakerNestedSandbox: _wn,
|
|
131
|
+
...keep
|
|
132
|
+
} = cur;
|
|
133
|
+
const curFs = cur.filesystem && typeof cur.filesystem === "object" ? cur.filesystem : {};
|
|
134
|
+
const { disabled: _d, allowRead: _ar, ...keepFs } = curFs;
|
|
135
|
+
const curNet = cur.network && typeof cur.network === "object" ? cur.network : {};
|
|
136
|
+
const { allowAllUnixSockets: _us, ...keepNet } = curNet;
|
|
137
|
+
return {
|
|
138
|
+
...keep,
|
|
139
|
+
...Object.fromEntries(Object.entries(want).filter(([, v]) => typeof v !== "object")),
|
|
140
|
+
filesystem: {
|
|
141
|
+
...keepFs,
|
|
142
|
+
allowWrite: [...want.filesystem.allowWrite],
|
|
143
|
+
denyWrite: union(curFs.denyWrite, want.filesystem.denyWrite),
|
|
144
|
+
denyRead: union(curFs.denyRead, want.filesystem.denyRead),
|
|
145
|
+
},
|
|
146
|
+
network: {
|
|
147
|
+
...keepNet,
|
|
148
|
+
...Object.fromEntries(Object.entries(want.network).filter(([, v]) => !Array.isArray(v))),
|
|
149
|
+
allowMachLookup: [...want.network.allowMachLookup],
|
|
150
|
+
allowedDomains: [...new Set([...want.network.allowedDomains, ...extraHosts])],
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
29
154
|
|
|
30
155
|
/**
|
|
31
|
-
*
|
|
32
|
-
* printed
|
|
33
|
-
*
|
|
156
|
+
* What applying the profile would do. describe and apply both read this, so
|
|
157
|
+
* the printed plan and the write cannot disagree.
|
|
158
|
+
*
|
|
159
|
+
* @param {object} current the profile file's parsed content, or {}
|
|
160
|
+
* @param {{home?: string, settings?: object, extraHosts?: string[]}} [opts]
|
|
161
|
+
* settings: ~/.claude/settings.json, parsed, for the whole-Bash warning and
|
|
162
|
+
* the migration; extraHosts: the prefs hosts, read from home when omitted
|
|
34
163
|
*/
|
|
35
|
-
export
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
164
|
+
export function planUnattendedProfile(current = {}, { home = "", settings, extraHosts } = {}) {
|
|
165
|
+
const perms = current.permissions || {};
|
|
166
|
+
const allow = Array.isArray(perms.allow) ? perms.allow.map(String) : [];
|
|
167
|
+
const deny = Array.isArray(perms.deny) ? perms.deny.map(String) : [];
|
|
168
|
+
const env = current.env || {};
|
|
169
|
+
const attended =
|
|
170
|
+
settings ?? (home ? readSettingsFile(join(home, ".claude", "settings.json")) : {});
|
|
171
|
+
const attendedAllow = Array.isArray(attended.permissions?.allow)
|
|
172
|
+
? attended.permissions.allow.map(String)
|
|
173
|
+
: [];
|
|
174
|
+
const hosts = extraHosts ?? (home ? prefsHosts(home) : []);
|
|
175
|
+
const rows = [];
|
|
176
|
+
|
|
177
|
+
const mode = perms.defaultMode;
|
|
178
|
+
const wantMode = PROFILE.defaultMode.value;
|
|
179
|
+
const modeLabel = `defaultMode:${wantMode}`;
|
|
180
|
+
if (mode === wantMode)
|
|
181
|
+
rows.push({ label: modeLabel, why: PROFILE.defaultMode.why, mark: "already" });
|
|
182
|
+
else if (mode === undefined || mode === "default" || mode === "manual")
|
|
183
|
+
rows.push({ label: modeLabel, why: PROFILE.defaultMode.why, mark: "add" });
|
|
184
|
+
else
|
|
185
|
+
rows.push({
|
|
186
|
+
label: modeLabel,
|
|
187
|
+
why: `${PROFILE.defaultMode.why}; replaces ${mode}, which would let an unattended run act without the allow list`,
|
|
188
|
+
mark: "replace",
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
for (const { rule, why } of PROFILE.wideAllows) {
|
|
192
|
+
if (hasRule(attendedAllow, rule)) rows.push({ label: `warn:${rule}`, why, mark: "warn" });
|
|
193
|
+
}
|
|
194
|
+
for (const [rule, why] of PROFILE.allow) {
|
|
195
|
+
rows.push({ label: rule, why, mark: hasRule(allow, rule) ? "already" : "add" });
|
|
196
|
+
}
|
|
197
|
+
for (const [rule, why] of PROFILE.deny) {
|
|
198
|
+
rows.push({ label: `deny:${rule}`, why, mark: hasRule(deny, rule) ? "already" : "add" });
|
|
199
|
+
}
|
|
200
|
+
for (const [key, value, why] of PROFILE.env) {
|
|
201
|
+
let mark = "add";
|
|
202
|
+
if (env[key] === value) mark = "already";
|
|
203
|
+
else if (env[key] !== undefined) mark = "kept";
|
|
204
|
+
rows.push({ label: `env:${key}=${value}`, why, mark });
|
|
205
|
+
}
|
|
206
|
+
const present = current.sandbox && typeof current.sandbox === "object";
|
|
207
|
+
const target = sandboxBlock(current.sandbox, hosts);
|
|
208
|
+
let sandboxMark = "add";
|
|
209
|
+
if (present)
|
|
210
|
+
sandboxMark =
|
|
211
|
+
JSON.stringify(current.sandbox) === JSON.stringify(target) ? "already" : "correct";
|
|
212
|
+
rows.push({
|
|
213
|
+
label: "sandbox",
|
|
214
|
+
why: "OS sandbox for Bash and everything it starts: required, no unsandboxed retry, no excluded commands, writes limited to the worktree and the unattended run directory, protected host files denied, credential stores unreadable, network limited to the listed hosts",
|
|
215
|
+
mark: sandboxMark,
|
|
216
|
+
});
|
|
217
|
+
for (const label of legacyEntries(attended)) {
|
|
218
|
+
rows.push({
|
|
219
|
+
label: `migrate:${label}`,
|
|
220
|
+
why: "written into ~/.claude/settings.json by an earlier install; it moves to the profile file",
|
|
221
|
+
mark: "migrate",
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return { rows, extraHosts: hosts };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const MARK_TEXT = {
|
|
228
|
+
add: "will be added",
|
|
229
|
+
already: "already there",
|
|
230
|
+
kept: "kept as is",
|
|
231
|
+
replace: "will be replaced",
|
|
232
|
+
correct: "will be corrected",
|
|
233
|
+
warn: "left in settings.json",
|
|
234
|
+
migrate: "removed from settings.json",
|
|
235
|
+
};
|
|
50
236
|
|
|
51
237
|
/**
|
|
52
238
|
* Render the profile for a human to read before it is applied.
|
|
53
239
|
*
|
|
54
|
-
* @param {
|
|
240
|
+
* @param {object} current the profile file's parsed content, or {}
|
|
241
|
+
* @param {{home?: string, settings?: object}} [opts]
|
|
55
242
|
* @returns {string}
|
|
56
243
|
*/
|
|
57
|
-
export function describeUnattendedProfile(
|
|
244
|
+
export function describeUnattendedProfile(current = {}, opts = {}) {
|
|
245
|
+
const { rows } = planUnattendedProfile(current || {}, opts);
|
|
246
|
+
const target = opts.home ? unattendedSettingsPath(opts.home) : unattendedSettingsPath();
|
|
58
247
|
const lines = [
|
|
59
|
-
|
|
60
|
-
"
|
|
248
|
+
` Unattended permission profile - these go into ${target},`,
|
|
249
|
+
" which the autopilot runner passes to each run with `claude --settings`.",
|
|
250
|
+
" ~/.claude/settings.json (the attended posture) is not changed.",
|
|
251
|
+
" An entry is 'already there' only when that exact rule is present.",
|
|
61
252
|
"",
|
|
62
253
|
];
|
|
63
|
-
for (const
|
|
64
|
-
|
|
65
|
-
lines.push(` ${tool.padEnd(12)} ${why} (${mark})`);
|
|
254
|
+
for (const r of rows) {
|
|
255
|
+
lines.push(` ${r.label.padEnd(44)} ${r.why} (${MARK_TEXT[r.mark]})`);
|
|
66
256
|
}
|
|
67
257
|
lines.push("");
|
|
68
|
-
lines.push(
|
|
69
|
-
|
|
70
|
-
|
|
258
|
+
lines.push(
|
|
259
|
+
" The OS sandbox is the boundary for Bash; the deny rules cover the file tools it does",
|
|
260
|
+
);
|
|
261
|
+
lines.push(
|
|
262
|
+
" not reach, and agent-guard is a second layer under MULTI_AGENT_UNATTENDED=1. The runner",
|
|
263
|
+
);
|
|
264
|
+
lines.push(
|
|
265
|
+
" refuses to launch unless this file still holds the posture. See features/unattended-security.md.",
|
|
266
|
+
);
|
|
71
267
|
return lines.join("\n");
|
|
72
268
|
}
|
|
73
269
|
|
|
270
|
+
function removeLegacy(settings, labels) {
|
|
271
|
+
const perms = { ...(settings.permissions || {}) };
|
|
272
|
+
const env = { ...(settings.env || {}) };
|
|
273
|
+
for (const label of labels) {
|
|
274
|
+
if (label.startsWith("defaultMode:")) delete perms.defaultMode;
|
|
275
|
+
else if (label.startsWith("deny:")) {
|
|
276
|
+
const rule = label.slice("deny:".length);
|
|
277
|
+
perms.deny = (perms.deny || []).filter((r) => String(r) !== rule);
|
|
278
|
+
} else if (label.startsWith("env:")) delete env[label.slice("env:".length).split("=")[0]];
|
|
279
|
+
else perms.allow = (perms.allow || []).filter((r) => String(r) !== label);
|
|
280
|
+
}
|
|
281
|
+
for (const k of ["allow", "deny"])
|
|
282
|
+
if (Array.isArray(perms[k]) && !perms[k].length) delete perms[k];
|
|
283
|
+
const out = { ...settings, permissions: perms, env };
|
|
284
|
+
if (!Object.keys(perms).length) delete out.permissions;
|
|
285
|
+
if (!Object.keys(env).length) delete out.env;
|
|
286
|
+
return out;
|
|
287
|
+
}
|
|
288
|
+
|
|
74
289
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
290
|
+
* The profile file's next content: `current` with every "add", "replace" and
|
|
291
|
+
* "correct" row of the plan applied. Pure; applyUnattendedProfile writes it.
|
|
292
|
+
*
|
|
293
|
+
* @param {object} current the profile file's parsed content, or {}
|
|
294
|
+
* @param {{home?: string, settings?: object, extraHosts?: string[]}} [opts]
|
|
295
|
+
* @returns {object}
|
|
296
|
+
*/
|
|
297
|
+
export function buildUnattendedProfile(current = {}, opts = {}) {
|
|
298
|
+
const { rows, extraHosts } = planUnattendedProfile(current, { settings: {}, ...opts });
|
|
299
|
+
const perms = { ...(current.permissions || {}) };
|
|
300
|
+
const allow = Array.isArray(perms.allow) ? [...perms.allow] : [];
|
|
301
|
+
const deny = Array.isArray(perms.deny) ? [...perms.deny] : [];
|
|
302
|
+
const next = { ...current };
|
|
303
|
+
for (const { label, mark } of rows) {
|
|
304
|
+
if (!["add", "replace", "correct"].includes(mark)) continue;
|
|
305
|
+
if (label.startsWith("defaultMode:")) perms.defaultMode = label.slice("defaultMode:".length);
|
|
306
|
+
else if (label.startsWith("deny:")) deny.push(label.slice("deny:".length));
|
|
307
|
+
else if (label.startsWith("env:")) {
|
|
308
|
+
const [key, ...rest] = label.slice("env:".length).split("=");
|
|
309
|
+
next.env = { ...(next.env || {}), [key]: rest.join("=") };
|
|
310
|
+
} else if (label === "sandbox") next.sandbox = sandboxBlock(current.sandbox, extraHosts);
|
|
311
|
+
else allow.push(label);
|
|
312
|
+
}
|
|
313
|
+
perms.allow = allow;
|
|
314
|
+
if (deny.length) perms.deny = deny;
|
|
315
|
+
next.permissions = perms;
|
|
316
|
+
return next;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Write the profile into its own settings file. Idempotent: running it twice
|
|
321
|
+
* changes nothing the second time.
|
|
78
322
|
*
|
|
79
323
|
* @param {{home:string, dryRun?:boolean}} opts
|
|
80
|
-
* @returns {{path:string, added:string[], already:string[], written:boolean}}
|
|
324
|
+
* @returns {{path:string, added:string[], warned:string[], migrated:string[], removed:string[], already:string[], kept:string[], written:boolean}}
|
|
81
325
|
*/
|
|
82
326
|
export function applyUnattendedProfile({ home, dryRun = false }) {
|
|
83
|
-
const path =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
327
|
+
const path = unattendedSettingsPath(home);
|
|
328
|
+
const settingsPath = join(home, ".claude", "settings.json");
|
|
329
|
+
const current = readSettingsFile(path);
|
|
330
|
+
const settings = readSettingsFile(settingsPath);
|
|
331
|
+
const { rows, extraHosts } = planUnattendedProfile(current, { home, settings });
|
|
332
|
+
const pick = (...marks) => rows.filter((r) => marks.includes(r.mark)).map((r) => r.label);
|
|
333
|
+
const added = pick("add", "replace", "correct");
|
|
334
|
+
const migrated = pick("migrate").map((l) => l.slice("migrate:".length));
|
|
335
|
+
const result = {
|
|
336
|
+
path,
|
|
337
|
+
added,
|
|
338
|
+
warned: pick("warn").map((l) => l.slice("warn:".length)),
|
|
339
|
+
migrated,
|
|
340
|
+
removed: [],
|
|
341
|
+
already: pick("already"),
|
|
342
|
+
kept: pick("kept"),
|
|
343
|
+
};
|
|
344
|
+
if (dryRun || (!added.length && !migrated.length)) return { ...result, written: false };
|
|
345
|
+
|
|
346
|
+
if (added.length) {
|
|
347
|
+
const next = buildUnattendedProfile(current, { home, settings, extraHosts });
|
|
348
|
+
const gaps = profileGaps(next, PROFILE, { extraHosts });
|
|
349
|
+
if (gaps.sandbox.length || gaps.permissions.length)
|
|
350
|
+
throw new Error(
|
|
351
|
+
`the profile would still fall short: ${[...gaps.sandbox, ...gaps.permissions].join("; ")}`,
|
|
352
|
+
);
|
|
353
|
+
writeFileSync(path, `${JSON.stringify(next, null, 2)}\n`, { mode: 0o600 });
|
|
95
354
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const already = [];
|
|
99
|
-
const added = [];
|
|
100
|
-
for (const [tool] of UNATTENDED_ALLOW) {
|
|
101
|
-
if (allow.some((a) => String(a) === tool || String(a).startsWith(`${tool}(`)))
|
|
102
|
-
already.push(tool);
|
|
103
|
-
else {
|
|
104
|
-
allow.push(tool);
|
|
105
|
-
added.push(tool);
|
|
106
|
-
}
|
|
355
|
+
if (migrated.length) {
|
|
356
|
+
writeFileSync(settingsPath, `${JSON.stringify(removeLegacy(settings, migrated), null, 2)}\n`);
|
|
107
357
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
settings.permissions = { ...permissions, allow };
|
|
111
|
-
writeFileSync(path, `${JSON.stringify(settings, null, 2)}\n`);
|
|
112
|
-
return { path, added, already, written: true };
|
|
358
|
+
return { ...result, written: true };
|
|
113
359
|
}
|