@productbrain/cli 0.1.0-beta.997 → 0.1.0-beta.9975

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 (1428) hide show
  1. package/README.md +11 -2
  2. package/dist/__tests__/adapters.test.js +79 -53
  3. package/dist/__tests__/adapters.test.js.map +1 -1
  4. package/dist/__tests__/adminConfig.test.d.ts +18 -0
  5. package/dist/__tests__/adminConfig.test.d.ts.map +1 -0
  6. package/dist/__tests__/adminConfig.test.js +221 -0
  7. package/dist/__tests__/adminConfig.test.js.map +1 -0
  8. package/dist/__tests__/batch-transformations.test.js +2 -26
  9. package/dist/__tests__/batch-transformations.test.js.map +1 -1
  10. package/dist/__tests__/capture-receipt-coaching.test.d.ts +2 -0
  11. package/dist/__tests__/capture-receipt-coaching.test.d.ts.map +1 -0
  12. package/dist/__tests__/capture-receipt-coaching.test.js +109 -0
  13. package/dist/__tests__/capture-receipt-coaching.test.js.map +1 -0
  14. package/dist/__tests__/capture-receipt-role-hint.test.d.ts +2 -0
  15. package/dist/__tests__/capture-receipt-role-hint.test.d.ts.map +1 -0
  16. package/dist/__tests__/capture-receipt-role-hint.test.js +67 -0
  17. package/dist/__tests__/capture-receipt-role-hint.test.js.map +1 -0
  18. package/dist/__tests__/capture-receipt-spine-floor.test.d.ts +2 -0
  19. package/dist/__tests__/capture-receipt-spine-floor.test.d.ts.map +1 -0
  20. package/dist/__tests__/capture-receipt-spine-floor.test.js +45 -0
  21. package/dist/__tests__/capture-receipt-spine-floor.test.js.map +1 -0
  22. package/dist/__tests__/capture.test.js +1337 -181
  23. package/dist/__tests__/capture.test.js.map +1 -1
  24. package/dist/__tests__/client-binding-guard.test.d.ts +2 -0
  25. package/dist/__tests__/client-binding-guard.test.d.ts.map +1 -0
  26. package/dist/__tests__/client-binding-guard.test.js +84 -0
  27. package/dist/__tests__/client-binding-guard.test.js.map +1 -0
  28. package/dist/__tests__/coaching-mirror-drift.test.d.ts +2 -0
  29. package/dist/__tests__/coaching-mirror-drift.test.d.ts.map +1 -0
  30. package/dist/__tests__/coaching-mirror-drift.test.js +47 -0
  31. package/dist/__tests__/coaching-mirror-drift.test.js.map +1 -0
  32. package/dist/__tests__/codex-prep-parity.test.d.ts +2 -0
  33. package/dist/__tests__/codex-prep-parity.test.d.ts.map +1 -0
  34. package/dist/__tests__/codex-prep-parity.test.js +84 -0
  35. package/dist/__tests__/codex-prep-parity.test.js.map +1 -0
  36. package/dist/__tests__/collection-registry-seed-drift.test.d.ts +2 -0
  37. package/dist/__tests__/collection-registry-seed-drift.test.d.ts.map +1 -0
  38. package/dist/__tests__/collection-registry-seed-drift.test.js +102 -0
  39. package/dist/__tests__/collection-registry-seed-drift.test.js.map +1 -0
  40. package/dist/__tests__/config-prod-fallthrough.test.d.ts +2 -0
  41. package/dist/__tests__/config-prod-fallthrough.test.d.ts.map +1 -0
  42. package/dist/__tests__/config-prod-fallthrough.test.js +93 -0
  43. package/dist/__tests__/config-prod-fallthrough.test.js.map +1 -0
  44. package/dist/__tests__/config.test.js +559 -40
  45. package/dist/__tests__/config.test.js.map +1 -1
  46. package/dist/__tests__/constellation.test.js +26 -14
  47. package/dist/__tests__/constellation.test.js.map +1 -1
  48. package/dist/__tests__/conversation.test.d.ts +2 -0
  49. package/dist/__tests__/conversation.test.d.ts.map +1 -0
  50. package/dist/__tests__/conversation.test.js +113 -0
  51. package/dist/__tests__/conversation.test.js.map +1 -0
  52. package/dist/__tests__/entry-formatter.test.d.ts +2 -0
  53. package/dist/__tests__/entry-formatter.test.d.ts.map +1 -0
  54. package/dist/__tests__/entry-formatter.test.js +159 -0
  55. package/dist/__tests__/entry-formatter.test.js.map +1 -0
  56. package/dist/__tests__/entry-preflight.test.d.ts +2 -0
  57. package/dist/__tests__/entry-preflight.test.d.ts.map +1 -0
  58. package/dist/__tests__/entry-preflight.test.js +58 -0
  59. package/dist/__tests__/entry-preflight.test.js.map +1 -0
  60. package/dist/__tests__/entryAccept-batch.test.d.ts +2 -0
  61. package/dist/__tests__/entryAccept-batch.test.d.ts.map +1 -0
  62. package/dist/__tests__/entryAccept-batch.test.js +305 -0
  63. package/dist/__tests__/entryAccept-batch.test.js.map +1 -0
  64. package/dist/__tests__/entryAccept.test.d.ts +2 -0
  65. package/dist/__tests__/entryAccept.test.d.ts.map +1 -0
  66. package/dist/__tests__/entryAccept.test.js +526 -0
  67. package/dist/__tests__/entryAccept.test.js.map +1 -0
  68. package/dist/__tests__/entryDiscardResolve.test.d.ts +2 -0
  69. package/dist/__tests__/entryDiscardResolve.test.d.ts.map +1 -0
  70. package/dist/__tests__/entryDiscardResolve.test.js +28 -0
  71. package/dist/__tests__/entryDiscardResolve.test.js.map +1 -0
  72. package/dist/__tests__/entryOwn.test.d.ts +2 -0
  73. package/dist/__tests__/entryOwn.test.d.ts.map +1 -0
  74. package/dist/__tests__/entryOwn.test.js +50 -0
  75. package/dist/__tests__/entryOwn.test.js.map +1 -0
  76. package/dist/__tests__/entryTick.test.d.ts +2 -0
  77. package/dist/__tests__/entryTick.test.d.ts.map +1 -0
  78. package/dist/__tests__/entryTick.test.js +40 -0
  79. package/dist/__tests__/entryTick.test.js.map +1 -0
  80. package/dist/__tests__/envelope-contract.test.js +2 -0
  81. package/dist/__tests__/envelope-contract.test.js.map +1 -1
  82. package/dist/__tests__/errors.test.js +41 -0
  83. package/dist/__tests__/errors.test.js.map +1 -1
  84. package/dist/__tests__/fields.test.js +14 -3
  85. package/dist/__tests__/fields.test.js.map +1 -1
  86. package/dist/__tests__/gateway-dry-run-timeout.test.d.ts +2 -0
  87. package/dist/__tests__/gateway-dry-run-timeout.test.d.ts.map +1 -0
  88. package/dist/__tests__/gateway-dry-run-timeout.test.js +70 -0
  89. package/dist/__tests__/gateway-dry-run-timeout.test.js.map +1 -0
  90. package/dist/__tests__/gateway-timeout-body-phase.test.d.ts +2 -0
  91. package/dist/__tests__/gateway-timeout-body-phase.test.d.ts.map +1 -0
  92. package/dist/__tests__/gateway-timeout-body-phase.test.js +116 -0
  93. package/dist/__tests__/gateway-timeout-body-phase.test.js.map +1 -0
  94. package/dist/__tests__/handshake-augment.test.js +4 -20
  95. package/dist/__tests__/handshake-augment.test.js.map +1 -1
  96. package/dist/__tests__/handshake-dormancy.test.js +10 -193
  97. package/dist/__tests__/handshake-dormancy.test.js.map +1 -1
  98. package/dist/__tests__/handshake-formatter.test.js +44 -0
  99. package/dist/__tests__/handshake-formatter.test.js.map +1 -1
  100. package/dist/__tests__/handshake-preview.test.js +271 -612
  101. package/dist/__tests__/handshake-preview.test.js.map +1 -1
  102. package/dist/__tests__/handshake-session-threading.test.d.ts +2 -0
  103. package/dist/__tests__/handshake-session-threading.test.d.ts.map +1 -0
  104. package/dist/__tests__/handshake-session-threading.test.js +185 -0
  105. package/dist/__tests__/handshake-session-threading.test.js.map +1 -0
  106. package/dist/__tests__/handshake.e2e.test.js +7 -1033
  107. package/dist/__tests__/handshake.e2e.test.js.map +1 -1
  108. package/dist/__tests__/handshake.test.js +523 -308
  109. package/dist/__tests__/handshake.test.js.map +1 -1
  110. package/dist/__tests__/health-gap-kinds-drift.test.d.ts +2 -0
  111. package/dist/__tests__/health-gap-kinds-drift.test.d.ts.map +1 -0
  112. package/dist/__tests__/health-gap-kinds-drift.test.js +43 -0
  113. package/dist/__tests__/health-gap-kinds-drift.test.js.map +1 -0
  114. package/dist/__tests__/hook-intents.test.js +3 -3
  115. package/dist/__tests__/hook-intents.test.js.map +1 -1
  116. package/dist/__tests__/ingest.test.js +9 -0
  117. package/dist/__tests__/ingest.test.js.map +1 -1
  118. package/dist/__tests__/init.test.js +51 -14
  119. package/dist/__tests__/init.test.js.map +1 -1
  120. package/dist/__tests__/kernel-value-sets-drift.test.d.ts +2 -0
  121. package/dist/__tests__/kernel-value-sets-drift.test.d.ts.map +1 -0
  122. package/dist/__tests__/kernel-value-sets-drift.test.js +46 -0
  123. package/dist/__tests__/kernel-value-sets-drift.test.js.map +1 -0
  124. package/dist/__tests__/kernel-value-sets-generator.test.d.ts +2 -0
  125. package/dist/__tests__/kernel-value-sets-generator.test.d.ts.map +1 -0
  126. package/dist/__tests__/kernel-value-sets-generator.test.js +108 -0
  127. package/dist/__tests__/kernel-value-sets-generator.test.js.map +1 -0
  128. package/dist/__tests__/login.test.js +18 -1
  129. package/dist/__tests__/login.test.js.map +1 -1
  130. package/dist/__tests__/method-registry.integration.test.js +2 -3
  131. package/dist/__tests__/method-registry.integration.test.js.map +1 -1
  132. package/dist/__tests__/method-registry.test.d.ts +6 -8
  133. package/dist/__tests__/method-registry.test.d.ts.map +1 -1
  134. package/dist/__tests__/method-registry.test.js +22 -70
  135. package/dist/__tests__/method-registry.test.js.map +1 -1
  136. package/dist/__tests__/missingPin.test.d.ts +11 -0
  137. package/dist/__tests__/missingPin.test.d.ts.map +1 -0
  138. package/dist/__tests__/missingPin.test.js +232 -0
  139. package/dist/__tests__/missingPin.test.js.map +1 -0
  140. package/dist/__tests__/notice-marker.test.js +146 -11
  141. package/dist/__tests__/notice-marker.test.js.map +1 -1
  142. package/dist/__tests__/onboarding.test.js +29 -5
  143. package/dist/__tests__/onboarding.test.js.map +1 -1
  144. package/dist/__tests__/onboardingFallback.test.d.ts +2 -0
  145. package/dist/__tests__/onboardingFallback.test.d.ts.map +1 -0
  146. package/dist/__tests__/onboardingFallback.test.js +74 -0
  147. package/dist/__tests__/onboardingFallback.test.js.map +1 -0
  148. package/dist/__tests__/orient.test.js +367 -38
  149. package/dist/__tests__/orient.test.js.map +1 -1
  150. package/dist/__tests__/perimeter.test.js +1 -1
  151. package/dist/__tests__/perimeter.test.js.map +1 -1
  152. package/dist/__tests__/preview-key-refresh.test.d.ts +2 -0
  153. package/dist/__tests__/preview-key-refresh.test.d.ts.map +1 -0
  154. package/dist/__tests__/preview-key-refresh.test.js +126 -0
  155. package/dist/__tests__/preview-key-refresh.test.js.map +1 -0
  156. package/dist/__tests__/profiles.test.js +498 -8
  157. package/dist/__tests__/profiles.test.js.map +1 -1
  158. package/dist/__tests__/prompts.test.js +18 -1
  159. package/dist/__tests__/prompts.test.js.map +1 -1
  160. package/dist/__tests__/proof-run.test.d.ts +2 -0
  161. package/dist/__tests__/proof-run.test.d.ts.map +1 -0
  162. package/dist/__tests__/proof-run.test.js +255 -0
  163. package/dist/__tests__/proof-run.test.js.map +1 -0
  164. package/dist/__tests__/rate-limit-resilience.test.d.ts +7 -0
  165. package/dist/__tests__/rate-limit-resilience.test.d.ts.map +1 -0
  166. package/dist/__tests__/rate-limit-resilience.test.js +209 -0
  167. package/dist/__tests__/rate-limit-resilience.test.js.map +1 -0
  168. package/dist/__tests__/read-target-notice.test.d.ts +2 -0
  169. package/dist/__tests__/read-target-notice.test.d.ts.map +1 -0
  170. package/dist/__tests__/read-target-notice.test.js +125 -0
  171. package/dist/__tests__/read-target-notice.test.js.map +1 -0
  172. package/dist/__tests__/relate.test.js +246 -14
  173. package/dist/__tests__/relate.test.js.map +1 -1
  174. package/dist/__tests__/reply-commands-registered.test.d.ts +2 -0
  175. package/dist/__tests__/reply-commands-registered.test.d.ts.map +1 -0
  176. package/dist/__tests__/reply-commands-registered.test.js +81 -0
  177. package/dist/__tests__/reply-commands-registered.test.js.map +1 -0
  178. package/dist/__tests__/repo-detect.test.js +18 -38
  179. package/dist/__tests__/repo-detect.test.js.map +1 -1
  180. package/dist/__tests__/reportedProfile.test.d.ts +2 -0
  181. package/dist/__tests__/reportedProfile.test.d.ts.map +1 -0
  182. package/dist/__tests__/reportedProfile.test.js +328 -0
  183. package/dist/__tests__/reportedProfile.test.js.map +1 -0
  184. package/dist/__tests__/restore.test.d.ts +2 -0
  185. package/dist/__tests__/restore.test.d.ts.map +1 -0
  186. package/dist/__tests__/restore.test.js +85 -0
  187. package/dist/__tests__/restore.test.js.map +1 -0
  188. package/dist/__tests__/route-latency-budget.test.d.ts +2 -0
  189. package/dist/__tests__/route-latency-budget.test.d.ts.map +1 -0
  190. package/dist/__tests__/route-latency-budget.test.js +106 -0
  191. package/dist/__tests__/route-latency-budget.test.js.map +1 -0
  192. package/dist/__tests__/runner.test.js +59 -44
  193. package/dist/__tests__/runner.test.js.map +1 -1
  194. package/dist/__tests__/session-binding-refusal-tenant.test.d.ts +2 -0
  195. package/dist/__tests__/session-binding-refusal-tenant.test.d.ts.map +1 -0
  196. package/dist/__tests__/session-binding-refusal-tenant.test.js +112 -0
  197. package/dist/__tests__/session-binding-refusal-tenant.test.js.map +1 -0
  198. package/dist/__tests__/session-close-loop.test.d.ts +2 -0
  199. package/dist/__tests__/session-close-loop.test.d.ts.map +1 -0
  200. package/dist/__tests__/session-close-loop.test.js +213 -0
  201. package/dist/__tests__/session-close-loop.test.js.map +1 -0
  202. package/dist/__tests__/session-label.test.d.ts +2 -0
  203. package/dist/__tests__/session-label.test.d.ts.map +1 -0
  204. package/dist/__tests__/session-label.test.js +46 -0
  205. package/dist/__tests__/session-label.test.js.map +1 -0
  206. package/dist/__tests__/session-list-show.test.d.ts +2 -0
  207. package/dist/__tests__/session-list-show.test.d.ts.map +1 -0
  208. package/dist/__tests__/session-list-show.test.js +173 -0
  209. package/dist/__tests__/session-list-show.test.js.map +1 -0
  210. package/dist/__tests__/session-pinned-role.test.d.ts +2 -0
  211. package/dist/__tests__/session-pinned-role.test.d.ts.map +1 -0
  212. package/dist/__tests__/session-pinned-role.test.js +257 -0
  213. package/dist/__tests__/session-pinned-role.test.js.map +1 -0
  214. package/dist/__tests__/session-reset.test.d.ts +2 -0
  215. package/dist/__tests__/session-reset.test.d.ts.map +1 -0
  216. package/dist/__tests__/session-reset.test.js +138 -0
  217. package/dist/__tests__/session-reset.test.js.map +1 -0
  218. package/dist/__tests__/session-resume-backstop.test.d.ts +2 -0
  219. package/dist/__tests__/session-resume-backstop.test.d.ts.map +1 -0
  220. package/dist/__tests__/session-resume-backstop.test.js +139 -0
  221. package/dist/__tests__/session-resume-backstop.test.js.map +1 -0
  222. package/dist/__tests__/session-role-name-sanitize.test.d.ts +2 -0
  223. package/dist/__tests__/session-role-name-sanitize.test.d.ts.map +1 -0
  224. package/dist/__tests__/session-role-name-sanitize.test.js +129 -0
  225. package/dist/__tests__/session-role-name-sanitize.test.js.map +1 -0
  226. package/dist/__tests__/session-start-key-refresh.test.d.ts +2 -0
  227. package/dist/__tests__/session-start-key-refresh.test.d.ts.map +1 -0
  228. package/dist/__tests__/session-start-key-refresh.test.js +197 -0
  229. package/dist/__tests__/session-start-key-refresh.test.js.map +1 -0
  230. package/dist/__tests__/session-state-machine.test.js +190 -9
  231. package/dist/__tests__/session-state-machine.test.js.map +1 -1
  232. package/dist/__tests__/session-switch.test.js +218 -4
  233. package/dist/__tests__/session-switch.test.js.map +1 -1
  234. package/dist/__tests__/session-touch.test.js +6 -1
  235. package/dist/__tests__/session-touch.test.js.map +1 -1
  236. package/dist/__tests__/sessionBinding.test.d.ts +2 -0
  237. package/dist/__tests__/sessionBinding.test.d.ts.map +1 -0
  238. package/dist/__tests__/sessionBinding.test.js +118 -0
  239. package/dist/__tests__/sessionBinding.test.js.map +1 -0
  240. package/dist/__tests__/sessionByIdLookup.test.d.ts +2 -0
  241. package/dist/__tests__/sessionByIdLookup.test.d.ts.map +1 -0
  242. package/dist/__tests__/sessionByIdLookup.test.js +63 -0
  243. package/dist/__tests__/sessionByIdLookup.test.js.map +1 -0
  244. package/dist/__tests__/skill-vocabulary.test.d.ts +1 -1
  245. package/dist/__tests__/skill-vocabulary.test.js +7 -2
  246. package/dist/__tests__/skill-vocabulary.test.js.map +1 -1
  247. package/dist/__tests__/state.test.js +21 -1
  248. package/dist/__tests__/state.test.js.map +1 -1
  249. package/dist/__tests__/stillTrue.test.d.ts +2 -0
  250. package/dist/__tests__/stillTrue.test.d.ts.map +1 -0
  251. package/dist/__tests__/stillTrue.test.js +52 -0
  252. package/dist/__tests__/stillTrue.test.js.map +1 -0
  253. package/dist/__tests__/strip.test.js +57 -3
  254. package/dist/__tests__/strip.test.js.map +1 -1
  255. package/dist/__tests__/tenant-notice-write-path.test.d.ts +2 -0
  256. package/dist/__tests__/tenant-notice-write-path.test.d.ts.map +1 -0
  257. package/dist/__tests__/tenant-notice-write-path.test.js +169 -0
  258. package/dist/__tests__/tenant-notice-write-path.test.js.map +1 -0
  259. package/dist/__tests__/update.test.js +458 -8
  260. package/dist/__tests__/update.test.js.map +1 -1
  261. package/dist/__tests__/verify-formatter.test.d.ts +2 -0
  262. package/dist/__tests__/verify-formatter.test.d.ts.map +1 -0
  263. package/dist/__tests__/verify-formatter.test.js +85 -0
  264. package/dist/__tests__/verify-formatter.test.js.map +1 -0
  265. package/dist/__tests__/vocabulary-leak.test.d.ts +1 -7
  266. package/dist/__tests__/vocabulary-leak.test.d.ts.map +1 -1
  267. package/dist/__tests__/vocabulary-leak.test.js +7 -114
  268. package/dist/__tests__/vocabulary-leak.test.js.map +1 -1
  269. package/dist/__tests__/workspace.test.js +11 -72
  270. package/dist/__tests__/workspace.test.js.map +1 -1
  271. package/dist/__tests__/workspaceNotice.test.d.ts +2 -0
  272. package/dist/__tests__/workspaceNotice.test.d.ts.map +1 -0
  273. package/dist/__tests__/workspaceNotice.test.js +571 -0
  274. package/dist/__tests__/workspaceNotice.test.js.map +1 -0
  275. package/dist/commands/__tests__/quality.test.d.ts +2 -0
  276. package/dist/commands/__tests__/quality.test.d.ts.map +1 -0
  277. package/dist/commands/__tests__/quality.test.js +156 -0
  278. package/dist/commands/__tests__/quality.test.js.map +1 -0
  279. package/dist/commands/__tests__/rework.test.d.ts +2 -0
  280. package/dist/commands/__tests__/rework.test.d.ts.map +1 -0
  281. package/dist/commands/__tests__/rework.test.js +149 -0
  282. package/dist/commands/__tests__/rework.test.js.map +1 -0
  283. package/dist/commands/__tests__/tensionsList.test.d.ts +2 -0
  284. package/dist/commands/__tests__/tensionsList.test.d.ts.map +1 -0
  285. package/dist/commands/__tests__/tensionsList.test.js +63 -0
  286. package/dist/commands/__tests__/tensionsList.test.js.map +1 -0
  287. package/dist/commands/accept-policy.d.ts +10 -0
  288. package/dist/commands/accept-policy.d.ts.map +1 -0
  289. package/dist/commands/accept-policy.js +107 -0
  290. package/dist/commands/accept-policy.js.map +1 -0
  291. package/dist/commands/admin/cockpit.d.ts +2 -13
  292. package/dist/commands/admin/cockpit.d.ts.map +1 -1
  293. package/dist/commands/admin/cockpit.js +5 -5
  294. package/dist/commands/admin/cockpit.js.map +1 -1
  295. package/dist/commands/admin/index.d.ts +49 -0
  296. package/dist/commands/admin/index.d.ts.map +1 -1
  297. package/dist/commands/admin/index.js +148 -29
  298. package/dist/commands/admin/index.js.map +1 -1
  299. package/dist/commands/admin/index.test.d.ts +2 -0
  300. package/dist/commands/admin/index.test.d.ts.map +1 -0
  301. package/dist/commands/admin/index.test.js +94 -0
  302. package/dist/commands/admin/index.test.js.map +1 -0
  303. package/dist/commands/admin/inspect.d.ts.map +1 -1
  304. package/dist/commands/admin/inspect.js +2 -7
  305. package/dist/commands/admin/inspect.js.map +1 -1
  306. package/dist/commands/admin/probe.d.ts +75 -0
  307. package/dist/commands/admin/probe.d.ts.map +1 -0
  308. package/dist/commands/admin/probe.js +224 -0
  309. package/dist/commands/admin/probe.js.map +1 -0
  310. package/dist/commands/admin/probe.test.d.ts +2 -0
  311. package/dist/commands/admin/probe.test.d.ts.map +1 -0
  312. package/dist/commands/admin/probe.test.js +193 -0
  313. package/dist/commands/admin/probe.test.js.map +1 -0
  314. package/dist/commands/admin/run.d.ts +43 -0
  315. package/dist/commands/admin/run.d.ts.map +1 -0
  316. package/dist/commands/admin/run.js +78 -0
  317. package/dist/commands/admin/run.js.map +1 -0
  318. package/dist/commands/admin/run.test.d.ts +18 -0
  319. package/dist/commands/admin/run.test.d.ts.map +1 -0
  320. package/dist/commands/admin/run.test.js +168 -0
  321. package/dist/commands/admin/run.test.js.map +1 -0
  322. package/dist/commands/admin/seed.d.ts +6 -21
  323. package/dist/commands/admin/seed.d.ts.map +1 -1
  324. package/dist/commands/admin/seed.js +41 -310
  325. package/dist/commands/admin/seed.js.map +1 -1
  326. package/dist/commands/admin/seed.test.d.ts +3 -4
  327. package/dist/commands/admin/seed.test.d.ts.map +1 -1
  328. package/dist/commands/admin/seed.test.js +26 -76
  329. package/dist/commands/admin/seed.test.js.map +1 -1
  330. package/dist/commands/admin/seedRegistryEntries.generated.d.ts.map +1 -1
  331. package/dist/commands/admin/seedRegistryEntries.generated.js +3 -84
  332. package/dist/commands/admin/seedRegistryEntries.generated.js.map +1 -1
  333. package/dist/commands/admin/seedRegistryEntries.test.d.ts +5 -3
  334. package/dist/commands/admin/seedRegistryEntries.test.d.ts.map +1 -1
  335. package/dist/commands/admin/seedRegistryEntries.test.js +60 -26
  336. package/dist/commands/admin/seedRegistryEntries.test.js.map +1 -1
  337. package/dist/commands/admin/seedRowType.d.ts +22 -0
  338. package/dist/commands/admin/seedRowType.d.ts.map +1 -0
  339. package/dist/commands/admin/seedRowType.js +2 -0
  340. package/dist/commands/admin/seedRowType.js.map +1 -0
  341. package/dist/commands/admin/seedStatusColor.d.ts +9 -0
  342. package/dist/commands/admin/seedStatusColor.d.ts.map +1 -0
  343. package/dist/commands/admin/seedStatusColor.js +19 -0
  344. package/dist/commands/admin/seedStatusColor.js.map +1 -0
  345. package/dist/commands/admin/seedStatusColor.test.d.ts +2 -0
  346. package/dist/commands/admin/seedStatusColor.test.d.ts.map +1 -0
  347. package/dist/commands/admin/seedStatusColor.test.js +31 -0
  348. package/dist/commands/admin/seedStatusColor.test.js.map +1 -0
  349. package/dist/commands/brief.d.ts.map +1 -1
  350. package/dist/commands/brief.js +24 -2
  351. package/dist/commands/brief.js.map +1 -1
  352. package/dist/commands/capture.d.ts +17 -9
  353. package/dist/commands/capture.d.ts.map +1 -1
  354. package/dist/commands/capture.js +173 -227
  355. package/dist/commands/capture.js.map +1 -1
  356. package/dist/commands/chain-walk.d.ts.map +1 -1
  357. package/dist/commands/chain-walk.js.map +1 -1
  358. package/dist/commands/changes.d.ts.map +1 -1
  359. package/dist/commands/changes.js.map +1 -1
  360. package/dist/commands/codex-prep.d.ts +11 -1
  361. package/dist/commands/codex-prep.d.ts.map +1 -1
  362. package/dist/commands/codex-prep.js +14 -83
  363. package/dist/commands/codex-prep.js.map +1 -1
  364. package/dist/commands/collections.d.ts +1 -1
  365. package/dist/commands/collections.d.ts.map +1 -1
  366. package/dist/commands/collections.js +1 -1
  367. package/dist/commands/collections.js.map +1 -1
  368. package/dist/commands/conflicts.d.ts +35 -0
  369. package/dist/commands/conflicts.d.ts.map +1 -0
  370. package/dist/commands/conflicts.js +194 -0
  371. package/dist/commands/conflicts.js.map +1 -0
  372. package/dist/commands/conflicts.test.d.ts +2 -0
  373. package/dist/commands/conflicts.test.d.ts.map +1 -0
  374. package/dist/commands/conflicts.test.js +179 -0
  375. package/dist/commands/conflicts.test.js.map +1 -0
  376. package/dist/commands/connect-config.test.js +11 -3
  377. package/dist/commands/connect-config.test.js.map +1 -1
  378. package/dist/commands/connect-context.d.ts +27 -17
  379. package/dist/commands/connect-context.d.ts.map +1 -1
  380. package/dist/commands/connect-context.js +45 -31
  381. package/dist/commands/connect-context.js.map +1 -1
  382. package/dist/commands/connect-context.test.js +91 -53
  383. package/dist/commands/connect-context.test.js.map +1 -1
  384. package/dist/commands/connect-decline.test.d.ts +2 -0
  385. package/dist/commands/connect-decline.test.d.ts.map +1 -0
  386. package/dist/commands/connect-decline.test.js +70 -0
  387. package/dist/commands/connect-decline.test.js.map +1 -0
  388. package/dist/commands/connect-integration.test.js +24 -7
  389. package/dist/commands/connect-integration.test.js.map +1 -1
  390. package/dist/commands/connect-legacy-migration.test.d.ts +2 -0
  391. package/dist/commands/connect-legacy-migration.test.d.ts.map +1 -0
  392. package/dist/commands/connect-legacy-migration.test.js +109 -0
  393. package/dist/commands/connect-legacy-migration.test.js.map +1 -0
  394. package/dist/commands/connect-redeem-failure.test.d.ts +2 -0
  395. package/dist/commands/connect-redeem-failure.test.d.ts.map +1 -0
  396. package/dist/commands/connect-redeem-failure.test.js +134 -0
  397. package/dist/commands/connect-redeem-failure.test.js.map +1 -0
  398. package/dist/commands/connect-screens.d.ts +14 -3
  399. package/dist/commands/connect-screens.d.ts.map +1 -1
  400. package/dist/commands/connect-screens.js +62 -9
  401. package/dist/commands/connect-screens.js.map +1 -1
  402. package/dist/commands/connect-seal.test.d.ts +2 -0
  403. package/dist/commands/connect-seal.test.d.ts.map +1 -0
  404. package/dist/commands/connect-seal.test.js +55 -0
  405. package/dist/commands/connect-seal.test.js.map +1 -0
  406. package/dist/commands/connect.d.ts +14 -11
  407. package/dist/commands/connect.d.ts.map +1 -1
  408. package/dist/commands/connect.js +236 -69
  409. package/dist/commands/connect.js.map +1 -1
  410. package/dist/commands/connect.test.js +226 -23
  411. package/dist/commands/connect.test.js.map +1 -1
  412. package/dist/commands/constellation.d.ts.map +1 -1
  413. package/dist/commands/constellation.js.map +1 -1
  414. package/dist/commands/context.d.ts.map +1 -1
  415. package/dist/commands/context.js.map +1 -1
  416. package/dist/commands/cross-cut.d.ts.map +1 -1
  417. package/dist/commands/cross-cut.js.map +1 -1
  418. package/dist/commands/digest.d.ts +17 -0
  419. package/dist/commands/digest.d.ts.map +1 -0
  420. package/dist/commands/digest.js +58 -0
  421. package/dist/commands/digest.js.map +1 -0
  422. package/dist/commands/digest.test.d.ts +2 -0
  423. package/dist/commands/digest.test.d.ts.map +1 -0
  424. package/dist/commands/digest.test.js +36 -0
  425. package/dist/commands/digest.test.js.map +1 -0
  426. package/dist/commands/direction.d.ts +10 -0
  427. package/dist/commands/direction.d.ts.map +1 -0
  428. package/dist/commands/direction.js +79 -0
  429. package/dist/commands/direction.js.map +1 -0
  430. package/dist/commands/doctor.d.ts.map +1 -1
  431. package/dist/commands/doctor.js +105 -35
  432. package/dist/commands/doctor.js.map +1 -1
  433. package/dist/commands/doctor.test.js +202 -6
  434. package/dist/commands/doctor.test.js.map +1 -1
  435. package/dist/commands/entryAccept.d.ts +26 -0
  436. package/dist/commands/entryAccept.d.ts.map +1 -0
  437. package/dist/commands/entryAccept.js +308 -0
  438. package/dist/commands/entryAccept.js.map +1 -0
  439. package/dist/commands/entryDiscardResolve.d.ts +9 -0
  440. package/dist/commands/entryDiscardResolve.d.ts.map +1 -0
  441. package/dist/commands/entryDiscardResolve.js +27 -0
  442. package/dist/commands/entryDiscardResolve.js.map +1 -0
  443. package/dist/commands/entryOwn.d.ts +5 -0
  444. package/dist/commands/entryOwn.d.ts.map +1 -0
  445. package/dist/commands/entryOwn.js +17 -0
  446. package/dist/commands/entryOwn.js.map +1 -0
  447. package/dist/commands/entryPreflight.d.ts +8 -0
  448. package/dist/commands/entryPreflight.d.ts.map +1 -0
  449. package/dist/commands/entryPreflight.js +48 -0
  450. package/dist/commands/entryPreflight.js.map +1 -0
  451. package/dist/commands/entryTick.d.ts +8 -0
  452. package/dist/commands/entryTick.d.ts.map +1 -0
  453. package/dist/commands/entryTick.js +43 -0
  454. package/dist/commands/entryTick.js.map +1 -0
  455. package/dist/commands/feedback.d.ts +36 -0
  456. package/dist/commands/feedback.d.ts.map +1 -0
  457. package/dist/commands/feedback.js +174 -0
  458. package/dist/commands/feedback.js.map +1 -0
  459. package/dist/commands/feedback.test.d.ts +2 -0
  460. package/dist/commands/feedback.test.d.ts.map +1 -0
  461. package/dist/commands/feedback.test.js +110 -0
  462. package/dist/commands/feedback.test.js.map +1 -0
  463. package/dist/commands/fields.d.ts.map +1 -1
  464. package/dist/commands/fields.js +1 -1
  465. package/dist/commands/fields.js.map +1 -1
  466. package/dist/commands/files.d.ts +26 -0
  467. package/dist/commands/files.d.ts.map +1 -0
  468. package/dist/commands/files.js +160 -0
  469. package/dist/commands/files.js.map +1 -0
  470. package/dist/commands/files.test.d.ts +2 -0
  471. package/dist/commands/files.test.d.ts.map +1 -0
  472. package/dist/commands/files.test.js +278 -0
  473. package/dist/commands/files.test.js.map +1 -0
  474. package/dist/commands/handshake.d.ts +42 -186
  475. package/dist/commands/handshake.d.ts.map +1 -1
  476. package/dist/commands/handshake.js +469 -1540
  477. package/dist/commands/handshake.js.map +1 -1
  478. package/dist/commands/handshakeCursorSkillCleanup.d.ts +36 -0
  479. package/dist/commands/handshakeCursorSkillCleanup.d.ts.map +1 -0
  480. package/dist/commands/handshakeCursorSkillCleanup.js +110 -0
  481. package/dist/commands/handshakeCursorSkillCleanup.js.map +1 -0
  482. package/dist/commands/handshakeDriftClassification.d.ts +33 -0
  483. package/dist/commands/handshakeDriftClassification.d.ts.map +1 -0
  484. package/dist/commands/handshakeDriftClassification.js +62 -0
  485. package/dist/commands/handshakeDriftClassification.js.map +1 -0
  486. package/dist/commands/history.d.ts +30 -0
  487. package/dist/commands/history.d.ts.map +1 -0
  488. package/dist/commands/history.js +62 -0
  489. package/dist/commands/history.js.map +1 -0
  490. package/dist/commands/history.test.d.ts +2 -0
  491. package/dist/commands/history.test.d.ts.map +1 -0
  492. package/dist/commands/history.test.js +106 -0
  493. package/dist/commands/history.test.js.map +1 -0
  494. package/dist/commands/ingest.d.ts.map +1 -1
  495. package/dist/commands/ingest.js +9 -0
  496. package/dist/commands/ingest.js.map +1 -1
  497. package/dist/commands/init.d.ts +1 -1
  498. package/dist/commands/init.d.ts.map +1 -1
  499. package/dist/commands/init.js +22 -13
  500. package/dist/commands/init.js.map +1 -1
  501. package/dist/commands/login.d.ts.map +1 -1
  502. package/dist/commands/login.js +15 -11
  503. package/dist/commands/login.js.map +1 -1
  504. package/dist/commands/organisation.d.ts +12 -0
  505. package/dist/commands/organisation.d.ts.map +1 -0
  506. package/dist/commands/organisation.js +147 -0
  507. package/dist/commands/organisation.js.map +1 -0
  508. package/dist/commands/organisation.test.d.ts +2 -0
  509. package/dist/commands/organisation.test.d.ts.map +1 -0
  510. package/dist/commands/organisation.test.js +116 -0
  511. package/dist/commands/organisation.test.js.map +1 -0
  512. package/dist/commands/organisationHierarchy.d.ts +8 -0
  513. package/dist/commands/organisationHierarchy.d.ts.map +1 -0
  514. package/dist/commands/organisationHierarchy.js +75 -0
  515. package/dist/commands/organisationHierarchy.js.map +1 -0
  516. package/dist/commands/organisationHierarchy.test.d.ts +2 -0
  517. package/dist/commands/organisationHierarchy.test.d.ts.map +1 -0
  518. package/dist/commands/organisationHierarchy.test.js +72 -0
  519. package/dist/commands/organisationHierarchy.test.js.map +1 -0
  520. package/dist/commands/organisationWrite.d.ts +18 -0
  521. package/dist/commands/organisationWrite.d.ts.map +1 -0
  522. package/dist/commands/organisationWrite.js +71 -0
  523. package/dist/commands/organisationWrite.js.map +1 -0
  524. package/dist/commands/orient.d.ts +45 -96
  525. package/dist/commands/orient.d.ts.map +1 -1
  526. package/dist/commands/orient.js +135 -29
  527. package/dist/commands/orient.js.map +1 -1
  528. package/dist/commands/outcome.d.ts +91 -0
  529. package/dist/commands/outcome.d.ts.map +1 -0
  530. package/dist/commands/outcome.js +204 -0
  531. package/dist/commands/outcome.js.map +1 -0
  532. package/dist/commands/outcome.test.d.ts +2 -0
  533. package/dist/commands/outcome.test.d.ts.map +1 -0
  534. package/dist/commands/outcome.test.js +308 -0
  535. package/dist/commands/outcome.test.js.map +1 -0
  536. package/dist/commands/people.d.ts +6 -0
  537. package/dist/commands/people.d.ts.map +1 -0
  538. package/dist/commands/people.js +22 -0
  539. package/dist/commands/people.js.map +1 -0
  540. package/dist/commands/people.test.d.ts +2 -0
  541. package/dist/commands/people.test.d.ts.map +1 -0
  542. package/dist/commands/people.test.js +61 -0
  543. package/dist/commands/people.test.js.map +1 -0
  544. package/dist/commands/profile.d.ts +23 -2
  545. package/dist/commands/profile.d.ts.map +1 -1
  546. package/dist/commands/profile.js +192 -35
  547. package/dist/commands/profile.js.map +1 -1
  548. package/dist/commands/proof-run.d.ts +51 -0
  549. package/dist/commands/proof-run.d.ts.map +1 -0
  550. package/dist/commands/proof-run.js +209 -0
  551. package/dist/commands/proof-run.js.map +1 -0
  552. package/dist/commands/quality.d.ts +16 -0
  553. package/dist/commands/quality.d.ts.map +1 -0
  554. package/dist/commands/quality.js +29 -0
  555. package/dist/commands/quality.js.map +1 -0
  556. package/dist/commands/questions.d.ts +23 -0
  557. package/dist/commands/questions.d.ts.map +1 -0
  558. package/dist/commands/questions.js +238 -0
  559. package/dist/commands/questions.js.map +1 -0
  560. package/dist/commands/questions.test.d.ts +2 -0
  561. package/dist/commands/questions.test.d.ts.map +1 -0
  562. package/dist/commands/questions.test.js +159 -0
  563. package/dist/commands/questions.test.js.map +1 -0
  564. package/dist/commands/relate.d.ts +1 -0
  565. package/dist/commands/relate.d.ts.map +1 -1
  566. package/dist/commands/relate.js +85 -13
  567. package/dist/commands/relate.js.map +1 -1
  568. package/dist/commands/restore.d.ts +2 -0
  569. package/dist/commands/restore.d.ts.map +1 -0
  570. package/dist/commands/restore.js +83 -0
  571. package/dist/commands/restore.js.map +1 -0
  572. package/dist/commands/rework.d.ts +24 -0
  573. package/dist/commands/rework.d.ts.map +1 -0
  574. package/dist/commands/rework.js +97 -0
  575. package/dist/commands/rework.js.map +1 -0
  576. package/dist/commands/role.d.ts +67 -0
  577. package/dist/commands/role.d.ts.map +1 -0
  578. package/dist/commands/role.js +164 -0
  579. package/dist/commands/role.js.map +1 -0
  580. package/dist/commands/role.test.d.ts +2 -0
  581. package/dist/commands/role.test.d.ts.map +1 -0
  582. package/dist/commands/role.test.js +290 -0
  583. package/dist/commands/role.test.js.map +1 -0
  584. package/dist/commands/scoreboard.d.ts +26 -0
  585. package/dist/commands/scoreboard.d.ts.map +1 -0
  586. package/dist/commands/scoreboard.js +40 -0
  587. package/dist/commands/scoreboard.js.map +1 -0
  588. package/dist/commands/search.d.ts +3 -0
  589. package/dist/commands/search.d.ts.map +1 -1
  590. package/dist/commands/search.js +7 -1
  591. package/dist/commands/search.js.map +1 -1
  592. package/dist/commands/session.d.ts +60 -7
  593. package/dist/commands/session.d.ts.map +1 -1
  594. package/dist/commands/session.js +409 -98
  595. package/dist/commands/session.js.map +1 -1
  596. package/dist/commands/status.d.ts +7 -0
  597. package/dist/commands/status.d.ts.map +1 -0
  598. package/dist/commands/status.js +102 -0
  599. package/dist/commands/status.js.map +1 -0
  600. package/dist/commands/status.test.d.ts +2 -0
  601. package/dist/commands/status.test.d.ts.map +1 -0
  602. package/dist/commands/status.test.js +75 -0
  603. package/dist/commands/status.test.js.map +1 -0
  604. package/dist/commands/stillTrue.d.ts +14 -0
  605. package/dist/commands/stillTrue.d.ts.map +1 -0
  606. package/dist/commands/stillTrue.js +48 -0
  607. package/dist/commands/stillTrue.js.map +1 -0
  608. package/dist/commands/tensionsList.d.ts +5 -0
  609. package/dist/commands/tensionsList.d.ts.map +1 -0
  610. package/dist/commands/tensionsList.js +27 -0
  611. package/dist/commands/tensionsList.js.map +1 -0
  612. package/dist/commands/update.d.ts +21 -0
  613. package/dist/commands/update.d.ts.map +1 -1
  614. package/dist/commands/update.js +155 -41
  615. package/dist/commands/update.js.map +1 -1
  616. package/dist/commands/usage.d.ts.map +1 -1
  617. package/dist/commands/usage.js +0 -18
  618. package/dist/commands/usage.js.map +1 -1
  619. package/dist/commands/verify.d.ts.map +1 -1
  620. package/dist/commands/verify.js +5 -0
  621. package/dist/commands/verify.js.map +1 -1
  622. package/dist/commands/welcome.d.ts.map +1 -1
  623. package/dist/commands/welcome.js +5 -2
  624. package/dist/commands/welcome.js.map +1 -1
  625. package/dist/commands/whoami.d.ts +10 -2
  626. package/dist/commands/whoami.d.ts.map +1 -1
  627. package/dist/commands/whoami.js +76 -20
  628. package/dist/commands/whoami.js.map +1 -1
  629. package/dist/commands/whoami.test.js +86 -6
  630. package/dist/commands/whoami.test.js.map +1 -1
  631. package/dist/commands/workspace.d.ts +7 -74
  632. package/dist/commands/workspace.d.ts.map +1 -1
  633. package/dist/commands/workspace.js +9 -70
  634. package/dist/commands/workspace.js.map +1 -1
  635. package/dist/formatters/__tests__/orient-plannedWorkCut.test.d.ts +2 -0
  636. package/dist/formatters/__tests__/orient-plannedWorkCut.test.d.ts.map +1 -0
  637. package/dist/formatters/__tests__/orient-plannedWorkCut.test.js +49 -0
  638. package/dist/formatters/__tests__/orient-plannedWorkCut.test.js.map +1 -0
  639. package/dist/formatters/__tests__/orient-provenance.test.d.ts +2 -3
  640. package/dist/formatters/__tests__/orient-provenance.test.d.ts.map +1 -1
  641. package/dist/formatters/__tests__/orient-provenance.test.js +39 -174
  642. package/dist/formatters/__tests__/orient-provenance.test.js.map +1 -1
  643. package/dist/formatters/__tests__/orient-ruleLists.test.d.ts +2 -0
  644. package/dist/formatters/__tests__/orient-ruleLists.test.d.ts.map +1 -0
  645. package/dist/formatters/__tests__/orient-ruleLists.test.js +93 -0
  646. package/dist/formatters/__tests__/orient-ruleLists.test.js.map +1 -0
  647. package/dist/formatters/__tests__/session-list-show.test.d.ts +2 -0
  648. package/dist/formatters/__tests__/session-list-show.test.d.ts.map +1 -0
  649. package/dist/formatters/__tests__/session-list-show.test.js +195 -0
  650. package/dist/formatters/__tests__/session-list-show.test.js.map +1 -0
  651. package/dist/formatters/__tests__/session.test.d.ts +2 -0
  652. package/dist/formatters/__tests__/session.test.d.ts.map +1 -0
  653. package/dist/formatters/__tests__/session.test.js +214 -0
  654. package/dist/formatters/__tests__/session.test.js.map +1 -0
  655. package/dist/formatters/__tests__/tensionsList.test.d.ts +2 -0
  656. package/dist/formatters/__tests__/tensionsList.test.d.ts.map +1 -0
  657. package/dist/formatters/__tests__/tensionsList.test.js +30 -0
  658. package/dist/formatters/__tests__/tensionsList.test.js.map +1 -0
  659. package/dist/formatters/brief.d.ts +6 -15
  660. package/dist/formatters/brief.d.ts.map +1 -1
  661. package/dist/formatters/brief.js +16 -14
  662. package/dist/formatters/brief.js.map +1 -1
  663. package/dist/formatters/brief.test.d.ts +2 -0
  664. package/dist/formatters/brief.test.d.ts.map +1 -0
  665. package/dist/formatters/brief.test.js +21 -0
  666. package/dist/formatters/brief.test.js.map +1 -0
  667. package/dist/formatters/capture.d.ts +17 -10
  668. package/dist/formatters/capture.d.ts.map +1 -1
  669. package/dist/formatters/capture.js +33 -10
  670. package/dist/formatters/capture.js.map +1 -1
  671. package/dist/formatters/coaching.d.ts +53 -0
  672. package/dist/formatters/coaching.d.ts.map +1 -0
  673. package/dist/formatters/coaching.js +51 -0
  674. package/dist/formatters/coaching.js.map +1 -0
  675. package/dist/formatters/collections.d.ts +0 -1
  676. package/dist/formatters/collections.d.ts.map +1 -1
  677. package/dist/formatters/collections.js +14 -5
  678. package/dist/formatters/collections.js.map +1 -1
  679. package/dist/formatters/conflicts.d.ts +69 -0
  680. package/dist/formatters/conflicts.d.ts.map +1 -0
  681. package/dist/formatters/conflicts.js +87 -0
  682. package/dist/formatters/conflicts.js.map +1 -0
  683. package/dist/formatters/conflicts.test.d.ts +2 -0
  684. package/dist/formatters/conflicts.test.d.ts.map +1 -0
  685. package/dist/formatters/conflicts.test.js +136 -0
  686. package/dist/formatters/conflicts.test.js.map +1 -0
  687. package/dist/formatters/context.d.ts +1 -1
  688. package/dist/formatters/context.d.ts.map +1 -1
  689. package/dist/formatters/context.js.map +1 -1
  690. package/dist/formatters/digest.d.ts +13 -0
  691. package/dist/formatters/digest.d.ts.map +1 -0
  692. package/dist/formatters/digest.js +98 -0
  693. package/dist/formatters/digest.js.map +1 -0
  694. package/dist/formatters/digest.test.d.ts +2 -0
  695. package/dist/formatters/digest.test.d.ts.map +1 -0
  696. package/dist/formatters/digest.test.js +166 -0
  697. package/dist/formatters/digest.test.js.map +1 -0
  698. package/dist/formatters/direction.d.ts +48 -0
  699. package/dist/formatters/direction.d.ts.map +1 -0
  700. package/dist/formatters/direction.js +75 -0
  701. package/dist/formatters/direction.js.map +1 -0
  702. package/dist/formatters/direction.test.d.ts +2 -0
  703. package/dist/formatters/direction.test.d.ts.map +1 -0
  704. package/dist/formatters/direction.test.js +70 -0
  705. package/dist/formatters/direction.test.js.map +1 -0
  706. package/dist/formatters/entry.d.ts +46 -3
  707. package/dist/formatters/entry.d.ts.map +1 -1
  708. package/dist/formatters/entry.js +57 -7
  709. package/dist/formatters/entry.js.map +1 -1
  710. package/dist/formatters/entryAccept.d.ts +79 -0
  711. package/dist/formatters/entryAccept.d.ts.map +1 -0
  712. package/dist/formatters/entryAccept.js +78 -0
  713. package/dist/formatters/entryAccept.js.map +1 -0
  714. package/dist/formatters/feedback.d.ts +58 -0
  715. package/dist/formatters/feedback.d.ts.map +1 -0
  716. package/dist/formatters/feedback.js +91 -0
  717. package/dist/formatters/feedback.js.map +1 -0
  718. package/dist/formatters/feedback.test.d.ts +2 -0
  719. package/dist/formatters/feedback.test.d.ts.map +1 -0
  720. package/dist/formatters/feedback.test.js +123 -0
  721. package/dist/formatters/feedback.test.js.map +1 -0
  722. package/dist/formatters/fields.d.ts +7 -1
  723. package/dist/formatters/fields.d.ts.map +1 -1
  724. package/dist/formatters/fields.js +9 -3
  725. package/dist/formatters/fields.js.map +1 -1
  726. package/dist/formatters/fields.test.d.ts +2 -0
  727. package/dist/formatters/fields.test.d.ts.map +1 -0
  728. package/dist/formatters/fields.test.js +42 -0
  729. package/dist/formatters/fields.test.js.map +1 -0
  730. package/dist/formatters/handshake.d.ts +24 -6
  731. package/dist/formatters/handshake.d.ts.map +1 -1
  732. package/dist/formatters/handshake.js +34 -15
  733. package/dist/formatters/handshake.js.map +1 -1
  734. package/dist/formatters/orient.coherencyCheckTag.test.d.ts +2 -0
  735. package/dist/formatters/orient.coherencyCheckTag.test.d.ts.map +1 -0
  736. package/dist/formatters/orient.coherencyCheckTag.test.js +22 -0
  737. package/dist/formatters/orient.coherencyCheckTag.test.js.map +1 -0
  738. package/dist/formatters/orient.d.ts +94 -145
  739. package/dist/formatters/orient.d.ts.map +1 -1
  740. package/dist/formatters/orient.js +144 -183
  741. package/dist/formatters/orient.js.map +1 -1
  742. package/dist/formatters/orient.rcrtMiss.test.d.ts +2 -0
  743. package/dist/formatters/orient.rcrtMiss.test.d.ts.map +1 -0
  744. package/dist/formatters/orient.rcrtMiss.test.js +77 -0
  745. package/dist/formatters/orient.rcrtMiss.test.js.map +1 -0
  746. package/dist/formatters/orient.rituals.test.d.ts +2 -0
  747. package/dist/formatters/orient.rituals.test.d.ts.map +1 -0
  748. package/dist/formatters/orient.rituals.test.js +73 -0
  749. package/dist/formatters/orient.rituals.test.js.map +1 -0
  750. package/dist/formatters/orientDegradation.d.ts +38 -0
  751. package/dist/formatters/orientDegradation.d.ts.map +1 -0
  752. package/dist/formatters/orientDegradation.js +50 -0
  753. package/dist/formatters/orientDegradation.js.map +1 -0
  754. package/dist/formatters/orientDegradation.test.d.ts +2 -0
  755. package/dist/formatters/orientDegradation.test.d.ts.map +1 -0
  756. package/dist/formatters/orientDegradation.test.js +28 -0
  757. package/dist/formatters/orientDegradation.test.js.map +1 -0
  758. package/dist/formatters/orientDirection.d.ts +25 -0
  759. package/dist/formatters/orientDirection.d.ts.map +1 -0
  760. package/dist/formatters/orientDirection.js +7 -0
  761. package/dist/formatters/orientDirection.js.map +1 -0
  762. package/dist/formatters/orientDirection.test.d.ts +2 -0
  763. package/dist/formatters/orientDirection.test.d.ts.map +1 -0
  764. package/dist/formatters/orientDirection.test.js +48 -0
  765. package/dist/formatters/orientDirection.test.js.map +1 -0
  766. package/dist/formatters/orientRetrievalMiss.d.ts +22 -0
  767. package/dist/formatters/orientRetrievalMiss.d.ts.map +1 -0
  768. package/dist/formatters/orientRetrievalMiss.js +17 -0
  769. package/dist/formatters/orientRetrievalMiss.js.map +1 -0
  770. package/dist/formatters/plannedWorkCounts.d.ts +19 -0
  771. package/dist/formatters/plannedWorkCounts.d.ts.map +1 -0
  772. package/dist/formatters/plannedWorkCounts.js +17 -0
  773. package/dist/formatters/plannedWorkCounts.js.map +1 -0
  774. package/dist/formatters/questions.d.ts +72 -0
  775. package/dist/formatters/questions.d.ts.map +1 -0
  776. package/dist/formatters/questions.js +116 -0
  777. package/dist/formatters/questions.js.map +1 -0
  778. package/dist/formatters/questions.test.d.ts +2 -0
  779. package/dist/formatters/questions.test.d.ts.map +1 -0
  780. package/dist/formatters/questions.test.js +144 -0
  781. package/dist/formatters/questions.test.js.map +1 -0
  782. package/dist/formatters/relate.d.ts +13 -2
  783. package/dist/formatters/relate.d.ts.map +1 -1
  784. package/dist/formatters/relate.js +15 -5
  785. package/dist/formatters/relate.js.map +1 -1
  786. package/dist/formatters/relate.test.d.ts +2 -0
  787. package/dist/formatters/relate.test.d.ts.map +1 -0
  788. package/dist/formatters/relate.test.js +91 -0
  789. package/dist/formatters/relate.test.js.map +1 -0
  790. package/dist/formatters/scoreboard.d.ts +11 -0
  791. package/dist/formatters/scoreboard.d.ts.map +1 -0
  792. package/dist/formatters/scoreboard.js +162 -0
  793. package/dist/formatters/scoreboard.js.map +1 -0
  794. package/dist/formatters/scoreboard.test.d.ts +2 -0
  795. package/dist/formatters/scoreboard.test.d.ts.map +1 -0
  796. package/dist/formatters/scoreboard.test.js +301 -0
  797. package/dist/formatters/scoreboard.test.js.map +1 -0
  798. package/dist/formatters/search.d.ts +3 -0
  799. package/dist/formatters/search.d.ts.map +1 -1
  800. package/dist/formatters/search.js +15 -1
  801. package/dist/formatters/search.js.map +1 -1
  802. package/dist/formatters/search.test.d.ts +2 -0
  803. package/dist/formatters/search.test.d.ts.map +1 -0
  804. package/dist/formatters/search.test.js +76 -0
  805. package/dist/formatters/search.test.js.map +1 -0
  806. package/dist/formatters/session-feedback.test.d.ts +2 -0
  807. package/dist/formatters/session-feedback.test.d.ts.map +1 -0
  808. package/dist/formatters/session-feedback.test.js +146 -0
  809. package/dist/formatters/session-feedback.test.js.map +1 -0
  810. package/dist/formatters/session.d.ts +126 -5
  811. package/dist/formatters/session.d.ts.map +1 -1
  812. package/dist/formatters/session.js +321 -21
  813. package/dist/formatters/session.js.map +1 -1
  814. package/dist/formatters/spineCheck.d.ts +14 -0
  815. package/dist/formatters/spineCheck.d.ts.map +1 -0
  816. package/dist/formatters/spineCheck.js +113 -0
  817. package/dist/formatters/spineCheck.js.map +1 -0
  818. package/dist/formatters/spineCheck.test.d.ts +2 -0
  819. package/dist/formatters/spineCheck.test.d.ts.map +1 -0
  820. package/dist/formatters/spineCheck.test.js +76 -0
  821. package/dist/formatters/spineCheck.test.js.map +1 -0
  822. package/dist/formatters/tensionsList.d.ts +17 -0
  823. package/dist/formatters/tensionsList.d.ts.map +1 -0
  824. package/dist/formatters/tensionsList.js +33 -0
  825. package/dist/formatters/tensionsList.js.map +1 -0
  826. package/dist/formatters/update.d.ts +22 -0
  827. package/dist/formatters/update.d.ts.map +1 -1
  828. package/dist/formatters/update.js +36 -7
  829. package/dist/formatters/update.js.map +1 -1
  830. package/dist/formatters/update.test.d.ts +2 -0
  831. package/dist/formatters/update.test.d.ts.map +1 -0
  832. package/dist/formatters/update.test.js +59 -0
  833. package/dist/formatters/update.test.js.map +1 -0
  834. package/dist/formatters/verify.d.ts +12 -4
  835. package/dist/formatters/verify.d.ts.map +1 -1
  836. package/dist/formatters/verify.js +20 -2
  837. package/dist/formatters/verify.js.map +1 -1
  838. package/dist/generated/healthGapKinds.generated.d.ts +12 -0
  839. package/dist/generated/healthGapKinds.generated.d.ts.map +1 -0
  840. package/dist/generated/healthGapKinds.generated.js +16 -0
  841. package/dist/generated/healthGapKinds.generated.js.map +1 -0
  842. package/dist/generated/organisationalAuthorityRefusalCodes.generated.d.ts +12 -0
  843. package/dist/generated/organisationalAuthorityRefusalCodes.generated.d.ts.map +1 -0
  844. package/dist/generated/organisationalAuthorityRefusalCodes.generated.js +11 -0
  845. package/dist/generated/organisationalAuthorityRefusalCodes.generated.js.map +1 -0
  846. package/dist/generated/relationTypes.generated.d.ts +12 -0
  847. package/dist/generated/relationTypes.generated.d.ts.map +1 -0
  848. package/dist/generated/relationTypes.generated.js +11 -0
  849. package/dist/generated/relationTypes.generated.js.map +1 -0
  850. package/dist/generated/routeLatencyBudget.generated.d.ts +56 -0
  851. package/dist/generated/routeLatencyBudget.generated.d.ts.map +1 -0
  852. package/dist/generated/routeLatencyBudget.generated.js +275 -0
  853. package/dist/generated/routeLatencyBudget.generated.js.map +1 -0
  854. package/dist/generated/sourceSurfaces.generated.d.ts +12 -0
  855. package/dist/generated/sourceSurfaces.generated.d.ts.map +1 -0
  856. package/dist/generated/sourceSurfaces.generated.js +11 -0
  857. package/dist/generated/sourceSurfaces.generated.js.map +1 -0
  858. package/dist/generators/adapters.d.ts +39 -6
  859. package/dist/generators/adapters.d.ts.map +1 -1
  860. package/dist/generators/adapters.js +88 -89
  861. package/dist/generators/adapters.js.map +1 -1
  862. package/dist/generators/adapters.test.js +14 -6
  863. package/dist/generators/adapters.test.js.map +1 -1
  864. package/dist/generators/boundary-manifest.real-file.test.d.ts +2 -0
  865. package/dist/generators/boundary-manifest.real-file.test.d.ts.map +1 -0
  866. package/dist/generators/boundary-manifest.real-file.test.js +70 -0
  867. package/dist/generators/boundary-manifest.real-file.test.js.map +1 -0
  868. package/dist/generators/briefing-projections.test.d.ts +2 -0
  869. package/dist/generators/briefing-projections.test.d.ts.map +1 -0
  870. package/dist/generators/briefing-projections.test.js +98 -0
  871. package/dist/generators/briefing-projections.test.js.map +1 -0
  872. package/dist/generators/context-md.d.ts +7 -2
  873. package/dist/generators/context-md.d.ts.map +1 -1
  874. package/dist/generators/context-md.js +14 -53
  875. package/dist/generators/context-md.js.map +1 -1
  876. package/dist/generators/everyone-rules-md.d.ts +9 -0
  877. package/dist/generators/everyone-rules-md.d.ts.map +1 -0
  878. package/dist/generators/everyone-rules-md.js +21 -0
  879. package/dist/generators/everyone-rules-md.js.map +1 -0
  880. package/dist/generators/noProjectionAssets.d.ts +15 -0
  881. package/dist/generators/noProjectionAssets.d.ts.map +1 -0
  882. package/dist/generators/noProjectionAssets.js +6 -0
  883. package/dist/generators/noProjectionAssets.js.map +1 -0
  884. package/dist/generators/portable-knowledge.d.ts +9 -26
  885. package/dist/generators/portable-knowledge.d.ts.map +1 -1
  886. package/dist/generators/portable-knowledge.js +11 -125
  887. package/dist/generators/portable-knowledge.js.map +1 -1
  888. package/dist/generators/portable-knowledge.test.js +82 -267
  889. package/dist/generators/portable-knowledge.test.js.map +1 -1
  890. package/dist/generators/region-projections.d.ts +0 -1
  891. package/dist/generators/region-projections.d.ts.map +1 -1
  892. package/dist/generators/region-projections.js +7 -5
  893. package/dist/generators/region-projections.js.map +1 -1
  894. package/dist/generators/region-projections.test.js +10 -15
  895. package/dist/generators/region-projections.test.js.map +1 -1
  896. package/dist/generators/retired-projections.d.ts +12 -0
  897. package/dist/generators/retired-projections.d.ts.map +1 -0
  898. package/dist/generators/retired-projections.js +75 -0
  899. package/dist/generators/retired-projections.js.map +1 -0
  900. package/dist/generators/retired-projections.test.d.ts +2 -0
  901. package/dist/generators/retired-projections.test.d.ts.map +1 -0
  902. package/dist/generators/retired-projections.test.js +64 -0
  903. package/dist/generators/retired-projections.test.js.map +1 -0
  904. package/dist/handleCliError.d.ts +2 -0
  905. package/dist/handleCliError.d.ts.map +1 -0
  906. package/dist/handleCliError.js +56 -0
  907. package/dist/handleCliError.js.map +1 -0
  908. package/dist/index.d.ts +0 -5
  909. package/dist/index.d.ts.map +1 -1
  910. package/dist/index.js +183 -541
  911. package/dist/index.js.map +1 -1
  912. package/dist/lib/__tests__/legalRelationTypes.test.d.ts +2 -0
  913. package/dist/lib/__tests__/legalRelationTypes.test.d.ts.map +1 -0
  914. package/dist/lib/__tests__/legalRelationTypes.test.js +61 -0
  915. package/dist/lib/__tests__/legalRelationTypes.test.js.map +1 -0
  916. package/dist/lib/__tests__/parseFields.test.d.ts +2 -0
  917. package/dist/lib/__tests__/parseFields.test.d.ts.map +1 -0
  918. package/dist/lib/__tests__/parseFields.test.js +40 -0
  919. package/dist/lib/__tests__/parseFields.test.js.map +1 -0
  920. package/dist/lib/adminConfig.d.ts +48 -0
  921. package/dist/lib/adminConfig.d.ts.map +1 -0
  922. package/dist/lib/adminConfig.js +130 -0
  923. package/dist/lib/adminConfig.js.map +1 -0
  924. package/dist/lib/canonicalRefs.d.ts +27 -8
  925. package/dist/lib/canonicalRefs.d.ts.map +1 -1
  926. package/dist/lib/canonicalRefs.js +25 -6
  927. package/dist/lib/canonicalRefs.js.map +1 -1
  928. package/dist/lib/captureGrounding.d.ts +48 -0
  929. package/dist/lib/captureGrounding.d.ts.map +1 -0
  930. package/dist/lib/captureGrounding.js +54 -0
  931. package/dist/lib/captureGrounding.js.map +1 -0
  932. package/dist/lib/captureGrounding.test.d.ts +2 -0
  933. package/dist/lib/captureGrounding.test.d.ts.map +1 -0
  934. package/dist/lib/captureGrounding.test.js +74 -0
  935. package/dist/lib/captureGrounding.test.js.map +1 -0
  936. package/dist/lib/captureLink.d.ts +26 -0
  937. package/dist/lib/captureLink.d.ts.map +1 -0
  938. package/dist/lib/captureLink.js +110 -0
  939. package/dist/lib/captureLink.js.map +1 -0
  940. package/dist/lib/checklist.d.ts +32 -0
  941. package/dist/lib/checklist.d.ts.map +1 -0
  942. package/dist/lib/checklist.js +77 -0
  943. package/dist/lib/checklist.js.map +1 -0
  944. package/dist/lib/client.d.ts +32 -19
  945. package/dist/lib/client.d.ts.map +1 -1
  946. package/dist/lib/client.js +211 -66
  947. package/dist/lib/client.js.map +1 -1
  948. package/dist/lib/collectionRegistry.d.ts +40 -5
  949. package/dist/lib/collectionRegistry.d.ts.map +1 -1
  950. package/dist/lib/collectionRegistry.js +71 -48
  951. package/dist/lib/collectionRegistry.js.map +1 -1
  952. package/dist/lib/commanderOptions.d.ts +8 -0
  953. package/dist/lib/commanderOptions.d.ts.map +1 -0
  954. package/dist/lib/commanderOptions.js +10 -0
  955. package/dist/lib/commanderOptions.js.map +1 -0
  956. package/dist/lib/compose-wrapup-view.d.ts +56 -0
  957. package/dist/lib/compose-wrapup-view.d.ts.map +1 -0
  958. package/dist/lib/compose-wrapup-view.js +39 -0
  959. package/dist/lib/compose-wrapup-view.js.map +1 -0
  960. package/dist/lib/config.d.ts +65 -102
  961. package/dist/lib/config.d.ts.map +1 -1
  962. package/dist/lib/config.js +164 -286
  963. package/dist/lib/config.js.map +1 -1
  964. package/dist/lib/configResult.d.ts +102 -0
  965. package/dist/lib/configResult.d.ts.map +1 -0
  966. package/dist/lib/configResult.js +179 -0
  967. package/dist/lib/configResult.js.map +1 -0
  968. package/dist/lib/connectProfileName.d.ts +36 -0
  969. package/dist/lib/connectProfileName.d.ts.map +1 -0
  970. package/dist/lib/connectProfileName.js +72 -0
  971. package/dist/lib/connectProfileName.js.map +1 -0
  972. package/dist/lib/connectProfileName.test.d.ts +2 -0
  973. package/dist/lib/connectProfileName.test.d.ts.map +1 -0
  974. package/dist/lib/connectProfileName.test.js +100 -0
  975. package/dist/lib/connectProfileName.test.js.map +1 -0
  976. package/dist/lib/constants.d.ts +3 -1
  977. package/dist/lib/constants.d.ts.map +1 -1
  978. package/dist/lib/constants.js +6 -1
  979. package/dist/lib/constants.js.map +1 -1
  980. package/dist/lib/conversation.d.ts +36 -0
  981. package/dist/lib/conversation.d.ts.map +1 -0
  982. package/dist/lib/conversation.js +66 -0
  983. package/dist/lib/conversation.js.map +1 -0
  984. package/dist/lib/createEntryResult.d.ts +34 -0
  985. package/dist/lib/createEntryResult.d.ts.map +1 -0
  986. package/dist/lib/createEntryResult.js +12 -0
  987. package/dist/lib/createEntryResult.js.map +1 -0
  988. package/dist/lib/deployment.js +2 -2
  989. package/dist/lib/deployment.js.map +1 -1
  990. package/dist/lib/deployment.test.js +20 -1
  991. package/dist/lib/deployment.test.js.map +1 -1
  992. package/dist/lib/envKeySnapshot.d.ts +10 -0
  993. package/dist/lib/envKeySnapshot.d.ts.map +1 -0
  994. package/dist/lib/envKeySnapshot.js +30 -0
  995. package/dist/lib/envKeySnapshot.js.map +1 -0
  996. package/dist/lib/errors.d.ts +90 -0
  997. package/dist/lib/errors.d.ts.map +1 -1
  998. package/dist/lib/errors.js +83 -0
  999. package/dist/lib/errors.js.map +1 -1
  1000. package/dist/lib/frontmatter.d.ts +55 -0
  1001. package/dist/lib/frontmatter.d.ts.map +1 -0
  1002. package/dist/lib/frontmatter.js +92 -0
  1003. package/dist/lib/frontmatter.js.map +1 -0
  1004. package/dist/lib/frontmatter.test.d.ts +15 -0
  1005. package/dist/lib/frontmatter.test.d.ts.map +1 -0
  1006. package/dist/lib/frontmatter.test.js +98 -0
  1007. package/dist/lib/frontmatter.test.js.map +1 -0
  1008. package/dist/lib/gatewayTimeout.d.ts +88 -0
  1009. package/dist/lib/gatewayTimeout.d.ts.map +1 -0
  1010. package/dist/lib/gatewayTimeout.js +118 -0
  1011. package/dist/lib/gatewayTimeout.js.map +1 -0
  1012. package/dist/lib/gitEnvLeakKeysParity.test.d.ts +2 -0
  1013. package/dist/lib/gitEnvLeakKeysParity.test.d.ts.map +1 -0
  1014. package/dist/lib/gitEnvLeakKeysParity.test.js +73 -0
  1015. package/dist/lib/gitEnvLeakKeysParity.test.js.map +1 -0
  1016. package/dist/lib/glossary.js +1 -1
  1017. package/dist/lib/glossary.js.map +1 -1
  1018. package/dist/lib/hook-intents.js +3 -3
  1019. package/dist/lib/hook-intents.js.map +1 -1
  1020. package/dist/lib/judgeWait.d.ts +50 -0
  1021. package/dist/lib/judgeWait.d.ts.map +1 -0
  1022. package/dist/lib/judgeWait.js +64 -0
  1023. package/dist/lib/judgeWait.js.map +1 -0
  1024. package/dist/lib/kernelEnvelope.d.ts +42 -0
  1025. package/dist/lib/kernelEnvelope.d.ts.map +1 -0
  1026. package/dist/lib/kernelEnvelope.js +67 -0
  1027. package/dist/lib/kernelEnvelope.js.map +1 -0
  1028. package/dist/lib/legalRelationTypes.d.ts +19 -0
  1029. package/dist/lib/legalRelationTypes.d.ts.map +1 -0
  1030. package/dist/lib/legalRelationTypes.js +64 -0
  1031. package/dist/lib/legalRelationTypes.js.map +1 -0
  1032. package/dist/lib/localBinding.d.ts +86 -0
  1033. package/dist/lib/localBinding.d.ts.map +1 -0
  1034. package/dist/lib/localBinding.js +173 -0
  1035. package/dist/lib/localBinding.js.map +1 -0
  1036. package/dist/lib/method-registry.d.ts +16 -11
  1037. package/dist/lib/method-registry.d.ts.map +1 -1
  1038. package/dist/lib/method-registry.js +13 -25
  1039. package/dist/lib/method-registry.js.map +1 -1
  1040. package/dist/lib/normalizeMaterializedFilename.d.ts +3 -3
  1041. package/dist/lib/normalizeMaterializedFilename.js +3 -3
  1042. package/dist/lib/notice-marker.d.ts.map +1 -1
  1043. package/dist/lib/notice-marker.js +186 -16
  1044. package/dist/lib/notice-marker.js.map +1 -1
  1045. package/dist/lib/onboarding-path-b.d.ts.map +1 -1
  1046. package/dist/lib/onboarding-path-b.js +39 -14
  1047. package/dist/lib/onboarding-path-b.js.map +1 -1
  1048. package/dist/lib/onboarding-shared.d.ts +27 -4
  1049. package/dist/lib/onboarding-shared.d.ts.map +1 -1
  1050. package/dist/lib/onboarding-shared.js +54 -20
  1051. package/dist/lib/onboarding-shared.js.map +1 -1
  1052. package/dist/lib/onboarding-shared.test.d.ts +2 -0
  1053. package/dist/lib/onboarding-shared.test.d.ts.map +1 -0
  1054. package/dist/lib/onboarding-shared.test.js +131 -0
  1055. package/dist/lib/onboarding-shared.test.js.map +1 -0
  1056. package/dist/lib/onboarding-topics.js +1 -1
  1057. package/dist/lib/onboarding.d.ts +5 -1
  1058. package/dist/lib/onboarding.d.ts.map +1 -1
  1059. package/dist/lib/onboarding.js +62 -25
  1060. package/dist/lib/onboarding.js.map +1 -1
  1061. package/dist/lib/ownerLine.d.ts +73 -0
  1062. package/dist/lib/ownerLine.d.ts.map +1 -0
  1063. package/dist/lib/ownerLine.js +57 -0
  1064. package/dist/lib/ownerLine.js.map +1 -0
  1065. package/dist/lib/parseFields.d.ts +19 -0
  1066. package/dist/lib/parseFields.d.ts.map +1 -0
  1067. package/dist/lib/parseFields.js +49 -0
  1068. package/dist/lib/parseFields.js.map +1 -0
  1069. package/dist/lib/pinnedRole.d.ts +28 -0
  1070. package/dist/lib/pinnedRole.d.ts.map +1 -0
  1071. package/dist/lib/pinnedRole.js +105 -0
  1072. package/dist/lib/pinnedRole.js.map +1 -0
  1073. package/dist/lib/platformGlossary.d.ts +19 -0
  1074. package/dist/lib/platformGlossary.d.ts.map +1 -0
  1075. package/dist/lib/platformGlossary.js +21 -0
  1076. package/dist/lib/platformGlossary.js.map +1 -0
  1077. package/dist/lib/previewBanner.d.ts +9 -0
  1078. package/dist/lib/previewBanner.d.ts.map +1 -0
  1079. package/dist/lib/previewBanner.js +37 -0
  1080. package/dist/lib/previewBanner.js.map +1 -0
  1081. package/dist/lib/productbrain-files.d.ts +108 -0
  1082. package/dist/lib/productbrain-files.d.ts.map +1 -0
  1083. package/dist/lib/productbrain-files.js +240 -0
  1084. package/dist/lib/productbrain-files.js.map +1 -0
  1085. package/dist/lib/productbrain-files.test.d.ts +2 -0
  1086. package/dist/lib/productbrain-files.test.d.ts.map +1 -0
  1087. package/dist/lib/productbrain-files.test.js +518 -0
  1088. package/dist/lib/productbrain-files.test.js.map +1 -0
  1089. package/dist/lib/profiles.d.ts +52 -4
  1090. package/dist/lib/profiles.d.ts.map +1 -1
  1091. package/dist/lib/profiles.js +72 -21
  1092. package/dist/lib/profiles.js.map +1 -1
  1093. package/dist/lib/projectConfig.d.ts +96 -0
  1094. package/dist/lib/projectConfig.d.ts.map +1 -0
  1095. package/dist/lib/projectConfig.js +185 -0
  1096. package/dist/lib/projectConfig.js.map +1 -0
  1097. package/dist/lib/prompts.d.ts +2 -0
  1098. package/dist/lib/prompts.d.ts.map +1 -1
  1099. package/dist/lib/prompts.js +2 -0
  1100. package/dist/lib/prompts.js.map +1 -1
  1101. package/dist/lib/proseBody.d.ts +14 -0
  1102. package/dist/lib/proseBody.d.ts.map +1 -0
  1103. package/dist/lib/proseBody.js +25 -0
  1104. package/dist/lib/proseBody.js.map +1 -0
  1105. package/dist/lib/rate-limit.d.ts +38 -0
  1106. package/dist/lib/rate-limit.d.ts.map +1 -0
  1107. package/dist/lib/rate-limit.js +83 -0
  1108. package/dist/lib/rate-limit.js.map +1 -0
  1109. package/dist/lib/readinessNotices.d.ts +12 -0
  1110. package/dist/lib/readinessNotices.d.ts.map +1 -0
  1111. package/dist/lib/readinessNotices.js +15 -0
  1112. package/dist/lib/readinessNotices.js.map +1 -0
  1113. package/dist/lib/repo-detect.d.ts +8 -2
  1114. package/dist/lib/repo-detect.d.ts.map +1 -1
  1115. package/dist/lib/repo-detect.js +11 -6
  1116. package/dist/lib/repo-detect.js.map +1 -1
  1117. package/dist/lib/reportedProfile.d.ts +18 -0
  1118. package/dist/lib/reportedProfile.d.ts.map +1 -0
  1119. package/dist/lib/reportedProfile.js +144 -0
  1120. package/dist/lib/reportedProfile.js.map +1 -0
  1121. package/dist/lib/ruleListRender.d.ts +193 -0
  1122. package/dist/lib/ruleListRender.d.ts.map +1 -0
  1123. package/dist/lib/ruleListRender.js +274 -0
  1124. package/dist/lib/ruleListRender.js.map +1 -0
  1125. package/dist/lib/runner.d.ts +9 -1
  1126. package/dist/lib/runner.d.ts.map +1 -1
  1127. package/dist/lib/runner.js +30 -4
  1128. package/dist/lib/runner.js.map +1 -1
  1129. package/dist/lib/seatSentence.d.ts +42 -0
  1130. package/dist/lib/seatSentence.d.ts.map +1 -0
  1131. package/dist/lib/seatSentence.js +25 -0
  1132. package/dist/lib/seatSentence.js.map +1 -0
  1133. package/dist/lib/session.d.ts +86 -12
  1134. package/dist/lib/session.d.ts.map +1 -1
  1135. package/dist/lib/session.js +255 -25
  1136. package/dist/lib/session.js.map +1 -1
  1137. package/dist/lib/sessionBinding.d.ts +61 -0
  1138. package/dist/lib/sessionBinding.d.ts.map +1 -0
  1139. package/dist/lib/sessionBinding.js +125 -0
  1140. package/dist/lib/sessionBinding.js.map +1 -0
  1141. package/dist/lib/sessionNotices.d.ts +54 -0
  1142. package/dist/lib/sessionNotices.d.ts.map +1 -0
  1143. package/dist/lib/sessionNotices.js +130 -0
  1144. package/dist/lib/sessionNotices.js.map +1 -0
  1145. package/dist/lib/sessionNotices.test.d.ts +2 -0
  1146. package/dist/lib/sessionNotices.test.d.ts.map +1 -0
  1147. package/dist/lib/sessionNotices.test.js +55 -0
  1148. package/dist/lib/sessionNotices.test.js.map +1 -0
  1149. package/dist/lib/spineVerdictRead.d.ts +70 -0
  1150. package/dist/lib/spineVerdictRead.d.ts.map +1 -0
  1151. package/dist/lib/spineVerdictRead.js +73 -0
  1152. package/dist/lib/spineVerdictRead.js.map +1 -0
  1153. package/dist/lib/spinner.js +2 -2
  1154. package/dist/lib/spinner.js.map +1 -1
  1155. package/dist/lib/startup-resolution-signals.d.ts +34 -0
  1156. package/dist/lib/startup-resolution-signals.d.ts.map +1 -0
  1157. package/dist/lib/startup-resolution-signals.js +116 -0
  1158. package/dist/lib/startup-resolution-signals.js.map +1 -0
  1159. package/dist/lib/startup-resolution-signals.test.d.ts +2 -0
  1160. package/dist/lib/startup-resolution-signals.test.d.ts.map +1 -0
  1161. package/dist/lib/startup-resolution-signals.test.js +113 -0
  1162. package/dist/lib/startup-resolution-signals.test.js.map +1 -0
  1163. package/dist/lib/startup-signals.d.ts +12 -0
  1164. package/dist/lib/startup-signals.d.ts.map +1 -0
  1165. package/dist/lib/startup-signals.js +179 -0
  1166. package/dist/lib/startup-signals.js.map +1 -0
  1167. package/dist/lib/startup-signals.test.d.ts +2 -0
  1168. package/dist/lib/startup-signals.test.d.ts.map +1 -0
  1169. package/dist/lib/startup-signals.test.js +165 -0
  1170. package/dist/lib/startup-signals.test.js.map +1 -0
  1171. package/dist/lib/state.d.ts +11 -2
  1172. package/dist/lib/state.d.ts.map +1 -1
  1173. package/dist/lib/state.js +11 -4
  1174. package/dist/lib/state.js.map +1 -1
  1175. package/dist/lib/statusCategories.d.ts +160 -0
  1176. package/dist/lib/statusCategories.d.ts.map +1 -0
  1177. package/dist/lib/statusCategories.js +284 -0
  1178. package/dist/lib/statusCategories.js.map +1 -0
  1179. package/dist/lib/strip.d.ts +17 -0
  1180. package/dist/lib/strip.d.ts.map +1 -1
  1181. package/dist/lib/strip.js +48 -1
  1182. package/dist/lib/strip.js.map +1 -1
  1183. package/dist/lib/style.d.ts +8 -2
  1184. package/dist/lib/style.d.ts.map +1 -1
  1185. package/dist/lib/style.js +24 -17
  1186. package/dist/lib/style.js.map +1 -1
  1187. package/dist/lib/tokenConstants.d.ts +2 -0
  1188. package/dist/lib/tokenConstants.d.ts.map +1 -1
  1189. package/dist/lib/tokenConstants.js +2 -0
  1190. package/dist/lib/tokenConstants.js.map +1 -1
  1191. package/dist/lib/workspaceNotice.d.ts +202 -0
  1192. package/dist/lib/workspaceNotice.d.ts.map +1 -0
  1193. package/dist/lib/workspaceNotice.js +345 -0
  1194. package/dist/lib/workspaceNotice.js.map +1 -0
  1195. package/dist/{setup/perimeter.d.ts → lib/writePerimeter.d.ts} +11 -11
  1196. package/dist/lib/writePerimeter.d.ts.map +1 -0
  1197. package/dist/{setup/perimeter.js → lib/writePerimeter.js} +11 -11
  1198. package/dist/lib/writePerimeter.js.map +1 -0
  1199. package/dist/registerEntryCommands.d.ts +18 -0
  1200. package/dist/registerEntryCommands.d.ts.map +1 -0
  1201. package/dist/registerEntryCommands.js +123 -0
  1202. package/dist/registerEntryCommands.js.map +1 -0
  1203. package/dist/registerHistoryCommand.d.ts +8 -0
  1204. package/dist/registerHistoryCommand.d.ts.map +1 -0
  1205. package/dist/registerHistoryCommand.js +14 -0
  1206. package/dist/registerHistoryCommand.js.map +1 -0
  1207. package/dist/registerOutcomeCommands.d.ts +27 -0
  1208. package/dist/registerOutcomeCommands.d.ts.map +1 -0
  1209. package/dist/registerOutcomeCommands.js +27 -0
  1210. package/dist/registerOutcomeCommands.js.map +1 -0
  1211. package/dist/registerRoleCommands.d.ts +11 -0
  1212. package/dist/registerRoleCommands.d.ts.map +1 -0
  1213. package/dist/registerRoleCommands.js +38 -0
  1214. package/dist/registerRoleCommands.js.map +1 -0
  1215. package/dist/registerTensionsCommands.d.ts +10 -0
  1216. package/dist/registerTensionsCommands.d.ts.map +1 -0
  1217. package/dist/registerTensionsCommands.js +15 -0
  1218. package/dist/registerTensionsCommands.js.map +1 -0
  1219. package/dist/scoreboard/diagnose.d.ts +190 -0
  1220. package/dist/scoreboard/diagnose.d.ts.map +1 -0
  1221. package/dist/scoreboard/diagnose.js +282 -0
  1222. package/dist/scoreboard/diagnose.js.map +1 -0
  1223. package/dist/scoreboard/diagnose.test.d.ts +15 -0
  1224. package/dist/scoreboard/diagnose.test.d.ts.map +1 -0
  1225. package/dist/scoreboard/diagnose.test.js +288 -0
  1226. package/dist/scoreboard/diagnose.test.js.map +1 -0
  1227. package/dist/scoreboard/floors.d.ts +47 -0
  1228. package/dist/scoreboard/floors.d.ts.map +1 -0
  1229. package/dist/scoreboard/floors.js +33 -0
  1230. package/dist/scoreboard/floors.js.map +1 -0
  1231. package/dist/scoreboard/localDrift.d.ts +23 -0
  1232. package/dist/scoreboard/localDrift.d.ts.map +1 -0
  1233. package/dist/scoreboard/localDrift.js +111 -0
  1234. package/dist/scoreboard/localDrift.js.map +1 -0
  1235. package/dist/scoreboard/localDrift.test.d.ts +9 -0
  1236. package/dist/scoreboard/localDrift.test.d.ts.map +1 -0
  1237. package/dist/scoreboard/localDrift.test.js +82 -0
  1238. package/dist/scoreboard/localDrift.test.js.map +1 -0
  1239. package/dist/surfaces/__tests__/adapter.test.js +2 -6
  1240. package/dist/surfaces/__tests__/adapter.test.js.map +1 -1
  1241. package/dist/surfaces/__tests__/claude-skill-pointer-drift.test.d.ts +2 -0
  1242. package/dist/surfaces/__tests__/claude-skill-pointer-drift.test.d.ts.map +1 -0
  1243. package/dist/surfaces/__tests__/claude-skill-pointer-drift.test.js +179 -0
  1244. package/dist/surfaces/__tests__/claude-skill-pointer-drift.test.js.map +1 -0
  1245. package/dist/surfaces/adapters/claude.d.ts.map +1 -1
  1246. package/dist/surfaces/adapters/claude.js +30 -25
  1247. package/dist/surfaces/adapters/claude.js.map +1 -1
  1248. package/package.json +9 -7
  1249. package/dist/__tests__/audit.test.d.ts +0 -2
  1250. package/dist/__tests__/audit.test.d.ts.map +0 -1
  1251. package/dist/__tests__/audit.test.js +0 -399
  1252. package/dist/__tests__/audit.test.js.map +0 -1
  1253. package/dist/__tests__/authority-domains.test.d.ts +0 -2
  1254. package/dist/__tests__/authority-domains.test.d.ts.map +0 -1
  1255. package/dist/__tests__/authority-domains.test.js +0 -48
  1256. package/dist/__tests__/authority-domains.test.js.map +0 -1
  1257. package/dist/__tests__/promote.test.d.ts +0 -2
  1258. package/dist/__tests__/promote.test.d.ts.map +0 -1
  1259. package/dist/__tests__/promote.test.js +0 -230
  1260. package/dist/__tests__/promote.test.js.map +0 -1
  1261. package/dist/__tests__/proposals.test.d.ts +0 -2
  1262. package/dist/__tests__/proposals.test.d.ts.map +0 -1
  1263. package/dist/__tests__/proposals.test.js +0 -167
  1264. package/dist/__tests__/proposals.test.js.map +0 -1
  1265. package/dist/__tests__/setup-ingest.test.d.ts +0 -2
  1266. package/dist/__tests__/setup-ingest.test.d.ts.map +0 -1
  1267. package/dist/__tests__/setup-ingest.test.js +0 -71
  1268. package/dist/__tests__/setup-ingest.test.js.map +0 -1
  1269. package/dist/__tests__/setup-resolver.test.d.ts +0 -14
  1270. package/dist/__tests__/setup-resolver.test.d.ts.map +0 -1
  1271. package/dist/__tests__/setup-resolver.test.js +0 -228
  1272. package/dist/__tests__/setup-resolver.test.js.map +0 -1
  1273. package/dist/commands/__tests__/setup-detect-surfaces.test.d.ts +0 -15
  1274. package/dist/commands/__tests__/setup-detect-surfaces.test.d.ts.map +0 -1
  1275. package/dist/commands/__tests__/setup-detect-surfaces.test.js +0 -149
  1276. package/dist/commands/__tests__/setup-detect-surfaces.test.js.map +0 -1
  1277. package/dist/commands/__tests__/setup-state.test.d.ts +0 -2
  1278. package/dist/commands/__tests__/setup-state.test.d.ts.map +0 -1
  1279. package/dist/commands/__tests__/setup-state.test.js +0 -194
  1280. package/dist/commands/__tests__/setup-state.test.js.map +0 -1
  1281. package/dist/commands/accept.d.ts +0 -18
  1282. package/dist/commands/accept.d.ts.map +0 -1
  1283. package/dist/commands/accept.js +0 -76
  1284. package/dist/commands/accept.js.map +0 -1
  1285. package/dist/commands/audit.d.ts +0 -25
  1286. package/dist/commands/audit.d.ts.map +0 -1
  1287. package/dist/commands/audit.js +0 -215
  1288. package/dist/commands/audit.js.map +0 -1
  1289. package/dist/commands/authority-domains.d.ts +0 -146
  1290. package/dist/commands/authority-domains.d.ts.map +0 -1
  1291. package/dist/commands/authority-domains.js +0 -283
  1292. package/dist/commands/authority-domains.js.map +0 -1
  1293. package/dist/commands/method.d.ts +0 -99
  1294. package/dist/commands/method.d.ts.map +0 -1
  1295. package/dist/commands/method.js +0 -785
  1296. package/dist/commands/method.js.map +0 -1
  1297. package/dist/commands/migrate-setup.d.ts +0 -18
  1298. package/dist/commands/migrate-setup.d.ts.map +0 -1
  1299. package/dist/commands/migrate-setup.js +0 -198
  1300. package/dist/commands/migrate-setup.js.map +0 -1
  1301. package/dist/commands/promote.d.ts +0 -12
  1302. package/dist/commands/promote.d.ts.map +0 -1
  1303. package/dist/commands/promote.js +0 -113
  1304. package/dist/commands/promote.js.map +0 -1
  1305. package/dist/commands/proposals.d.ts +0 -9
  1306. package/dist/commands/proposals.d.ts.map +0 -1
  1307. package/dist/commands/proposals.js +0 -24
  1308. package/dist/commands/proposals.js.map +0 -1
  1309. package/dist/commands/reject.d.ts +0 -14
  1310. package/dist/commands/reject.d.ts.map +0 -1
  1311. package/dist/commands/reject.js +0 -44
  1312. package/dist/commands/reject.js.map +0 -1
  1313. package/dist/commands/setup-audit.d.ts +0 -59
  1314. package/dist/commands/setup-audit.d.ts.map +0 -1
  1315. package/dist/commands/setup-audit.js +0 -250
  1316. package/dist/commands/setup-audit.js.map +0 -1
  1317. package/dist/commands/setup-detect-surfaces.d.ts +0 -38
  1318. package/dist/commands/setup-detect-surfaces.d.ts.map +0 -1
  1319. package/dist/commands/setup-detect-surfaces.js +0 -76
  1320. package/dist/commands/setup-detect-surfaces.js.map +0 -1
  1321. package/dist/commands/setup-ingest.d.ts +0 -17
  1322. package/dist/commands/setup-ingest.d.ts.map +0 -1
  1323. package/dist/commands/setup-ingest.js +0 -226
  1324. package/dist/commands/setup-ingest.js.map +0 -1
  1325. package/dist/commands/setup-resolver.d.ts +0 -58
  1326. package/dist/commands/setup-resolver.d.ts.map +0 -1
  1327. package/dist/commands/setup-resolver.js +0 -150
  1328. package/dist/commands/setup-resolver.js.map +0 -1
  1329. package/dist/commands/setup-state.d.ts +0 -42
  1330. package/dist/commands/setup-state.d.ts.map +0 -1
  1331. package/dist/commands/setup-state.js +0 -93
  1332. package/dist/commands/setup-state.js.map +0 -1
  1333. package/dist/commands/setup.d.ts +0 -23
  1334. package/dist/commands/setup.d.ts.map +0 -1
  1335. package/dist/commands/setup.js +0 -69
  1336. package/dist/commands/setup.js.map +0 -1
  1337. package/dist/formatters/audit.d.ts +0 -52
  1338. package/dist/formatters/audit.d.ts.map +0 -1
  1339. package/dist/formatters/audit.js +0 -81
  1340. package/dist/formatters/audit.js.map +0 -1
  1341. package/dist/formatters/promote.d.ts +0 -30
  1342. package/dist/formatters/promote.d.ts.map +0 -1
  1343. package/dist/formatters/promote.js +0 -39
  1344. package/dist/formatters/promote.js.map +0 -1
  1345. package/dist/formatters/proposals.d.ts +0 -45
  1346. package/dist/formatters/proposals.d.ts.map +0 -1
  1347. package/dist/formatters/proposals.js +0 -62
  1348. package/dist/formatters/proposals.js.map +0 -1
  1349. package/dist/generators/archetypes.d.ts +0 -52
  1350. package/dist/generators/archetypes.d.ts.map +0 -1
  1351. package/dist/generators/archetypes.js +0 -153
  1352. package/dist/generators/archetypes.js.map +0 -1
  1353. package/dist/generators/archetypes.test.d.ts +0 -2
  1354. package/dist/generators/archetypes.test.d.ts.map +0 -1
  1355. package/dist/generators/archetypes.test.js +0 -237
  1356. package/dist/generators/archetypes.test.js.map +0 -1
  1357. package/dist/generators/chain-classifier.d.ts +0 -49
  1358. package/dist/generators/chain-classifier.d.ts.map +0 -1
  1359. package/dist/generators/chain-classifier.js +0 -180
  1360. package/dist/generators/chain-classifier.js.map +0 -1
  1361. package/dist/generators/chain-classifier.test.d.ts +0 -2
  1362. package/dist/generators/chain-classifier.test.d.ts.map +0 -1
  1363. package/dist/generators/chain-classifier.test.js +0 -257
  1364. package/dist/generators/chain-classifier.test.js.map +0 -1
  1365. package/dist/generators/chain-rules.d.ts +0 -42
  1366. package/dist/generators/chain-rules.d.ts.map +0 -1
  1367. package/dist/generators/chain-rules.js +0 -144
  1368. package/dist/generators/chain-rules.js.map +0 -1
  1369. package/dist/generators/chain-rules.test.d.ts +0 -2
  1370. package/dist/generators/chain-rules.test.d.ts.map +0 -1
  1371. package/dist/generators/chain-rules.test.js +0 -179
  1372. package/dist/generators/chain-rules.test.js.map +0 -1
  1373. package/dist/generators/handshake-diff.d.ts +0 -67
  1374. package/dist/generators/handshake-diff.d.ts.map +0 -1
  1375. package/dist/generators/handshake-diff.js +0 -183
  1376. package/dist/generators/handshake-diff.js.map +0 -1
  1377. package/dist/generators/handshake-diff.test.d.ts +0 -2
  1378. package/dist/generators/handshake-diff.test.d.ts.map +0 -1
  1379. package/dist/generators/handshake-diff.test.js +0 -264
  1380. package/dist/generators/handshake-diff.test.js.map +0 -1
  1381. package/dist/lib/activation.d.ts +0 -28
  1382. package/dist/lib/activation.d.ts.map +0 -1
  1383. package/dist/lib/activation.js +0 -57
  1384. package/dist/lib/activation.js.map +0 -1
  1385. package/dist/lib/activation.test.d.ts +0 -6
  1386. package/dist/lib/activation.test.d.ts.map +0 -1
  1387. package/dist/lib/activation.test.js +0 -121
  1388. package/dist/lib/activation.test.js.map +0 -1
  1389. package/dist/lib/inferSourceDate.d.ts +0 -12
  1390. package/dist/lib/inferSourceDate.d.ts.map +0 -1
  1391. package/dist/lib/inferSourceDate.js +0 -44
  1392. package/dist/lib/inferSourceDate.js.map +0 -1
  1393. package/dist/setup/__tests__/coach-traces.test.d.ts +0 -2
  1394. package/dist/setup/__tests__/coach-traces.test.d.ts.map +0 -1
  1395. package/dist/setup/__tests__/coach-traces.test.js +0 -189
  1396. package/dist/setup/__tests__/coach-traces.test.js.map +0 -1
  1397. package/dist/setup/__tests__/setup-commands.test.d.ts +0 -2
  1398. package/dist/setup/__tests__/setup-commands.test.d.ts.map +0 -1
  1399. package/dist/setup/__tests__/setup-commands.test.js +0 -177
  1400. package/dist/setup/__tests__/setup-commands.test.js.map +0 -1
  1401. package/dist/setup/__tests__/state-machine.test.d.ts +0 -2
  1402. package/dist/setup/__tests__/state-machine.test.d.ts.map +0 -1
  1403. package/dist/setup/__tests__/state-machine.test.js +0 -341
  1404. package/dist/setup/__tests__/state-machine.test.js.map +0 -1
  1405. package/dist/setup/detect-surfaces.d.ts +0 -21
  1406. package/dist/setup/detect-surfaces.d.ts.map +0 -1
  1407. package/dist/setup/detect-surfaces.js +0 -39
  1408. package/dist/setup/detect-surfaces.js.map +0 -1
  1409. package/dist/setup/manifest-writer.d.ts +0 -17
  1410. package/dist/setup/manifest-writer.d.ts.map +0 -1
  1411. package/dist/setup/manifest-writer.js +0 -153
  1412. package/dist/setup/manifest-writer.js.map +0 -1
  1413. package/dist/setup/perimeter.d.ts.map +0 -1
  1414. package/dist/setup/perimeter.js.map +0 -1
  1415. package/dist/setup/state-machine.d.ts +0 -67
  1416. package/dist/setup/state-machine.d.ts.map +0 -1
  1417. package/dist/setup/state-machine.js +0 -124
  1418. package/dist/setup/state-machine.js.map +0 -1
  1419. package/dist/surfaces/__tests__/pb-setup-passthrough.test.d.ts +0 -2
  1420. package/dist/surfaces/__tests__/pb-setup-passthrough.test.d.ts.map +0 -1
  1421. package/dist/surfaces/__tests__/pb-setup-passthrough.test.js +0 -132
  1422. package/dist/surfaces/__tests__/pb-setup-passthrough.test.js.map +0 -1
  1423. package/templates/archetypes/boundary.md +0 -23
  1424. package/templates/archetypes/constraint.md +0 -23
  1425. package/templates/archetypes/convention.md +0 -23
  1426. package/templates/archetypes/policy.md +0 -23
  1427. package/templates/archetypes/quality-gate.md +0 -23
  1428. package/templates/archetypes/workflow.md +0 -23
