@productbrain/cli 0.1.0-beta.9 → 0.1.0-beta.91

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 (643) hide show
  1. package/README.md +77 -92
  2. package/dist/__tests__/adapters.test.d.ts +2 -0
  3. package/dist/__tests__/adapters.test.d.ts.map +1 -0
  4. package/dist/__tests__/adapters.test.js +417 -0
  5. package/dist/__tests__/adapters.test.js.map +1 -0
  6. package/dist/__tests__/audit.test.d.ts +2 -0
  7. package/dist/__tests__/audit.test.d.ts.map +1 -0
  8. package/dist/__tests__/audit.test.js +394 -0
  9. package/dist/__tests__/audit.test.js.map +1 -0
  10. package/dist/__tests__/batch-transformations.test.d.ts +2 -0
  11. package/dist/__tests__/batch-transformations.test.d.ts.map +1 -0
  12. package/dist/__tests__/batch-transformations.test.js +263 -0
  13. package/dist/__tests__/batch-transformations.test.js.map +1 -0
  14. package/dist/__tests__/capture.test.js +309 -18
  15. package/dist/__tests__/capture.test.js.map +1 -1
  16. package/dist/__tests__/config.test.d.ts +8 -0
  17. package/dist/__tests__/config.test.d.ts.map +1 -0
  18. package/dist/__tests__/config.test.js +166 -0
  19. package/dist/__tests__/config.test.js.map +1 -0
  20. package/dist/__tests__/constants.test.d.ts +2 -0
  21. package/dist/__tests__/constants.test.d.ts.map +1 -0
  22. package/dist/__tests__/constants.test.js +141 -0
  23. package/dist/__tests__/constants.test.js.map +1 -0
  24. package/dist/__tests__/constellation.test.js +20 -26
  25. package/dist/__tests__/constellation.test.js.map +1 -1
  26. package/dist/__tests__/context-strategy.test.d.ts +2 -0
  27. package/dist/__tests__/context-strategy.test.d.ts.map +1 -0
  28. package/dist/__tests__/context-strategy.test.js +79 -0
  29. package/dist/__tests__/context-strategy.test.js.map +1 -0
  30. package/dist/__tests__/errors.test.d.ts +2 -0
  31. package/dist/__tests__/errors.test.d.ts.map +1 -0
  32. package/dist/__tests__/errors.test.js +117 -0
  33. package/dist/__tests__/errors.test.js.map +1 -0
  34. package/dist/__tests__/experiment.test.d.ts +6 -0
  35. package/dist/__tests__/experiment.test.d.ts.map +1 -0
  36. package/dist/__tests__/experiment.test.js +69 -0
  37. package/dist/__tests__/experiment.test.js.map +1 -0
  38. package/dist/__tests__/fields.test.js +68 -68
  39. package/dist/__tests__/fields.test.js.map +1 -1
  40. package/dist/__tests__/glossary.test.d.ts +2 -0
  41. package/dist/__tests__/glossary.test.d.ts.map +1 -0
  42. package/dist/__tests__/glossary.test.js +32 -0
  43. package/dist/__tests__/glossary.test.js.map +1 -0
  44. package/dist/__tests__/handshake-preview.test.d.ts +2 -0
  45. package/dist/__tests__/handshake-preview.test.d.ts.map +1 -0
  46. package/dist/__tests__/handshake-preview.test.js +156 -0
  47. package/dist/__tests__/handshake-preview.test.js.map +1 -0
  48. package/dist/__tests__/handshake.test.js +27 -18
  49. package/dist/__tests__/handshake.test.js.map +1 -1
  50. package/dist/__tests__/hook-intents.test.d.ts +2 -0
  51. package/dist/__tests__/hook-intents.test.d.ts.map +1 -0
  52. package/dist/__tests__/hook-intents.test.js +184 -0
  53. package/dist/__tests__/hook-intents.test.js.map +1 -0
  54. package/dist/__tests__/ingest.test.js +110 -12
  55. package/dist/__tests__/ingest.test.js.map +1 -1
  56. package/dist/__tests__/init.test.d.ts +7 -0
  57. package/dist/__tests__/init.test.d.ts.map +1 -0
  58. package/dist/__tests__/init.test.js +146 -0
  59. package/dist/__tests__/init.test.js.map +1 -0
  60. package/dist/__tests__/login.test.d.ts +2 -0
  61. package/dist/__tests__/login.test.d.ts.map +1 -0
  62. package/dist/__tests__/login.test.js +167 -0
  63. package/dist/__tests__/login.test.js.map +1 -0
  64. package/dist/__tests__/manifest.test.d.ts +6 -0
  65. package/dist/__tests__/manifest.test.d.ts.map +1 -0
  66. package/dist/__tests__/manifest.test.js +138 -0
  67. package/dist/__tests__/manifest.test.js.map +1 -0
  68. package/dist/__tests__/method-registry.integration.test.d.ts +6 -0
  69. package/dist/__tests__/method-registry.integration.test.d.ts.map +1 -0
  70. package/dist/__tests__/method-registry.integration.test.js +18 -0
  71. package/dist/__tests__/method-registry.integration.test.js.map +1 -0
  72. package/dist/__tests__/method-registry.test.d.ts +14 -0
  73. package/dist/__tests__/method-registry.test.d.ts.map +1 -0
  74. package/dist/__tests__/method-registry.test.js +134 -0
  75. package/dist/__tests__/method-registry.test.js.map +1 -0
  76. package/dist/__tests__/onboarding-path-b.test.d.ts +2 -0
  77. package/dist/__tests__/onboarding-path-b.test.d.ts.map +1 -0
  78. package/dist/__tests__/onboarding-path-b.test.js +46 -0
  79. package/dist/__tests__/onboarding-path-b.test.js.map +1 -0
  80. package/dist/__tests__/onboarding.test.d.ts +6 -0
  81. package/dist/__tests__/onboarding.test.d.ts.map +1 -0
  82. package/dist/__tests__/onboarding.test.js +347 -0
  83. package/dist/__tests__/onboarding.test.js.map +1 -0
  84. package/dist/__tests__/orient.test.d.ts +2 -0
  85. package/dist/__tests__/orient.test.d.ts.map +1 -0
  86. package/dist/__tests__/orient.test.js +143 -0
  87. package/dist/__tests__/orient.test.js.map +1 -0
  88. package/dist/__tests__/personal-layer.test.d.ts +12 -0
  89. package/dist/__tests__/personal-layer.test.d.ts.map +1 -0
  90. package/dist/__tests__/personal-layer.test.js +304 -0
  91. package/dist/__tests__/personal-layer.test.js.map +1 -0
  92. package/dist/__tests__/profiles.test.d.ts +2 -0
  93. package/dist/__tests__/profiles.test.d.ts.map +1 -0
  94. package/dist/__tests__/profiles.test.js +168 -0
  95. package/dist/__tests__/profiles.test.js.map +1 -0
  96. package/dist/__tests__/promote.test.d.ts +2 -0
  97. package/dist/__tests__/promote.test.d.ts.map +1 -0
  98. package/dist/__tests__/promote.test.js +161 -0
  99. package/dist/__tests__/promote.test.js.map +1 -0
  100. package/dist/__tests__/prompts.test.d.ts +6 -0
  101. package/dist/__tests__/prompts.test.d.ts.map +1 -0
  102. package/dist/__tests__/prompts.test.js +146 -0
  103. package/dist/__tests__/prompts.test.js.map +1 -0
  104. package/dist/__tests__/proposals.test.d.ts +2 -0
  105. package/dist/__tests__/proposals.test.d.ts.map +1 -0
  106. package/dist/__tests__/proposals.test.js +167 -0
  107. package/dist/__tests__/proposals.test.js.map +1 -0
  108. package/dist/__tests__/relate.test.js +57 -33
  109. package/dist/__tests__/relate.test.js.map +1 -1
  110. package/dist/__tests__/repo-detect.test.js +97 -1
  111. package/dist/__tests__/repo-detect.test.js.map +1 -1
  112. package/dist/__tests__/runner.test.js +19 -15
  113. package/dist/__tests__/runner.test.js.map +1 -1
  114. package/dist/__tests__/session-state-machine.test.d.ts +2 -0
  115. package/dist/__tests__/session-state-machine.test.d.ts.map +1 -0
  116. package/dist/__tests__/session-state-machine.test.js +154 -0
  117. package/dist/__tests__/session-state-machine.test.js.map +1 -0
  118. package/dist/__tests__/session-touch.test.js +11 -11
  119. package/dist/__tests__/session-touch.test.js.map +1 -1
  120. package/dist/__tests__/session.test.js +4 -10
  121. package/dist/__tests__/session.test.js.map +1 -1
  122. package/dist/__tests__/setup.test.d.ts +2 -0
  123. package/dist/__tests__/setup.test.d.ts.map +1 -0
  124. package/dist/__tests__/setup.test.js +141 -0
  125. package/dist/__tests__/setup.test.js.map +1 -0
  126. package/dist/__tests__/spinner-labels.test.d.ts +2 -0
  127. package/dist/__tests__/spinner-labels.test.d.ts.map +1 -0
  128. package/dist/__tests__/spinner-labels.test.js +23 -0
  129. package/dist/__tests__/spinner-labels.test.js.map +1 -0
  130. package/dist/__tests__/state.test.d.ts +6 -0
  131. package/dist/__tests__/state.test.d.ts.map +1 -0
  132. package/dist/__tests__/state.test.js +97 -0
  133. package/dist/__tests__/state.test.js.map +1 -0
  134. package/dist/__tests__/strip.test.js +2 -2
  135. package/dist/__tests__/strip.test.js.map +1 -1
  136. package/dist/__tests__/surface-profiles.test.d.ts +2 -0
  137. package/dist/__tests__/surface-profiles.test.d.ts.map +1 -0
  138. package/dist/__tests__/surface-profiles.test.js +233 -0
  139. package/dist/__tests__/surface-profiles.test.js.map +1 -0
  140. package/dist/__tests__/surfaces.test.d.ts +2 -0
  141. package/dist/__tests__/surfaces.test.d.ts.map +1 -0
  142. package/dist/__tests__/surfaces.test.js +46 -0
  143. package/dist/__tests__/surfaces.test.js.map +1 -0
  144. package/dist/__tests__/update.test.js +123 -43
  145. package/dist/__tests__/update.test.js.map +1 -1
  146. package/dist/__tests__/workspace.test.d.ts +2 -0
  147. package/dist/__tests__/workspace.test.d.ts.map +1 -0
  148. package/dist/__tests__/workspace.test.js +308 -0
  149. package/dist/__tests__/workspace.test.js.map +1 -0
  150. package/dist/commands/accept.d.ts +18 -0
  151. package/dist/commands/accept.d.ts.map +1 -0
  152. package/dist/commands/accept.js +76 -0
  153. package/dist/commands/accept.js.map +1 -0
  154. package/dist/commands/admin/cockpit.d.ts +90 -0
  155. package/dist/commands/admin/cockpit.d.ts.map +1 -0
  156. package/dist/commands/admin/cockpit.js +618 -0
  157. package/dist/commands/admin/cockpit.js.map +1 -0
  158. package/dist/commands/admin/index.d.ts +21 -0
  159. package/dist/commands/admin/index.d.ts.map +1 -0
  160. package/dist/commands/admin/index.js +256 -0
  161. package/dist/commands/admin/index.js.map +1 -0
  162. package/dist/commands/admin/inspect.d.ts +30 -0
  163. package/dist/commands/admin/inspect.d.ts.map +1 -0
  164. package/dist/commands/admin/inspect.js +555 -0
  165. package/dist/commands/admin/inspect.js.map +1 -0
  166. package/dist/commands/admin/inspect.test.d.ts +7 -0
  167. package/dist/commands/admin/inspect.test.d.ts.map +1 -0
  168. package/dist/commands/admin/inspect.test.js +90 -0
  169. package/dist/commands/admin/inspect.test.js.map +1 -0
  170. package/dist/commands/admin/manage.d.ts +8 -0
  171. package/dist/commands/admin/manage.d.ts.map +1 -0
  172. package/dist/commands/admin/manage.js +76 -0
  173. package/dist/commands/admin/manage.js.map +1 -0
  174. package/dist/commands/admin/seed.d.ts +32 -0
  175. package/dist/commands/admin/seed.d.ts.map +1 -0
  176. package/dist/commands/admin/seed.js +533 -0
  177. package/dist/commands/admin/seed.js.map +1 -0
  178. package/dist/commands/admin/seed.test.d.ts +6 -0
  179. package/dist/commands/admin/seed.test.d.ts.map +1 -0
  180. package/dist/commands/admin/seed.test.js +65 -0
  181. package/dist/commands/admin/seed.test.js.map +1 -0
  182. package/dist/commands/audit.d.ts +25 -0
  183. package/dist/commands/audit.d.ts.map +1 -0
  184. package/dist/commands/audit.js +188 -0
  185. package/dist/commands/audit.js.map +1 -0
  186. package/dist/commands/brand-pack.d.ts +2 -0
  187. package/dist/commands/brand-pack.d.ts.map +1 -0
  188. package/dist/commands/brand-pack.js +25 -0
  189. package/dist/commands/brand-pack.js.map +1 -0
  190. package/dist/commands/brief.d.ts +28 -0
  191. package/dist/commands/brief.d.ts.map +1 -0
  192. package/dist/commands/brief.js +75 -0
  193. package/dist/commands/brief.js.map +1 -0
  194. package/dist/commands/capture.d.ts +9 -0
  195. package/dist/commands/capture.d.ts.map +1 -1
  196. package/dist/commands/capture.js +256 -17
  197. package/dist/commands/capture.js.map +1 -1
  198. package/dist/commands/chain-walk.d.ts +14 -0
  199. package/dist/commands/chain-walk.d.ts.map +1 -0
  200. package/dist/commands/chain-walk.js +38 -0
  201. package/dist/commands/chain-walk.js.map +1 -0
  202. package/dist/commands/changes.d.ts +11 -0
  203. package/dist/commands/changes.d.ts.map +1 -0
  204. package/dist/commands/changes.js +46 -0
  205. package/dist/commands/changes.js.map +1 -0
  206. package/dist/commands/codex-prep.d.ts +12 -0
  207. package/dist/commands/codex-prep.d.ts.map +1 -0
  208. package/dist/commands/codex-prep.js +122 -0
  209. package/dist/commands/codex-prep.js.map +1 -0
  210. package/dist/commands/collections.d.ts +22 -0
  211. package/dist/commands/collections.d.ts.map +1 -0
  212. package/dist/commands/collections.js +77 -0
  213. package/dist/commands/collections.js.map +1 -0
  214. package/dist/commands/connect-integration.test.d.ts +7 -0
  215. package/dist/commands/connect-integration.test.d.ts.map +1 -0
  216. package/dist/commands/connect-integration.test.js +195 -0
  217. package/dist/commands/connect-integration.test.js.map +1 -0
  218. package/dist/commands/connect-screens.d.ts +21 -0
  219. package/dist/commands/connect-screens.d.ts.map +1 -0
  220. package/dist/commands/connect-screens.js +79 -0
  221. package/dist/commands/connect-screens.js.map +1 -0
  222. package/dist/commands/connect.d.ts +21 -0
  223. package/dist/commands/connect.d.ts.map +1 -0
  224. package/dist/commands/connect.js +237 -0
  225. package/dist/commands/connect.js.map +1 -0
  226. package/dist/commands/connect.test.d.ts +6 -0
  227. package/dist/commands/connect.test.d.ts.map +1 -0
  228. package/dist/commands/connect.test.js +234 -0
  229. package/dist/commands/connect.test.js.map +1 -0
  230. package/dist/commands/constellation.d.ts.map +1 -1
  231. package/dist/commands/constellation.js +8 -3
  232. package/dist/commands/constellation.js.map +1 -1
  233. package/dist/commands/context.d.ts.map +1 -1
  234. package/dist/commands/context.js +8 -3
  235. package/dist/commands/context.js.map +1 -1
  236. package/dist/commands/cross-cut.d.ts +11 -0
  237. package/dist/commands/cross-cut.d.ts.map +1 -0
  238. package/dist/commands/cross-cut.js +23 -0
  239. package/dist/commands/cross-cut.js.map +1 -0
  240. package/dist/commands/doctor.d.ts +18 -0
  241. package/dist/commands/doctor.d.ts.map +1 -0
  242. package/dist/commands/doctor.js +232 -0
  243. package/dist/commands/doctor.js.map +1 -0
  244. package/dist/commands/doctor.test.d.ts +8 -0
  245. package/dist/commands/doctor.test.d.ts.map +1 -0
  246. package/dist/commands/doctor.test.js +311 -0
  247. package/dist/commands/doctor.test.js.map +1 -0
  248. package/dist/commands/fields.d.ts.map +1 -1
  249. package/dist/commands/fields.js +8 -4
  250. package/dist/commands/fields.js.map +1 -1
  251. package/dist/commands/get.d.ts.map +1 -1
  252. package/dist/commands/get.js +14 -6
  253. package/dist/commands/get.js.map +1 -1
  254. package/dist/commands/handshake.d.ts +12 -0
  255. package/dist/commands/handshake.d.ts.map +1 -1
  256. package/dist/commands/handshake.js +422 -74
  257. package/dist/commands/handshake.js.map +1 -1
  258. package/dist/commands/ingest.d.ts +7 -2
  259. package/dist/commands/ingest.d.ts.map +1 -1
  260. package/dist/commands/ingest.js +137 -31
  261. package/dist/commands/ingest.js.map +1 -1
  262. package/dist/commands/init.d.ts +14 -0
  263. package/dist/commands/init.d.ts.map +1 -0
  264. package/dist/commands/init.js +109 -0
  265. package/dist/commands/init.js.map +1 -0
  266. package/dist/commands/login.d.ts +4 -0
  267. package/dist/commands/login.d.ts.map +1 -1
  268. package/dist/commands/login.js +101 -38
  269. package/dist/commands/login.js.map +1 -1
  270. package/dist/commands/method.d.ts +99 -0
  271. package/dist/commands/method.d.ts.map +1 -0
  272. package/dist/commands/method.js +781 -0
  273. package/dist/commands/method.js.map +1 -0
  274. package/dist/commands/orient.d.ts +106 -1
  275. package/dist/commands/orient.d.ts.map +1 -1
  276. package/dist/commands/orient.js +13 -2
  277. package/dist/commands/orient.js.map +1 -1
  278. package/dist/commands/profile.d.ts +24 -0
  279. package/dist/commands/profile.d.ts.map +1 -0
  280. package/dist/commands/profile.js +82 -0
  281. package/dist/commands/profile.js.map +1 -0
  282. package/dist/commands/promote.d.ts +12 -0
  283. package/dist/commands/promote.d.ts.map +1 -0
  284. package/dist/commands/promote.js +90 -0
  285. package/dist/commands/promote.js.map +1 -0
  286. package/dist/commands/proposals.d.ts +9 -0
  287. package/dist/commands/proposals.d.ts.map +1 -0
  288. package/dist/commands/proposals.js +24 -0
  289. package/dist/commands/proposals.js.map +1 -0
  290. package/dist/commands/reject.d.ts +14 -0
  291. package/dist/commands/reject.d.ts.map +1 -0
  292. package/dist/commands/reject.js +43 -0
  293. package/dist/commands/reject.js.map +1 -0
  294. package/dist/commands/relate.d.ts +1 -0
  295. package/dist/commands/relate.d.ts.map +1 -1
  296. package/dist/commands/relate.js +41 -15
  297. package/dist/commands/relate.js.map +1 -1
  298. package/dist/commands/search.js +2 -2
  299. package/dist/commands/search.js.map +1 -1
  300. package/dist/commands/session.d.ts.map +1 -1
  301. package/dist/commands/session.js +85 -16
  302. package/dist/commands/session.js.map +1 -1
  303. package/dist/commands/setup.d.ts +15 -0
  304. package/dist/commands/setup.d.ts.map +1 -0
  305. package/dist/commands/setup.js +148 -0
  306. package/dist/commands/setup.js.map +1 -0
  307. package/dist/commands/update.d.ts +1 -0
  308. package/dist/commands/update.d.ts.map +1 -1
  309. package/dist/commands/update.js +102 -13
  310. package/dist/commands/update.js.map +1 -1
  311. package/dist/commands/usage.d.ts +40 -0
  312. package/dist/commands/usage.d.ts.map +1 -0
  313. package/dist/commands/usage.js +232 -0
  314. package/dist/commands/usage.js.map +1 -0
  315. package/dist/commands/verify.d.ts +13 -0
  316. package/dist/commands/verify.d.ts.map +1 -0
  317. package/dist/commands/verify.js +49 -0
  318. package/dist/commands/verify.js.map +1 -0
  319. package/dist/commands/welcome.d.ts +21 -0
  320. package/dist/commands/welcome.d.ts.map +1 -0
  321. package/dist/commands/welcome.js +50 -0
  322. package/dist/commands/welcome.js.map +1 -0
  323. package/dist/commands/workspace.d.ts +41 -0
  324. package/dist/commands/workspace.d.ts.map +1 -0
  325. package/dist/commands/workspace.js +239 -0
  326. package/dist/commands/workspace.js.map +1 -0
  327. package/dist/formatters/audit.d.ts +46 -0
  328. package/dist/formatters/audit.d.ts.map +1 -0
  329. package/dist/formatters/audit.js +81 -0
  330. package/dist/formatters/audit.js.map +1 -0
  331. package/dist/formatters/brief.d.ts +112 -0
  332. package/dist/formatters/brief.d.ts.map +1 -0
  333. package/dist/formatters/brief.js +179 -0
  334. package/dist/formatters/brief.js.map +1 -0
  335. package/dist/formatters/capture.d.ts +21 -3
  336. package/dist/formatters/capture.d.ts.map +1 -1
  337. package/dist/formatters/capture.js +20 -1
  338. package/dist/formatters/capture.js.map +1 -1
  339. package/dist/formatters/chain-walk.d.ts +33 -0
  340. package/dist/formatters/chain-walk.d.ts.map +1 -0
  341. package/dist/formatters/chain-walk.js +54 -0
  342. package/dist/formatters/chain-walk.js.map +1 -0
  343. package/dist/formatters/changes.d.ts +25 -0
  344. package/dist/formatters/changes.d.ts.map +1 -0
  345. package/dist/formatters/changes.js +60 -0
  346. package/dist/formatters/changes.js.map +1 -0
  347. package/dist/formatters/collections.d.ts +40 -0
  348. package/dist/formatters/collections.d.ts.map +1 -0
  349. package/dist/formatters/collections.js +93 -0
  350. package/dist/formatters/collections.js.map +1 -0
  351. package/dist/formatters/cross-cut.d.ts +21 -0
  352. package/dist/formatters/cross-cut.d.ts.map +1 -0
  353. package/dist/formatters/cross-cut.js +32 -0
  354. package/dist/formatters/cross-cut.js.map +1 -0
  355. package/dist/formatters/entry.d.ts +11 -4
  356. package/dist/formatters/entry.d.ts.map +1 -1
  357. package/dist/formatters/entry.js +24 -8
  358. package/dist/formatters/entry.js.map +1 -1
  359. package/dist/formatters/handshake.d.ts +29 -0
  360. package/dist/formatters/handshake.d.ts.map +1 -1
  361. package/dist/formatters/handshake.js +115 -3
  362. package/dist/formatters/handshake.js.map +1 -1
  363. package/dist/formatters/orient.d.ts +104 -1
  364. package/dist/formatters/orient.d.ts.map +1 -1
  365. package/dist/formatters/orient.js +140 -17
  366. package/dist/formatters/orient.js.map +1 -1
  367. package/dist/formatters/promote.d.ts +30 -0
  368. package/dist/formatters/promote.d.ts.map +1 -0
  369. package/dist/formatters/promote.js +39 -0
  370. package/dist/formatters/promote.js.map +1 -0
  371. package/dist/formatters/proposals.d.ts +45 -0
  372. package/dist/formatters/proposals.d.ts.map +1 -0
  373. package/dist/formatters/proposals.js +62 -0
  374. package/dist/formatters/proposals.js.map +1 -0
  375. package/dist/formatters/relate.d.ts +3 -0
  376. package/dist/formatters/relate.d.ts.map +1 -1
  377. package/dist/formatters/relate.js +6 -0
  378. package/dist/formatters/relate.js.map +1 -1
  379. package/dist/formatters/search.d.ts +0 -4
  380. package/dist/formatters/search.d.ts.map +1 -1
  381. package/dist/formatters/search.js +4 -1
  382. package/dist/formatters/search.js.map +1 -1
  383. package/dist/formatters/session.d.ts +1 -1
  384. package/dist/formatters/session.d.ts.map +1 -1
  385. package/dist/formatters/session.js +3 -1
  386. package/dist/formatters/session.js.map +1 -1
  387. package/dist/formatters/update.d.ts.map +1 -1
  388. package/dist/formatters/update.js +2 -0
  389. package/dist/formatters/update.js.map +1 -1
  390. package/dist/formatters/verify.d.ts +11 -0
  391. package/dist/formatters/verify.d.ts.map +1 -0
  392. package/dist/formatters/verify.js +11 -0
  393. package/dist/formatters/verify.js.map +1 -0
  394. package/dist/generators/__tests__/surface-profiles.test.d.ts +2 -0
  395. package/dist/generators/__tests__/surface-profiles.test.d.ts.map +1 -0
  396. package/dist/generators/__tests__/surface-profiles.test.js +89 -0
  397. package/dist/generators/__tests__/surface-profiles.test.js.map +1 -0
  398. package/dist/generators/adapters.d.ts +37 -3
  399. package/dist/generators/adapters.d.ts.map +1 -1
  400. package/dist/generators/adapters.js +193 -5
  401. package/dist/generators/adapters.js.map +1 -1
  402. package/dist/generators/adapters.test.d.ts +2 -0
  403. package/dist/generators/adapters.test.d.ts.map +1 -0
  404. package/dist/generators/adapters.test.js +27 -0
  405. package/dist/generators/adapters.test.js.map +1 -0
  406. package/dist/generators/archetypes.d.ts +52 -0
  407. package/dist/generators/archetypes.d.ts.map +1 -0
  408. package/dist/generators/archetypes.js +153 -0
  409. package/dist/generators/archetypes.js.map +1 -0
  410. package/dist/generators/archetypes.test.d.ts +2 -0
  411. package/dist/generators/archetypes.test.d.ts.map +1 -0
  412. package/dist/generators/archetypes.test.js +237 -0
  413. package/dist/generators/archetypes.test.js.map +1 -0
  414. package/dist/generators/chain-classifier.d.ts +49 -0
  415. package/dist/generators/chain-classifier.d.ts.map +1 -0
  416. package/dist/generators/chain-classifier.js +180 -0
  417. package/dist/generators/chain-classifier.js.map +1 -0
  418. package/dist/generators/chain-classifier.test.d.ts +2 -0
  419. package/dist/generators/chain-classifier.test.d.ts.map +1 -0
  420. package/dist/generators/chain-classifier.test.js +257 -0
  421. package/dist/generators/chain-classifier.test.js.map +1 -0
  422. package/dist/generators/chain-rules.d.ts +42 -0
  423. package/dist/generators/chain-rules.d.ts.map +1 -0
  424. package/dist/generators/chain-rules.js +144 -0
  425. package/dist/generators/chain-rules.js.map +1 -0
  426. package/dist/generators/chain-rules.test.d.ts +2 -0
  427. package/dist/generators/chain-rules.test.d.ts.map +1 -0
  428. package/dist/generators/chain-rules.test.js +179 -0
  429. package/dist/generators/chain-rules.test.js.map +1 -0
  430. package/dist/generators/context-md.d.ts +1 -1
  431. package/dist/generators/context-md.d.ts.map +1 -1
  432. package/dist/generators/context-md.js +12 -1
  433. package/dist/generators/context-md.js.map +1 -1
  434. package/dist/generators/handshake-diff.d.ts +67 -0
  435. package/dist/generators/handshake-diff.d.ts.map +1 -0
  436. package/dist/generators/handshake-diff.js +183 -0
  437. package/dist/generators/handshake-diff.js.map +1 -0
  438. package/dist/generators/handshake-diff.test.d.ts +2 -0
  439. package/dist/generators/handshake-diff.test.d.ts.map +1 -0
  440. package/dist/generators/handshake-diff.test.js +264 -0
  441. package/dist/generators/handshake-diff.test.js.map +1 -0
  442. package/dist/generators/manifest.d.ts +37 -0
  443. package/dist/generators/manifest.d.ts.map +1 -0
  444. package/dist/generators/manifest.js +166 -0
  445. package/dist/generators/manifest.js.map +1 -0
  446. package/dist/generators/portable-knowledge.d.ts +102 -9
  447. package/dist/generators/portable-knowledge.d.ts.map +1 -1
  448. package/dist/generators/portable-knowledge.js +384 -17
  449. package/dist/generators/portable-knowledge.js.map +1 -1
  450. package/dist/generators/portable-knowledge.test.js +529 -1
  451. package/dist/generators/portable-knowledge.test.js.map +1 -1
  452. package/dist/generators/surface-profiles.d.ts +49 -0
  453. package/dist/generators/surface-profiles.d.ts.map +1 -0
  454. package/dist/generators/surface-profiles.js +98 -0
  455. package/dist/generators/surface-profiles.js.map +1 -0
  456. package/dist/index.js +618 -138
  457. package/dist/index.js.map +1 -1
  458. package/dist/lib/activation.d.ts +28 -0
  459. package/dist/lib/activation.d.ts.map +1 -0
  460. package/dist/lib/activation.js +57 -0
  461. package/dist/lib/activation.js.map +1 -0
  462. package/dist/lib/activation.test.d.ts +6 -0
  463. package/dist/lib/activation.test.d.ts.map +1 -0
  464. package/dist/lib/activation.test.js +121 -0
  465. package/dist/lib/activation.test.js.map +1 -0
  466. package/dist/lib/client.d.ts +45 -3
  467. package/dist/lib/client.d.ts.map +1 -1
  468. package/dist/lib/client.js +188 -36
  469. package/dist/lib/client.js.map +1 -1
  470. package/dist/lib/collectionRegistry.d.ts +38 -0
  471. package/dist/lib/collectionRegistry.d.ts.map +1 -0
  472. package/dist/lib/collectionRegistry.js +112 -0
  473. package/dist/lib/collectionRegistry.js.map +1 -0
  474. package/dist/lib/config.d.ts +84 -4
  475. package/dist/lib/config.d.ts.map +1 -1
  476. package/dist/lib/config.js +322 -42
  477. package/dist/lib/config.js.map +1 -1
  478. package/dist/lib/constants.d.ts +42 -0
  479. package/dist/lib/constants.d.ts.map +1 -0
  480. package/dist/lib/constants.js +76 -0
  481. package/dist/lib/constants.js.map +1 -0
  482. package/dist/lib/conversation-engine.d.ts +45 -0
  483. package/dist/lib/conversation-engine.d.ts.map +1 -0
  484. package/dist/lib/conversation-engine.js +112 -0
  485. package/dist/lib/conversation-engine.js.map +1 -0
  486. package/dist/lib/conversation-phases.d.ts +59 -0
  487. package/dist/lib/conversation-phases.d.ts.map +1 -0
  488. package/dist/lib/conversation-phases.js +11 -0
  489. package/dist/lib/conversation-phases.js.map +1 -0
  490. package/dist/lib/conversation-signals.d.ts +30 -0
  491. package/dist/lib/conversation-signals.d.ts.map +1 -0
  492. package/dist/lib/conversation-signals.js +64 -0
  493. package/dist/lib/conversation-signals.js.map +1 -0
  494. package/dist/lib/deployment.d.ts +23 -0
  495. package/dist/lib/deployment.d.ts.map +1 -0
  496. package/dist/lib/deployment.js +78 -0
  497. package/dist/lib/deployment.js.map +1 -0
  498. package/dist/lib/deployment.test.d.ts +5 -0
  499. package/dist/lib/deployment.test.d.ts.map +1 -0
  500. package/dist/lib/deployment.test.js +54 -0
  501. package/dist/lib/deployment.test.js.map +1 -0
  502. package/dist/lib/errors.d.ts +58 -0
  503. package/dist/lib/errors.d.ts.map +1 -0
  504. package/dist/lib/errors.js +67 -0
  505. package/dist/lib/errors.js.map +1 -0
  506. package/dist/lib/experiment.d.ts +18 -0
  507. package/dist/lib/experiment.d.ts.map +1 -0
  508. package/dist/lib/experiment.js +28 -0
  509. package/dist/lib/experiment.js.map +1 -0
  510. package/dist/lib/format.d.ts +10 -0
  511. package/dist/lib/format.d.ts.map +1 -0
  512. package/dist/lib/format.js +27 -0
  513. package/dist/lib/format.js.map +1 -0
  514. package/dist/lib/glossary.d.ts +19 -0
  515. package/dist/lib/glossary.d.ts.map +1 -0
  516. package/dist/lib/glossary.js +53 -0
  517. package/dist/lib/glossary.js.map +1 -0
  518. package/dist/lib/hook-intents.d.ts +51 -0
  519. package/dist/lib/hook-intents.d.ts.map +1 -0
  520. package/dist/lib/hook-intents.js +85 -0
  521. package/dist/lib/hook-intents.js.map +1 -0
  522. package/dist/lib/inferSourceDate.d.ts +12 -0
  523. package/dist/lib/inferSourceDate.d.ts.map +1 -0
  524. package/dist/lib/inferSourceDate.js +44 -0
  525. package/dist/lib/inferSourceDate.js.map +1 -0
  526. package/dist/lib/method-registry.d.ts +32 -0
  527. package/dist/lib/method-registry.d.ts.map +1 -0
  528. package/dist/lib/method-registry.js +53 -0
  529. package/dist/lib/method-registry.js.map +1 -0
  530. package/dist/lib/onboarding-path-b.d.ts +10 -0
  531. package/dist/lib/onboarding-path-b.d.ts.map +1 -0
  532. package/dist/lib/onboarding-path-b.js +214 -0
  533. package/dist/lib/onboarding-path-b.js.map +1 -0
  534. package/dist/lib/onboarding-phases.d.ts +9 -0
  535. package/dist/lib/onboarding-phases.d.ts.map +1 -0
  536. package/dist/lib/onboarding-phases.js +120 -0
  537. package/dist/lib/onboarding-phases.js.map +1 -0
  538. package/dist/lib/onboarding-shared.d.ts +81 -0
  539. package/dist/lib/onboarding-shared.d.ts.map +1 -0
  540. package/dist/lib/onboarding-shared.js +190 -0
  541. package/dist/lib/onboarding-shared.js.map +1 -0
  542. package/dist/lib/onboarding-topics.d.ts +27 -0
  543. package/dist/lib/onboarding-topics.d.ts.map +1 -0
  544. package/dist/lib/onboarding-topics.js +57 -0
  545. package/dist/lib/onboarding-topics.js.map +1 -0
  546. package/dist/lib/onboarding.d.ts +17 -0
  547. package/dist/lib/onboarding.d.ts.map +1 -0
  548. package/dist/lib/onboarding.js +350 -0
  549. package/dist/lib/onboarding.js.map +1 -0
  550. package/dist/lib/profiles.d.ts +39 -0
  551. package/dist/lib/profiles.d.ts.map +1 -0
  552. package/dist/lib/profiles.js +185 -0
  553. package/dist/lib/profiles.js.map +1 -0
  554. package/dist/lib/prompts.d.ts +65 -0
  555. package/dist/lib/prompts.d.ts.map +1 -0
  556. package/dist/lib/prompts.js +132 -0
  557. package/dist/lib/prompts.js.map +1 -0
  558. package/dist/lib/repo-detect.d.ts +19 -0
  559. package/dist/lib/repo-detect.d.ts.map +1 -1
  560. package/dist/lib/repo-detect.js +25 -0
  561. package/dist/lib/repo-detect.js.map +1 -1
  562. package/dist/lib/runner.d.ts +2 -0
  563. package/dist/lib/runner.d.ts.map +1 -1
  564. package/dist/lib/runner.js +21 -7
  565. package/dist/lib/runner.js.map +1 -1
  566. package/dist/lib/session.d.ts +25 -0
  567. package/dist/lib/session.d.ts.map +1 -1
  568. package/dist/lib/session.js +70 -4
  569. package/dist/lib/session.js.map +1 -1
  570. package/dist/lib/spinner.d.ts +27 -0
  571. package/dist/lib/spinner.d.ts.map +1 -0
  572. package/dist/lib/spinner.js +76 -0
  573. package/dist/lib/spinner.js.map +1 -0
  574. package/dist/lib/spinner.test.d.ts +2 -0
  575. package/dist/lib/spinner.test.d.ts.map +1 -0
  576. package/dist/lib/spinner.test.js +39 -0
  577. package/dist/lib/spinner.test.js.map +1 -0
  578. package/dist/lib/state.d.ts +51 -0
  579. package/dist/lib/state.d.ts.map +1 -0
  580. package/dist/lib/state.js +90 -0
  581. package/dist/lib/state.js.map +1 -0
  582. package/dist/lib/strip.d.ts +1 -0
  583. package/dist/lib/strip.d.ts.map +1 -1
  584. package/dist/lib/strip.js +15 -0
  585. package/dist/lib/strip.js.map +1 -1
  586. package/dist/lib/style.d.ts +96 -0
  587. package/dist/lib/style.d.ts.map +1 -0
  588. package/dist/lib/style.js +169 -0
  589. package/dist/lib/style.js.map +1 -0
  590. package/dist/lib/style.test.d.ts +7 -0
  591. package/dist/lib/style.test.d.ts.map +1 -0
  592. package/dist/lib/style.test.js +263 -0
  593. package/dist/lib/style.test.js.map +1 -0
  594. package/dist/lib/telemetry.d.ts +15 -0
  595. package/dist/lib/telemetry.d.ts.map +1 -0
  596. package/dist/lib/telemetry.js +47 -0
  597. package/dist/lib/telemetry.js.map +1 -0
  598. package/dist/lib/tokenConstants.d.ts +17 -0
  599. package/dist/lib/tokenConstants.d.ts.map +1 -0
  600. package/dist/lib/tokenConstants.js +17 -0
  601. package/dist/lib/tokenConstants.js.map +1 -0
  602. package/dist/lib/update-check.d.ts +21 -0
  603. package/dist/lib/update-check.d.ts.map +1 -0
  604. package/dist/lib/update-check.js +145 -0
  605. package/dist/lib/update-check.js.map +1 -0
  606. package/dist/lib/wizard-surfaces.d.ts +47 -0
  607. package/dist/lib/wizard-surfaces.d.ts.map +1 -0
  608. package/dist/lib/wizard-surfaces.js +176 -0
  609. package/dist/lib/wizard-surfaces.js.map +1 -0
  610. package/dist/lib/wizard-surfaces.test.d.ts +2 -0
  611. package/dist/lib/wizard-surfaces.test.d.ts.map +1 -0
  612. package/dist/lib/wizard-surfaces.test.js +127 -0
  613. package/dist/lib/wizard-surfaces.test.js.map +1 -0
  614. package/dist/lib/wizard-trust.d.ts +31 -0
  615. package/dist/lib/wizard-trust.d.ts.map +1 -0
  616. package/dist/lib/wizard-trust.js +66 -0
  617. package/dist/lib/wizard-trust.js.map +1 -0
  618. package/dist/lib/wizard-trust.test.d.ts +2 -0
  619. package/dist/lib/wizard-trust.test.d.ts.map +1 -0
  620. package/dist/lib/wizard-trust.test.js +32 -0
  621. package/dist/lib/wizard-trust.test.js.map +1 -0
  622. package/dist/lib/workspace-probe.d.ts +19 -0
  623. package/dist/lib/workspace-probe.d.ts.map +1 -0
  624. package/dist/lib/workspace-probe.js +27 -0
  625. package/dist/lib/workspace-probe.js.map +1 -0
  626. package/dist/surfaces/registry.d.ts +20 -0
  627. package/dist/surfaces/registry.d.ts.map +1 -0
  628. package/dist/surfaces/registry.js +42 -0
  629. package/dist/surfaces/registry.js.map +1 -0
  630. package/package.json +9 -3
  631. package/templates/archetypes/boundary.md +23 -0
  632. package/templates/archetypes/constraint.md +23 -0
  633. package/templates/archetypes/convention.md +23 -0
  634. package/templates/archetypes/policy.md +23 -0
  635. package/templates/archetypes/quality-gate.md +23 -0
  636. package/templates/archetypes/workflow.md +23 -0
  637. package/templates/general/code-integrity.md +11 -0
  638. package/templates/general/getting-started.md +12 -0
  639. package/templates/method-registry.json +16 -0
  640. package/templates/node-ts/code-integrity.md +13 -0
  641. package/templates/node-ts/testing.md +12 -0
  642. package/templates/python/code-integrity.md +13 -0
  643. package/templates/python/testing.md +12 -0
