hammoc 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. package/README.md +428 -405
  2. package/bin/hammoc.js +0 -6
  3. package/package.json +100 -94
  4. package/packages/client/dist/assets/agentExampleHighlight-ltj9ce0U.js +1 -0
  5. package/packages/client/dist/assets/commandTokenHighlight-ji_ViMb4.js +1 -0
  6. package/packages/client/dist/assets/index-B-DiRGuz.js +2 -0
  7. package/packages/client/dist/assets/index-B09doO8H.js +139 -0
  8. package/packages/client/dist/assets/index-BT4RIi0U.js +1523 -0
  9. package/packages/client/dist/assets/index-DyNJ5jEW.css +32 -0
  10. package/packages/client/dist/assets/snippetTokenHighlight-CP3v4o2g.js +1 -0
  11. package/packages/client/dist/index.html +2 -2
  12. package/packages/client/dist/sw.js +1 -1
  13. package/packages/server/dist/app.d.ts.map +1 -1
  14. package/packages/server/dist/app.js +13 -21
  15. package/packages/server/dist/app.js.map +1 -1
  16. package/packages/server/dist/controllers/bmadCoreConfigController.d.ts +41 -0
  17. package/packages/server/dist/controllers/bmadCoreConfigController.d.ts.map +1 -0
  18. package/packages/server/dist/controllers/bmadCoreConfigController.js +172 -0
  19. package/packages/server/dist/controllers/bmadCoreConfigController.js.map +1 -0
  20. package/packages/server/dist/controllers/claudeMdController.d.ts +26 -0
  21. package/packages/server/dist/controllers/claudeMdController.d.ts.map +1 -0
  22. package/packages/server/dist/controllers/claudeMdController.js +158 -0
  23. package/packages/server/dist/controllers/claudeMdController.js.map +1 -0
  24. package/packages/server/dist/controllers/contextBuilderController.d.ts +43 -0
  25. package/packages/server/dist/controllers/contextBuilderController.d.ts.map +1 -0
  26. package/packages/server/dist/controllers/contextBuilderController.js +159 -0
  27. package/packages/server/dist/controllers/contextBuilderController.js.map +1 -0
  28. package/packages/server/dist/controllers/harnessAgentController.d.ts +35 -0
  29. package/packages/server/dist/controllers/harnessAgentController.d.ts.map +1 -0
  30. package/packages/server/dist/controllers/harnessAgentController.js +372 -0
  31. package/packages/server/dist/controllers/harnessAgentController.js.map +1 -0
  32. package/packages/server/dist/controllers/harnessBundleController.d.ts +37 -0
  33. package/packages/server/dist/controllers/harnessBundleController.d.ts.map +1 -0
  34. package/packages/server/dist/controllers/harnessBundleController.js +312 -0
  35. package/packages/server/dist/controllers/harnessBundleController.js.map +1 -0
  36. package/packages/server/dist/controllers/harnessCommandController.d.ts +35 -0
  37. package/packages/server/dist/controllers/harnessCommandController.d.ts.map +1 -0
  38. package/packages/server/dist/controllers/harnessCommandController.js +415 -0
  39. package/packages/server/dist/controllers/harnessCommandController.js.map +1 -0
  40. package/packages/server/dist/controllers/harnessController.d.ts +21 -0
  41. package/packages/server/dist/controllers/harnessController.d.ts.map +1 -0
  42. package/packages/server/dist/controllers/harnessController.js +176 -0
  43. package/packages/server/dist/controllers/harnessController.js.map +1 -0
  44. package/packages/server/dist/controllers/harnessHookController.d.ts +32 -0
  45. package/packages/server/dist/controllers/harnessHookController.d.ts.map +1 -0
  46. package/packages/server/dist/controllers/harnessHookController.js +406 -0
  47. package/packages/server/dist/controllers/harnessHookController.js.map +1 -0
  48. package/packages/server/dist/controllers/harnessLintController.d.ts +18 -0
  49. package/packages/server/dist/controllers/harnessLintController.d.ts.map +1 -0
  50. package/packages/server/dist/controllers/harnessLintController.js +72 -0
  51. package/packages/server/dist/controllers/harnessLintController.js.map +1 -0
  52. package/packages/server/dist/controllers/harnessMcpController.d.ts +28 -0
  53. package/packages/server/dist/controllers/harnessMcpController.d.ts.map +1 -0
  54. package/packages/server/dist/controllers/harnessMcpController.js +371 -0
  55. package/packages/server/dist/controllers/harnessMcpController.js.map +1 -0
  56. package/packages/server/dist/controllers/harnessPluginController.d.ts +17 -0
  57. package/packages/server/dist/controllers/harnessPluginController.d.ts.map +1 -0
  58. package/packages/server/dist/controllers/harnessPluginController.js +115 -0
  59. package/packages/server/dist/controllers/harnessPluginController.js.map +1 -0
  60. package/packages/server/dist/controllers/harnessShareScopeController.d.ts +24 -0
  61. package/packages/server/dist/controllers/harnessShareScopeController.d.ts.map +1 -0
  62. package/packages/server/dist/controllers/harnessShareScopeController.js +120 -0
  63. package/packages/server/dist/controllers/harnessShareScopeController.js.map +1 -0
  64. package/packages/server/dist/controllers/harnessSkillController.d.ts +32 -0
  65. package/packages/server/dist/controllers/harnessSkillController.d.ts.map +1 -0
  66. package/packages/server/dist/controllers/harnessSkillController.js +453 -0
  67. package/packages/server/dist/controllers/harnessSkillController.js.map +1 -0
  68. package/packages/server/dist/controllers/marketplaceController.d.ts +19 -0
  69. package/packages/server/dist/controllers/marketplaceController.d.ts.map +1 -0
  70. package/packages/server/dist/controllers/marketplaceController.js +74 -0
  71. package/packages/server/dist/controllers/marketplaceController.js.map +1 -0
  72. package/packages/server/dist/controllers/observabilityController.d.ts +32 -0
  73. package/packages/server/dist/controllers/observabilityController.d.ts.map +1 -0
  74. package/packages/server/dist/controllers/observabilityController.js +148 -0
  75. package/packages/server/dist/controllers/observabilityController.js.map +1 -0
  76. package/packages/server/dist/controllers/projectController.d.ts.map +1 -1
  77. package/packages/server/dist/controllers/projectController.js +11 -0
  78. package/packages/server/dist/controllers/projectController.js.map +1 -1
  79. package/packages/server/dist/controllers/snippetController.d.ts +35 -0
  80. package/packages/server/dist/controllers/snippetController.d.ts.map +1 -0
  81. package/packages/server/dist/controllers/snippetController.js +294 -0
  82. package/packages/server/dist/controllers/snippetController.js.map +1 -0
  83. package/packages/server/dist/handlers/streamCallbacks.d.ts +8 -0
  84. package/packages/server/dist/handlers/streamCallbacks.d.ts.map +1 -1
  85. package/packages/server/dist/handlers/streamCallbacks.js +8 -0
  86. package/packages/server/dist/handlers/streamCallbacks.js.map +1 -1
  87. package/packages/server/dist/handlers/websocket.d.ts +15 -0
  88. package/packages/server/dist/handlers/websocket.d.ts.map +1 -1
  89. package/packages/server/dist/handlers/websocket.js +103 -2
  90. package/packages/server/dist/handlers/websocket.js.map +1 -1
  91. package/packages/server/dist/index.js +5 -0
  92. package/packages/server/dist/index.js.map +1 -1
  93. package/packages/server/dist/locales/en/server.json +37 -4
  94. package/packages/server/dist/locales/es/server.json +0 -4
  95. package/packages/server/dist/locales/ja/server.json +0 -4
  96. package/packages/server/dist/locales/ko/server.json +0 -4
  97. package/packages/server/dist/locales/pt/server.json +0 -4
  98. package/packages/server/dist/locales/zh-CN/server.json +0 -4
  99. package/packages/server/dist/routes/harness.d.ts +8 -0
  100. package/packages/server/dist/routes/harness.d.ts.map +1 -0
  101. package/packages/server/dist/routes/harness.js +150 -0
  102. package/packages/server/dist/routes/harness.js.map +1 -0
  103. package/packages/server/dist/routes/projects.d.ts.map +1 -1
  104. package/packages/server/dist/routes/projects.js +5 -60
  105. package/packages/server/dist/routes/projects.js.map +1 -1
  106. package/packages/server/dist/routes/snippets.d.ts +14 -0
  107. package/packages/server/dist/routes/snippets.d.ts.map +1 -0
  108. package/packages/server/dist/routes/snippets.js +27 -0
  109. package/packages/server/dist/routes/snippets.js.map +1 -0
  110. package/packages/server/dist/services/bmadCoreConfigService.d.ts +86 -0
  111. package/packages/server/dist/services/bmadCoreConfigService.d.ts.map +1 -0
  112. package/packages/server/dist/services/bmadCoreConfigService.js +175 -0
  113. package/packages/server/dist/services/bmadCoreConfigService.js.map +1 -0
  114. package/packages/server/dist/services/bmadStatusService.d.ts +15 -2
  115. package/packages/server/dist/services/bmadStatusService.d.ts.map +1 -1
  116. package/packages/server/dist/services/bmadStatusService.js +146 -37
  117. package/packages/server/dist/services/bmadStatusService.js.map +1 -1
  118. package/packages/server/dist/services/chatService.d.ts +3 -0
  119. package/packages/server/dist/services/chatService.d.ts.map +1 -1
  120. package/packages/server/dist/services/chatService.js +28 -7
  121. package/packages/server/dist/services/chatService.js.map +1 -1
  122. package/packages/server/dist/services/claudeMdService.d.ts +48 -0
  123. package/packages/server/dist/services/claudeMdService.d.ts.map +1 -0
  124. package/packages/server/dist/services/claudeMdService.js +240 -0
  125. package/packages/server/dist/services/claudeMdService.js.map +1 -0
  126. package/packages/server/dist/services/commandService.d.ts +10 -0
  127. package/packages/server/dist/services/commandService.d.ts.map +1 -1
  128. package/packages/server/dist/services/commandService.js +129 -4
  129. package/packages/server/dist/services/commandService.js.map +1 -1
  130. package/packages/server/dist/services/contextBuilderScriptTemplate.d.ts +24 -0
  131. package/packages/server/dist/services/contextBuilderScriptTemplate.d.ts.map +1 -0
  132. package/packages/server/dist/services/contextBuilderScriptTemplate.js +181 -0
  133. package/packages/server/dist/services/contextBuilderScriptTemplate.js.map +1 -0
  134. package/packages/server/dist/services/contextBuilderService.d.ts +68 -0
  135. package/packages/server/dist/services/contextBuilderService.d.ts.map +1 -0
  136. package/packages/server/dist/services/contextBuilderService.js +345 -0
  137. package/packages/server/dist/services/contextBuilderService.js.map +1 -0
  138. package/packages/server/dist/services/fileWatcherService.d.ts +24 -0
  139. package/packages/server/dist/services/fileWatcherService.d.ts.map +1 -1
  140. package/packages/server/dist/services/fileWatcherService.js +232 -1
  141. package/packages/server/dist/services/fileWatcherService.js.map +1 -1
  142. package/packages/server/dist/services/harnessAgentService.d.ts +97 -0
  143. package/packages/server/dist/services/harnessAgentService.d.ts.map +1 -0
  144. package/packages/server/dist/services/harnessAgentService.js +988 -0
  145. package/packages/server/dist/services/harnessAgentService.js.map +1 -0
  146. package/packages/server/dist/services/harnessBundleService.d.ts +145 -0
  147. package/packages/server/dist/services/harnessBundleService.d.ts.map +1 -0
  148. package/packages/server/dist/services/harnessBundleService.js +1318 -0
  149. package/packages/server/dist/services/harnessBundleService.js.map +1 -0
  150. package/packages/server/dist/services/harnessCommandService.d.ts +81 -0
  151. package/packages/server/dist/services/harnessCommandService.d.ts.map +1 -0
  152. package/packages/server/dist/services/harnessCommandService.js +917 -0
  153. package/packages/server/dist/services/harnessCommandService.js.map +1 -0
  154. package/packages/server/dist/services/harnessHookService.d.ts +82 -0
  155. package/packages/server/dist/services/harnessHookService.d.ts.map +1 -0
  156. package/packages/server/dist/services/harnessHookService.js +1112 -0
  157. package/packages/server/dist/services/harnessHookService.js.map +1 -0
  158. package/packages/server/dist/services/harnessLintService.d.ts +49 -0
  159. package/packages/server/dist/services/harnessLintService.d.ts.map +1 -0
  160. package/packages/server/dist/services/harnessLintService.js +628 -0
  161. package/packages/server/dist/services/harnessLintService.js.map +1 -0
  162. package/packages/server/dist/services/harnessMcpService.d.ts +100 -0
  163. package/packages/server/dist/services/harnessMcpService.d.ts.map +1 -0
  164. package/packages/server/dist/services/harnessMcpService.js +884 -0
  165. package/packages/server/dist/services/harnessMcpService.js.map +1 -0
  166. package/packages/server/dist/services/harnessPluginService.d.ts +66 -0
  167. package/packages/server/dist/services/harnessPluginService.d.ts.map +1 -0
  168. package/packages/server/dist/services/harnessPluginService.js +559 -0
  169. package/packages/server/dist/services/harnessPluginService.js.map +1 -0
  170. package/packages/server/dist/services/harnessService.d.ts +40 -0
  171. package/packages/server/dist/services/harnessService.d.ts.map +1 -0
  172. package/packages/server/dist/services/harnessService.js +222 -0
  173. package/packages/server/dist/services/harnessService.js.map +1 -0
  174. package/packages/server/dist/services/harnessShareScopeService.d.ts +50 -0
  175. package/packages/server/dist/services/harnessShareScopeService.d.ts.map +1 -0
  176. package/packages/server/dist/services/harnessShareScopeService.js +158 -0
  177. package/packages/server/dist/services/harnessShareScopeService.js.map +1 -0
  178. package/packages/server/dist/services/harnessSkillService.d.ts +70 -0
  179. package/packages/server/dist/services/harnessSkillService.d.ts.map +1 -0
  180. package/packages/server/dist/services/harnessSkillService.js +636 -0
  181. package/packages/server/dist/services/harnessSkillService.js.map +1 -0
  182. package/packages/server/dist/services/issueService.d.ts.map +1 -1
  183. package/packages/server/dist/services/issueService.js +3 -1
  184. package/packages/server/dist/services/issueService.js.map +1 -1
  185. package/packages/server/dist/services/manualSyncService.d.ts +19 -0
  186. package/packages/server/dist/services/manualSyncService.d.ts.map +1 -0
  187. package/packages/server/dist/services/manualSyncService.js +110 -0
  188. package/packages/server/dist/services/manualSyncService.js.map +1 -0
  189. package/packages/server/dist/services/marketplaceService.d.ts +50 -0
  190. package/packages/server/dist/services/marketplaceService.d.ts.map +1 -0
  191. package/packages/server/dist/services/marketplaceService.js +326 -0
  192. package/packages/server/dist/services/marketplaceService.js.map +1 -0
  193. package/packages/server/dist/services/observabilityService.d.ts +87 -0
  194. package/packages/server/dist/services/observabilityService.d.ts.map +1 -0
  195. package/packages/server/dist/services/observabilityService.js +0 -0
  196. package/packages/server/dist/services/observabilityService.js.map +1 -0
  197. package/packages/server/dist/services/queueService.d.ts.map +1 -1
  198. package/packages/server/dist/services/queueService.js +48 -2
  199. package/packages/server/dist/services/queueService.js.map +1 -1
  200. package/packages/server/dist/services/sessionService.d.ts +16 -0
  201. package/packages/server/dist/services/sessionService.d.ts.map +1 -1
  202. package/packages/server/dist/services/sessionService.js +125 -0
  203. package/packages/server/dist/services/sessionService.js.map +1 -1
  204. package/packages/server/dist/services/snippetService.d.ts +54 -0
  205. package/packages/server/dist/services/snippetService.d.ts.map +1 -0
  206. package/packages/server/dist/services/snippetService.js +371 -0
  207. package/packages/server/dist/services/snippetService.js.map +1 -0
  208. package/packages/server/dist/services/tokenCountService.d.ts +71 -0
  209. package/packages/server/dist/services/tokenCountService.d.ts.map +1 -0
  210. package/packages/server/dist/services/tokenCountService.js +313 -0
  211. package/packages/server/dist/services/tokenCountService.js.map +1 -0
  212. package/packages/server/dist/services/utils/applyYamlFrontmatterPatch.d.ts +46 -0
  213. package/packages/server/dist/services/utils/applyYamlFrontmatterPatch.d.ts.map +1 -0
  214. package/packages/server/dist/services/utils/applyYamlFrontmatterPatch.js +125 -0
  215. package/packages/server/dist/services/utils/applyYamlFrontmatterPatch.js.map +1 -0
  216. package/packages/server/dist/snippets/apply-qa-fixes +7 -5
  217. package/packages/server/dist/snippets/qa-review +5 -1
  218. package/packages/server/dist/snippets/split-commit +9 -0
  219. package/packages/server/dist/utils/applySecretsPolicy.d.ts +53 -0
  220. package/packages/server/dist/utils/applySecretsPolicy.d.ts.map +1 -0
  221. package/packages/server/dist/utils/applySecretsPolicy.js +204 -0
  222. package/packages/server/dist/utils/applySecretsPolicy.js.map +1 -0
  223. package/packages/server/dist/utils/assertNoSecretOnShared.d.ts +40 -0
  224. package/packages/server/dist/utils/assertNoSecretOnShared.d.ts.map +1 -0
  225. package/packages/server/dist/utils/assertNoSecretOnShared.js +47 -0
  226. package/packages/server/dist/utils/assertNoSecretOnShared.js.map +1 -0
  227. package/packages/server/dist/utils/assertSafeBundlePath.d.ts +29 -0
  228. package/packages/server/dist/utils/assertSafeBundlePath.d.ts.map +1 -0
  229. package/packages/server/dist/utils/assertSafeBundlePath.js +53 -0
  230. package/packages/server/dist/utils/assertSafeBundlePath.js.map +1 -0
  231. package/packages/server/dist/utils/bundledBinaryModelSupport.d.ts +7 -0
  232. package/packages/server/dist/utils/bundledBinaryModelSupport.d.ts.map +1 -0
  233. package/packages/server/dist/utils/bundledBinaryModelSupport.js +107 -0
  234. package/packages/server/dist/utils/bundledBinaryModelSupport.js.map +1 -0
  235. package/packages/server/dist/utils/effortUtils.d.ts +2 -2
  236. package/packages/server/dist/utils/effortUtils.js +5 -5
  237. package/packages/server/dist/utils/effortUtils.js.map +1 -1
  238. package/packages/server/dist/utils/errors.d.ts +1 -0
  239. package/packages/server/dist/utils/errors.d.ts.map +1 -1
  240. package/packages/server/dist/utils/errors.js +17 -0
  241. package/packages/server/dist/utils/errors.js.map +1 -1
  242. package/packages/server/dist/utils/gitignoreFilter.d.ts +23 -0
  243. package/packages/server/dist/utils/gitignoreFilter.d.ts.map +1 -0
  244. package/packages/server/dist/utils/gitignoreFilter.js +42 -0
  245. package/packages/server/dist/utils/gitignoreFilter.js.map +1 -0
  246. package/packages/server/dist/utils/harnessBundleSchema.d.ts +107 -0
  247. package/packages/server/dist/utils/harnessBundleSchema.d.ts.map +1 -0
  248. package/packages/server/dist/utils/harnessBundleSchema.js +89 -0
  249. package/packages/server/dist/utils/harnessBundleSchema.js.map +1 -0
  250. package/packages/server/dist/utils/harnessPaths.d.ts +74 -0
  251. package/packages/server/dist/utils/harnessPaths.d.ts.map +1 -0
  252. package/packages/server/dist/utils/harnessPaths.js +247 -0
  253. package/packages/server/dist/utils/harnessPaths.js.map +1 -0
  254. package/packages/server/dist/utils/secretHeuristic.d.ts +72 -0
  255. package/packages/server/dist/utils/secretHeuristic.d.ts.map +1 -0
  256. package/packages/server/dist/utils/secretHeuristic.js +163 -0
  257. package/packages/server/dist/utils/secretHeuristic.js.map +1 -0
  258. package/packages/server/dist/utils/secretPlaceholderNamer.d.ts +41 -0
  259. package/packages/server/dist/utils/secretPlaceholderNamer.d.ts.map +1 -0
  260. package/packages/server/dist/utils/secretPlaceholderNamer.js +81 -0
  261. package/packages/server/dist/utils/secretPlaceholderNamer.js.map +1 -0
  262. package/packages/server/dist/utils/serverPathResolver.d.ts +29 -0
  263. package/packages/server/dist/utils/serverPathResolver.d.ts.map +1 -0
  264. package/packages/server/dist/utils/serverPathResolver.js +59 -0
  265. package/packages/server/dist/utils/serverPathResolver.js.map +1 -0
  266. package/packages/server/dist/utils/snippetPaths.d.ts +61 -0
  267. package/packages/server/dist/utils/snippetPaths.d.ts.map +1 -0
  268. package/packages/server/dist/utils/snippetPaths.js +123 -0
  269. package/packages/server/dist/utils/snippetPaths.js.map +1 -0
  270. package/packages/server/dist/utils/structuredEditor.d.ts +34 -0
  271. package/packages/server/dist/utils/structuredEditor.d.ts.map +1 -0
  272. package/packages/server/dist/utils/structuredEditor.js +111 -0
  273. package/packages/server/dist/utils/structuredEditor.js.map +1 -0
  274. package/packages/server/package.json +6 -2
  275. package/packages/server/resources/internals/INDEX.md +25 -0
  276. package/packages/server/resources/internals/bmad-qa-fix-marker.md +32 -0
  277. package/packages/server/resources/internals/harness-files.md +85 -0
  278. package/packages/server/resources/internals/image-storage.md +43 -0
  279. package/packages/server/resources/internals/observability-storage.md +23 -0
  280. package/packages/server/resources/manual/01-getting-started.md +104 -0
  281. package/packages/server/resources/manual/02-chat.md +285 -0
  282. package/packages/server/resources/manual/03-sessions.md +48 -0
  283. package/packages/server/resources/manual/04-slash-commands-favorites.md +152 -0
  284. package/packages/server/resources/manual/05-projects.md +76 -0
  285. package/packages/server/resources/manual/06-file-explorer-editor.md +90 -0
  286. package/packages/server/resources/manual/07-git.md +94 -0
  287. package/packages/server/resources/manual/08-terminal.md +59 -0
  288. package/packages/server/resources/manual/09-queue-runner.md +262 -0
  289. package/packages/server/resources/manual/10-project-board.md +194 -0
  290. package/packages/server/resources/manual/11-bmad-method-integration.md +130 -0
  291. package/packages/server/resources/manual/12-harness-workbench.md +256 -0
  292. package/packages/server/resources/manual/13-settings.md +241 -0
  293. package/packages/server/resources/manual/14-keyboard-shortcuts.md +68 -0
  294. package/packages/server/resources/manual/15-environment-variables.md +28 -0
  295. package/packages/server/resources/manual/16-troubleshooting.md +110 -0
  296. package/packages/server/resources/manual/INDEX.md +60 -0
  297. package/packages/shared/dist/index.d.ts +7 -0
  298. package/packages/shared/dist/index.d.ts.map +1 -1
  299. package/packages/shared/dist/index.js +14 -0
  300. package/packages/shared/dist/index.js.map +1 -1
  301. package/packages/shared/dist/types/bmadCoreConfig.d.ts +71 -0
  302. package/packages/shared/dist/types/bmadCoreConfig.d.ts.map +1 -0
  303. package/packages/shared/dist/types/bmadCoreConfig.js +30 -0
  304. package/packages/shared/dist/types/bmadCoreConfig.js.map +1 -0
  305. package/packages/shared/dist/types/bmadStatus.d.ts +10 -0
  306. package/packages/shared/dist/types/bmadStatus.d.ts.map +1 -1
  307. package/packages/shared/dist/types/bmadStatus.js.map +1 -1
  308. package/packages/shared/dist/types/board.d.ts +6 -0
  309. package/packages/shared/dist/types/board.d.ts.map +1 -1
  310. package/packages/shared/dist/types/command.d.ts +3 -3
  311. package/packages/shared/dist/types/command.d.ts.map +1 -1
  312. package/packages/shared/dist/types/contextBuilder.d.ts +102 -0
  313. package/packages/shared/dist/types/contextBuilder.d.ts.map +1 -0
  314. package/packages/shared/dist/types/contextBuilder.js +55 -0
  315. package/packages/shared/dist/types/contextBuilder.js.map +1 -0
  316. package/packages/shared/dist/types/harness.d.ts +1211 -0
  317. package/packages/shared/dist/types/harness.d.ts.map +1 -0
  318. package/packages/shared/dist/types/harness.js +107 -0
  319. package/packages/shared/dist/types/harness.js.map +1 -0
  320. package/packages/shared/dist/types/harnessBundle.d.ts +205 -0
  321. package/packages/shared/dist/types/harnessBundle.d.ts.map +1 -0
  322. package/packages/shared/dist/types/harnessBundle.js +18 -0
  323. package/packages/shared/dist/types/harnessBundle.js.map +1 -0
  324. package/packages/shared/dist/types/marketplace.d.ts +83 -0
  325. package/packages/shared/dist/types/marketplace.d.ts.map +1 -0
  326. package/packages/shared/dist/types/marketplace.js +18 -0
  327. package/packages/shared/dist/types/marketplace.js.map +1 -0
  328. package/packages/shared/dist/types/observability.d.ts +148 -0
  329. package/packages/shared/dist/types/observability.d.ts.map +1 -0
  330. package/packages/shared/dist/types/observability.js +24 -0
  331. package/packages/shared/dist/types/observability.js.map +1 -0
  332. package/packages/shared/dist/types/preferences.d.ts +4 -0
  333. package/packages/shared/dist/types/preferences.d.ts.map +1 -1
  334. package/packages/shared/dist/types/preferences.js.map +1 -1
  335. package/packages/shared/dist/types/queue.d.ts +9 -0
  336. package/packages/shared/dist/types/queue.d.ts.map +1 -1
  337. package/packages/shared/dist/types/sdk.d.ts +1 -1
  338. package/packages/shared/dist/types/sdk.d.ts.map +1 -1
  339. package/packages/shared/dist/types/sdk.js +1 -1
  340. package/packages/shared/dist/types/sdk.js.map +1 -1
  341. package/packages/shared/dist/types/websocket.d.ts +10 -0
  342. package/packages/shared/dist/types/websocket.d.ts.map +1 -1
  343. package/packages/shared/dist/utils/markdownSections.d.ts +50 -0
  344. package/packages/shared/dist/utils/markdownSections.d.ts.map +1 -0
  345. package/packages/shared/dist/utils/markdownSections.js +111 -0
  346. package/packages/shared/dist/utils/markdownSections.js.map +1 -0
  347. package/packages/shared/dist/utils/queueParser.d.ts.map +1 -1
  348. package/packages/shared/dist/utils/queueParser.js +104 -0
  349. package/packages/shared/dist/utils/queueParser.js.map +1 -1
  350. package/scripts/build-manual-shards.mjs +100 -0
  351. package/packages/client/dist/assets/index-6jREnVYd.js +0 -2
  352. package/packages/client/dist/assets/index-BFF0iqyW.css +0 -32
  353. package/packages/client/dist/assets/index-BcI4y-fU.js +0 -1454
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Story 31.3 (Task A.3 / A.5): token attribution + exact count_tokens proxy.
3
+ *
4
+ * Two responsibilities, sharing one text-resolution path so the "exact count"
5
+ * input and the "approximation" input are always the same bytes (N-1):
6
+ *
7
+ * 1. listTokenAttribution(projectSlug) — enumerate the measured harness
8
+ * elements (project/global CLAUDE.md · each skill's SKILL.md · the
9
+ * Hammoc-managed context-builder injection) and report UTF-8 byte size +
10
+ * `approxTokens = ceil(bytes/4)` + a sha256 content hash (AC-B1 / AC-B2).
11
+ *
12
+ * 2. exactCount(projectSlug, req) — proxy the official `count_tokens` via the
13
+ * already-installed `@anthropic-ai/sdk` `messages.countTokens` (spike #2,
14
+ * §15 — no new dependency), keyed by a server-recomputed content hash
15
+ * (N-B: the request hash is only an optimistic hint). Failures are
16
+ * non-blocking (`failed: true`) so the client keeps the approximation
17
+ * (AC-B3.c).
18
+ *
19
+ * Enumeration REUSES existing controllers/services (claudeMdService,
20
+ * harnessSkillService, contextBuilderService) — no new file scanner (S-2). The
21
+ * context-builder injection is estimated from the Story 31.2 manifest WITHOUT
22
+ * executing the hook (dynamic variable / command values are placeholders).
23
+ *
24
+ * Per spike #1 (§14) the SERVER approximation tier is byte `size/4` only — the
25
+ * `@anthropic-ai/tokenizer` tier was NOT adopted (Task A.4 skipped).
26
+ */
27
+ import fs from 'node:fs/promises';
28
+ import { readFileSync } from 'node:fs';
29
+ import path from 'node:path';
30
+ import os from 'node:os';
31
+ import { createHash } from 'node:crypto';
32
+ import Anthropic from '@anthropic-ai/sdk';
33
+ import { createLogger } from '../utils/logger.js';
34
+ import { claudeMdService } from './claudeMdService.js';
35
+ import { harnessSkillService } from './harnessSkillService.js';
36
+ import { contextBuilderService } from './contextBuilderService.js';
37
+ import { projectService } from './projectService.js';
38
+ const log = createLogger('tokenCountService');
39
+ /**
40
+ * Model passed to count_tokens. The count is tokenizer-family stable across
41
+ * Claude 4.x, so any current model works; overridable via env in case the
42
+ * default is later deprecated. spike #2 verified the call live.
43
+ */
44
+ const COUNT_TOKENS_MODEL = process.env.OBSERVABILITY_COUNT_TOKENS_MODEL || 'claude-sonnet-4-6';
45
+ function sha256(text) {
46
+ return createHash('sha256').update(text, 'utf8').digest('hex');
47
+ }
48
+ function utf8Bytes(text) {
49
+ return Buffer.byteLength(text, 'utf8');
50
+ }
51
+ /** ceil(bytes / 4) — the size-based heuristic (§14). */
52
+ export function approxTokensFromBytes(bytes) {
53
+ return Math.ceil(Math.max(0, bytes) / 4);
54
+ }
55
+ function samePath(a, b) {
56
+ const na = path.normalize(a);
57
+ const nb = path.normalize(b);
58
+ return process.platform === 'win32' ? na.toLowerCase() === nb.toLowerCase() : na === nb;
59
+ }
60
+ /**
61
+ * Construct an Anthropic client for count_tokens (spike #2). Priority:
62
+ * `ANTHROPIC_API_KEY` → the Claude Code OAuth access token from
63
+ * `~/.claude/.credentials.json` (verified live). Returns null when neither is
64
+ * available — the caller degrades gracefully.
65
+ */
66
+ function getAnthropicClient() {
67
+ if (process.env.ANTHROPIC_API_KEY)
68
+ return new Anthropic();
69
+ try {
70
+ const credPath = path.join(os.homedir(), '.claude', '.credentials.json');
71
+ const cred = JSON.parse(readFileSync(credPath, 'utf8'));
72
+ const token = cred?.claudeAiOauth?.accessToken;
73
+ if (token)
74
+ return new Anthropic({ authToken: token });
75
+ }
76
+ catch {
77
+ // no credentials — fall through.
78
+ }
79
+ return null;
80
+ }
81
+ class TokenCountService {
82
+ /** sha256(text) → token count. In-memory; persisted best-effort to disk. */
83
+ cache = new Map();
84
+ cacheLoaded = false;
85
+ cacheFilePath() {
86
+ return path.join(os.homedir(), '.hammoc', 'observability', 'token-count-cache.json');
87
+ }
88
+ async loadCache() {
89
+ if (this.cacheLoaded)
90
+ return;
91
+ this.cacheLoaded = true;
92
+ try {
93
+ const text = await fs.readFile(this.cacheFilePath(), 'utf8');
94
+ const obj = JSON.parse(text);
95
+ for (const [k, v] of Object.entries(obj)) {
96
+ if (typeof v === 'number')
97
+ this.cache.set(k, v);
98
+ }
99
+ }
100
+ catch {
101
+ // missing/corrupt — start empty.
102
+ }
103
+ }
104
+ async persistCache() {
105
+ try {
106
+ const file = this.cacheFilePath();
107
+ await fs.mkdir(path.dirname(file), { recursive: true });
108
+ await fs.writeFile(file, JSON.stringify(Object.fromEntries(this.cache)), 'utf8');
109
+ }
110
+ catch (err) {
111
+ log.warn(`token cache persist failed: ${err.message}`);
112
+ }
113
+ }
114
+ /**
115
+ * Enumerate measured harness elements (AC-B1.a). Missing CLAUDE.md files and a
116
+ * disabled/empty context builder are omitted (they contribute no tokens).
117
+ */
118
+ async listTokenAttribution(projectSlug) {
119
+ const items = [];
120
+ // project / global CLAUDE.md
121
+ const projectMd = await this.readClaudeMd({ scope: 'project', projectSlug });
122
+ if (projectMd)
123
+ items.push(this.makeItem('claudeMd-project', 'CLAUDE.md (project)', projectMd.text, projectMd.path));
124
+ const globalMd = await this.readClaudeMd({ scope: 'user' });
125
+ if (globalMd)
126
+ items.push(this.makeItem('claudeMd-global', 'CLAUDE.md (global)', globalMd.text, globalMd.path));
127
+ // each skill's SKILL.md (active source only)
128
+ try {
129
+ const { cards } = await harnessSkillService.listCards(projectSlug);
130
+ for (const card of cards) {
131
+ const root = card.sources[0]?.absoluteRoot;
132
+ if (!root)
133
+ continue;
134
+ const skillMd = path.join(root, 'SKILL.md');
135
+ try {
136
+ const text = await fs.readFile(skillMd, 'utf8');
137
+ items.push(this.makeItem('skill', `skill: ${card.name}`, text, skillMd));
138
+ }
139
+ catch {
140
+ // SKILL.md unreadable — skip this card.
141
+ }
142
+ }
143
+ }
144
+ catch (err) {
145
+ log.warn(`skill enumeration failed: ${err.message}`);
146
+ }
147
+ // Hammoc-managed context builder injection (manifest-assembled, no execution)
148
+ const cbText = await this.assembleContextBuilderText(projectSlug);
149
+ if (cbText)
150
+ items.push(this.makeItem('contextBuilder', 'Context builder injection', cbText));
151
+ return items;
152
+ }
153
+ /**
154
+ * Exact count for one element (AC-B3). The text is re-resolved server-side and
155
+ * its sha256 is the AUTHORITATIVE cache key (N-B) — the request `contentHash`
156
+ * is only an optimistic hint. count_tokens failures return `failed: true`.
157
+ */
158
+ async exactCount(projectSlug, req) {
159
+ const text = await this.resolveElementText(projectSlug, req.kind, req.path);
160
+ if (text == null)
161
+ return { tokens: 0, cached: false, failed: true };
162
+ const key = sha256(text);
163
+ await this.loadCache();
164
+ const hit = this.cache.get(key);
165
+ if (hit !== undefined)
166
+ return { tokens: hit, cached: true };
167
+ const tokens = await this.callCountTokens(text);
168
+ if (tokens == null)
169
+ return { tokens: 0, cached: false, failed: true };
170
+ this.cache.set(key, tokens);
171
+ void this.persistCache();
172
+ return { tokens, cached: false };
173
+ }
174
+ // -------------------------------------------------------------------------
175
+ // internals
176
+ // -------------------------------------------------------------------------
177
+ makeItem(kind, label, text, filePath) {
178
+ const bytes = utf8Bytes(text);
179
+ return {
180
+ kind,
181
+ label,
182
+ ...(filePath ? { path: filePath } : {}),
183
+ bytes,
184
+ approxTokens: approxTokensFromBytes(bytes),
185
+ contentHash: sha256(text),
186
+ };
187
+ }
188
+ /** Resolve the text used for BOTH attribution and exact-count (N-1). */
189
+ async resolveElementText(projectSlug, kind, elementPath) {
190
+ switch (kind) {
191
+ case 'claudeMd-project':
192
+ return (await this.readClaudeMd({ scope: 'project', projectSlug }))?.text ?? null;
193
+ case 'claudeMd-global':
194
+ return (await this.readClaudeMd({ scope: 'user' }))?.text ?? null;
195
+ case 'contextBuilder': {
196
+ const t = await this.assembleContextBuilderText(projectSlug);
197
+ return t || null;
198
+ }
199
+ case 'skill':
200
+ return this.readSkillTextByPath(projectSlug, elementPath);
201
+ default:
202
+ return null;
203
+ }
204
+ }
205
+ async readClaudeMd(ref) {
206
+ try {
207
+ const res = await claudeMdService.read(ref);
208
+ return { text: res.content ?? '', path: res.absolutePath ?? 'CLAUDE.md' };
209
+ }
210
+ catch {
211
+ return null; // missing / not-a-file → omit.
212
+ }
213
+ }
214
+ /**
215
+ * Read a skill's SKILL.md, validating `elementPath` against the enumerated
216
+ * skills so an arbitrary client path can never be read (the path must be one
217
+ * the server itself vouched for in listTokenAttribution).
218
+ */
219
+ async readSkillTextByPath(projectSlug, elementPath) {
220
+ if (!elementPath)
221
+ return null;
222
+ try {
223
+ const { cards } = await harnessSkillService.listCards(projectSlug);
224
+ for (const card of cards) {
225
+ const root = card.sources[0]?.absoluteRoot;
226
+ if (!root)
227
+ continue;
228
+ const skillMd = path.join(root, 'SKILL.md');
229
+ if (samePath(skillMd, elementPath)) {
230
+ return await fs.readFile(skillMd, 'utf8');
231
+ }
232
+ }
233
+ }
234
+ catch {
235
+ // fall through.
236
+ }
237
+ return null;
238
+ }
239
+ /**
240
+ * Assemble the context-builder `additionalContext` text WITHOUT executing the
241
+ * hook (N-1). Reference files are read (their content dominates the size);
242
+ * dynamic variables / acknowledged commands contribute only their block
243
+ * headers with a `(dynamic)` placeholder. Mirrors the block format of
244
+ * `contextBuilderScriptTemplate` for the statically-knowable parts. Returns ''
245
+ * when the builder is disabled or empty.
246
+ */
247
+ async assembleContextBuilderText(projectSlug) {
248
+ let manifest;
249
+ try {
250
+ ({ manifest } = await contextBuilderService.readManifest(projectSlug));
251
+ }
252
+ catch {
253
+ return '';
254
+ }
255
+ if (!manifest.enabled)
256
+ return '';
257
+ let projectRoot;
258
+ try {
259
+ projectRoot = await projectService.resolveOriginalPath(projectSlug);
260
+ }
261
+ catch {
262
+ return '';
263
+ }
264
+ const blocks = [];
265
+ for (const rel of manifest.files) {
266
+ const abs = path.resolve(projectRoot, rel);
267
+ try {
268
+ const content = await fs.readFile(abs, 'utf8');
269
+ blocks.push(`## Reference file: ${rel}\n\n${content}`);
270
+ }
271
+ catch {
272
+ blocks.push(`## Reference file: ${rel}\n\n(파일을 찾을 수 없음: ${rel})`);
273
+ }
274
+ }
275
+ // Dynamic variable headers (values are computed at hook runtime — placeholder here).
276
+ if (manifest.variables.gitBranch)
277
+ blocks.push('## Current git branch\n\n(dynamic)');
278
+ if (manifest.variables.recentCommits) {
279
+ blocks.push(`## Recent ${manifest.recentCommitsCount ?? 5} commit(s)\n\n(dynamic)`);
280
+ }
281
+ if (manifest.variables.uncommittedCount)
282
+ blocks.push('## Uncommitted file count\n\n(dynamic)');
283
+ if (manifest.variables.today)
284
+ blocks.push('## Today\n\n(dynamic)');
285
+ if (manifest.variables.activeBmadStory)
286
+ blocks.push('## Active BMad story\n\n(dynamic)');
287
+ for (const cc of manifest.customCommands) {
288
+ if (cc.acknowledged)
289
+ blocks.push(`## Command: ${cc.command}\n\n(dynamic)`);
290
+ }
291
+ return blocks.join('\n\n');
292
+ }
293
+ async callCountTokens(text) {
294
+ const client = getAnthropicClient();
295
+ if (!client) {
296
+ log.warn('count_tokens unavailable — no ANTHROPIC_API_KEY and no OAuth credentials');
297
+ return null;
298
+ }
299
+ try {
300
+ const res = await client.messages.countTokens({
301
+ model: COUNT_TOKENS_MODEL,
302
+ messages: [{ role: 'user', content: text }],
303
+ });
304
+ return res.input_tokens;
305
+ }
306
+ catch (err) {
307
+ log.warn(`count_tokens failed: ${err.message}`);
308
+ return null;
309
+ }
310
+ }
311
+ }
312
+ export const tokenCountService = new TokenCountService();
313
+ //# sourceMappingURL=tokenCountService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenCountService.js","sourceRoot":"","sources":["../../src/services/tokenCountService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAO1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,GAAG,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;AAE9C;;;;GAIG;AACH,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,gCAAgC,IAAI,mBAAmB,CAAC;AAE/F,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACzC,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS,EAAE,CAAS;IACpC,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC7B,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;AAC1F,CAAC;AAED;;;;;GAKG;AACH,SAAS,kBAAkB;IACzB,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,IAAI,SAAS,EAAE,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;QACzE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAErD,CAAC;QACF,MAAM,KAAK,GAAG,IAAI,EAAE,aAAa,EAAE,WAAW,CAAC;QAC/C,IAAI,KAAK;YAAE,OAAO,IAAI,SAAS,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,iCAAiC;IACnC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,iBAAiB;IACrB,4EAA4E;IACpE,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAClC,WAAW,GAAG,KAAK,CAAC;IAEpB,aAAa;QACnB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,eAAe,EAAE,wBAAwB,CAAC,CAAC;IACvF,CAAC;IAEO,KAAK,CAAC,SAAS;QACrB,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO;QAC7B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,CAAC;YAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA2B,CAAC;YACvD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzC,IAAI,OAAO,CAAC,KAAK,QAAQ;oBAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,iCAAiC;QACnC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,YAAY;QACxB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;YAClC,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACnF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,+BAAgC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,oBAAoB,CAAC,WAAmB;QAC5C,MAAM,KAAK,GAA2B,EAAE,CAAC;QAEzC,6BAA6B;QAC7B,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7E,IAAI,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,EAAE,qBAAqB,EAAE,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACpH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5D,IAAI,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAE/G,6CAA6C;QAC7C,IAAI,CAAC;YACH,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YACnE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC;gBAC3C,IAAI,CAAC,IAAI;oBAAE,SAAS;gBACpB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC5C,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;oBAChD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC3E,CAAC;gBAAC,MAAM,CAAC;oBACP,wCAAwC;gBAC1C,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,6BAA8B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,8EAA8E;QAC9E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC;QAClE,IAAI,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,CAAC,CAAC,CAAC;QAE7F,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAU,CAAC,WAAmB,EAAE,GAA2B;QAC/D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAC5E,IAAI,IAAI,IAAI,IAAI;YAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAEpE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QACzB,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAE5D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAChD,IAAI,MAAM,IAAI,IAAI;YAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAEtE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC5B,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC;QACzB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC;IAED,4EAA4E;IAC5E,YAAY;IACZ,4EAA4E;IAEpE,QAAQ,CACd,IAA0B,EAC1B,KAAa,EACb,IAAY,EACZ,QAAiB;QAEjB,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO;YACL,IAAI;YACJ,KAAK;YACL,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvC,KAAK;YACL,YAAY,EAAE,qBAAqB,CAAC,KAAK,CAAC;YAC1C,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC;SAC1B,CAAC;IACJ,CAAC;IAED,wEAAwE;IAChE,KAAK,CAAC,kBAAkB,CAC9B,WAAmB,EACnB,IAA0B,EAC1B,WAAoB;QAEpB,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,kBAAkB;gBACrB,OAAO,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC;YACpF,KAAK,iBAAiB;gBACpB,OAAO,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,IAAI,IAAI,IAAI,CAAC;YACpE,KAAK,gBAAgB,CAAC,CAAC,CAAC;gBACtB,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,0BAA0B,CAAC,WAAW,CAAC,CAAC;gBAC7D,OAAO,CAAC,IAAI,IAAI,CAAC;YACnB,CAAC;YACD,KAAK,OAAO;gBACV,OAAO,IAAI,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YAC5D;gBACE,OAAO,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,YAAY,CACxB,GAAkE;QAElE,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC5C,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,YAAY,IAAI,WAAW,EAAE,CAAC;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,CAAC,+BAA+B;QAC9C,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,mBAAmB,CAAC,WAAmB,EAAE,WAAoB;QACzE,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YACnE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC;gBAC3C,IAAI,CAAC,IAAI;oBAAE,SAAS;gBACpB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBAC5C,IAAI,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;oBACnC,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,0BAA0B,CAAC,WAAmB;QAC1D,IAAI,QAAQ,CAAC;QACb,IAAI,CAAC;YACH,CAAC,EAAE,QAAQ,EAAE,GAAG,MAAM,qBAAqB,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;QACzE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QAEjC,IAAI,WAAmB,CAAC;QACxB,IAAI,CAAC;YACH,WAAW,GAAG,MAAM,cAAc,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;YAC3C,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBAC/C,MAAM,CAAC,IAAI,CAAC,sBAAsB,GAAG,OAAO,OAAO,EAAE,CAAC,CAAC;YACzD,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,CAAC,IAAI,CAAC,sBAAsB,GAAG,qBAAqB,GAAG,GAAG,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;QACD,qFAAqF;QACrF,IAAI,QAAQ,CAAC,SAAS,CAAC,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QACpF,IAAI,QAAQ,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC;YACrC,MAAM,CAAC,IAAI,CAAC,aAAa,QAAQ,CAAC,kBAAkB,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACtF,CAAC;QACD,IAAI,QAAQ,CAAC,SAAS,CAAC,gBAAgB;YAAE,MAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QAC/F,IAAI,QAAQ,CAAC,SAAS,CAAC,KAAK;YAAE,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QACnE,IAAI,QAAQ,CAAC,SAAS,CAAC,eAAe;YAAE,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;QACzF,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,cAAc,EAAE,CAAC;YACzC,IAAI,EAAE,CAAC,YAAY;gBAAE,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,OAAO,eAAe,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,IAAY;QACxC,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;QACpC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,GAAG,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;YACrF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAC5C,KAAK,EAAE,kBAAkB;gBACzB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;aAC5C,CAAC,CAAC;YACH,OAAO,GAAG,CAAC,YAAY,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,wBAAyB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3D,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Story 28.5: YAML frontmatter round-trip helper.
3
+ *
4
+ * Slash command files (`.claude/commands/**\/*.md`) are markdown documents with
5
+ * an optional `--- ... ---` YAML frontmatter block at the top. To preserve
6
+ * comments / key order / blank lines inside the frontmatter while leaving the
7
+ * markdown body byte-for-byte intact, we round-trip just the frontmatter slice
8
+ * via `yaml`(eemeli) `parseDocument`.
9
+ *
10
+ * Behaviour:
11
+ * - File has no frontmatter + patch is empty (all keys absent) → return source
12
+ * unchanged.
13
+ * - File has no frontmatter + patch contains keys → prepend a
14
+ * fresh `--- ... ---` block.
15
+ * - File has frontmatter + patch is empty → strip the
16
+ * block entirely (matches AC3.a "all four fields absent ⇒ no frontmatter").
17
+ * - File has frontmatter + patch sets keys → mutate keys
18
+ * in place, preserving comments / order / blank lines for untouched keys.
19
+ *
20
+ * The body region (everything after the closing `---`) is taken from the source
21
+ * via raw substring slicing so byte-level equality holds — this is asserted by
22
+ * the unit tests with `result.slice(boundary) === source.slice(boundary)`.
23
+ */
24
+ /**
25
+ * Apply key-level patches to the YAML frontmatter block of a markdown file.
26
+ * Body markdown is preserved byte-for-byte. Pass `undefined` to delete a key.
27
+ *
28
+ * - When the resulting frontmatter has no keys left, the entire `--- ... ---`
29
+ * block (including the closing newline) is stripped.
30
+ * - When the source has no frontmatter and `newFrontmatter` carries at least
31
+ * one defined value, a `--- ... ---` block is prepended with a single
32
+ * trailing newline before the body.
33
+ *
34
+ * @throws HARNESS_PARSE_ERROR when the existing frontmatter is malformed YAML.
35
+ */
36
+ export declare function applyYamlFrontmatterPatch(source: string, newFrontmatter: Record<string, unknown>): string;
37
+ /**
38
+ * Strip the `--- ... ---` block (if any) and return the remaining body.
39
+ * Convenience helper — used by the service to surface the body separately
40
+ * from frontmatter on the read path.
41
+ */
42
+ export declare function splitFrontmatterAndBody(source: string): {
43
+ frontmatterRaw: string | null;
44
+ body: string;
45
+ };
46
+ //# sourceMappingURL=applyYamlFrontmatterPatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyYamlFrontmatterPatch.d.ts","sourceRoot":"","sources":["../../../src/services/utils/applyYamlFrontmatterPatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAuCH;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACtC,MAAM,CAuDR;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG;IACvD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd,CAIA"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Story 28.5: YAML frontmatter round-trip helper.
3
+ *
4
+ * Slash command files (`.claude/commands/**\/*.md`) are markdown documents with
5
+ * an optional `--- ... ---` YAML frontmatter block at the top. To preserve
6
+ * comments / key order / blank lines inside the frontmatter while leaving the
7
+ * markdown body byte-for-byte intact, we round-trip just the frontmatter slice
8
+ * via `yaml`(eemeli) `parseDocument`.
9
+ *
10
+ * Behaviour:
11
+ * - File has no frontmatter + patch is empty (all keys absent) → return source
12
+ * unchanged.
13
+ * - File has no frontmatter + patch contains keys → prepend a
14
+ * fresh `--- ... ---` block.
15
+ * - File has frontmatter + patch is empty → strip the
16
+ * block entirely (matches AC3.a "all four fields absent ⇒ no frontmatter").
17
+ * - File has frontmatter + patch sets keys → mutate keys
18
+ * in place, preserving comments / order / blank lines for untouched keys.
19
+ *
20
+ * The body region (everything after the closing `---`) is taken from the source
21
+ * via raw substring slicing so byte-level equality holds — this is asserted by
22
+ * the unit tests with `result.slice(boundary) === source.slice(boundary)`.
23
+ */
24
+ import { parseDocument } from 'yaml';
25
+ import { HARNESS_ERRORS } from '@hammoc/shared';
26
+ /** Match a leading `---\n...---\n?` frontmatter block. */
27
+ const FRONTMATTER_RE = /^---\s*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n)?/;
28
+ function findFrontmatter(source) {
29
+ const match = FRONTMATTER_RE.exec(source);
30
+ if (!match)
31
+ return null;
32
+ const eol = source.includes('\r\n') ? '\r\n' : '\n';
33
+ return { inner: match[1], bodyStart: match[0].length, eol };
34
+ }
35
+ function frontmatterIsEmpty(values) {
36
+ for (const v of Object.values(values)) {
37
+ if (v !== undefined)
38
+ return false;
39
+ }
40
+ return true;
41
+ }
42
+ function throwParseError(cause) {
43
+ const err = new Error(`failed to parse frontmatter: ${cause?.message ?? String(cause)}`);
44
+ err.code = HARNESS_ERRORS.HARNESS_PARSE_ERROR.code;
45
+ throw err;
46
+ }
47
+ /**
48
+ * Apply key-level patches to the YAML frontmatter block of a markdown file.
49
+ * Body markdown is preserved byte-for-byte. Pass `undefined` to delete a key.
50
+ *
51
+ * - When the resulting frontmatter has no keys left, the entire `--- ... ---`
52
+ * block (including the closing newline) is stripped.
53
+ * - When the source has no frontmatter and `newFrontmatter` carries at least
54
+ * one defined value, a `--- ... ---` block is prepended with a single
55
+ * trailing newline before the body.
56
+ *
57
+ * @throws HARNESS_PARSE_ERROR when the existing frontmatter is malformed YAML.
58
+ */
59
+ export function applyYamlFrontmatterPatch(source, newFrontmatter) {
60
+ const slice = findFrontmatter(source);
61
+ const allEmpty = frontmatterIsEmpty(newFrontmatter);
62
+ if (!slice) {
63
+ if (allEmpty)
64
+ return source;
65
+ const eol = source.includes('\r\n') ? '\r\n' : '\n';
66
+ let doc;
67
+ try {
68
+ doc = parseDocument('', { keepSourceTokens: true });
69
+ }
70
+ catch (cause) {
71
+ throwParseError(cause);
72
+ }
73
+ if (doc.contents == null) {
74
+ doc.contents = doc.createNode({});
75
+ }
76
+ for (const [key, value] of Object.entries(newFrontmatter)) {
77
+ if (value === undefined)
78
+ continue;
79
+ doc.setIn([key], value);
80
+ }
81
+ const yamlText = doc.toString().replace(/\r?\n$/, '');
82
+ return `---${eol}${yamlText}${eol}---${eol}${source}`;
83
+ }
84
+ let doc;
85
+ try {
86
+ doc = parseDocument(slice.inner, { keepSourceTokens: true });
87
+ if (doc.errors.length > 0) {
88
+ throw doc.errors[0];
89
+ }
90
+ }
91
+ catch (cause) {
92
+ throwParseError(cause);
93
+ }
94
+ if (doc.contents == null) {
95
+ doc.contents = doc.createNode({});
96
+ }
97
+ for (const [key, value] of Object.entries(newFrontmatter)) {
98
+ if (value === undefined) {
99
+ if (doc.hasIn([key]))
100
+ doc.deleteIn([key]);
101
+ continue;
102
+ }
103
+ doc.setIn([key], value);
104
+ }
105
+ // If the patched document is empty (no top-level keys left), strip the block.
106
+ const docContents = doc.contents;
107
+ const remainingKeys = docContents?.items?.length ?? 0;
108
+ if (remainingKeys === 0) {
109
+ return source.slice(slice.bodyStart);
110
+ }
111
+ const yamlText = doc.toString().replace(/\r?\n$/, '');
112
+ return `---${slice.eol}${yamlText}${slice.eol}---${slice.eol}${source.slice(slice.bodyStart)}`;
113
+ }
114
+ /**
115
+ * Strip the `--- ... ---` block (if any) and return the remaining body.
116
+ * Convenience helper — used by the service to surface the body separately
117
+ * from frontmatter on the read path.
118
+ */
119
+ export function splitFrontmatterAndBody(source) {
120
+ const slice = findFrontmatter(source);
121
+ if (!slice)
122
+ return { frontmatterRaw: null, body: source };
123
+ return { frontmatterRaw: slice.inner, body: source.slice(slice.bodyStart) };
124
+ }
125
+ //# sourceMappingURL=applyYamlFrontmatterPatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyYamlFrontmatterPatch.js","sourceRoot":"","sources":["../../../src/services/utils/applyYamlFrontmatterPatch.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
- /BMad:agents:dev
2
- ---
3
- *review-qa {arg1}
4
-
5
- After completing QA fixes, update the gate YAML file's gate field to 'FIXED'.
1
+ /BMad:agents:dev
2
+ ---
3
+ *review-qa {arg1}
4
+
5
+ After the fixes are applied and you update the story's Dev Agent Record, record which QA gate you addressed so Hammoc can track it. Read the `updated:` value from this story's QA gate YAML, then append this exact line inside the Completion Notes — replace the placeholder with that value. Do NOT change Status and do NOT edit the gate file:
6
+ <!-- hammoc:qa-fix gate="<paste the gate's updated value>" applied="true" -->
7
+ This flips the story from "apply QA fixes" to "request QA re-review" in Hammoc.
@@ -1,3 +1,7 @@
1
1
  /BMad:agents:qa