@@ -2,24 +2,26 @@
2
2
  * pb handshake — generate context files for AI developer tools.
3
3
  * Context export wiring (read-only filesystem bridge; GLO-63, DEC-161) — not a product surface.
4
4
  */
5
- import { mkdirSync, writeFileSync, existsSync, readFileSync, readdirSync, copyFileSync, appendFileSync, unlinkSync, statSync, renameSync, rmSync, realpathSync } from 'fs';
6
- import { join, dirname, resolve, basename, relative, sep, isAbsolute } from 'path';
5
+ import { mkdirSync, writeFileSync, existsSync, readFileSync, readdirSync, copyFileSync, realpathSync } from 'fs';
6
+ import { join, dirname, resolve, basename, relative, sep } from 'path';
7
7
  import { homedir } from 'os';
8
8
  import { fileURLToPath } from 'url';
9
- import { createHash } from 'crypto';
9
+ import { execSync } from 'child_process';
10
10
  import { getConfigOrGuide } from '../lib/config.js';
11
11
  import { select as promptSelect, confirm as promptConfirm } from '../lib/prompts.js';
12
12
  import { composeHooksFromIntents, getHookStatusForSurface } from '../lib/hook-intents.js';
13
- import { kernelCall, kernelCallWithSession } from '../lib/client.js';
13
+ import { kernelCall } from '../lib/client.js';
14
14
  import { readSession } from '../lib/session.js';
