@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
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @file graph-links.mjs - which files of one repository import another.
4
+ *
5
+ * Each repository keeps its own code graph (ADR-0010); a run that touches a
6
+ * main repository and its libraries needs to know where they meet. This joins
7
+ * graphs without merging them: a repository's import of a name it does not
8
+ * declare (a `module:` node) is matched against the names other repositories
9
+ * export, and every match becomes one link row.
10
+ *
11
+ * What a repository exports, by stack:
12
+ * node the `name` in package.json
13
+ * python top-level package directories (they hold __init__.py)
14
+ * ios target directories under Sources/
15
+ * go the module path in go.mod
16
+ * android top-level, non-nested type and composable declarations, since a
17
+ * Kotlin import names a class
18
+ * any the repository directory name, when the stack names nothing
19
+ *
20
+ * A Kotlin import keeps only its last segment in the graph, and names like
21
+ * `Text` or `Result` exist in many packages. An android link therefore holds
22
+ * only the importing files whose `import <package>.<Name>` names the package
23
+ * the exporting file declares; both repositories are read from disk for it.
24
+ *
25
+ * Usage:
26
+ * graph-links.mjs build --projects <a,b,...> [--out <path>]
27
+ * graph-links.mjs affected --project <b> [--name <module-or-symbol>] [--links <path>]
28
+ *
29
+ * Projects are directory names under ~/.claude/knowledge/. `build` writes
30
+ * ~/.claude/knowledge/_links.json unless --out says otherwise. `affected`
31
+ * lists the files in other repositories that import project b (or one of
32
+ * its names), so a change there can be followed across.
33
+ *
34
+ * Exit: 0 done · 1 a graph or the link file is missing · 64 usage
35
+ *
36
+ * @module pipeline/scripts/graph-links
37
+ */
38
+
39
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
40
+ import { homedir } from "node:os";
41
+ import { basename, join, resolve } from "node:path";
42
+
43
+ import { loadGraph } from "./graph-query.mjs";
44
+ import { invokedDirectly } from "../lib/invoked-directly.mjs";
45
+
46
+ const KNOWLEDGE = () => join(homedir(), ".claude", "knowledge");
47
+ const PROJECT_RE = /^[A-Za-z0-9._-]+$/;
48
+ const ANDROID_KINDS = new Set(["class", "object", "interface", "enum", "composable", "typealias"]);
49
+
50
+ function readText(p) {
51
+ try {
52
+ return readFileSync(p, "utf8");
53
+ } catch {
54
+ return null;
55
+ }
56
+ }
57
+
58
+ function dirs(p) {
59
+ try {
60
+ return readdirSync(p, { withFileTypes: true })
61
+ .filter((d) => d.isDirectory() && !d.name.startsWith("."))
62
+ .map((d) => d.name);
63
+ } catch {
64
+ return [];
65
+ }
66
+ }
67
+
68
+ /** name -> what it points at in this repository (a symbol id, or null for the repo). */
69
+ export function exportsOf(graph) {
70
+ const out = new Map();
71
+ const root = graph.root || "";
72
+ if (graph.stack === "node") {
73
+ const pkg = readText(join(root, "package.json"));
74
+ try {
75
+ const name = JSON.parse(pkg ?? "null")?.name;
76
+ if (typeof name === "string" && name) out.set(name, null);
77
+ } catch {
78
+ /* no package name */
79
+ }
80
+ } else if (graph.stack === "python") {
81
+ for (const d of dirs(root)) if (existsSync(join(root, d, "__init__.py"))) out.set(d, null);
82
+ } else if (graph.stack === "ios") {
83
+ for (const d of dirs(join(root, "Sources"))) out.set(d, null);
84
+ } else if (graph.stack === "go") {
85
+ const mod = /^module\s+(\S+)/m.exec(readText(join(root, "go.mod")) ?? "");
86
+ if (mod) out.set(mod[1], null);
87
+ } else if (graph.stack === "android") {
88
+ for (const n of graph.nodes) {
89
+ if (n.kind === "symbol" && !n.nested && ANDROID_KINDS.has(n.symbolKind) && !out.has(n.name))
90
+ out.set(n.name, n.id);
91
+ }
92
+ }
93
+ if (!out.size && root) out.set(basename(root), null);
94
+ return out;
95
+ }
96
+
97
+ /** The package a Kotlin symbol's file declares, or null. */
98
+ function kotlinPackage(root, symbolId, cache) {
99
+ const rel = symbolId.slice("sym:".length, symbolId.lastIndexOf("#"));
100
+ const key = `${root}\0${rel}`;
101
+ if (!cache.has(key)) {
102
+ const text = rel.includes("..") ? null : readText(join(root, rel));
103
+ cache.set(key, /^\s*package\s+([\w.]+)/m.exec(text ?? "")?.[1] ?? null);
104
+ }
105
+ return cache.get(key);
106
+ }
107
+
108
+ /** True when the file imports `name` from exactly that package. */
109
+ function importsFrom(root, rel, pkg, name) {
110
+ if (rel.includes("..")) return false;
111
+ const text = readText(join(root, rel)) ?? "";
112
+ const esc = (v) => v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
113
+ return new RegExp(`^\\s*import\\s+${esc(pkg)}\\.${esc(name)}(?![\\w])`, "m").test(text);
114
+ }
115
+
116
+ /** The names an import could be asking for: itself, and its package prefix. */
117
+ export function candidates(moduleName) {
118
+ const m = String(moduleName);
119
+ const set = new Set([m]);
120
+ if (m.startsWith("@")) set.add(m.split("/").slice(0, 2).join("/"));
121
+ else set.add(m.split(/[/.]/)[0]);
122
+ return [...set];
123
+ }
124
+
125
+ /** Link rows between every pair of the given graphs. */
126
+ export function link(graphs) {
127
+ const exported = graphs.map((g) => ({
128
+ project: g.project,
129
+ graph: g.graph,
130
+ names: exportsOf(g.graph),
131
+ }));
132
+ const packages = new Map();
133
+ const rows = [];
134
+ for (const { project, graph } of graphs) {
135
+ const importers = new Map();
136
+ for (const e of graph.edges) {
137
+ if (e.kind !== "imports" || !e.to.startsWith("module:")) continue;
138
+ if (!importers.has(e.to)) importers.set(e.to, []);
139
+ importers.get(e.to).push(e.from.replace(/^file:/, ""));
140
+ }
141
+ for (const [mid, files] of importers) {
142
+ const name = mid.slice("module:".length);
143
+ for (const other of exported) {
144
+ if (other.project === project) continue;
145
+ const hit = candidates(name).find((c) => other.names.has(c));
146
+ if (hit === undefined) continue;
147
+ const target = other.names.get(hit);
148
+ let kept = [...new Set(files)].sort();
149
+ if (other.graph.stack === "android" && target) {
150
+ const pkg = kotlinPackage(other.graph.root || "", target, packages);
151
+ kept = pkg ? kept.filter((f) => importsFrom(graph.root || "", f, pkg, hit)) : [];
152
+ }
153
+ if (!kept.length) continue;
154
+ rows.push({ from: project, module: name, to: other.project, target, files: kept });
155
+ }
156
+ }
157
+ }
158
+ return rows.sort(
159
+ (a, b) =>
160
+ a.to.localeCompare(b.to) || a.from.localeCompare(b.from) || a.module.localeCompare(b.module),
161
+ );
162
+ }
163
+
164
+ function graphPath(project) {
165
+ if (!PROJECT_RE.test(project) || project === "." || project === "..")
166
+ throw new Error(`not a project name: ${project}`);
167
+ return join(KNOWLEDGE(), project, "code-graph.json");
168
+ }
169
+
170
+ function flag(argv, name) {
171
+ const i = argv.indexOf(`--${name}`);
172
+ return i >= 0 ? argv[i + 1] : undefined;
173
+ }
174
+
175
+ function main(argv) {
176
+ const sub = argv[0];
177
+ const linksPath = resolve(
178
+ flag(argv, "links") || flag(argv, "out") || join(KNOWLEDGE(), "_links.json"),
179
+ );
180
+ if (sub === "build") {
181
+ const projects = (flag(argv, "projects") || "").split(",").filter(Boolean);
182
+ if (projects.length < 2) return usage();
183
+ let graphs;
184
+ try {
185
+ graphs = projects.map((project) => ({ project, graph: loadGraph(graphPath(project)) }));
186
+ } catch (e) {
187
+ process.stderr.write(`graph-links: ${e.message}\n`);
188
+ return 1;
189
+ }
190
+ const rows = link(graphs);
191
+ const doc = { v: 1, builtAt: new Date().toISOString(), projects, links: rows };
192
+ writeFileSync(linksPath, JSON.stringify(doc, null, 2) + "\n", { mode: 0o600 });
193
+ process.stdout.write(JSON.stringify({ out: linksPath, projects, links: rows.length }) + "\n");
194
+ return 0;
195
+ }
196
+ if (sub === "affected") {
197
+ const project = flag(argv, "project");
198
+ if (!project) return usage();
199
+ const doc = readText(linksPath);
200
+ if (!doc) {
201
+ process.stderr.write(`graph-links: no link file at ${linksPath}; run build first\n`);
202
+ return 1;
203
+ }
204
+ const name = flag(argv, "name");
205
+ const hits = JSON.parse(doc).links.filter(
206
+ (r) =>
207
+ r.to === project &&
208
+ (!name ||
209
+ r.module === name ||
210
+ r.target?.endsWith(`#${name}`) ||
211
+ candidates(r.module).includes(name)),
212
+ );
213
+ process.stdout.write(
214
+ JSON.stringify({ project, name: name ?? null, importers: hits }, null, 2) + "\n",
215
+ );
216
+ return 0;
217
+ }
218
+ return usage();
219
+ }
220
+
221
+ function usage() {
222
+ process.stderr.write(
223
+ "usage: graph-links.mjs build --projects <a,b,...> [--out <path>] | affected --project <b> [--name <n>] [--links <path>]\n",
224
+ );
225
+ return 64;
226
+ }
227
+
228
+ if (invokedDirectly(import.meta.url)) {
229
+ process.exitCode = main(process.argv.slice(2));
230
+ }
@@ -18,9 +18,16 @@
18
18
  * --seeds N How many ranked seeds to expand. Default: 8
