@mmerterden/multi-agent-pipeline 20.33.0 → 20.35.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 (390) hide show
  1. package/CHANGELOG.md +98 -1
  2. package/README.md +3 -1
  3. package/README.tr.md +2 -1
  4. package/docs/adr/0018-cross-repo-links-not-a-global-graph.md +43 -0
  5. package/docs/adr/README.md +2 -1
  6. package/docs/facts.json +5 -4
  7. package/docs/features.md +1 -1
  8. package/install/_dev-only-files.mjs +1 -0
  9. package/install/catalog-history.json +1 -1
  10. package/install/claude.mjs +24 -2
  11. package/install/templates/claude-hooks.json +34 -1
  12. package/manifest.json +393 -339
  13. package/package.json +3 -1
  14. package/pipeline/agents/bulk-reader.md +3 -0
  15. package/pipeline/agents/code-reviewer.md +9 -0
  16. package/pipeline/agents/explorer.md +4 -0
  17. package/pipeline/agents/plan-critic.md +4 -2
  18. package/pipeline/commands/multi-agent/SKILL.md +17 -136
  19. package/pipeline/commands/multi-agent/channels/SKILL.md +16 -298
  20. package/pipeline/commands/multi-agent/graph/SKILL.md +5 -2
  21. package/pipeline/commands/multi-agent/language/SKILL.md +3 -3
  22. package/pipeline/commands/multi-agent/office-on/SKILL.md +7 -3
  23. package/pipeline/commands/multi-agent/office-status/SKILL.md +3 -2
  24. package/pipeline/commands/multi-agent/resume/SKILL.md +8 -22
  25. package/pipeline/commands/multi-agent/review/SKILL.md +7 -131
  26. package/pipeline/commands/multi-agent/setup/SKILL.md +19 -224
  27. package/pipeline/contract/CHANGELOG.md +9 -0
  28. package/pipeline/contract/README.md +6 -2
  29. package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
  30. package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
  31. package/pipeline/contract/fixtures/error-unsigned.json +1 -1
  32. package/pipeline/contract/manifest.json +14 -1
  33. package/pipeline/contract/types/index.d.ts +24 -2
  34. package/pipeline/lib/json-file-lock.mjs +61 -15
  35. package/pipeline/lib/office-remote.mjs +228 -0
  36. package/pipeline/lib/qr-code.mjs +360 -0
  37. package/pipeline/lib/repo-hygiene.sh +1 -0
  38. package/pipeline/lib/run-completion.mjs +17 -0
  39. package/pipeline/multi-agent-refs/channels/generator.md +146 -0
  40. package/pipeline/multi-agent-refs/channels/issue-comment.md +1 -1
  41. package/pipeline/multi-agent-refs/channels/menu.md +55 -0
  42. package/pipeline/multi-agent-refs/channels/multi-repo.md +6 -0
  43. package/pipeline/multi-agent-refs/channels/preview.md +25 -0
  44. package/pipeline/multi-agent-refs/channels/reference.md +98 -0
  45. package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +1 -1
  46. package/pipeline/multi-agent-refs/features/code-graph.md +27 -0
  47. package/pipeline/multi-agent-refs/features/office-remote-protocol.md +166 -0
  48. package/pipeline/multi-agent-refs/features/office-threat-model.md +2 -2
  49. package/pipeline/multi-agent-refs/features/plan-critic.md +5 -2
  50. package/pipeline/multi-agent-refs/features/review-delta.md +4 -1
  51. package/pipeline/multi-agent-refs/features/scope-check.md +25 -1
  52. package/pipeline/multi-agent-refs/features/verify-by-test.md +10 -0
  53. package/pipeline/multi-agent-refs/keychain.md +7 -0
  54. package/pipeline/multi-agent-refs/knowledge.md +9 -0
  55. package/pipeline/multi-agent-refs/orchestrator/dispatcher.md +163 -0
  56. package/pipeline/multi-agent-refs/phases/phase-0-init.md +6 -2
  57. package/pipeline/multi-agent-refs/phases/phase-1-plan.md +8 -10
  58. package/pipeline/multi-agent-refs/phases/phase-2-dev.md +18 -20
  59. package/pipeline/multi-agent-refs/phases/phase-3-review.md +20 -14
  60. package/pipeline/multi-agent-refs/phases/phase-4-commit.md +8 -7
  61. package/pipeline/multi-agent-refs/phases/phase-5-report.md +6 -3
  62. package/pipeline/multi-agent-refs/picker-contract.md +1 -1
  63. package/pipeline/multi-agent-refs/resume/details.md +35 -0
  64. package/pipeline/multi-agent-refs/review/inputs.md +87 -0
  65. package/pipeline/multi-agent-refs/review/module-guides.md +25 -0
  66. package/pipeline/multi-agent-refs/review/valven.md +42 -0
  67. package/pipeline/multi-agent-refs/rules.md +3 -2
  68. package/pipeline/multi-agent-refs/setup/accounts.md +27 -0
  69. package/pipeline/multi-agent-refs/setup/app-store-connect.md +5 -0
  70. package/pipeline/multi-agent-refs/setup/firebase.md +5 -0
  71. package/pipeline/multi-agent-refs/setup/google-play.md +4 -0
  72. package/pipeline/multi-agent-refs/setup/hooks-and-plugins.md +21 -0
  73. package/pipeline/multi-agent-refs/setup/language.md +46 -0
  74. package/pipeline/multi-agent-refs/setup/multi-repo-group.md +51 -0
  75. package/pipeline/multi-agent-refs/setup/summaries.md +63 -0
  76. package/pipeline/multi-agent-refs/setup/token-save-flow.md +51 -0
  77. package/pipeline/multi-agent-refs/tracker-contract.md +1 -1
  78. package/pipeline/office/NOTICE.md +4 -1
  79. package/pipeline/office/assets/char_12.png +0 -0
  80. package/pipeline/office/assets/char_13.png +0 -0
  81. package/pipeline/office/assets/char_14.png +0 -0
  82. package/pipeline/office/assets/char_15.png +0 -0
  83. package/pipeline/office/assets/char_16.png +0 -0
  84. package/pipeline/office/assets/char_17.png +0 -0
  85. package/pipeline/office/assets/char_18.png +0 -0
  86. package/pipeline/office/assets/char_19.png +0 -0
  87. package/pipeline/office/assets/char_20.png +0 -0
  88. package/pipeline/office/assets/char_21.png +0 -0
  89. package/pipeline/office/assets/char_22.png +0 -0
  90. package/pipeline/office/assets/char_23.png +0 -0
  91. package/pipeline/office/assets/char_24.png +0 -0
  92. package/pipeline/office/assets/char_25.png +0 -0
  93. package/pipeline/office/assets/char_26.png +0 -0
  94. package/pipeline/office/assets/char_27.png +0 -0
  95. package/pipeline/office/assets/char_28.png +0 -0
  96. package/pipeline/office/assets/char_29.png +0 -0
  97. package/pipeline/office/assets/char_30.png +0 -0
  98. package/pipeline/office/index.html +304 -55
  99. package/pipeline/office/toolkit.json +1 -1
  100. package/pipeline/rules/response-shape.md +6 -7
  101. package/pipeline/schemas/agent-state.schema.json +36 -0
  102. package/pipeline/schemas/phases.json +4 -4
  103. package/pipeline/schemas/plan-critique.schema.json +9 -2
  104. package/pipeline/schemas/planning-output.schema.json +43 -2
  105. package/pipeline/schemas/pr-reach.schema.json +55 -0
  106. package/pipeline/schemas/prefs.schema.json +37 -8
  107. package/pipeline/schemas/reviewer-output.schema.json +20 -2
  108. package/pipeline/schemas/token-budget.json +4 -4
  109. package/pipeline/schemas/triage-output.schema.json +32 -3
  110. package/pipeline/schemas/unattended-policy.json +2 -1
  111. package/pipeline/scripts/_graph-analysis.mjs +270 -0
  112. package/pipeline/scripts/_guard_rules.py +449 -1
  113. package/pipeline/scripts/_memory-policy.mjs +165 -0
  114. package/pipeline/scripts/_secret-scan.mjs +105 -0
  115. package/pipeline/scripts/_test-gaming.mjs +36 -0
  116. package/pipeline/scripts/_unified-diff.mjs +2 -2
  117. package/pipeline/scripts/agent-guard.py +79 -19
  118. package/pipeline/scripts/anonymize-findings.mjs +99 -0
  119. package/pipeline/scripts/answer-check.mjs +113 -0
  120. package/pipeline/scripts/answer-check.sh +20 -0
  121. package/pipeline/scripts/autopilot-publish.mjs +9 -2
  122. package/pipeline/scripts/capture-flush.sh +12 -2
  123. package/pipeline/scripts/check-read-size.sh +9 -0
  124. package/pipeline/scripts/code-graph-rules/android.json +8 -3
  125. package/pipeline/scripts/contract-server.mjs +71 -16
  126. package/pipeline/scripts/debt-ledger.mjs +323 -0
  127. package/pipeline/scripts/file-context.mjs +261 -0
  128. package/pipeline/scripts/file-context.sh +20 -0
  129. package/pipeline/scripts/gate-ledger.mjs +144 -21
  130. package/pipeline/scripts/graph-links.mjs +230 -0
  131. package/pipeline/scripts/graph-query.mjs +133 -1
  132. package/pipeline/scripts/graph-report.mjs +65 -0
  133. package/pipeline/scripts/learn-from-transcripts.mjs +12 -48
  134. package/pipeline/scripts/learnings-ledger.mjs +143 -24
  135. package/pipeline/scripts/office-build.mjs +276 -5
  136. package/pipeline/scripts/office-control.mjs +70 -10
  137. package/pipeline/scripts/office-pair.mjs +407 -0
  138. package/pipeline/scripts/office-remote-client.mjs +463 -0
  139. package/pipeline/scripts/phase-tracker.sh +8 -0
  140. package/pipeline/scripts/phase0-exit-gate.mjs +40 -37
  141. package/pipeline/scripts/phone-devices.mjs +9 -1
  142. package/pipeline/scripts/plan-critique-gate.mjs +11 -2
  143. package/pipeline/scripts/pre-commit-check.sh +28 -2
  144. package/pipeline/scripts/pre-push-check.sh +6 -12
  145. package/pipeline/scripts/rework-base.mjs +87 -0
  146. package/pipeline/scripts/rework-rulings.mjs +106 -0
  147. package/pipeline/scripts/run-commit-check.mjs +104 -0
  148. package/pipeline/scripts/run-scope-guard.mjs +58 -3
  149. package/pipeline/scripts/run-scope-guard.sh +13 -1
  150. package/pipeline/scripts/scope-check-gate.mjs +213 -2
  151. package/pipeline/scripts/task-mirror.mjs +106 -15
  152. package/pipeline/scripts/task-mirror.sh +3 -2
  153. package/pipeline/scripts/test-stability-gate.mjs +112 -0
  154. package/pipeline/scripts/triage-memory.mjs +64 -37
  155. package/pipeline/scripts/update-check.sh +7 -1
  156. package/pipeline/scripts/update-issue-progress.sh +73 -8
  157. package/pipeline/scripts/validate-planning.mjs +172 -4
  158. package/pipeline/scripts/validate-reviewer.mjs +20 -0
  159. package/pipeline/scripts/validate-triage.mjs +149 -4
  160. package/pipeline/scripts/work-items.mjs +119 -1
  161. package/pipeline/scripts/worktree-prepare-all.mjs +200 -0
  162. package/pipeline/scripts/worktree-prepare.sh +40 -4
  163. package/pipeline/scripts/write-state.mjs +67 -24
  164. package/pipeline/skills/.skill-manifest.json +9 -9
  165. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +5 -5
  166. package/pipeline/skills/shared/core/google-play-compliance/references/rules.yml +1 -1
  167. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +1 -1
  168. package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +5 -2
  169. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +4 -4
  170. package/pipeline/skills/shared/core/multi-agent-office-status/SKILL.md +2 -2
  171. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +2 -0
  172. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +4 -4
  173. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +14 -0
  174. package/pipeline/skills/shared/external/android-architecture/references/patterns.md +6 -0
  175. package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +10 -0
  176. package/pipeline/skills/shared/external/android-datastore/references/patterns.md +11 -0
  177. package/pipeline/skills/shared/external/android-design-tokens-codegen/references/patterns.md +8 -0
  178. package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +6 -0
  179. package/pipeline/skills/shared/external/android-mvi-viewmodel/references/patterns.md +10 -0
  180. package/pipeline/skills/shared/external/android-performance/references/patterns.md +13 -0
  181. package/pipeline/skills/shared/external/android-security/references/patterns.md +16 -0
  182. package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +9 -0
  183. package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +12 -0
  184. package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +13 -0
  185. package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +12 -0
  186. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +9 -0
  187. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +8 -0
  188. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +10 -0
  189. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +21 -0
  190. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +9 -0
  191. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +7 -0
  192. package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -2
  193. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +10 -0
  194. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +10 -1
  195. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +22 -0
  196. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +17 -0
  197. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +22 -0
  198. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +17 -0
  199. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +9 -0
  200. package/pipeline/skills/shared/external/authentication/references/passkeys.md +11 -0
  201. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +13 -0
  202. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +9 -0
  203. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +10 -0
  204. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +15 -0
  205. package/pipeline/skills/shared/external/compose-components/references/patterns.md +7 -0
  206. package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +7 -0
  207. package/pipeline/skills/shared/external/compose-testing/references/patterns.md +15 -0
  208. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +9 -0
  209. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +11 -0
  210. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +10 -0
  211. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +13 -0
  212. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +20 -0
  213. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +16 -0
  214. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +16 -0
  215. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +14 -0
  216. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +13 -0
  217. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +10 -0
  218. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +10 -0
  219. package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +10 -0
  220. package/pipeline/skills/shared/external/gradle-kotlin-dsl/references/patterns.md +17 -0
  221. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +12 -0
  222. package/pipeline/skills/shared/external/hig-app-icons/references/icon-workflow.md +10 -0
  223. package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +10 -0
  224. package/pipeline/skills/shared/external/hig-components-layout/references/bars-and-tabs.md +11 -0
  225. package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +13 -0
  226. package/pipeline/skills/shared/external/hig-foundations/references/type-color-spacing.md +13 -0
  227. package/pipeline/skills/shared/external/hig-patterns/references/onboarding-and-states.md +11 -0
  228. package/pipeline/skills/shared/external/hig-platforms/references/ipad-layout.md +12 -0
  229. package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +16 -0
  230. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +9 -0
  231. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +18 -0
  232. package/pipeline/skills/shared/external/ios-accessibility/references/large-content-and-appearance.md +9 -0
  233. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +9 -0
  234. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +7 -0
  235. package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +13 -0
  236. package/pipeline/skills/shared/external/ios-design-review/references/appearance-matrix.md +9 -0
  237. package/pipeline/skills/shared/external/ios-design-review/references/checklist.md +15 -0
  238. package/pipeline/skills/shared/external/ios-haptics/references/core-haptics.md +11 -0
  239. package/pipeline/skills/shared/external/ios-iphone-duo/references/api-map.md +11 -0
  240. package/pipeline/skills/shared/external/ios-iphone-duo/references/fixed-assumptions.md +15 -0
  241. package/pipeline/skills/shared/external/ios-iphone-duo/references/poses-and-panes.md +11 -0
  242. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +18 -0
  243. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +19 -0
  244. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +15 -0
  245. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +7 -0
  246. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +8 -0
  247. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +12 -0
  248. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +17 -0
  249. package/pipeline/skills/shared/external/ios-security/references/app-review-guidelines.md +8 -0
  250. package/pipeline/skills/shared/external/ios-security/references/cryptokit-advanced.md +14 -0
  251. package/pipeline/skills/shared/external/ios-security/references/file-storage-patterns.md +8 -0
  252. package/pipeline/skills/shared/external/ios-security/references/privacy-manifest.md +9 -0
  253. package/pipeline/skills/shared/external/ios-sf-symbols/references/effects-and-custom-symbols.md +9 -0
  254. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +13 -0
  255. package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +8 -0
  256. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +21 -0
  257. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +9 -0
  258. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +12 -0
  259. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +16 -0
  260. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +21 -0
  261. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +10 -0
  262. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +9 -0
  263. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +12 -0
  264. package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +11 -0
  265. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +11 -0
  266. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +18 -0
  267. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +11 -0
  268. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +11 -0
  269. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +15 -0
  270. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +14 -0
  271. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +14 -0
  272. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +14 -0
  273. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +14 -0
  274. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +10 -0
  275. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +12 -0
  276. package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +14 -0
  277. package/pipeline/skills/shared/external/room-database/references/patterns.md +16 -0
  278. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +10 -0
  279. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +10 -0
  280. package/pipeline/skills/shared/external/spm-build-analysis/references/build-optimization-sources.md +14 -0
  281. package/pipeline/skills/shared/external/spm-build-analysis/references/spm-analysis-checks.md +19 -0
  282. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +13 -0
  283. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +31 -0
  284. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +8 -0
  285. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +9 -0
  286. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +10 -0
  287. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +8 -0
  288. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +24 -0
  289. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +8 -0
  290. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +14 -0
  291. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +12 -0
  292. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +10 -0
  293. package/pipeline/skills/shared/external/swift-concurrency-expert/references/swift-6-2-concurrency.md +8 -0
  294. package/pipeline/skills/shared/external/swift-concurrency-pro/references/actors.md +10 -0
  295. package/pipeline/skills/shared/external/swift-concurrency-pro/references/cancellation.md +7 -0
  296. package/pipeline/skills/shared/external/swift-concurrency-pro/references/interop.md +10 -0
  297. package/pipeline/skills/shared/external/swift-concurrency-pro/references/new-features.md +11 -0
  298. package/pipeline/skills/shared/external/swift-concurrency-pro/references/structured.md +9 -0
  299. package/pipeline/skills/shared/external/swift-concurrency-pro/references/testing.md +13 -0
  300. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +7 -0
  301. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +14 -0
  302. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +16 -0
  303. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +17 -0
  304. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +19 -0
  305. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +16 -0
  306. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +19 -0
  307. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +18 -0
  308. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +16 -0
  309. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +17 -0
  310. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +17 -0
  311. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +17 -0
  312. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +18 -0
  313. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +21 -0
  314. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +16 -0
  315. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +16 -0
  316. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +9 -0
  317. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +24 -0
  318. package/pipeline/skills/shared/external/swift-testing-pro/references/async-tests.md +9 -0
  319. package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +11 -0
  320. package/pipeline/skills/shared/external/swift-testing-pro/references/writing-better-tests.md +13 -0
  321. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +8 -0
  322. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +17 -0
  323. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +12 -0
  324. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +11 -0
  325. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +7 -0
  326. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +13 -0
  327. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +24 -0
  328. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +12 -0
  329. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +15 -0
  330. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +15 -0
  331. package/pipeline/skills/shared/external/swiftui-animation/references/scroll-effects.md +12 -0
  332. package/pipeline/skills/shared/external/swiftui-expert-skill/references/accessibility-patterns.md +11 -0
  333. package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-advanced.md +7 -0
  334. package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-basics.md +13 -0
  335. package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-transitions.md +9 -0
  336. package/pipeline/skills/shared/external/swiftui-expert-skill/references/charts-accessibility.md +9 -0
  337. package/pipeline/skills/shared/external/swiftui-expert-skill/references/charts.md +17 -0
  338. package/pipeline/skills/shared/external/swiftui-expert-skill/references/image-optimization.md +9 -0
  339. package/pipeline/skills/shared/external/swiftui-expert-skill/references/latest-apis.md +10 -0
  340. package/pipeline/skills/shared/external/swiftui-expert-skill/references/layout-best-practices.md +12 -0
  341. package/pipeline/skills/shared/external/swiftui-expert-skill/references/list-patterns.md +12 -0
  342. package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-scenes.md +13 -0
  343. package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-views.md +12 -0
  344. package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-window-styling.md +12 -0
  345. package/pipeline/skills/shared/external/swiftui-expert-skill/references/performance-patterns.md +7 -0
  346. package/pipeline/skills/shared/external/swiftui-expert-skill/references/scroll-patterns.md +9 -0
  347. package/pipeline/skills/shared/external/swiftui-expert-skill/references/sheet-navigation-patterns.md +10 -0
  348. package/pipeline/skills/shared/external/swiftui-expert-skill/references/state-management.md +18 -0
  349. package/pipeline/skills/shared/external/swiftui-expert-skill/references/view-structure.md +16 -0
  350. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +11 -0
  351. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +8 -0
  352. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +14 -0
  353. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +9 -0
  354. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +22 -0
  355. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/uikit-glass.md +14 -0
  356. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +10 -0
  357. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +10 -0
  358. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +13 -0
  359. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +10 -0
  360. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +14 -0
  361. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +30 -0
  362. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +16 -0
  363. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +11 -0
  364. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +11 -0
  365. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +10 -0
  366. package/pipeline/skills/shared/external/swiftui-performance-audit/references/code-smells.md +8 -0
  367. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/app-wiring.md +12 -0
  368. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/menu-bar.md +10 -0
  369. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/navigationstack.md +11 -0
  370. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/scroll-reveal.md +12 -0
  371. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/sheets.md +14 -0
  372. package/pipeline/skills/shared/external/swiftui-ui-patterns/references/tabview.md +10 -0
  373. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +10 -0
  374. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +13 -0
  375. package/pipeline/skills/shared/external/swiftui-view-refactor/references/mv-patterns.md +12 -0
  376. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +8 -0
  377. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +8 -0
  378. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +14 -0
  379. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +17 -0
  380. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +11 -0
  381. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +11 -0
  382. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +27 -0
  383. package/pipeline/skills/shared/external/xcode-build-fixer/references/build-settings-best-practices.md +9 -0
  384. package/pipeline/skills/shared/external/xcode-build-fixer/references/fix-patterns.md +7 -0
  385. package/pipeline/skills/shared/external/xcode-build-orchestrator/references/build-settings-best-practices.md +9 -0
  386. package/pipeline/skills/shared/external/xcode-compilation-analyzer/references/build-optimization-sources.md +14 -0
  387. package/pipeline/skills/shared/external/xcode-compilation-analyzer/references/code-compilation-checks.md +8 -0
  388. package/pipeline/skills/shared/external/xcode-project-analyzer/references/build-optimization-sources.md +14 -0
  389. package/pipeline/skills/shared/external/xcode-project-analyzer/references/build-settings-best-practices.md +9 -0
  390. package/pipeline/skills/shared/external/xcode-project-analyzer/references/project-audit-checks.md +13 -0