15
15
  import { detectRepo, extractWorkspaceProfile } from '../lib/repo-detect.js';
16
16
  import { generateContextMd } from '../generators/context-md.js';
17
17
  import { generateBriefingMd } from '../generators/briefing-md.js';
18
- import { MARKER, generateAgentsMd, generateClaudeMd, generateCursorMdc, generateCopilotMd } from '../generators/adapters.js';
19
- 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';
20
- import { generateChainRules } from '../generators/chain-rules.js';
21
- import { saveHandshakeState, loadPreviousState, diffHandshakeState, formatDiff, buildCurrentState, } from '../generators/handshake-diff.js';
18
+ import { MARKER, generateAgentsMd, generateClaudeMd, generateCursorMdc, generateCopilotMd, generateCopilotInstructionFiles } from '../generators/adapters.js';
19
+ import { readCanonicalSkills, readCanonicalRules, readPersonalLayer, readPersonalSkillsLayer, generateCursorSkill, generateCursorRule, generateCodexSkill, generateCodexSkillIndex, shouldEmitToTarget, filterByLevel, validateCodexSkills, evaluateConditions, } from '../generators/portable-knowledge.js';
20
+ import { findNoProjectionAssets } from '../generators/noProjectionAssets.js'; // WP-660 S2 combine
22
21
  import { resolveSurfaceProfile } from '../generators/surface-profiles.js';
