@mmerterden/multi-agent-pipeline 20.2.1 → 20.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (621) hide show
  1. package/CHANGELOG.md +912 -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 +616 -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/user-facing.mjs +82 -0
  148. package/pipeline/lib/user-facing.sh +58 -0
  149. package/pipeline/multi-agent-refs/_dev-context.md +1 -1
  150. package/pipeline/multi-agent-refs/analysis/evidence.md +4 -0
  151. package/pipeline/multi-agent-refs/analysis/locked.md +2 -2
  152. package/pipeline/multi-agent-refs/analysis/render.md +4 -3
  153. package/pipeline/multi-agent-refs/analysis/resolve.md +3 -1
  154. package/pipeline/multi-agent-refs/analysis/synthesis.md +4 -5
  155. package/pipeline/multi-agent-refs/analysis-template.md +10 -17
  156. package/pipeline/multi-agent-refs/channels/jira.md +1 -1
  157. package/pipeline/multi-agent-refs/component-dispatch.md +3 -3
  158. package/pipeline/multi-agent-refs/conventions-defaults.md +32 -32
  159. package/pipeline/multi-agent-refs/cross-cli-contract.md +10 -17
  160. package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +37 -9
  161. package/pipeline/multi-agent-refs/features/autopilot-operations.md +277 -0
  162. package/pipeline/multi-agent-refs/features/constitution.md +196 -0
  163. package/pipeline/multi-agent-refs/features/doctor.md +6 -3
  164. package/pipeline/multi-agent-refs/features/external-context-injection.md +6 -1
  165. package/pipeline/multi-agent-refs/features/jira-context.md +1 -1
  166. package/pipeline/multi-agent-refs/features/maturity-followup.md +43 -23
  167. package/pipeline/multi-agent-refs/features/model-fallback.md +9 -0
  168. package/pipeline/multi-agent-refs/features/phone-api.md +306 -0
  169. package/pipeline/multi-agent-refs/features/plan-critic.md +159 -0
  170. package/pipeline/multi-agent-refs/features/research.md +150 -0
  171. package/pipeline/multi-agent-refs/features/review-decision.md +185 -0
  172. package/pipeline/multi-agent-refs/features/scaffold.md +160 -0
  173. package/pipeline/multi-agent-refs/features/security-audit.md +6 -2
  174. package/pipeline/multi-agent-refs/features/skill-conformance.md +4 -1
  175. package/pipeline/multi-agent-refs/features/stack-adapters.md +116 -0
  176. package/pipeline/multi-agent-refs/features/unattended-gates.md +316 -0
  177. package/pipeline/multi-agent-refs/features/unattended-security.md +731 -0
  178. package/pipeline/multi-agent-refs/features/url-enrichment.md +2 -2
  179. package/pipeline/multi-agent-refs/features/usage-reporting.md +127 -35
  180. package/pipeline/multi-agent-refs/features/verify-by-test.md +1 -1
  181. package/pipeline/multi-agent-refs/features/visual-evidence.md +7 -7
  182. package/pipeline/multi-agent-refs/keychain.md +6 -11
  183. package/pipeline/multi-agent-refs/payload-contracts.md +2 -2
  184. package/pipeline/multi-agent-refs/phases/log-format.md +2 -3
  185. package/pipeline/multi-agent-refs/phases/modes.md +10 -12
  186. package/pipeline/multi-agent-refs/phases/operations.md +11 -5
  187. package/pipeline/multi-agent-refs/phases/phase-0-init.md +73 -81
  188. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +22 -22
  189. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +42 -66
  190. package/pipeline/multi-agent-refs/phases/phase-3-review.md +45 -79
  191. package/pipeline/multi-agent-refs/phases/phase-4-commit.md +28 -38
  192. package/pipeline/multi-agent-refs/phases/phase-5-report.md +27 -25
  193. package/pipeline/multi-agent-refs/phases.md +1 -1
  194. package/pipeline/multi-agent-refs/picker-contract.md +1 -1
  195. package/pipeline/multi-agent-refs/progress-contract.md +13 -16
  196. package/pipeline/multi-agent-refs/readiness-review.md +1 -1
  197. package/pipeline/multi-agent-refs/research/engine.md +91 -0
  198. package/pipeline/multi-agent-refs/rules.md +6 -4
  199. package/pipeline/multi-agent-refs/setup/repo-discovery.md +2 -2
  200. package/pipeline/multi-agent-refs/tracker-contract.md +2 -2
  201. package/pipeline/multi-agent-refs/unattended-contract.md +68 -16
  202. package/pipeline/rules/figma-pipeline.md +12 -12
  203. package/pipeline/schemas/agent-state.schema.json +480 -18
  204. package/pipeline/schemas/analysis-spec.schema.json +4 -4
  205. package/pipeline/schemas/answer-request.schema.json +24 -0
  206. package/pipeline/schemas/answer-result.schema.json +28 -0
  207. package/pipeline/schemas/autopilot-config.schema.json +111 -13
  208. package/pipeline/schemas/command-parameters.schema.json +99 -0
  209. package/pipeline/schemas/constitution.schema.json +56 -0
  210. package/pipeline/schemas/contract-error.schema.json +52 -0
  211. package/pipeline/schemas/design-check-config.schema.json +5 -1
  212. package/pipeline/schemas/issues.schema.json +61 -0
  213. package/pipeline/schemas/launch-plan.schema.json +46 -0
  214. package/pipeline/schemas/launch-request.schema.json +45 -0
  215. package/pipeline/schemas/launch.json +61 -0
  216. package/pipeline/schemas/launch.schema.json +84 -0
  217. package/pipeline/schemas/phases.json +2 -2
  218. package/pipeline/schemas/phases.schema.json +68 -0
  219. package/pipeline/schemas/phone-devices.schema.json +61 -0
  220. package/pipeline/schemas/phone-signed-request.schema.json +67 -0
  221. package/pipeline/schemas/plan-critique.schema.json +99 -0
  222. package/pipeline/schemas/plan-todos.schema.json +7 -7
  223. package/pipeline/schemas/planning-output.schema.json +5 -0
  224. package/pipeline/schemas/pr-request.schema.json +46 -0
  225. package/pipeline/schemas/prefs.schema.json +79 -8
  226. package/pipeline/schemas/research-output.schema.json +118 -0
  227. package/pipeline/schemas/review-file-exclusions.schema.json +25 -0
  228. package/pipeline/schemas/reviewer-output.schema.json +40 -4
  229. package/pipeline/schemas/run-questions.json +392 -0
  230. package/pipeline/schemas/run-questions.schema.json +118 -0
  231. package/pipeline/schemas/runs-index.schema.json +189 -0
  232. package/pipeline/schemas/scaffold-manifest.schema.json +43 -0
  233. package/pipeline/schemas/secret-patterns.schema.json +28 -0
  234. package/pipeline/schemas/stack-adapters.json +527 -0
  235. package/pipeline/schemas/stack-adapters.schema.json +184 -0
  236. package/pipeline/schemas/token-budget.json +1 -1
  237. package/pipeline/schemas/token-budget.schema.json +26 -0
  238. package/pipeline/schemas/triage-output.schema.json +64 -3
  239. package/pipeline/schemas/unattended-policy.json +139 -0
  240. package/pipeline/schemas/unattended-policy.schema.json +73 -0
  241. package/pipeline/schemas/unattended-profile.json +248 -0
  242. package/pipeline/schemas/unattended-profile.schema.json +198 -0
  243. package/pipeline/schemas/worktrees.schema.json +51 -0
  244. package/pipeline/scripts/README.md +1 -0
  245. package/pipeline/scripts/_autopilot-config.mjs +130 -0
  246. package/pipeline/scripts/_autopilot-ops.mjs +567 -0
  247. package/pipeline/scripts/_autopilot-outcomes.mjs +174 -0
  248. package/pipeline/scripts/_command-contract.mjs +384 -0
  249. package/pipeline/scripts/_cost.mjs +40 -0
  250. package/pipeline/scripts/_notices.mjs +160 -0
  251. package/pipeline/scripts/_phone-auth.mjs +485 -0
  252. package/pipeline/scripts/_pre-existing.mjs +294 -0
  253. package/pipeline/scripts/_redact.mjs +77 -0
  254. package/pipeline/scripts/_run-paths.mjs +4 -2
  255. package/pipeline/scripts/_stack-adapter.mjs +678 -0
  256. package/pipeline/scripts/_stack-routing.mjs +1 -1
  257. package/pipeline/scripts/agent-guard.py +348 -37
  258. package/pipeline/scripts/agent-guard.sh +41 -13
  259. package/pipeline/scripts/analysis-story-tree.mjs +79 -3
  260. package/pipeline/scripts/answer-question.mjs +181 -0
  261. package/pipeline/scripts/audit-log-rotate.sh +1 -4
  262. package/pipeline/scripts/audit-log.sh +4 -4
  263. package/pipeline/scripts/autopilot-arming.mjs +389 -21
  264. package/pipeline/scripts/autopilot-awake.mjs +255 -0
  265. package/pipeline/scripts/autopilot-intake.mjs +137 -36
  266. package/pipeline/scripts/autopilot-menubar.swift +156 -44
  267. package/pipeline/scripts/autopilot-publish.mjs +1625 -0
  268. package/pipeline/scripts/autopilot-runner.mjs +1678 -222
  269. package/pipeline/scripts/autopilot-status.sh +198 -33
  270. package/pipeline/scripts/build-lock.sh +120 -0
  271. package/pipeline/scripts/build-references.mjs +4 -1
  272. package/pipeline/scripts/build-stack-plugins.mjs +59 -22
  273. package/pipeline/scripts/capture-flush.sh +1 -1
  274. package/pipeline/scripts/capture-resume.sh +13 -9
  275. package/pipeline/scripts/check-derived-drift.mjs +52 -11
  276. package/pipeline/scripts/commands.mjs +88 -0
  277. package/pipeline/scripts/constitution.mjs +362 -0
  278. package/pipeline/scripts/contract-server.mjs +776 -0
  279. package/pipeline/scripts/cost-analyze.mjs +89 -39
  280. package/pipeline/scripts/diff-explain.mjs +12 -1
  281. package/pipeline/scripts/doctor.mjs +77 -28
  282. package/pipeline/scripts/evidence-gate.mjs +192 -12
  283. package/pipeline/scripts/feedback-send.mjs +4 -2
  284. package/pipeline/scripts/gate-ledger.mjs +449 -0
  285. package/pipeline/scripts/gc-abandoned.sh +132 -13
  286. package/pipeline/scripts/gen-facts.mjs +31 -15
  287. package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
  288. package/pipeline/scripts/github-ssh-setup.sh +140 -29
  289. package/pipeline/scripts/graph-mermaid.mjs +4 -1
  290. package/pipeline/scripts/issues.mjs +236 -0
  291. package/pipeline/scripts/jira-attach.sh +6 -2
  292. package/pipeline/scripts/jira-search.sh +4 -3
  293. package/pipeline/scripts/keychain-save.sh +125 -24
  294. package/pipeline/scripts/keychain.py +63 -93
  295. package/pipeline/scripts/launch-request.mjs +747 -0
  296. package/pipeline/scripts/localize-commands.mjs +4 -10
  297. package/pipeline/scripts/log-metric.sh +6 -5
  298. package/pipeline/scripts/maturity-followup.mjs +13 -4
  299. package/pipeline/scripts/memory-save.sh +25 -0
  300. package/pipeline/scripts/migrate-prefs.mjs +4 -3
  301. package/pipeline/scripts/open-questions-gate.mjs +276 -0
  302. package/pipeline/scripts/phase-tracker.sh +41 -27
  303. package/pipeline/scripts/phase0-exit-gate.mjs +22 -4
  304. package/pipeline/scripts/phone-devices.mjs +224 -0
  305. package/pipeline/scripts/plan-coverage-gate.mjs +200 -66
  306. package/pipeline/scripts/plan-critique-gate.mjs +591 -0
  307. package/pipeline/scripts/pr-request.mjs +188 -0
  308. package/pipeline/scripts/pre-commit-check.sh +115 -4
  309. package/pipeline/scripts/probe-evidence-capability.sh +44 -5
  310. package/pipeline/scripts/record-phase.mjs +71 -0
  311. package/pipeline/scripts/render-agent-log-cost.sh +17 -2
  312. package/pipeline/scripts/render-cost-summary.sh +1 -1
  313. package/pipeline/scripts/render-work-summary.sh +1 -1
  314. package/pipeline/scripts/require-supported-version.sh +4 -1
  315. package/pipeline/scripts/research-gate.mjs +704 -0
  316. package/pipeline/scripts/review-decision-gate.mjs +403 -0
  317. package/pipeline/scripts/routine-registry.mjs +5 -2
  318. package/pipeline/scripts/runs-index.mjs +135 -27
  319. package/pipeline/scripts/scaffold-gate.mjs +393 -0
  320. package/pipeline/scripts/skill-conformance.mjs +25 -8
  321. package/pipeline/scripts/skill-siblings.mjs +2 -1
  322. package/pipeline/scripts/smoke-cross-cli-behavior.sh +32 -6
  323. package/pipeline/scripts/smoke-schema-validation.sh +6 -2
  324. package/pipeline/scripts/spec-consistency-gate.mjs +469 -0
  325. package/pipeline/scripts/symbol-existence-gate.mjs +450 -0
  326. package/pipeline/scripts/test-gap-scan.mjs +40 -2
  327. package/pipeline/scripts/test-integrity-gate.mjs +20 -4
  328. package/pipeline/scripts/test-strength.mjs +484 -0
  329. package/pipeline/scripts/test-summary.mjs +651 -0
  330. package/pipeline/scripts/triage-memory.mjs +49 -9
  331. package/pipeline/scripts/unattended_policy.py +2786 -0
  332. package/pipeline/scripts/uninstall.mjs +10 -10
  333. package/pipeline/scripts/update-issue-progress.sh +1 -1
  334. package/pipeline/scripts/usage-identity.mjs +288 -0
  335. package/pipeline/scripts/usage-register.mjs +185 -65
  336. package/pipeline/scripts/usage-report.mjs +230 -66
  337. package/pipeline/scripts/validate-complaint-doc.mjs +28 -10
  338. package/pipeline/scripts/validate-planning.mjs +6 -0
  339. package/pipeline/scripts/verify-citations.mjs +151 -38
  340. package/pipeline/scripts/verify.mjs +58 -18
  341. package/pipeline/scripts/worktree-prepare.sh +126 -0
  342. package/pipeline/scripts/worktrees.mjs +124 -0
  343. package/pipeline/scripts/write-state.mjs +48 -17
  344. package/pipeline/skills/.skill-manifest.json +222 -226
  345. package/pipeline/skills/.skills-index.json +77 -88
  346. package/pipeline/skills/shared/README.md +44 -45
  347. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +3 -2
  348. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +3 -2
  349. package/pipeline/skills/shared/core/multi-agent/SKILL.md +10 -9
  350. package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +6 -5
  351. package/pipeline/skills/shared/core/multi-agent-analysis-jira/SKILL.md +11 -3
  352. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +2 -1
  353. package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +4 -3
  354. package/pipeline/skills/shared/core/multi-agent-autopilot-off/SKILL.md +32 -6
  355. package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +66 -8
  356. package/pipeline/skills/shared/core/multi-agent-autopilot-status/SKILL.md +27 -9
  357. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +2 -1
  358. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +7 -4
  359. package/pipeline/skills/shared/core/multi-agent-complaint-analysis/SKILL.md +3 -2
  360. package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +2 -1
  361. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +7 -5
  362. package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +2 -1
  363. package/pipeline/skills/shared/core/multi-agent-doctor/SKILL.md +3 -2
  364. package/pipeline/skills/shared/core/multi-agent-feedback/SKILL.md +2 -1
  365. package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +2 -1
  366. package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +2 -1
  367. package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +2 -1
  368. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -1
  369. package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +2 -1
  370. package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +3 -2
  371. package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +2 -1
  372. package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +7 -4
  373. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -1
  374. package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +2 -1
  375. package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +2 -1
  376. package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +2 -1
  377. package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +2 -1
  378. package/pipeline/skills/shared/core/multi-agent-prune-prompts/SKILL.md +2 -1
  379. package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +2 -1
  380. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +2 -1
  381. package/pipeline/skills/shared/core/multi-agent-research/SKILL.md +35 -0
  382. package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +7 -3
  383. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +7 -5
  384. package/pipeline/skills/shared/core/multi-agent-review-analysis/SKILL.md +2 -1
  385. package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +3 -2
  386. package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +2 -1
  387. package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +2 -1
  388. package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +2 -1
  389. package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +2 -1
  390. package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +2 -1
  391. package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +3 -2
  392. package/pipeline/skills/shared/core/multi-agent-scaffold/SKILL.md +30 -0
  393. package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +2 -1
  394. package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +4 -3
  395. package/pipeline/skills/shared/core/multi-agent-security-review/SKILL.md +2 -1
  396. package/pipeline/skills/shared/core/multi-agent-serve/SKILL.md +60 -0
  397. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +8 -8
  398. package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +2 -1
  399. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +7 -8
  400. package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -1
  401. package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +2 -1
  402. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +10 -10
  403. package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -1
  404. package/pipeline/skills/shared/core/multi-agent-test-accessibility/SKILL.md +2 -1
  405. package/pipeline/skills/shared/core/multi-agent-test-dark-mode/SKILL.md +2 -1
  406. package/pipeline/skills/shared/core/multi-agent-test-dynamic-type/SKILL.md +2 -1
  407. package/pipeline/skills/shared/core/multi-agent-test-screenshots/SKILL.md +2 -1
  408. package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +2 -1
  409. package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +3 -2
  410. package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -1
  411. package/pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md +46 -0
  412. package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +9 -3
  413. package/pipeline/skills/shared/external/NOTICE-paul-hudson-skills.md +54 -0
  414. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +9 -11
  415. package/pipeline/skills/shared/external/NOTICE-vibeship-spawner-skills.md +203 -0
  416. package/pipeline/skills/shared/external/NOTICE-xcode-build-skills.md +10 -3
  417. package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +131 -25
  418. package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -3
  419. package/pipeline/skills/shared/external/alarmkit/SKILL.md +2 -1
  420. package/pipeline/skills/shared/external/android-architecture/SKILL.md +85 -76
  421. package/pipeline/skills/shared/external/android-build-quality-gates/SKILL.md +51 -3
  422. package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +9 -0
  423. package/pipeline/skills/shared/external/android-datastore/SKILL.md +4 -3
  424. package/pipeline/skills/shared/external/android-design-tokens-codegen/SKILL.md +4 -3
  425. package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +106 -181
  426. package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +147 -0
  427. package/pipeline/skills/shared/external/android-mvi-viewmodel/SKILL.md +45 -4
  428. package/pipeline/skills/shared/external/android-performance/SKILL.md +27 -2
  429. package/pipeline/skills/shared/external/android-performance/references/patterns.md +37 -37
  430. package/pipeline/skills/shared/external/api-patterns/SKILL.md +111 -67
  431. package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +128 -0
  432. package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +136 -186
  433. package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +140 -0
  434. package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +207 -0
  435. package/pipeline/skills/shared/external/api-security-best-practices/references/operations.md +66 -0
  436. package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +175 -0
  437. package/pipeline/skills/shared/external/app-clips/SKILL.md +2 -0
  438. package/pipeline/skills/shared/external/app-intents/SKILL.md +2 -0
  439. package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +4 -3
  440. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +2 -0
  441. package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -0
  442. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +2 -0
  443. package/pipeline/skills/shared/external/architecture/SKILL.md +106 -39
  444. package/pipeline/skills/shared/external/architecture/references/adr-and-review.md +76 -0
  445. package/pipeline/skills/shared/external/authentication/SKILL.md +2 -0
  446. package/pipeline/skills/shared/external/avkit/SKILL.md +2 -0
  447. package/pipeline/skills/shared/external/background-processing/SKILL.md +2 -1
  448. package/pipeline/skills/shared/external/backlog/SKILL.md +3 -2
  449. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +2 -0
  450. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +1 -1
  451. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +3 -2
  452. package/pipeline/skills/shared/external/clean-code/SKILL.md +192 -90
  453. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +2 -1
  454. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +1 -1
  455. package/pipeline/skills/shared/external/compose-components/SKILL.md +4 -4
  456. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +22 -22
  457. package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +10 -10
  458. package/pipeline/skills/shared/external/compose-testing/SKILL.md +13 -6
  459. package/pipeline/skills/shared/external/compose-testing/references/patterns.md +59 -59
  460. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +2 -0
  461. package/pipeline/skills/shared/external/context-compression/SKILL.md +118 -250
  462. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +2 -0
  463. package/pipeline/skills/shared/external/core-data/SKILL.md +2 -0
  464. package/pipeline/skills/shared/external/core-motion/SKILL.md +2 -0
  465. package/pipeline/skills/shared/external/core-nfc/SKILL.md +2 -0
  466. package/pipeline/skills/shared/external/coreml/SKILL.md +2 -1
  467. package/pipeline/skills/shared/external/council/SKILL.md +2 -1
  468. package/pipeline/skills/shared/external/cryptokit/SKILL.md +2 -0
  469. package/pipeline/skills/shared/external/css-modern/SKILL.md +3 -2
  470. package/pipeline/skills/shared/external/database-patterns/SKILL.md +3 -2
  471. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +2 -0
  472. package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +130 -20
  473. package/pipeline/skills/shared/external/debugging-strategies/references/hard-cases.md +54 -0
  474. package/pipeline/skills/shared/external/device-integrity/SKILL.md +2 -0
  475. package/pipeline/skills/shared/external/docker-expert/SKILL.md +137 -381
  476. package/pipeline/skills/shared/external/docker-expert/references/patterns.md +98 -0
  477. package/pipeline/skills/shared/external/energykit/SKILL.md +2 -1
  478. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +3 -1
  479. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +2 -2
  480. package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +116 -185
  481. package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +235 -0
  482. package/pipeline/skills/shared/external/fastapi-pro/references/testing-and-deployment.md +69 -0
  483. package/pipeline/skills/shared/external/firebase/SKILL.md +4 -3
  484. package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +151 -293
  485. package/pipeline/skills/shared/external/github-actions-templates/references/patterns.md +96 -0
  486. package/pipeline/skills/shared/external/healthkit/SKILL.md +2 -0
  487. package/pipeline/skills/shared/external/hig-components-content/SKILL.md +69 -72
  488. package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +111 -0
  489. package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +77 -86
  490. package/pipeline/skills/shared/external/hig-components-layout/references/containers.md +98 -0
  491. package/pipeline/skills/shared/external/hig-components-status/SKILL.md +150 -78
  492. package/pipeline/skills/shared/external/hig-components-system/SKILL.md +76 -97
  493. package/pipeline/skills/shared/external/hig-components-system/references/surfaces.md +98 -0
  494. package/pipeline/skills/shared/external/hig-foundations/SKILL.md +48 -76
  495. package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +132 -0
  496. package/pipeline/skills/shared/external/hig-inputs/SKILL.md +147 -106
  497. package/pipeline/skills/shared/external/hig-patterns/SKILL.md +61 -77
  498. package/pipeline/skills/shared/external/hig-patterns/references/patterns.md +92 -0
  499. package/pipeline/skills/shared/external/hig-platforms/SKILL.md +147 -77
  500. package/pipeline/skills/shared/external/hig-technologies/SKILL.md +61 -121
  501. package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +108 -0
  502. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +2 -0
  503. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +1 -1
  504. package/pipeline/skills/shared/external/html-semantic/SKILL.md +3 -2
  505. package/pipeline/skills/shared/external/humanizer/SKILL.md +2 -1
  506. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +2 -0
  507. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +2 -1
  508. package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +14 -2
  509. package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
  510. package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +4 -3
  511. package/pipeline/skills/shared/external/ios-localization/SKILL.md +8 -6
  512. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +2 -2
  513. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +11 -11
  514. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +2 -1
  515. package/pipeline/skills/shared/external/ios-networking/SKILL.md +2 -0
  516. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +2 -0
  517. package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +102 -193
  518. package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +103 -0
  519. package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -2
  520. package/pipeline/skills/shared/external/live-activities/evals/evals.json +2 -2
  521. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +7 -9
  522. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +3 -3
  523. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +2 -2
  524. package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +4 -3
  525. package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +5 -3
  526. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +2 -0
  527. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +1 -1
  528. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +2 -0
  529. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +1 -1
  530. package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +149 -46
  531. package/pipeline/skills/shared/external/monorepo-architect/references/patterns.md +70 -0
  532. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +2 -0
  533. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +1 -1
  534. package/pipeline/skills/shared/external/natural-language/SKILL.md +2 -0
  535. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +3 -2
  536. package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +91 -21
  537. package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +247 -0
  538. package/pipeline/skills/shared/external/nodejs-backend-patterns/references/testing-and-frameworks.md +57 -0
  539. package/pipeline/skills/shared/external/observability-engineer/SKILL.md +155 -232
  540. package/pipeline/skills/shared/external/observability-engineer/references/patterns.md +75 -0
  541. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +2 -0
  542. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +2 -2
  543. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +18 -18
  544. package/pipeline/skills/shared/external/pdfkit/SKILL.md +2 -1
  545. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +2 -0
  546. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +1 -1
  547. package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -0
  548. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +2 -1
  549. package/pipeline/skills/shared/external/push-notifications/SKILL.md +2 -0
  550. package/pipeline/skills/shared/external/python-patterns/SKILL.md +3 -2
  551. package/pipeline/skills/shared/external/react-best-practices/SKILL.md +3 -2
  552. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +2 -2
  553. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +1 -1
  554. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +3 -2
  555. package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +7 -7
  556. package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +69 -69
  557. package/pipeline/skills/shared/external/room-database/references/patterns.md +126 -126
  558. package/pipeline/skills/shared/external/search-first/SKILL.md +2 -1
  559. package/pipeline/skills/shared/external/security-review/SKILL.md +4 -3
  560. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +2 -2
  561. package/pipeline/skills/shared/external/signal-community/SKILL.md +1 -1
  562. package/pipeline/skills/shared/external/skill-creator/SKILL.md +2 -1
  563. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +2 -1
  564. package/pipeline/skills/shared/external/spm-build-analysis/SKILL.md +2 -0
  565. package/pipeline/skills/shared/external/storekit/SKILL.md +2 -0
  566. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +2 -0
  567. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +2 -1
  568. package/pipeline/skills/shared/external/swift-charts/SKILL.md +2 -1
  569. package/pipeline/skills/shared/external/swift-codable/SKILL.md +2 -0
  570. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +3 -1
  571. package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +5 -4
  572. package/pipeline/skills/shared/external/swift-concurrency-pro/SKILL.md +2 -1
  573. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +2 -0
  574. package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -1
  575. package/pipeline/skills/shared/external/swift-security/SKILL.md +2 -1
  576. package/pipeline/skills/shared/external/swift-testing/SKILL.md +2 -0
  577. package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +2 -1
  578. package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +10 -0
  579. package/pipeline/skills/shared/external/swiftdata/SKILL.md +2 -0
  580. package/pipeline/skills/shared/external/swiftdata-pro/SKILL.md +2 -1
  581. package/pipeline/skills/shared/external/swiftlint/SKILL.md +2 -0
  582. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +2 -0
  583. package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +3 -1
  584. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +2 -0
  585. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +2 -0
  586. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +2 -0
  587. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +2 -0
  588. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +3 -1
  589. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +3 -1
  590. package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +5 -4
  591. package/pipeline/skills/shared/external/swiftui-pro/SKILL.md +2 -1
  592. package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +5 -4
  593. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +2 -0
  594. package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +4 -3
  595. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +2 -0
  596. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +3 -2
  597. package/pipeline/skills/shared/external/testing-backend/SKILL.md +3 -2
  598. package/pipeline/skills/shared/external/tipkit/SKILL.md +2 -0
  599. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +3 -2
  600. package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -0
  601. package/pipeline/skills/shared/external/vue-composition/SKILL.md +3 -2
  602. package/pipeline/skills/shared/external/weatherkit/SKILL.md +2 -0
  603. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +3 -2
  604. package/pipeline/skills/shared/external/web-performance/SKILL.md +3 -2
  605. package/pipeline/skills/shared/external/web-testing/SKILL.md +3 -2
  606. package/pipeline/skills/shared/external/widgetkit/SKILL.md +2 -0
  607. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +1 -1
  608. package/pipeline/skills/shared/external/xcode-build-benchmark/SKILL.md +2 -0
  609. package/pipeline/skills/shared/external/xcode-build-fixer/SKILL.md +2 -0
  610. package/pipeline/skills/shared/external/xcode-build-orchestrator/SKILL.md +2 -0
  611. package/pipeline/skills/shared/external/xcode-compilation-analyzer/SKILL.md +2 -0
  612. package/pipeline/skills/shared/external/xcode-project-analyzer/SKILL.md +2 -0
  613. package/pipeline/skills/skills-index.md +40 -41
  614. package/docs/token-budget-history.md +0 -24
  615. package/pipeline/skills/shared/external/agentflow/SKILL.md +0 -199
  616. package/pipeline/skills/shared/external/android-ui-verification/SKILL.md +0 -66
  617. package/pipeline/skills/shared/external/api-security-best-practices/references/auth.md +0 -299
  618. package/pipeline/skills/shared/external/api-security-best-practices/references/input-validation.md +0 -255
  619. package/pipeline/skills/shared/external/api-security-best-practices/references/rate-limiting.md +0 -167
  620. package/pipeline/skills/shared/external/closed-loop-delivery/SKILL.md +0 -116
  621. package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -216
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # fetch-fortify.sh
4
4
  # Query a Fortify SSC instance for a project version's open findings and