@@ -1,8 +1,8 @@
1
1
  // Generated by pipeline/contract/build.mjs from pipeline/schemas/*.schema.json.
2
2
  // Do not edit: change the schema and run `node pipeline/contract/build.mjs --write`.
3
3
 
4
- export type ContractVersion = "1.6.0";
5
- export type SurfaceId = "runs" | "run" | "commands" | "questions" | "issues" | "worktrees" | "launch-spec" | "repos" | "repo-add" | "repo-remove" | "launch" | "answer" | "run-log" | "resume" | "kill" | "gc" | "autopilot" | "autopilot-off" | "phone-runs" | "phone-run" | "phone-answer" | "phone-launch" | "autopilot-on" | "steer" | "activity" | "activity-stream" | "agent-chat" | "routines" | "routine-delete" | "jobs" | "job-start" | "stack" | "stack-set" | "ledger" | "system" | "prune-logs" | "settings" | "settings-set" | "credentials" | "memory" | "run-results" | "run-evidence" | "review-verdict" | "issue-maturity" | "prs" | "tools" | "tool-call" | "service-confluence" | "service-crashlytics" | "service-figma" | "permissions";
4
+ export type ContractVersion = "1.7.0";
5
+ export type SurfaceId = "runs" | "run" | "commands" | "questions" | "issues" | "worktrees" | "launch-spec" | "repos" | "repo-add" | "repo-remove" | "launch" | "answer" | "run-log" | "resume" | "kill" | "gc" | "autopilot" | "autopilot-off" | "phone-runs" | "phone-run" | "phone-answer" | "phone-launch" | "autopilot-on" | "steer" | "activity" | "activity-stream" | "agent-chat" | "routines" | "routine-delete" | "jobs" | "job-start" | "stack" | "stack-set" | "ledger" | "system" | "prune-logs" | "settings" | "settings-set" | "credentials" | "memory" | "run-results" | "run-evidence" | "review-verdict" | "issue-maturity" | "prs" | "prs-reach" | "tools" | "tool-call" | "service-confluence" | "service-crashlytics" | "service-figma" | "permissions";
6
6
 