22
+ import { generateEveryoneRulesMd } from '../generators/everyone-rules-md.js';
23
+ import { removeStaleBriefingProjections, retireGeneratedProjections } from '../generators/retired-projections.js';
24
+ import { formatWorkspaceBriefingLines } from '../lib/ruleListRender.js';
23
25
  import { formatHandshakeReport } from '../formatters/handshake.js';
24
26
  import { classifyAdapterFile, detectEol, spliceAppend, spliceReplace } from '../generators/region.js';
25
27
  import { REGION_PROJECTIONS } from '../generators/region-projections.js';
@@ -27,225 +29,17 @@ import { readManifest, readManifestStatus, filterByAdoptionState } from '../gene
27
29
  import { generateBoundaryManifest, getBoundaryEnforcementMode } from '../generators/boundary-manifest.js';
28
30
  import { loadMethodRegistry } from '../lib/method-registry.js';
29
31
  import { CLIError, ErrorCode } from '../lib/errors.js';
30
- import { trackEvent } from '../lib/telemetry.js';
32
+ import { isJsonMode } from '../lib/runner.js';
33
+ import { stripConvexInternals } from '../lib/strip.js';
31
34
  import { replaceVocabTokens } from '../lib/canonicalRefs.js';
32
35
  // WP-436 S3: vocab projector — resolves {{vocab:...}} tokens before writing to disk.
33
36
  import { getOrFetchVocabCtx } from '../lib/workspaceVocabCache.js';
34
37
  import { normalizeMaterializedFilename } from '../lib/normalizeMaterializedFilename.js';