5
- # emit a normalized JSON view that Phase 4 (Review) consumes as a
5
+ # emit a normalized JSON view that Phase 3 (Review) consumes as a
6
6
  # deterministic security gate.
7
7
  #
8
8
  # Three input forms:
@@ -125,8 +125,8 @@ fi
125
125
 
126
126
  # Keychain write through credential-store.sh with the `-` form, which reads the secret
127
127
  # from stdin: the value never lands on any argv (visible to ps), which is the property
128
- # the previous `security -i` call was carefully preserving. The store does the same thing
129
- # per platform, so that property now holds on Linux and Windows as well.
128
+ # a direct `security -i` call would also preserve, kept here in the one place that owns
129
+ # key mapping.
130
130
  save_keychain_secret() {
131
131
  local service="$1" secret="$2"
132
132
  printf '%s' "$secret" | "$CRED_STORE" set "$service" - >/dev/null
@@ -31,6 +31,10 @@
31
31
  # An unset or non-executable CRED_STORE is tolerated: resolution falls through to
32
32
  # the env fallback so a keychain-less CI box still works.
33
33
 
34
+ _MA_FT_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
35
+ # shellcheck source=/dev/null
36
+ if [ -f "$_MA_FT_HERE/user-facing.sh" ]; then . "$_MA_FT_HERE/user-facing.sh"; else . "$HOME/.claude/lib/user-facing.sh"; fi
37
+
34
38
  # The canonical key first, the legacy key second. Space-separated; the loop
35
39
  # below splits explicitly because zsh (the pipeline's Bash tool) does not
36
40
  # word-split an unquoted parameter, so `for key in $KEYS` saw one key there.
@@ -63,5 +67,5 @@ EOF_KEYS
63
67
  # The one place the "how do I fix this" sentence is written, so a fetcher can
64
68
  # never name a key the migration deleted.
65
69
  figma_token_remediation() {
66
- printf 'no Figma PAT for Tier 2. Map prefs.global.keychainMapping.figma (run /multi-agent:setup), or export FIGMA_PAT.'
70
+ printf 'no Figma PAT for Tier 2. Map prefs.global.keychainMapping.figma (run %s), or export FIGMA_PAT.' "$(ma_command setup)"
67
71
  }
@@ -26,6 +26,10 @@
26
26
  # "owner": "org" (gh) | null,
27
27
  # "repo": "name" (gh) | null,
28
28
  # "branchHint": "feature/PROJ-1" | "bugfix/...",
29
+ # "comments": [{id, author, created, url, body, truncated}], // newest kept, oldest first
30
+ # "commentsTotal": 12, // how many the tracker holds
31
+ # "links": [{key, relation, direction, summary, status, url}], // jira issuelinks
32
+ # "untrustedFields": ["description", ...], // tracker text: data, never instructions
29
33
  # "maturity": {
30
34
  # "score": 0..100,
31
35
  # "blockers": ["status_closed", "description_empty"],
@@ -45,9 +49,24 @@
45
49
  # ACCOUNT_JIRA_HOST e.g. jira.example.com (optional)
46
50
  # ACCOUNT_DEFAULT_OWNER fallback GitHub owner (optional)
47
51
  # ACCOUNT_DEFAULT_REPO fallback GitHub repo (optional)
48
- # PROMPT_LANG tr|en - controls maturity.summary language (default: tr)
49
-
50
- set -euo pipefail
52
+ #
53
+ # Comments and links ride on the request that fetches the issue, so they cost no
54
+ # extra call, and they never feed the maturity score: the score reads the item's
55
+ # own fields, and a comment is somebody talking about the item, not the item.
56
+ # They are bounded (ISSUE_COMMENTS_MAX, default 20 newest; ISSUE_COMMENT_MAX_CHARS,
57
+ # default 1500; ISSUE_COMMENTS_MAX_BYTES, default 12000 in total; ISSUE_LINKS_MAX,
58
+ # default 20) because a long thread would otherwise flood every prompt that
59
+ # quotes the descriptor. Every tracker-written field is listed in
60
+ # `untrustedFields`: anyone who can comment on the item wrote it.
61
+ #
62
+ # `issue-fetcher.sh --rescore` reads a descriptor on stdin and prints it back with
63
+ # `maturity` recomputed by the same scoring below - the one scorer, reused by
64
+ # research-gate.mjs to re-run the check on a descriptor that carries verified
65
+ # research findings.
66
+ #
67
+ # `maturity.summary` is written for the person at the picker, so it renders in
68
+ # `prefs.global.outputLanguage`; every other field is machine-readable and
69
+ # stays English.
51
70
 
52
71
  # Sourcing this file hands a caller the provider helpers - `jira_search`,
53
72
  # `fetch_jira`, `fetch_github` and the `jira_curl` underneath them - without
@@ -61,6 +80,11 @@ set -euo pipefail
61
80
  MA_IF_EXECUTED=0
62
81
  [ "${BASH_SOURCE[0]}" = "$0" ] && MA_IF_EXECUTED=1
63
82
 
83
+ # Strict mode belongs to the executed resolver. A sourcing caller keeps its own
84
+ # error handling: jira-search.sh runs without errexit on purpose so that a
85
+ # failed query reaches its own warning and exit code.
86
+ if [ "$MA_IF_EXECUTED" = 1 ]; then set -euo pipefail; fi
87
+
64
88
  INPUT="${1:-}"
65
89
  if [ "$MA_IF_EXECUTED" = 1 ] && [ -z "$INPUT" ]; then
66
90
  echo '{"error":"input required"}'
@@ -71,7 +95,11 @@ JIRA_TOKEN_KEY="${ACCOUNT_JIRA_TOKEN_KEY:-}"
71
95
  JIRA_HOST="${ACCOUNT_JIRA_HOST:-}"
72
96
  DEFAULT_OWNER="${ACCOUNT_DEFAULT_OWNER:-}"
73
97
  DEFAULT_REPO="${ACCOUNT_DEFAULT_REPO:-}"
74
- PROMPT_LANG="${PROMPT_LANG:-tr}"
98
+
99
+ _MA_IF_HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
100
+ # shellcheck source=/dev/null
101
+ if [ -f "$_MA_IF_HERE/user-facing.sh" ]; then . "$_MA_IF_HERE/user-facing.sh"; elif [ -f "$HOME/.claude/lib/user-facing.sh" ]; then . "$HOME/.claude/lib/user-facing.sh"; fi
102
+ if command -v ma_output_lang >/dev/null 2>&1; then SUMMARY_LANG=$(ma_output_lang); else SUMMARY_LANG=en; fi
75
103
 
76
104
  # --- Detect input kind --------------------------------------------------------
77
105
  detect_kind() {
@@ -105,6 +133,7 @@ detect_kind() {
105
133
  }
106
134
 
107
135
  KIND=$(detect_kind "$INPUT")
136
+ [ "$INPUT" = "--rescore" ] && KIND=rescore
108
137
 
109
138
  # --- Helpers ------------------------------------------------------------------
110
139
  slugify() {
@@ -134,6 +163,41 @@ branch_for() {
134
163
 
135
164
  # --- Provider fetchers (return raw JSON or empty) -----------------------------
136
165
 
166
+ # Shared by both provider parses: the newest comments, oldest first, inside a
167
+ # count, a per-comment and a total byte budget. Prepended to each parse script
168
+ # so the bound is one piece of code, not two.
169
+ _PY_BOUND_COMMENTS='
170
+ import os
171
+ def _env_int(name, default):
172
+ v = os.environ.get(name)
173
+ try:
174
+ return int(v) if v not in (None, "") else default
175
+ except ValueError:
176
+ return default
177
+ def bound_comments(rows):
178
+ cap = _env_int("ISSUE_COMMENTS_MAX", 20)
179
+ chars = _env_int("ISSUE_COMMENT_MAX_CHARS", 1500)
180
+ budget = _env_int("ISSUE_COMMENTS_MAX_BYTES", 12000)
181
+ kept, used = [], 0
182
+ for r in reversed(rows):
183
+ if len(kept) >= cap:
184
+ break
185
+ body = (r.get("body") or "").replace("\x1f", " ")
186
+ truncated = False
187
+ if chars > 0 and len(body) > chars:
188
+ body, truncated = body[:chars] + "...", True
189
+ size = len(body.encode("utf-8"))
190
+ if budget > 0 and used + size > budget:
191
+ if kept:
192
+ break
193
+ body = body.encode("utf-8")[:max(budget - 3, 0)].decode("utf-8", "ignore") + "..."
194
+ truncated, size = True, len(body.encode("utf-8"))
195
+ kept.append(dict(r, body=body, truncated=truncated))
196
+ used += size
197
+ kept.reverse()
198
+ return kept
199
+ '
200
+
137
201
  # Bearer-auth via a curl config fed through process substitution so the
138
202
  # token never appears in argv (argv is visible to `ps` / process audit).
139
203
  jira_auth_cfg() { printf 'header = "Authorization: Bearer %s"\n' "$1"; }
@@ -178,7 +242,7 @@ jira_curl() {
178
242
  echo "ERR: Jira token not found in credential store ($JIRA_TOKEN_KEY)" >&2
179
243
  return 1
180
244
  fi
181
- curl -sf -K <(jira_auth_cfg "$token") "https://$JIRA_HOST$path"
245
+ curl -sf -m 30 -K <(jira_auth_cfg "$token") "https://$JIRA_HOST$path"
182
246
  }
183
247
 
184
248
  # The field list is a parameter because the related-issue lookup wants a
@@ -207,7 +271,7 @@ fetch_github() {
207
271
  return 1
208
272
  fi
209
273
  gh issue view "$num" --repo "$owner/$repo" \
210
- --json number,title,labels,state,url,body 2>/dev/null \
274
+ --json number,title,labels,state,url,body,comments 2>/dev/null \
211
275
  || { echo "ERR: GitHub fetch failed for $owner/$repo#$num" >&2; return 1; }
212
276
  }
213
277
 
@@ -217,7 +281,7 @@ fetch_github() {
217
281
 
218
282
  # Build the descriptor JSON, then attach maturity. Pythonized so escaping stays sane.
219
283
  emit_descriptor() {
220
- python3 - "$PROMPT_LANG" "$@" <<'PY'
284
+ python3 - "$SUMMARY_LANG" "$@" <<'PY'
221
285
  import json, sys, re
222
286
 
223
287
  lang = sys.argv[1]
@@ -252,6 +316,21 @@ except Exception:
252
316
  if not isinstance(related, list):
253
317
  related = []
254
318
 
319
+ def _json_field(name, want):
320
+ try:
321
+ v = json.loads(fields.get(name) or "null")
322
+ except Exception:
323
+ v = None
324
+ return v if isinstance(v, want) else None
325
+
326
+ cblob = _json_field("comments", dict) or {}
327
+ comments = cblob.get("items") if isinstance(cblob.get("items"), list) else []
328
+ try:
329
+ comments_total = int(cblob.get("total") or len(comments))
330
+ except (TypeError, ValueError):
331
+ comments_total = len(comments)
332
+ links = _json_field("links", list) or []
333
+
255
334
  descriptor = {
256
335
  "kind": fields.get("kind"),
257
336
  "key": fields.get("key") or None,
@@ -271,6 +350,10 @@ descriptor = {
271
350
  "repo": fields.get("repo") or None,
272
351
  "branchHint": fields.get("branchHint") or None,
273
352
  "relatedIssues": related,
353
+ "comments": comments,
354
+ "commentsTotal": comments_total,
355
+ "links": links,
356
+ "untrustedFields": ["title", "description", "parentDescription", "relatedIssues", "comments", "links"],
274
357
  }
275
358
  extra = {}
276
359
  if fields.get("needsRepoPicker"):
@@ -380,17 +463,21 @@ if [ "$MA_IF_EXECUTED" = 1 ]; then
380
463
  case "$KIND" in
381
464
  jira-id)
382
465
  KEY="$INPUT"
383
- raw=$(fetch_jira "$KEY") || raw=""
466
+ raw=$(fetch_jira "$KEY" "summary,status,issuetype,description,priority,resolution,fixVersions,parent,comment,issuelinks") || raw=""
467
+ commentsjson='{"items":[],"total":0}'; linksjson="[]"
384
468
  if [ -n "$raw" ]; then
385
469
  # Single python3 pass - emit all fields joined by U+001F (Unit Separator)
386
470
  # so we avoid spawning 7 interpreter startups per Jira fetch
387
471
  # (~200-300ms each). The separator is non-whitespace, so empty fields
388
472
  # (e.g. unresolved issues) are preserved by `read` instead of collapsed.
389
473
  # `read -d ''` lets descriptions with embedded newlines pass through.
390
- parsed=$(printf '%s' "$raw" | python3 -c '
391
- import json, sys
474
+ parsed=$(printf '%s' "$raw" | SELF_KEY="$KEY" JIRA_HOST="$JIRA_HOST" python3 -c "$_PY_BOUND_COMMENTS"'
475
+ import json, re, sys
392
476
  d = json.load(sys.stdin)
393
477
  f = d.get("fields", {}) or {}
478
+ host = os.environ.get("JIRA_HOST", "")
479
+ self_key = os.environ.get("SELF_KEY", "")
480
+ key_re = re.compile(r"^[A-Z][A-Z0-9]*-[0-9]+$")
394
481
  def _name(x):
395
482
  return (x or {}).get("name", "") or ""
396
483
  title = f.get("summary", "") or ""
@@ -401,11 +488,47 @@ priority = _name(f.get("priority"))
401
488
  resolution = _name(f.get("resolution"))
402
489
  fixversions = ",".join((v or {}).get("name", "") for v in (f.get("fixVersions") or []))
403
490
  parentkey = (f.get("parent") or {}).get("key", "") or ""
491
+ cblock = f.get("comment") or {}
492
+ crows = []
493
+ for c in cblock.get("comments") or []:
494
+ if not isinstance(c, dict):
495
+ continue
496
+ cid = str(c.get("id") or "")
497
+ crows.append({
498
+ "id": cid,
499
+ "author": ((c.get("author") or {}).get("displayName") or ""),
500
+ "created": c.get("created") or "",
501
+ "url": "https://%s/browse/%s?focusedCommentId=%s" % (host, self_key, cid) if host and cid else "",
502
+ "body": c.get("body") or "",
503
+ })
504
+ comments = {"items": bound_comments(crows), "total": int(cblock.get("total") or len(crows))}
505
+ links = []
506
+ for l in f.get("issuelinks") or []:
507
+ if not isinstance(l, dict):
508
+ continue
509
+ t = l.get("type") or {}
510
+ other, direction = (l.get("outwardIssue"), "outward") if l.get("outwardIssue") else (l.get("inwardIssue"), "inward")
511
+ other = other or {}
512
+ lkey = other.get("key") or ""
513
+ if not key_re.match(lkey):
514
+ continue
515
+ of = other.get("fields") or {}
516
+ links.append({
517
+ "key": lkey,
518
+ "relation": (t.get(direction) or t.get("name") or ""),
519
+ "direction": direction,
520
+ "summary": of.get("summary") or "",
521
+ "status": _name(of.get("status")),
522
+ "url": "https://%s/browse/%s" % (host, lkey) if host else "",
523
+ })
524
+ links = links[:max(_env_int("ISSUE_LINKS_MAX", 20), 0)]
404
525
  parts = [title, itype, status, description, priority, resolution, fixversions, parentkey]
405
526
  parts = [v.replace("\x1f", " ") for v in parts]
527
+ parts += [json.dumps(comments, ensure_ascii=False), json.dumps(links, ensure_ascii=False)]
406
528
  sys.stdout.write("\x1f".join(parts))
407
529
  ')
408
- IFS=$'\x1f' read -r -d '' title itype status description priority resolution fixversions parentkey <<< "$parsed" || true
530
+ IFS=$'\x1f' read -r -d '' title itype status description priority resolution fixversions parentkey commentsjson linksjson <<< "$parsed" || true
531
+ linksjson="${linksjson%$'\n'}"
409
532
  # `<<<` appends a trailing newline to its input; `read -d ''` has no
410
533
  # delimiter to stop on, so that newline folds into whichever field
411
534
  # comes last - now parentkey. Strip it, or a genuinely-empty parent
@@ -534,12 +657,49 @@ sys.stdout.write(json.dumps(out[:cap], ensure_ascii=False))
534
657
  "url=https://$JIRA_HOST/browse/$KEY" "branchHint=$branch" \
535
658
  "priority=$priority" "resolution=$resolution" "fixVersions=$fixversions" \
536
659
  "parentKey=$parentkey" "parentDescription=$parentdesc" \
537
- "relatedIssues=$relatedjson"
660
+ "relatedIssues=$relatedjson" "comments=$commentsjson" "links=$linksjson"
538
661
  ;;
539
662
 
540
663
  jira-url)
541
664
  HOST=$(printf '%s' "$INPUT" | sed -E 's#https?://##; s#/.*##')
542
- KEY=$(printf '%s' "$INPUT" | sed -E 's#.*/browse/##; s#[/?].*##')
665
+ KEY=$(printf '%s' "$INPUT" | sed -E 's#.*/browse/##; s#[/?#].*##')
666
+ # Re-dispatch only a real key. Anything else would fall through
667
+ # detect_kind to the freetext branch and start a run titled with a URL.
668
+ if ! [[ "$KEY" =~ ^[A-Z][A-Z0-9]*-[0-9]+$ ]]; then
669
+ echo '{"error":"no Jira issue key in URL"}'
670
+ exit 2
671
+ fi
672
+ # The link's host receives the Jira token on the re-dispatch, and a link is
673
+ # ticket or request text. HOST is the exact string curl will see, so it must
674
+ # be a bare host[:port] and name the configured Jira host; without one, only
675
+ # Atlassian Cloud, where the host is the tenant.
676
+ if ! [[ "$HOST" =~ ^[A-Za-z0-9.-]+(:[0-9]{1,5})?$ ]]; then
677
+ echo '{"error":"host-malformed"}'
678
+ exit 2
679
+ fi
680
+ _allowed="${JIRA_HOST:-}"
681
+ if [ -z "$_allowed" ]; then
682
+ _prefs="${MA_PREFS_FILE:-$HOME/.claude/multi-agent-preferences.json}"
683
+ _allowed=$(python3 - "$_prefs" <<'PY' 2>/dev/null || true
684
+ import json, sys
685
+ try:
686
+ print((json.load(open(sys.argv[1])).get("global", {}).get("hosts", {}) or {}).get("jira") or "")
687
+ except Exception:
688
+ print("")
689
+ PY
690
+ )
691
+ fi
692
+ _allowed=$(printf '%s' "$_allowed" | tr '[:upper:]' '[:lower:]' | sed -E 's#^https?://##; s#/.*##; s#:.*##; s#\.$##')
693
+ _host=$(printf '%s' "$HOST" | tr '[:upper:]' '[:lower:]' | sed -E 's#:.*##; s#\.$##')
694
+ if [ -n "$_allowed" ]; then
695
+ [ "$_host" = "$_allowed" ] || { echo '{"error":"host-not-allowed"}'; exit 2; }
696
+ else
697
+ case "$_host" in
698
+ *.atlassian.net) ;;
699
+ *) echo '{"error":"host-not-configured"}'; exit 2 ;;
700
+ esac
701
+ fi
702
+ unset _allowed _prefs _host
543
703
  ACCOUNT_JIRA_HOST="$HOST" JIRA_HOST="$HOST" exec "$0" "$KEY"
544
704
  ;;
545
705
 
@@ -548,21 +708,38 @@ sys.stdout.write(json.dumps(out[:cap], ensure_ascii=False))
548
708
  REPO=$(printf '%s' "$INPUT" | sed -E 's#https?://github.com/[^/]+/##; s#/.*##')
549
709
  NUM=$(printf '%s' "$INPUT" | sed -E 's#.*/issues/##; s#[/?#].*##')
550
710
  raw=$(fetch_github "$OWNER" "$REPO" "$NUM") || raw=""
711
+ commentsjson='{"items":[],"total":0}'
551
712
  if [ -n "$raw" ]; then
552
713
  # Single python3 pass - see jira-id branch for rationale on the
553
714
  # U+001F separator + `read -d ''` combo.
554
- parsed=$(printf '%s' "$raw" | python3 -c '
715
+ parsed=$(printf '%s' "$raw" | python3 -c "$_PY_BOUND_COMMENTS"'
555
716
  import json, sys
556
717
  d = json.load(sys.stdin)
557
718
  title = d.get("title", "") or ""
558
719
  labels = ",".join((l or {}).get("name", "") for l in (d.get("labels") or []))
559
720
  status = d.get("state", "open") or "open"
560
721
  description = d.get("body", "") or ""
722
+ crows = []
723
+ for c in d.get("comments") or []:
724
+ if not isinstance(c, dict):
725
+ continue
726
+ crows.append({
727
+ "id": str(c.get("id") or ""),
728
+ "author": ((c.get("author") or {}).get("login") or ""),
729
+ "created": c.get("createdAt") or "",
730
+ "url": c.get("url") or "",
731
+ "body": c.get("body") or "",
732
+ })
733
+ comments = {"items": bound_comments(crows), "total": len(crows)}
561
734
  parts = [title, labels, status, description]
562
735
  parts = [v.replace("\x1f", " ") for v in parts]
736
+ parts.append(json.dumps(comments, ensure_ascii=False))
563
737
  sys.stdout.write("\x1f".join(parts))
564
738
  ')
565
- IFS=$'\x1f' read -r -d '' title labels status description <<< "$parsed" || true
739
+ IFS=$'\x1f' read -r -d '' title labels status description commentsjson <<< "$parsed" || true
740
+ # Same `<<<` trailing newline as the jira-id branch; here the comments
741
+ # JSON is the last field and would carry it.
742
+ commentsjson="${commentsjson%$'\n'}"
566
743
  else
567
744
  title="(unfetched)"; labels=""; status="open"; description=""
568
745
  fi
@@ -572,7 +749,7 @@ sys.stdout.write("\x1f".join(parts))
572
749
  "kind=github" "key=$NUM" "title=$title" "type=$itype" "status=$status" \
573
750
  "description=$description" "host=github.com" \
574
751
  "url=https://github.com/$OWNER/$REPO/issues/$NUM" \
575
- "owner=$OWNER" "repo=$REPO" "branchHint=$branch"
752
+ "owner=$OWNER" "repo=$REPO" "branchHint=$branch" "comments=$commentsjson"
576
753
  ;;
577
754
 
578
755
  gh-short)
@@ -600,6 +777,46 @@ sys.stdout.write("\x1f".join(parts))
600
777
  exec "$0" "https://github.com/$OWNER/$REPO/issues/$NUM"
601
778
  ;;
602
779
 
780
+ rescore)
781
+ # The descriptor's own fields, handed back to the one scorer. Read in full
782
+ # first: the argument list is built by a second process.
783
+ desc_in=$(cat)
784
+ rescore_args=()
785
+ while IFS= read -r -d '' a; do rescore_args+=("$a"); done < <(printf '%s' "$desc_in" | python3 -c '
786
+ import json, sys
787
+ try:
788
+ d = json.load(sys.stdin)
789
+ except Exception:
790
+ d = None
791
+ if not isinstance(d, dict):
792
+ sys.exit(0)
793
+ def s(v):
794
+ return "" if v is None else str(v)
795
+ comments = d.get("comments") if isinstance(d.get("comments"), list) else []
796
+ out = {
797
+ "kind": s(d.get("kind")), "key": s(d.get("key")), "title": s(d.get("title")),
798
+ "type": s(d.get("type")), "status": s(d.get("status")), "description": s(d.get("description")),
799
+ "priority": s(d.get("priority")), "resolution": s(d.get("resolution")),
800
+ "fixVersions": ",".join(s(v) for v in (d.get("fixVersions") or [])),
801
+ "parentKey": s(d.get("parentKey")), "parentDescription": s(d.get("parentDescription")),
802
+ "host": s(d.get("host")), "url": s(d.get("url")), "owner": s(d.get("owner")),
803
+ "repo": s(d.get("repo")), "branchHint": s(d.get("branchHint")),
804
+ "relatedIssues": json.dumps(d.get("relatedIssues") or [], ensure_ascii=False),
805
+ "comments": json.dumps({"items": comments, "total": d.get("commentsTotal") or len(comments)}, ensure_ascii=False),
806
+ "links": json.dumps(d.get("links") or [], ensure_ascii=False),
807
+ }
808
+ if d.get("needsRepoPicker"):
809
+ out["needsRepoPicker"] = "1"
810
+ for k, v in out.items():
811
+ sys.stdout.write("%s=%s\0" % (k, v.replace("\0", "")))
812
+ ')
813
+ if [ "${#rescore_args[@]}" -eq 0 ]; then
814
+ echo '{"error":"--rescore needs a descriptor JSON object on stdin"}'
815
+ exit 2
816
+ fi
817
+ emit_descriptor "${rescore_args[@]}"
818
+ ;;
819
+
603
820
  freetext)
604
821
  title="$INPUT"
605
822
  branch=$(branch_for "" "Task" "$title")
@@ -0,0 +1,172 @@
1
+ /**
2
+ * json-file-lock.mjs - synchronous read-modify-write of a small JSON file
3
+ * under a lock, replaced atomically with owner-only permissions.
4
+ *
5
+ * The lock is `<file>.lock`, created the way write-state.mjs creates it: the
6
+ * owning PID is written to a private stage file that is hard-linked into place,
7
+ * so the lock never exists without its PID. The two helpers therefore exclude
8
+ * each other on the same file. A lock whose PID is no longer alive is
9
+ * reclaimed by inode identity; a lock with no readable PID is reclaimed only
10
+ * once it is older than `staleMs`.
11
+ *
12
+ * The write goes to a temp file in the same directory, created exclusively at
13
+ * `mode`, and is renamed over the target, so a reader sees the old document or
14
+ * the new one and never a partial write.
15
+ *
16
+ * @module pipeline/lib/json-file-lock
17
+ */
18
+
19
+ import {
20
+ chmodSync,
21
+ linkSync,
22
+ readFileSync,
23
+ renameSync,
24
+ rmSync,
25
+ statSync,
26
+ unlinkSync,
27
+ writeFileSync,
28
+ } from "node:fs";
29
+ import { basename, dirname, join } from "node:path";
30
+ import { readRegularJson } from "./regular-file.mjs";
31
+
32
+ const DEFAULT_TIMEOUT_MS = 15_000;
33
+ const DEFAULT_STALE_MS = 30_000;
34
+ const POLL_MS = 50;
35
+
36
+ export class FileLockTimeout extends Error {
37
+ constructor(lockPath, timeoutMs) {
38
+ super(`lock timeout on ${lockPath} after ${timeoutMs}ms`);
39
+ this.name = "FileLockTimeout";
40
+ this.code = "LOCK_TIMEOUT";
41
+ }
42
+ }
43
+
44
+ const pause = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
45
+
46
+ function staleIdentity(lockPath, staleMs) {
47
+ let pid;
48
+ let st;
49
+ try {
50
+ pid = parseInt(readFileSync(lockPath, "utf8").trim(), 10);
51
+ st = statSync(lockPath);
52
+ } catch {
53
+ return null;
54
+ }
55
+ const age = Date.now() - st.mtimeMs;
56
+ if (!Number.isInteger(pid) || pid <= 0) return age > staleMs ? st : null;
57
+ try {
58
+ process.kill(pid, 0);
59
+ return null;
60
+ } catch (err) {
61
+ return err.code === "ESRCH" ? st : null;
62
+ }
63
+ }
64
+
65
+ function acquire(lockPath, timeoutMs, staleMs) {
66
+ const stage = `${lockPath}.${process.pid}.stage`;
67
+ const deadline = Date.now() + timeoutMs;
68
+ for (;;) {
69
+ try {
70
+ writeFileSync(stage, String(process.pid), { mode: 0o600 });
71
+ linkSync(stage, lockPath);
72
+ const ino = statSync(lockPath).ino;
73
+ unlinkSync(stage);
74
+ return ino;
75
+ } catch (err) {
76
+ rmSync(stage, { force: true });
77
+ if (err.code !== "EEXIST") throw err;
78
+ }
79
+ const stale = staleIdentity(lockPath, staleMs);
80
+ if (stale) {
81
+ try {
82
+ const now = statSync(lockPath);
83
+ if (now.ino === stale.ino && now.mtimeMs === stale.mtimeMs) unlinkSync(lockPath);
84
+ } catch {
85
+ /* gone already */
86
+ }
87
+ continue;
88
+ }
89
+ if (Date.now() >= deadline) throw new FileLockTimeout(lockPath, timeoutMs);
90
+ pause(POLL_MS);
91
+ }
92
+ }
93
+
94
+ function release(lockPath, ino) {
95
+ try {
96
+ if (statSync(lockPath).ino === ino) unlinkSync(lockPath);
97
+ } catch {
98
+ /* gone already */
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Run `fn` while holding `<path>.lock`.
104
+ *
105
+ * @template T
106
+ * @param {string} path
107
+ * @param {() => T} fn
108
+ * @param {{timeoutMs?: number, staleMs?: number}} [opts]
109
+ * @returns {T}
110
+ */
111
+ export function withFileLockSync(
112
+ path,
113
+ fn,
114
+ { timeoutMs = DEFAULT_TIMEOUT_MS, staleMs = DEFAULT_STALE_MS } = {},
115
+ ) {
116
+ const lockPath = `${path}.lock`;
117
+ const ino = acquire(lockPath, timeoutMs, staleMs);
118
+ try {
119
+ return fn();
120
+ } finally {
121
+ release(lockPath, ino);
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Replace `path` with `data` as JSON, atomically, at `mode`.
127
+ *
128
+ * @param {string} path
129
+ * @param {unknown} data
130
+ * @param {{mode?: number}} [opts]
131
+ */
132
+ export function writeJsonAtomicSync(path, data, { mode = 0o600 } = {}) {
133
+ const tmp = join(dirname(path), `.${basename(path)}.${process.pid}.tmp`);
134
+ rmSync(tmp, { force: true });
135
+ try {
136
+ writeFileSync(tmp, `${JSON.stringify(data, null, 2)}\n`, { mode, flag: "wx" });
137
+ chmodSync(tmp, mode);
138
+ renameSync(tmp, path);
139
+ } catch (err) {
140
+ rmSync(tmp, { force: true });
141
+ throw err;
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Lock, read, mutate and atomically replace a JSON file. `mutate` receives the
147
+ * parsed document (or `fallback` when the file is missing or unreadable) and
148
+ * returns the next one; returning `undefined` writes nothing.
149
+ *
150
+ * @param {string} path
151
+ * @param {(current: any) => any} mutate
152
+ * @param {{fallback?: any, mode?: number, timeoutMs?: number, staleMs?: number}} [opts]
153
+ * @returns {any} the document written, or undefined when nothing was
154
+ */
155
+ export function updateJsonFileSync(path, mutate, { fallback = null, mode = 0o600, ...lock } = {}) {
156
+ return withFileLockSync(
157
+ path,
158
+ () => {
159
+ const next = mutate(readRegularJson(path, fallback));
160
+ if (next === undefined) return undefined;
161
+ writeJsonAtomicSync(path, next, { mode });
162
+ return next;
163
+ },
164
+ lock,
165
+ );
166
+ }
167
+
168
+ /** A lock timeout from `env.WRITE_STATE_LOCK_TIMEOUT_MS`, the knob write-state reads. */
169
+ export function lockTimeoutFrom(env = process.env) {
170
+ const n = Number(env?.WRITE_STATE_LOCK_TIMEOUT_MS);
171
+ return Number.isFinite(n) && n > 0 ? n : DEFAULT_TIMEOUT_MS;
172
+ }
@@ -52,15 +52,8 @@ done
52
52
 
53
53
  emit() { printf '%s\n' "$1"; exit 0; }
54
54
 
55
- case "$CALL_SITE" in
56
- subagent|bulk-read|research) ;;
57
- *) emit "$DEFAULT_RUNG" ;;
58
- esac
59
-
60
55
  [ -n "$DEFAULT_RUNG" ] || DEFAULT_RUNG="sonnet"
61
56
 
62
- command -v jq >/dev/null 2>&1 || emit "$DEFAULT_RUNG"
63
-
64
57
  PREFS=""
65
58
  for candidate in \
66
59
  "${MULTI_AGENT_PREFS:-}" \
@@ -69,6 +62,23 @@ for candidate in \
69
62
  do
70
63
  [ -n "$candidate" ] && [ -f "$candidate" ] && { PREFS="$candidate"; break; }
71
64
  done
65
+
66
+ # The fable rung exists only while modelFallback.fableEnabled is true, and it
67
+ # ships false. A caller whose default is fable - a command that runs without
68
+ # Phase 0, such as review - gets the documented resolution, opus, on every path
69
+ # out of here: routing off, out of scope, no rule, or nothing readable.
70
+ FABLE_ON=false
71
+ if [ -n "$PREFS" ] && command -v jq >/dev/null 2>&1; then
72
+ FABLE_ON=$(jq -r '.global.modelFallback.fableEnabled // false' "$PREFS" 2>/dev/null || echo false)
73
+ fi
74
+ [ "$DEFAULT_RUNG" = "fable" ] && [ "$FABLE_ON" != "true" ] && DEFAULT_RUNG="opus"
75
+
76
+ case "$CALL_SITE" in
77
+ subagent|bulk-read|research) ;;
78
+ *) emit "$DEFAULT_RUNG" ;;
79
+ esac
80
+
81
+ command -v jq >/dev/null 2>&1 || emit "$DEFAULT_RUNG"
72
82
  [ -n "$PREFS" ] || emit "$DEFAULT_RUNG"
73
83
 
74
84
  ENABLED=$(jq -r '.global.modelRouting.enabled // false' "$PREFS" 2>/dev/null) || emit "$DEFAULT_RUNG"
@@ -98,11 +108,10 @@ MATCH=$(jq -r \
98
108
  HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
99
109
  COST_TABLE="$HERE/../scripts/cost-table.json"
100
110
 
101
- # The fable rung answers only when the fable switch is on. Routing is a policy
102
- # over what is available; it is not a second way to turn a rung on, or
103
- # `/multi-agent:model off` would stop meaning anything the moment a rule named
104
- # fable.
105
- FABLE_ON=$(jq -r '.global.modelFallback.fableEnabled // false' "$PREFS" 2>/dev/null)
111
+ # The fable rung answers only when the fable switch is on (FABLE_ON, read
112
+ # above). Routing is a policy over what is available; it is not a second way to
113
+ # turn a rung on, or `/multi-agent:model off` would stop meaning anything the
114
+ # moment a rule named fable.
106
115
 
107
116
  record() {
108
117
  [ -x "$HERE/../scripts/log-metric.sh" ] || return 0