7
7
  /** What `runs-index.mjs --json` prints: every run under the log root and the unattended log root (one record per task id), grouped per status/SKILL.md 3b. Fields are only ever added - a decoder ignores keys it does not know. `--redact` drops every x-sensitivity local field (and `logsRoot`) and scrubs the free text in the title, `now`, sub-step names, task subjects and the pending question. */
8
8
  export interface RunsIndex {
@@ -1202,6 +1202,28 @@ export interface Prs {
1202
1202
  }>;
1203
1203
  }
1204
1204
 
1205
+ /** What GET /v1/prs/reach returns (`work-items.mjs reach`): for each open GitHub pull request (at most 20), how many files in the repository's own code graph depend on what it changes, widest first. Changed paths serve only as keys into the local graph and are never returned. A pull request that cannot be measured carries reach null and its reason. */
1206
+ export interface PrReach {
1207
+ contractVersion: string;
1208
+ /** Reverse-dependency depth the count was taken at. */
1209
+ depth: number;
1210
+ items: Array<{
1211
+ source: "github" | "bitbucket";
1212
+ repo: string;
1213
+ number: number;
1214
+ /** The knowledge-folder project whose graph answered, or null. */
1215
+ project: string | null;
1216
+ /** Files the pull request changes. */
1217
+ changed?: number;
1218
+ /** Of those, files the graph knows. */
1219
+ inGraph?: number;
1220
+ /** Files that depend on the changed ones, within depth. Null when not measured. */
1221
+ reach: number | null;
1222
+ /** Why reach is null. */
1223
+ reason?: string;
1224
+ }>;
1225
+ }
1226
+
1205
1227
  /** The body of POST /v1/runs/{id}/review-verdict: empty for the preview, confirmToken to post. The verdict is never chosen by the request; it follows from the review's recorded findings. */
