@mmerterden/multi-agent-pipeline 20.2.1 → 20.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (622) hide show
  1. package/CHANGELOG.md +919 -1
  2. package/README.md +104 -81
  3. package/README.tr.md +103 -62
  4. package/docs/FIGMA_PIPELINE.md +35 -35
  5. package/docs/adr/0006-skills-core-external-split.md +1 -1
  6. package/docs/adr/0007-multi-tool-adapter-framework.md +6 -0
  7. package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +7 -0
  8. package/docs/architecture.md +50 -14
  9. package/docs/best-practices.md +1 -1
  10. package/docs/ecosystem.md +56 -32
  11. package/docs/facts.json +10 -10
  12. package/docs/features.md +97 -5
  13. package/docs/recovery-guide.md +7 -14
  14. package/docs/server-readiness.md +31 -24
  15. package/index.js +1 -1
  16. package/install/_common.mjs +3 -5
  17. package/install/_platform-filter.mjs +23 -1
  18. package/install/_unattended-profile.mjs +321 -75
  19. package/install/claude.mjs +51 -10
  20. package/install/codex.mjs +2 -0
  21. package/install/copilot.mjs +2 -0
  22. package/install/index.mjs +30 -17
  23. package/install/templates/claude-hooks.json +16 -5
  24. package/install/templates/copilot-instructions.md +1 -1
  25. package/install/templates/multi-agent-autopilot-awake.plist.template +48 -0
  26. package/install/templates/multi-agent-autopilot.plist.template +12 -5
  27. package/install/unattended-profile-legacy.json +80 -0
  28. package/manifest.json +617 -483
  29. package/package.json +8 -3
  30. package/pipeline/agents/code-reviewer.md +10 -0
  31. package/pipeline/agents/plan-critic.md +98 -0
  32. package/pipeline/agents/security-auditor.md +10 -0
  33. package/pipeline/agents/task-clarifier.md +10 -0
  34. package/pipeline/commands/multi-agent/SKILL.md +2 -2
  35. package/pipeline/commands/multi-agent/analysis/SKILL.md +6 -2
  36. package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +12 -1
  37. package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +4 -0
  38. package/pipeline/commands/multi-agent/autopilot/SKILL.md +6 -2
  39. package/pipeline/commands/multi-agent/autopilot-off/SKILL.md +36 -6
  40. package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +77 -12
  41. package/pipeline/commands/multi-agent/autopilot-status/SKILL.md +29 -8
  42. package/pipeline/commands/multi-agent/build-optimize/SKILL.md +4 -0
  43. package/pipeline/commands/multi-agent/channels/SKILL.md +9 -9
  44. package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +5 -1
  45. package/pipeline/commands/multi-agent/create-jira/SKILL.md +4 -0
  46. package/pipeline/commands/multi-agent/design-check/SKILL.md +16 -11
  47. package/pipeline/commands/multi-agent/diff-explain/SKILL.md +4 -0
  48. package/pipeline/commands/multi-agent/doctor/SKILL.md +4 -0
  49. package/pipeline/commands/multi-agent/feedback/SKILL.md +5 -1
  50. package/pipeline/commands/multi-agent/forget/SKILL.md +4 -0
  51. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +4 -0
  52. package/pipeline/commands/multi-agent/graph/SKILL.md +4 -0
  53. package/pipeline/commands/multi-agent/help/SKILL.md +37 -39
  54. package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +4 -0
  55. package/pipeline/commands/multi-agent/issue/SKILL.md +7 -1
  56. package/pipeline/commands/multi-agent/jira/SKILL.md +7 -1
  57. package/pipeline/commands/multi-agent/kill/SKILL.md +9 -3
  58. package/pipeline/commands/multi-agent/language/SKILL.md +4 -0
  59. package/pipeline/commands/multi-agent/log/SKILL.md +4 -0
  60. package/pipeline/commands/multi-agent/manual-test/SKILL.md +5 -0
  61. package/pipeline/commands/multi-agent/model/SKILL.md +4 -0
  62. package/pipeline/commands/multi-agent/prune-logs/SKILL.md +4 -0
  63. package/pipeline/commands/multi-agent/prune-prompts/SKILL.md +4 -0
  64. package/pipeline/commands/multi-agent/purge/SKILL.md +4 -0
  65. package/pipeline/commands/multi-agent/refactor/SKILL.md +5 -0
  66. package/pipeline/commands/multi-agent/research/SKILL.md +49 -0
  67. package/pipeline/commands/multi-agent/resume/SKILL.md +29 -6
  68. package/pipeline/commands/multi-agent/review/SKILL.md +28 -9
  69. package/pipeline/commands/multi-agent/review-analysis/SKILL.md +5 -1
  70. package/pipeline/commands/multi-agent/review-issue/SKILL.md +4 -0
  71. package/pipeline/commands/multi-agent/review-jira/SKILL.md +4 -0
  72. package/pipeline/commands/multi-agent/route-off/SKILL.md +4 -0
  73. package/pipeline/commands/multi-agent/route-on/SKILL.md +4 -0
  74. package/pipeline/commands/multi-agent/route-status/SKILL.md +4 -0
  75. package/pipeline/commands/multi-agent/routines/SKILL.md +4 -0
  76. package/pipeline/commands/multi-agent/save/SKILL.md +6 -2
  77. package/pipeline/commands/multi-agent/scaffold/SKILL.md +47 -0
  78. package/pipeline/commands/multi-agent/scan/SKILL.md +4 -0
  79. package/pipeline/commands/multi-agent/search/SKILL.md +12 -8
  80. package/pipeline/commands/multi-agent/security-review/SKILL.md +4 -0
  81. package/pipeline/commands/multi-agent/serve/SKILL.md +62 -0
  82. package/pipeline/commands/multi-agent/setup/SKILL.md +27 -36
  83. package/pipeline/commands/multi-agent/stack/SKILL.md +4 -0
  84. package/pipeline/commands/multi-agent/status/SKILL.md +10 -9
  85. package/pipeline/commands/multi-agent/steer/SKILL.md +5 -1
  86. package/pipeline/commands/multi-agent/store-ready/SKILL.md +4 -0
  87. package/pipeline/commands/multi-agent/sync/SKILL.md +13 -13
  88. package/pipeline/commands/multi-agent/test/SKILL.md +4 -0
  89. package/pipeline/commands/multi-agent/test-accessibility/SKILL.md +4 -0
  90. package/pipeline/commands/multi-agent/test-dark-mode/SKILL.md +4 -0
  91. package/pipeline/commands/multi-agent/test-dynamic-type/SKILL.md +4 -0
  92. package/pipeline/commands/multi-agent/test-screenshots/SKILL.md +5 -1
  93. package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +4 -0
  94. package/pipeline/commands/multi-agent/uninstall/SKILL.md +5 -1
  95. package/pipeline/commands/multi-agent/update/SKILL.md +4 -0
  96. package/pipeline/contract/CHANGELOG.md +74 -0
  97. package/pipeline/contract/README.md +126 -0
  98. package/pipeline/contract/build.mjs +427 -0
  99. package/pipeline/contract/fixtures/answer-result.json +11 -0
  100. package/pipeline/contract/fixtures/error-invalid-request.json +8 -0
  101. package/pipeline/contract/fixtures/error-unauthorized.json +5 -0
  102. package/pipeline/contract/fixtures/error-unsigned.json +5 -0
  103. package/pipeline/contract/fixtures/issues-empty.json +18 -0
  104. package/pipeline/contract/fixtures/launch-plan.json +31 -0
  105. package/pipeline/contract/fixtures/runs-awaiting-question.json +70 -0
  106. package/pipeline/contract/fixtures/runs-empty.json +6 -0
  107. package/pipeline/contract/fixtures/runs-failed.json +84 -0
  108. package/pipeline/contract/fixtures/runs-old-schema.json +70 -0
  109. package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +101 -0
  110. package/pipeline/contract/fixtures/runs-pr-opened.json +106 -0
  111. package/pipeline/contract/fixtures/runs-running.json +84 -0
  112. package/pipeline/contract/fixtures/worktrees-empty.json +4 -0
  113. package/pipeline/contract/frozen/toolbox.json +107 -0
  114. package/pipeline/contract/manifest.json +263 -0
  115. package/pipeline/contract/types/index.d.ts +343 -0
  116. package/pipeline/lib/_jira-auth.sh +6 -2
  117. package/pipeline/lib/account-resolver.sh +1 -1
  118. package/pipeline/lib/autopilot-state.sh +19 -0
  119. package/pipeline/lib/context-link-extractor.sh +12 -5
  120. package/pipeline/lib/credential-inventory.sh +12 -5
  121. package/pipeline/lib/credential-store.sh +116 -185
  122. package/pipeline/lib/fetch-confluence.sh +44 -3
  123. package/pipeline/lib/fetch-document.sh +3 -4
  124. package/pipeline/lib/fetch-fortify.sh +1 -1
  125. package/pipeline/lib/figma-mcp-refresh.sh +2 -2
  126. package/pipeline/lib/figma-token.sh +5 -1
  127. package/pipeline/lib/issue-fetcher.sh +233 -16
  128. package/pipeline/lib/json-file-lock.mjs +172 -0
  129. package/pipeline/lib/model-dispatch.sh +21 -12
  130. package/pipeline/lib/model-rung.sh +6 -1
  131. package/pipeline/lib/multi-repo-pipeline.sh +1 -1
  132. package/pipeline/lib/outbound-gate.mjs +46 -16
  133. package/pipeline/lib/parse-complaints.sh +14 -7
  134. package/pipeline/lib/plan-todos.sh +3 -3
  135. package/pipeline/lib/post-pr-review.sh +9 -9
  136. package/pipeline/lib/pr-request-location.mjs +85 -0
  137. package/pipeline/lib/regular-file.mjs +153 -0
  138. package/pipeline/lib/repo-hygiene.sh +17 -0
  139. package/pipeline/lib/route-state.sh +5 -1
  140. package/pipeline/lib/run-paths.sh +3 -2
  141. package/pipeline/lib/stack-detect.sh +19 -1
  142. package/pipeline/lib/unattended-profile-check.mjs +178 -0
  143. package/pipeline/lib/unattended-settings-location.mjs +28 -0
  144. package/pipeline/lib/unattended.mjs +76 -0
  145. package/pipeline/lib/unattended.sh +32 -0
  146. package/pipeline/lib/untrusted.mjs +76 -0
  147. package/pipeline/lib/usage-endpoint.mjs +33 -0
  148. package/pipeline/lib/user-facing.mjs +82 -0
  149. package/pipeline/lib/user-facing.sh +58 -0
  150. package/pipeline/multi-agent-refs/_dev-context.md +1 -1
  151. package/pipeline/multi-agent-refs/analysis/evidence.md +4 -0
  152. package/pipeline/multi-agent-refs/analysis/locked.md +2 -2
  153. package/pipeline/multi-agent-refs/analysis/render.md +4 -3
  154. package/pipeline/multi-agent-refs/analysis/resolve.md +3 -1
  155. package/pipeline/multi-agent-refs/analysis/synthesis.md +4 -5
  156. package/pipeline/multi-agent-refs/analysis-template.md +10 -17
  157. package/pipeline/multi-agent-refs/channels/jira.md +1 -1
  158. package/pipeline/multi-agent-refs/component-dispatch.md +3 -3
  159. package/pipeline/multi-agent-refs/conventions-defaults.md +32 -32
  160. package/pipeline/multi-agent-refs/cross-cli-contract.md +10 -17
  161. package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +37 -9
  162. package/pipeline/multi-agent-refs/features/autopilot-operations.md +277 -0
  163. package/pipeline/multi-agent-refs/features/constitution.md +196 -0
  164. package/pipeline/multi-agent-refs/features/doctor.md +6 -3
  165. package/pipeline/multi-agent-refs/features/external-context-injection.md +6 -1
  166. package/pipeline/multi-agent-refs/features/jira-context.md +1 -1
  167. package/pipeline/multi-agent-refs/features/maturity-followup.md +43 -23
  168. package/pipeline/multi-agent-refs/features/model-fallback.md +9 -0
  169. package/pipeline/multi-agent-refs/features/phone-api.md +306 -0
  170. package/pipeline/multi-agent-refs/features/plan-critic.md +159 -0
  171. package/pipeline/multi-agent-refs/features/research.md +150 -0
  172. package/pipeline/multi-agent-refs/features/review-decision.md +185 -0
  173. package/pipeline/multi-agent-refs/features/scaffold.md +160 -0
  174. package/pipeline/multi-agent-refs/features/security-audit.md +6 -2
  175. package/pipeline/multi-agent-refs/features/skill-conformance.md +4 -1
  176. package/pipeline/multi-agent-refs/features/stack-adapters.md +116 -0
  177. package/pipeline/multi-agent-refs/features/unattended-gates.md +316 -0
  178. package/pipeline/multi-agent-refs/features/unattended-security.md +731 -0
  179. package/pipeline/multi-agent-refs/features/url-enrichment.md +2 -2
  180. package/pipeline/multi-agent-refs/features/usage-reporting.md +127 -35
  181. package/pipeline/multi-agent-refs/features/verify-by-test.md +1 -1
  182. package/pipeline/multi-agent-refs/features/visual-evidence.md +7 -7
  183. package/pipeline/multi-agent-refs/keychain.md +6 -11
  184. package/pipeline/multi-agent-refs/payload-contracts.md +2 -2
  185. package/pipeline/multi-agent-refs/phases/log-format.md +2 -3
  186. package/pipeline/multi-agent-refs/phases/modes.md +10 -12
  187. package/pipeline/multi-agent-refs/phases/operations.md +11 -5
  188. package/pipeline/multi-agent-refs/phases/phase-0-init.md +73 -81
  189. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +22 -22
  190. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +42 -66
  191. package/pipeline/multi-agent-refs/phases/phase-3-review.md +45 -79
  192. package/pipeline/multi-agent-refs/phases/phase-4-commit.md +28 -38
  193. package/pipeline/multi-agent-refs/phases/phase-5-report.md +27 -25
  194. package/pipeline/multi-agent-refs/phases.md +1 -1
  195. package/pipeline/multi-agent-refs/picker-contract.md +1 -1
  196. package/pipeline/multi-agent-refs/progress-contract.md +13 -16
  197. package/pipeline/multi-agent-refs/readiness-review.md +1 -1
  198. package/pipeline/multi-agent-refs/research/engine.md +91 -0
  199. package/pipeline/multi-agent-refs/rules.md +6 -4
  200. package/pipeline/multi-agent-refs/setup/repo-discovery.md +2 -2
  201. package/pipeline/multi-agent-refs/tracker-contract.md +2 -2
  202. package/pipeline/multi-agent-refs/unattended-contract.md +68 -16
  203. package/pipeline/rules/figma-pipeline.md +12 -12
  204. package/pipeline/schemas/agent-state.schema.json +480 -18
  205. package/pipeline/schemas/analysis-spec.schema.json +4 -4
  206. package/pipeline/schemas/answer-request.schema.json +24 -0
  207. package/pipeline/schemas/answer-result.schema.json +28 -0
  208. package/pipeline/schemas/autopilot-config.schema.json +111 -13
  209. package/pipeline/schemas/command-parameters.schema.json +99 -0
  210. package/pipeline/schemas/constitution.schema.json +56 -0
  211. package/pipeline/schemas/contract-error.schema.json +52 -0
  212. package/pipeline/schemas/design-check-config.schema.json +5 -1
  213. package/pipeline/schemas/issues.schema.json +61 -0
  214. package/pipeline/schemas/launch-plan.schema.json +46 -0
  215. package/pipeline/schemas/launch-request.schema.json +45 -0
  216. package/pipeline/schemas/launch.json +61 -0
  217. package/pipeline/schemas/launch.schema.json +84 -0
  218. package/pipeline/schemas/phases.json +2 -2
  219. package/pipeline/schemas/phases.schema.json +68 -0
  220. package/pipeline/schemas/phone-devices.schema.json +61 -0
  221. package/pipeline/schemas/phone-signed-request.schema.json +67 -0
  222. package/pipeline/schemas/plan-critique.schema.json +99 -0
  223. package/pipeline/schemas/plan-todos.schema.json +7 -7
  224. package/pipeline/schemas/planning-output.schema.json +5 -0
  225. package/pipeline/schemas/pr-request.schema.json +46 -0
  226. package/pipeline/schemas/prefs.schema.json +79 -8
  227. package/pipeline/schemas/research-output.schema.json +118 -0
  228. package/pipeline/schemas/review-file-exclusions.schema.json +25 -0
  229. package/pipeline/schemas/reviewer-output.schema.json +40 -4
  230. package/pipeline/schemas/run-questions.json +392 -0
  231. package/pipeline/schemas/run-questions.schema.json +118 -0
  232. package/pipeline/schemas/runs-index.schema.json +189 -0
  233. package/pipeline/schemas/scaffold-manifest.schema.json +43 -0
  234. package/pipeline/schemas/secret-patterns.schema.json +28 -0
  235. package/pipeline/schemas/stack-adapters.json +527 -0
  236. package/pipeline/schemas/stack-adapters.schema.json +184 -0
  237. package/pipeline/schemas/token-budget.json +1 -1
  238. package/pipeline/schemas/token-budget.schema.json +26 -0
  239. package/pipeline/schemas/triage-output.schema.json +64 -3
  240. package/pipeline/schemas/unattended-policy.json +139 -0
  241. package/pipeline/schemas/unattended-policy.schema.json +73 -0
  242. package/pipeline/schemas/unattended-profile.json +248 -0
  243. package/pipeline/schemas/unattended-profile.schema.json +198 -0
  244. package/pipeline/schemas/worktrees.schema.json +51 -0
  245. package/pipeline/scripts/README.md +1 -0
  246. package/pipeline/scripts/_autopilot-config.mjs +130 -0
  247. package/pipeline/scripts/_autopilot-ops.mjs +567 -0
  248. package/pipeline/scripts/_autopilot-outcomes.mjs +174 -0
  249. package/pipeline/scripts/_command-contract.mjs +384 -0
  250. package/pipeline/scripts/_cost.mjs +40 -0
  251. package/pipeline/scripts/_notices.mjs +160 -0
  252. package/pipeline/scripts/_phone-auth.mjs +485 -0
  253. package/pipeline/scripts/_pre-existing.mjs +294 -0
  254. package/pipeline/scripts/_redact.mjs +77 -0
  255. package/pipeline/scripts/_run-paths.mjs +4 -2
  256. package/pipeline/scripts/_stack-adapter.mjs +678 -0
  257. package/pipeline/scripts/_stack-routing.mjs +1 -1
  258. package/pipeline/scripts/agent-guard.py +348 -37
  259. package/pipeline/scripts/agent-guard.sh +41 -13
  260. package/pipeline/scripts/analysis-story-tree.mjs +79 -3
  261. package/pipeline/scripts/answer-question.mjs +181 -0
  262. package/pipeline/scripts/audit-log-rotate.sh +1 -4
  263. package/pipeline/scripts/audit-log.sh +4 -4
  264. package/pipeline/scripts/autopilot-arming.mjs +389 -21
  265. package/pipeline/scripts/autopilot-awake.mjs +255 -0
  266. package/pipeline/scripts/autopilot-intake.mjs +137 -36
  267. package/pipeline/scripts/autopilot-menubar.swift +156 -44
  268. package/pipeline/scripts/autopilot-publish.mjs +1625 -0
  269. package/pipeline/scripts/autopilot-runner.mjs +1678 -222
  270. package/pipeline/scripts/autopilot-status.sh +198 -33
  271. package/pipeline/scripts/build-lock.sh +120 -0
  272. package/pipeline/scripts/build-references.mjs +4 -1
  273. package/pipeline/scripts/build-stack-plugins.mjs +59 -22
  274. package/pipeline/scripts/capture-flush.sh +1 -1
  275. package/pipeline/scripts/capture-resume.sh +13 -9
  276. package/pipeline/scripts/check-derived-drift.mjs +52 -11
  277. package/pipeline/scripts/commands.mjs +88 -0
  278. package/pipeline/scripts/constitution.mjs +362 -0
  279. package/pipeline/scripts/contract-server.mjs +776 -0
  280. package/pipeline/scripts/cost-analyze.mjs +89 -39
  281. package/pipeline/scripts/diff-explain.mjs +12 -1
  282. package/pipeline/scripts/doctor.mjs +77 -28
  283. package/pipeline/scripts/evidence-gate.mjs +192 -12
  284. package/pipeline/scripts/feedback-send.mjs +4 -2
  285. package/pipeline/scripts/gate-ledger.mjs +449 -0
  286. package/pipeline/scripts/gc-abandoned.sh +132 -13
  287. package/pipeline/scripts/gen-facts.mjs +31 -15
  288. package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
  289. package/pipeline/scripts/github-ssh-setup.sh +140 -29
  290. package/pipeline/scripts/graph-mermaid.mjs +4 -1
  291. package/pipeline/scripts/issues.mjs +236 -0
  292. package/pipeline/scripts/jira-attach.sh +6 -2
  293. package/pipeline/scripts/jira-search.sh +4 -3
  294. package/pipeline/scripts/keychain-save.sh +125 -24
  295. package/pipeline/scripts/keychain.py +63 -93
  296. package/pipeline/scripts/launch-request.mjs +747 -0
  297. package/pipeline/scripts/localize-commands.mjs +4 -10
  298. package/pipeline/scripts/log-metric.sh +6 -5
  299. package/pipeline/scripts/maturity-followup.mjs +13 -4
  300. package/pipeline/scripts/memory-save.sh +25 -0
  301. package/pipeline/scripts/migrate-prefs.mjs +4 -3
  302. package/pipeline/scripts/open-questions-gate.mjs +276 -0
  303. package/pipeline/scripts/phase-tracker.sh +41 -27
  304. package/pipeline/scripts/phase0-exit-gate.mjs +22 -4
  305. package/pipeline/scripts/phone-devices.mjs +224 -0
  306. package/pipeline/scripts/plan-coverage-gate.mjs +200 -66
  307. package/pipeline/scripts/plan-critique-gate.mjs +591 -0
  308. package/pipeline/scripts/pr-request.mjs +188 -0
  309. package/pipeline/scripts/pre-commit-check.sh +115 -4
  310. package/pipeline/scripts/probe-evidence-capability.sh +44 -5
  311. package/pipeline/scripts/record-phase.mjs +71 -0
  312. package/pipeline/scripts/render-agent-log-cost.sh +17 -2
  313. package/pipeline/scripts/render-cost-summary.sh +1 -1
  314. package/pipeline/scripts/render-work-summary.sh +1 -1
  315. package/pipeline/scripts/require-supported-version.sh +4 -1
  316. package/pipeline/scripts/research-gate.mjs +704 -0
  317. package/pipeline/scripts/review-decision-gate.mjs +403 -0
  318. package/pipeline/scripts/routine-registry.mjs +5 -2
  319. package/pipeline/scripts/runs-index.mjs +135 -27
  320. package/pipeline/scripts/scaffold-gate.mjs +393 -0
  321. package/pipeline/scripts/skill-conformance.mjs +25 -8
  322. package/pipeline/scripts/skill-siblings.mjs +2 -1
  323. package/pipeline/scripts/smoke-cross-cli-behavior.sh +32 -6
  324. package/pipeline/scripts/smoke-schema-validation.sh +6 -2
  325. package/pipeline/scripts/spec-consistency-gate.mjs +469 -0
  326. package/pipeline/scripts/symbol-existence-gate.mjs +450 -0
  327. package/pipeline/scripts/test-gap-scan.mjs +40 -2
  328. package/pipeline/scripts/test-integrity-gate.mjs +20 -4
  329. package/pipeline/scripts/test-strength.mjs +484 -0
  330. package/pipeline/scripts/test-summary.mjs +651 -0
  331. package/pipeline/scripts/triage-memory.mjs +49 -9
  332. package/pipeline/scripts/unattended_policy.py +2786 -0
  333. package/pipeline/scripts/uninstall.mjs +10 -10
  334. package/pipeline/scripts/update-issue-progress.sh +1 -1
  335. package/pipeline/scripts/usage-identity.mjs +288 -0
  336. package/pipeline/scripts/usage-register.mjs +187 -67
  337. package/pipeline/scripts/usage-report.mjs +232 -67
  338. package/pipeline/scripts/validate-complaint-doc.mjs +28 -10
  339. package/pipeline/scripts/validate-planning.mjs +6 -0
  340. package/pipeline/scripts/verify-citations.mjs +151 -38
  341. package/pipeline/scripts/verify.mjs +58 -18
  342. package/pipeline/scripts/worktree-prepare.sh +126 -0
  343. package/pipeline/scripts/worktrees.mjs +124 -0
  344. package/pipeline/scripts/write-state.mjs +48 -17
  345. package/pipeline/skills/.skill-manifest.json +222 -226
  346. package/pipeline/skills/.skills-index.json +77 -88
  347. package/pipeline/skills/shared/README.md +44 -45
  348. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +3 -2
  349. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +3 -2
  350. package/pipeline/skills/shared/core/multi-agent/SKILL.md +10 -9
  351. package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +6 -5
  352. package/pipeline/skills/shared/core/multi-agent-analysis-jira/SKILL.md +11 -3
  353. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +2 -1
  354. package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +4 -3
  355. package/pipeline/skills/shared/core/multi-agent-autopilot-off/SKILL.md +32 -6
  356. package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +66 -8
  357. package/pipeline/skills/shared/core/multi-agent-autopilot-status/SKILL.md +27 -9
  358. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +2 -1
  359. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +7 -4
  360. package/pipeline/skills/shared/core/multi-agent-complaint-analysis/SKILL.md +3 -2
  361. package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +2 -1
  362. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +7 -5
  363. package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +2 -1
  364. package/pipeline/skills/shared/core/multi-agent-doctor/SKILL.md +3 -2
  365. package/pipeline/skills/shared/core/multi-agent-feedback/SKILL.md +2 -1
  366. package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +2 -1
  367. package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +2 -1
  368. package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +2 -1
  369. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -1
  370. package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +2 -1
  371. package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +3 -2
  372. package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +2 -1
  373. package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +7 -4
  374. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -1
  375. package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +2 -1
  376. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +2 -1
  377. package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +2 -1
  378. package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +2 -1
  379. package/pipeline/skills/shared/core/multi-agent-prune-prompts/SKILL.md +2 -1
  380. package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +2 -1
  381. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +2 -1
  382. package/pipeline/skills/shared/core/multi-agent-research/SKILL.md +35 -0
  383. package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +7 -3
  384. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +7 -5
  385. package/pipeline/skills/shared/core/multi-agent-review-analysis/SKILL.md +2 -1
  386. package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +3 -2
  387. package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +2 -1
  388. package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +2 -1
  389. package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +2 -1
  390. package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +2 -1
  391. package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +2 -1
  392. package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +3 -2
  393. package/pipeline/skills/shared/core/multi-agent-scaffold/SKILL.md +30 -0
  394. package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +2 -1
  395. package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +4 -3
  396. package/pipeline/skills/shared/core/multi-agent-security-review/SKILL.md +2 -1
  397. package/pipeline/skills/shared/core/multi-agent-serve/SKILL.md +60 -0
  398. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +8 -8
  399. package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +2 -1
  400. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +7 -8
  401. package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -1
  402. package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +2 -1
  403. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +10 -10
  404. package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -1
  405. package/pipeline/skills/shared/core/multi-agent-test-accessibility/SKILL.md +2 -1
  406. package/pipeline/skills/shared/core/multi-agent-test-dark-mode/SKILL.md +2 -1
  407. package/pipeline/skills/shared/core/multi-agent-test-dynamic-type/SKILL.md +2 -1
  408. package/pipeline/skills/shared/core/multi-agent-test-screenshots/SKILL.md +2 -1
  409. package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +2 -1
  410. package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +3 -2
  411. package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -1
  412. package/pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md +46 -0
  413. package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +9 -3
  414. package/pipeline/skills/shared/external/NOTICE-paul-hudson-skills.md +54 -0
  415. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +9 -11
  416. package/pipeline/skills/shared/external/NOTICE-vibeship-spawner-skills.md +203 -0
  417. package/pipeline/skills/shared/external/NOTICE-xcode-build-skills.md +10 -3
  418. package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +131 -25
  419. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -3
  420. package/pipeline/skills/shared/external/alarmkit/SKILL.md +2 -1
  421. package/pipeline/skills/shared/external/android-architecture/SKILL.md +85 -76
  422. package/pipeline/skills/shared/external/android-build-quality-gates/SKILL.md +51 -3
  423. package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +9 -0
  424. package/pipeline/skills/shared/external/android-datastore/SKILL.md +4 -3
  425. package/pipeline/skills/shared/external/android-design-tokens-codegen/SKILL.md +4 -3
  426. package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +106 -181
  427. package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +147 -0
  428. package/pipeline/skills/shared/external/android-mvi-viewmodel/SKILL.md +45 -4
  429. package/pipeline/skills/shared/external/android-performance/SKILL.md +27 -2
  430. package/pipeline/skills/shared/external/android-performance/references/patterns.md +37 -37
  431. package/pipeline/skills/shared/external/api-patterns/SKILL.md +111 -67
  432. package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +128 -0
  433. package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +136 -186
  434. package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +140 -0
  435. package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +207 -0
  436. package/pipeline/skills/shared/external/api-security-best-practices/references/operations.md +66 -0
  437. package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +175 -0
  438. package/pipeline/skills/shared/external/app-clips/SKILL.md +2 -0
  439. package/pipeline/skills/shared/external/app-intents/SKILL.md +2 -0
  440. package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +4 -3
  441. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +2 -0
  442. package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -0
  443. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +2 -0
  444. package/pipeline/skills/shared/external/architecture/SKILL.md +106 -39
  445. package/pipeline/skills/shared/external/architecture/references/adr-and-review.md +76 -0
  446. package/pipeline/skills/shared/external/authentication/SKILL.md +2 -0
  447. package/pipeline/skills/shared/external/avkit/SKILL.md +2 -0
  448. package/pipeline/skills/shared/external/background-processing/SKILL.md +2 -1
  449. package/pipeline/skills/shared/external/backlog/SKILL.md +3 -2
  450. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +2 -0
  451. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +1 -1
  452. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +3 -2
  453. package/pipeline/skills/shared/external/clean-code/SKILL.md +192 -90
  454. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +2 -1
  455. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +1 -1
  456. package/pipeline/skills/shared/external/compose-components/SKILL.md +4 -4
  457. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +22 -22
  458. package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +10 -10
  459. package/pipeline/skills/shared/external/compose-testing/SKILL.md +13 -6
  460. package/pipeline/skills/shared/external/compose-testing/references/patterns.md +59 -59
  461. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +2 -0
  462. package/pipeline/skills/shared/external/context-compression/SKILL.md +118 -250
  463. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +2 -0
  464. package/pipeline/skills/shared/external/core-data/SKILL.md +2 -0
  465. package/pipeline/skills/shared/external/core-motion/SKILL.md +2 -0
  466. package/pipeline/skills/shared/external/core-nfc/SKILL.md +2 -0
  467. package/pipeline/skills/shared/external/coreml/SKILL.md +2 -1
  468. package/pipeline/skills/shared/external/council/SKILL.md +2 -1
  469. package/pipeline/skills/shared/external/cryptokit/SKILL.md +2 -0
  470. package/pipeline/skills/shared/external/css-modern/SKILL.md +3 -2
  471. package/pipeline/skills/shared/external/database-patterns/SKILL.md +3 -2
  472. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +2 -0
  473. package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +130 -20
  474. package/pipeline/skills/shared/external/debugging-strategies/references/hard-cases.md +54 -0
  475. package/pipeline/skills/shared/external/device-integrity/SKILL.md +2 -0
  476. package/pipeline/skills/shared/external/docker-expert/SKILL.md +137 -381
  477. package/pipeline/skills/shared/external/docker-expert/references/patterns.md +98 -0
  478. package/pipeline/skills/shared/external/energykit/SKILL.md +2 -1
  479. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +3 -1
  480. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +2 -2
  481. package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +116 -185
  482. package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +235 -0
  483. package/pipeline/skills/shared/external/fastapi-pro/references/testing-and-deployment.md +69 -0
  484. package/pipeline/skills/shared/external/firebase/SKILL.md +4 -3
  485. package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +151 -293
  486. package/pipeline/skills/shared/external/github-actions-templates/references/patterns.md +96 -0
  487. package/pipeline/skills/shared/external/healthkit/SKILL.md +2 -0
  488. package/pipeline/skills/shared/external/hig-components-content/SKILL.md +69 -72
  489. package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +111 -0
  490. package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +77 -86
  491. package/pipeline/skills/shared/external/hig-components-layout/references/containers.md +98 -0
  492. package/pipeline/skills/shared/external/hig-components-status/SKILL.md +150 -78
  493. package/pipeline/skills/shared/external/hig-components-system/SKILL.md +76 -97
  494. package/pipeline/skills/shared/external/hig-components-system/references/surfaces.md +98 -0
  495. package/pipeline/skills/shared/external/hig-foundations/SKILL.md +48 -76
  496. package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +132 -0
  497. package/pipeline/skills/shared/external/hig-inputs/SKILL.md +147 -106
  498. package/pipeline/skills/shared/external/hig-patterns/SKILL.md +61 -77
  499. package/pipeline/skills/shared/external/hig-patterns/references/patterns.md +92 -0
  500. package/pipeline/skills/shared/external/hig-platforms/SKILL.md +147 -77
  501. package/pipeline/skills/shared/external/hig-technologies/SKILL.md +61 -121
  502. package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +108 -0
  503. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +2 -0
  504. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +1 -1
  505. package/pipeline/skills/shared/external/html-semantic/SKILL.md +3 -2
  506. package/pipeline/skills/shared/external/humanizer/SKILL.md +2 -1
  507. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +2 -0
  508. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +2 -1
  509. package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +14 -2
  510. package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
  511. package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +4 -3
  512. package/pipeline/skills/shared/external/ios-localization/SKILL.md +8 -6
  513. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +2 -2
  514. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +11 -11
  515. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +2 -1
  516. package/pipeline/skills/shared/external/ios-networking/SKILL.md +2 -0
  517. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +2 -0
  518. package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +102 -193
  519. package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +103 -0
  520. package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -2
  521. package/pipeline/skills/shared/external/live-activities/evals/evals.json +2 -2
  522. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +7 -9
  523. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +3 -3
  524. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +2 -2
  525. package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +4 -3
  526. package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +5 -3
  527. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +2 -0
  528. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +1 -1
  529. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +2 -0
  530. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +1 -1
  531. package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +149 -46
  532. package/pipeline/skills/shared/external/monorepo-architect/references/patterns.md +70 -0
  533. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +2 -0
  534. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +1 -1
  535. package/pipeline/skills/shared/external/natural-language/SKILL.md +2 -0
  536. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +3 -2
  537. package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +91 -21
  538. package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +247 -0
  539. package/pipeline/skills/shared/external/nodejs-backend-patterns/references/testing-and-frameworks.md +57 -0
  540. package/pipeline/skills/shared/external/observability-engineer/SKILL.md +155 -232
  541. package/pipeline/skills/shared/external/observability-engineer/references/patterns.md +75 -0
  542. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +2 -0
  543. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +2 -2
  544. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +18 -18
  545. package/pipeline/skills/shared/external/pdfkit/SKILL.md +2 -1
  546. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +2 -0
  547. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +1 -1
  548. package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -0
  549. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +2 -1
  550. package/pipeline/skills/shared/external/push-notifications/SKILL.md +2 -0
  551. package/pipeline/skills/shared/external/python-patterns/SKILL.md +3 -2
  552. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +3 -2
  553. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +2 -2
  554. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +1 -1
  555. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +3 -2
  556. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +7 -7
  557. package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +69 -69
  558. package/pipeline/skills/shared/external/room-database/references/patterns.md +126 -126
  559. package/pipeline/skills/shared/external/search-first/SKILL.md +2 -1
  560. package/pipeline/skills/shared/external/security-review/SKILL.md +4 -3
  561. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +2 -2
  562. package/pipeline/skills/shared/external/signal-community/SKILL.md +1 -1
  563. package/pipeline/skills/shared/external/skill-creator/SKILL.md +2 -1
  564. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +2 -1
  565. package/pipeline/skills/shared/external/spm-build-analysis/SKILL.md +2 -0
  566. package/pipeline/skills/shared/external/storekit/SKILL.md +2 -0
  567. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +2 -0
  568. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +2 -1
  569. package/pipeline/skills/shared/external/swift-charts/SKILL.md +2 -1
  570. package/pipeline/skills/shared/external/swift-codable/SKILL.md +2 -0
  571. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +3 -1
  572. package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +5 -4
  573. package/pipeline/skills/shared/external/swift-concurrency-pro/SKILL.md +2 -1
  574. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +2 -0
  575. package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -1
  576. package/pipeline/skills/shared/external/swift-security/SKILL.md +2 -1
  577. package/pipeline/skills/shared/external/swift-testing/SKILL.md +2 -0
  578. package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +2 -1
  579. package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +10 -0
  580. package/pipeline/skills/shared/external/swiftdata/SKILL.md +2 -0
  581. package/pipeline/skills/shared/external/swiftdata-pro/SKILL.md +2 -1
  582. package/pipeline/skills/shared/external/swiftlint/SKILL.md +2 -0
  583. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +2 -0
  584. package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +3 -1
  585. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +2 -0
  586. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +2 -0
  587. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +2 -0
  588. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +2 -0
  589. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +3 -1
  590. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +3 -1
  591. package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +5 -4
  592. package/pipeline/skills/shared/external/swiftui-pro/SKILL.md +2 -1
  593. package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +5 -4
  594. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +2 -0
  595. package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +4 -3
  596. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +2 -0
  597. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +3 -2
  598. package/pipeline/skills/shared/external/testing-backend/SKILL.md +3 -2
  599. package/pipeline/skills/shared/external/tipkit/SKILL.md +2 -0
  600. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +3 -2
  601. package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -0
  602. package/pipeline/skills/shared/external/vue-composition/SKILL.md +3 -2
  603. package/pipeline/skills/shared/external/weatherkit/SKILL.md +2 -0
  604. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +3 -2
  605. package/pipeline/skills/shared/external/web-performance/SKILL.md +3 -2
  606. package/pipeline/skills/shared/external/web-testing/SKILL.md +3 -2
  607. package/pipeline/skills/shared/external/widgetkit/SKILL.md +2 -0
  608. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +1 -1
  609. package/pipeline/skills/shared/external/xcode-build-benchmark/SKILL.md +2 -0
  610. package/pipeline/skills/shared/external/xcode-build-fixer/SKILL.md +2 -0
  611. package/pipeline/skills/shared/external/xcode-build-orchestrator/SKILL.md +2 -0
  612. package/pipeline/skills/shared/external/xcode-compilation-analyzer/SKILL.md +2 -0
  613. package/pipeline/skills/shared/external/xcode-project-analyzer/SKILL.md +2 -0
  614. package/pipeline/skills/skills-index.md +40 -41
  615. package/docs/token-budget-history.md +0 -24
  616. package/pipeline/skills/shared/external/agentflow/SKILL.md +0 -199
  617. package/pipeline/skills/shared/external/android-ui-verification/SKILL.md +0 -66
  618. package/pipeline/skills/shared/external/api-security-best-practices/references/auth.md +0 -299
  619. package/pipeline/skills/shared/external/api-security-best-practices/references/input-validation.md +0 -255
  620. package/pipeline/skills/shared/external/api-security-best-practices/references/rate-limiting.md +0 -167
  621. package/pipeline/skills/shared/external/closed-loop-delivery/SKILL.md +0 -116
  622. package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -216