19
19
  * --json Emit JSON instead of text
20
20
  *
21
+ * graph-query --path <from> <to> [--max-depth N] [--directed] [--kind K,...]
22
+ * Shortest path between two symbols or files, by node id or
23
+ * by name. A name that matches more than one node is refused
24
+ * with the candidates, never guessed; a name that matches
25
+ * none gets its nearest names.
26
+ *
21
27
  * Exit codes:
22
- * 0 - answered (possibly empty)
28
+ * 0 - answered (possibly empty, or no path within the depth)
23
29
  * 1 - graph missing or unreadable
30
+ * 3 - a --path endpoint is ambiguous or unknown
24
31
  * 64 - usage error
25
32
  *
26
33
  * @module pipeline/scripts/graph-query
@@ -93,6 +100,72 @@ export function rankNodes(graph, question) {
93
100
  .map((s) => ({ node: graph.nodes[s.index], score: s.score }));
94
101
  }
95
102
 
103
+ const CANDIDATES = 5;
104
+
105
+ /**
106
+ * One node for a name or id. Exact id first, then exact name, then the name
107
+ * case-insensitively. More than one match is refused with the candidates; no
108
+ * match returns the nearest names by the same ranking the query uses.
109
+ *
110
+ * @returns {{node: object} | {ambiguous: object[]} | {unknown: object[]}}
111
+ */
112
+ export function resolveNode(graph, ref) {
113
+ const byId = graph.nodes.find((n) => n.id === ref);
114
+ if (byId) return { node: byId };
115
+ let matches = graph.nodes.filter((n) => n.name === ref);
116
+ if (!matches.length) {
117
+ const lower = String(ref).toLowerCase();
118
+ matches = graph.nodes.filter((n) => (n.name || "").toLowerCase() === lower);
119
+ }
120
+ if (matches.length === 1) return { node: matches[0] };
121
+ if (matches.length > 1) return { ambiguous: matches.slice(0, CANDIDATES) };
122
+ return {
123
+ unknown: rankNodes(graph, String(ref))
124
+ .slice(0, CANDIDATES)
125
+ .map((r) => r.node),
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Breadth-first shortest path. Undirected unless `directed`, so a subclass
131
+ * reaches its base and the base reaches the subclass. External module nodes
132
+ * are endpoints only.
133
+ *
134
+ * @returns {{path: Array<{node: object, via: string|null}>} | {path: null}}
135
+ */
136
+ export function shortestPath(
137
+ graph,
138
+ fromId,
139
+ toId,
140
+ { maxDepth = 8, directed = false, kinds = null } = {},
141
+ ) {
142
+ const byId = new Map(graph.nodes.map((n) => [n.id, n]));
143
+ const adj = adjacency(graph);
144
+ const prev = new Map([[fromId, null]]);
145
+ let frontier = [fromId];
146
+ for (let d = 0; d < maxDepth && frontier.length && !prev.has(toId); d++) {
147
+ const next = [];
148
+ for (const id of frontier) {
149
+ for (const n of adj.get(id) || []) {
150
+ if (directed && n.dir !== "out") continue;
151
+ if (kinds && !kinds.includes(n.kind)) continue;
152
+ if (prev.has(n.id)) continue;
153
+ prev.set(n.id, { from: id, via: `${n.kind}/${n.dir}` });
154
+ // An external module joins every file that imports it, so it ends a
155
+ // path but is never walked through.
156
+ if (byId.get(n.id)?.kind !== "module" || n.id === toId) next.push(n.id);
157
+ }
158
+ }
159
+ frontier = next;
160
+ }
161
+ if (!prev.has(toId)) return { path: null };
162
+ const path = [];
163
+ for (let id = toId; id !== null; id = prev.get(id)?.from ?? null) {
164
+ path.unshift({ node: byId.get(id), via: prev.get(id)?.via ?? null });
165
+ }
166
+ return { path };
167
+ }
168
+
96
169
  function renderNode(node) {
97
170
  const where = node.path ? `${node.path}${node.line ? `:${node.line}` : ""}` : "-";
98
171
  const kind = node.symbolKind || node.kind;
@@ -157,8 +230,67 @@ export function traverse({ graph, question, budget, depth, seedCount }) {
157
230
  return { seeds, hits, truncated, tokens };
158
231
  }
159
232
 
233
+ function pathMain(flags, positional, graph) {
234
+ if (positional.length !== 2) {
235
+ process.stderr.write(
236
+ "graph-query: --path needs two endpoints, e.g. --path LoginView AuthService\n",
237
+ );
238
+ return 64;
239
+ }
240
+ const ends = positional.map((ref) => ({ ref, ...resolveNode(graph, ref) }));
241
+ const bad = ends.filter((e) => !e.node);
242
+ if (bad.length) {
243
+ const doc = bad.map((e) => ({
244
+ ref: e.ref,
245
+ reason: e.ambiguous ? "ambiguous" : "unknown",
246
+ candidates: (e.ambiguous || e.unknown).map((n) => ({ id: n.id, line: renderNode(n) })),
247
+ }));
248
+ if (flags.json === true) process.stdout.write(JSON.stringify({ refused: doc }, null, 2) + "\n");
249
+ else
250
+ for (const d of doc) {
251
+ process.stdout.write(`${d.ref}: ${d.reason}; pass one of these ids:\n`);
252
+ for (const c of d.candidates) process.stdout.write(` ${c.id} ${c.line}\n`);
253
+ }
254
+ return 3;
255
+ }
256
+ const maxDepth = Math.min(Number(flags["max-depth"]) > 0 ? Number(flags["max-depth"]) : 8, 12);
257
+ const kinds = typeof flags.kind === "string" ? flags.kind.split(",") : null;
258
+ const { path } = shortestPath(graph, ends[0].node.id, ends[1].node.id, {
259
+ maxDepth,
260
+ directed: flags.directed === true,
261
+ kinds,
262
+ });
263
+ if (flags.json === true) {
264
+ const hops =
265
+ path?.map((h) => ({ id: h.node.id, line: renderNode(h.node), via: h.via })) ?? null;
266
+ process.stdout.write(
267
+ JSON.stringify({ from: ends[0].node.id, to: ends[1].node.id, path: hops }, null, 2) + "\n",
268
+ );
269
+ return 0;
270
+ }
271
+ if (!path) {
272
+ process.stdout.write(`no path within ${maxDepth} hops\n`);
273
+ return 0;
274
+ }
275
+ path.forEach((h, i) => process.stdout.write(`${printedLine(i, renderNode(h.node), h.via)}\n`));
276
+ return 0;
277
+ }
278
+
160
279
  function main() {
161
280
  const { flags, positional } = parseFlags(process.argv.slice(2));
281
+ if (flags.path !== undefined) {
282
+ // parseFlags reads the first endpoint as the flag's value.
283
+ const ends = typeof flags.path === "string" ? [flags.path, ...positional] : positional;
284
+ const path = flags.graph && flags.graph !== true ? resolve(flags.graph) : defaultGraphPath();
285
+ let graph;
286
+ try {
287
+ graph = loadGraph(path);
288
+ } catch (e) {
289
+ process.stderr.write(`graph-query: ${e.message}\n`);
290
+ process.exit(1);
291
+ }
292
+ process.exit(pathMain(flags, ends, graph));
293
+ }
162
294
  const question = positional.join(" ").trim();
163
295
  if (!question) {
164
296
  process.stderr.write('graph-query: a question is required, e.g. graph-query "flight search"\n');
@@ -17,6 +17,8 @@
17
17
  * --out <path> Report path. Default: GRAPH_REPORT.md beside the graph
18
18
  * --top N Rows per ranked section. Default: 15
19
19
  * --stdout Print instead of writing
20
+ * --diff <path> Compare with another build of the same repository (the
21
+ * older one) and print what changed as JSON, writing nothing.
20
22
  * --status Print one header line and exit, writing nothing. This is
21
23
  * what `/multi-agent:graph status` runs: the graph is a
22
24
  * 22MB JSON on a large repo, so "read the header yourself"
@@ -35,6 +37,7 @@ import { join, dirname, resolve } from "node:path";
35
37
  import { parseFlags } from "./graph-build.mjs";
36
38
  import { loadGraph, defaultGraphPath } from "./graph-query.mjs";
37
39
  import { loadRules } from "./_code-graph.mjs";
40
+ import { clusters, graphDiff, importCycles, questions } from "./_graph-analysis.mjs";
38
41
 
39
42
  /**
40
43
  * Top-level source directory of a path, used as the module bucket.
@@ -223,6 +226,49 @@ export function render(graph, top) {
223
226
  }
224
227
  L.push("");
225
228
 
229
+ const cycles = importCycles(graph);
230
+ L.push(`## Import cycles`);
231
+ L.push("");
232
+ if (!cycles.length) {
233
+ L.push(`None: no files import each other, directly or around a loop.`);
234
+ } else {
235
+ L.push(
236
+ `${cycles.length} group(s) of files that import each other. A change to one reaches all of them.`,
237
+ );
238
+ L.push("");
239
+ for (const c of cycles.slice(0, top)) {
240
+ const shown = c
241
+ .slice(0, 6)
242
+ .map((f) => `\`${f.replace(/^file:/, "")}\``)
243
+ .join(", ");
244
+ L.push(`- ${c.length} files: ${shown}${c.length > 6 ? `, ... ${c.length - 6} more` : ""}`);
245
+ }
246
+ }
247
+ L.push("");
248
+
249
+ const groups = clusters(graph);
250
+ L.push(`## Clusters`);
251
+ L.push("");
252
+ L.push(
253
+ `Files more connected to each other than to the rest (label propagation over imports and references). ` +
254
+ `Cohesion is the share of a cluster's edges that stay inside it.`,
255
+ );
256
+ L.push("");
257
+ L.push(`| Files | Cohesion | Around | Where |`);
258
+ L.push(`|---|---|---|---|`);
259
+ for (const g of groups.slice(0, top)) {
260
+ L.push(`| ${g.files.length} | ${g.cohesion} | \`${g.id}\` | ${g.dirs} |`);
261
+ }
262
+ L.push("");
263
+
264
+ const asks = questions(graph, { hubs: s.hubs, cycles, groups });
265
+ if (asks.length) {
266
+ L.push(`## Questions worth asking`);
267
+ L.push("");
268
+ for (const q of asks) L.push(`- ${q}`);
269
+ L.push("");
270
+ }
271
+
226
272
  L.push(`## Modules`);
227
273
  L.push("");
228
274
  L.push(`| Module | Files | Symbols | Test files |`);
@@ -358,7 +404,14 @@ export function statusLine(graph, path) {
358
404
  );
359
405
  }
360
406
 
407
+ const USAGE =
408
+ "usage: graph-report.mjs [--graph <path>] [--out <path>] [--top N] [--stdout] [--diff <older-graph>] [--status]\n";
409
+
361
410
  function main() {
411
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
412
+ process.stdout.write(USAGE);
413
+ return;
414
+ }
362
415
  const { flags } = parseFlags(process.argv.slice(2));
363
416
  const path = flags.graph && flags.graph !== true ? resolve(flags.graph) : defaultGraphPath();
364
417
 
@@ -375,6 +428,18 @@ function main() {
375
428
  return;
376
429
  }
377
430
 
431
+ if (flags.diff && flags.diff !== true) {
432
+ let before;
433
+ try {
434
+ before = loadGraph(resolve(flags.diff));
435
+ } catch (e) {
436
+ process.stderr.write(`graph-report: ${e.message}\n`);
437
+ process.exit(1);
438
+ }
439
+ process.stdout.write(JSON.stringify(graphDiff(before, graph), null, 2) + "\n");
440
+ return;
441
+ }
442
+
378
443
  const top = Number(flags.top) > 0 ? Number(flags.top) : 15;
379
444
  const markdown = render(graph, top);
380
445
 
@@ -53,20 +53,14 @@
53
53
  * Exit: 0 ok (including "nothing found") | 1 usage
54
54
  */
55
55
 
56
- import {
57
- existsSync,
58
- mkdtempSync,
59
- readFileSync,
60
- readdirSync,
61
- rmSync,
62
- statSync,
63
- writeFileSync,
64
- } from "node:fs";
56
+ import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
65
57
  import { execFileSync } from "node:child_process";
66
58
  import { basename, dirname, join } from "node:path";
67
- import { homedir, tmpdir } from "node:os";
59
+ import { homedir } from "node:os";
68
60
  import { fileURLToPath } from "node:url";
69
61
  import { runMain } from "../lib/fatal.mjs";
62
+ import { memoryExcluded } from "./_memory-policy.mjs";
63
+ import { dropSecrets } from "./_secret-scan.mjs";
70
64
 
71
65
  const HERE = dirname(fileURLToPath(import.meta.url));
72
66
  const argv = process.argv.slice(2);
@@ -382,41 +376,6 @@ function mine(events) {
382
376
  return found;
383
377
  }
384
378
 
385
- /* ----------------------------------------------------------------- privacy */
386
-
387
- /**
388
- * The single-source secret check. Candidates go to a temp file and through
389
- * pre-commit-check.sh, which owns the patterns; a hit is dropped, never written.
390
- */
391
- function dropSecrets(items) {
392
- const scanner = existsSync(join(HERE, "pre-commit-check.sh"))
393
- ? join(HERE, "pre-commit-check.sh")
394
- : join(homedir(), ".claude", "scripts", "pre-commit-check.sh");
395
- if (!existsSync(scanner)) {
396
- return { kept: items, dropped: 0, scanned: false };
397
- }
398
- const dir = mkdtempSync(join(tmpdir(), "lft-"));
399
- const kept = [];
400
- let dropped = 0;
401
- try {
402
- for (const it of items) {
403
- const f = join(dir, "candidate.txt");
404
- writeFileSync(f, `${it.statement}\n${it.diagnosis || ""}\n${it.scope}\n`);
405
- let clean = true;
406
- try {
407
- execFileSync("bash", [scanner, "--scan-file", f], { stdio: "ignore" });
408
- } catch {
409
- clean = false;
410
- }
411
- if (clean) kept.push(it);
412
- else dropped++;
413
- }
414
- } finally {
415
- rmSync(dir, { recursive: true, force: true });
416
- }
417
- return { kept, dropped, scanned: true };
418
- }
419
-
420
379
  /* -------------------------------------------------------------------- main */
421
380
 
422
381
  function main() {
@@ -462,12 +421,16 @@ function main() {
462
421
  uniq.push(it);
463
422
  }
464
423
 
465
- const { kept, dropped, scanned } = dropSecrets(uniq);
424
+ const { kept, dropped, scanned } = dropSecrets(
425
+ uniq,
426
+ (it) => `${it.statement}\n${it.diagnosis || ""}\n${it.scope}`,
427
+ );
466
428
  const slug = repoSlug();
429
+ const excluded = memoryExcluded(slug);
467
430
 
468
431
  let written = 0;
469
432
  let deduped = 0;
470
- if (APPLY && kept.length) {
433
+ if (APPLY && kept.length && !excluded) {
471
434
  const ledger = existsSync(join(HERE, "learnings-ledger.mjs"))
472
435
  ? join(HERE, "learnings-ledger.mjs")
473
436
  : join(homedir(), ".claude", "scripts", "learnings-ledger.mjs");
@@ -572,7 +535,7 @@ function main() {
572
535
  }
573
536
 
574
537
  let localFile = null;
575
- if (APPLY && kept.length) localFile = writeLocalBlock(kept);
538
+ if (APPLY && kept.length && !excluded) localFile = writeLocalBlock(kept);
576
539
 
577
540
  // Record how many lessons the machine found, kept apart from the ones a model
578
541
  // proposed. Pooling them lets a "lessons learned" number climb while the half
@@ -595,6 +558,7 @@ function main() {
595
558
  const result = {
596
559
  status: "ok",
597
560
  repo: slug,
561
+ excluded,
598
562
  transcripts: files.length,
599
563
  toolResultsExamined: examined,
600
564
  candidates: uniq.length,