@@ -2,18 +2,27 @@
2
2
  * pb handshake — generate context files for AI developer tools.
3
3
  * The fourth delivery surface: context export (GLO-63, DEC-161).
4
4
  */
5
- import { mkdirSync, writeFileSync, existsSync, readFileSync } from 'fs';
6
- import { join } from 'path';
5
+ import { mkdirSync, writeFileSync, existsSync, readFileSync, readdirSync, copyFileSync } from 'fs';
6
+ import { join, dirname, resolve } from 'path';
7
7
  import { homedir } from 'os';
8
- import { createInterface } from 'readline';
8
+ import { fileURLToPath } from 'url';
9
9
  import { getConfigOrGuide } from '../lib/config.js';
10
- import { mcpCall } from '../lib/client.js';
11
- import { detectRepo } from '../lib/repo-detect.js';
10
+ import { select as promptSelect } from '../lib/prompts.js';
11
+ import { composeHooksFromIntents, getHookStatusForSurface } from '../lib/hook-intents.js';
12
+ import { kernelCall, kernelCallWithSession } from '../lib/client.js';
13
+ import { readSession } from '../lib/session.js';
14
+ import { detectRepo, extractWorkspaceProfile } from '../lib/repo-detect.js';
12
15
  import { generateContextMd } from '../generators/context-md.js';