@@ -0,0 +1,747 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @file launch-request.mjs - validate a launch request and turn it into the
4
+ * pickers Phase 0 may skip.
5
+ *
6
+ * A client that wants a run started without a terminal conversation writes a
7
+ * request file (launch-request.schema.json) and sets MA_LAUNCH_REQUEST to its
8
+ * path. Phase 0 Step 0.1 calls `resolve`; each answer then stands in for the
9
+ * picker run-questions.json names, and every other picker asks as it always did.
10
+ *
11
+ * With MA_LAUNCH_REQUEST unset the answer is `present: false` with an empty
12
+ * prefill and an empty state patch, so an interactive run writes nothing it did
13
+ * not write before. A variable naming a file that does not exist is the same
14
+ * answer plus a warning: the terminal path is the safe fallback, and a request
15
+ * nobody can read has no answers to apply.
16
+ *
17
+ * A request that IS present and wrong is rejected whole - exit 1, nothing
18
+ * pre-filled. Half-applying one would ask some questions and silently answer
19
+ * others with values nobody validated. The rules, beyond the schema:
20
+ *
21
+ * - every answered id exists in run-questions.json and is answerable;
22
+ * - a static question takes one of its option ids, a run-time-enumerated one
23
+ * a value matching its `answer.pattern`, multi-select an array of them;
24
+ * - `disabled-when` is enforced: `workspace: local` under `mode: autopilot`
25
+ * is rejected, and so is `workspace: local` when `--repo` names a working
26
+ * tree with uncommitted changes (Step 6b would check out a new branch over
27
+ * them). Without `--repo` the tree is reported `unchecked`, and Phase 0
28
+ * re-runs `resolve --repo "$PROJECT_ROOT"` at Step 5b before applying it.
29
+ *
30
+ * Answers are data. Nothing here or in Phase 0 reads an answer as an
31
+ * instruction: an answer selects an option, and a value that is not an option
32
+ * never reaches a picker.
33
+ *
34
+ * The input is data too, and it lands in the prompt of a session started with
35
+ * no permission prompts, so it is held to a shape instead of passed through:
36
+ *
37
+ * - a structured reference: a Jira key, a GitHub issue URL
38
+ * (https://github.com/<owner>/<repo>/issues/<n>), repo#N, #N, or a Jira
39
+ * URL on the configured Jira host (prefs global.hosts.jira). It reaches
40
+ * the prompt as it is;
41
+ * - free text, on the desktop channel only (the bearer route, the CLI, and a
42
+ * request file Phase 0 reads): one line of at most FREE_TEXT_MAX printable
43
+ * characters, no quote, backslash or backtick, reaching the prompt as one
44
+ * double-quoted argument so the dispatcher reads it as a task description.
45
+ * The phone channel takes structured references only.
46
+ *
47
+ * Either way a newline, a control or format character, a leading "-", a token
48
+ * that looks like a flag, and a first token that names a pipeline op or a mode
49
+ * keyword is refused. Only the first token is held to the reserved words: free
50
+ * text reaches the prompt as one quoted argument, so a later word cannot route,
51
+ * and a structured reference is a single token. The op names are the command
52
+ * tree's ids plus the words the dispatcher's routing table routes on; the mode
53
+ * keywords are the modes in phases.json and launch.json, the request modes and
54
+ * the workspace options. Both are read from that data, never listed here. A command tree
55
+ * that cannot be read refuses free text rather than guessing.
56
+ *
57
+ * A launch names its working directory, and only a configured autopilot repo
58
+ * (config.json repos[].localPath) or one the desktop client registered with
59
+ * `register-repo` (launch-repos.json under the autopilot root) is accepted,
60
+ * compared by real path.
61
+ *
62
+ * Zero runtime dependencies (ADR-0004); the schema checks are hand-written and
63
+ * test/launch-request.test.mjs holds them to launch-request.schema.json.
64
+ *
65
+ * `plan` is the other half, for a client that starts the run itself: the argv,
66
+ * environment and working directory launch.json declares for the request's
67
+ * mode, with every placeholder filled. It only prints; nothing here spawns a
68
+ * host. `questions` and `spec` print run-questions.json and launch.json as the
69
+ * contract carries them, so a client reads the same bytes from the CLI as from
70
+ * contract-server.mjs.
71
+ *
72
+ * Usage:
73
+ * node launch-request.mjs validate <file> [--repo <path>]
74
+ * node launch-request.mjs resolve [<file>] [--repo <path>] # file defaults to $MA_LAUNCH_REQUEST
75
+ * node launch-request.mjs plan <file> --repo <path> --session-id <uuid> [--channel desktop|phone] [--redact]
76
+ * node launch-request.mjs questions
77
+ * node launch-request.mjs spec
78
+ * node launch-request.mjs register-repo <absolute path>
79
+ *
80
+ * Output: one JSON object on stdout, always carrying contractVersion.
81
+ * Exit: 0 valid or absent, 1 invalid, 2 usage error, 3 register-repo from an
82
+ * unattended run.
83
+ *
84
+ * @module pipeline/scripts/launch-request
85
+ */
86
+
87
+ import {
88
+ chmodSync,
89
+ existsSync,
90
+ mkdirSync,
91
+ readFileSync,
92
+ realpathSync,
93
+ statSync,
94
+ writeFileSync,
95
+ } from "node:fs";
96
+ import { spawnSync } from "node:child_process";
97
+ import { homedir } from "node:os";
98
+ import { isAbsolute, join } from "node:path";
99
+ import { catalog, commandsDir } from "./commands.mjs";
100
+ import { runMain } from "../lib/fatal.mjs";
101
+ import { invokedDirectly } from "../lib/invoked-directly.mjs";
102
+ import { autopilotRoot, unattendedLogsRoot } from "../lib/pr-request-location.mjs";
103
+ import { lockTimeoutFrom, updateJsonFileSync } from "../lib/json-file-lock.mjs";
104
+ import { unattendedSettingsPath } from "../lib/unattended-settings-location.mjs";
105
+ import { isUnattended } from "../lib/unattended.mjs";
106
+
107
+ export const CONTRACT_VERSION = "1.0.0";
108
+ export const MODES = ["interactive", "autopilot"];
109
+ const TOP_KEYS = ["contractVersion", "input", "mode", "answers"];
110
+
111
+ const readSchemaJson = (name) =>
112
+ JSON.parse(readFileSync(new URL(`../schemas/${name}`, import.meta.url), "utf8"));
113
+
114
+ /** run-questions.json, as the `questions` subcommand prints it. */
115
+ export function questionsDocument() {
116
+ return readSchemaJson("run-questions.json");
117
+ }
118
+
119
+ /** launch.json, as the `spec` subcommand prints it. */
120
+ export function launchSpec() {
121
+ return readSchemaJson("launch.json");
122
+ }
123
+
124
+ export function loadQuestions() {
125
+ return questionsDocument().questions;
126
+ }
127
+
128
+ /**
129
+ * `clean`, `dirty`, or `unreadable` for a working tree. Unreadable counts as
130
+ * dirty wherever it matters: a tree git cannot describe is not one to check a
131
+ * branch out over.
132
+ */
133
+ export function workingTreeState(repo) {
134
+ const r = spawnSync("git", ["-C", repo, "status", "--porcelain"], {
135
+ encoding: "utf8",
136
+ timeout: 10000,
137
+ });
138
+ if (r.status !== 0) return "unreadable";
139
+ return r.stdout.trim() === "" ? "clean" : "dirty";
140
+ }
141
+
142
+ const isString = (v, max) => typeof v === "string" && v.length >= 1 && v.length <= max;
143
+
144
+ export const CHANNELS = ["desktop", "phone"];
145
+ export const FREE_TEXT_MAX = 500;
146
+ const JIRA_KEY = /^[A-Z][A-Z0-9]+-[0-9]+$/;
147
+ const GITHUB_ISSUE_URL =
148
+ /^https:\/\/github\.com\/[A-Za-z0-9][A-Za-z0-9-]{0,38}\/([A-Za-z0-9._-]{1,100})\/issues\/[1-9][0-9]{0,9}$/;
149
+ const REPO_ISSUE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}#[1-9][0-9]{0,9}$/;
150
+ const ISSUE_NUMBER = /^#[1-9][0-9]{0,9}$/;
151
+ const JIRA_URL = /^https:\/\/([A-Za-z0-9.-]+(?::[0-9]{1,5})?)\/browse\/([A-Z][A-Z0-9]+-[0-9]+)$/;
152
+ const UNSAFE_CHAR = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}"\\`]/u;
153
+ const FLAG_TOKEN = /^-/;
154
+
155
+ const normalizeHost = (h) =>
156
+ String(h ?? "")
157
+ .trim()
158
+ .toLowerCase()
159
+ .replace(/^https?:\/\//, "")
160
+ .replace(/\/.*$/, "")
161
+ .replace(/:.*$/, "")
162
+ .replace(/\.$/, "");
163
+
164
+ /** The configured Jira host from prefs, normalized, or "" when there is none. */
165
+ export function configuredJiraHost(env = process.env) {
166
+ const file = env.MA_PREFS_FILE || join(homedir(), ".claude", "multi-agent-preferences.json");
167
+ try {
168
+ return normalizeHost(JSON.parse(readFileSync(file, "utf8"))?.global?.hosts?.jira);
169
+ } catch {
170
+ return "";
171
+ }
172
+ }
173
+
174
+ /** The words the dispatcher's routing table routes on: the first word of each row's pattern. */
175
+ function routingWords(dir) {
176
+ try {
177
+ const text = readFileSync(join(dir, "SKILL.md"), "utf8");
178
+ const start = text.indexOf("\n## Routing");
179
+ if (start === -1) return [];
180
+ const end = text.indexOf("\n## ", start + 1);
181
+ const section = text.slice(start, end === -1 ? undefined : end);
182
+ const words = [];
183
+ for (const line of section.split("\n")) {
184
+ const cell = /^\|\s*([^|]*)\|/.exec(line)?.[1] ?? "";
185
+ for (const m of cell.matchAll(/`([a-z][a-z0-9-]*)(?=[\s`[])/g)) words.push(m[1]);
186
+ }
187
+ return words;
188
+ } catch {
189
+ return [];
190
+ }
191
+ }
192
+
193
+ let reservedCache = null;
194
+
195
+ /**
196
+ * The op names and mode keywords an input may not contain, read from the
197
+ * command tree, the dispatcher, phases.json, launch.json and run-questions.json.
198
+ * `ops` is null when the command tree cannot be read.
199
+ */
200
+ export function reservedWords({ questions, spec } = {}) {
201
+ if (!questions && !spec && reservedCache) return reservedCache;
202
+ const words = computeReservedWords(questions ?? loadQuestions(), spec ?? launchSpec());
203
+ if (!questions && !spec) reservedCache = words;
204
+ return words;
205
+ }
206
+
207
+ function computeReservedWords(questions, spec) {
208
+ const dir = commandsDir();
209
+ const cat = catalog();
210
+ const ops = cat && dir ? new Set([...cat.commands.map((c) => c.id), ...routingWords(dir)]) : null;
211
+ const modes = new Set([
212
+ ...MODES,
213
+ ...Object.keys(readSchemaJson("phases.json").modes ?? {}),
214
+ ...Object.values(spec.hosts ?? {}).flatMap((h) => Object.keys(h.modes ?? {})),
215
+ ...(questions.find((q) => q.id === "workspace")?.options ?? []).map((o) => o.id),
216
+ ]);
217
+ return { ops, modes };
218
+ }
219
+
220
+ /**
221
+ * Which structured reference an input is, or null when it is none of them.
222
+ * A Jira URL counts only on `jiraHost`.
223
+ */
224
+ export function structuredKind(input, jiraHost = "") {
225
+ if (typeof input !== "string") return null;
226
+ if (JIRA_KEY.test(input)) return "jira-id";
227
+ const gh = GITHUB_ISSUE_URL.exec(input);
228
+ if (gh) return /^\.+$/.test(gh[1]) ? null : "gh-url";
229
+ if (REPO_ISSUE.test(input)) return "gh-short";
230
+ if (ISSUE_NUMBER.test(input)) return "gh-num";
231
+ const jira = JIRA_URL.exec(input);
232
+ if (jira && jiraHost && normalizeHost(jira[1]) === normalizeHost(jiraHost)) return "jira-url";
233
+ return null;
234
+ }
235
+
236
+ /**
237
+ * Every reason `input` may not start a run on `channel`. Pure apart from the
238
+ * reserved words, which are handed in.
239
+ */
240
+ export function inputErrors(input, { channel = "desktop", jiraHost = "", reserved } = {}) {
241
+ if (!isString(input, 4000))
242
+ return ["input must be a non-empty string of at most 4000 characters"];
243
+ const errors = [];
244
+ if (UNSAFE_CHAR.test(input)) {
245
+ errors.push(
246
+ "input may not carry a newline, a control or format character, a quote, a backslash or a backtick",
247
+ );
248
+ }
249
+ if (FLAG_TOKEN.test(input)) errors.push('input may not start with "-"');
250
+ const { ops, modes } = reserved ?? reservedWords();
251
+ const tokens = input.split(/\s+/).filter(Boolean);
252
+ for (const raw of tokens) {
253
+ if (FLAG_TOKEN.test(raw) && raw !== input) errors.push(`input may not carry a flag (${raw})`);
254
+ }
255
+ const first = (tokens[0] ?? "").toLowerCase().replace(/^[^a-z0-9-]+|[^a-z0-9-]+$/g, "");
256
+ if (ops?.has(first)) errors.push(`input may not start with the pipeline op "${first}"`);
257
+ if (modes.has(first)) errors.push(`input may not start with the mode keyword "${first}"`);
258
+ if (errors.length) return [...new Set(errors)];
259
+ if (structuredKind(input, jiraHost)) return [];
260
+ if (channel === "phone") {
261
+ return [
262
+ "the phone channel takes a structured input only: a Jira key, a GitHub issue URL, repo#N, #N, or a Jira URL on the configured host",
263
+ ];
264
+ }
265
+ if (!ops) return ["free text cannot be checked without the command tree; use a structured input"];
266
+ if (input.length > FREE_TEXT_MAX) return [`free text is at most ${FREE_TEXT_MAX} characters`];
267
+ if (input.trim() !== input || /^[/#]/.test(input) || !/\p{L}/u.test(input)) {
268
+ return ["free text is a task description: no leading or trailing space, no leading / or #"];
269
+ }
270
+ if (!/\s/.test(input)) {
271
+ return ["a single word that is not a structured reference is refused; free text is a sentence"];
272
+ }
273
+ if (/[a-z][a-z0-9+.-]*:\/\//i.test(input)) {
274
+ return ["free text may not carry a URL; a GitHub or Jira link is sent as the whole input"];
275
+ }
276
+ return [];
277
+ }
278
+
279
+ /** The input as the prompt receives it: a structured reference as is, free text quoted. */
280
+ export function promptArgument(input, jiraHost = "") {
281
+ return structuredKind(input, jiraHost) ? input : `"${input}"`;
282
+ }
283
+
284
+ /**
285
+ * Every reason a request is not acceptable. Pure: the working-tree state is
286
+ * handed in, so the rule is testable without a repository.
287
+ *
288
+ * @param {unknown} req
289
+ * @param {{questions?: object[], workingTree?: "clean"|"dirty"|"unreadable"|"unchecked",
290
+ * channel?: "desktop"|"phone", jiraHost?: string}} [opts]
291
+ * @returns {string[]}
292
+ */
293
+ export function validateRequest(req, opts = {}) {
294
+ const questions = opts.questions ?? loadQuestions();
295
+ const workingTree = opts.workingTree ?? "unchecked";
296
+ const channel = opts.channel ?? "desktop";
297
+ const jiraHost = opts.jiraHost ?? configuredJiraHost();
298
+ const errors = [];
299
+ if (!req || typeof req !== "object" || Array.isArray(req))
300
+ return ["request is not a JSON object"];
301
+
302
+ for (const k of Object.keys(req)) {
303
+ if (!TOP_KEYS.includes(k)) errors.push(`unknown field ${k}`);
304
+ }
305
+ if (typeof req.contractVersion !== "string" || !/^1\.[0-9]+\.[0-9]+$/.test(req.contractVersion)) {
306
+ errors.push(`contractVersion must be 1.x.y (this pipeline speaks ${CONTRACT_VERSION})`);
307
+ }
308
+ if (!CHANNELS.includes(channel)) errors.push(`channel must be ${CHANNELS.join(" | ")}`);
309
+ else errors.push(...inputErrors(req.input, { channel, jiraHost, reserved: opts.reserved }));
310
+ if (!MODES.includes(req.mode)) errors.push(`mode must be ${MODES.join(" | ")}`);
311
+ const answers = req.answers;
312
+ if (!answers || typeof answers !== "object" || Array.isArray(answers)) {
313
+ errors.push("answers must be an object");
314
+ return errors;
315
+ }
316
+
317
+ const byId = new Map(questions.map((q) => [q.id, q]));
318
+ for (const [id, value] of Object.entries(answers)) {
319
+ const q = byId.get(id);
320
+ if (!q) {
321
+ errors.push(`answers.${id}: no such question in run-questions.json`);
322
+ continue;
323
+ }
324
+ if (!q.answerable) {
325
+ errors.push(`answers.${id}: this question is always asked and cannot be pre-filled`);
326
+ continue;
327
+ }
328
+ const multi = q.kind === "multi-select";
329
+ const values = multi ? value : [value];
330
+ if (multi && !Array.isArray(value)) {
331
+ errors.push(`answers.${id}: a multi-select answer is an array`);
332
+ continue;
333
+ }
334
+ if (!multi && typeof value !== "string") {
335
+ errors.push(`answers.${id}: a single-select answer is one string`);
336
+ continue;
337
+ }
338
+ for (const v of values) {
339
+ if (!isString(v, 200)) {
340
+ errors.push(`answers.${id}: every value is a non-empty string of at most 200 characters`);
341
+ } else if (q.options && !q.options.some((o) => o.id === v)) {
342
+ errors.push(`answers.${id}: "${v}" is not one of ${q.options.map((o) => o.id).join(", ")}`);
343
+ } else if (!q.options && q.answer && !new RegExp(q.answer.pattern).test(v)) {
344
+ errors.push(`answers.${id}: "${v}" does not match ${q.answer.pattern}`);
345
+ }
346
+ }
347
+ for (const rule of q["disabled-when"] ?? []) {
348
+ if (!values.includes(rule.option)) continue;
349
+ if (rule.mode && rule.mode === req.mode) {
350
+ errors.push(`answers.${id}: "${rule.option}" is not allowed in ${rule.mode} mode`);
351
+ }
352
+ if (
353
+ rule.workingTree === "dirty" &&
354
+ (workingTree === "dirty" || workingTree === "unreadable")
355
+ ) {
356
+ errors.push(
357
+ `answers.${id}: "${rule.option}" is not allowed on a working tree with uncommitted changes`,
358
+ );
359
+ }
360
+ }
361
+ }
362
+ return errors;
363
+ }
364
+
365
+ /**
366
+ * What Phase 0 applies: the pre-filled pickers and the one state field that
367
+ * records a request was used. Called only on a request validateRequest passed.
368
+ */
369
+ export function prefillFor(req, questions = loadQuestions(), now = new Date()) {
370
+ const byId = new Map(questions.map((q) => [q.id, q]));
371
+ const prefill = {};
372
+ for (const [id, answer] of Object.entries(req.answers)) {
373
+ const q = byId.get(id);
374
+ prefill[id] = {
375
+ answer,
376
+ askedAt: q["asked-at"],
377
+ ...(q.stateField ? { stateField: q.stateField } : {}),
378
+ };
379
+ }
380
+ return {
381
+ prefill,
382
+ statePatch: {
383
+ launchRequest: {
384
+ contractVersion: req.contractVersion,
385
+ mode: req.mode,
386
+ answered: Object.keys(req.answers).sort(),
387
+ resolvedAt: now.toISOString(),
388
+ },
389
+ },
390
+ };
391
+ }
392
+
393
+ /**
394
+ * The whole resolve step as data, so the CLI and the tests read one answer.
395
+ *
396
+ * @param {{file?: string|null, repo?: string|null, env?: object, questions?: object[]}} args
397
+ */
398
+ export function resolveRequest({ file = null, repo = null, env = process.env, questions } = {}) {
399
+ const qs = questions ?? loadQuestions();
400
+ const path = file || env.MA_LAUNCH_REQUEST || "";
401
+ const absent = { contractVersion: CONTRACT_VERSION, present: false, prefill: {}, statePatch: {} };
402
+ if (!path) return { code: 0, out: absent };
403
+ if (!existsSync(path)) {
404
+ return { code: 0, out: { ...absent, warning: "request-file-missing" } };
405
+ }
406
+ let req;
407
+ try {
408
+ req = JSON.parse(readFileSync(path, "utf8"));
409
+ } catch {
410
+ return {
411
+ code: 1,
412
+ out: {
413
+ contractVersion: CONTRACT_VERSION,
414
+ present: true,
415
+ valid: false,
416
+ errors: ["request is not valid JSON"],
417
+ },
418
+ };
419
+ }
420
+ const workingTree = repo ? workingTreeState(repo) : "unchecked";
421
+ const errors = validateRequest(req, { questions: qs, workingTree });
422
+ if (errors.length) {
423
+ return {
424
+ code: 1,
425
+ out: { contractVersion: CONTRACT_VERSION, present: true, valid: false, errors },
426
+ };
427
+ }
428
+ return {
429
+ code: 0,
430
+ out: {
431
+ contractVersion: CONTRACT_VERSION,
432
+ present: true,
433
+ valid: true,
434
+ input: req.input,
435
+ mode: req.mode,
436
+ workingTree,
437
+ ...prefillFor(req, qs),
438
+ },
439
+ };
440
+ }
441
+
442
+ export const SESSION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
443
+
444
+ /** Where request files live, per launch.json requestFile.directory. */
445
+ export function requestsDir(env = process.env) {
446
+ return env.MA_AUTOPILOT_ROOT
447
+ ? join(env.MA_AUTOPILOT_ROOT, "requests")
448
+ : join(homedir(), ".claude", "autopilot", "requests");
449
+ }
450
+
451
+ /**
452
+ * Write a request file the way launch.json says a client does: named for the
453
+ * session, mode 0600, in a 0700 directory, never over an existing file.
454
+ * Returns the path. Called only with a request validateRequest passed.
455
+ */
456
+ export function writeRequestFile(req, sessionId, env = process.env) {
457
+ if (!SESSION_ID.test(sessionId)) throw new Error("session id is not a UUID");
458
+ const dir = requestsDir(env);
459
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
460
+ chmodSync(dir, 0o700);
461
+ const path = join(dir, `${sessionId}.json`);
462
+ writeFileSync(path, JSON.stringify(req, null, 2) + "\n", { mode: 0o600, flag: "wx" });
463
+ return path;
464
+ }
465
+
466
+ /** Where the desktop client's registered launch repos live. */
467
+ export const launchReposPath = (env = process.env) => join(autopilotRoot(env), "launch-repos.json");
468
+
469
+ const realDir = (p) => {
470
+ try {
471
+ const real = realpathSync(p);
472
+ return statSync(real).isDirectory() ? real : null;
473
+ } catch {
474
+ return null;
475
+ }
476
+ };
477
+
478
+ const expandHome = (p) => String(p ?? "").replace(/^~(?=\/|$)/, homedir());
479
+
480
+ function readJsonOr(file, fallback) {
481
+ try {
482
+ return JSON.parse(readFileSync(file, "utf8"));
483
+ } catch {
484
+ return fallback;
485
+ }
486
+ }
487
+
488
+ /** Real paths a launch may name: configured autopilot repos and registered ones. */
489
+ export function allowedLaunchRepos(env = process.env) {
490
+ const config = readJsonOr(join(autopilotRoot(env), "config.json"), {});
491
+ const registered = readJsonOr(launchReposPath(env), {});
492
+ const paths = [
493
+ ...(Array.isArray(config?.repos) ? config.repos.map((r) => r?.localPath) : []),
494
+ ...(Array.isArray(registered?.repos) ? registered.repos : []),
495
+ ];
496
+ return new Set(
497
+ paths
498
+ .filter((p) => typeof p === "string" && p)
499
+ .map((p) => realDir(expandHome(p)))
500
+ .filter(Boolean),
501
+ );
502
+ }
503
+
504
+ /** Is `repoPath` a directory a launch may start in? Compared by real path. */
505
+ export function launchRepoAllowed(repoPath, env = process.env) {
506
+ const real = typeof repoPath === "string" && isAbsolute(repoPath) ? realDir(repoPath) : null;
507
+ return Boolean(real) && allowedLaunchRepos(env).has(real);
508
+ }
509
+
510
+ /**
511
+ * Add a checkout to launch-repos.json: an absolute directory that is not the
512
+ * home directory or the filesystem root, stored by real path in a 0600 file.
513
+ * The read-modify-write holds the file's lock and replaces it atomically, so
514
+ * two registrations at once both land. Returns the stored path.
515
+ */
516
+ export function registerRepo(repoPath, env = process.env) {
517
+ if (typeof repoPath !== "string" || !isAbsolute(repoPath))
518
+ throw new Error("the path must be absolute");
519
+ const real = realDir(repoPath);
520
+ if (!real) throw new Error("the path is not a directory");
521
+ if (real === "/" || real === realDir(homedir())) {
522
+ throw new Error("the home directory or the root is not a repository");
523
+ }
524
+ const file = launchReposPath(env);
525
+ mkdirSync(autopilotRoot(env), { recursive: true, mode: 0o700 });
526
+ updateJsonFileSync(
527
+ file,
528
+ (current) => {
529
+ const repos = new Set(Array.isArray(current?.repos) ? current.repos : []);
530
+ repos.add(real);
531
+ return { repos: [...repos].sort() };
532
+ },
533
+ { fallback: {}, mode: 0o600, timeoutMs: lockTimeoutFrom(env) },
534
+ );
535
+ return real;
536
+ }
537
+
538
+ /** The launch-plan fields that name this machine, dropped under redact. */
539
+ export const LOCAL_PLAN_FIELDS = ["requestFile", "cwd", "argv", "env"];
540
+
541
+ const fill = (template, values) =>
542
+ template.replace(/\{([a-zA-Z]+)\}/g, (whole, k) => (k in values ? values[k] : whole));
543
+
544
+ /**
545
+ * What a client runs to start this request unattended, from launch.json. Pure
546
+ * apart from the working-tree state, which is handed in.
547
+ *
548
+ * @param {{request: object, requestFile: string, repoPath: string, sessionId: string,
549
+ * workingTree?: string, spec?: object, questions?: object[], redact?: boolean,
550
+ * channel?: "desktop"|"phone", jiraHost?: string, settingsFile?: string,
551
+ * runLogsRoot?: string}} args
552
+ * @returns {{code: number, reason?: string, out: object}}
553
+ */
554
+ export function planLaunch({
555
+ request,
556
+ requestFile,
557
+ repoPath,
558
+ sessionId,
559
+ settingsFile = unattendedSettingsPath(),
560
+ runLogsRoot = unattendedLogsRoot(),
561
+ workingTree = "unchecked",
562
+ spec = launchSpec(),
563
+ questions,
564
+ redact = false,
565
+ channel = "desktop",
566
+ jiraHost = configuredJiraHost(),
567
+ }) {
568
+ const errors = validateRequest(request, { questions, workingTree, channel, jiraHost });
569
+ if (!SESSION_ID.test(String(sessionId ?? ""))) errors.push("session id must be a UUID");
570
+ if (typeof repoPath !== "string" || !isAbsolute(repoPath)) {
571
+ errors.push("the repository path must be absolute");
572
+ }
573
+ if (errors.length) {
574
+ return {
575
+ code: 1,
576
+ reason: "invalid-request",
577
+ out: { contractVersion: CONTRACT_VERSION, valid: false, errors },
578
+ };
579
+ }
580
+ const host = spec.hosts.claude;
581
+ const shape = host.supported ? host.modes?.[request.mode] : undefined;
582
+ if (!shape) {
583
+ return {
584
+ code: 1,
585
+ reason: "no-launch-shape",
586
+ out: {
587
+ contractVersion: CONTRACT_VERSION,
588
+ valid: false,
589
+ errors: [`launch.json declares no unattended launch for mode ${request.mode}`],
590
+ },
591
+ };
592
+ }
593
+ const values = {
594
+ input: promptArgument(request.input, jiraHost),
595
+ sessionId,
596
+ requestFile,
597
+ repoPath,
598
+ settingsFile,
599
+ runLogsRoot,
600
+ };
601
+ const plan = {
602
+ contractVersion: CONTRACT_VERSION,
603
+ valid: true,
604
+ verified: spec.verified === true,
605
+ host: "claude",
606
+ mode: request.mode,
607
+ sessionId,
608
+ requestFile,
609
+ bin: host.bin,
610
+ cwd: fill(host.cwd, values),
611
+ argv: shape.argv.map((a) => fill(a, values)),
612
+ env: Object.fromEntries(Object.entries(shape.env).map(([k, v]) => [k, fill(v, values)])),
613
+ shell: false,
614
+ };
615
+ if (redact) for (const k of LOCAL_PLAN_FIELDS) delete plan[k];
616
+ return { code: 0, out: plan };
617
+ }
618
+
619
+ function planMain(rest) {
620
+ let file = null;
621
+ let repo = null;
622
+ let sessionId = null;
623
+ let redact = false;
624
+ let channel = "desktop";
625
+ for (let i = 0; i < rest.length; i++) {
626
+ if (rest[i] === "--repo") repo = rest[++i] ?? null;
627
+ else if (rest[i] === "--session-id") sessionId = rest[++i] ?? null;
628
+ else if (rest[i] === "--redact") redact = true;
629
+ else if (rest[i] === "--channel") channel = rest[++i] ?? "";
630
+ else if (!file && !rest[i].startsWith("--")) file = rest[i];
631
+ else {
632
+ process.stderr.write(`launch-request: unknown argument ${rest[i]}\n`);
633
+ return 2;
634
+ }
635
+ }
636
+ if (!file || !repo || !sessionId || !CHANNELS.includes(channel)) {
637
+ process.stderr.write(
638
+ `usage: launch-request.mjs plan <file> --repo <path> --session-id <uuid> [--channel ${CHANNELS.join("|")}] [--redact]\n`,
639
+ );
640
+ return 2;
641
+ }
642
+ let request;
643
+ try {
644
+ request = JSON.parse(readFileSync(file, "utf8"));
645
+ } catch {
646
+ process.stderr.write("launch-request: the request file is missing or not JSON\n");
647
+ return 1;
648
+ }
649
+ if (!launchRepoAllowed(repo)) {
650
+ const out = {
651
+ contractVersion: CONTRACT_VERSION,
652
+ valid: false,
653
+ errors: ["the repository is neither a configured autopilot repo nor a registered one"],
654
+ };
655
+ process.stdout.write(JSON.stringify(out, null, 2) + "\n");
656
+ return 1;
657
+ }
658
+ const { code, out } = planLaunch({
659
+ request,
660
+ requestFile: file,
661
+ repoPath: repo,
662
+ sessionId,
663
+ workingTree: workingTreeState(repo),
664
+ redact,
665
+ channel,
666
+ });
667
+ process.stdout.write(JSON.stringify(out, null, 2) + "\n");
668
+ return code;
669
+ }
670
+
671
+ function registerMain(rest) {
672
+ if (rest.length !== 1) {
673
+ process.stderr.write("usage: launch-request.mjs register-repo <absolute path>\n");
674
+ return 2;
675
+ }
676
+ if (isUnattended()) {
677
+ process.stderr.write(
678
+ "launch-request: an unattended run may not register a launch repository\n",
679
+ );
680
+ return 3;
681
+ }
682
+ try {
683
+ const stored = registerRepo(rest[0]);
684
+ process.stdout.write(
685
+ JSON.stringify({ contractVersion: CONTRACT_VERSION, registered: stored }) + "\n",
686
+ );
687
+ return 0;
688
+ } catch (err) {
689
+ process.stderr.write(`launch-request: ${err.message}\n`);
690
+ return 2;
691
+ }
692
+ }
693
+
694
+ function main(argv) {
695
+ const [cmd, ...rest] = argv;
696
+ if (cmd === "questions" || cmd === "spec") {
697
+ if (rest.length) {
698
+ process.stderr.write(`launch-request: ${cmd} takes no arguments\n`);
699
+ return 2;
700
+ }
701
+ const doc = cmd === "questions" ? questionsDocument() : launchSpec();
702
+ process.stdout.write(JSON.stringify(doc, null, 2) + "\n");
703
+ return 0;
704
+ }
705
+ if (cmd === "plan") return planMain(rest);
706
+ if (cmd === "register-repo") return registerMain(rest);
707
+ let file = null;
708
+ let repo = null;
709
+ for (let i = 0; i < rest.length; i++) {
710
+ if (rest[i] === "--repo") repo = rest[++i] ?? null;
711
+ else if (!file && !rest[i].startsWith("--")) file = rest[i];
712
+ else {
713
+ process.stderr.write(`launch-request: unknown argument ${rest[i]}\n`);
714
+ return 2;
715
+ }
716
+ }
717
+ if (cmd !== "validate" && cmd !== "resolve") {
718
+ process.stderr.write(
719
+ "usage: launch-request.mjs validate <file> | resolve [<file>] [--repo <path>] | plan <file> --repo <path> --session-id <uuid> [--channel desktop|phone] | questions | spec | register-repo <path>\n",
720
+ );
721
+ return 2;
722
+ }
723
+ if (cmd === "validate" && !file) {
724
+ process.stderr.write("launch-request: validate needs a file\n");
725
+ return 2;
726
+ }
727
+ if (cmd === "validate" && !existsSync(file)) {
728
+ const out = {
729
+ contractVersion: CONTRACT_VERSION,
730
+ present: false,
731
+ valid: false,
732
+ errors: ["no such file"],
733
+ };
734
+ process.stdout.write(JSON.stringify(out, null, 2) + "\n");
735
+ return 1;
736
+ }
737
+ const { code, out } = resolveRequest({ file, repo });
738
+ if (out.warning) process.stderr.write(`launch-request: ${out.warning}, continuing without it\n`);
739
+ process.stdout.write(JSON.stringify(out, null, 2) + "\n");
740
+ return code;
741
+ }
742
+
743
+ if (invokedDirectly(import.meta.url)) {
744
+ runMain("launch-request", () => {
745
+ process.exitCode = main(process.argv.slice(2));
746
+ });
747
+ }