35
- import { assertSetupWritePath } from '../setup/perimeter.js';
36
- // WP-421 S3: SurfaceAdapter reverse-map for tampered prompts (DEC-952, doneWhen #34).
37
- import { canonicalPathForAnySurface, SURFACE_GOVERN_NO_SURFACES, SURFACE_REGISTRY, validateSurfacesForMode, } from '../surfaces/registry.js';
38
- import { getReverseMapFallbackMessage, reportReverseMapMissing } from '../surfaces/telemetry.js';
39
- const MAX_HANDSHAKE_WAIT_MS = 10_000; // 10 seconds
40
- const POLL_INTERVAL_MS = 500; // 500 ms per poll
41
- const MAX_POLLS = MAX_HANDSHAKE_WAIT_MS / POLL_INTERVAL_MS; // 20
42
- // ── WP-379 S4: Dormant marker ─────────────────────────────────────────────────
43
- /**
44
- * DORMANT_MARKER — appended to previously-projected asset files when the asset's
45
- * gate deactivates (e.g. workspace readiness exceeds the max threshold).
46
- *
47
- * Contract:
48
- * - The file is NOT deleted. It persists on disk so that history is preserved
49
- * and the agent surface remains inspectable.
50
- * - The marker is appended at the end of the file, idempotent — if it already
51
- * exists, no second append occurs.
52
- * - The marker does NOT trigger a drift TEN. Dormant files are intentionally
53
- * deactivated, not accidentally forked.
54
- * - The marker is never included in active file writes — only dormant writes.
55
- *
56
- * Used by: writeDormantMarker() (write) and hasDormantMarker() (idempotency check).
57
- * Exported for use in tests.
58
- *
59
- * Chain: WP-379 S4.
60
- */
61
- export const DORMANT_MARKER = '<!-- pb-status: dormant -->';
62
- /**
63
- * hasDormantMarker — check whether a file on disk already has the dormant marker.
64
- * Used for idempotency: if the marker is already present, skip the append.
65
- */
66
- function hasDormantMarker(content) {
67
- return content.includes(DORMANT_MARKER);
68
- }
69
- /**
70
- * writeDormantMarker — append the dormant marker to a previously-projected file.
71
- *
72
- * Idempotent: if DORMANT_MARKER is already present, no-op.
73
- * Only operates on files that have the auto-gen MARKER — we never touch
74
- * manually-authored files.
75
- *
76
- * @param filePath Absolute path to the file.
77
- * @returns 'written' | 'already-dormant' | 'skipped' (no auto-gen marker)
78
- */
79
- export function writeDormantMarkerToFile(filePath) {
80
- if (!existsSync(filePath))
81
- return 'skipped';
82
- const content = readFileSync(filePath, 'utf8');
83
- // Only mark files that were originally projected by pb handshake.
84
- // Files without the auto-gen MARKER are manually authored — leave them alone.
85
- if (!content.includes(MARKER))
86
- return 'skipped';
87
- if (hasDormantMarker(content))
88
- return 'already-dormant';
89
- // Append the marker on its own line. No trailing newline assumption —
90
- // appendFileSync adds to whatever is already there.
91
- appendFileSync(filePath, `\n${DORMANT_MARKER}\n`);
92
- return 'written';
93
- }
94
- /**
95
- * renameSurfaceForDormancy — rename a projected surface file to `<path>.dormant`
96
- * so external scanners (which glob *.md / *.mdc) stop loading it. WP-426 E4.
97
- * The HTML-comment marker is invisible to scanners; the extension change removes
98
- * the file from their glob set. Only touches files carrying the auto-gen MARKER.
99
- * Runs on an INDEPENDENT existence check (not gated on marker-write result) so
100
- * legacy WP-379 marker-only files still rename. Idempotent.
101
- * Codex P1: when a .dormant already exists, only replace it if its body matches the
102
- * live file. A divergent .dormant (user edited it) is preserved and reported as 'drift'
103
- * rather than force-deleted — no silent data loss.
104
- * @returns 'renamed' | 'replaced' | 'already-dormant' | 'skipped' | 'drift'
105
- */
106
- export function renameSurfaceForDormancy(filePath) {
107
- const dormantPath = `${filePath}.dormant`;
108
- if (!existsSync(filePath))
109
- return existsSync(dormantPath) ? 'already-dormant' : 'skipped';
110
- if (!readFileSync(filePath, 'utf8').includes(MARKER))
111
- return 'skipped';
112
- const replacing = existsSync(dormantPath);
113
- if (replacing) {
114
- // Codex P1: the existing .dormant may carry user edits (e.g. the user reactivated to
115
- // the live path but kept an edited dormant sibling). Compare normalized bodies
116
- // (DORMANT_MARKER + volatile auto-gen timestamp stripped from both); if they diverge,
117
- // preserve the .dormant and signal drift instead of force-replacing it.
118
- const strip = (s) => normalizeHandshakeContentForComparison(s.split(DORMANT_MARKER).join('')).trimEnd();
119
- if (strip(readFileSync(filePath, 'utf8')) !== strip(readFileSync(dormantPath, 'utf8'))) {
120
- return 'drift';
121
- }
122
- rmSync(dormantPath, { force: true });
123
- }
124
- renameSync(filePath, dormantPath);
125
- return replacing ? 'replaced' : 'renamed';
126
- }
127
- /**
128
- * restoreSurfaceFromDormant — clean the orphan `<path>.dormant` sibling after a
129
- * raised (observe→project) asset has been re-projected fresh from the DB body by
130
- * the normal write loop. WP-426 E4.
131
- * Normalizes the volatile auto-gen timestamp (via normalizeHandshakeContentForComparison)
132
- * before comparing, else the lowering-time timestamp would always force a false
133
- * 'orphan-drift'. Identical body → remove. Differs (user edited) → preserve + drift.
134
- * @returns 'restored' | 'orphan-drift' | 'skipped'
135
- */
136
- export function restoreSurfaceFromDormant(filePath) {
137
- const dormantPath = `${filePath}.dormant`;
138
- if (!existsSync(dormantPath))
139
- return 'skipped';
140
- // WP-426 E4: no fresh live projection this run (surface filtered / user-owned / not written) →
141
- // nothing to reconcile; absence of fresh is NOT evidence of a user edit. Leave the .dormant.
142
- if (!existsSync(filePath))
143
- return 'skipped';
144
- const fresh = readFileSync(filePath, 'utf8');
145
- // Codex P2: only reconcile against a PB-managed projection. A live file WITHOUT the auto-gen
146
- // MARKER is a user-owned file (shouldWriteAdapter would have skipped reprojecting it),
147
- // so it was NOT raised this run — comparing the .dormant against it would wrongly delete it or
148
- // re-fire "edited while dormant" drift. Leave the .dormant untouched.
149
- if (!fresh.includes(MARKER))
150
- return 'skipped';
151
- const dormant = readFileSync(dormantPath, 'utf8').split(DORMANT_MARKER).join('');
152
- const norm = (s) => normalizeHandshakeContentForComparison(s).trimEnd();
153
- if (norm(dormant) === norm(fresh)) {
154
- rmSync(dormantPath, { force: true });
155
- return 'restored';
156
- }
157
- return 'orphan-drift';
158
- }
159
- /**
160
- * deriveDormantFilePaths — compute the set of on-disk file paths that would have
161
- * been projected for a given dormant asset (by name and assetKind).
162
- *
163
- * Assets are projected to one or more surfaces (cursor/claude/codex) depending
164
- * on shouldEmitToTarget. Since we don't re-run shouldEmitToTarget here, we
165
- * speculatively probe all known surface paths and let writeDormantMarkerToFile
166
- * decide whether each exists and has the auto-gen MARKER.
167
- *
168
- * @param asset The dormant asset from the server.
169
- * @param cwd Current working directory (project root).
170
- * @returns Each candidate path paired with its owning surface, so callers can
171
- * filter by the run's allowedTargets (--surfaces) and the perimeter.
172
- */
173
- function deriveDormantFilePaths(asset, cwd) {
174
- // Defense-in-depth: even though `name` originates from platform-seeded DB
175
- // entries (not user input), validate it against a strict charset before
176
- // interpolating into a filesystem path. Reject anything that could traverse
177
- // out of the expected directories. WP-379 S4 review finding.
178
- if (!/^[A-Za-z0-9 ._-]+$/.test(asset.name)) {
179
- return [];
180
- }
181
- const out = [];
182
- const { name, assetKind } = asset;
183
- if (assetKind === 'skill') {
184
- out.push({ path: join(cwd, '.cursor', 'skills', name, 'SKILL.md'), surface: 'cursor' });
185
- out.push({ path: join(cwd, '.codex', 'skills', `${name}.md`), surface: 'codex' });
186
- }
187
- else if (assetKind === 'rule' || assetKind === 'hook') {
188
- out.push({ path: join(cwd, '.cursor', 'rules', `${name}.mdc`), surface: 'cursor' });
189
- out.push({ path: join(cwd, '.claude', 'rules', `${name}.md`), surface: 'claude' });
190
- }
191
- return out;
192
- }
193
- /**
194
- * Single-shot health probe — calls `workspace.health` and inspects
195
- * `starterSetupSeeded`. Does NOT poll internally; polling is the caller's
196
- * responsibility (connect-context.ts).
197
- *
198
- * Returns:
199
- * - `seeds-ready` — health query succeeded AND starterSetupSeeded is true
200
- * - `seeds-pending` — health query succeeded but starterSetupSeeded is false
201
- * - `probe-failed` — health query threw (network, auth, etc.)
202
- */
203
- export async function probeStarterSetupSeeded() {
204
- try {
205
- const health = await kernelCall('workspace.health', {});
206
- if (health.starterSetupSeeded) {
207
- return { status: 'seeds-ready' };
208
- }
209
- const starterGaps = (health.gaps ?? []).filter((g) => g.kind === 'starter-setup-missing' || g.kind === 'platform-domains-missing');
210
- return {
211
- status: 'seeds-pending',
212
- gaps: starterGaps.length > 0 ? starterGaps : [
213
- {
214
- kind: 'starter-setup-missing',
215
- severity: 'warn',
216
- message: 'Starter setup seeds are still running.',
217
- },
218
- ],
219
- };
220
- }
221
- catch (err) {
222
- return {
223
- status: 'probe-failed',
224
- error: err instanceof Error ? err.message : String(err),
225
- };
226
- }
227
- }
228
- /**
229
- * Poll `probeStarterSetupSeeded` up to MAX_POLLS times (10s at 500ms intervals).
230
- * Returns the final probe result — caller decides how to render the outcome.
231
- *
232
- * Exported so connect-context.ts can use it without re-implementing the loop.
233
- */
234
- export async function pollUntilSeedsReady() {
235
- for (let poll = 0; poll < MAX_POLLS; poll++) {
236
- const result = await probeStarterSetupSeeded();
237
- if (result.status === 'seeds-ready')
238
- return result;
239
- if (result.status === 'probe-failed')
240
- return result; // don't retry on auth/network errors
241
- // seeds-pending — wait before next poll
242
- if (poll < MAX_POLLS - 1) {
243
- await new Promise((res) => setTimeout(res, POLL_INTERVAL_MS));
244
- }
245
- }
246
- // Final probe after exhausting waits — return whatever state we have
247
- return probeStarterSetupSeeded();
248
- }
38
+ import { findLeftoverCursorSkills, LEFTOVER_FILES_MAX } from './handshakeCursorSkillCleanup.js';
39
+ import { classifyDriftBucket } from './handshakeDriftClassification.js';
40
+ import { sanitizeStartupResolutionSignals } from '../lib/startup-resolution-signals.js';
41
+ import { assertSetupWritePath } from '../lib/writePerimeter.js';
42
+ import { SURFACE_GOVERN_NO_SURFACES, SURFACE_REGISTRY, validateSurfacesForMode, } from '../surfaces/registry.js';
249
43
  const LEVELS = {
250
44
  guide: {
251
45
  label: 'Guide me',
@@ -274,8 +68,7 @@ const LEVELS = {
274
68
  };
275
69
  // Explicit ordering — determines menu numbering in promptLevel(). Do not reorder.
276
70
  const LEVEL_KEYS = ['guide', 'work', 'silent', 'full-trust'];
277
- // Hook failure contract (TEN-712): all hook commands MUST end with '2>/dev/null || true'
278
- // so Claude Code always starts even if pb is unavailable. Never remove this suffix.
71
+ // Hook failure contract (TEN-712): every hook command MUST end with '|| true' so Claude Code always starts even if pb is unavailable.
279
72
  const INIT_PERMISSION = 'Bash(pb:*)';
280
73
  function readSettings(filePath) {
281
74
  if (!existsSync(filePath))
@@ -376,8 +169,7 @@ export async function runHandshakeInit(options = {}) {
376
169
  for (const item of teamAdded)
377
170
  console.log(` + ${item}`);
378
171
  }
379
- // Step 2: Personal config — wizard or --level flag
380
- // Cast is safe: LEVEL_KEYS.includes() validated above; invalid level already threw CLIError.
172
+ // Step 2: Personal config — wizard or --level flag. Cast is safe: LEVEL_KEYS.includes() validated above.
381
173
  const levelKey = options.level ? options.level : await promptLevel();
382
174
  const level = LEVELS[levelKey];
383
175
  const personalAdded = writePersonalSettings(levelKey, dryRun);
@@ -399,11 +191,7 @@ export async function runHandshakeInit(options = {}) {
399
191
  if (!dryRun)
400
192
  console.log('Reload /hooks in Claude Code (or restart) to activate.');
401
193
  console.log('Run `pb handshake --init --level <guide|work|silent|full-trust>` to change level.');
402
- // Step 2b: Report multi-surface hook opt-in status (WP-310 E3b)
403
- // Reads manifest.hooks.{cursor,copilot} and prints an informational note for
404
- // each opted-in surface. Silence = no manifest or no hooks flags set.
405
- // DEC-536: Claude-native default is already wired above; this block only fires
406
- // when the user has explicitly opted in via manifest.
194
+ // Step 2b: Report multi-surface hook opt-in status (WP-310 E3b) — manifest.hooks.{cursor,copilot}, silence = no manifest/flags (DEC-536).
407
195
  const pbDirForManifest = join(cwd, '.productbrain');
408
196
  const initManifest = readManifest(pbDirForManifest);
409
197
  const multiSurfaceOptIns = [];
@@ -472,22 +260,218 @@ export async function runHandshakeInit(options = {}) {
472
260
  }
473
261
  }
474
262
  }
475
- /**
476
- * Normalize volatile handshake-only timestamps before comparing generated files.
477
- * This keeps the visible timestamps in generated artifacts while avoiding
478
- * meaningless rewrites when semantic content is unchanged.
479
- */
263
+ const LOCAL_REF_REGEX = /\b(?:WP|TEN|DEC|BET|FEAT|INS|STD|PRI|ARCH)[-\s#]*\d+\b|\bPR\s*#?\s*\d+\b/gi;
264
+ const STARTUP_RESOLUTION_RESOLVER_VERSION = 'startup-resolution-v1';
265
+ // Global cap on collected refs (spec "Contract: StartupResolutionSignals" — arrays are capped).
266
+ const LOCAL_REF_GLOBAL_CAP = 25;
267
+ // Per-source cap so a broad source (context.md) can't starve briefing.md's task-specific refs (Codex@677).
268
+ const LOCAL_REF_PER_SOURCE_CAP = 18;
269
+ // Time-boxed so an unauthed/slow `gh` can't stall session-start (F4).
270
+ const PR_DIFF_TIMEOUT_MS = 4_000;
271
+ // Bounds worst-case `gh` subprocess invocations per handshake.
272
+ const PR_DIFF_MAX_REFS = 5;
273
+ function runGitText(cwd, command) {
274
+ try {
275
+ const value = execSync(command, {
276
+ cwd,
277
+ encoding: 'utf8',
278
+ stdio: ['ignore', 'pipe', 'ignore'],
279
+ }).trim();
280
+ return value.length > 0 ? value : undefined;
281
+ }
282
+ catch {
283
+ return undefined;
284
+ }
285
+ }
286
+ /** Dereference a "PR #N" ref to its changed paths via `gh pr diff <N> --name-only` (F4: server
287
+ * resolver has no git/gh access). Guarded/time-boxed; `run` is injectable for tests. */
288
+ export function dereferencePrRefToPaths(cwd, prNumber, run = runGitTextTimeboxed) {
289
+ if (!Number.isInteger(prNumber) || prNumber <= 0)
290
+ return [];
291
+ const raw = run(cwd, `gh pr diff ${prNumber} --name-only`, PR_DIFF_TIMEOUT_MS);
292
+ if (!raw)
293
+ return [];
294
+ return raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
295
+ }
296
+ /** Time-boxed variant of runGitText for the PR-diff dereference (F4). */
297
+ function runGitTextTimeboxed(cwd, command, timeoutMs) {
298
+ try {
299
+ const value = execSync(command, {
300
+ cwd,
301
+ encoding: 'utf8',
302
+ stdio: ['ignore', 'pipe', 'ignore'],
303
+ timeout: timeoutMs,
304
+ }).trim();
305
+ return value.length > 0 ? value : undefined;
306
+ }
307
+ catch {
308
+ return undefined;
309
+ }
310
+ }
311
+ function readOptionalLocalText(cwd, path) {
312
+ const fullPath = join(cwd, path);
313
+ if (!existsSync(fullPath))
314
+ return undefined;
315
+ try {
316
+ return readFileSync(fullPath, 'utf8');
317
+ }
318
+ catch {
319
+ return undefined;
320
+ }
321
+ }
322
+ function normalizeLocalRef(ref) {
323
+ const trimmed = ref.trim().replace(/\s+/g, ' ');
324
+ const pr = trimmed.match(/^PR\s*#?\s*(\d+)$/i);
325
+ if (pr)
326
+ return `PR #${pr[1]}`;
327
+ const entry = trimmed.match(/^([A-Z]+)[-\s#]*(\d+)$/i);
328
+ if (entry)
329
+ return `${entry[1].toUpperCase()}-${entry[2]}`;
330
+ return trimmed;
331
+ }
332
+ /** Collect normalized local refs across several text sources, deduped. Codex@677: a per-source
333
+ * cap alongside the global one, so a broad source (context.md) can't starve a later,
334
+ * task-specific source (briefing.md); already-collected refs dedupe without spending later quota. */
335
+ function collectLocalRefs(texts) {
336
+ const refs = [];
337
+ const seen = new Set();
338
+ for (const text of texts) {
339
+ if (!text)
340
+ continue;
341
+ let fromThisSource = 0;
342
+ for (const match of text.matchAll(LOCAL_REF_REGEX)) {
343
+ const ref = normalizeLocalRef(match[0]);
344
+ const key = ref.toLowerCase();
345
+ if (seen.has(key))
346
+ continue;
347
+ if (fromThisSource >= LOCAL_REF_PER_SOURCE_CAP)
348
+ break;
349
+ seen.add(key);
350
+ refs.push(ref);
351
+ fromThisSource++;
352
+ if (refs.length >= LOCAL_REF_GLOBAL_CAP)
353
+ return refs;
354
+ }
355
+ }
356
+ return refs;
357
+ }
358
+ function deriveHandshakeStartupTask(refs, changedPaths, callerTask) {
359
+ if (callerTask && callerTask.trim())
360
+ return callerTask.trim();
361
+ const parts = [];
362
+ if (refs.length > 0)
363
+ parts.push(refs.join(' '));
364
+ if (changedPaths.length > 0)
365
+ parts.push(`changed paths ${changedPaths.slice(0, 5).join(' ')}`);
366
+ return parts.length > 0 ? parts.join(' ') : undefined;
367
+ }
368
+ const DEFAULT_HANDSHAKE_SIGNAL_DEPS = {
369
+ runGit: runGitText,
370
+ prDiff: (cwd, prNumber) => dereferencePrRefToPaths(cwd, prNumber),
371
+ };
372
+ /** Extract the PR number from a normalized "PR #N" ref, else null. */
373
+ function prNumberFromRef(ref) {
374
+ const m = ref.match(/^PR\s*#?\s*(\d+)$/i);
375
+ if (!m)
376
+ return null;
377
+ const n = Number(m[1]);
378
+ return Number.isInteger(n) && n > 0 ? n : null;
379
+ }
380
+ export function deriveHandshakeStartupSignals(cwd, callerSignals = {}, deps = DEFAULT_HANDSHAKE_SIGNAL_DEPS) {
381
+ const { runGit, prDiff } = deps;
382
+ const branchName = runGit(cwd, 'git branch --show-current');
383
+ const commitSha = runGit(cwd, 'git rev-parse --short HEAD');
384
+ // Changed paths, unioned + deduped: (1) dirty worktree; (2) committed branch delta vs origin/main's
385
+ // merge-base (Codex@665, invisible once the tree is clean); (3) PR-ref dereference (F4), appended later.
386
+ const dirtyChangedPaths = runGit(cwd, 'git diff --name-only HEAD')?.split(/\r?\n/).filter(Boolean) ?? [];
387
+ const mergeBase = runGit(cwd, 'git merge-base HEAD origin/main');
388
+ const branchChangedPaths = mergeBase
389
+ ? (runGit(cwd, `git diff --name-only ${mergeBase} HEAD`)?.split(/\r?\n/).filter(Boolean) ?? [])
390
+ : [];
391
+ const worktreeName = basename(cwd);
392
+ const contextText = readOptionalLocalText(cwd, '.productbrain/context.md');
393
+ const briefingText = readOptionalLocalText(cwd, '.productbrain/briefing.md');
394
+ const callerRefs = Array.isArray(callerSignals.reviewedArtifactRefs) ? callerSignals.reviewedArtifactRefs.join('\n') : undefined;
395
+ // Codex@677: briefing.md (task-specific) reads BEFORE context.md (broad) so its refs collect first — with the per-source cap, context.md can't starve briefing.
396
+ const refs = collectLocalRefs([
397
+ callerSignals.taskText ?? undefined,
398
+ callerSignals.explicitScope ?? undefined,
399
+ callerRefs,
400
+ branchName,
401
+ worktreeName,
402
+ briefingText,
403
+ contextText,
404
+ ]);
405
+ // F4: dereference "PR #N" refs to diff paths, folded into changedPaths — the only place this can happen (server records dereferenced:false, no git access). Time-boxed; absent/unauthed gh no-ops.
406
+ const prDiffPaths = [];
407
+ if (callerSignals.changedPaths === undefined) {
408
+ let derefed = 0;
409
+ for (const ref of refs) {
410
+ const prNumber = prNumberFromRef(ref);
411
+ if (prNumber === null)
412
+ continue;
413
+ if (derefed >= PR_DIFF_MAX_REFS)
414
+ break;
415
+ derefed++;
416
+ try {
417
+ for (const p of prDiff(cwd, prNumber))
418
+ prDiffPaths.push(p);
419
+ }
420
+ catch {
421
+ // gh absent / unauthed / PR missing — skip gracefully, leave existing behavior.
422
+ }
423
+ }
424
+ }
425
+ // Caller-supplied changedPaths win (backward compat); otherwise union the
426
+ // three local sources, deduped, order-stable.
427
+ const unionedChangedPaths = callerSignals.changedPaths ??
428
+ Array.from(new Set([...dirtyChangedPaths, ...branchChangedPaths, ...prDiffPaths]));
429
+ const baseSignals = sanitizeStartupResolutionSignals({
430
+ ...callerSignals,
431
+ sourceSurface: callerSignals.sourceSurface ?? 'cli',
432
+ resolverVersion: callerSignals.resolverVersion ?? STARTUP_RESOLUTION_RESOLVER_VERSION,
433
+ branchName: callerSignals.branchName ?? branchName,
434
+ worktreeName: callerSignals.worktreeName ?? worktreeName,
435
+ changedPaths: unionedChangedPaths,
436
+ reviewedArtifactRefs: callerSignals.reviewedArtifactRefs ?? refs,
437
+ commitSha: callerSignals.commitSha ?? commitSha,
438
+ });
439
+ const taskText = deriveHandshakeStartupTask(baseSignals.reviewedArtifactRefs ?? [], baseSignals.changedPaths ?? [], baseSignals.taskText);
440
+ const sanitized = sanitizeStartupResolutionSignals({
441
+ ...baseSignals,
442
+ taskText,
443
+ });
444
+ const hasMeaningfulEvidence = Boolean(sanitized.taskText) ||
445
+ (sanitized.changedPaths?.length ?? 0) > 0 ||
446
+ (sanitized.reviewedArtifactRefs?.length ?? 0) > 0 ||
447
+ Boolean(sanitized.explicitScope);
448
+ if (hasMeaningfulEvidence)
449
+ return sanitized;
450
+ // Codex@704: even with no evidence, emit a minimal envelope carrying attribution — {} would
451
+ // drop the whole startup block, losing the loud domain-unresolved signal (spec "Loud Unresolved State", AC #4).
452
+ return sanitizeStartupResolutionSignals({
453
+ sourceSurface: sanitized.sourceSurface ?? 'cli',
454
+ resolverVersion: sanitized.resolverVersion ?? STARTUP_RESOLUTION_RESOLVER_VERSION,
455
+ branchName: sanitized.branchName,
456
+ worktreeName: sanitized.worktreeName,
457
+ commitSha: sanitized.commitSha,
458
+ changeId: sanitized.changeId,
459
+ });
460
+ }
461
+ /** Normalize volatile handshake-only timestamps before comparing generated files — keeps visible
462
+ * timestamps in artifacts while avoiding meaningless rewrites when content is unchanged. */
480
463
  export function normalizeHandshakeContentForComparison(content) {
481
464
  return content
482
465
  .replace(/<!-- auto-generated by pb handshake — [0-9]{4}-[0-9]{2}-[0-9]{2}T[^>]+ -->/g, '<!-- auto-generated by pb handshake — <TIMESTAMP> -->')
483
466
  .replace(/^_Generated: [0-9]{4}-[0-9]{2}-[0-9]{2}T.*_$/gm, '_Generated: <TIMESTAMP>_');
484
467
  }
485
468
  function shouldWriteAdapter(filePath, force) {
486
- if (force)
487
- return true;
469
+ // An absent file at an adapter path is a projection target → materialize it.
488
470
  if (!existsSync(filePath))
489
471
  return true;
490
472
  const content = readFileSync(filePath, 'utf8');
473
+ // No MARKER → user-owned/committed-static (CLAUDE.md, AGENTS.md, Copilot instructions) — never overwritten, not even under --force.
474
+ void force;
491
475
  return content.includes(MARKER);
492
476
  }
493
477
  function normalizeSurfaceName(surface) {
@@ -504,242 +488,9 @@ function surfacePerimeterRoots(surface) {
504
488
  return ['.claude', 'CLAUDE.md'];
505
489
  return [`.${surface}`];
506
490
  }
507
- function modeRank(mode) {
508
- return { off: 0, observe: 1, project: 2, govern: 3 }[mode];
509
- }
510
- function normalizeSetupAuthoringBody(body) {
511
- return body.replace(/\r\n/g, '\n').replace(/\r/g, '\n').trimEnd();
512
- }
513
- function setupAuthoringAssetHash(asset) {
514
- const canonical = {
515
- entryId: asset.entryId,
516
- name: asset.name,
517
- description: asset.description ?? '',
518
- assetKind: asset.assetKind,
519
- triggers: asset.triggers ?? [],
520
- semanticRefs: asset.semanticRefs ?? [],
521
- body: normalizeSetupAuthoringBody(asset.body),
522
- };
523
- return `sha256:${createHash('sha256').update(JSON.stringify(canonical), 'utf8').digest('hex')}`;
524
- }
525
- function parseSetupAuthoringFrontmatter(raw) {
526
- const fmMatch = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
527
- if (!fmMatch) {
528
- const h1 = raw.match(/^# (.+)$/m);
529
- return { name: h1?.[1] ?? '', description: '', body: raw, triggers: [], semanticRefs: [] };
530
- }
531
- const fields = new Map();
532
- const arrayFields = new Map();
533
- const lines = fmMatch[1].split('\n');
534
- let currentArrayKey = null;
535
- let currentArrayValues = [];
536
- for (const line of lines) {
537
- const arrayItemMatch = line.match(/^\s+-\s+(.+)$/);
538
- const keyValueMatch = line.match(/^(\w+):\s*(.*)$/);
539
- if (arrayItemMatch && currentArrayKey) {
540
- currentArrayValues.push(arrayItemMatch[1].trim().replace(/^['"]|['"]$/g, ''));
541
- }
542
- else if (keyValueMatch) {
543
- if (currentArrayKey) {
544
- arrayFields.set(currentArrayKey, currentArrayValues);
545
- currentArrayKey = null;
546
- currentArrayValues = [];
547
- }
548
- const [, key, value] = keyValueMatch;
549
- if (value.trim() === '') {
550
- currentArrayKey = key;
551
- }
552
- else {
553
- fields.set(key, value.trim().replace(/^['"]|['"]$/g, ''));
554
- }
555
- }
556
- }
557
- if (currentArrayKey)
558
- arrayFields.set(currentArrayKey, currentArrayValues);
559
- const body = fmMatch[2];
560
- return {
561
- frontmatterId: fields.get('id'),
562
- name: fields.get('name') ?? body.match(/^# (.+)$/m)?.[1] ?? '',
563
- description: fields.get('description') ?? '',
564
- body,
565
- triggers: arrayFields.get('triggers') ?? [],
566
- semanticRefs: arrayFields.get('semanticRefs') ?? [],
567
- };
568
- }
569
- function deriveSetupAuthoringEntryId(filename, kind) {
570
- const base = basename(filename, '.md');
571
- const snakeCase = base.toUpperCase().replace(/[^A-Z0-9]+/g, '_');
572
- return `SETUP-${kind.toUpperCase()}-${snakeCase}`;
573
- }
574
- function scanSetupAuthoringFiles(productbrainDir) {
575
- const dirs = [
576
- { dir: 'skills', kind: 'skill' },
577
- { dir: 'rules', kind: 'rule' },
578
- { dir: 'hooks', kind: 'hook' },
579
- ];
580
- const items = [];
581
- for (const { dir, kind } of dirs) {
582
- const absDir = join(productbrainDir, dir);
583
- if (!existsSync(absDir))
584
- continue;
585
- for (const file of readdirSync(absDir).filter((f) => f.endsWith('.md'))) {
586
- const filePath = join(absDir, file);
587
- const parsed = parseSetupAuthoringFrontmatter(readFileSync(filePath, 'utf8'));
588
- const fallbackName = basename(file, '.md');
589
- items.push({
590
- filePath,
591
- derivedEntryId: deriveSetupAuthoringEntryId(file, kind),
592
- frontmatterId: parsed.frontmatterId,
593
- name: parsed.name || fallbackName,
594
- description: parsed.description,
595
- body: parsed.body,
596
- assetKind: kind,
597
- triggers: parsed.triggers,
598
- semanticRefs: parsed.semanticRefs,
599
- });
600
- }
601
- }
602
- return items.sort((a, b) => a.filePath.localeCompare(b.filePath));
603
- }
604
- function setupAuthoringDirForKind(kind) {
605
- if (kind === 'skill')
606
- return 'skills';
607
- if (kind === 'rule')
608
- return 'rules';
609
- if (kind === 'hook')
610
- return 'hooks';
611
- return null;
612
- }
613
- function setupAuthoringFilename(name, entryId) {
614
- const base = (name || entryId)
615
- .replace(/[\/\\:*?"<>|]/g, '-')
616
- .replace(/\s+/g, ' ')
617
- .trim();
618
- return `${base || entryId}.md`;
619
- }
620
- function setupAuthoringPath(cwd, asset) {
621
- const dir = setupAuthoringDirForKind(asset.assetKind);
622
- if (!dir)
623
- return null;
624
- // WP-426 E3: recorded authoring source path wins so reprojection lands where the
625
- // user authored — no duplicate (TEN-1920). Stored relative to .productbrain/.
626
- if (asset.authoringPath && asset.authoringPath.trim()) {
627
- // Codex P1/P2: authoringPath comes from the DB and is untrusted at projection
628
- // time. It is probed via existsSync/readFileSync (and later writeFileSync) in the
629
- // writeback loop BEFORE any assertSetupWritePath guard runs. Containment alone is
630
- // not enough — a bad DB row could still point at a directory (e.g. "skills") or an
631
- // internal PB file (".authoring-sync.json", "manifest.yaml"), which the loop would
632
- // mis-handle as markdown (throw on a directory read, or overwrite PB state).
633
- // Constrain to a kind-appropriate markdown file (<dir>/**/*.md); otherwise fall
634
- // back to the safe name-derived path.
635
- const pbDir = join(cwd, '.productbrain');
636
- const candidate = resolve(pbDir, asset.authoringPath);
637
- const within = relative(pbDir, candidate);
638
- const withinPosix = within.split(sep).join('/');
639
- if (!within.startsWith('..') &&
640
- !isAbsolute(within) &&
641
- withinPosix.startsWith(`${dir}/`) &&
642
- withinPosix.toLowerCase().endsWith('.md')) {
643
- return candidate;
644
- }
645
- }
646
- return join(cwd, '.productbrain', dir, setupAuthoringFilename(asset.name, asset.entryId));
647
- }
648
- function renderSetupAuthoringFile(asset) {
649
- const lines = [
650
- '---',
651
- `id: ${asset.entryId}`,
652
- `name: ${JSON.stringify(asset.name)}`,
653
- `description: ${JSON.stringify(asset.description ?? '')}`,
654
- `assetKind: ${asset.assetKind}`,
655
- ];
656
- const pushArray = (key, values) => {
657
- if (!values || values.length === 0)
658
- return;
659
- lines.push(`${key}:`);
660
- for (const value of values)
661
- lines.push(` - ${JSON.stringify(value)}`);
662
- };
663
- pushArray('triggers', asset.triggers);
664
- pushArray('semanticRefs', asset.semanticRefs);
665
- lines.push('---', normalizeSetupAuthoringBody(asset.body), '');
666
- return lines.join('\n');
667
- }
668
- function loadAuthoringSyncState(productbrainDir) {
669
- const statePath = join(productbrainDir, '.authoring-sync.json');
670
- if (!existsSync(statePath))
671
- return { version: 1, assets: {} };
672
- try {
673
- const parsed = JSON.parse(readFileSync(statePath, 'utf8'));
674
- if (parsed.version !== 1 || !parsed.assets || typeof parsed.assets !== 'object') {
675
- return { version: 1, assets: {} };
676
- }
677
- // Codex P2: the dormant registries are consumed via .includes() in the dormant loop
678
- // BEFORE its per-file try/catch, so a malformed .authoring-sync.json (a field set to
679
- // an object/number instead of an array) would throw a TypeError and abort the whole
680
- // handshake. Coerce to a string[] (mirrors the assets validation above) to fail open.
681
- const toStringArray = (v) => Array.isArray(v) ? v.filter((x) => typeof x === 'string') : [];
682
- return {
683
- version: 1,
684
- assets: parsed.assets,
685
- dormantRenamed: toStringArray(parsed.dormantRenamed),
686
- dormantReactivated: toStringArray(parsed.dormantReactivated),
687
- };
688
- }
689
- catch {
690
- return { version: 1, assets: {} };
691
- }
692
- }
693
- function saveAuthoringSyncState(productbrainDir, state) {
694
- const statePath = join(productbrainDir, '.authoring-sync.json');
695
- assertSetupWritePath(statePath, { surfaces: [] });
696
- mkdirSync(productbrainDir, { recursive: true });
697
- writeFileSync(statePath, JSON.stringify(state, null, 2) + '\n');
698
- }
699
- const DRIFT_HASH_TRAILER_REGEX = /^<!--\s*pb-hash:\s*sha256:([0-9a-f]+)\s*-->\s*$/m;
700
- const DRIFT_HASH_TRAILER_STRIP = /^<!--\s*pb-hash:.*-->\s*$/gm;
701
- const DRIFT_TIMESTAMP_STRIP = /^<!--\s*pb-generated-at:.*-->\s*$/gm;
702
- /**
703
- * Classify a single projection-target file into one of the three drift buckets.
704
- *
705
- * Returns `null` when `filePath` does not exist (first-run / unprojected) — the
706
- * write loop treats that as "would-write" and the file is not part of any bucket.
707
- *
708
- * @param filePath Absolute path to the projection file on disk.
709
- * @returns { bucket, expectedHash, actualHash } when the file exists.
710
- * `expectedHash`/`actualHash` are populated only for the
711
- * tampered bucket so the headless refusal payload can include
712
- * them verbatim. For clean / user-owned, both are `''`.
713
- */
714
- export function classifyDriftBucket(filePath) {
715
- if (!existsSync(filePath))
716
- return null;
717
- const content = readFileSync(filePath, 'utf8');
718
- // No auto-gen MARKER → user-owned. Never touch.
719
- if (!content.includes(MARKER)) {
720
- return { bucket: 'user-owned', expectedHash: '', actualHash: '' };
721
- }
722
- // Marker present but no hash trailer → legacy / pre-S0c projection: treat as
723
- // clean (the hash trailer was added in WP-345 S0c). The user-owned-vs-clean
724
- // semantic falls back to existing shouldWriteAdapter behavior.
725
- const trailerMatch = content.match(DRIFT_HASH_TRAILER_REGEX);
726
- if (!trailerMatch) {
727
- return { bucket: 'pb-managed-clean', expectedHash: '', actualHash: '' };
728
- }
729
- const expectedHash = `sha256:${trailerMatch[1]}`;
730
- // Recompute the actual hash from the body (strip trailer + timestamp, LF, trim).
731
- const normalized = content
732
- .replace(DRIFT_HASH_TRAILER_STRIP, '')
733
- .replace(DRIFT_TIMESTAMP_STRIP, '')
734
- .replace(/\r\n/g, '\n')
735
- .replace(/\r/g, '\n')
736
- .trimEnd();
737
- const actualHash = `sha256:${createHash('sha256').update(normalized, 'utf8').digest('hex')}`;
738
- if (actualHash === expectedHash) {
739
- return { bucket: 'pb-managed-clean', expectedHash, actualHash };
740
- }
741
- return { bucket: 'pb-managed-tampered', expectedHash, actualHash };
742
- }
491
+ // ── WP-421 S3: Three-bucket drift classification (doneWhen #17) — now its own module (STD-2/DEC-1504
492
+ // shrink-only offset). Re-exported so existing imports `from '../commands/handshake.js'` keep working.
493
+ export { classifyDriftBucket };
743
494
  function deduplicateEntries(entries) {
744
495
  const seen = new Set();
745
496
  const result = [];
@@ -753,46 +504,35 @@ function deduplicateEntries(entries) {
753
504
  return result;
754
505
  }
755
506
  /**
756
- * resolveProjectionCollision — WP-379 S5b
507
+ * findLeftoverProjections — WP-379 S5b
757
508
  *
758
- * Marker-scoped orphan unlink: enumerates target dirs (.cursor/rules/,
759
- * .claude/rules/, .claude/skills/, .codex/skills/); for each file that has
760
- * the auto-gen MARKER whose lowercase-normalized filename does NOT match any
761
- * current active-asset materializedFilename, the file is unlinked.
509
+ * Lists marker-bearing files under .cursor/rules/, .claude/rules/, .claude/skills/, .codex/skills/
510
+ * (plus the nested .cursor/skills/<name>/SKILL.md layout) that look stale: orphan (no canonical
511
+ * asset), stale case/punctuation variant, or a leftover `.dormant` copy. User-owned (no MARKER)
512
+ * files and unselected `allowedTargets` are never reported.
762
513
  *
763
- * User-owned files (no MARKER) are never touched, regardless of name.
514
+ * Round 12: stops once `LEFTOVER_FILES_MAX + 1` matches are found across the flat + merged
515
+ * nested-Cursor scan combined — bounds read/enumerate I/O, not just the reported list.
516
+ * `truncated` says more exist beyond the capped, returned `files`.
764
517
  *
765
- * Linux case-collision disambiguation:
766
- * 1. Exact match (lowercase name == any canonical name): survives.
767
- * 2. Case-variant with MARKER (marker file, no exact canonical match): unlinked.
768
- * 3. Ambiguous (zero exact, multiple case-variants with MARKER):
769
- * newest mtime wins; all others are unlinked; a collision TEN is
770
- * appended to the session capture queue (not fired inline).
771
- *
772
- * Returns a list of unlink results so the caller can log/report them.
773
- *
774
- * @param cwd Project root (absolute path).
775
- * @param assetNames The current set of canonical asset names from the server
776
- * (e.g. ["Setup-ProductBrain", "chain-rules"]).
777
- * @param log Progress log function.
778
- * @param logErr Error log function.
518
+ * @param cursorSkillNames Cursor-specific, SKILL-kind-only canon (falls back to `assetNames`).
519
+ * @param exactRelativePaths Round 11: exact write-plan paths (forward-slash), exempted from both
520
+ * checks — covers asset-less generated files and a canonical raw name not already normalized.
779
521
  */
780
- export function resolveProjectionCollision(cwd, assetNames, log, logErr) {
781
- // Target directories by extension suffix.
522
+ export function findLeftoverProjections(cwd, assetNames, allowedTargets, cursorSkillNames, exactRelativePaths) {
782
523
  const TARGET_DIRS_BY_EXT = [
783
- { dir: join(cwd, '.cursor', 'rules'), ext: '.mdc' },
784
- { dir: join(cwd, '.claude', 'rules'), ext: '.md' },
785
- { dir: join(cwd, '.claude', 'skills'), ext: '.md' },
786
- { dir: join(cwd, '.codex', 'skills'), ext: '.md' },
524
+ { dir: join(cwd, '.cursor', 'rules'), ext: '.mdc', surface: 'cursor' },
525
+ { dir: join(cwd, '.claude', 'rules'), ext: '.md', surface: 'claude' },
526
+ { dir: join(cwd, '.claude', 'skills'), ext: '.md', surface: 'claude' },
527
+ { dir: join(cwd, '.codex', 'skills'), ext: '.md', surface: 'codex' },
787
528
  ];
788
- // Build a set of normalized canonical names (without extension) for fast lookup.
789
- // We normalize all asset names to detect case-variant collisions.
790
- // For each asset name we derive the normalized basename (the part before the ext).
791
- // canonicalNormalizedNames: Set<normalized-stem> (lowercase + slug).
792
529
  const canonicalNormalizedStems = new Set(assetNames.map((n) => normalizeMaterializedFilename(n)));
793
- const results = [];
794
- const collisionTens = [];
795
- for (const { dir, ext } of TARGET_DIRS_BY_EXT) {
530
+ const exactPaths = exactRelativePaths ?? new Set();
531
+ const leftovers = [];
532
+ let truncated = false;
533
+ scanLoop: for (const { dir, ext, surface } of TARGET_DIRS_BY_EXT) {
534
+ if (!allowedTargets.has(surface))
535
+ continue;
796
536
  if (!existsSync(dir))
797
537
  continue;
798
538
  let files;
@@ -802,14 +542,10 @@ export function resolveProjectionCollision(cwd, assetNames, log, logErr) {
802
542
  catch {
803
543
  continue; // unreadable dir — skip
804
544
  }
805
- // Group files by their normalized stem.
806
- // normalizedStem → [ { filename, fullPath } ]
807
- const groups = new Map();
808
545
  for (const filename of files) {
809
- if (!filename.endsWith(ext))
546
+ if (!filename.endsWith(ext) && !filename.endsWith(`${ext}.dormant`))
810
547
  continue;
811
548
  const fullPath = join(dir, filename);
812
- // Only operate on files that have the auto-gen MARKER.
813
549
  let content;
814
550
  try {
815
551
  content = readFileSync(fullPath, 'utf8');
@@ -818,97 +554,63 @@ export function resolveProjectionCollision(cwd, assetNames, log, logErr) {
818
554
  continue; // unreadable file — skip
819
555
  }
820
556
  if (!content.includes(MARKER))
821
- continue; // user-owned — never touch
822
- const stem = basename(filename, ext);
557
+ continue; // user-owned — never reported
558
+ const isDormant = filename.endsWith('.dormant');
559
+ // A live file the write plan targets by this exact path is canonical by construction.
560
+ if (!isDormant) {
561
+ const relativePath = relative(cwd, fullPath).split(sep).join('/');
562
+ if (exactPaths.has(relativePath))
563
+ continue;
564
+ }
565
+ const stem = basename(isDormant ? filename.slice(0, -'.dormant'.length) : filename, ext);
823
566
  const normalizedStem = normalizeMaterializedFilename(stem);
824
- const group = groups.get(normalizedStem) ?? [];
825
- group.push({ filename, fullPath });
826
- groups.set(normalizedStem, group);
827
- }
828
- // Evaluate each normalized stem group.
829
- for (const [normalizedStem, members] of groups) {
830
- const isKnownCanonical = canonicalNormalizedStems.has(normalizedStem);
831
- if (!isKnownCanonical) {
832
- // All members of this group are orphans (no canonical asset with this stem).
833
- // Unlink them all — they're stale projections of an asset no longer in the server.
834
- for (const { filename, fullPath } of members) {
835
- try {
836
- unlinkSync(fullPath);
837
- log(`Orphan unlinked: ${fullPath}`);
838
- results.push({ action: 'unlinked', filePath: fullPath, reason: 'orphan-no-canonical-match' });
839
- }
840
- catch (err) {
841
- logErr(`Warning: could not unlink orphan ${fullPath} — ${err instanceof Error ? err.message : String(err)}`);
842
- results.push({ action: 'kept', filePath: fullPath, reason: 'unlink-failed' });
843
- }
844
- }
845
- continue;
567
+ let entry = null;
568
+ if (!canonicalNormalizedStems.has(normalizedStem)) {
569
+ entry = { path: fullPath, reason: 'orphan — no canonical asset matches this name' };
846
570
  }
847
- // The stem IS known canonical. Check for case-collision.
848
- if (members.length === 1) {
849
- // Single file — no collision.
850
- results.push({ action: 'kept', filePath: members[0].fullPath, reason: 'canonical-exact' });
851
- continue;
571
+ else if (isDormant) {
572
+ entry = { path: fullPath, reason: 'leftover .dormant file from an older binary version' };
852
573
  }
853
- // Multiple files with the same normalized stem → case-collision.
854
- // Rule: exact match (filename stem === normalized stem, i.e. already lowercase) wins.
855
- const exactMatches = members.filter(({ filename }) => {
856
- const stem = basename(filename, ext);
857
- return stem === normalizedStem; // lowercase-equal means already normalized
858
- });
859
- if (exactMatches.length === 1) {
860
- // Rule 1: exactly one exact match → keep it, unlink all case-variants.
861
- const keeper = exactMatches[0];
862
- results.push({ action: 'kept', filePath: keeper.fullPath, reason: 'case-exact-match-wins' });
863
- for (const member of members) {
864
- if (member.fullPath === keeper.fullPath)
865
- continue;
866
- try {
867
- unlinkSync(member.fullPath);
868
- log(`Case-variant unlinked: ${member.fullPath} (kept: ${keeper.filename})`);
869
- results.push({ action: 'unlinked', filePath: member.fullPath, reason: 'case-variant-unlinked' });
870
- }
871
- catch (err) {
872
- logErr(`Warning: could not unlink case-variant ${member.fullPath} — ${err instanceof Error ? err.message : String(err)}`);
873
- results.push({ action: 'kept', filePath: member.fullPath, reason: 'unlink-failed' });
874
- }
875
- }
876
- continue;
574
+ else if (stem !== normalizedStem) {
575
+ entry = { path: fullPath, reason: `stale case/punctuation variant — canonical form is "${normalizedStem}${ext}"` };
877
576
  }
878
- // Rule 3: ambiguous — zero exact matches (or multiple exact matches, which
879
- // can't happen on a case-sensitive FS). Newest mtime wins.
880
- // Sort by mtime descending: highest mtime = newest = winner.
881
- const withStats = members.map(({ filename, fullPath }) => {
882
- try {
883
- const { mtimeMs } = statSync(fullPath);
884
- return { filename, fullPath, mtimeMs };
885
- }
886
- catch {
887
- return { filename, fullPath, mtimeMs: 0 };
888
- }
889
- });
890
- withStats.sort((a, b) => b.mtimeMs - a.mtimeMs);
891
- const winner = withStats[0];
892
- log(`Case-collision ambiguous for ${normalizedStem}${ext}: newest mtime wins (${winner.filename})`);
893
- results.push({ action: 'collision-ten', filePath: winner.fullPath, reason: 'ambiguous-newest-mtime-wins' });
894
- const tenMsg = `Handshake case-collision: ambiguous filename for stem "${normalizedStem}${ext}" ` +
895
- `(${members.map((m) => m.filename).join(', ')}). ` +
896
- `Kept newest: ${winner.filename}. Consider renaming to ${normalizedStem}${ext}.`;
897
- collisionTens.push(tenMsg);
898
- for (const member of withStats.slice(1)) {
899
- try {
900
- unlinkSync(member.fullPath);
901
- log(`Case-variant (ambiguous) unlinked: ${member.fullPath}`);
902
- results.push({ action: 'unlinked', filePath: member.fullPath, reason: 'ambiguous-case-variant-unlinked' });
903
- }
904
- catch (err) {
905
- logErr(`Warning: could not unlink ambiguous case-variant ${member.fullPath} — ${err instanceof Error ? err.message : String(err)}`);
906
- results.push({ action: 'kept', filePath: member.fullPath, reason: 'unlink-failed' });
907
- }
577
+ if (!entry)
578
+ continue;
579
+ leftovers.push(entry);
580
+ if (leftovers.length > LEFTOVER_FILES_MAX) {
581
+ truncated = true;
582
+ leftovers.pop();
583
+ break scanLoop;
908
584
  }
909
585
  }
910
586
  }
911
- return { results, collisionTens };
587
+ // Nested Cursor skills — extracted to its own module (STD-2/DEC-1504 shrink-only offset).
588
+ // Skipped once the flat scan already hit the cap; the remaining budget keeps the combined
589
+ // total across both scans stopping at LEFTOVER_FILES_MAX + 1.
590
+ if (!truncated && allowedTargets.has('cursor')) {
591
+ const nested = findLeftoverCursorSkills(cwd, cursorSkillNames ?? assetNames, LEFTOVER_FILES_MAX - leftovers.length);
592
+ leftovers.push(...nested.files);
593
+ truncated = nested.truncated;
594
+ }
595
+ return { files: leftovers, truncated };
596
+ }
597
+ /** Round 13 (Codex P1, security): strips a `user:token@` userinfo segment from an https remote
598
+ * so a credential never reaches JSON output. SSH remotes (`git@host:...`) are untouched — that
599
+ * `git@` is a fixed public username, not a secret. */
600
+ function redactGitRemote(remote) {
601
+ return remote ? remote.replace(/^(https?:\/\/)[^@/]+@/i, '$1') : remote;
602
+ }
603
+ /** Round 13 (Codex P1, security): `pb --json handshake` serialized the report directly — leaking
604
+ * an HTTPS git-remote credential and raw Convex `_id`/`_creationTime` on `matchedEntries` (never
605
+ * went through the shared runner's `stripConvexInternals`). One public shape, both JSON paths. */
606
+ function toPublicJsonReport(report) {
607
+ return stripConvexInternals({ ...report, repo: { ...report.repo, gitRemote: redactGitRemote(report.repo.gitRemote) } });
608
+ }
609
+ /** TASK-554 (RULE-659): getOrientView always serves the briefing's facts; a view without them is a broken contract. */
610
+ function servedBriefing(view) {
611
+ if (view.briefing)
612
+ return view.briefing;
613
+ throw new CLIError('The orient view carried no briefing; getOrientView always serves one.', { code: ErrorCode.INTERNAL, category: 'internal' });
912
614
  }
913
615
  export async function runHandshake(options = {}) {
914
616
  const config = await getConfigOrGuide(async () => { await runHandshake(options); });
@@ -917,16 +619,17 @@ export async function runHandshake(options = {}) {
917
619
  const cwd = process.cwd();
918
620
  const force = options.force ?? false;
919
621
  const dryRun = options.dryRun ?? false;
920
- // Preview mode: default when neither --apply nor --dry-run is passed.
921
- // --dry-run is kept as a backward-compat alias for preview (same behavior).
622
+ // Preview mode: default when neither --apply nor --dry-run is passed (--dry-run is a backward-compat alias).
922
623
  const preview = !options.apply && !dryRun;
923
624
  const applyMode = options.apply === true && !dryRun;
924
625
  const level = options.level;
626
+ // `quiet` gates the final report write (`--json` alone still prints). `suppressProgress`
627
+ // also silences stdout log() prose in JSON mode. logErr() stays on `quiet` alone (stderr).
925
628
  const quiet = options.quiet ?? false;
926
- const generate = options.generate ?? false;
629
+ const suppressProgress = quiet || isJsonMode();
927
630
  const timestamp = new Date().toISOString();
928
- // Helper: emit progress line only when not quiet (used when handshake is a sub-step)
929
- const log = (msg) => { if (!quiet)
631
+ // Helper: emit progress line only when not suppressed. logErr is gated on `quiet` alone.
632
+ const log = (msg) => { if (!suppressProgress)
930
633
  process.stdout.write(msg + '\n'); };
931
634
  const logErr = (msg) => { if (!quiet)
932
635
  process.stderr.write(msg + '\n'); };
@@ -945,6 +648,21 @@ export async function runHandshake(options = {}) {
945
648
  if (repo.detectedStack.length > 0) {
946
649
  log(`Stack: ${repo.detectedStack.join(', ')}`);
947
650
  }
651
+ const startupSignals = deriveHandshakeStartupSignals(cwd, options.startupSignals ?? {});
652
+ const orientArgs = { tier: 'standard' };
653
+ if (options.invocationPath)
654
+ orientArgs.invocationPath = options.invocationPath;
655
+ if (Object.keys(startupSignals).length > 0) {
656
+ orientArgs.startupSignals = startupSignals;
657
+ if (startupSignals.taskText)
658
+ orientArgs.task = startupSignals.taskText;
659
+ }
660
+ // Scopes the role rule lists this orient call returns to THIS session, not a sibling's.
661
+ const activeSession = readSession();
662
+ if (activeSession?.sessionId)
663
+ orientArgs.sessionId = activeSession.sessionId;
664
+ if (activeSession?.conversationId)
665
+ orientArgs.conversationId = activeSession.conversationId;
948
666
  // 2. Fetch orient view + workspace readiness in parallel (budget max +200ms added latency)
949
667
  log('Fetching workspace context...');
950
668
  let orientView = null;
@@ -952,7 +670,7 @@ export async function runHandshake(options = {}) {
952
670
  try {
953
671
  const workspaceReadinessPromise = kernelCall('chain.workspaceReadiness', {}).catch(() => null);
954
672
  const [orientResult, readinessRaw] = await Promise.all([
955
- kernelCall('chain.getOrientView', { tier: 'standard' }).catch((err) => {
673
+ kernelCall('chain.getOrientView', orientArgs).catch((err) => {
956
674
  logErr(`Warning: could not fetch workspace context — ${err instanceof Error ? err.message : err}`);
957
675
  logErr('Continuing with limited context (Chain search + portable knowledge only).');
958
676
  return null;
@@ -967,7 +685,7 @@ export async function runHandshake(options = {}) {
967
685
  logErr('Continuing with limited context (Chain search + portable knowledge only).');
968
686
  }
969
687
  if (workspaceProfile) {
970
- log(`Workspace profile: stage=${workspaceProfile.stage}, entries=${workspaceProfile.totalEntries}, governance=${workspaceProfile.governanceMode}`);
688
+ log(`Workspace profile: entries=${workspaceProfile.totalEntries}`);
971
689
  }
972
690
  // 3. Build search queries from repo context
973
691
  const searchQueries = [];
@@ -989,9 +707,7 @@ export async function runHandshake(options = {}) {
989
707
  const searchResults = await Promise.all(uniqueQueries.map((q) => kernelCall('chain.searchEntries', { query: q }).catch(() => [])));
990
708
  matchedEntries = deduplicateEntries(searchResults.flat());
991
709
  }
992
- // 5. Read canonical skills & rules — DB-first (WP-345 S0c, TEN-1459), FS fallback.
993
- // Primary: query setup.listAssetsForUser from DB (workspace SSOT).
994
- // Fallback: read from .productbrain/ filesystem (legacy — used when DB is empty or unavailable).
710
+ // 5. Read canonical skills & rules — DB-first (WP-345 S0c, TEN-1459): query setup.listAssetsForUser, FS fallback.
995
711
  const pbDir = join(cwd, '.productbrain');
996
712
  const manifestStatus = readManifestStatus(pbDir);
997
713
  const manifest = manifestStatus.manifest;
@@ -1030,329 +746,17 @@ export async function runHandshake(options = {}) {
1030
746
  const authorityCanWrite = manifestStatus.mode === 'project' || manifestStatus.mode === 'govern';
1031
747
  const authorityPreviewOnly = applyMode && !authorityCanWrite;
1032
748
  const writeMode = applyMode && authorityCanWrite;
1033
- let dbSkills = [];
1034
- let dbRules = [];
1035
- let usedDbSource = false;
1036
- let dbAssetRows = [];
1037
- // WP-379 S4: dormant assets (gate-failed) — their on-disk files get the dormant marker.
1038
- let dormantDbAssetRows = [];
1039
- // WP-428 S2 (Finding #5): tracks entryIds whose body fetch from storage failed.
1040
- // Hoisted here (same scope as dbAssetRows) so both the skills/rules projection loop
1041
- // AND the authoring-file projection loop can skip failed assets.
1042
- const bodyFetchFailedEntryIds = new Set();
1043
- const dbProjectionHashes = new Map();
1044
- const syncDriftTensToFire = [];
1045
- const deferredAuthoringBaselineEntryIds = new Set();
1046
- if (writeMode) {
1047
- const authoringItems = scanSetupAuthoringFiles(pbDir);
1048
- if (authoringItems.length > 0) {
1049
- // WP-428 S2 (Critical #1): ingestSetupAssetsBatch is an internalMutation — it cannot
1050
- // call ctx.storage.store(). We now call ingestSetupAssetWithBody (action) per-asset so
1051
- // each asset gets bodyStorageId written. This loses intra-batch collision detection;
1052
- // canonical-id collision check is now client-side before dispatch.
1053
- //
1054
- // Client-side collision detection (replaces server-side DEC-954 check in the batch mutation):
1055
- const idToPaths = new Map();
1056
- for (const item of authoringItems) {
1057
- const canonicalId = item.frontmatterId?.trim() || item.derivedEntryId;
1058
- const paths = idToPaths.get(canonicalId) ?? [];
1059
- paths.push(item.filePath);
1060
- idToPaths.set(canonicalId, paths);
1061
- }
1062
- const conflictingPaths = new Set();
1063
- for (const [, paths] of idToPaths) {
1064
- if (paths.length > 1) {
1065
- for (const p of paths)
1066
- conflictingPaths.add(p);
1067
- }
1068
- }
1069
- if (conflictingPaths.size > 0) {
1070
- logErr(`Setup authoring import partial: ${conflictingPaths.size} file(s) refused for duplicate setup id. ` +
1071
- [...conflictingPaths].join(', '));
1072
- }
1073
- const itemsToIngest = authoringItems.filter((item) => !conflictingPaths.has(item.filePath));
1074
- if (itemsToIngest.length > 0) {
1075
- try {
1076
- // Parallel uploads — concurrency limit 10 to avoid overwhelming the gateway.
1077
- const CONCURRENCY = 10;
1078
- const ingestResults = [];
1079
- for (let i = 0; i < itemsToIngest.length; i += CONCURRENCY) {
1080
- const batch = itemsToIngest.slice(i, i + CONCURRENCY);
1081
- const settled = await Promise.allSettled(batch.map(async (item) => {
1082
- const result = await kernelCall('setup.ingestSetupAssetWithBody', {
1083
- entryId: item.derivedEntryId,
1084
- frontmatterId: item.frontmatterId,
1085
- name: item.name,
1086
- description: item.description,
1087
- body: item.body,
1088
- assetKind: item.assetKind,
1089
- triggers: item.triggers,
1090
- semanticRefs: item.semanticRefs,
1091
- authoringPath: relative(pbDir, item.filePath).split(sep).join('/'),
1092
- });
1093
- return { filePath: item.filePath, ...result };
1094
- }));
1095
- for (const r of settled) {
1096
- if (r.status === 'fulfilled') {
1097
- ingestResults.push(r.value);
1098
- if (r.value.conflict === 'repo-wins') {
1099
- syncDriftTensToFire.push(`Repo authoring file won setup sync conflict for ${r.value.entryId} at ${r.value.filePath}.`);
1100
- logErr(`Warning: repo authoring file won sync conflict for ${r.value.entryId}; DB edit was overwritten.`);
1101
- }
1102
- }
1103
- else {
1104
- trackEvent('setup.authoring_import.item_failed', { error: r.reason instanceof Error ? r.reason.message : String(r.reason) });
1105
- logErr(`Warning: setup authoring import failed for one asset — ${r.reason instanceof Error ? r.reason.message : String(r.reason)}`);
1106
- }
1107
- }
1108
- }
1109
- if (ingestResults.length > 0) {
1110
- log(`Setup authoring import: ${ingestResults.length} file(s) checked (with bodyStorageId).`);
1111
- }
1112
- }
1113
- catch (err) {
1114
- trackEvent('setup.authoring_import.failed', { error: err instanceof Error ? err.message : String(err) });
1115
- logErr(`Warning: setup authoring import failed — ${err instanceof Error ? err.message : String(err)}`);
1116
- }
1117
- }
1118
- }
1119
- }
1120
- try {
1121
- // WP-379 S4: listAssetsForUser now returns { activeAssets, dormantAssets }.
1122
- // Wire format changed from DbAsset[] to { activeAssets: DbAsset[], dormantAssets: DbAsset[] }.
1123
- // Fall back to empty arrays if the server returns the old flat-array shape (graceful degradation).
1124
- const rawResponse = await kernelCall('setup.listAssetsForUser', {}).catch(() => null);
1125
- let dbAssets = [];
1126
- if (rawResponse !== null) {
1127
- if (Array.isArray(rawResponse)) {
1128
- // Pre-S4 server — treat entire response as active assets with no dormant list.
1129
- dbAssets = rawResponse;
1130
- dormantDbAssetRows = [];
1131
- }
1132
- else {
1133
- dbAssets = rawResponse.activeAssets ?? [];
1134
- dormantDbAssetRows = rawResponse.dormantAssets ?? [];
1135
- }
1136
- }
1137
- if (dbAssets.length > 0) {
1138
- dbAssetRows = dbAssets;
1139
- // WP-428 S2: body is no longer inline — fetch from storage per-asset when bodyStorageId is set.
1140
- // Projectable assets: non-disabled skill/rule/hook entries. Fetch bodies in parallel (bounded).
1141
- const projectableAssets = dbAssets.filter((a) => !a.disabledByOwner && (a.assetKind === 'skill' || a.assetKind === 'rule' || a.assetKind === 'hook'));
1142
- const assetsNeedingBodyFetch = projectableAssets.filter((a) => a.bodyStorageId);
1143
- const bodyFetchMap = new Map(); // entryId → body
1144
- // WP-428 S2 (Finding #5/#12): track fetch-failed assets so we can skip their projection.
1145
- // Failed entryIds are excluded from dbSkills/dbRules — no empty body written, no lastProjectedHash update.
1146
- // bodyFetchFailedEntryIds is declared at outer scope (also used by authoring-file projection loop).
1147
- if (assetsNeedingBodyFetch.length > 0) {
1148
- log(`Fetching ${assetsNeedingBodyFetch.length} asset body(s) from storage...`);
1149
- const bodyFetchResults = await Promise.allSettled(assetsNeedingBodyFetch.map(async (asset) => {
1150
- const result = await kernelCall('setup.fetchAssetBody', { bodyStorageId: asset.bodyStorageId });
1151
- return { entryId: asset.entryId, name: asset.name, body: result.body };
1152
- }));
1153
- for (let i = 0; i < bodyFetchResults.length; i++) {
1154
- const result = bodyFetchResults[i];
1155
- if (result.status === 'fulfilled') {
1156
- bodyFetchMap.set(result.value.entryId, result.value.body);
1157
- }
1158
- else {
1159
- // WP-428 S2 (Finding #12): include entryId and name in the warning (Finding #5: skip projection).
1160
- const asset = assetsNeedingBodyFetch[i];
1161
- logErr(`Warning: failed to fetch body for ${asset.entryId} (${asset.name}) — ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`);
1162
- bodyFetchFailedEntryIds.add(asset.entryId);
1163
- }
1164
- }
1165
- if (bodyFetchFailedEntryIds.size > 0) {
1166
- // WP-439 S4: strict-by-default. Any body-fetch failure is a hard
1167
- // failure unless --lenient is passed. The strict path surfaces an
1168
- // actionable pointer at the audit/repair command operators can run
1169
- // to diagnose and fix orphaned setup-asset rows.
1170
- const failedList = [...bodyFetchFailedEntryIds].join(', ');
1171
- if (options.lenient) {
1172
- logErr(`Warning: ${bodyFetchFailedEntryIds.size} asset(s) skipped due to body fetch failure (--lenient): ${failedList}`);
1173
- }
1174
- else {
1175
- throw new CLIError(`${bodyFetchFailedEntryIds.size} asset(s) failed body fetch: ${failedList}. ` +
1176
- `Run \`pb setup-audit\` to diagnose, then \`pb setup-audit --repair\` to reseed. ` +
1177
- `Pass --lenient to suppress this and continue with affected entries skipped (legacy behaviour).`, { code: ErrorCode.INTERNAL, category: 'internal' });
1178
- }
1179
- }
1180
- }
1181
- // Map DB assets to CanonicalSkill/CanonicalRule shapes
1182
- for (const asset of dbAssets) {
1183
- if (asset.disabledByOwner)
1184
- continue;
1185
- // WP-428 S2 (Finding #5): skip projection for assets whose body fetch failed.
1186
- // Do NOT write empty body to disk and do NOT update lastProjectedHash.
1187
- if (bodyFetchFailedEntryIds.has(asset.entryId))
1188
- continue;
1189
- // WP-428 S2: resolve body — prefer storage-fetched body, fall back to inline body (pre-S2 servers).
1190
- // Fallback: pre-S2 servers (no bodyStorageId) return inline body. Once all servers are S2+, this can be deleted.
1191
- const resolvedBody = bodyFetchMap.get(asset.entryId) ?? asset.body ?? '';
1192
- if (asset.assetKind === 'skill') {
1193
- dbSkills.push({
1194
- name: asset.name,
1195
- description: asset.description,
1196
- triggers: asset.triggers ?? [],
1197
- body: resolvedBody,
1198
- sourcePath: `db:${asset.entryId}`,
1199
- });
1200
- }
1201
- else if (asset.assetKind === 'rule' || asset.assetKind === 'hook') {
1202
- dbRules.push({
1203
- name: asset.name,
1204
- description: asset.description,
1205
- autoApply: false,
1206
- body: resolvedBody,
1207
- sourcePath: `db:${asset.entryId}`,
1208
- });
1209
- }
1210
- }
1211
- usedDbSource = true;
1212
- log(`Setup assets: ${dbSkills.length} skills, ${dbRules.length} rules/hooks from DB (WP-345 DB-first path)`);
1213
- if (dormantDbAssetRows.length > 0) {
1214
- log(`Setup assets: ${dormantDbAssetRows.length} dormant (gate-filtered) asset(s) will be marked on disk`);
1215
- }
1216
- }
1217
- }
1218
- catch {
1219
- // DB source unavailable — silently fall through to FS path
1220
- }
1221
- const allSkills = usedDbSource ? dbSkills : readCanonicalSkills(pbDir);
1222
- const manualRules = usedDbSource ? dbRules : readCanonicalRules(pbDir);
1223
- if (!usedDbSource) {
1224
- log('Setup assets: reading from filesystem (DB source unavailable or empty)');
1225
- }
1226
- // 5a-pre. E4: Resolve semantic refs in DB assets (WP-345, DEC-A, DEC-C, DEC-K)
1227
- // For each asset with semanticRefs[], resolve them via the Convex resolver and
1228
- // replace {{ref:key}} placeholders in the body. Runs in apply mode only (not preview).
1229
- // NG11: PostHog events fire from CLI side only (never inside Convex mutations).
1230
- if (usedDbSource && writeMode) {
1231
- const projectableDbAssets = dbAssetRows.filter((a) => !a.disabledByOwner && (a.assetKind === 'skill' || a.assetKind === 'rule' || a.assetKind === 'hook'));
1232
- const assetsWithRefs = projectableDbAssets.filter((a) => a.semanticRefs && a.semanticRefs.length > 0);
1233
- if (assetsWithRefs.length > 0) {
1234
- log(`Resolving semantic refs for ${assetsWithRefs.length} asset(s)...`);
1235
- // Collect unique ref keys across all assets
1236
- const allRefKeys = [...new Set(assetsWithRefs.flatMap((a) => a.semanticRefs))];
1237
- // Resolve all refs in a single batch call. Shape: SetupRefResolution[]
1238
- // (DEC-767 / WP-354 Build-Order #6 — kind + status discriminator).
1239
- let resolvedRefs = [];
1240
- try {
1241
- resolvedRefs = await kernelCall('setup.resolveSemanticRefs', { semanticRefs: allRefKeys });
1242
- }
1243
- catch (err) {
1244
- trackEvent('setup.refs.resolve_failed', { error: err instanceof Error ? err.message : String(err) });
1245
- logErr(`Warning: could not resolve semantic refs — ${err instanceof Error ? err.message : String(err)}`);
1246
- }
1247
- // Build resolved map: canonicalKey → display name. Only required refs
1248
- // count as unresolved warnings; seed/unknown refs are not gates.
1249
- const resolvedMap = new Map();
1250
- let unresolvedCount = 0;
1251
- for (const result of resolvedRefs) {
1252
- if (result.status === 'resolved' && result.localEntryId) {
1253
- resolvedMap.set(result.ref, result.localEntryId);
1254
- trackEvent('skill.ref.resolved', { ref: result.ref, kind: result.kind });
1255
- }
1256
- else if (result.status === 'unsupported-future') {
1257
- // seed: refs are explicitly future scope per WP-354 Build-Order #6 — not a warning.
1258
- trackEvent('skill.ref.future', { ref: result.ref, kind: result.kind });
1259
- }
1260
- else if (result.required) {
1261
- unresolvedCount++;
1262
- trackEvent('skill.ref.unresolved', { ref: result.ref, kind: result.kind, status: result.status });
1263
- }
1264
- }
1265
- if (unresolvedCount > 0) {
1266
- logErr(`Warning: ${unresolvedCount} required semantic ref(s) could not be resolved.`);
1267
- }
1268
- // Projection must preserve ref tokens as portable machine-readable refs.
1269
- // resolvedMap is only used for validation/telemetry here; generated setup
1270
- // artifacts keep {{ref:domain:...}} / {{ref:entry:...}} intact.
1271
- }
1272
- // Compute projection hash for each projected DB asset (DEC-K).
1273
- // The stored hash is sha256 of the normalized resolved asset body; DB persistence
1274
- // is deferred until the write loop confirms a matching file was emitted.
1275
- // Strip existing hash trailer and timestamp lines, normalize to LF, then hash.
1276
- const HASH_TRAILER_REGEX = /^<!--\s*pb-hash:.*-->\s*$/gm;
1277
- const TIMESTAMP_REGEX = /^<!--\s*pb-generated-at:.*-->\s*$/gm;
1278
- for (const rawAsset of projectableDbAssets) {
1279
- const resolvedAsset = [...dbSkills, ...dbRules].find((a) => a.sourcePath === `db:${rawAsset.entryId}`);
1280
- if (!resolvedAsset)
1281
- continue;
1282
- try {
1283
- // Build the projected body (what will be written to disk)
1284
- const projectedBody = resolvedAsset.body;
1285
- // Normalize: strip existing hash/timestamp trailers, convert to LF
1286
- const normalized = projectedBody
1287
- .replace(HASH_TRAILER_REGEX, '')
1288
- .replace(TIMESTAMP_REGEX, '')
1289
- .replace(/\r\n/g, '\n')
1290
- .replace(/\r/g, '\n')
1291
- .trimEnd();
1292
- // Compute sha256 hash
1293
- const hash = createHash('sha256').update(normalized, 'utf8').digest('hex');
1294
- const hashTrailer = `<!-- pb-hash: sha256:${hash} -->`;
1295
- // Append hash trailer to the projected body
1296
- resolvedAsset.body = `${normalized}\n${hashTrailer}`;
1297
- dbProjectionHashes.set(rawAsset.entryId, {
1298
- hash: `sha256:${hash}`,
1299
- assetKind: rawAsset.assetKind,
1300
- });
1301
- // Drift detection: compare against last known hash
1302
- if (rawAsset.lastProjectedHash && rawAsset.lastProjectedHash !== `sha256:${hash}`) {
1303
- trackEvent('skill.drift.detected', {
1304
- entryId: rawAsset.entryId,
1305
- assetKind: rawAsset.assetKind,
1306
- });
1307
- log(`Drift detected for asset ${rawAsset.entryId} — projecting updated version.`);
1308
- }
1309
- trackEvent('skill.projection.succeeded', {
1310
- entryId: rawAsset.entryId,
1311
- assetKind: rawAsset.assetKind,
1312
- });
1313
- }
1314
- catch (err) {
1315
- trackEvent('skill.projection.failed', {
1316
- entryId: rawAsset.entryId,
1317
- assetKind: rawAsset.assetKind,
1318
- });
1319
- logErr(`Warning: projection failed for ${rawAsset.entryId} — ${err instanceof Error ? err.message : String(err)}`);
1320
- }
1321
- }
1322
- }
1323
- // 5a. Optionally fetch and merge Chain-derived rules (--generate flag)
1324
- let chainRulesStats = null;
1325
- let chainGaps = [];
749
+ // TASK-554 (TEN-4036): materialize governs the coding-tool surfaces (DEC-951). PB's own files
750
+ // under .productbrain/ (context.md, briefing.md, generated/) refresh on every --apply wherever
751
+ // that folder exists; mode `off` means it does not (DEC-955), and then nothing is created.
752
+ const pbOwnedWriteMode = applyMode && manifestStatus.mode !== 'off';
753
+ // Skills and rules are read from the filesystem only (WP-776 S3f, DEC-1771).
754
+ const allSkills = readCanonicalSkills(pbDir);
755
+ const manualRules = readCanonicalRules(pbDir);
756
+ // The --generate flag and its chain-rules generator are gone: the everyone/team/role rule lists
757
+ // (DEC-1774) are the rule-delivery path (context.md, chain.mdc, everyone-rules.md).
1326
758
  let allRules = manualRules;
1327
- if (generate) {
1328
- log('Generating Chain-derived rules...');
1329
- const chainResult = await generateChainRules(kernelCall, manualRules);
1330
- if (chainResult.sentinel) {
1331
- // MCP unavailable — inject sentinel rule and warn
1332
- allRules = [...manualRules, chainResult.sentinel];
1333
- logErr('Warning: Chain MCP unavailable — generated rules are disabled. Sentinel rule injected.');
1334
- }
1335
- else {
1336
- // Merge generated rules after manual rules (manual takes precedence on dedup)
1337
- allRules = [...manualRules, ...chainResult.rules];
1338
- chainRulesStats = chainResult.stats;
1339
- chainGaps = chainResult.gaps;
1340
- const { generatedRules, suppressedByManual, suppressedByZeroEntries } = chainResult.stats;
1341
- log(`Chain-derived rules: ${generatedRules} generated, ${suppressedByManual} suppressed by manual, ${suppressedByZeroEntries} gaps`);
1342
- if (chainGaps.length > 0) {
1343
- log(`Gaps (no matching governance entries): ${chainGaps.join(', ')}`);
1344
- }
1345
- // Diff: compare current state against previous run
1346
- const previousState = loadPreviousState(pbDir);
1347
- const currentState = buildCurrentState(chainResult.rules, chainResult.classified);
1348
- saveHandshakeState(pbDir, chainResult.rules, chainResult.classified);
1349
- const diff = diffHandshakeState(currentState, previousState);
1350
- const diffText = formatDiff(diff);
1351
- log(diffText);
1352
- }
1353
- }
1354
- // 5b. Read personal layer (WP-310 E2) — machine-local rules/skills from .productbrain/.local/
1355
- // Returns [] when the directory is absent. All returned entries have persist: 'local'.
759
+ // 5b. Read personal layer (WP-310 E2) — machine-local rules/skills from .productbrain/.local/, [] if absent, all persist: 'local'.
1356
760
  const personalRules = readPersonalLayer(pbDir);
1357
761
  if (personalRules.length > 0) {
1358
762
  // Name collision detection — warn when a personal rule overrides a team rule
@@ -1375,11 +779,12 @@ export async function runHandshake(options = {}) {
1375
779
  }
1376
780
  allSkills.push(...personalSkills);
1377
781
  }
1378
- // 5d. Load method registry (WP-310 E4) — only when manifest is present.
782
+ // 5d. Load method registry (WP-310 E4) — only when manifest is present. Unrelated to the
783
+ // setup-assets system (WP-329's own "methods" Chain collection, no setup.* coupling) — kept.
1379
784
  let registrySource;
1380
785
  let registryStale;
1381
786
  if (manifest) {
1382
- const registryResult = await loadMethodRegistry(manifest.method_source, kernelCall).catch(() => null);
787
+ const registryResult = await loadMethodRegistry().catch(() => null);
1383
788
  if (registryResult) {
1384
789
  registrySource = registryResult.source;
1385
790
  registryStale = registryResult.stale;
@@ -1390,24 +795,10 @@ export async function runHandshake(options = {}) {
1390
795
  // Compute adoption counts for report (only meaningful when manifest is present)
1391
796
  const adoptedRulesCount = manifest ? adoptionFilteredRules.length : undefined;
1392
797
  const rejectedRulesCount = manifest ? allRules.length - adoptionFilteredRules.length : undefined;
1393
- // Apply level filtering with stage-gating (after adoption filter, before target filtering in write loop)
1394
- // Stage caps the effective level: blank→beginner, seed→intermediate, grounded+→expert.
1395
- // If stage caps below the requested level, log it so the user knows why items were dropped.
1396
- const profileStage = workspaceProfile?.stage;
1397
- const levelFilteredSkills = filterByLevel(adoptionFilteredSkills, level, profileStage);
1398
- const levelFilteredRules = filterByLevel(adoptionFilteredRules, level, profileStage);
1399
- // Log when stage gating changes the effective level
1400
- if (profileStage) {
1401
- const stageCap = STAGE_TO_MAX_LEVEL[profileStage];
1402
- if (stageCap) {
1403
- const requestedIdx = level ? LEVEL_ORDER.indexOf(level) : LEVEL_ORDER.length - 1;
1404
- const capIdx = LEVEL_ORDER.indexOf(stageCap);
1405
- if (capIdx < requestedIdx) {
1406
- log(`Stage "${profileStage}" caps level from ${level || 'expert'} to ${stageCap}`);
1407
- }
1408
- }
1409
- }
1410
- // Apply when-condition filtering (stage-aware, workspace profile + repo context)
798
+ // Level filtering: requested level only (WP-762 C4e-2, DEC-1800 — no more stage cap).
799
+ const levelFilteredSkills = filterByLevel(adoptionFilteredSkills, level);
800
+ const levelFilteredRules = filterByLevel(adoptionFilteredRules, level);
801
+ // Apply when-condition filtering (workspace profile + repo context)
1411
802
  const canonicalSkills = levelFilteredSkills.filter((skill) => {
1412
803
  const result = evaluateConditions(skill.conditions ?? {}, workspaceProfile, repo);
1413
804
  if (dryRun && !result.included) {
@@ -1428,26 +819,23 @@ export async function runHandshake(options = {}) {
1428
819
  if (dryRun && canonicalRules.length > 0) {
1429
820
  log(` INCLUDED rules: ${canonicalRules.map((r) => r.name).join(', ')}`);
1430
821
  }
822
+ const noProjectionAssets = findNoProjectionAssets(canonicalSkills, canonicalRules);
1431
823
  if (canonicalSkills.length > 0 || canonicalRules.length > 0) {
1432
824
  const levelSuffix = level ? ` (level: ${level})` : '';
1433
- const stageSuffix = profileStage ? `, stage: ${profileStage}` : '';
1434
825
  const stackSuffix = repo.detectedStack.length > 0 ? `, stack: [${repo.detectedStack.join(', ')}]` : '';
1435
826
  const totalSkills = allSkills.length;
1436
827
  const totalRules = allRules.length;
1437
- log(`Portable knowledge: ${canonicalSkills.length}/${totalSkills} skills, ${canonicalRules.length}/${totalRules} rules${levelSuffix}${stageSuffix}${stackSuffix}`);
828
+ log(`Portable knowledge: ${canonicalSkills.length}/${totalSkills} skills, ${canonicalRules.length}/${totalRules} rules${levelSuffix}${stackSuffix}`);
1438
829
  }
1439
830
  // 6. Generate file contents
1440
- // Build workspace context for AGENTS.md enrichment (stage, focus, governance, entry count)
831
+ // Build workspace context for AGENTS.md enrichment (focus, entry count) — TASK-435 (C4c) deleted `stage` from it.
1441
832
  const agentsWorkspaceContext = workspaceProfile
1442
833
  ? {
1443
- stage: workspaceProfile.stage,
1444
834
  focus: orientView?.strategicContext?.currentWorkPackage ?? undefined,
1445
- governanceMode: workspaceProfile.governanceMode,
1446
835
  totalEntries: workspaceProfile.totalEntries,
1447
836
  }
1448
837
  : undefined;
1449
- // Collect codex-targeted skills for AGENTS.md skill directory.
1450
- // persist: 'local' entries are included; all projections are now local-only.
838
+ // Collect codex-targeted skills for AGENTS.md skill directory — persist: 'local' entries included (all projections are local-only now).
1451
839
  const agentsCodexSkills = canonicalSkills
1452
840
  .filter((s) => shouldEmitToTarget(s, 'codex'))
1453
841
  .map((s) => ({
@@ -1477,15 +865,27 @@ export async function runHandshake(options = {}) {
1477
865
  skills: copilotSkills.length > 0 ? copilotSkills : undefined,
1478
866
  rules: copilotRules.length > 0 ? copilotRules : undefined,
1479
867
  };
1480
- const contextContent = orientView ? generateContextMd(orientView, repo, timestamp, workspaceProfile?.stage) : null;
868
+ // TASK-554 (WP-777, DEC-1888): one workspace briefing (spine and the Everyone rule list, from
869
+ // the kernel builder) feeds context.md, everyone-rules.md and chain.mdc. `null` means the orient
870
+ // fetch failed: the two briefing files are not written (and a stale copy is removed in apply
871
+ // mode below), and chain.mdc says the briefing is unavailable.
872
+ const workspaceBriefingLines = orientView ? formatWorkspaceBriefingLines(servedBriefing(orientView), orientView.ruleLists) : null;
873
+ const contextContent = orientView && workspaceBriefingLines ? generateContextMd(orientView, workspaceBriefingLines, repo, timestamp) : null;
874
+ const everyoneRulesContent = workspaceBriefingLines ? generateEveryoneRulesMd(workspaceBriefingLines, timestamp) : null;
1481
875
  const briefingContent = generateBriefingMd(matchedEntries, repo, uniqueQueries, timestamp);
1482
876
  const agentsContent = generateAgentsMd(timestamp, {
1483
877
  workspaceContext: agentsWorkspaceContext,
1484
878
  skills: agentsCodexSkills.length > 0 ? agentsCodexSkills : undefined,
1485
879
  });
1486
880
  const claudeContent = generateClaudeMd(timestamp);
1487
- const cursorContent = generateCursorMdc(timestamp);
881
+ const cursorContent = generateCursorMdc(timestamp, workspaceBriefingLines);
1488
882
  const copilotContent = generateCopilotMd(timestamp, copilotOptions);
883
+ // DEC-1343: one committed .github/instructions/<slug>.instructions.md per copilot rule with applyTo; repo-wide rules stay above.
884
+ const copilotInstructionFiles = generateCopilotInstructionFiles(canonicalRules
885
+ .filter((r) => shouldEmitToTarget(r, 'copilot'))
886
+ // `.github/instructions/` is COMMITTED — never project a machine-local (persist: 'local') rule into it.
887
+ .filter((r) => r.persist !== 'local')
888
+ .map((r) => ({ name: r.name, body: r.body, applyTo: r.applyTo, sourcePath: r.sourcePath })), timestamp);
1489
889
  const boundaryEnforcementMode = getBoundaryEnforcementMode(manifest);
1490
890
  const boundaryManifestContent = boundaryEnforcementMode === 'advisory'
1491
891
  ? null
@@ -1494,126 +894,30 @@ export async function runHandshake(options = {}) {
1494
894
  const filesWritten = [];
1495
895
  const filesSkipped = [];
1496
896
  const previewPlan = [];
1497
- if (writeMode && usedDbSource) {
1498
- const authoringSyncState = loadAuthoringSyncState(pbDir);
1499
- let authoringSyncStateChanged = false;
1500
- const personalAssets = dbAssetRows.filter((asset) => asset.scope === 'personal' &&
1501
- !asset.disabledByOwner &&
1502
- (asset.assetKind === 'skill' || asset.assetKind === 'rule' || asset.assetKind === 'hook'));
1503
- for (const asset of personalAssets) {
1504
- // WP-428 S2 (Finding #5): skip projection for assets whose body fetch failed.
1505
- // Do NOT write the authoring file with empty body, do NOT update lastProjectedHash.
1506
- if (bodyFetchFailedEntryIds.has(asset.entryId))
1507
- continue;
1508
- const authoringPath = setupAuthoringPath(cwd, asset);
1509
- if (!authoringPath)
1510
- continue;
1511
- // Review: use relative() for correct cross-platform path computation (string-replace
1512
- // mis-fires when cwd uses a non-'/' separator), matching the dormant passes below.
1513
- const relativeAuthoringPath = relative(cwd, authoringPath);
1514
- const bodyHash = setupAuthoringAssetHash(asset);
1515
- const authoringExists = existsSync(authoringPath);
1516
- const tracked = authoringSyncState.assets[asset.entryId];
1517
- const trackedHere = tracked?.path === relativeAuthoringPath;
1518
- const trackedMatchesServer = Boolean(trackedHere && asset.lastProjectedHash && tracked?.hash === asset.lastProjectedHash);
1519
- if (!authoringExists && asset.lastProjectedHash && trackedHere && trackedMatchesServer) {
1520
- try {
1521
- const dormantResult = await kernelCall('setup.markPersonalSetupAssetDormantFromSync', { entryId: asset.entryId, expectedLastProjectedHash: tracked.hash });
1522
- if (dormantResult.action === 'conflict') {
1523
- syncDriftTensToFire.push(`Repo authoring deletion skipped for ${asset.entryId}; server baseline changed during sync, so writeback was deferred until the next DB read.`);
1524
- logErr(`Warning: authoring deletion for ${asset.entryId} was not applied because the DB baseline changed during sync.`);
1525
- deferredAuthoringBaselineEntryIds.add(asset.entryId);
1526
- continue;
1527
- }
1528
- else {
1529
- syncDriftTensToFire.push(`Repo authoring file was deleted for ${asset.entryId}; caller-owned personal setup asset marked dormant.`);
1530
- log(`Setup authoring deletion: ${asset.entryId} marked dormant.`);
1531
- delete authoringSyncState.assets[asset.entryId];
1532
- authoringSyncStateChanged = true;
1533
- continue;
1534
- }
1535
- }
1536
- catch (err) {
1537
- logErr(`Warning: could not mark ${asset.entryId} dormant after authoring deletion — ${err instanceof Error ? err.message : String(err)}`);
1538
- continue;
1539
- }
1540
- }
1541
- else if (!authoringExists && asset.lastProjectedHash && trackedHere) {
1542
- syncDriftTensToFire.push(`Repo authoring deletion skipped for ${asset.entryId}; local sync baseline is stale, so DB writeback wins.`);
1543
- logErr(`Warning: authoring deletion for ${asset.entryId} was not applied because the DB baseline changed.`);
1544
- }
1545
- const nextAuthoringContent = renderSetupAuthoringFile(asset);
1546
- if (authoringExists) {
1547
- const parsed = parseSetupAuthoringFrontmatter(readFileSync(authoringPath, 'utf8'));
1548
- const fileHash = setupAuthoringAssetHash({
1549
- entryId: parsed.frontmatterId?.trim() || asset.entryId,
1550
- name: parsed.name || asset.name,
1551
- description: parsed.description,
1552
- body: parsed.body,
1553
- assetKind: asset.assetKind,
1554
- triggers: parsed.triggers,
1555
- semanticRefs: parsed.semanticRefs,
1556
- });
1557
- if (fileHash === bodyHash) {
1558
- if (asset.lastProjectedHash !== bodyHash) {
1559
- await kernelCall('setup.updateLastProjectedHash', {
1560
- entryId: asset.entryId,
1561
- hash: bodyHash,
1562
- }).catch(() => null);
1563
- }
1564
- authoringSyncState.assets[asset.entryId] = { path: relativeAuthoringPath, hash: bodyHash };
1565
- authoringSyncStateChanged = true;
1566
- continue;
1567
- }
1568
- if (!asset.lastProjectedHash) {
1569
- syncDriftTensToFire.push(`Repo authoring file differs from DB for ${asset.entryId} at ${authoringPath} with no shared baseline; DB writeback skipped.`);
1570
- logErr(`Warning: setup authoring drift for ${asset.entryId}; DB writeback skipped because no shared baseline exists.`);
1571
- continue;
1572
- }
1573
- if (fileHash !== asset.lastProjectedHash &&
1574
- bodyHash !== asset.lastProjectedHash) {
1575
- syncDriftTensToFire.push(`Repo authoring file won setup sync conflict for ${asset.entryId} at ${authoringPath}.`);
1576
- logErr(`Warning: repo authoring file won sync conflict for ${asset.entryId}; DB writeback skipped.`);
1577
- continue;
1578
- }
1579
- if (fileHash !== asset.lastProjectedHash) {
1580
- syncDriftTensToFire.push(`Repo authoring file differs from DB baseline for ${asset.entryId} at ${authoringPath}; DB writeback skipped.`);
1581
- logErr(`Warning: setup authoring drift for ${asset.entryId}; DB writeback skipped.`);
1582
- continue;
1583
- }
1584
- }
1585
- try {
1586
- assertSetupWritePath(authoringPath, perimeterManifest);
1587
- mkdirSync(dirname(authoringPath), { recursive: true });
1588
- writeFileSync(authoringPath, nextAuthoringContent);
1589
- filesWritten.push(relativeAuthoringPath);
1590
- await kernelCall('setup.updateLastProjectedHash', {
1591
- entryId: asset.entryId,
1592
- hash: bodyHash,
1593
- }).catch(() => null);
1594
- authoringSyncState.assets[asset.entryId] = { path: relativeAuthoringPath, hash: bodyHash };
1595
- authoringSyncStateChanged = true;
1596
- }
1597
- catch (err) {
1598
- logErr(`Warning: could not write setup authoring file for ${asset.entryId} — ${err instanceof Error ? err.message : String(err)}`);
1599
- }
1600
- }
1601
- if (authoringSyncStateChanged) {
1602
- try {
1603
- saveAuthoringSyncState(pbDir, authoringSyncState);
1604
- }
1605
- catch (err) {
1606
- logErr(`Warning: could not persist setup authoring sync state — ${err instanceof Error ? err.message : String(err)}`);
1607
- }
1608
- }
1609
- }
1610
897
  const writes = [
1611
898
  ...(contextContent ? [{ path: join(cwd, '.productbrain', 'context.md'), relative: '.productbrain/context.md', content: contextContent, dirs: join(cwd, '.productbrain'), isAdapter: false }] : []),
899
+ ...(everyoneRulesContent
900
+ ? [{
901
+ path: join(cwd, '.productbrain', 'generated', 'everyone-rules.md'),
902
+ relative: '.productbrain/generated/everyone-rules.md',
903
+ content: everyoneRulesContent,
904
+ dirs: join(cwd, '.productbrain', 'generated'),
905
+ isAdapter: false,
906
+ }]
907
+ : []),
1612
908
  { path: join(cwd, '.productbrain', 'briefing.md'), relative: '.productbrain/briefing.md', content: briefingContent, isAdapter: false },
1613
909
  { path: join(cwd, 'AGENTS.md'), relative: 'AGENTS.md', content: agentsContent, isAdapter: true, target: 'codex', augmentTarget: true },
1614
910
  { path: join(cwd, 'CLAUDE.md'), relative: 'CLAUDE.md', content: claudeContent, isAdapter: true, target: 'claude', augmentTarget: true },
1615
911
  { path: join(cwd, '.cursor', 'rules', 'chain.mdc'), relative: '.cursor/rules/chain.mdc', content: cursorContent, dirs: join(cwd, '.cursor', 'rules'), isAdapter: true, target: 'cursor' },
1616
912
  { path: join(cwd, '.github', 'copilot-instructions.md'), relative: '.github/copilot-instructions.md', content: copilotContent, dirs: join(cwd, '.github'), isAdapter: true, target: 'copilot' },
913
+ ...copilotInstructionFiles.map((f) => ({
914
+ path: join(cwd, f.relativePath),
915
+ relative: f.relativePath,
916
+ content: f.content,
917
+ dirs: join(cwd, '.github', 'instructions'),
918
+ isAdapter: true,
919
+ target: 'copilot',
920
+ })),
1617
921
  ...(boundaryManifestContent ? [{
1618
922
  path: join(cwd, '.productbrain', 'generated', 'boundaries.json'),
1619
923
  relative: '.productbrain/generated/boundaries.json',
@@ -1679,54 +983,38 @@ export async function runHandshake(options = {}) {
1679
983
  dbAssetEntryId,
1680
984
  });
1681
985
  }
1682
- // Add Claude Code rule copies (filtered by target)
1683
- const claudeProfile = resolveSurfaceProfile('claude');
1684
- for (const rule of canonicalRules) {
1685
- if (!shouldEmitToTarget(rule, 'claude'))
1686
- continue;
1687
- const dbAssetEntryId = rule.sourcePath.startsWith('db:') ? rule.sourcePath.slice(3) : undefined;
1688
- writes.push({
1689
- path: join(cwd, '.claude', 'rules', `${rule.name}.md`),
1690
- relative: `.claude/rules/${rule.name}.md`,
1691
- content: generateClaudeRule(rule, claudeProfile),
1692
- dirs: join(cwd, '.claude', 'rules'),
1693
- isAdapter: true,
1694
- target: 'claude',
1695
- dbAssetEntryId,
1696
- });
1697
- }
1698
- // Add Claude Code skill router (filtered by target)
1699
- const claudeSkills = canonicalSkills.filter((s) => shouldEmitToTarget(s, 'claude'));
1700
- const skillRouterContent = generateClaudeSkillRouter(claudeSkills, claudeProfile);
1701
- if (skillRouterContent) {
1702
- writes.push({
1703
- path: join(cwd, '.claude', 'rules', 'skill-router.md'),
1704
- relative: '.claude/rules/skill-router.md',
1705
- content: skillRouterContent,
1706
- dirs: join(cwd, '.claude', 'rules'),
1707
- isAdapter: true,
1708
- target: 'claude',
1709
- });
986
+ // 7a. WP-379 S5b: find leftover projections (apply mode) — REPORT-ONLY (coordinator ruling, PR
987
+ // #912 round 10), see findLeftoverProjections's own header. WP-776 S3f: gated on writeMode
988
+ // alone now — the DB source (dbQuerySucceeded) is gone, so activeAssetNames comes from the
989
+ // filesystem-sourced allSkills/allRules (which already include the personal layer, merged in
990
+ // above) instead of dbAssetRows.
991
+ let leftoverFiles = [];
992
+ let leftoverFilesTruncated = false;
993
+ // TASK-554 (RULE-659): a failed orient fetch is named in the report, and apply removes stale briefing copies.
994
+ if (orientView === null) {
995
+ for (const path of ['.productbrain/context.md', '.productbrain/generated/everyone-rules.md'])
996
+ filesSkipped.push({ path, reason: 'briefing unavailable — the orient fetch failed' });
997
+ const stale = pbOwnedWriteMode ? removeStaleBriefingProjections(cwd) : [];
998
+ if (stale.length > 0)
999
+ logErr(`Warning: the workspace briefing could not be fetched; removed the stale ${stale.join(', ')}.`);
1710
1000
  }
1711
- // 7a. WP-379 S5b: Resolve projection collisions before writing.
1712
- // In apply mode, enumerate target dirs and unlink any auto-generated files
1713
- // whose normalized name no longer matches any active asset from the server.
1714
- // This prevents case-variant orphans from accumulating across handshakes.
1715
- // Runs only when we have a DB asset list (usedDbSource) — without a DB source,
1716
- // we can't determine which files are canonical vs. orphan.
1717
- const collisionTensToFire = [];
1718
- if (writeMode && usedDbSource) {
1719
- const activeAssetNames = dbAssetRows
1720
- .filter((a) => !a.disabledByOwner)
1721
- .map((a) => a.name);
1722
- const { collisionTens } = resolveProjectionCollision(cwd, activeAssetNames, log, logErr);
1723
- collisionTensToFire.push(...collisionTens);
1724
- }
1725
- // ── WP-436 S3: Vocab projector — fetch workspace vocab context once per handshake ──
1726
- // Source-side (.productbrain/skills/*.md + rules/*.md) stays tokenized.
1727
- // The projector resolves {{vocab:...}} tokens before writing adapter output to disk
1728
- // (.cursor/rules/, .claude/rules/, CLAUDE.md, AGENTS.md, .github/copilot-instructions.md).
1729
- // Fail-open: if vocab fetch fails, skip resolution and write raw token (no breakage).
1001
+ if (writeMode) {
1002
+ retireGeneratedProjections(cwd, log);
1003
+ const activeAssetNames = [
1004
+ ...allSkills.map((s) => s.name),
1005
+ ...allRules.map((r) => r.name),
1006
+ ];
1007
+ // Nested .cursor/skills scan gets its OWN canon: canonicalSkills is SKILL-kind only and
1008
+ // shouldEmitToTarget(_, 'cursor') respects per-skill target routing.
1009
+ const cursorSkillNames = canonicalSkills.filter((s) => shouldEmitToTarget(s, 'cursor')).map((s) => s.name);
1010
+ // Round 11: exempt exact write-plan paths from the leftover scan (see findLeftoverProjections's own doc).
1011
+ const exactRelativePaths = new Set(writes.map((w) => w.relative));
1012
+ const scanResult = findLeftoverProjections(cwd, activeAssetNames, allowedTargets, cursorSkillNames, exactRelativePaths);
1013
+ leftoverFiles = scanResult.files;
1014
+ leftoverFilesTruncated = scanResult.truncated;
1015
+ }
1016
+ // ── WP-436 S3: Vocab projector — fetch workspace vocab context once per handshake. Source-side
1017
+ // stays tokenized; resolves {{vocab:...}} before writing. Fail-open: a failed fetch writes the raw token.
1730
1018
  const handshakeVocabCtx = await getOrFetchVocabCtx(config.apiKey, async () => {
1731
1019
  try {
1732
1020
  const vocab = await kernelCall('chain.getVocabulary', {});
@@ -1743,24 +1031,12 @@ export async function runHandshake(options = {}) {
1743
1031
  }
1744
1032
  });
1745
1033
  const userOwnedSkipped = [];
1746
- const projectedHashUpdates = new Map();
1747
1034
  const cleanBucketPaths = [];
1748
1035
  const tamperedBucket = [];
1749
- const recordProjectedHash = (entryId) => {
1750
- if (!applyMode || !entryId)
1751
- return;
1752
- if (deferredAuthoringBaselineEntryIds.has(entryId))
1753
- return;
1754
- const projection = dbProjectionHashes.get(entryId);
1755
- if (projection)
1756
- projectedHashUpdates.set(entryId, projection.hash);
1757
- };
1758
- // TEN-2155: region augmentation context + symlink dedupe.
1759
- // codexActive gates the AGENTS.md skills-index pointer (region-projections.ts).
1036
+ // TEN-2155: region augmentation context + symlink dedupe — codexActive gates the AGENTS.md skills-index pointer.
1760
1037
  const regionCtx = { codexActive: allowedTargets.has('codex') };
1761
1038
  const malformedRegionPaths = [];
1762
- // If two augment targets resolve to the same inode (e.g. CLAUDE.md symlinked to AGENTS.md),
1763
- // augment only the first-seen (AGENTS.md precedes CLAUDE.md in `writes`) to avoid double-injection.
1039
+ // Same inode for two augment targets (e.g. CLAUDE.md symlinked to AGENTS.md): augment only first-seen.
1764
1040
  const seenAugmentRealpaths = new Set();
1765
1041
  const augmentTargetSkip = new Set();
1766
1042
  for (const w of writes) {
@@ -1786,9 +1062,8 @@ export async function runHandshake(options = {}) {
1786
1062
  previewPlan.push({ path: w.relative, status: 'filtered' });
1787
1063
  continue;
1788
1064
  }
1789
- // ── TEN-2155: augment user-owned CLAUDE.md / AGENTS.md with a marked PB region ──
1790
- // Runs ahead of the legacy MARKER-keyed gates. Only existing augmentable/region-present
1791
- // files are spliced here; absent + legacy-pb-managed fall through to the legacy path.
1065
+ // ── TEN-2155: augment user-owned CLAUDE.md / AGENTS.md with a marked PB region — runs ahead
1066
+ // of the legacy MARKER gates; absent/legacy-pb-managed fall through to the legacy path.
1792
1067
  if (w.augmentTarget) {
1793
1068
  const projection = REGION_PROJECTIONS[w.target];
1794
1069
  if (projection && existsSync(w.path)) {
@@ -1841,10 +1116,7 @@ export async function runHandshake(options = {}) {
1841
1116
  malformedRegionPaths.push(w.relative);
1842
1117
  continue;
1843
1118
  }
1844
- // cls 'pb-managed' → fall through to the legacy whole-file re-projection path below.
1845
- // cls 'opt-out' (file carries the pb:no-augment sentinel — e.g. this repo's committed
1846
- // constitution) → fall through too, landing on the legacy user-owned skip: left untouched,
1847
- // never spliced. This is how a file declines augmentation without losing its user-owned status.
1119
+ // cls 'pb-managed' falls through to legacy re-projection; 'opt-out' (pb:no-augment) falls through to the user-owned skip.
1848
1120
  }
1849
1121
  // absent file → fall through to legacy whole-file CREATE.
1850
1122
  }
@@ -1861,7 +1133,7 @@ export async function runHandshake(options = {}) {
1861
1133
  }
1862
1134
  continue;
1863
1135
  }
1864
- if (authorityPreviewOnly) {
1136
+ if (w.isAdapter ? authorityPreviewOnly : applyMode && !pbOwnedWriteMode) {
1865
1137
  filesSkipped.push({
1866
1138
  path: w.relative,
1867
1139
  reason: `preview-only (materialize: ${manifestStatus.mode})`,
@@ -1892,12 +1164,8 @@ export async function runHandshake(options = {}) {
1892
1164
  }
1893
1165
  continue;
1894
1166
  }
1895
- // ── WP-421 S3: defer tampered adapter writes (doneWhen #17) ──────────────
1896
- // For adapter projections that already exist on disk, classify into
1897
- // pb-managed-clean / pb-managed-tampered. Tampered = MARKER present +
1898
- // hash trailer mismatches body. Defer (do NOT overwrite); post-loop
1899
- // resolution handles them. --force bypasses the tampered defer (legacy
1900
- // semantic: explicit user opt-in to overwrite).
1167
+ // ── WP-421 S3: defer tampered adapter writes (doneWhen #17) — classify pb-managed-clean vs
1168
+ // pb-managed-tampered, deferred not overwritten; post-loop resolves. --force bypasses the defer.
1901
1169
  if (w.isAdapter && !force) {
1902
1170
  const drift = classifyDriftBucket(w.path);
1903
1171
  if (drift && drift.bucket === 'pb-managed-tampered') {
@@ -1908,7 +1176,6 @@ export async function runHandshake(options = {}) {
1908
1176
  expectedHash: drift.expectedHash,
1909
1177
  actualHash: drift.actualHash,
1910
1178
  dirs: w.dirs,
1911
- dbAssetEntryId: w.dbAssetEntryId,
1912
1179
  });
1913
1180
  // Do NOT write — defer until prompt/refusal resolves the file.
1914
1181
  continue;
@@ -1920,10 +1187,8 @@ export async function runHandshake(options = {}) {
1920
1187
  assertSetupWritePath(w.path, perimeterManifest);
1921
1188
  if (w.dirs)
1922
1189
  mkdirSync(w.dirs, { recursive: true });
1923
- // WP-436 S3: resolve {{vocab:...}} tokens before writing projected adapter files.
1924
- // Source-side (.productbrain/skills/*.md, rules/*.md) stays tokenized.
1925
- // Only adapter projections (cursor/rules, claude/rules, CLAUDE.md, AGENTS.md, etc.) get resolved.
1926
- // Fail-open: if vocabCtx is undefined, replaceVocabTokens falls back to canonicalKey literals.
1190
+ // WP-436 S3: resolve {{vocab:...}} tokens before writing projected adapter files only
1191
+ // (source-side stays tokenized). Fail-open: undefined vocabCtx falls back to canonicalKey literals.
1927
1192
  const resolvedContent = w.isAdapter
1928
1193
  ? replaceVocabTokens(w.content, handshakeVocabCtx)
1929
1194
  : w.content;
@@ -1933,34 +1198,14 @@ export async function runHandshake(options = {}) {
1933
1198
  const currentNormalized = normalizeHandshakeContentForComparison(current);
1934
1199
  if (nextNormalized === currentNormalized) {
1935
1200
  filesSkipped.push({ path: w.relative, reason: 'unchanged' });
1936
- recordProjectedHash(w.dbAssetEntryId);
1937
1201
  continue;
1938
1202
  }
1939
1203
  }
1940
1204
  writeFileSync(w.path, resolvedContent);
1941
1205
  filesWritten.push(w.relative);
1942
- recordProjectedHash(w.dbAssetEntryId);
1943
1206
  }
1944
- if (projectedHashUpdates.size > 0) {
1945
- const updates = [...projectedHashUpdates];
1946
- const results = await Promise.allSettled(updates.map(([entryId, hash]) => kernelCall('setup.updateLastProjectedHash', { entryId, hash })));
1947
- results.forEach((result, index) => {
1948
- if (result.status === 'rejected') {
1949
- const [entryId] = updates[index];
1950
- trackEvent('skill.projection.failed', {
1951
- entryId,
1952
- reason: result.reason instanceof Error ? result.reason.message : String(result.reason),
1953
- });
1954
- }
1955
- });
1956
- }
1957
- // Ordering note: this refusal runs AFTER the projected-hash flush so that files legitimately
1958
- // written THIS run still record their hashes; malformed files were never written (no hash to record).
1959
- // TEN-2155: in non-interactive apply, a malformed PB region is a refusal, not a silent skip.
1960
- // Gated on applyMode (NOT writeMode): a malformed region is a user-file INTEGRITY fault, so the
1961
- // refusal fires on any headless `--apply` regardless of materialize authority (STD-263 invariant vi —
1962
- // "headless → non-zero refusal", unqualified). writeMode would suppress it under observe/off, where
1963
- // the malformed file still gets enumerated but the corruption signal would be silently dropped.
1207
+ // Runs AFTER the write loop (malformed files were never written, nothing to record). TEN-2155:
1208
+ // non-interactive apply refuses on a malformed region — gated on applyMode per STD-263 vi.
1964
1209
  if (applyMode && malformedRegionPaths.length > 0 && (options.noPrompt || !process.stdout.isTTY)) {
1965
1210
  throw new CLIError(`Malformed PB region in: ${malformedRegionPaths.join(', ')}`, {
1966
1211
  code: ErrorCode.VALIDATION_FAILED,
@@ -1968,21 +1213,16 @@ export async function runHandshake(options = {}) {
1968
1213
  guidance: 'Fix the `<!-- pb:region:start -->` / `<!-- pb:region:end -->` sentinels (one balanced pair), then re-run `pb handshake`.',
1969
1214
  });
1970
1215
  }
1971
- // ── WP-421 S3: tampered-bucket resolution (doneWhen #17) ────────────────────
1972
- // Apply mode only. Tampered files were DEFERRED in the write loop above;
1973
- // here we either prompt the user (interactive TTY) or refuse (headless).
1974
- //
1975
- // Headless = `--no-prompt` flag OR `process.stdout.isTTY === false`. When
1976
- // headless: enumerate each tampered file to stderr, write a setup_receipt
1977
- // row with kind='transition' (DEC-962) capturing `refusedTamperedFiles[]`,
1978
- // then exit non-zero. NEVER auto-resolve. (#17 + exclusions: edits to
1979
- // projection dirs are detected, NOT silently overwritten.)
1980
- //
1981
- // Interactive: for each tampered file, present adopt-or-revert. Adopt =
1982
- // create a personal-scoped setup_asset draft from the tampered content
1983
- // (see helper below). Revert = re-project canonical content over the
1984
- // tampered file (write w.content to w.path).
1985
- const adoptedTamperedPaths = [];
1216
+ // ── WP-421 S3: tampered-bucket resolution (doneWhen #17), apply mode only — headless (--no-prompt
1217
+ // / non-TTY) refuses, exit non-zero. WP-776 S3d/S3f: the setup-assets system this resolution used
1218
+ // to offer as an "adopt" alternative (capture tampered edits as a personal-scoped draft via
1219
+ // setup.ingestSetupAsset) is deleted, and with it the only OTHER option besides overwriting —
1220
+ // per DEC-1771 (delete, never hide) there is no shim standing in for that capability. Revert
1221
+ // (re-project canonical content) is the only resolution left; this is a real capability loss
1222
+ // for anyone who was relying on "adopt" to preserve hand-edits, named here rather than silently
1223
+ // dropped. The refusal receipt (`setup.recordTamperRefusal`) is deleted along with the rest of
1224
+ // the setup-assets gateway routes — headless mode still refuses and reports, it just no longer
1225
+ // writes an audit row for the refusal.
1986
1226
  const revertedTamperedPaths = [];
1987
1227
  if (writeMode && tamperedBucket.length > 0) {
1988
1228
  const headless = options.noPrompt === true || !process.stdout.isTTY;
@@ -1990,7 +1230,7 @@ export async function runHandshake(options = {}) {
1990
1230
  // ── Headless refusal path (doneWhen #17) ────────────────────────────────
1991
1231
  logErr('');
1992
1232
  logErr(`pb handshake: ${tamperedBucket.length} PB-managed projection file(s) were edited downstream of the auto-gen marker.`);
1993
- logErr('Headless mode (--no-prompt or no TTY) cannot resolve adopt-or-revert — refusing.');
1233
+ logErr('Headless mode (--no-prompt or no TTY) cannot confirm an overwrite — refusing.');
1994
1234
  logErr('');
1995
1235
  const refusedTamperedFiles = tamperedBucket.map((t) => ({
1996
1236
  path: t.relative,
@@ -2004,38 +1244,15 @@ export async function runHandshake(options = {}) {
2004
1244
  }
2005
1245
  logErr('');
2006
1246
  logErr('Re-run interactively to resolve, or use --force to overwrite (data loss).');
2007
- // Write the kind='transition' setup_receipt row. Fail-open on the
2008
- // network/auth side: if the row cannot be written, we still exit non-zero
2009
- // (the audit trail is best-effort; refusal is mandatory).
2010
- try {
2011
- const manifestStatus = readManifestStatus(pbDir);
2012
- await kernelCall('setup.recordTamperRefusal', {
2013
- mode: manifestStatus.mode,
2014
- refusedTamperedFiles,
2015
- });
2016
- trackEvent('setup.transition.refused', {
2017
- fileCount: refusedTamperedFiles.length,
2018
- mode: manifestStatus.mode,
2019
- });
2020
- }
2021
- catch (err) {
2022
- trackEvent('setup.transition.refused.write_failed', {
2023
- error: err instanceof Error ? err.message : String(err),
2024
- });
2025
- logErr(`Warning: could not record transition receipt — ${err instanceof Error ? err.message : String(err)}`);
2026
- }
2027
1247
  // Surface the report counts before exit (visibility for CI logs).
2028
1248
  if (!quiet) {
2029
- process.stdout.write('\n');
2030
- process.stdout.write(formatHandshakeReport({
1249
+ const refusalReport = {
2031
1250
  filesWritten,
2032
1251
  filesSkipped,
2033
1252
  matchedEntries,
2034
1253
  searchQueries: uniqueQueries,
2035
1254
  repo,
2036
1255
  codexWarnings: codexWarnings.length > 0 ? codexWarnings : undefined,
2037
- chainRulesStats: chainRulesStats ?? undefined,
2038
- chainGaps: chainGaps.length > 0 ? chainGaps : undefined,
2039
1256
  adoptedCount: adoptedRulesCount,
2040
1257
  rejectedCount: rejectedRulesCount,
2041
1258
  personalRuleCount: personalRules.length > 0 ? personalRules.length : undefined,
@@ -2045,64 +1262,29 @@ export async function runHandshake(options = {}) {
2045
1262
  userOwnedSkipped: userOwnedSkipped.length > 0 ? userOwnedSkipped : undefined,
2046
1263
  managedCleanCount: cleanBucketPaths.length || undefined,
2047
1264
  tamperedFiles: refusedTamperedFiles,
2048
- }) + '\n');
1265
+ leftoverFiles: leftoverFiles.length > 0 ? leftoverFiles : undefined,
1266
+ leftoverFilesTruncated: leftoverFilesTruncated || undefined, noProjectionAssets: noProjectionAssets.length > 0 ? noProjectionAssets : undefined, // same-line combine, shrink-only budget
1267
+ };
1268
+ process.stdout.write('\n');
1269
+ process.stdout.write(isJsonMode() ? JSON.stringify(toPublicJsonReport(refusalReport)) + '\n' : formatHandshakeReport(refusalReport) + '\n');
2049
1270
  }
2050
1271
  // Exit non-zero per #17.
2051
1272
  process.exit(1);
2052
1273
  }
2053
- // ── Interactive path: prompt adopt-or-revert per file ──────────────────────
1274
+ // ── Interactive path: confirm, then revert every tampered file ─────────────
2054
1275
  log('');
2055
1276
  log(`pb handshake: ${tamperedBucket.length} PB-managed projection file(s) were edited downstream of the auto-gen marker.`);
2056
- log('You can ADOPT (capture your edits as a personal-scoped draft) or REVERT (overwrite with canonical content).');
2057
- // Batch yes-to-all / no-to-all when the user has many tampered files.
2058
- // Threshold: 5 (arbitrary; mirrors the typical handshake projection set).
2059
- let batchChoice = null;
2060
- if (tamperedBucket.length >= 5) {
2061
- const useBatch = await promptConfirm({
2062
- message: `Apply the same choice to all ${tamperedBucket.length} tampered files?`,
2063
- initialValue: false,
2064
- });
2065
- if (useBatch) {
2066
- const choice = await promptSelect({
2067
- message: 'Apply to all:',
2068
- options: [
2069
- { value: 'adopt', label: 'Adopt all — capture each as a personal-scoped draft' },
2070
- { value: 'revert', label: 'Revert all — overwrite with canonical content' },
2071
- ],
2072
- });
2073
- batchChoice = choice === 'adopt' ? 'adopt-all' : 'revert-all';
2074
- }
2075
- }
2076
- for (const tamper of tamperedBucket) {
2077
- // Reverse-map the projection path back to the canonical authoring path.
2078
- const reverse = canonicalPathForAnySurface(tamper.relative);
2079
- const canonicalHint = reverse
2080
- ? `Canonical authoring path: ${reverse.canonicalPath}`
2081
- : (() => {
2082
- // Telemetry + fallback message per surfaces/telemetry.ts.
2083
- reportReverseMapMissing({ surface: 'unknown', projectionPath: tamper.relative }, logErr);
2084
- return `Canonical authoring path: ${getReverseMapFallbackMessage()}`;
2085
- })();
2086
- log('');
2087
- log(`Tampered: ${tamper.relative}`);
2088
- log(` expected: ${tamper.expectedHash}`);
2089
- log(` actual: ${tamper.actualHash}`);
2090
- log(` ${canonicalHint}`);
2091
- let action;
2092
- if (batchChoice === 'adopt-all')
2093
- action = 'adopt';
2094
- else if (batchChoice === 'revert-all')
2095
- action = 'revert';
2096
- else {
2097
- action = await promptSelect({
2098
- message: 'Adopt or revert?',
2099
- options: [
2100
- { value: 'adopt', label: 'Adopt — capture this as a personal-scoped setup_asset draft' },
2101
- { value: 'revert', label: 'Revert — overwrite with canonical content' },
2102
- ],
2103
- });
2104
- }
2105
- if (action === 'revert') {
1277
+ log('These will be REVERTED (overwritten with canonical content) — there is no adopt/draft path any more.');
1278
+ const proceed = await promptConfirm({
1279
+ message: `Overwrite ${tamperedBucket.length} tampered file(s) with canonical content?`,
1280
+ initialValue: false,
1281
+ });
1282
+ if (proceed) {
1283
+ for (const tamper of tamperedBucket) {
1284
+ log('');
1285
+ log(`Reverting: ${tamper.relative}`);
1286
+ log(` expected: ${tamper.expectedHash}`);
1287
+ log(` actual: ${tamper.actualHash}`);
2106
1288
  // Re-project canonical content over the tampered file.
2107
1289
  // WP-436 S3: resolve vocab tokens before writing (all tampered files are adapters).
2108
1290
  if (tamper.dirs)
@@ -2110,278 +1292,22 @@ export async function runHandshake(options = {}) {
2110
1292
  assertSetupWritePath(tamper.path, perimeterManifest);
2111
1293
  writeFileSync(tamper.path, replaceVocabTokens(tamper.content, handshakeVocabCtx));
2112
1294
  revertedTamperedPaths.push(tamper.relative);
2113
- recordProjectedHash(tamper.dbAssetEntryId);
2114
- trackEvent('setup.tampered.reverted', { path: tamper.relative });
2115
- }
2116
- else {
2117
- // Adopt: capture the tampered content as a personal-scoped draft.
2118
- // Per DEC-953 sync rules: personal scope = push (no fork required).
2119
- // The mutation is best-effort — if the adopt write fails, the file is
2120
- // kept on disk untouched and a warning is logged. Adopt does NOT
2121
- // revert; it preserves the user's edits AND records them as a draft.
2122
- const draftName = basename(tamper.relative).replace(/\.(md|mdc)$/, '') + ' (adopted)';
2123
- try {
2124
- const tamperedContent = readFileSync(tamper.path, 'utf8');
2125
- const session = readSession();
2126
- const caller = session ? kernelCallWithSession : kernelCall;
2127
- await caller('setup.ingestSetupAsset', {
2128
- entryId: `SETUP-ADOPTED-${Date.now()}-${draftName.replace(/\s+/g, '-')}`,
2129
- name: draftName,
2130
- // WP-421 S3
2131
- description: `Adopted from tampered projection at ${tamper.relative}.`,
2132
- body: tamperedContent,
2133
- assetKind: tamper.relative.includes('/skills/') ? 'skill' : 'rule',
2134
- triggers: [],
2135
- semanticRefs: [],
2136
- });
2137
- adoptedTamperedPaths.push(tamper.relative);
2138
- trackEvent('setup.tampered.adopted', { path: tamper.relative });
2139
- }
2140
- catch (err) {
2141
- logErr(`Warning: could not adopt ${tamper.relative} as draft — ${err instanceof Error ? err.message : String(err)}`);
2142
- trackEvent('setup.tampered.adopt_failed', {
2143
- path: tamper.relative,
2144
- error: err instanceof Error ? err.message : String(err),
2145
- });
2146
- }
2147
1295
  }
2148
1296
  }
2149
- }
2150
- // 8a. Dormant marker + .dormant rename (WP-379 S4 + WP-426 E4) — apply mode only.
2151
- const dormantMarkedPaths = [];
2152
- if (writeMode && dormantDbAssetRows.length > 0) {
2153
- const dormantState = loadAuthoringSyncState(pbDir);
2154
- let dormantStateChanged = false;
2155
- for (const dormantAsset of dormantDbAssetRows) {
2156
- for (const { path: filePath, surface } of deriveDormantFilePaths(dormantAsset, cwd)) {
2157
- // Codex P2: deriveDormantFilePaths emits every known surface path. Honor the run's
2158
- // target set (allowedTargets = the --surfaces selection, else all manifest surfaces)
2159
- // so a `--surfaces cursor` run never renames .claude/.codex to .dormant, and surfaces
2160
- // outside the manifest are skipped silently (no false "could not dormant-mark" warning).
2161
- if (!allowedTargets.has(surface))
2162
- continue;
2163
- // FIX 4: use relative() instead of string-replace for correct cross-platform behaviour.
2164
- const rel = relative(cwd, filePath);
2165
- const alreadyReactivated = dormantState.dormantReactivated?.includes(rel) ?? false;
2166
- const previouslyRenamed = dormantState.dormantRenamed?.includes(rel) ?? false;
2167
- try {
2168
- assertSetupWritePath(filePath, perimeterManifest);
2169
- // WP-426 E4: BUG 1 fix — hands-off set.
2170
- //
2171
- // Step 1: permanently hands-off — user already reactivated this path on a
2172
- // prior run. Skip silently every time until they re-lower or raise in PB.
2173
- // (Task 7 raise-cleanup must later also prune dormantReactivated for raised
2174
- // assets — see the `dormantReactivated` comment on AuthoringSyncState.)
2175
- if (alreadyReactivated) {
2176
- continue; // leave file untouched; no TEN (already fired on first detection)
2177
- }
2178
- // Step 2: FIRST detection of manual reactivation — we previously renamed
2179
- // this to .dormant but the user renamed it back to a live file. Push the
2180
- // drift TEN exactly once, add to the permanent hands-off set, remove from
2181
- // dormantRenamed, leave file untouched.
2182
- if (previouslyRenamed && existsSync(filePath) && !existsSync(`${filePath}.dormant`)) {
2183
- syncDriftTensToFire.push(`Dormant asset ${dormantAsset.entryId} was manually reactivated at ${rel}; left untouched. Re-lower or raise it in PB to resync.`);
2184
- logErr(`Warning: ${rel} was manually un-dormanted; leaving it in place (drift).`);
2185
- dormantState.dormantReactivated = [...(dormantState.dormantReactivated ?? []), rel];
2186
- dormantState.dormantRenamed = (dormantState.dormantRenamed ?? []).filter((p) => p !== rel);
2187
- dormantStateChanged = true;
2188
- continue;
2189
- }
2190
- // Step 3: normal lowering — write dormant marker + rename to .dormant.
2191
- // WP-426 E4 spec: every rename TARGET must also pass the perimeter guard.
2192
- // Check the post-rename .dormant path BEFORE any FS mutation, so a guard
2193
- // failure can't leave a half-dormant file (marker appended but not renamed).
2194
- assertSetupWritePath(`${filePath}.dormant`, perimeterManifest);
2195
- const markerResult = writeDormantMarkerToFile(filePath);
2196
- if (markerResult === 'written')
2197
- log(`Dormant marker written: ${filePath}`);
2198
- const renameResult = renameSurfaceForDormancy(filePath);
2199
- if (renameResult === 'renamed' || renameResult === 'replaced') {
2200
- // dormantMarkedPaths holds post-rename .dormant paths (not the original surface paths).
2201
- dormantMarkedPaths.push(`${filePath}.dormant`);
2202
- if (!dormantState.dormantRenamed?.includes(rel)) {
2203
- dormantState.dormantRenamed = [...(dormantState.dormantRenamed ?? []), rel];
2204
- dormantStateChanged = true;
2205
- }
2206
- log(`Dormant rename: ${filePath} → ${filePath}.dormant`);
2207
- }
2208
- else if (renameResult === 'drift') {
2209
- // Codex P1: an edited .dormant already exists alongside the live file. Preserve
2210
- // both and flag, rather than overwriting the user's edited dormant copy.
2211
- syncDriftTensToFire.push(`Edited dormant copy ${rel}.dormant diverges from the live surface for ${dormantAsset.entryId}; left both in place. Resolve manually.`);
2212
- logErr(`Warning: ${rel}.dormant diverges from the live file; not replacing (possible manual edit).`);
2213
- }
2214
- }
2215
- catch (err) {
2216
- logErr(`Warning: could not dormant-mark ${filePath} — ${err instanceof Error ? err.message : String(err)}`);
2217
- }
2218
- }
2219
- }
2220
- if (dormantMarkedPaths.length > 0) {
2221
- log('Run `pb setup observe --purge` to remove these instead of dormant-renaming.');
2222
- }
2223
- if (dormantStateChanged) {
2224
- try {
2225
- saveAuthoringSyncState(pbDir, dormantState);
2226
- }
2227
- catch (err) {
2228
- logErr(`Warning: could not persist dormancy state — ${err instanceof Error ? err.message : String(err)}`);
2229
- }
2230
- }
2231
- }
2232
- // 8b. Raise-cleanup (WP-426 E4): for assets active this run, drop any orphan
2233
- // <surface>.dormant left by a prior lowering (active surface was re-projected
2234
- // fresh above). User-edited dormant copies are preserved + flagged. Fail-open.
2235
- if (writeMode) {
2236
- const raiseState = loadAuthoringSyncState(pbDir);
2237
- let raiseStateChanged = false;
2238
- const dormantIds = new Set(dormantDbAssetRows.map((a) => a.entryId));
2239
- const activeRows = dbAssetRows.filter((a) => !dormantIds.has(a.entryId) &&
2240
- (a.assetKind === 'skill' || a.assetKind === 'rule' || a.assetKind === 'hook'));
2241
- for (const asset of activeRows) {
2242
- // Codex P2: if this asset's body fetch failed, the write loop did NOT reproject its
2243
- // surfaces this run (same skip the authoring loop applies), so there's no fresh surface
2244
- // to reconcile against — skip raise-cleanup to avoid acting on stale content.
2245
- if (bodyFetchFailedEntryIds.has(asset.entryId))
2246
- continue;
2247
- for (const { path: filePath, surface } of deriveDormantFilePaths(asset, cwd)) {
2248
- // Codex P2: honor the run's target set (parity with the dormant pass) — a
2249
- // `--surfaces cursor` run must not touch .claude/.codex .dormant files, and surfaces
2250
- // outside the manifest are skipped silently (no false "raise-cleanup failed" warning).
2251
- if (!allowedTargets.has(surface))
2252
- continue;
2253
- const rel = relative(cwd, filePath);
2254
- try {
2255
- assertSetupWritePath(filePath, perimeterManifest); // WP-426 E4: perimeter before any FS mutation (parity with the dormant pass)
2256
- // E4 spec parity (review): restoreSurfaceFromDormant deletes the .dormant
2257
- // sibling, so guard that delete TARGET too — exactly as the lowering pass
2258
- // guards both filePath and ${filePath}.dormant.
2259
- assertSetupWritePath(`${filePath}.dormant`, perimeterManifest);
2260
- const r = restoreSurfaceFromDormant(filePath);
2261
- if (r === 'restored') {
2262
- log(`Raised: removed superseded ${filePath}.dormant`);
2263
- }
2264
- else if (r === 'orphan-drift') {
2265
- syncDriftTensToFire.push(`Dormant copy ${rel}.dormant was edited while dormant for ${asset.entryId}; preserved on raise. Resolve manually.`);
2266
- logErr(`Warning: ${rel}.dormant differs from the freshly raised projection; left in place.`);
2267
- }
2268
- // Prune the registry only when no .dormant sibling remains for this surface:
2269
- // • 'restored' removed it, or
2270
- // • it was already gone (manual .dormant→live reactivation; 'skipped', no .dormant).
2271
- // Carry-over obligation (Phase 3) + Codex P1: the manual-reactivation case must
2272
- // leave the hands-off set so a future lowering can re-evaluate the surface.
2273
- // Codex P2: but if a .dormant STILL exists (surface-filtered 'skipped' with no
2274
- // fresh live file, or a preserved 'orphan-drift'), KEEP the registry evidence —
2275
- // otherwise a later manual .dormant→live reactivation would not be recognized as
2276
- // previouslyRenamed and would be silently re-dormanted on the next lowering.
2277
- if (!existsSync(`${filePath}.dormant`)) {
2278
- if (raiseState.dormantRenamed?.includes(rel)) {
2279
- raiseState.dormantRenamed = raiseState.dormantRenamed.filter((p) => p !== rel);
2280
- raiseStateChanged = true;
2281
- }
2282
- if (raiseState.dormantReactivated?.includes(rel)) {
2283
- raiseState.dormantReactivated = raiseState.dormantReactivated.filter((p) => p !== rel);
2284
- raiseStateChanged = true;
2285
- }
2286
- }
2287
- }
2288
- catch (err) {
2289
- logErr(`Warning: raise-cleanup failed for ${filePath} — ${err instanceof Error ? err.message : String(err)}`);
2290
- }
2291
- }
2292
- }
2293
- if (raiseStateChanged) {
2294
- try {
2295
- saveAuthoringSyncState(pbDir, raiseState);
2296
- }
2297
- catch { /* fail-open */ }
2298
- }
2299
- }
2300
- // 8. User-owned files left untouched are NOT drift (TEN-2150).
2301
- // A marker-less file at an adapter path is the user's own file: handshake never
2302
- // wrote it, so there is nothing to "sync" and no draft TEN is logged. These files
2303
- // are surfaced benignly under "Skipped:" and relayed to the connect screen via
2304
- // report.userOwnedSkipped. (The legitimate "tampered" and authoring-sync drift
2305
- // signals below are unaffected.)
2306
- if (syncDriftTensToFire.length > 0) {
2307
- const session = readSession();
2308
- if (session) {
2309
- for (const driftDescription of syncDriftTensToFire) {
2310
- kernelCallWithSession('chain.createEntry', {
2311
- collectionSlug: 'tensions',
2312
- name: 'TEN: setup authoring sync drift — repo wins',
2313
- status: 'draft',
2314
- data: {
2315
- kind: 'drift',
2316
- description: driftDescription,
2317
- },
2318
- sessionId: session.sessionId,
2319
- createdBy: `agent:${session.sessionId}`,
2320
- }).catch(() => { });
2321
- }
2322
- }
2323
- }
2324
- // 8. Case-collision TENs (WP-379 S5b).
2325
- // These are distinct from drift TENs: they record ambiguous filename collisions
2326
- // where the "newest mtime wins" heuristic was applied. They always fire on a
2327
- // detected collision (collision is a data quality issue, not a drift issue).
2328
- if (collisionTensToFire.length > 0) {
2329
- const session = readSession();
2330
- if (session) {
2331
- for (const tenDescription of collisionTensToFire) {
2332
- kernelCallWithSession('chain.createEntry', {
2333
- collectionSlug: 'tensions',
2334
- name: `TEN: handshake case-collision — ambiguous filename resolved by mtime`,
2335
- // Collision audit TENs intentionally stay draft — they need explicit human review,
2336
- // not auto-commit, even in Open mode (mirrors smart-capture.ts recordCommitFailure).
2337
- status: 'draft',
2338
- data: { description: tenDescription },
2339
- sessionId: session.sessionId,
2340
- createdBy: `agent:${session.sessionId}`,
2341
- }).catch(() => { });
2342
- }
2343
- }
2344
- }
2345
- // 8b. Setup receipt — record which assets were materialized (apply mode only)
2346
- // Fail-open: receipt write is advisory, never blocks the handshake.
2347
- if (applyMode) {
2348
- const session = readSession();
2349
- const caller = session ? kernelCallWithSession : kernelCall;
2350
- try {
2351
- const currentState = await caller('setup.getCurrentSetupState', {});
2352
- const fromMode = currentState?.effectiveMode ?? 'observe';
2353
- if (fromMode !== manifestStatus.mode) {
2354
- await caller('setup.recordTransition', {
2355
- fromMode,
2356
- toMode: manifestStatus.mode,
2357
- parseStatus: manifestStatus.parseStatus,
2358
- surfaces: manifestStatus.surfaces,
2359
- lock: manifestStatus.lock,
2360
- });
2361
- if (modeRank(manifestStatus.mode) < modeRank(fromMode)) {
2362
- trackEvent('setup.transition.lowered', { fromMode, toMode: manifestStatus.mode });
2363
- }
2364
- }
2365
- }
2366
- catch (err) {
2367
- trackEvent('setup.transition.write_failed', { error: err instanceof Error ? err.message : String(err) });
2368
- logErr(`Warning: could not record setup transition — ${err instanceof Error ? err.message : String(err)}`);
2369
- }
2370
- }
2371
- if (writeMode) {
2372
- const session = readSession();
2373
- const caller = session ? kernelCallWithSession : kernelCall;
2374
- try {
2375
- const receiptResult = await caller('setup.materializeSetup', {});
2376
- if (receiptResult?.assetCount > 0) {
2377
- log(`Setup receipt: ${receiptResult.assetCount} asset(s) recorded.`);
2378
- }
2379
- }
2380
- catch (err) {
2381
- trackEvent('setup.receipt.write_failed', { error: err instanceof Error ? err.message : String(err) });
2382
- logErr(`Warning: could not write setup receipt — ${err instanceof Error ? err.message : String(err)}`);
1297
+ else {
1298
+ logErr('Skipped — tampered files left as-is; re-run to resolve.');
1299
+ process.exit(1); // doneWhen #17: never exit 0 with a tampered file unresolved (codex review round 3)
2383
1300
  }
2384
1301
  }
1302
+ // DEC-1690: a dormant (gate-failed) asset is simply not projected — dbAssets already comes
1303
+ // from the server's activeAssets list. The WP-379 S4 / WP-426 E4 on-disk marker/rename/restore
1304
+ // machinery (and its .authoring-sync.json registries) is retired: nothing to reconcile.
1305
+ // 8. User-owned files left untouched are NOT drift (TEN-2150) — a marker-less adapter-path
1306
+ // file is the user's own; handshake never wrote it, so no "sync", no draft TEN, just a benign
1307
+ // "Skipped:" surfaced via report.userOwnedSkipped.
1308
+ // 8. Case-collision and dormant-drift TENs are gone (coordinator ruling, PR #912 round 10) —
1309
+ // they existed only to audit automated deletions that no longer happen; `report.leftoverFiles`
1310
+ // below is the single reporting surface now.
2385
1311
  // 9. Report
2386
1312
  const report = {
2387
1313
  filesWritten,
@@ -2390,8 +1316,6 @@ export async function runHandshake(options = {}) {
2390
1316
  searchQueries: uniqueQueries,
2391
1317
  repo,
2392
1318
  codexWarnings: codexWarnings.length > 0 ? codexWarnings : undefined,
2393
- chainRulesStats: chainRulesStats ?? undefined,
2394
- chainGaps: chainGaps.length > 0 ? chainGaps : undefined,
2395
1319
  adoptedCount: adoptedRulesCount,
2396
1320
  rejectedCount: rejectedRulesCount,
2397
1321
  personalRuleCount: personalRules.length > 0 ? personalRules.length : undefined,
@@ -2403,19 +1327,24 @@ export async function runHandshake(options = {}) {
2403
1327
  userOwnedSkipped: userOwnedSkipped.length > 0 ? userOwnedSkipped : undefined,
2404
1328
  // WP-421 S3: three-bucket drift report (doneWhen #17). PB-managed-clean is
2405
1329
  // the count of files whose marker + hash matched. Tampered files were
2406
- // resolved (adopted/reverted) above and are reported separately.
1330
+ // resolved (reverted) above and are reported separately. WP-776 S3d/S3f:
1331
+ // adoptedTamperedPaths is gone — "adopt" is no longer an option (see the
1332
+ // tampered-bucket resolution comment above).
2407
1333
  managedCleanCount: cleanBucketPaths.length > 0 ? cleanBucketPaths.length : undefined,
2408
- adoptedTamperedPaths: adoptedTamperedPaths.length > 0 ? adoptedTamperedPaths : undefined,
2409
1334
  revertedTamperedPaths: revertedTamperedPaths.length > 0 ? revertedTamperedPaths : undefined,
1335
+ // REPORT-ONLY leftover-file listing (coordinator ruling, PR #912 round 10) — the human removes these.
1336
+ leftoverFiles: leftoverFiles.length > 0 ? leftoverFiles : undefined,
1337
+ leftoverFilesTruncated: leftoverFilesTruncated || undefined, noProjectionAssets: noProjectionAssets.length > 0 ? noProjectionAssets : undefined, // WP-660 S2 combine
2410
1338
  };
2411
1339
  if (!quiet) {
2412
1340
  process.stdout.write('\n');
2413
- process.stdout.write(formatHandshakeReport(report) + '\n');
1341
+ process.stdout.write(isJsonMode() ? JSON.stringify(toPublicJsonReport(report)) + '\n' : formatHandshakeReport(report) + '\n');
2414
1342
  }
2415
1343
  // Return the report so non-UI callers (e.g. prepareConnectContext) can surface
2416
1344
  // skipped/user-owned files without re-deriving the skip logic (TEN-2107).
2417
1345
  return report;
2418
1346
  }
2419
- // WP-426 E3/E4: exported test-only surface (not part of the public CLI API).
2420
- export const __test = { setupAuthoringPath, renameSurfaceForDormancy, restoreSurfaceFromDormant, loadAuthoringSyncState, MARKER };
1347
+ // WP-426 E3/E4: exported test-only surface (not part of the public CLI API). setupAuthoringPath
1348
+ // and loadAuthoringSyncState are gone with the setup-authoring sync machinery (WP-776 S3d/S3f).
1349
+ export const __test = { MARKER };
2421
1350
  //# sourceMappingURL=handshake.js.map