13
16
  import { generateBriefingMd } from '../generators/briefing-md.js';
14
- import { MARKER, generateClaudeMd, generateCursorMdc, generateCopilotMd } from '../generators/adapters.js';
15
- import { readCanonicalSkills, readCanonicalRules, generateCursorSkill, generateCursorRule, generateClaudeRule, generateClaudeSkillRouter, shouldEmitToTarget, filterByLevel, } from '../generators/portable-knowledge.js';
17
+ import { MARKER, generateAgentsMd, generateClaudeMd, generateCursorMdc, generateCopilotMd } from '../generators/adapters.js';
18
+ import { readCanonicalSkills, readCanonicalRules, readPersonalLayer, readPersonalSkillsLayer, generateCursorSkill, generateCursorRule, generateCodexSkill, generateCodexSkillIndex, generateClaudeRule, generateClaudeSkillRouter, shouldEmitToTarget, filterByLevel, validateCodexSkills, evaluateConditions, STAGE_TO_MAX_LEVEL, LEVEL_ORDER, } from '../generators/portable-knowledge.js';
19
+ import { generateChainRules } from '../generators/chain-rules.js';
20
+ import { saveHandshakeState, loadPreviousState, diffHandshakeState, formatDiff, buildCurrentState, } from '../generators/handshake-diff.js';
21
+ import { resolveSurfaceProfile } from '../generators/surface-profiles.js';
16
22
  import { formatHandshakeReport } from '../formatters/handshake.js';