1206
1228
  export interface ReviewVerdictRequest {
1207
1229
  contractVersion: string;
@@ -18,9 +18,12 @@
18
18
 
19
19
  import {
20
20
  chmodSync,
21
+ closeSync,
22
+ fstatSync,
21
23
  linkSync,
22
24
  lstatSync,
23
25
  mkdirSync,
26
+ openSync,
24
27
  readFileSync,
25
28
  readlinkSync,
26
29
  realpathSync,
@@ -47,22 +50,70 @@ export class FileLockTimeout extends Error {
47
50
 
48
51
  const pause = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
49
52
 
50
- function staleIdentity(lockPath, staleMs) {
51
- let pid;
52
- let st;
53
+ /**
54
+ * The PID inside a lock file and that file's identity, read through one
55
+ * descriptor. Read by path twice, the PID can come from a lock that was
56
+ * released in between and the identity from the one acquired after it, which
57
+ * makes a live lock look like a dead holder's.
58
+ *
59
+ * @param {string} lockPath
60
+ * @returns {{pid: number, ino: number, mtimeMs: number} | null}
61
+ */
62
+ export function readLockOwner(lockPath) {
63
+ let fd;
53
64
  try {
54
- pid = parseInt(readFileSync(lockPath, "utf8").trim(), 10);
55
- st = statSync(lockPath);
65
+ fd = openSync(lockPath, "r");
66
+ const st = fstatSync(fd);
67
+ const pid = parseInt(readFileSync(fd, "utf8").trim(), 10);
68
+ return { pid, ino: st.ino, mtimeMs: st.mtimeMs };
56
69
  } catch {
57
70
  return null;
71
+ } finally {
72
+ if (fd !== undefined) closeSync(fd);
58
73
  }
59
- const age = Date.now() - st.mtimeMs;
60
- if (!Number.isInteger(pid) || pid <= 0) return age > staleMs ? st : null;
74
+ }
75
+
76
+ /**
77
+ * Remove the lock judged stale, and only that one. The lock is first moved to
78
+ * a name private to this process, so the file examined is the file removed; a
79
+ * live lock that took its place in the meantime is linked back as the same
80
+ * file, which its holder's release recognises by inode.
81
+ *
82
+ * @param {string} lockPath
83
+ * @param {{ino: number, mtimeMs: number}} judged
84
+ * @returns {boolean} true when the stale lock was removed
85
+ */
86
+ export function reapLock(lockPath, judged) {
87
+ const reap = `${lockPath}.${process.pid}.reap`;
61
88
  try {
62
- process.kill(pid, 0);
89
+ renameSync(lockPath, reap);
90
+ } catch {
91
+ return false;
92
+ }
93
+ const st = statSync(reap);
94
+ if (st.ino === judged.ino && st.mtimeMs === judged.mtimeMs) {
95
+ unlinkSync(reap);
96
+ return true;
97
+ }
98
+ try {
99
+ linkSync(reap, lockPath);
100
+ } catch {
101
+ /* a new holder already has the path; the displaced one keeps its inode */
102
+ }
103
+ unlinkSync(reap);
104
+ return false;
105
+ }
106
+
107
+ function staleIdentity(lockPath, staleMs) {
108
+ const owner = readLockOwner(lockPath);
109
+ if (!owner) return null;
110
+ const age = Date.now() - owner.mtimeMs;
111
+ if (!Number.isInteger(owner.pid) || owner.pid <= 0) return age > staleMs ? owner : null;
112
+ try {
113
+ process.kill(owner.pid, 0);
63
114
  return null;
64
115
  } catch (err) {
65
- return err.code === "ESRCH" ? st : null;
116
+ return err.code === "ESRCH" ? owner : null;
66
117
  }
67
118
  }
68
119
 
@@ -82,12 +133,7 @@ function acquire(lockPath, timeoutMs, staleMs) {
82
133
  }
83
134
  const stale = staleIdentity(lockPath, staleMs);
84
135
  if (stale) {
85
- try {
86
- const now = statSync(lockPath);
87
- if (now.ino === stale.ino && now.mtimeMs === stale.mtimeMs) unlinkSync(lockPath);
88
- } catch {
89
- /* gone already */
90
- }
136
+ reapLock(lockPath, stale);
91
137
  continue;
92
138
  }
93
139
  if (Date.now() >= deadline) throw new FileLockTimeout(lockPath, timeoutMs);
@@ -0,0 +1,228 @@
1
+ /**
2
+ * office-remote.mjs - the machine side of the office remote layer
3
+ * (features/office-remote-protocol.md).
4
+ *
5
+ * - Keys: P-256 ECDH between the machine key and the phone's session key,
6
+ * through HKDF-SHA-256 with the pairing id as salt, into one AES-256 key per
7
+ * direction.
8
+ * - Frames: AES-256-GCM; the 12-byte nonce is a 4-byte direction tag and an
9
+ * 8-byte counter, so a frame opens only in its own direction and a counter
10
+ * that does not exceed the last accepted one is refused as a replay.
11
+ * - Pairing: the phone's first message is sealed with a key that also mixes in
12
+ * the one-time pairing secret from the QR code, so the relay cannot open it
13
+ * even holding both public keys.
14
+ * - Comparison code: six digits from both public keys, the same on either end.
15
+ * - Passkey: a WebAuthn assertion checked against the paired credential key,
16
+ * rp id, origin, the request-bound challenge, user verification and the sign
17
+ * count.
18
+ *
19
+ * Zero runtime dependencies (ADR-0004): node:crypto only.
20
+ *
21
+ * @module pipeline/lib/office-remote
22
+ */
23
+
24
+ import {
25
+ createCipheriv,
26
+ createDecipheriv,
27
+ createHash,
28
+ createPrivateKey,
29
+ createPublicKey,
30
+ diffieHellman,
31
+ generateKeyPairSync,
32
+ hkdfSync,
33
+ timingSafeEqual,
34
+ verify,
35
+ } from "node:crypto";
36
+
37
+ const DIRECTIONS = { "phone-to-machine": 1, "machine-to-phone": 2 };
38
+ const INFO = "ma-office v1 ";
39
+ const MAX_COUNTER = 2 ** 48;
40
+
41
+ const b64u = (b) => Buffer.from(b).toString("base64url");
42
+ const fromB64u = (s) => Buffer.from(String(s || ""), "base64url");
43
+ const sha256 = (b) => createHash("sha256").update(b).digest();
44
+
45
+ /** A new machine key pair: PKCS#8 PEM private key, base64url SPKI public key. */
46
+ export function createMachineKeys() {
47
+ const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "prime256v1" });
48
+ return {
49
+ privatePem: privateKey.export({ type: "pkcs8", format: "pem" }),
50
+ publicKey: b64u(publicKey.export({ type: "spki", format: "der" })),
51
+ };
52
+ }
53
+
54
+ function shared(privatePem, peerPublic) {
55
+ return diffieHellman({
56
+ privateKey: createPrivateKey(privatePem),
57
+ publicKey: createPublicKey({ key: fromB64u(peerPublic), format: "der", type: "spki" }),
58
+ });
59
+ }
60
+
61
+ const derive = (ikm, pairingId, label) =>
62
+ Buffer.from(
63
+ hkdfSync("sha256", ikm, Buffer.from(String(pairingId)), Buffer.from(INFO + label), 32),
64
+ );
65
+
66
+ /**
67
+ * The two AES keys of a pairing, from this end's point of view.
68
+ *
69
+ * @param {{privatePem: string, peerPublic: string, pairingId: string, role: "machine"|"phone"}} p
70
+ * @returns {{send: Buffer, recv: Buffer}}
71
+ */
72
+ export function directionKeys({ privatePem, peerPublic, pairingId, role }) {
73
+ const ikm = shared(privatePem, peerPublic);
74
+ const p2m = derive(ikm, pairingId, "phone-to-machine");
75
+ const m2p = derive(ikm, pairingId, "machine-to-phone");
76
+ return role === "machine" ? { send: m2p, recv: p2m } : { send: p2m, recv: m2p };
77
+ }
78
+
79
+ function nonceFor(direction, counter) {
80
+ const tag = DIRECTIONS[direction];
81
+ if (!tag) throw new Error(`unknown direction ${direction}`);
82
+ if (!Number.isSafeInteger(counter) || counter < 1 || counter >= MAX_COUNTER) {
83
+ throw new Error("counter out of range");
84
+ }
85
+ const iv = Buffer.alloc(12);
86
+ iv.writeUInt32BE(tag, 0);
87
+ iv.writeUIntBE(counter, 6, 6);
88
+ return iv;
89
+ }
90
+
91
+ /** Seal a JSON value as one frame. */
92
+ export function sealFrame(key, counter, direction, value) {
93
+ const iv = nonceFor(direction, counter);
94
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
95
+ cipher.setAAD(Buffer.from(direction));
96
+ const body = Buffer.concat([cipher.update(JSON.stringify(value), "utf8"), cipher.final()]);
97
+ return { counter, ct: b64u(Buffer.concat([body, cipher.getAuthTag()])) };
98
+ }
99
+
100
+ /**
101
+ * Open one frame. Refuses a counter that does not exceed `lastCounter`, a
102
+ * frame for the other direction and any altered byte.
103
+ *
104
+ * @returns {{ok: true, value: unknown, counter: number} | {ok: false, reason: string}}
105
+ */
106
+ export function openFrame(key, frame, direction, lastCounter) {
107
+ const counter = Number(frame?.counter);
108
+ if (!Number.isSafeInteger(counter) || counter <= Number(lastCounter || 0)) {
109
+ return { ok: false, reason: "counter did not grow (replay or reorder)" };
110
+ }
111
+ let iv;
112
+ try {
113
+ iv = nonceFor(direction, counter);
114
+ } catch (err) {
115
+ return { ok: false, reason: err.message };
116
+ }
117
+ const raw = fromB64u(frame?.ct);
118
+ if (raw.length < 17) return { ok: false, reason: "frame too short" };
119
+ try {
120
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
121
+ decipher.setAAD(Buffer.from(direction));
122
+ decipher.setAuthTag(raw.subarray(raw.length - 16));
123
+ const text = Buffer.concat([
124
+ decipher.update(raw.subarray(0, raw.length - 16)),
125
+ decipher.final(),
126
+ ]);
127
+ return { ok: true, value: JSON.parse(text.toString("utf8")), counter };
128
+ } catch {
129
+ return { ok: false, reason: "frame did not authenticate" };
130
+ }
131
+ }
132
+
133
+ function pairingKey({ privatePem, peerPublic, secret, pairingId }) {
134
+ const ikm = Buffer.concat([shared(privatePem, peerPublic), fromB64u(secret)]);
135
+ return derive(ikm, pairingId, "pairing");
136
+ }
137
+
138
+ /** Seal the phone's pairing message (counter 1, phone to machine). */
139
+ export function sealPairing({ privatePem, peerPublic, secret, pairingId, value }) {
140
+ return sealFrame(
141
+ pairingKey({ privatePem, peerPublic, secret, pairingId }),
142
+ 1,
143
+ "phone-to-machine",
144
+ value,
145
+ );
146
+ }
147
+
148
+ /** Open the phone's pairing message with the machine key and the pairing secret. */
149
+ export function openPairing({ privatePem, peerPublic, secret, pairingId, sealed }) {
150
+ try {
151
+ const key = pairingKey({ privatePem, peerPublic, secret, pairingId });
152
+ const r = openFrame(key, sealed, "phone-to-machine", 0);
153
+ return r.ok ? { ok: true, value: r.value } : r;
154
+ } catch {
155
+ return { ok: false, reason: "pairing message could not be opened" };
156
+ }
157
+ }
158
+
159
+ /** Six digits from two public keys, independent of their order. */
160
+ export function comparisonCode(a, b) {
161
+ const [x, y] = [String(a), String(b)].sort();
162
+ const n = sha256(Buffer.from(`${INFO}compare\n${x}\n${y}`)).readUInt32BE(0) % 1_000_000;
163
+ return String(n).padStart(6, "0");
164
+ }
165
+
166
+ const sameBytes = (a, b) => a.length === b.length && timingSafeEqual(a, b);
167
+
168
+ /**
169
+ * Check a WebAuthn assertion against the paired passkey.
170
+ *
171
+ * @param {object} p
172
+ * @param {{authenticatorData: string, clientDataJSON: string, signature: string}} p.assertion base64url fields
173
+ * @param {string} p.credential base64url SPKI of the passkey public key
174
+ * @param {string} p.rpId
175
+ * @param {string} p.origin
176
+ * @param {Buffer} p.challenge the bytes this request binds (SHA-256 of its canonical signed text)
177
+ * @param {number} [p.prevSignCount]
178
+ * @returns {{ok: true, signCount: number} | {ok: false, reason: string}}
179
+ */
180
+ export function verifyPasskey({
181
+ assertion,
182
+ credential,
183
+ rpId,
184
+ origin,
185
+ challenge,
186
+ prevSignCount = 0,
187
+ }) {
188
+ const authData = fromB64u(assertion?.authenticatorData);
189
+ const clientRaw = fromB64u(assertion?.clientDataJSON);
190
+ if (authData.length < 37) return { ok: false, reason: "authenticator data too short" };
191
+ let client;
192
+ try {
193
+ client = JSON.parse(clientRaw.toString("utf8"));
194
+ } catch {
195
+ return { ok: false, reason: "client data is not JSON" };
196
+ }
197
+ if (client?.type !== "webauthn.get")
198
+ return { ok: false, reason: "client data type is not webauthn.get" };
199
+ if (!sameBytes(fromB64u(client.challenge), Buffer.from(challenge))) {
200
+ return { ok: false, reason: "challenge is not this request" };
201
+ }
202
+ if (client.origin !== origin) return { ok: false, reason: "origin is not the paired one" };
203
+ if (!sameBytes(authData.subarray(0, 32), sha256(Buffer.from(rpId)))) {
204
+ return { ok: false, reason: "rp id is not the paired one" };
205
+ }
206
+ const flags = authData[32];
207
+ if (!(flags & 0x01) || !(flags & 0x04))
208
+ return { ok: false, reason: "the user was not present and verified" };
209
+ const signCount = authData.readUInt32BE(33);
210
+ if ((signCount !== 0 || prevSignCount !== 0) && signCount <= prevSignCount) {
211
+ return { ok: false, reason: "sign count did not grow (a cloned authenticator or a replay)" };
212
+ }
213
+ let good;
214
+ try {
215
+ const key = createPublicKey({ key: fromB64u(credential), format: "der", type: "spki" });
216
+ good = verify(
217
+ "sha256",
218
+ Buffer.concat([authData, sha256(clientRaw)]),
219
+ key,
220
+ fromB64u(assertion.signature),
221
+ );
222
+ } catch {
223
+ good = false;
224
+ }
225
+ return good
226
+ ? { ok: true, signCount }
227
+ : { ok: false, reason: "signature does not verify with the paired passkey" };
228
+ }