2
2
  ---
3
- *review {arg1}
3
+ *review {arg1}
4
+
5
+ When you write the quality gate, if the gate decision is CONCERNS or FAIL, also record it in the story so Hammoc tracks that a fix is pending. Append this exact line inside the story's QA Results section, replacing the placeholder with the gate's `updated:` value you just wrote:
6
+ <!-- hammoc:qa-fix gate="<paste the gate's updated value>" applied="false" -->
7
+ For a PASS or WAIVED gate, do not add this marker.
@@ -0,0 +1,9 @@
1
+ Review the current working tree with `git status` and `git diff` (both staged and unstaged). Group the changes into logically coherent units so that each commit represents a single concern (one feature, one fix, one refactor, etc.). For each group:
2
+
3
+ 1. Stage only the files (or hunks, via `git add -p`, when a single file mixes concerns) that belong to the group.
4
+ 2. Commit with a clear conventional-commit style message that explains *why* the change exists, not just *what* changed.
5
+ 3. Move on to the next group.
6
+
7
+ Do not push. Do not amend existing commits. If the changes are already coherent as a single commit, say so and make one commit instead of forcing a split.
8
+
9
+ When you finish, list the resulting commits (hash + subject line) as a summary.
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Story 30.3 (Task 2.2): apply the three `secretsPolicy` modes to a payload
3
+ * before it is written into the bundle.
4
+ *
5
+ * Two operating shapes, mirroring `detectSecretsInValue` / `detectSecretsInText`:
6
+ *
7
+ * 1. `applyPolicyToValue` walks a JSON-like value (mcp config, settings.json
8
+ * hooks block). For `excluded` the matched leaf is deleted from its
9
+ * parent; for `placeholder` it is rewritten as `${ENV_REF_NAME}` using
10
+ * `secretPlaceholderNamer`; for `included-explicit` the value is left
11
+ * untouched.
12
+ *
13
+ * 2. `applyPolicyToText` walks line-oriented text (CLAUDE.md, agent body,
14
+ * command body). For `excluded` the offending line is replaced with the
15
+ * sentinel `<< SECRET REMOVED >>` so line numbers stay stable; for
16
+ * `placeholder` every secret substring on that line is rewritten as
17
+ * `${ENV_REF_NAME}`; for `included-explicit` the text is unchanged.
18
+ *
19
+ * Both return per-call counters that the caller aggregates into the
20
+ * `ImportApplySummary` (well, the export equivalent — same idea: surface to
21
+ * the user how many secrets were affected).
22
+ */
23
+ import type { BundleItemDomain, SecretsPolicy } from '@hammoc/shared';
24
+ export declare const SECRET_REMOVED_TEXT_PLACEHOLDER = "<< SECRET REMOVED >>";
25
+ export interface ApplyPolicyValueInput {
26
+ policy: SecretsPolicy;
27
+ domain: BundleItemDomain;
28
+ cardName: string;
29
+ hookEvent?: string;
30
+ /** Root-relative path prefix for matched dot-paths (e.g. `mcpServers.context7`). */
31
+ pathPrefix?: string[];
32
+ value: unknown;
33
+ }
34
+ export interface ApplyPolicyValueResult {
35
+ value: unknown;
36
+ removedCount: number;
37
+ replacedCount: number;
38
+ }
39
+ export interface ApplyPolicyTextInput {
40
+ policy: SecretsPolicy;
41
+ domain: BundleItemDomain;
42
+ cardName: string;
43
+ hookEvent?: string;
44
+ text: string;
45
+ }
46
+ export interface ApplyPolicyTextResult {
47
+ text: string;
48
+ removedCount: number;
49
+ replacedCount: number;
50
+ }
51
+ export declare function applyPolicyToText(input: ApplyPolicyTextInput): ApplyPolicyTextResult;
52
+ export declare function applyPolicyToValue(input: ApplyPolicyValueInput): ApplyPolicyValueResult;
53
+ //# sourceMappingURL=applySecretsPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applySecretsPolicy.d.ts","sourceRoot":"","sources":["../../src/utils/applySecretsPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEtE,eAAO,MAAM,+BAA+B,yBAAyB,CAAC;AAEtE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAwFD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,GAAG,qBAAqB,CAsCpF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CA4DvF"}