23
+ import { readManifest, filterByAdoptionState } from '../generators/manifest.js';
24
+ import { loadMethodRegistry } from '../lib/method-registry.js';
25
+ import { CLIError, ErrorCode } from '../lib/errors.js';
17
26
  const LEVELS = {
18
27
  guide: {
19
28
  label: 'Guide me',
@@ -45,9 +54,6 @@ const LEVEL_KEYS = ['guide', 'work', 'silent', 'full-trust'];
45
54
  // Hook failure contract (TEN-712): all hook commands MUST end with '2>/dev/null || true'
46
55
  // so Claude Code always starts even if pb is unavailable. Never remove this suffix.
47
56
  const INIT_PERMISSION = 'Bash(pb:*)';
48
- const INIT_SESSION_START_CMD = 'pb session start 2>/dev/null || true';
49
- const INIT_SESSION_CLOSE_CMD = 'pb session close 2>/dev/null || true';
50
- const INIT_PRECOMPACT_CMD = 'pb session id > /dev/null 2>&1 && echo \'{"systemMessage": "pb session active — capture decisions/tensions before compacting: pb capture \\"DEC: ...\\""}\' || true';
51
57
  function readSettings(filePath) {
52
58
  if (!existsSync(filePath))
53
59
  return {};
@@ -59,9 +65,6 @@ function readSettings(filePath) {
59
65
  return {};
60
66
  }
61
67
  }
62
- function hasCommand(groups, cmd) {
63
- return (groups ?? []).some((g) => g.hooks?.some((h) => h.command === cmd));
64
- }
65
68
  // Team write: hooks + Bash(pb:*) → .claude/settings.json (safe to commit)
66
69
  function writeTeamSettings(cwd, dryRun) {
67
70
  const claudeDir = join(cwd, '.claude');
@@ -77,26 +80,10 @@ function writeTeamSettings(cwd, dryRun) {
77
80
  }
78
81
  settings.permissions = permissions;
79
82
  const hooks = (settings.hooks ?? {});
80
- if (!hasCommand(hooks.SessionStart, INIT_SESSION_START_CMD)) {
81
- hooks.SessionStart = [
82
- ...(hooks.SessionStart ?? []),
83
- { hooks: [{ type: 'command', command: INIT_SESSION_START_CMD, statusMessage: 'Opening pb session...' }] },
84
- ];
85
- added.push('SessionStart → pb session start');
86
- }
87
- if (!hasCommand(hooks.Stop, INIT_SESSION_CLOSE_CMD)) {
88
- hooks.Stop = [
89
- ...(hooks.Stop ?? []),
90
- { hooks: [{ type: 'command', command: INIT_SESSION_CLOSE_CMD, statusMessage: 'Closing pb session...' }] },
91
- ];
92
- added.push('Stop → pb session close');
93
- }
94
- if (!hasCommand(hooks.PreCompact, INIT_PRECOMPACT_CMD)) {
95
- hooks.PreCompact = [
96
- ...(hooks.PreCompact ?? []),
97
- { hooks: [{ type: 'command', command: INIT_PRECOMPACT_CMD }] },
98
- ];
99
- added.push('PreCompact → decision capture reminder');
83
+ const hookAdditions = composeHooksFromIntents(['session-start', 'session-close', 'pre-compact'], hooks);
84
+ for (const addition of hookAdditions) {
85
+ hooks[addition.event] = [...(hooks[addition.event] ?? []), addition.entry];
86
+ added.push(addition.label);
100
87
  }
101
88
  settings.hooks = hooks;
102
89
  if (!dryRun) {
@@ -133,31 +120,26 @@ function writePersonalSettings(levelKey, dryRun) {
133
120
  return added;
134
121
  }
135
122
  async function promptLevel() {
136
- const rl = createInterface({ input: process.stdin, output: process.stdout });
137
- console.log('\nHow much should Claude explain before acting?\n');
138
- LEVEL_KEYS.forEach((key, i) => {
139
- const l = LEVELS[key];
140
- console.log(` ${i + 1}. ${l.label.padEnd(12)} — ${l.description}`);
141
- });
142
- console.log('');
143
- return new Promise((resolve) => {
144
- rl.question('> ', (answer) => {
145
- rl.close();
146
- const n = parseInt(answer.trim(), 10);
147
- if (!(n >= 1 && n <= LEVEL_KEYS.length)) {
148
- console.log(' (Invalid choice — defaulting to "Just work")');
149
- }
150
- resolve(n >= 1 && n <= LEVEL_KEYS.length ? LEVEL_KEYS[n - 1] : 'work');
151
- });
123
+ const result = await promptSelect({
124
+ message: 'How much should Claude explain before acting?',
125
+ options: LEVEL_KEYS.map((key) => ({
126
+ value: key,
127
+ label: LEVELS[key].label,
128
+ hint: LEVELS[key].description,
129
+ })),
152
130
  });
131
+ return result;
153
132
  }
154
133
  export async function runHandshakeInit(options = {}) {
155
134
  const cwd = process.cwd();
156
135
  const dryRun = options.dryRun ?? false;
157
136
  const suffix = dryRun ? ' (dry run)' : '';
158
137
  if (options.level && !LEVEL_KEYS.includes(options.level)) {
159
- console.error(`Unknown level "${options.level}". Valid: ${LEVEL_KEYS.join(', ')}`);
160
- process.exit(1);
138
+ throw new CLIError(`Unknown level "${options.level}".`, {
139
+ code: ErrorCode.VALIDATION_FAILED,
140
+ category: 'validation',
141
+ guidance: `Valid levels: ${LEVEL_KEYS.join(', ')}`,
142
+ });
161
143
  }
162
144
  console.log('Setting up Claude Code integration...\n');
163
145
  // Step 1: Team config — always, no prompt
@@ -172,7 +154,7 @@ export async function runHandshakeInit(options = {}) {
172
154
  console.log(` + ${item}`);
173
155
  }
174
156
  // Step 2: Personal config — wizard or --level flag
175
- // Cast is safe: LEVEL_KEYS.includes() validated above; invalid level already called process.exit(1).
157
+ // Cast is safe: LEVEL_KEYS.includes() validated above; invalid level already threw CLIError.
176
158
  const levelKey = options.level ? options.level : await promptLevel();
177
159
  const level = LEVELS[levelKey];
178
160
  const personalAdded = writePersonalSettings(levelKey, dryRun);
@@ -194,6 +176,88 @@ export async function runHandshakeInit(options = {}) {
194
176
  if (!dryRun)
195
177
  console.log('Reload /hooks in Claude Code (or restart) to activate.');
196
178
  console.log('Run `pb handshake --init --level <guide|work|silent|full-trust>` to change level.');
179
+ // Step 2b: Report multi-surface hook opt-in status (WP-310 E3b)
180
+ // Reads manifest.hooks.{cursor,copilot} and prints an informational note for
181
+ // each opted-in surface. Silence = no manifest or no hooks flags set.
182
+ // DEC-536: Claude-native default is already wired above; this block only fires
183
+ // when the user has explicitly opted in via manifest.
184
+ const pbDirForManifest = join(cwd, '.productbrain');
185
+ const initManifest = readManifest(pbDirForManifest);
186
+ const multiSurfaceOptIns = [];
187
+ if (initManifest?.hooks?.cursor)
188
+ multiSurfaceOptIns.push('cursor');
189
+ if (initManifest?.hooks?.copilot)
190
+ multiSurfaceOptIns.push('copilot');
191
+ if (multiSurfaceOptIns.length > 0) {
192
+ console.log('');
193
+ for (const surface of multiSurfaceOptIns) {
194
+ const status = getHookStatusForSurface(surface);
195
+ if (status.writable) {
196
+ // Future-proofing path: surface has hook events, would write files.
197
+ console.log(`ℹ ${surface} hooks: opted in — hooks will be written`);
198
+ }
199
+ else {
200
+ console.log(`ℹ ${surface} hooks: opted in — no auto-hooks (${surface} has no session events; run \`pb session start\` manually)`);
201
+ }
202
+ }
203
+ }
204
+ // Step 3: Scaffold starter templates if .productbrain/rules/ is empty
205
+ const rulesDir = join(cwd, '.productbrain', 'rules');
206
+ const hasExistingRules = existsSync(rulesDir) && readdirSync(rulesDir).filter((f) => f.endsWith('.md')).length > 0;
207
+ if (!hasExistingRules) {
208
+ // Detect stack from repo to pick template set
209
+ const repo = detectRepo(cwd);
210
+ const stack = repo.detectedStack.map((s) => s.toLowerCase());
211
+ let templateSet;
212
+ if (stack.some((s) => ['typescript', 'sveltekit', 'nextjs', 'react'].includes(s))) {
213
+ templateSet = 'node-ts';
214
+ }
215
+ else if (stack.includes('python')) {
216
+ templateSet = 'python';
217
+ }
218
+ else {
219
+ templateSet = 'general';
220
+ }
221
+ // Resolve templates directory relative to this file
222
+ const __filename = fileURLToPath(import.meta.url);
223
+ const __dirname = dirname(__filename);
224
+ // From dist/commands/handshake.js → ../../templates/
225
+ const templatesRoot = resolve(__dirname, '..', '..', 'templates');
226
+ const templateDir = join(templatesRoot, templateSet);
227
+ if (existsSync(templateDir)) {
228
+ const templateFiles = readdirSync(templateDir).filter((f) => f.endsWith('.md'));
229
+ if (templateFiles.length > 0) {
230
+ console.log('');
231
+ console.log(`Scaffolding starter rules from ${templateSet} template...`);
232
+ if (!dryRun) {
233
+ mkdirSync(rulesDir, { recursive: true });
234
+ for (const file of templateFiles) {
235
+ const src = join(templateDir, file);
236
+ const dest = join(rulesDir, file);
237
+ copyFileSync(src, dest);
238
+ console.log(` + .productbrain/rules/${file}`);
239
+ }
240
+ console.log('');
241
+ console.log('Run `pb handshake` to sync the scaffolded rules to your AI tools.');
242
+ }
243
+ else {
244
+ for (const file of templateFiles) {
245
+ console.log(` + .productbrain/rules/${file} (dry run)`);
246
+ }
247
+ }
248
+ }
249
+ }
250
+ }
251
+ }
252
+ /**
253
+ * Normalize volatile handshake-only timestamps before comparing generated files.
254
+ * This keeps the visible timestamps in generated artifacts while avoiding
255
+ * meaningless rewrites when semantic content is unchanged.
256
+ */
257
+ export function normalizeHandshakeContentForComparison(content) {
258
+ return content
259
+ .replace(/<!-- auto-generated by pb handshake — [0-9]{4}-[0-9]{2}-[0-9]{2}T[^>]+ -->/g, '<!-- auto-generated by pb handshake — <TIMESTAMP> -->')
260
+ .replace(/^_Generated: [0-9]{4}-[0-9]{2}-[0-9]{2}T.*_$/gm, '_Generated: <TIMESTAMP>_');
197
261
  }
198
262
  function shouldWriteAdapter(filePath, force) {
199
263
  if (force)
@@ -222,8 +286,12 @@ export async function runHandshake(options = {}) {
222
286
  const cwd = process.cwd();
223
287
  const force = options.force ?? false;
224
288
  const dryRun = options.dryRun ?? false;
289
+ // Preview mode: default when neither --apply nor --dry-run is passed.
290
+ // --dry-run is kept as a backward-compat alias for preview (same behavior).
291
+ const preview = !options.apply && !dryRun;
225
292
  const level = options.level;
226
293
  const quiet = options.quiet ?? false;
294
+ const generate = options.generate ?? false;
227
295
  const timestamp = new Date().toISOString();
228
296
  // Helper: emit progress line only when not quiet (used when handshake is a sub-step)
229
297
  const log = (msg) => { if (!quiet)
@@ -233,8 +301,11 @@ export async function runHandshake(options = {}) {
233
301
  // Validate --level if provided (for handshake content filtering, not --init trust level)
234
302
  const VALID_HANDSHAKE_LEVELS = ['beginner', 'intermediate', 'expert'];
235
303
  if (level && !VALID_HANDSHAKE_LEVELS.includes(level)) {
236
- process.stderr.write(`Unknown level "${level}". Valid levels: ${VALID_HANDSHAKE_LEVELS.join(', ')}\n`);
237
- process.exit(1);
304
+ throw new CLIError(`Unknown level "${level}".`, {
305
+ code: ErrorCode.VALIDATION_FAILED,
306
+ category: 'validation',
307
+ guidance: `Valid levels: ${VALID_HANDSHAKE_LEVELS.join(', ')}`,
308
+ });
238
309
  }
239
310
  // 1. Detect repo
240
311
  const repo = detectRepo(cwd);
@@ -242,16 +313,30 @@ export async function runHandshake(options = {}) {
242
313
  if (repo.detectedStack.length > 0) {
243
314
  log(`Stack: ${repo.detectedStack.join(', ')}`);
244
315
  }
245
- // 2. Fetch orient view
316
+ // 2. Fetch orient view + workspace readiness in parallel (budget max +200ms added latency)
246
317
  log('Fetching workspace context...');
247
318
  let orientView = null;
319
+ let workspaceProfile = null;
248
320
  try {
249
- orientView = await mcpCall('chain.getOrientView', {});
321
+ const workspaceReadinessPromise = kernelCall('chain.workspaceReadiness', {}).catch(() => null);
322
+ const [orientResult, readinessRaw] = await Promise.all([
323
+ kernelCall('chain.getOrientView', {}).catch((err) => {
324
+ logErr(`Warning: could not fetch workspace context — ${err instanceof Error ? err.message : err}`);
325
+ logErr('Continuing with limited context (Chain search + portable knowledge only).');
326
+ return null;
327
+ }),
328
+ workspaceReadinessPromise,
329
+ ]);
330
+ orientView = orientResult;
331
+ workspaceProfile = extractWorkspaceProfile(readinessRaw);
250
332
  }
251
333
  catch (err) {
252
334
  logErr(`Warning: could not fetch workspace context — ${err instanceof Error ? err.message : err}`);
253
335
  logErr('Continuing with limited context (Chain search + portable knowledge only).');
254
336
  }
337
+ if (workspaceProfile) {
338
+ log(`Workspace profile: stage=${workspaceProfile.stage}, entries=${workspaceProfile.totalEntries}, governance=${workspaceProfile.governanceMode}`);
339
+ }
255
340
  // 3. Build search queries from repo context
256
341
  const searchQueries = [];
257
342
  if (repo.name && repo.name.length >= 2)
@@ -269,37 +354,200 @@ export async function runHandshake(options = {}) {
269
354
  let matchedEntries = [];
270
355
  if (uniqueQueries.length > 0) {
271
356
  log(`Searching Chain for: ${uniqueQueries.join(', ')}...`);
272
- const searchResults = await Promise.all(uniqueQueries.map((q) => mcpCall('chain.searchEntries', { query: q }).catch(() => [])));
357
+ const searchResults = await Promise.all(uniqueQueries.map((q) => kernelCall('chain.searchEntries', { query: q }).catch(() => [])));
273
358
  matchedEntries = deduplicateEntries(searchResults.flat());
274
359
  }
275
360
  // 5. Read canonical skills & rules from .productbrain/
276
361
  const pbDir = join(cwd, '.productbrain');
277
362
  const allSkills = readCanonicalSkills(pbDir);
278
- const allRules = readCanonicalRules(pbDir);
279
- // Apply level filtering (after read, before target filtering in write loop)
280
- const canonicalSkills = filterByLevel(allSkills, level);
281
- const canonicalRules = filterByLevel(allRules, level);
363
+ const manualRules = readCanonicalRules(pbDir);
364
+ // 5a. Optionally fetch and merge Chain-derived rules (--generate flag)
365
+ let chainRulesStats = null;
366
+ let chainGaps = [];
367
+ let allRules = manualRules;
368
+ if (generate) {
369
+ log('Generating Chain-derived rules...');
370
+ const chainResult = await generateChainRules(kernelCall, manualRules);
371
+ if (chainResult.sentinel) {
372
+ // MCP unavailable — inject sentinel rule and warn
373
+ allRules = [...manualRules, chainResult.sentinel];
374
+ logErr('Warning: Chain MCP unavailable — generated rules are disabled. Sentinel rule injected.');
375
+ }
376
+ else {
377
+ // Merge generated rules after manual rules (manual takes precedence on dedup)
378
+ allRules = [...manualRules, ...chainResult.rules];
379
+ chainRulesStats = chainResult.stats;
380
+ chainGaps = chainResult.gaps;
381
+ const { generatedRules, suppressedByManual, suppressedByZeroEntries } = chainResult.stats;
382
+ log(`Chain-derived rules: ${generatedRules} generated, ${suppressedByManual} suppressed by manual, ${suppressedByZeroEntries} gaps`);
383
+ if (chainGaps.length > 0) {
384
+ log(`Gaps (no matching governance entries): ${chainGaps.join(', ')}`);
385
+ }
386
+ // Diff: compare current state against previous run
387
+ const previousState = loadPreviousState(pbDir);
388
+ const currentState = buildCurrentState(chainResult.rules, chainResult.classified);
389
+ saveHandshakeState(pbDir, chainResult.rules, chainResult.classified);
390
+ const diff = diffHandshakeState(currentState, previousState);
391
+ const diffText = formatDiff(diff);
392
+ log(diffText);
393
+ }
394
+ }
395
+ // 5b. Read personal layer (WP-310 E2) — machine-local rules/skills from .productbrain/.local/
396
+ // Returns [] when the directory is absent. All returned entries have persist: 'local'.
397
+ const personalRules = readPersonalLayer(pbDir);
398
+ if (personalRules.length > 0) {
399
+ // Name collision detection — warn when a personal rule overrides a team rule
400
+ const teamRuleNames = new Set(allRules.map((r) => r.name));
401
+ for (const pr of personalRules) {
402
+ if (teamRuleNames.has(pr.name)) {
403
+ logErr(`Personal rule "${pr.name}" overrides team rule (local takes precedence).`);
404
+ }
405
+ }
406
+ // Merge: team rules first, personal rules appended (personal takes precedence via name collision above)
407
+ allRules = [...allRules, ...personalRules];
408
+ }
409
+ const personalSkills = readPersonalSkillsLayer(pbDir);
410
+ if (personalSkills.length > 0) {
411
+ const teamSkillNames = new Set(allSkills.map((s) => s.name));
412
+ for (const ps of personalSkills) {
413
+ if (teamSkillNames.has(ps.name)) {
414
+ logErr(`Personal skill "${ps.name}" overrides team skill (local takes precedence).`);
415
+ }
416
+ }
417
+ allSkills.push(...personalSkills);
418
+ }
419
+ // 5c. Apply manifest-based adoption filter (WP-310 E1)
420
+ // readManifest returns null when manifest.yaml is absent → filterByAdoptionState is a no-op.
421
+ const manifest = readManifest(pbDir);
422
+ // 5d. Load method registry (WP-310 E4) — only when manifest is present.
423
+ let registrySource;
424
+ let registryStale;
425
+ if (manifest) {
426
+ const registryResult = await loadMethodRegistry(manifest.method_source, kernelCall).catch(() => null);
427
+ if (registryResult) {
428
+ registrySource = registryResult.source;
429
+ registryStale = registryResult.stale;
430
+ }
431
+ }
432
+ const adoptionFilteredSkills = filterByAdoptionState(allSkills, manifest);
433
+ const adoptionFilteredRules = filterByAdoptionState(allRules, manifest);
434
+ // Compute adoption counts for report (only meaningful when manifest is present)
435
+ const adoptedRulesCount = manifest ? adoptionFilteredRules.length : undefined;
436
+ const rejectedRulesCount = manifest ? allRules.length - adoptionFilteredRules.length : undefined;
437
+ // Apply level filtering with stage-gating (after adoption filter, before target filtering in write loop)
438
+ // Stage caps the effective level: blank→beginner, seed→intermediate, grounded+→expert.
439
+ // If stage caps below the requested level, log it so the user knows why items were dropped.
440
+ const profileStage = workspaceProfile?.stage;
441
+ const levelFilteredSkills = filterByLevel(adoptionFilteredSkills, level, profileStage);
442
+ const levelFilteredRules = filterByLevel(adoptionFilteredRules, level, profileStage);
443
+ // Log when stage gating changes the effective level
444
+ if (profileStage) {
445
+ const stageCap = STAGE_TO_MAX_LEVEL[profileStage];
446
+ if (stageCap) {
447
+ const requestedIdx = level ? LEVEL_ORDER.indexOf(level) : LEVEL_ORDER.length - 1;
448
+ const capIdx = LEVEL_ORDER.indexOf(stageCap);
449
+ if (capIdx < requestedIdx) {
450
+ log(`Stage "${profileStage}" caps level from ${level || 'expert'} to ${stageCap}`);
451
+ }
452
+ }
453
+ }
454
+ // Apply when-condition filtering (stage-aware, workspace profile + repo context)
455
+ const canonicalSkills = levelFilteredSkills.filter((skill) => {
456
+ const result = evaluateConditions(skill.conditions ?? {}, workspaceProfile, repo);
457
+ if (dryRun && !result.included) {
458
+ log(` EXCLUDED skill ${skill.name}: ${result.reasons.join(', ')}`);
459
+ }
460
+ return result.included;
461
+ });
462
+ const canonicalRules = levelFilteredRules.filter((rule) => {
463
+ const result = evaluateConditions(rule.conditions ?? {}, workspaceProfile, repo);
464
+ if (dryRun && !result.included) {
465
+ log(` EXCLUDED rule ${rule.name}: ${result.reasons.join(', ')}`);
466
+ }
467
+ return result.included;
468
+ });
469
+ if (dryRun && canonicalSkills.length > 0) {
470
+ log(` INCLUDED skills: ${canonicalSkills.map((s) => s.name).join(', ')}`);
471
+ }
472
+ if (dryRun && canonicalRules.length > 0) {
473
+ log(` INCLUDED rules: ${canonicalRules.map((r) => r.name).join(', ')}`);
474
+ }
282
475
  if (canonicalSkills.length > 0 || canonicalRules.length > 0) {
283
476
  const levelSuffix = level ? ` (level: ${level})` : '';
284
- log(`Portable knowledge: ${canonicalSkills.length} skill(s), ${canonicalRules.length} rule(s)${levelSuffix}`);
477
+ const stageSuffix = profileStage ? `, stage: ${profileStage}` : '';
478
+ const stackSuffix = repo.detectedStack.length > 0 ? `, stack: [${repo.detectedStack.join(', ')}]` : '';
479
+ const totalSkills = allSkills.length;
480
+ const totalRules = allRules.length;
481
+ log(`Portable knowledge: ${canonicalSkills.length}/${totalSkills} skills, ${canonicalRules.length}/${totalRules} rules${levelSuffix}${stageSuffix}${stackSuffix}`);
285
482
  }
286
483
  // 6. Generate file contents
287
- const contextContent = orientView ? generateContextMd(orientView, repo, timestamp) : null;
484
+ // Build workspace context for AGENTS.md enrichment (stage, focus, governance, entry count)
485
+ const agentsWorkspaceContext = workspaceProfile
486
+ ? {
487
+ stage: workspaceProfile.stage,
488
+ focus: orientView?.strategicContext?.currentBet ?? undefined,
489
+ governanceMode: workspaceProfile.governanceMode,
490
+ totalEntries: workspaceProfile.totalEntries,
491
+ }
492
+ : undefined;
493
+ // Collect codex-targeted skills for AGENTS.md skill directory
494
+ // Exclude persist: 'local' rules — committed adapter files must never include local-only rules.
495
+ const agentsCodexSkills = canonicalSkills
496
+ .filter((s) => shouldEmitToTarget(s, 'codex'))
497
+ .map((s) => ({
498
+ name: s.name,
499
+ description: s.description,
500
+ triggers: s.triggers,
501
+ }));
502
+ // Collect copilot-targeted skills for copilot-instructions.md skill summaries
503
+ const copilotSkills = canonicalSkills
504
+ .filter((s) => shouldEmitToTarget(s, 'copilot'))
505
+ .map((s) => ({
506
+ name: s.name,
507
+ description: s.description,
508
+ triggers: s.triggers,
509
+ }));
510
+ // Collect copilot-targeted rules for copilot-instructions.md rule summaries
511
+ const copilotRules = canonicalRules
512
+ .filter((r) => shouldEmitToTarget(r, 'copilot'))
513
+ .map((r) => ({
514
+ name: r.name,
515
+ description: r.description,
516
+ }));
517
+ const copilotProfile = resolveSurfaceProfile('copilot');
518
+ const copilotOptions = {
519
+ profile: copilotProfile,
520
+ workspaceContext: agentsWorkspaceContext,
521
+ skills: copilotSkills.length > 0 ? copilotSkills : undefined,
522
+ rules: copilotRules.length > 0 ? copilotRules : undefined,
523
+ };
524
+ const contextContent = orientView ? generateContextMd(orientView, repo, timestamp, workspaceProfile?.stage) : null;
288
525
  const briefingContent = generateBriefingMd(matchedEntries, repo, uniqueQueries, timestamp);
526
+ const agentsContent = generateAgentsMd(timestamp, {
527
+ workspaceContext: agentsWorkspaceContext,
528
+ skills: agentsCodexSkills.length > 0 ? agentsCodexSkills : undefined,
529
+ });
289
530
  const claudeContent = generateClaudeMd(timestamp);
290
531
  const cursorContent = generateCursorMdc(timestamp);
291
- const copilotContent = generateCopilotMd(timestamp);
532
+ const copilotContent = generateCopilotMd(timestamp, copilotOptions);
292
533
  // 7. Write files
293
534
  const filesWritten = [];
294
535
  const filesSkipped = [];
536
+ const previewPlan = [];
537
+ // Surface filtering: skip adapter writes for targets not in the allowed set
538
+ const allowedTargets = options.surfaces && options.surfaces.length > 0
539
+ ? new Set(options.surfaces)
540
+ : null; // null = write all
295
541
  const writes = [
296
542
  ...(contextContent ? [{ path: join(cwd, '.productbrain', 'context.md'), relative: '.productbrain/context.md', content: contextContent, dirs: join(cwd, '.productbrain'), isAdapter: false }] : []),
297
543
  { path: join(cwd, '.productbrain', 'briefing.md'), relative: '.productbrain/briefing.md', content: briefingContent, isAdapter: false },
298
- { path: join(cwd, 'CLAUDE.md'), relative: 'CLAUDE.md', content: claudeContent, isAdapter: true },
299
- { path: join(cwd, '.cursor', 'rules', 'chain.mdc'), relative: '.cursor/rules/chain.mdc', content: cursorContent, dirs: join(cwd, '.cursor', 'rules'), isAdapter: true },
300
- { path: join(cwd, '.github', 'copilot-instructions.md'), relative: '.github/copilot-instructions.md', content: copilotContent, dirs: join(cwd, '.github'), isAdapter: true },
544
+ { path: join(cwd, 'AGENTS.md'), relative: 'AGENTS.md', content: agentsContent, isAdapter: true, target: 'codex' },
545
+ { path: join(cwd, 'CLAUDE.md'), relative: 'CLAUDE.md', content: claudeContent, isAdapter: true, target: 'claude' },
546
+ { path: join(cwd, '.cursor', 'rules', 'chain.mdc'), relative: '.cursor/rules/chain.mdc', content: cursorContent, dirs: join(cwd, '.cursor', 'rules'), isAdapter: true, target: 'cursor' },
547
+ { path: join(cwd, '.github', 'copilot-instructions.md'), relative: '.github/copilot-instructions.md', content: copilotContent, dirs: join(cwd, '.github'), isAdapter: true, target: 'copilot' },
301
548
  ];
302
549
  // Add Cursor skill copies (filtered by target)
550
+ const cursorProfile = resolveSurfaceProfile('cursor');
303
551
  for (const skill of canonicalSkills) {
304
552
  if (!shouldEmitToTarget(skill, 'cursor'))
305
553
  continue;
@@ -307,11 +555,35 @@ export async function runHandshake(options = {}) {
307
555
  writes.push({
308
556
  path: join(skillDir, 'SKILL.md'),
309
557
  relative: `.cursor/skills/${skill.name}/SKILL.md`,
310
- content: generateCursorSkill(skill),
558
+ content: generateCursorSkill(skill, cursorProfile),
311
559
  dirs: skillDir,
312
560
  isAdapter: true,
561
+ target: 'cursor',
313
562
  });
314
563
  }
564
+ // Add Codex skill copies (projected markdown + index)
565
+ const codexProfile = resolveSurfaceProfile('codex');
566
+ const codexSkills = canonicalSkills.filter((s) => shouldEmitToTarget(s, 'codex'));
567
+ for (const skill of codexSkills) {
568
+ writes.push({
569
+ path: join(cwd, '.codex', 'skills', `${skill.name}.md`),
570
+ relative: `.codex/skills/${skill.name}.md`,
571
+ content: generateCodexSkill(skill, codexProfile),
572
+ dirs: join(cwd, '.codex', 'skills'),
573
+ isAdapter: true,
574
+ target: 'codex',
575
+ });
576
+ }
577
+ writes.push({
578
+ path: join(cwd, '.codex', 'skills', 'README.md'),
579
+ relative: '.codex/skills/README.md',
580
+ content: generateCodexSkillIndex(codexSkills),
581
+ dirs: join(cwd, '.codex', 'skills'),
582
+ isAdapter: true,
583
+ target: 'codex',
584
+ });
585
+ // Validate Codex-projected skills for dead references
586
+ const codexWarnings = validateCodexSkills(codexSkills);
315
587
  // Add Cursor rule copies (filtered by target)
316
588
  for (const rule of canonicalRules) {
317
589
  if (!shouldEmitToTarget(rule, 'cursor'))
@@ -319,26 +591,29 @@ export async function runHandshake(options = {}) {
319
591
  writes.push({
320
592
  path: join(cwd, '.cursor', 'rules', `${rule.name}.mdc`),
321
593
  relative: `.cursor/rules/${rule.name}.mdc`,
322
- content: generateCursorRule(rule),
594
+ content: generateCursorRule(rule, cursorProfile),
323
595
  dirs: join(cwd, '.cursor', 'rules'),
324
596
  isAdapter: true,
597
+ target: 'cursor',
325
598
  });
326
599
  }
327
600
  // Add Claude Code rule copies (filtered by target)
601
+ const claudeProfile = resolveSurfaceProfile('claude');
328
602
  for (const rule of canonicalRules) {
329
603
  if (!shouldEmitToTarget(rule, 'claude'))
330
604
  continue;
331
605
  writes.push({
332
606
  path: join(cwd, '.claude', 'rules', `${rule.name}.md`),
333
607
  relative: `.claude/rules/${rule.name}.md`,
334
- content: generateClaudeRule(rule),
608
+ content: generateClaudeRule(rule, claudeProfile),
335
609
  dirs: join(cwd, '.claude', 'rules'),
336
610
  isAdapter: true,
611
+ target: 'claude',
337
612
  });
338
613
  }
339
614
  // Add Claude Code skill router (filtered by target)
340
615
  const claudeSkills = canonicalSkills.filter((s) => shouldEmitToTarget(s, 'claude'));
341
- const skillRouterContent = generateClaudeSkillRouter(claudeSkills);
616
+ const skillRouterContent = generateClaudeSkillRouter(claudeSkills, claudeProfile);
342
617
  if (skillRouterContent) {
343
618
  writes.push({
344
619
  path: join(cwd, '.claude', 'rules', 'skill-router.md'),
@@ -346,29 +621,102 @@ export async function runHandshake(options = {}) {
346
621
  content: skillRouterContent,
347
622
  dirs: join(cwd, '.claude', 'rules'),
348
623
  isAdapter: true,
624
+ target: 'claude',
349
625
  });
350
626
  }
627
+ const forkedPaths = [];
351
628
  for (const w of writes) {
629
+ // Surface filtering: skip adapter writes for targets not in the allowed set
630
+ if (allowedTargets && w.target && !allowedTargets.has(w.target)) {
631
+ filesSkipped.push({ path: w.relative, reason: `filtered (surface: ${w.target})` });
632
+ if (preview)
633
+ previewPlan.push({ path: w.relative, status: 'filtered' });
634
+ continue;
635
+ }
352
636
  if (w.isAdapter && !shouldWriteAdapter(w.path, force)) {
353
637
  filesSkipped.push({ path: w.relative, reason: 'exists without auto-generated marker (use --force to overwrite)' });
638
+ if (preview) {
639
+ previewPlan.push({ path: w.relative, status: 'forked' });
640
+ }
641
+ else {
642
+ forkedPaths.push(w.relative);
643
+ }
354
644
  continue;
355
645
  }
356
- if (dryRun) {
357
- filesWritten.push(w.relative + ' (dry run)');
646
+ if (preview || dryRun) {
647
+ // In preview/dry-run mode: check content to distinguish new/update/unchanged
648
+ if (existsSync(w.path)) {
649
+ const current = readFileSync(w.path, 'utf8');
650
+ const nextNormalized = normalizeHandshakeContentForComparison(w.content);
651
+ const currentNormalized = normalizeHandshakeContentForComparison(current);
652
+ if (nextNormalized === currentNormalized) {
653
+ filesSkipped.push({ path: w.relative, reason: 'unchanged' });
654
+ if (preview)
655
+ previewPlan.push({ path: w.relative, status: 'unchanged' });
656
+ }
657
+ else {
658
+ filesWritten.push(w.relative + (dryRun ? ' (dry run)' : ''));
659
+ if (preview)
660
+ previewPlan.push({ path: w.relative, status: 'would-update' });
661
+ }
662
+ }
663
+ else {
664
+ filesWritten.push(w.relative + (dryRun ? ' (dry run)' : ''));
665
+ if (preview)
666
+ previewPlan.push({ path: w.relative, status: 'would-write' });
667
+ }
358
668
  continue;
359
669
  }
360
670
  if (w.dirs)
361
671
  mkdirSync(w.dirs, { recursive: true });
672
+ if (existsSync(w.path)) {
673
+ const current = readFileSync(w.path, 'utf8');
674
+ const nextNormalized = normalizeHandshakeContentForComparison(w.content);
675
+ const currentNormalized = normalizeHandshakeContentForComparison(current);
676
+ if (nextNormalized === currentNormalized) {
677
+ filesSkipped.push({ path: w.relative, reason: 'unchanged' });
678
+ continue;
679
+ }
680
+ }
362
681
  writeFileSync(w.path, w.content);
363
682
  filesWritten.push(w.relative);
364
683
  }
365
- // 8. Report
684
+ // 8. Drift logging — if apply mode encountered forked adapters and a session is active, log a draft TEN
685
+ if (forkedPaths.length > 0) {
686
+ const session = readSession();
687
+ if (session) {
688
+ const names = forkedPaths.join(', ');
689
+ kernelCallWithSession('chain.createEntry', {
690
+ collectionSlug: 'tensions',
691
+ name: `TEN: handshake drift — ${forkedPaths.length} adapter(s) forked, sync blocked`,
692
+ status: 'draft',
693
+ data: {
694
+ description: `pb handshake --apply encountered forked adapters that blocked sync. Files: ${names}. Use --force to overwrite or resolve drift manually.`,
695
+ },
696
+ sessionId: session.sessionId,
697
+ createdBy: `agent:${session.sessionId}`,
698
+ }).catch(() => { });
699
+ }
700
+ }
701
+ // 9. Report
366
702
  const report = {
367
703
  filesWritten,
368
704
  filesSkipped,
369
705
  matchedEntries,
370
706
  searchQueries: uniqueQueries,
371
707
  repo,
708
+ codexWarnings: codexWarnings.length > 0 ? codexWarnings : undefined,
709
+ chainRulesStats: chainRulesStats ?? undefined,
710
+ chainGaps: chainGaps.length > 0 ? chainGaps : undefined,
711
+ adoptedCount: adoptedRulesCount,
712
+ rejectedCount: rejectedRulesCount,
713
+ personalRuleCount: personalRules.length > 0 ? personalRules.length : undefined,
714
+ personalSkillCount: personalSkills.length > 0 ? personalSkills.length : undefined,
715
+ registrySource,
716
+ registryStale,
717
+ preview: preview ? true : undefined,
718
+ previewPlan: preview && previewPlan.length > 0 ? previewPlan : undefined,
719
+ driftConflicts: forkedPaths.length > 0 ? forkedPaths : undefined,
372
720
  };
373
721
  if (!quiet) {
374
722
  process.stdout.write('\n');