hammoc 1.3.0 → 1.5.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 (336) hide show
  1. package/README.md +422 -403
  2. package/bin/hammoc.js +0 -6
  3. package/package.json +100 -93
  4. package/packages/client/dist/assets/agentExampleHighlight-BgwTm15v.js +1 -0
  5. package/packages/client/dist/assets/commandTokenHighlight-BljHwnrK.js +1 -0
  6. package/packages/client/dist/assets/index-CjyjnXB8.css +32 -0
  7. package/packages/client/dist/assets/index-D3LxqW3f.js +2 -0
  8. package/packages/client/dist/assets/index-NqJdhlek.js +1498 -0
  9. package/packages/client/dist/assets/snippetTokenHighlight-DWsaQXX0.js +1 -0
  10. package/packages/client/dist/index.html +2 -2
  11. package/packages/client/dist/sw.js +1 -1
  12. package/packages/server/dist/app.d.ts.map +1 -1
  13. package/packages/server/dist/app.js +24 -24
  14. package/packages/server/dist/app.js.map +1 -1
  15. package/packages/server/dist/controllers/boardController.d.ts.map +1 -1
  16. package/packages/server/dist/controllers/boardController.js +0 -5
  17. package/packages/server/dist/controllers/boardController.js.map +1 -1
  18. package/packages/server/dist/controllers/claudeMdController.d.ts +26 -0
  19. package/packages/server/dist/controllers/claudeMdController.d.ts.map +1 -0
  20. package/packages/server/dist/controllers/claudeMdController.js +158 -0
  21. package/packages/server/dist/controllers/claudeMdController.js.map +1 -0
  22. package/packages/server/dist/controllers/fileSystemController.d.ts +4 -0
  23. package/packages/server/dist/controllers/fileSystemController.d.ts.map +1 -1
  24. package/packages/server/dist/controllers/fileSystemController.js +20 -2
  25. package/packages/server/dist/controllers/fileSystemController.js.map +1 -1
  26. package/packages/server/dist/controllers/harnessAgentController.d.ts +28 -0
  27. package/packages/server/dist/controllers/harnessAgentController.d.ts.map +1 -0
  28. package/packages/server/dist/controllers/harnessAgentController.js +339 -0
  29. package/packages/server/dist/controllers/harnessAgentController.js.map +1 -0
  30. package/packages/server/dist/controllers/harnessCommandController.d.ts +28 -0
  31. package/packages/server/dist/controllers/harnessCommandController.d.ts.map +1 -0
  32. package/packages/server/dist/controllers/harnessCommandController.js +382 -0
  33. package/packages/server/dist/controllers/harnessCommandController.js.map +1 -0
  34. package/packages/server/dist/controllers/harnessController.d.ts +21 -0
  35. package/packages/server/dist/controllers/harnessController.d.ts.map +1 -0
  36. package/packages/server/dist/controllers/harnessController.js +176 -0
  37. package/packages/server/dist/controllers/harnessController.js.map +1 -0
  38. package/packages/server/dist/controllers/harnessHookController.d.ts +32 -0
  39. package/packages/server/dist/controllers/harnessHookController.d.ts.map +1 -0
  40. package/packages/server/dist/controllers/harnessHookController.js +363 -0
  41. package/packages/server/dist/controllers/harnessHookController.js.map +1 -0
  42. package/packages/server/dist/controllers/harnessLintController.d.ts +18 -0
  43. package/packages/server/dist/controllers/harnessLintController.d.ts.map +1 -0
  44. package/packages/server/dist/controllers/harnessLintController.js +72 -0
  45. package/packages/server/dist/controllers/harnessLintController.js.map +1 -0
  46. package/packages/server/dist/controllers/harnessMcpController.d.ts +28 -0
  47. package/packages/server/dist/controllers/harnessMcpController.d.ts.map +1 -0
  48. package/packages/server/dist/controllers/harnessMcpController.js +310 -0
  49. package/packages/server/dist/controllers/harnessMcpController.js.map +1 -0
  50. package/packages/server/dist/controllers/harnessPluginController.d.ts +17 -0
  51. package/packages/server/dist/controllers/harnessPluginController.d.ts.map +1 -0
  52. package/packages/server/dist/controllers/harnessPluginController.js +115 -0
  53. package/packages/server/dist/controllers/harnessPluginController.js.map +1 -0
  54. package/packages/server/dist/controllers/harnessShareScopeController.d.ts +15 -0
  55. package/packages/server/dist/controllers/harnessShareScopeController.d.ts.map +1 -0
  56. package/packages/server/dist/controllers/harnessShareScopeController.js +73 -0
  57. package/packages/server/dist/controllers/harnessShareScopeController.js.map +1 -0
  58. package/packages/server/dist/controllers/harnessSkillController.d.ts +32 -0
  59. package/packages/server/dist/controllers/harnessSkillController.d.ts.map +1 -0
  60. package/packages/server/dist/controllers/harnessSkillController.js +453 -0
  61. package/packages/server/dist/controllers/harnessSkillController.js.map +1 -0
  62. package/packages/server/dist/controllers/projectController.d.ts.map +1 -1
  63. package/packages/server/dist/controllers/projectController.js +11 -0
  64. package/packages/server/dist/controllers/projectController.js.map +1 -1
  65. package/packages/server/dist/controllers/serverController.d.ts.map +1 -1
  66. package/packages/server/dist/controllers/serverController.js +84 -49
  67. package/packages/server/dist/controllers/serverController.js.map +1 -1
  68. package/packages/server/dist/controllers/snippetController.d.ts +35 -0
  69. package/packages/server/dist/controllers/snippetController.d.ts.map +1 -0
  70. package/packages/server/dist/controllers/snippetController.js +294 -0
  71. package/packages/server/dist/controllers/snippetController.js.map +1 -0
  72. package/packages/server/dist/handlers/websocket.d.ts +16 -0
  73. package/packages/server/dist/handlers/websocket.d.ts.map +1 -1
  74. package/packages/server/dist/handlers/websocket.js +221 -8
  75. package/packages/server/dist/handlers/websocket.js.map +1 -1
  76. package/packages/server/dist/index.js +66 -0
  77. package/packages/server/dist/index.js.map +1 -1
  78. package/packages/server/dist/locales/en/server.json +41 -6
  79. package/packages/server/dist/locales/es/server.json +3 -5
  80. package/packages/server/dist/locales/ja/server.json +3 -5
  81. package/packages/server/dist/locales/ko/server.json +4 -6
  82. package/packages/server/dist/locales/pt/server.json +3 -5
  83. package/packages/server/dist/locales/zh-CN/server.json +3 -5
  84. package/packages/server/dist/routes/account.d.ts +7 -0
  85. package/packages/server/dist/routes/account.d.ts.map +1 -0
  86. package/packages/server/dist/routes/account.js +35 -0
  87. package/packages/server/dist/routes/account.js.map +1 -0
  88. package/packages/server/dist/routes/debug.d.ts +1 -1
  89. package/packages/server/dist/routes/debug.d.ts.map +1 -1
  90. package/packages/server/dist/routes/debug.js +60 -1
  91. package/packages/server/dist/routes/debug.js.map +1 -1
  92. package/packages/server/dist/routes/harness.d.ts +8 -0
  93. package/packages/server/dist/routes/harness.d.ts.map +1 -0
  94. package/packages/server/dist/routes/harness.js +92 -0
  95. package/packages/server/dist/routes/harness.js.map +1 -0
  96. package/packages/server/dist/routes/preferences.d.ts.map +1 -1
  97. package/packages/server/dist/routes/preferences.js +11 -2
  98. package/packages/server/dist/routes/preferences.js.map +1 -1
  99. package/packages/server/dist/routes/projects.d.ts.map +1 -1
  100. package/packages/server/dist/routes/projects.js +5 -60
  101. package/packages/server/dist/routes/projects.js.map +1 -1
  102. package/packages/server/dist/routes/snippets.d.ts +14 -0
  103. package/packages/server/dist/routes/snippets.d.ts.map +1 -0
  104. package/packages/server/dist/routes/snippets.js +27 -0
  105. package/packages/server/dist/routes/snippets.js.map +1 -0
  106. package/packages/server/dist/services/accountInfoService.d.ts +38 -0
  107. package/packages/server/dist/services/accountInfoService.d.ts.map +1 -0
  108. package/packages/server/dist/services/accountInfoService.js +118 -0
  109. package/packages/server/dist/services/accountInfoService.js.map +1 -0
  110. package/packages/server/dist/services/bmadStatusService.d.ts +6 -2
  111. package/packages/server/dist/services/bmadStatusService.d.ts.map +1 -1
  112. package/packages/server/dist/services/bmadStatusService.js +88 -32
  113. package/packages/server/dist/services/bmadStatusService.js.map +1 -1
  114. package/packages/server/dist/services/chatService.d.ts +3 -0
  115. package/packages/server/dist/services/chatService.d.ts.map +1 -1
  116. package/packages/server/dist/services/chatService.js +36 -8
  117. package/packages/server/dist/services/chatService.js.map +1 -1
  118. package/packages/server/dist/services/claudeMdService.d.ts +48 -0
  119. package/packages/server/dist/services/claudeMdService.d.ts.map +1 -0
  120. package/packages/server/dist/services/claudeMdService.js +240 -0
  121. package/packages/server/dist/services/claudeMdService.js.map +1 -0
  122. package/packages/server/dist/services/commandService.d.ts +10 -0
  123. package/packages/server/dist/services/commandService.d.ts.map +1 -1
  124. package/packages/server/dist/services/commandService.js +129 -4
  125. package/packages/server/dist/services/commandService.js.map +1 -1
  126. package/packages/server/dist/services/fileSystemService.d.ts +7 -1
  127. package/packages/server/dist/services/fileSystemService.d.ts.map +1 -1
  128. package/packages/server/dist/services/fileSystemService.js +67 -8
  129. package/packages/server/dist/services/fileSystemService.js.map +1 -1
  130. package/packages/server/dist/services/fileWatcherService.d.ts +59 -0
  131. package/packages/server/dist/services/fileWatcherService.d.ts.map +1 -0
  132. package/packages/server/dist/services/fileWatcherService.js +329 -0
  133. package/packages/server/dist/services/fileWatcherService.js.map +1 -0
  134. package/packages/server/dist/services/gitService.d.ts.map +1 -1
  135. package/packages/server/dist/services/gitService.js +67 -7
  136. package/packages/server/dist/services/gitService.js.map +1 -1
  137. package/packages/server/dist/services/harnessAgentService.d.ts +79 -0
  138. package/packages/server/dist/services/harnessAgentService.d.ts.map +1 -0
  139. package/packages/server/dist/services/harnessAgentService.js +933 -0
  140. package/packages/server/dist/services/harnessAgentService.js.map +1 -0
  141. package/packages/server/dist/services/harnessCommandService.d.ts +60 -0
  142. package/packages/server/dist/services/harnessCommandService.d.ts.map +1 -0
  143. package/packages/server/dist/services/harnessCommandService.js +853 -0
  144. package/packages/server/dist/services/harnessCommandService.js.map +1 -0
  145. package/packages/server/dist/services/harnessHookService.d.ts +55 -0
  146. package/packages/server/dist/services/harnessHookService.d.ts.map +1 -0
  147. package/packages/server/dist/services/harnessHookService.js +1060 -0
  148. package/packages/server/dist/services/harnessHookService.js.map +1 -0
  149. package/packages/server/dist/services/harnessLintService.d.ts +49 -0
  150. package/packages/server/dist/services/harnessLintService.d.ts.map +1 -0
  151. package/packages/server/dist/services/harnessLintService.js +628 -0
  152. package/packages/server/dist/services/harnessLintService.js.map +1 -0
  153. package/packages/server/dist/services/harnessMcpService.d.ts +77 -0
  154. package/packages/server/dist/services/harnessMcpService.d.ts.map +1 -0
  155. package/packages/server/dist/services/harnessMcpService.js +814 -0
  156. package/packages/server/dist/services/harnessMcpService.js.map +1 -0
  157. package/packages/server/dist/services/harnessPluginService.d.ts +66 -0
  158. package/packages/server/dist/services/harnessPluginService.d.ts.map +1 -0
  159. package/packages/server/dist/services/harnessPluginService.js +559 -0
  160. package/packages/server/dist/services/harnessPluginService.js.map +1 -0
  161. package/packages/server/dist/services/harnessService.d.ts +40 -0
  162. package/packages/server/dist/services/harnessService.d.ts.map +1 -0
  163. package/packages/server/dist/services/harnessService.js +222 -0
  164. package/packages/server/dist/services/harnessService.js.map +1 -0
  165. package/packages/server/dist/services/harnessShareScopeService.d.ts +31 -0
  166. package/packages/server/dist/services/harnessShareScopeService.d.ts.map +1 -0
  167. package/packages/server/dist/services/harnessShareScopeService.js +93 -0
  168. package/packages/server/dist/services/harnessShareScopeService.js.map +1 -0
  169. package/packages/server/dist/services/harnessSkillService.d.ts +70 -0
  170. package/packages/server/dist/services/harnessSkillService.d.ts.map +1 -0
  171. package/packages/server/dist/services/harnessSkillService.js +636 -0
  172. package/packages/server/dist/services/harnessSkillService.js.map +1 -0
  173. package/packages/server/dist/services/historyParser.d.ts +4 -14
  174. package/packages/server/dist/services/historyParser.d.ts.map +1 -1
  175. package/packages/server/dist/services/historyParser.js +60 -5
  176. package/packages/server/dist/services/historyParser.js.map +1 -1
  177. package/packages/server/dist/services/issueService.d.ts.map +1 -1
  178. package/packages/server/dist/services/issueService.js +10 -2
  179. package/packages/server/dist/services/issueService.js.map +1 -1
  180. package/packages/server/dist/services/manualSyncService.d.ts +19 -0
  181. package/packages/server/dist/services/manualSyncService.d.ts.map +1 -0
  182. package/packages/server/dist/services/manualSyncService.js +110 -0
  183. package/packages/server/dist/services/manualSyncService.js.map +1 -0
  184. package/packages/server/dist/services/notificationService.d.ts.map +1 -1
  185. package/packages/server/dist/services/notificationService.js +34 -9
  186. package/packages/server/dist/services/notificationService.js.map +1 -1
  187. package/packages/server/dist/services/preferencesService.d.ts.map +1 -1
  188. package/packages/server/dist/services/preferencesService.js +8 -1
  189. package/packages/server/dist/services/preferencesService.js.map +1 -1
  190. package/packages/server/dist/services/projectService.d.ts +5 -0
  191. package/packages/server/dist/services/projectService.d.ts.map +1 -1
  192. package/packages/server/dist/services/projectService.js +42 -2
  193. package/packages/server/dist/services/projectService.js.map +1 -1
  194. package/packages/server/dist/services/ptyService.d.ts +1 -0
  195. package/packages/server/dist/services/ptyService.d.ts.map +1 -1
  196. package/packages/server/dist/services/ptyService.js +36 -5
  197. package/packages/server/dist/services/ptyService.js.map +1 -1
  198. package/packages/server/dist/services/queueService.d.ts.map +1 -1
  199. package/packages/server/dist/services/queueService.js +83 -14
  200. package/packages/server/dist/services/queueService.js.map +1 -1
  201. package/packages/server/dist/services/sessionBufferManager.d.ts.map +1 -1
  202. package/packages/server/dist/services/sessionBufferManager.js +26 -0
  203. package/packages/server/dist/services/sessionBufferManager.js.map +1 -1
  204. package/packages/server/dist/services/sessionService.d.ts +4 -3
  205. package/packages/server/dist/services/sessionService.d.ts.map +1 -1
  206. package/packages/server/dist/services/sessionService.js +5 -4
  207. package/packages/server/dist/services/sessionService.js.map +1 -1
  208. package/packages/server/dist/services/snippetService.d.ts +54 -0
  209. package/packages/server/dist/services/snippetService.d.ts.map +1 -0
  210. package/packages/server/dist/services/snippetService.js +371 -0
  211. package/packages/server/dist/services/snippetService.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/services/webPushService.d.ts.map +1 -1
  217. package/packages/server/dist/services/webPushService.js +8 -1
  218. package/packages/server/dist/services/webPushService.js.map +1 -1
  219. package/packages/server/dist/snippets/split-commit +9 -0
  220. package/packages/server/dist/utils/applySecretsPolicy.d.ts +53 -0
  221. package/packages/server/dist/utils/applySecretsPolicy.d.ts.map +1 -0
  222. package/packages/server/dist/utils/applySecretsPolicy.js +204 -0
  223. package/packages/server/dist/utils/applySecretsPolicy.js.map +1 -0
  224. package/packages/server/dist/utils/assertNoSecretOnShared.d.ts +40 -0
  225. package/packages/server/dist/utils/assertNoSecretOnShared.d.ts.map +1 -0
  226. package/packages/server/dist/utils/assertNoSecretOnShared.js +47 -0
  227. package/packages/server/dist/utils/assertNoSecretOnShared.js.map +1 -0
  228. package/packages/server/dist/utils/effortUtils.d.ts +21 -0
  229. package/packages/server/dist/utils/effortUtils.d.ts.map +1 -0
  230. package/packages/server/dist/utils/effortUtils.js +36 -0
  231. package/packages/server/dist/utils/effortUtils.js.map +1 -0
  232. package/packages/server/dist/utils/gitignoreFilter.d.ts +23 -0
  233. package/packages/server/dist/utils/gitignoreFilter.d.ts.map +1 -0
  234. package/packages/server/dist/utils/gitignoreFilter.js +42 -0
  235. package/packages/server/dist/utils/gitignoreFilter.js.map +1 -0
  236. package/packages/server/dist/utils/harnessBundleSchema.d.ts +105 -0
  237. package/packages/server/dist/utils/harnessBundleSchema.d.ts.map +1 -0
  238. package/packages/server/dist/utils/harnessBundleSchema.js +79 -0
  239. package/packages/server/dist/utils/harnessBundleSchema.js.map +1 -0
  240. package/packages/server/dist/utils/harnessPaths.d.ts +34 -0
  241. package/packages/server/dist/utils/harnessPaths.d.ts.map +1 -0
  242. package/packages/server/dist/utils/harnessPaths.js +124 -0
  243. package/packages/server/dist/utils/harnessPaths.js.map +1 -0
  244. package/packages/server/dist/utils/pathUtils.d.ts +3 -2
  245. package/packages/server/dist/utils/pathUtils.d.ts.map +1 -1
  246. package/packages/server/dist/utils/pathUtils.js +26 -2
  247. package/packages/server/dist/utils/pathUtils.js.map +1 -1
  248. package/packages/server/dist/utils/secretHeuristic.d.ts +72 -0
  249. package/packages/server/dist/utils/secretHeuristic.d.ts.map +1 -0
  250. package/packages/server/dist/utils/secretHeuristic.js +163 -0
  251. package/packages/server/dist/utils/secretHeuristic.js.map +1 -0
  252. package/packages/server/dist/utils/secretPlaceholderNamer.d.ts +41 -0
  253. package/packages/server/dist/utils/secretPlaceholderNamer.d.ts.map +1 -0
  254. package/packages/server/dist/utils/secretPlaceholderNamer.js +81 -0
  255. package/packages/server/dist/utils/secretPlaceholderNamer.js.map +1 -0
  256. package/packages/server/dist/utils/serverPathResolver.d.ts +29 -0
  257. package/packages/server/dist/utils/serverPathResolver.d.ts.map +1 -0
  258. package/packages/server/dist/utils/serverPathResolver.js +59 -0
  259. package/packages/server/dist/utils/serverPathResolver.js.map +1 -0
  260. package/packages/server/dist/utils/snippetPaths.d.ts +61 -0
  261. package/packages/server/dist/utils/snippetPaths.d.ts.map +1 -0
  262. package/packages/server/dist/utils/snippetPaths.js +123 -0
  263. package/packages/server/dist/utils/snippetPaths.js.map +1 -0
  264. package/packages/server/dist/utils/structuredEditor.d.ts +34 -0
  265. package/packages/server/dist/utils/structuredEditor.d.ts.map +1 -0
  266. package/packages/server/dist/utils/structuredEditor.js +111 -0
  267. package/packages/server/dist/utils/structuredEditor.js.map +1 -0
  268. package/packages/server/package.json +6 -2
  269. package/packages/server/resources/internals/INDEX.md +23 -0
  270. package/packages/server/resources/internals/harness-files.md +63 -0
  271. package/packages/server/resources/internals/image-storage.md +43 -0
  272. package/packages/server/resources/manual/01-getting-started.md +104 -0
  273. package/packages/server/resources/manual/02-chat.md +285 -0
  274. package/packages/server/resources/manual/03-sessions.md +48 -0
  275. package/packages/server/resources/manual/04-slash-commands-favorites.md +152 -0
  276. package/packages/server/resources/manual/05-projects.md +74 -0
  277. package/packages/server/resources/manual/06-file-explorer-editor.md +90 -0
  278. package/packages/server/resources/manual/07-git.md +94 -0
  279. package/packages/server/resources/manual/08-terminal.md +59 -0
  280. package/packages/server/resources/manual/09-queue-runner.md +262 -0
  281. package/packages/server/resources/manual/10-project-board.md +193 -0
  282. package/packages/server/resources/manual/11-bmad-method-integration.md +128 -0
  283. package/packages/server/resources/manual/12-harness-workbench.md +175 -0
  284. package/packages/server/resources/manual/13-settings.md +241 -0
  285. package/packages/server/resources/manual/14-keyboard-shortcuts.md +68 -0
  286. package/packages/server/resources/manual/15-environment-variables.md +28 -0
  287. package/packages/server/resources/manual/16-troubleshooting.md +110 -0
  288. package/packages/server/resources/manual/INDEX.md +60 -0
  289. package/packages/shared/dist/index.d.ts +3 -0
  290. package/packages/shared/dist/index.d.ts.map +1 -1
  291. package/packages/shared/dist/index.js +6 -0
  292. package/packages/shared/dist/index.js.map +1 -1
  293. package/packages/shared/dist/types/command.d.ts +3 -3
  294. package/packages/shared/dist/types/command.d.ts.map +1 -1
  295. package/packages/shared/dist/types/fileSystem.d.ts +19 -0
  296. package/packages/shared/dist/types/fileSystem.d.ts.map +1 -1
  297. package/packages/shared/dist/types/fileSystem.js +5 -0
  298. package/packages/shared/dist/types/fileSystem.js.map +1 -1
  299. package/packages/shared/dist/types/git.d.ts +6 -1
  300. package/packages/shared/dist/types/git.d.ts.map +1 -1
  301. package/packages/shared/dist/types/git.js.map +1 -1
  302. package/packages/shared/dist/types/harness.d.ts +1211 -0
  303. package/packages/shared/dist/types/harness.d.ts.map +1 -0
  304. package/packages/shared/dist/types/harness.js +107 -0
  305. package/packages/shared/dist/types/harness.js.map +1 -0
  306. package/packages/shared/dist/types/harnessBundle.d.ts +170 -0
  307. package/packages/shared/dist/types/harnessBundle.d.ts.map +1 -0
  308. package/packages/shared/dist/types/harnessBundle.js +18 -0
  309. package/packages/shared/dist/types/harnessBundle.js.map +1 -0
  310. package/packages/shared/dist/types/history.d.ts +7 -0
  311. package/packages/shared/dist/types/history.d.ts.map +1 -1
  312. package/packages/shared/dist/types/preferences.d.ts +4 -1
  313. package/packages/shared/dist/types/preferences.d.ts.map +1 -1
  314. package/packages/shared/dist/types/preferences.js +1 -0
  315. package/packages/shared/dist/types/preferences.js.map +1 -1
  316. package/packages/shared/dist/types/queue.d.ts +9 -0
  317. package/packages/shared/dist/types/queue.d.ts.map +1 -1
  318. package/packages/shared/dist/types/sdk.d.ts +42 -1
  319. package/packages/shared/dist/types/sdk.d.ts.map +1 -1
  320. package/packages/shared/dist/types/sdk.js +26 -2
  321. package/packages/shared/dist/types/sdk.js.map +1 -1
  322. package/packages/shared/dist/types/websocket.d.ts +24 -0
  323. package/packages/shared/dist/types/websocket.d.ts.map +1 -1
  324. package/packages/shared/dist/utils/markdownSections.d.ts +50 -0
  325. package/packages/shared/dist/utils/markdownSections.d.ts.map +1 -0
  326. package/packages/shared/dist/utils/markdownSections.js +111 -0
  327. package/packages/shared/dist/utils/markdownSections.js.map +1 -0
  328. package/packages/shared/dist/utils/queueParser.d.ts.map +1 -1
  329. package/packages/shared/dist/utils/queueParser.js +104 -0
  330. package/packages/shared/dist/utils/queueParser.js.map +1 -1
  331. package/scripts/build-manual-shards.mjs +100 -0
  332. package/scripts/mock-telegram.mjs +172 -0
  333. package/scripts/run-integration-test.mjs +362 -0
  334. package/packages/client/dist/assets/index-Bf0D9oVJ.css +0 -32
  335. package/packages/client/dist/assets/index-CRmzoqHy.js +0 -2
  336. package/packages/client/dist/assets/index-CszGQ29O.js +0 -1432
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Effort Utilities
3
+ * Shared resolution of ThinkingEffort levels against model capabilities.
4
+ */
5
+ /**
6
+ * Clamp unsupported effort levels:
7
+ * · 'max' → 'high' unless model supports it (Opus 4.6+, Sonnet 4.6)
8
+ * · 'xhigh' → 'high' unless model supports it (Opus 4.7 only)
9
+ * Other levels pass through unchanged.
10
+ */
11
+ export function clampEffortForModel(effort, model) {
12
+ if (!effort)
13
+ return effort;
14
+ const supportsMax = !!model && (model === 'opus' || model === 'sonnet' ||
15
+ model.includes('opus-4-6') || model.includes('opus-4-7') || model.includes('sonnet-4-6'));
16
+ const supportsXHigh = !!model && (model === 'opus' || model.includes('opus-4-7'));
17
+ if (effort === 'max' && !supportsMax)
18
+ return 'high';
19
+ if (effort === 'xhigh' && !supportsXHigh)
20
+ return 'high';
21
+ return effort;
22
+ }
23
+ /**
24
+ * Whether the model supports Anthropic's adaptive thinking mode
25
+ * (`thinking: { type: 'adaptive' }`). Opus 4.7 requires adaptive;
26
+ * Opus 4.6 and Sonnet 4.6 accept adaptive as the recommended mode.
27
+ * Older models (Sonnet 4.5, Opus 4.5, Haiku, Sonnet 4, etc.) do NOT
28
+ * support adaptive and must stay on the legacy `maxThinkingTokens` path.
29
+ */
30
+ export function supportsAdaptiveThinking(model) {
31
+ if (!model)
32
+ return false;
33
+ return (model === 'opus' || model === 'sonnet' ||
34
+ model.includes('opus-4-6') || model.includes('opus-4-7') || model.includes('sonnet-4-6'));
35
+ }
36
+ //# sourceMappingURL=effortUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effortUtils.js","sourceRoot":"","sources":["../../src/utils/effortUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAkC,EAAE,KAAyB;IAC/F,IAAI,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC;IAC3B,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,IAAI,CAC7B,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ;QACtC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CACzF,CAAC;IACF,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IAClF,IAAI,MAAM,KAAK,KAAK,IAAI,CAAC,WAAW;QAAE,OAAO,MAAM,CAAC;IACpD,IAAI,MAAM,KAAK,OAAO,IAAI,CAAC,aAAa;QAAE,OAAO,MAAM,CAAC;IACxD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAyB;IAChE,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CACL,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ;QACtC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CACzF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Story 28.0.5 (Task 5): thin wrapper around `ignore` (kaelzhang/node-ignore).
3
+ *
4
+ * Originally introduced as preemptive infrastructure under the placeholder
5
+ * label "Epic 30 Story 10" (the pre-BMad-renumbering forward reference);
6
+ * Story 30.1 fills the call-sites (`harnessShareScopeService` + the
7
+ * client-side `ShareBadge` / `ModeBanner`) by consuming `loadGitignore()` +
8
+ * `isIgnored()` to drive the "shared vs. local vs. fully-ignored" badges on
9
+ * the harness workbench tree.
10
+ */
11
+ import { type Ignore } from 'ignore';
12
+ /**
13
+ * Load `<rootPath>/.gitignore` into an `Ignore` matcher. Missing files yield
14
+ * a matcher that never excludes anything (so callers can treat "no
15
+ * .gitignore" as "nothing is ignored" without a separate branch).
16
+ */
17
+ export declare function loadGitignore(rootPath: string): Promise<Ignore>;
18
+ /**
19
+ * Test a relative path against the matcher. Input paths are normalized to
20
+ * POSIX separators as required by `ignore`'s contract.
21
+ */
22
+ export declare function isIgnored(matcher: Ignore, relativePath: string): boolean;
23
+ //# sourceMappingURL=gitignoreFilter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignoreFilter.d.ts","sourceRoot":"","sources":["../../src/utils/gitignoreFilter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAsB,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEpD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAarE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAGxE"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Story 28.0.5 (Task 5): thin wrapper around `ignore` (kaelzhang/node-ignore).
3
+ *
4
+ * Originally introduced as preemptive infrastructure under the placeholder
5
+ * label "Epic 30 Story 10" (the pre-BMad-renumbering forward reference);
6
+ * Story 30.1 fills the call-sites (`harnessShareScopeService` + the
7
+ * client-side `ShareBadge` / `ModeBanner`) by consuming `loadGitignore()` +
8
+ * `isIgnored()` to drive the "shared vs. local vs. fully-ignored" badges on
9
+ * the harness workbench tree.
10
+ */
11
+ import fs from 'fs/promises';
12
+ import path from 'path';
13
+ import ignoreFactory from 'ignore';
14
+ /**
15
+ * Load `<rootPath>/.gitignore` into an `Ignore` matcher. Missing files yield
16
+ * a matcher that never excludes anything (so callers can treat "no
17
+ * .gitignore" as "nothing is ignored" without a separate branch).
18
+ */
19
+ export async function loadGitignore(rootPath) {
20
+ const matcher = ignoreFactory();
21
+ const gitignorePath = path.join(rootPath, '.gitignore');
22
+ try {
23
+ const content = await fs.readFile(gitignorePath, 'utf-8');
24
+ matcher.add(content);
25
+ }
26
+ catch (error) {
27
+ if (error.code !== 'ENOENT') {
28
+ throw error;
29
+ }
30
+ // No .gitignore — return an empty matcher.
31
+ }
32
+ return matcher;
33
+ }
34
+ /**
35
+ * Test a relative path against the matcher. Input paths are normalized to
36
+ * POSIX separators as required by `ignore`'s contract.
37
+ */
38
+ export function isIgnored(matcher, relativePath) {
39
+ const posix = relativePath.replace(/\\/g, '/');
40
+ return matcher.ignores(posix);
41
+ }
42
+ //# sourceMappingURL=gitignoreFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignoreFilter.js","sourceRoot":"","sources":["../../src/utils/gitignoreFilter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,aAA8B,MAAM,QAAQ,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB;IAClD,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACxD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,2CAA2C;IAC7C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,YAAoB;IAC7D,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Story 30.3 (Task 4.2): Zod runtime validation of `manifest.json` inside the
3
+ * harness export/import bundle. Lives on the server because zod is a
4
+ * server-only dep — the shared package exposes only the TypeScript surface
5
+ * (`packages/shared/src/types/harnessBundle.ts`).
6
+ *
7
+ * Two boundaries call this schema:
8
+ * - the bundle service when unpacking an import ZIP (AC5.c "malformed
9
+ * manifest" branch)
10
+ * - the controller when accepting an export request body (AC1, AC2, AC5)
11
+ *
12
+ * Both reuse the discriminator/value sets exported from `@hammoc/shared` so
13
+ * the schema and types stay in lockstep.
14
+ */
15
+ import { z } from 'zod';
16
+ /**
17
+ * Strict manifest schema — `bundleVersion` is locked to the literal 1 so
18
+ * future-version bundles fall through to the AC5.a "futureBundle" branch
19
+ * before this schema is even consulted (the import service inspects the raw
20
+ * JSON's version field first, then runs full Zod validation).
21
+ */
22
+ export declare const bundleManifestSchema: z.ZodObject<{
23
+ bundleVersion: z.ZodLiteral<1>;
24
+ hammocVersion: z.ZodString;
25
+ claudeCodeSpecVersion: z.ZodUnion<readonly [z.ZodString, z.ZodNull]>;
26
+ createdAt: z.ZodString;
27
+ sourceProjectSlug: z.ZodString;
28
+ includes: z.ZodArray<z.ZodEnum<{
29
+ agents: "agents";
30
+ hooks: "hooks";
31
+ commands: "commands";
32
+ skills: "skills";
33
+ mcp: "mcp";
34
+ "claude-md": "claude-md";
35
+ bmad: "bmad";
36
+ }>>;
37
+ secretsPolicy: z.ZodEnum<{
38
+ excluded: "excluded";
39
+ placeholder: "placeholder";
40
+ "included-explicit": "included-explicit";
41
+ }>;
42
+ pluginDependencies: z.ZodArray<z.ZodObject<{
43
+ name: z.ZodString;
44
+ marketplace: z.ZodString;
45
+ version: z.ZodOptional<z.ZodString>;
46
+ }, z.core.$strip>>;
47
+ items: z.ZodArray<z.ZodObject<{
48
+ domain: z.ZodEnum<{
49
+ agent: "agent";
50
+ command: "command";
51
+ skill: "skill";
52
+ mcp: "mcp";
53
+ hook: "hook";
54
+ "claude-md": "claude-md";
55
+ bmad: "bmad";
56
+ }>;
57
+ identity: z.ZodString;
58
+ relativePath: z.ZodString;
59
+ sourceShareScope: z.ZodEnum<{
60
+ local: "local";
61
+ shared: "shared";
62
+ fullyIgnored: "fullyIgnored";
63
+ }>;
64
+ }, z.core.$strip>>;
65
+ }, z.core.$strip>;
66
+ export type BundleManifestParsed = z.infer<typeof bundleManifestSchema>;
67
+ /**
68
+ * Loose schema used for "is this even a manifest?" detection before the
69
+ * strict schema runs. Lets the import service distinguish "totally garbage
70
+ * JSON" (no bundleVersion field at all) from "future bundle" (bundleVersion
71
+ * is a number outside our supported range).
72
+ */
73
+ export declare const loosenedManifestSchema: z.ZodObject<{
74
+ bundleVersion: z.ZodOptional<z.ZodNumber>;
75
+ }, z.core.$strip>;
76
+ export declare const exportBundleRequestSchema: z.ZodObject<{
77
+ projectSlug: z.ZodString;
78
+ includes: z.ZodArray<z.ZodEnum<{
79
+ agents: "agents";
80
+ hooks: "hooks";
81
+ commands: "commands";
82
+ skills: "skills";
83
+ mcp: "mcp";
84
+ "claude-md": "claude-md";
85
+ bmad: "bmad";
86
+ }>>;
87
+ secretsPolicy: z.ZodEnum<{
88
+ excluded: "excluded";
89
+ placeholder: "placeholder";
90
+ "included-explicit": "included-explicit";
91
+ }>;
92
+ }, z.core.$strip>;
93
+ export declare const importApplyRequestSchema: z.ZodObject<{
94
+ bundleToken: z.ZodString;
95
+ itemActions: z.ZodRecord<z.ZodString, z.ZodEnum<{
96
+ rename: "rename";
97
+ overwrite: "overwrite";
98
+ skip: "skip";
99
+ appendSection: "appendSection";
100
+ }>>;
101
+ }, z.core.$strip>;
102
+ export declare const pluginDepsQuerySchema: z.ZodObject<{
103
+ projectSlug: z.ZodString;
104
+ }, z.core.$strip>;
105
+ //# sourceMappingURL=harnessBundleSchema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harnessBundleSchema.d.ts","sourceRoot":"","sources":["../../src/utils/harnessBundleSchema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0CxB;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAU/B,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB;;iBAEjC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;iBAIpC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;iBAGnC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;iBAEhC,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Story 30.3 (Task 4.2): Zod runtime validation of `manifest.json` inside the
3
+ * harness export/import bundle. Lives on the server because zod is a
4
+ * server-only dep — the shared package exposes only the TypeScript surface
5
+ * (`packages/shared/src/types/harnessBundle.ts`).
6
+ *
7
+ * Two boundaries call this schema:
8
+ * - the bundle service when unpacking an import ZIP (AC5.c "malformed
9
+ * manifest" branch)
10
+ * - the controller when accepting an export request body (AC1, AC2, AC5)
11
+ *
12
+ * Both reuse the discriminator/value sets exported from `@hammoc/shared` so
13
+ * the schema and types stay in lockstep.
14
+ */
15
+ import { z } from 'zod';
16
+ import { BUNDLE_SECTIONS, HARNESS_BUNDLE_VERSION, } from '@hammoc/shared';
17
+ const sectionSchema = z.enum(BUNDLE_SECTIONS);
18
+ const secretsPolicySchema = z.enum(['excluded', 'placeholder', 'included-explicit']);
19
+ const itemDomainSchema = z.enum([
20
+ 'claude-md',
21
+ 'skill',
22
+ 'mcp',
23
+ 'hook',
24
+ 'command',
25
+ 'agent',
26
+ 'bmad',
27
+ ]);
28
+ const sourceShareScopeSchema = z.enum(['shared', 'local', 'fullyIgnored']);
29
+ const itemActionSchema = z.enum(['overwrite', 'skip', 'rename', 'appendSection']);
30
+ const pluginRefSchema = z.object({
31
+ name: z.string().min(1),
32
+ marketplace: z.string().min(1),
33
+ version: z.string().optional(),
34
+ });
35
+ const bundleItemSchema = z.object({
36
+ domain: itemDomainSchema,
37
+ identity: z.string().min(1),
38
+ relativePath: z.string().min(1),
39
+ sourceShareScope: sourceShareScopeSchema,
40
+ });
41
+ /**
42
+ * Strict manifest schema — `bundleVersion` is locked to the literal 1 so
43
+ * future-version bundles fall through to the AC5.a "futureBundle" branch
44
+ * before this schema is even consulted (the import service inspects the raw
45
+ * JSON's version field first, then runs full Zod validation).
46
+ */
47
+ export const bundleManifestSchema = z.object({
48
+ bundleVersion: z.literal(HARNESS_BUNDLE_VERSION),
49
+ hammocVersion: z.string().min(1),
50
+ claudeCodeSpecVersion: z.union([z.string().min(1), z.null()]),
51
+ createdAt: z.string().min(1),
52
+ sourceProjectSlug: z.string().min(1),
53
+ includes: z.array(sectionSchema),
54
+ secretsPolicy: secretsPolicySchema,
55
+ pluginDependencies: z.array(pluginRefSchema),
56
+ items: z.array(bundleItemSchema),
57
+ });
58
+ /**
59
+ * Loose schema used for "is this even a manifest?" detection before the
60
+ * strict schema runs. Lets the import service distinguish "totally garbage
61
+ * JSON" (no bundleVersion field at all) from "future bundle" (bundleVersion
62
+ * is a number outside our supported range).
63
+ */
64
+ export const loosenedManifestSchema = z.object({
65
+ bundleVersion: z.number().int().optional(),
66
+ });
67
+ export const exportBundleRequestSchema = z.object({
68
+ projectSlug: z.string().min(1),
69
+ includes: z.array(sectionSchema).min(1, 'at least one section is required'),
70
+ secretsPolicy: secretsPolicySchema,
71
+ });
72
+ export const importApplyRequestSchema = z.object({
73
+ bundleToken: z.string().min(1),
74
+ itemActions: z.record(z.string(), itemActionSchema),
75
+ });
76
+ export const pluginDepsQuerySchema = z.object({
77
+ projectSlug: z.string().min(1),
78
+ });
79
+ //# sourceMappingURL=harnessBundleSchema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harnessBundleSchema.js","sourceRoot":"","sources":["../../src/utils/harnessBundleSchema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Story 28.0.5: Harness workbench path resolver.
3
+ *
4
+ * Resolves `~/.claude` (user scope) and `<projectRoot>/.claude` (project scope)
5
+ * into absolute paths and enforces that any relative path requested by the
6
+ * caller stays inside the resolved root. Every entry point into `harnessService`
7
+ * MUST route through `resolveHarnessPath` so that Windows/POSIX separator
8
+ * mixing, drive letters, UNC paths, and null-byte inputs cannot escape the
9
+ * subtree.
10
+ */
11
+ import { type HarnessPathRef } from '@hammoc/shared';
12
+ /** Return the absolute path to the user-scope harness root (`~/.claude`). */
13
+ export declare function getUserHarnessRoot(): string;
14
+ /** Return the absolute path to the project-scope harness root (`<project>/.claude`). */
15
+ export declare function getProjectHarnessRoot(projectSlug: string): Promise<string>;
16
+ export interface ResolvedHarnessPath {
17
+ resolvedRoot: string;
18
+ absolutePath: string;
19
+ }
20
+ /**
21
+ * Resolve a `HarnessPathRef` to an absolute path, guaranteed to sit inside the
22
+ * resolved root. Throws `HARNESS_PATH_DENIED` for any traversal attempt.
23
+ */
24
+ export declare function resolveHarnessPath(ref: HarnessPathRef): Promise<ResolvedHarnessPath>;
25
+ /**
26
+ * Story 29.1 (AC6): resolve the project-root `<projectRoot>/CLAUDE.md` path —
27
+ * the single file in the harness workbench whose location sits OUTSIDE the
28
+ * project's `.claude/` subtree, so `resolveHarnessPath` would reject it as a
29
+ * traversal. This helper accepts only `projectSlug` (no caller-supplied
30
+ * relative path) and returns the canonical CLAUDE.md location alongside the
31
+ * project root, so traversal is impossible by construction.
32
+ */
33
+ export declare function resolveProjectClaudeMdPath(projectSlug: string): Promise<ResolvedHarnessPath>;
34
+ //# sourceMappingURL=harnessPaths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harnessPaths.d.ts","sourceRoot":"","sources":["../../src/utils/harnessPaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAWrE,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,MAAM,CAO3C;AAED,wFAAwF;AACxF,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBhF;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAwC1F;AAED;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAyBlG"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Story 28.0.5: Harness workbench path resolver.
3
+ *
4
+ * Resolves `~/.claude` (user scope) and `<projectRoot>/.claude` (project scope)
5
+ * into absolute paths and enforces that any relative path requested by the
6
+ * caller stays inside the resolved root. Every entry point into `harnessService`
7
+ * MUST route through `resolveHarnessPath` so that Windows/POSIX separator
8
+ * mixing, drive letters, UNC paths, and null-byte inputs cannot escape the
9
+ * subtree.
10
+ */
11
+ import os from 'os';
12
+ import path from 'path';
13
+ import { projectService } from '../services/projectService.js';
14
+ import { HARNESS_ERRORS } from '@hammoc/shared';
15
+ /**
16
+ * Test-only dependency-injection hook. When set, `getUserHarnessRoot()` returns
17
+ * this value instead of `~/.claude`. Production configurations leave it unset
18
+ * (no effect); unit tests in `harnessPaths.test.ts` / `harnessService.test.ts`
19
+ * redirect the user scope to a temp directory so they never touch the real
20
+ * home directory.
21
+ */
22
+ const HOME_OVERRIDE_ENV = 'HAMMOC_HARNESS_HOME_OVERRIDE';
23
+ /** Return the absolute path to the user-scope harness root (`~/.claude`). */
24
+ export function getUserHarnessRoot() {
25
+ const override = process.env[HOME_OVERRIDE_ENV];
26
+ if (override && override.length > 0) {
27
+ return override;
28
+ }
29
+ // Node resolves %USERPROFILE% on Windows and $HOME on POSIX.
30
+ return path.join(os.homedir(), '.claude');
31
+ }
32
+ /** Return the absolute path to the project-scope harness root (`<project>/.claude`). */
33
+ export async function getProjectHarnessRoot(projectSlug) {
34
+ if (!projectSlug) {
35
+ const err = new Error('projectSlug is required for project scope');
36
+ err.code = HARNESS_ERRORS.HARNESS_ROOT_MISSING.code;
37
+ throw err;
38
+ }
39
+ try {
40
+ const projectRoot = await projectService.resolveOriginalPath(projectSlug);
41
+ return path.join(projectRoot, '.claude');
42
+ }
43
+ catch (error) {
44
+ // Any failure to resolve the project (unknown slug, missing index, etc.)
45
+ // maps to HARNESS_ROOT_MISSING so the controller can return a uniform 404.
46
+ const wrapped = new Error(`Unable to resolve harness root for project "${projectSlug}": ${error.message}`);
47
+ wrapped.code = HARNESS_ERRORS.HARNESS_ROOT_MISSING.code;
48
+ throw wrapped;
49
+ }
50
+ }
51
+ /**
52
+ * Resolve a `HarnessPathRef` to an absolute path, guaranteed to sit inside the
53
+ * resolved root. Throws `HARNESS_PATH_DENIED` for any traversal attempt.
54
+ */
55
+ export async function resolveHarnessPath(ref) {
56
+ const rel = ref.relativePath ?? '';
57
+ // Reject absolute paths and null bytes before touching `path.join`, since
58
+ // join would otherwise discard the root prefix (POSIX absolute) or let a
59
+ // null byte slip through to fs APIs.
60
+ if (rel.includes('\0')) {
61
+ const err = new Error('null byte in relative path');
62
+ err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
63
+ throw err;
64
+ }
65
+ if (path.isAbsolute(rel)) {
66
+ const err = new Error('absolute path not allowed');
67
+ err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
68
+ throw err;
69
+ }
70
+ // UNC inputs (`\\server\share`) on Windows: path.isAbsolute flags some of
71
+ // these, but on POSIX it would not — reject the prefix defensively.
72
+ if (rel.startsWith('\\\\') || rel.startsWith('//')) {
73
+ const err = new Error('UNC path not allowed');
74
+ err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
75
+ throw err;
76
+ }
77
+ const resolvedRoot = ref.scope === 'user'
78
+ ? path.resolve(getUserHarnessRoot())
79
+ : path.resolve(await getProjectHarnessRoot(ref.projectSlug ?? ''));
80
+ const absolutePath = path.resolve(resolvedRoot, rel);
81
+ // Containment check: absolutePath must be the root itself or sit beneath it.
82
+ // `startsWith(root + sep)` avoids the false match where root="/a" and
83
+ // absolutePath="/abc".
84
+ if (absolutePath !== resolvedRoot && !absolutePath.startsWith(resolvedRoot + path.sep)) {
85
+ const err = new Error('path escapes harness root');
86
+ err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
87
+ throw err;
88
+ }
89
+ return { resolvedRoot, absolutePath };
90
+ }
91
+ /**
92
+ * Story 29.1 (AC6): resolve the project-root `<projectRoot>/CLAUDE.md` path —
93
+ * the single file in the harness workbench whose location sits OUTSIDE the
94
+ * project's `.claude/` subtree, so `resolveHarnessPath` would reject it as a
95
+ * traversal. This helper accepts only `projectSlug` (no caller-supplied
96
+ * relative path) and returns the canonical CLAUDE.md location alongside the
97
+ * project root, so traversal is impossible by construction.
98
+ */
99
+ export async function resolveProjectClaudeMdPath(projectSlug) {
100
+ if (!projectSlug || projectSlug.includes('\0')) {
101
+ const err = new Error('invalid projectSlug');
102
+ err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
103
+ throw err;
104
+ }
105
+ // Reject traversal-bearing slugs before they reach projectService — defense in depth.
106
+ if (projectSlug.includes('..') || projectSlug.includes('/') || projectSlug.includes('\\')) {
107
+ const err = new Error('projectSlug must not contain path separators');
108
+ err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
109
+ throw err;
110
+ }
111
+ let projectRoot;
112
+ try {
113
+ projectRoot = await projectService.resolveOriginalPath(projectSlug);
114
+ }
115
+ catch (error) {
116
+ const wrapped = new Error(`Unable to resolve project root for "${projectSlug}": ${error.message}`);
117
+ wrapped.code = HARNESS_ERRORS.HARNESS_ROOT_MISSING.code;
118
+ throw wrapped;
119
+ }
120
+ const resolvedRoot = path.resolve(projectRoot);
121
+ const absolutePath = path.join(resolvedRoot, 'CLAUDE.md');
122
+ return { resolvedRoot, absolutePath };
123
+ }
124
+ //# sourceMappingURL=harnessPaths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harnessPaths.js","sourceRoot":"","sources":["../../src/utils/harnessPaths.ts"],"names":[],"mappings":"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"}
@@ -15,8 +15,9 @@ export declare function isProtectedPath(relativePath: string): boolean;
15
15
  /** Maximum file size for full content response (1MB) */
16
16
  export declare const MAX_FILE_SIZE: number;
17
17
  /**
18
- * Detect if a file is binary by reading the first 8192 bytes
19
- * and checking for null byte presence.
18
+ * Detect if a file is binary.
19
+ * 1. Extension allowlist for formats whose headers lack null bytes (e.g. ZIP, PDF).
20
+ * 2. Fallback: read first 8192 bytes and check for null byte presence.
20
21
  * @param filePath Absolute path to the file
21
22
  * @returns true if the file appears to be binary
22
23
  */
@@ -1 +1 @@
1
- {"version":3,"file":"pathUtils.d.ts","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,iDAAkD,CAAC;AAErF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAI7D;AAED,wDAAwD;AACxD,eAAO,MAAM,aAAa,QAAkB,CAAC;AAK7C;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBrE;AA2BD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGpD"}
1
+ {"version":3,"file":"pathUtils.d.ts","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,iDAAkD,CAAC;AAErF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAI7D;AAED,wDAAwD;AACxD,eAAO,MAAM,aAAa,QAAkB,CAAC;AAyB7C;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBrE;AA2BD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGpD"}
@@ -23,12 +23,36 @@ export const MAX_FILE_SIZE = 1 * 1024 * 1024;
23
23
  /** Number of bytes to read for binary detection */
24
24
  const BINARY_CHECK_BYTES = 8192;
25
25
  /**
26
- * Detect if a file is binary by reading the first 8192 bytes
27
- * and checking for null byte presence.
26
+ * Extensions whose magic bytes do not contain null (0x00) and therefore
27
+ * evade the null-byte heuristic below. Detected by extension up front.
28
+ */
29
+ const BINARY_EXTENSIONS = new Set([
30
+ // Archives
31
+ '.zip', '.gz', '.tar', '.tgz', '.bz2', '.7z', '.rar', '.xz',
32
+ // Documents
33
+ '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
34
+ // Executables / libraries
35
+ '.exe', '.dll', '.so', '.dylib', '.class', '.jar', '.wasm',
36
+ // Databases
37
+ '.db', '.sqlite', '.sqlite3', '.mdb',
38
+ // Media (some already detected by null bytes, but listing for clarity)
39
+ '.mp3', '.mp4', '.avi', '.mov', '.wav', '.ogg', '.flac', '.webm',
40
+ '.webp', '.ico', '.bmp', '.tiff', '.heic',
41
+ // Fonts
42
+ '.ttf', '.otf', '.woff', '.woff2', '.eot',
43
+ ]);
44
+ /**
45
+ * Detect if a file is binary.
46
+ * 1. Extension allowlist for formats whose headers lack null bytes (e.g. ZIP, PDF).
47
+ * 2. Fallback: read first 8192 bytes and check for null byte presence.
28
48
  * @param filePath Absolute path to the file
29
49
  * @returns true if the file appears to be binary
30
50
  */
31
51
  export async function isBinaryFile(filePath) {
52
+ const ext = path.extname(filePath).toLowerCase();
53
+ if (BINARY_EXTENSIONS.has(ext)) {
54
+ return true;
55
+ }
32
56
  const handle = await fs.open(filePath, 'r');
33
57
  try {
34
58
  const buffer = Buffer.alloc(BINARY_CHECK_BYTES);
@@ -1 +1 @@
1
- {"version":3,"file":"pathUtils.js","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,6DAA6D;AAC7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,YAAY,CAAU,CAAC;AAErF;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,qBAAqB,CAAC,QAAQ,CAAC,YAAoD,CAAC,CAAC;AAC9F,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7C,mDAAmD;AACnD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAChD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC;QAE1E,2CAA2C;QAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpB,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED,qCAAqC;AACrC,MAAM,QAAQ,GAA2B;IACvC,KAAK,EAAE,iBAAiB;IACxB,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,iBAAiB;IACxB,MAAM,EAAE,iBAAiB;IACzB,OAAO,EAAE,kBAAkB;IAC3B,KAAK,EAAE,eAAe;IACtB,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,WAAW;IACnB,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,oBAAoB;IAC3B,MAAM,EAAE,YAAY;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;AACrD,CAAC"}
1
+ {"version":3,"file":"pathUtils.js","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,6DAA6D;AAC7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,YAAY,CAAU,CAAC;AAErF;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,qBAAqB,CAAC,QAAQ,CAAC,YAAoD,CAAC,CAAC;AAC9F,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7C,mDAAmD;AACnD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC;;;GAGG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,WAAW;IACX,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK;IAC3D,YAAY;IACZ,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO;IACzD,0BAA0B;IAC1B,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO;IAC1D,YAAY;IACZ,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM;IACpC,uEAAuE;IACvE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAChE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IACzC,QAAQ;IACR,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM;CAC1C,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,IAAI,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAChD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC;QAE1E,2CAA2C;QAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpB,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AACH,CAAC;AAED,qCAAqC;AACrC,MAAM,QAAQ,GAA2B;IACvC,KAAK,EAAE,iBAAiB;IACxB,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,iBAAiB;IACxB,MAAM,EAAE,iBAAiB;IACzB,OAAO,EAAE,kBAAkB;IAC3B,KAAK,EAAE,eAAe;IACtB,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,WAAW;IACpB,MAAM,EAAE,WAAW;IACnB,KAAK,EAAE,eAAe;IACtB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;IACvB,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,oBAAoB;IAC3B,MAAM,EAAE,YAAY;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,0BAA0B,CAAC;AACrD,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Story 30.1 (Task 1): single source of truth for secret-pattern heuristics
3
+ * used by the harness write paths.
4
+ *
5
+ * Replaces four drifted SECRET_PATTERNS definitions (harnessAgentService,
6
+ * harnessCommandService, harnessHookService, harnessMcpService). Drift
7
+ * before this module:
8
+ *
9
+ * - agent / command / hook : 32-char base64 unanchored, Bearer unanchored
10
+ * - mcp : 40-char base64 anchored, Bearer anchored
11
+ *
12
+ * Canonical chosen here (Story 30.1 sub-spike 1.0, option (b)):
13
+ * - 32-char base64 unanchored, Bearer unanchored
14
+ *
15
+ * Rationale: detection-rate first; Story 30.1 AC4.c provides a per-save
16
+ * "mark not a secret" opt-out that absorbs false positives, whereas missed
17
+ * detections silently leak credentials. MCP's stricter anchors were a local
18
+ * accident, not a deliberate spec decision.
19
+ *
20
+ * Two entry points are exposed because the four services walk two distinct
21
+ * shapes:
22
+ *
23
+ * - detectSecretsInText → string body (agent / command / hook commands)
24
+ * returns matched line numbers (1-based)
25
+ * - detectSecretsInValue → arbitrary JSON-like value (mcp config)
26
+ * returns matched dot-paths
27
+ *
28
+ * Both strip `${ENV_VAR}` references first so legitimate env-var indirection
29
+ * (`Authorization: 'Bearer ${GH_TOKEN}'`) does not raise false positives.
30
+ */
31
+ export interface SecretPattern {
32
+ name: string;
33
+ re: RegExp;
34
+ /**
35
+ * Optional minimum Shannon entropy (bits/char) gate for matched substrings.
36
+ * Story 30.3 spike #2: applies to the loose base64 pattern only. Natural
37
+ * English compounds (PascalCase identifiers, prose) sit at ~3.5–3.9; real
38
+ * base64-encoded tokens sit at ≥ 4.0 due to a-z/A-Z/0-9 uniform distribution.
39
+ * Other patterns keep their anchored prefixes (Bearer/sk-/AKIA/xox-) which
40
+ * already gate false positives — no entropy check needed.
41
+ */
42
+ minEntropy?: number;
43
+ }
44
+ export declare const SECRET_PATTERNS: readonly SecretPattern[];
45
+ export declare const ENV_REF_RE: RegExp;
46
+ /**
47
+ * Shannon entropy in bits/char of an arbitrary string. Used by patterns that
48
+ * opt in via `minEntropy` (currently the loose base64 pattern only).
49
+ */
50
+ export declare function shannonEntropy(s: string): number;
51
+ export interface DetectSecretsTextResult {
52
+ matched: boolean;
53
+ patternNames: string[];
54
+ lines: number[];
55
+ }
56
+ export interface DetectSecretsValueResult {
57
+ matched: boolean;
58
+ patternNames: string[];
59
+ paths: string[];
60
+ }
61
+ /**
62
+ * Line-based scanner for textual command / prompt bodies (agent system
63
+ * prompts, slash command bodies, hook command/prompt strings).
64
+ */
65
+ export declare function detectSecretsInText(text: string): DetectSecretsTextResult;
66
+ /**
67
+ * Object-walk scanner for JSON-like values (mcp server config). Each string
68
+ * leaf is evaluated against the canonical patterns; matches are reported as
69
+ * dot-paths (`env.GITHUB_TOKEN`, `headers.Authorization`, ...).
70
+ */
71
+ export declare function detectSecretsInValue(value: unknown, basePath?: string[]): DetectSecretsValueResult;
72
+ //# sourceMappingURL=secretHeuristic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secretHeuristic.d.ts","sourceRoot":"","sources":["../../src/utils/secretHeuristic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAMnD,CAAC;AAEF,eAAO,MAAM,UAAU,QAAkC,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAWhD;AAkCD,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAQD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,CA0BzE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,QAAQ,GAAE,MAAM,EAAO,GACtB,wBAAwB,CAgC1B"}