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,1211 @@
1
+ export type HarnessScope = 'user' | 'project';
2
+ export interface HarnessPathRef {
3
+ scope: HarnessScope;
4
+ /** Required when scope === 'project' */
5
+ projectSlug?: string;
6
+ /** Relative to ~/.claude (user) or <projectRoot>/.claude (project) */
7
+ relativePath: string;
8
+ }
9
+ export interface HarnessEntry {
10
+ name: string;
11
+ type: 'file' | 'directory';
12
+ size: number;
13
+ /** ISO 8601 — doubles as ETag */
14
+ modifiedAt: string;
15
+ }
16
+ export interface HarnessListResponse {
17
+ scope: HarnessScope;
18
+ projectSlug?: string;
19
+ /** Absolute path of ~/.claude or <project>/.claude */
20
+ resolvedRoot: string;
21
+ /** Echoed relativePath */
22
+ path: string;
23
+ entries: HarnessEntry[];
24
+ }
25
+ export interface HarnessReadResponse {
26
+ scope: HarnessScope;
27
+ projectSlug?: string;
28
+ path: string;
29
+ /** null when binary */
30
+ content: string | null;
31
+ isBinary: boolean;
32
+ /** True when file exceeds 1MB and was truncated */
33
+ isTruncated: boolean;
34
+ size: number;
35
+ /** ISO 8601 — ETag for conflict detection */
36
+ mtime: string;
37
+ mimeType: string;
38
+ /**
39
+ * Optional resolved absolute path of the file on disk. Populated by services
40
+ * (e.g. claudeMdService) that need the UI to display the canonical location
41
+ * in confirmation dialogs. Other harness services may leave this unset.
42
+ */
43
+ absolutePath?: string;
44
+ }
45
+ export interface HarnessWriteRequest {
46
+ content: string;
47
+ /** Omit to force overwrite (new file creation or explicit bypass) */
48
+ expectedMtime?: string;
49
+ }
50
+ export interface HarnessWriteResponse {
51
+ success: true;
52
+ size: number;
53
+ mtime: string;
54
+ }
55
+ /** One AST-level patch operation for structured files (YAML/JSONC). */
56
+ export interface HarnessStructuredPatchOp {
57
+ /** Key path into the parsed AST */
58
+ path: (string | number)[];
59
+ /** undefined = delete */
60
+ value: unknown | undefined;
61
+ }
62
+ export interface HarnessStructuredPatchRequest {
63
+ format: 'yaml' | 'jsonc';
64
+ ops: HarnessStructuredPatchOp[];
65
+ expectedMtime?: string;
66
+ }
67
+ export interface HarnessExternalChangeEvent {
68
+ scope: HarnessScope;
69
+ projectSlug?: string;
70
+ /** Relative path inside the resolved root (POSIX separators) */
71
+ path: string;
72
+ type: 'modified' | 'deleted' | 'created';
73
+ /** ISO 8601 when type !== 'deleted' */
74
+ mtime?: string;
75
+ }
76
+ /**
77
+ * Error code + HTTP status pairs. Modeled on the spirit of FILE_SYSTEM_ERRORS in
78
+ * packages/shared/src/types/fileSystem.ts but intentionally slimmer —
79
+ * FILE_SYSTEM_ERRORS carries `{code, message, httpStatus}` where `message` is a
80
+ * static Korean fallback that controllers never actually use (see
81
+ * fileSystemController.ts:297-328 — all user-facing messages go through
82
+ * `req.t!(...)` for i18n). Harness controllers follow the same pattern, so the
83
+ * static `message` field is dropped here and the envelope message is always
84
+ * produced by `req.t!('harness.error.<key>')`.
85
+ *
86
+ * There is no global Express error middleware in this codebase; this constant
87
+ * IS the single source of truth for (code → HTTP status) mapping.
88
+ */
89
+ export declare const HARNESS_ERRORS: {
90
+ readonly HARNESS_PATH_DENIED: {
91
+ readonly code: "HARNESS_PATH_DENIED";
92
+ readonly httpStatus: 403;
93
+ };
94
+ readonly HARNESS_FORBIDDEN: {
95
+ readonly code: "HARNESS_FORBIDDEN";
96
+ readonly httpStatus: 403;
97
+ };
98
+ readonly HARNESS_PLUGIN_SCOPE_DENIED: {
99
+ readonly code: "HARNESS_PLUGIN_SCOPE_DENIED";
100
+ readonly httpStatus: 403;
101
+ };
102
+ readonly HARNESS_FILE_NOT_FOUND: {
103
+ readonly code: "HARNESS_FILE_NOT_FOUND";
104
+ readonly httpStatus: 404;
105
+ };
106
+ readonly HARNESS_NOT_A_FILE: {
107
+ readonly code: "HARNESS_NOT_A_FILE";
108
+ readonly httpStatus: 404;
109
+ };
110
+ readonly HARNESS_ROOT_MISSING: {
111
+ readonly code: "HARNESS_ROOT_MISSING";
112
+ readonly httpStatus: 404;
113
+ };
114
+ readonly HARNESS_PARENT_NOT_FOUND: {
115
+ readonly code: "HARNESS_PARENT_NOT_FOUND";
116
+ readonly httpStatus: 404;
117
+ };
118
+ readonly HARNESS_PLUGIN_NOT_FOUND: {
119
+ readonly code: "HARNESS_PLUGIN_NOT_FOUND";
120
+ readonly httpStatus: 404;
121
+ };
122
+ readonly HARNESS_SKILL_NOT_FOUND: {
123
+ readonly code: "HARNESS_SKILL_NOT_FOUND";
124
+ readonly httpStatus: 404;
125
+ };
126
+ readonly HARNESS_MCP_NOT_FOUND: {
127
+ readonly code: "HARNESS_MCP_NOT_FOUND";
128
+ readonly httpStatus: 404;
129
+ };
130
+ readonly HARNESS_HOOK_NOT_FOUND: {
131
+ readonly code: "HARNESS_HOOK_NOT_FOUND";
132
+ readonly httpStatus: 404;
133
+ };
134
+ readonly HARNESS_HOOK_INVALID_EVENT: {
135
+ readonly code: "HARNESS_HOOK_INVALID_EVENT";
136
+ readonly httpStatus: 400;
137
+ };
138
+ readonly HARNESS_COMMAND_NOT_FOUND: {
139
+ readonly code: "HARNESS_COMMAND_NOT_FOUND";
140
+ readonly httpStatus: 404;
141
+ };
142
+ readonly HARNESS_STALE_WRITE: {
143
+ readonly code: "HARNESS_STALE_WRITE";
144
+ readonly httpStatus: 409;
145
+ };
146
+ readonly HARNESS_FILE_EXISTS: {
147
+ readonly code: "HARNESS_FILE_EXISTS";
148
+ readonly httpStatus: 409;
149
+ };
150
+ readonly HARNESS_SKILL_NAME_CONFLICT: {
151
+ readonly code: "HARNESS_SKILL_NAME_CONFLICT";
152
+ readonly httpStatus: 409;
153
+ };
154
+ readonly HARNESS_MCP_NAME_CONFLICT: {
155
+ readonly code: "HARNESS_MCP_NAME_CONFLICT";
156
+ readonly httpStatus: 409;
157
+ };
158
+ readonly HARNESS_COMMAND_NAME_CONFLICT: {
159
+ readonly code: "HARNESS_COMMAND_NAME_CONFLICT";
160
+ readonly httpStatus: 409;
161
+ };
162
+ readonly HARNESS_AGENT_NOT_FOUND: {
163
+ readonly code: "HARNESS_AGENT_NOT_FOUND";
164
+ readonly httpStatus: 404;
165
+ };
166
+ readonly HARNESS_AGENT_NAME_CONFLICT: {
167
+ readonly code: "HARNESS_AGENT_NAME_CONFLICT";
168
+ readonly httpStatus: 409;
169
+ };
170
+ readonly HARNESS_PARSE_ERROR: {
171
+ readonly code: "HARNESS_PARSE_ERROR";
172
+ readonly httpStatus: 422;
173
+ };
174
+ readonly HARNESS_WRITE_ERROR: {
175
+ readonly code: "HARNESS_WRITE_ERROR";
176
+ readonly httpStatus: 500;
177
+ };
178
+ readonly HARNESS_BUNDLED_READONLY: {
179
+ readonly code: "HARNESS_BUNDLED_READONLY";
180
+ readonly httpStatus: 409;
181
+ };
182
+ readonly HARNESS_SECRET_ON_SHARED: {
183
+ readonly code: "HARNESS_SECRET_ON_SHARED";
184
+ readonly httpStatus: 409;
185
+ };
186
+ };
187
+ export type HarnessErrorCode = typeof HARNESS_ERRORS[keyof typeof HARNESS_ERRORS]['code'];
188
+ /** Raw ~/.claude/plugins/installed_plugins.json entry. */
189
+ export interface HarnessInstalledPluginEntry {
190
+ scope: HarnessScope;
191
+ installPath: string;
192
+ version: string;
193
+ installedAt: string;
194
+ lastUpdated: string;
195
+ gitCommitSha: string;
196
+ /** Present when scope === 'project'. */
197
+ projectPath?: string;
198
+ }
199
+ /** Minimal shape of <installPath>/.claude-plugin/plugin.json. */
200
+ export interface HarnessPluginManifest {
201
+ name: string;
202
+ description?: string;
203
+ author?: {
204
+ name?: string;
205
+ email?: string;
206
+ } | string;
207
+ version?: string;
208
+ }
209
+ /** Marketplace catalog entry (marketplace.json · plugins[]). */
210
+ export interface HarnessMarketplacePluginMeta {
211
+ name: string;
212
+ description?: string;
213
+ category?: string;
214
+ strict?: boolean;
215
+ source?: string;
216
+ }
217
+ export type HarnessPluginType = 'standard' | 'external-mcp';
218
+ export interface HarnessPluginComponentCounts {
219
+ skills: number;
220
+ commands: number;
221
+ agents: number;
222
+ hooks: number;
223
+ mcpServers: number;
224
+ }
225
+ export interface HarnessPluginCard {
226
+ /** "<name>@<marketplace>" — matches enabledPlugins key space. */
227
+ key: string;
228
+ name: string;
229
+ marketplace: string;
230
+ /** Short commit sha (first 7 chars of gitCommitSha). */
231
+ version: string;
232
+ scope: HarnessScope;
233
+ category?: string;
234
+ projectPath?: string;
235
+ enabled: boolean;
236
+ pluginType: HarnessPluginType;
237
+ componentCounts: HarnessPluginComponentCounts;
238
+ manifest?: HarnessPluginManifest;
239
+ /**
240
+ * Which settings.json this card's enable/disable toggle writes to. Matches
241
+ * the CLI's `/plugin install --scope` semantics:
242
+ * - 'user' → ~/.claude/settings.json
243
+ * - 'project' → <currentProjectPath>/.claude/settings.json
244
+ * Cards whose installed_plugins.json entry is `scope:project` but whose
245
+ * `projectPath` does not match the current session's project still report
246
+ * `'user'` here (their toggle is gated by `HARNESS_PLUGIN_SCOPE_DENIED` so
247
+ * the field is informational only in that case).
248
+ */
249
+ settingsScope: HarnessScope;
250
+ /**
251
+ * ISO mtime of the settings.json indicated by `settingsScope`. Used as the
252
+ * `expectedMtime` value the client should send with the next toggle for this
253
+ * card — keeps STALE_WRITE detection accurate when user/project settings.json
254
+ * mtimes diverge.
255
+ */
256
+ settingsMtime: string;
257
+ }
258
+ export type HarnessEnabledPluginsFormat = 'array' | 'object';
259
+ export interface HarnessPluginListResponse {
260
+ cards: HarnessPluginCard[];
261
+ enabledPluginsFormat: HarnessEnabledPluginsFormat;
262
+ currentProjectPath?: string;
263
+ /**
264
+ * ISO mtime of ~/.claude/settings.json at read time. Empty string when the
265
+ * file did not yet exist. Consumed by the client store so that the next
266
+ * toggle request carries a fresh `expectedMtime` — prevents a STALE_WRITE
267
+ * → reload → STALE_WRITE loop after external edits.
268
+ */
269
+ settingsMtime: string;
270
+ }
271
+ export interface HarnessPluginToggleRequest {
272
+ key: string;
273
+ enabled: boolean;
274
+ expectedMtime?: string;
275
+ }
276
+ export interface HarnessPluginToggleResponse {
277
+ success: true;
278
+ mtime: string;
279
+ /** Informational echo of the format the server actually wrote. */
280
+ appliedFormat: HarnessEnabledPluginsFormat;
281
+ }
282
+ export type HarnessSkillSourceScope = 'project' | 'user' | 'plugin';
283
+ /** YAML frontmatter shape inside <skillDir>/SKILL.md. */
284
+ export interface HarnessSkillFrontmatter {
285
+ name: string;
286
+ description: string;
287
+ version?: string;
288
+ }
289
+ /** File counts under each well-known bundle directory of a skill. */
290
+ export interface HarnessSkillBundleCounts {
291
+ references: number;
292
+ examples: number;
293
+ scripts: number;
294
+ assets: number;
295
+ }
296
+ /**
297
+ * Identifies one source location that holds a particular skill name. The same
298
+ * `name` (directory name) may exist in 1–3 places (project, user, plugin) and
299
+ * each gets a separate `HarnessSkillSourceLocation`.
300
+ */
301
+ export interface HarnessSkillSourceLocation {
302
+ scope: HarnessSkillSourceScope;
303
+ /**
304
+ * Absolute path of the skill folder root. For project / user this is
305
+ * `<scopeRoot>/.claude/skills/<name>/`; for plugin this is
306
+ * `<installPath>/skills/<name>/`.
307
+ */
308
+ absoluteRoot: string;
309
+ /** scope === 'plugin' → "<pluginName>@<marketplace>". */
310
+ pluginKey?: string;
311
+ /** scope === 'project' → the active project's slug. */
312
+ projectSlug?: string;
313
+ }
314
+ /**
315
+ * Card-level DTO. Even when the same skill name exists in all three sources,
316
+ * the UI shows a single card with `sources[]` populated; `activeScope`
317
+ * reflects the priority resolution (project > user > plugin).
318
+ */
319
+ export interface HarnessSkillCard {
320
+ /** Skill directory name; matches the `name` frontmatter field. */
321
+ name: string;
322
+ /** Active source's frontmatter description (if present). */
323
+ description?: string;
324
+ /** Active source's frontmatter version (if present). */
325
+ version?: string;
326
+ /** 1–3 entries — one per existing scope. Sorted by priority. */
327
+ sources: HarnessSkillSource[];
328
+ /** Resolved priority (project > user > plugin). */
329
+ activeScope: HarnessSkillSourceScope;
330
+ }
331
+ /** A single source entry attached to a card. */
332
+ export interface HarnessSkillSource extends HarnessSkillSourceLocation {
333
+ /** Validated frontmatter — sources whose frontmatter failed parse are excluded. */
334
+ frontmatter: HarnessSkillFrontmatter;
335
+ /** ISO mtime of SKILL.md — used as STALE_WRITE ETag. */
336
+ skillMdMtime: string;
337
+ }
338
+ export interface HarnessSkillListResponse {
339
+ cards: HarnessSkillCard[];
340
+ /**
341
+ * SKILL.md files that failed frontmatter validation. Surfaced separately so
342
+ * the UI can render a "shadowed by malformed frontmatter" badge without the
343
+ * card list silently growing.
344
+ */
345
+ malformed: HarnessSkillMalformedEntry[];
346
+ }
347
+ export interface HarnessSkillMalformedEntry {
348
+ scope: HarnessSkillSourceScope;
349
+ absoluteRoot: string;
350
+ pluginKey?: string;
351
+ projectSlug?: string;
352
+ /** Raw failure reason — UI maps to an i18n key. */
353
+ reason: string;
354
+ }
355
+ export interface HarnessSkillReadResponse {
356
+ source: HarnessSkillSourceLocation;
357
+ frontmatter: HarnessSkillFrontmatter;
358
+ /** SKILL.md body — content after the closing `---` of the frontmatter block. */
359
+ body: string;
360
+ /** Full SKILL.md text (frontmatter + body) — used by the Raw editor toggle. */
361
+ raw: string;
362
+ bundleCounts: HarnessSkillBundleCounts;
363
+ skillMdMtime: string;
364
+ bundleEntries: HarnessSkillBundleEntry[];
365
+ /** True when the bundle tree was clipped at the configured depth limit. */
366
+ truncatedAtDepth: boolean;
367
+ }
368
+ export interface HarnessSkillBundleEntry {
369
+ /** Path relative to the skill root, e.g. "references/foo.md". */
370
+ relativePath: string;
371
+ isBinary: boolean;
372
+ isTruncated: boolean;
373
+ size: number;
374
+ mtime: string;
375
+ }
376
+ export interface HarnessSkillUpdateRequest {
377
+ /** Frontmatter form save — translated into a YAML round-trip on disk. */
378
+ frontmatter?: Partial<HarnessSkillFrontmatter>;
379
+ /** Body-only replace — keeps the existing frontmatter block intact. */
380
+ body?: string;
381
+ /** Raw replace — overwrites the entire SKILL.md with the supplied text. */
382
+ raw?: string;
383
+ /** STALE_WRITE guard — most recent skillMdMtime the client saw. */
384
+ expectedMtime?: string;
385
+ }
386
+ export interface HarnessSkillUpdateResponse {
387
+ success: true;
388
+ mtime: string;
389
+ }
390
+ export interface HarnessSkillCopyRequest {
391
+ sourceScope: HarnessSkillSourceScope;
392
+ /** Required when sourceScope === 'project'. */
393
+ sourceProjectSlug?: string;
394
+ /** Required when sourceScope === 'plugin'. */
395
+ sourcePluginKey?: string;
396
+ /** Skill directory name on the source side. */
397
+ sourceName: string;
398
+ /** Plugin destinations are forbidden — only project/user are allowed. */
399
+ targetScope: 'project' | 'user';
400
+ /** Required when targetScope === 'project'. */
401
+ targetProjectSlug?: string;
402
+ /** Final directory name on the target side; equal to `sourceName` for non-rename copies. */
403
+ targetName: string;
404
+ onConflict: 'overwrite' | 'skip' | 'rename';
405
+ }
406
+ export interface HarnessSkillCopyResponse {
407
+ success: true;
408
+ /** Number of files written under the new tree. */
409
+ copied: number;
410
+ /** True when onConflict === 'skip' and a conflict was actually hit. */
411
+ skipped: boolean;
412
+ /** Final directory name actually created (may differ from the request when renaming). */
413
+ finalName: string;
414
+ }
415
+ export type HarnessMcpSourceScope = 'project' | 'user' | 'plugin';
416
+ /** Stdio default per official MCP schema; explicit when set. */
417
+ export type HarnessMcpServerType = 'stdio' | 'sse' | 'http' | 'ws';
418
+ /** Common shape — all four type variants. type=stdio when omitted on disk. */
419
+ export interface HarnessMcpServerConfig {
420
+ type?: HarnessMcpServerType;
421
+ command?: string;
422
+ args?: string[];
423
+ url?: string;
424
+ headers?: Record<string, string>;
425
+ env?: Record<string, string>;
426
+ /**
427
+ * Disk-level enabled flag. Spike A 경로 1 (flag honored) 채택 시에만 디스크에
428
+ * 등장 — 명시 false 가 비활성, 키 부재(또는 true) 가 활성. 경로 2 (backup
429
+ * file) 채택 시 디스크에는 절대 나타나지 않으며 비활성은 entry 를
430
+ * mcp.disabled.json 백업 파일로 이동시켜 표현한다. 응답 측
431
+ * HarnessMcpCard.enabled 가 두 경로의 의미 차이를 흡수해 UI 토글에 단일
432
+ * boolean 으로 노출한다.
433
+ */
434
+ enabled?: boolean;
435
+ }
436
+ /** File kind hosting the server entry — informs server-side path/parsing. */
437
+ export type HarnessMcpSourceFileKind = 'mcp.json' | 'settings.json' | 'plugin.json';
438
+ export interface HarnessMcpSourceLocation {
439
+ scope: HarnessMcpSourceScope;
440
+ /** Absolute path of the file holding this server's entry. */
441
+ absoluteFile: string;
442
+ /** scope === 'plugin' → "<pluginName>@<marketplace>". */
443
+ pluginKey?: string;
444
+ /** scope === 'project' → the active project's slug. */
445
+ projectSlug?: string;
446
+ /** Spike B 후보 2 채택 시 'settings.json' / 후보 1 채택 시 'mcp.json' / plugin 은 'mcp.json' 또는 'plugin.json'. */
447
+ sourceFileKind: HarnessMcpSourceFileKind;
448
+ }
449
+ export interface HarnessMcpSource extends HarnessMcpSourceLocation {
450
+ config: HarnessMcpServerConfig;
451
+ /** ISO mtime of `absoluteFile` — STALE_WRITE ETag. */
452
+ mtime: string;
453
+ /** True when this entry currently lives in the disabled-backup file (Spike A 경로 2). */
454
+ disabledByBackup: boolean;
455
+ }
456
+ export interface HarnessMcpCard {
457
+ /** Server name = `mcpServers.<name>` key. */
458
+ name: string;
459
+ /** Active source's `type` field after default-stdio resolution. */
460
+ activeType: HarnessMcpServerType;
461
+ /**
462
+ * Resolved active state — UI uses this directly for the toggle.
463
+ * 경로 1 (Spike A flag 지원): true ⇔ active source 의 HarnessMcpServerConfig.enabled !== false.
464
+ * 경로 2 (Spike A backup 우회): true ⇔ active source 가 main 파일에 살아 있음
465
+ * (= !sources[activeIndex].disabledByBackup).
466
+ */
467
+ enabled: boolean;
468
+ /** 1–N entries — one per existing scope×file. Sorted by priority (project > user > plugin). */
469
+ sources: HarnessMcpSource[];
470
+ activeScope: HarnessMcpSourceScope;
471
+ }
472
+ export interface HarnessMcpMalformedEntry {
473
+ scope: HarnessMcpSourceScope;
474
+ absoluteFile: string;
475
+ serverName: string;
476
+ pluginKey?: string;
477
+ projectSlug?: string;
478
+ reason: string;
479
+ }
480
+ export interface HarnessMcpListResponse {
481
+ cards: HarnessMcpCard[];
482
+ /**
483
+ * Servers whose JSON object failed schema validation. Surfaced separately so
484
+ * the UI shows a "shadowed by malformed config" badge without the card list
485
+ * silently growing.
486
+ */
487
+ malformed: HarnessMcpMalformedEntry[];
488
+ /**
489
+ * Spike B outcome cached so the client UI can render the right empty-state.
490
+ * `null` means Claude Code does not recognise a global MCP file at all.
491
+ */
492
+ userFileKind: 'mcp.json' | 'settings.json' | null;
493
+ /**
494
+ * Spike A outcome cached. 'flag' = enabled flag honored (경로 1).
495
+ * 'backup' = disabled-backup file (경로 2).
496
+ */
497
+ disableStrategy: 'flag' | 'backup';
498
+ }
499
+ export interface HarnessMcpReadResponse {
500
+ source: HarnessMcpSourceLocation;
501
+ config: HarnessMcpServerConfig;
502
+ /** Raw JSON/JSONC text of the entire `mcpServers.<name>` object — used by the Raw editor toggle. */
503
+ raw: string;
504
+ mtime: string;
505
+ disabledByBackup: boolean;
506
+ }
507
+ /**
508
+ * Update request — exactly one of `config`, `raw`, or `enabled` is required.
509
+ * `enabled` is a no-arg toggle that routes through `disableStrategy` (see Spike A):
510
+ * - 'flag' → patches `mcpServers.<name>.enabled` true/false
511
+ * - 'backup' → moves the entry between main file and `mcp.disabled.json`
512
+ */
513
+ export interface HarnessMcpUpdateRequest {
514
+ config?: HarnessMcpServerConfig;
515
+ raw?: string;
516
+ enabled?: boolean;
517
+ expectedMtime?: string;
518
+ }
519
+ export interface HarnessMcpUpdateResponse {
520
+ success: true;
521
+ mtime: string;
522
+ }
523
+ export interface HarnessMcpCopyRequest {
524
+ sourceScope: HarnessMcpSourceScope;
525
+ sourceProjectSlug?: string;
526
+ sourcePluginKey?: string;
527
+ /** plugin sources may live in either .mcp.json or plugin.json — must be echoed. */
528
+ sourceFileKind?: HarnessMcpSourceFileKind;
529
+ sourceName: string;
530
+ /** plugin destinations forbidden — only project/user are allowed. */
531
+ targetScope: 'project' | 'user';
532
+ targetProjectSlug?: string;
533
+ targetName: string;
534
+ onConflict: 'overwrite' | 'skip' | 'rename';
535
+ /** Client must echo `true` after showing the secret-confirmation modal when heuristics matched. */
536
+ acknowledgedSecret?: boolean;
537
+ }
538
+ export interface HarnessMcpCopyResponse {
539
+ success: true;
540
+ finalName: string;
541
+ skipped: boolean;
542
+ /**
543
+ * Optional warnings the client surfaces as toasts. Currently only
544
+ * `'plugin-root-reference'` (the source contained `${CLAUDE_PLUGIN_ROOT}`).
545
+ */
546
+ warnings?: string[];
547
+ }
548
+ export interface HarnessMcpDeleteRequest {
549
+ scope: 'project' | 'user';
550
+ projectSlug?: string;
551
+ expectedMtime?: string;
552
+ }
553
+ export type HarnessHookSourceScope = 'project' | 'user' | 'plugin';
554
+ export type HarnessHookType = 'command' | 'prompt';
555
+ export declare const HARNESS_HOOK_EVENTS: readonly ["PreToolUse", "PostToolUse", "Stop", "SubagentStop", "SessionStart", "SessionEnd", "UserPromptSubmit", "PreCompact", "Notification"];
556
+ export type HarnessHookEvent = (typeof HARNESS_HOOK_EVENTS)[number];
557
+ /** Single hook entry — what one card represents. */
558
+ export interface HarnessHookConfig {
559
+ type: HarnessHookType;
560
+ /** Required when type === 'command'. */
561
+ command?: string;
562
+ /** Required when type === 'prompt'. */
563
+ prompt?: string;
564
+ /** Seconds (official spec); omit = Claude Code default. */
565
+ timeout?: number;
566
+ }
567
+ export interface HarnessHookSourceLocation {
568
+ scope: HarnessHookSourceScope;
569
+ /** Absolute path of the file holding this hook. */
570
+ absoluteFile: string;
571
+ /** scope === 'plugin' → "<pluginName>@<marketplace>". */
572
+ pluginKey?: string;
573
+ /** scope === 'project' → the active project's slug. */
574
+ projectSlug?: string;
575
+ /** Hook event name. */
576
+ event: HarnessHookEvent;
577
+ /** Index within `hooks.<event>` array (the matcher group index). */
578
+ groupIndex: number;
579
+ /** Index within `hooks.<event>[groupIndex].hooks` array. */
580
+ hookIndex: number;
581
+ /** True when this entry currently lives in the disabled-backup file (AC5). */
582
+ disabledByBackup: boolean;
583
+ }
584
+ export interface HarnessHookCard extends HarnessHookSourceLocation {
585
+ /** Group-level matcher (may be undefined or empty string). */
586
+ matcher?: string;
587
+ config: HarnessHookConfig;
588
+ /** ISO mtime of `absoluteFile` — STALE_WRITE ETag. */
589
+ mtime: string;
590
+ /**
591
+ * Resolved active state — UI uses this directly for the toggle.
592
+ * true ⇔ this entry currently lives in the main settings/hooks file.
593
+ * false ⇔ disabledByBackup === true.
594
+ */
595
+ enabled: boolean;
596
+ }
597
+ export interface HarnessHookMalformedEntry {
598
+ scope: HarnessHookSourceScope;
599
+ absoluteFile: string;
600
+ event?: HarnessHookEvent;
601
+ pluginKey?: string;
602
+ projectSlug?: string;
603
+ reason: string;
604
+ }
605
+ export interface HarnessHookListResponse {
606
+ /** Cards keyed by event for fast UI grouping; each list sorted by (scope, groupIndex, hookIndex). */
607
+ cardsByEvent: Record<HarnessHookEvent, HarnessHookCard[]>;
608
+ malformed: HarnessHookMalformedEntry[];
609
+ /**
610
+ * Spike outcome cached. 'supported' = `prompt` type works ⇒ UI radio enabled.
611
+ * 'unsupported' = `prompt` rejected ⇒ UI radio disabled (existing prompt cards still listed read-only).
612
+ * 'unknown' = pre-impl path, dev agent has not yet run the spike.
613
+ */
614
+ promptTypeSupport: 'supported' | 'unsupported' | 'unknown';
615
+ /**
616
+ * AC5 two-file STALE_WRITE guard support — current mtime of `hooks.disabled.json`
617
+ * for each writable scope. Absent key ⇔ backup file does not exist yet (server will
618
+ * create it on first disable). Clients must echo this back as
619
+ * `HarnessHookUpdateRequest.expectedBackupMtime` whenever toggling `enabled`.
620
+ */
621
+ backupMtimeByScope: {
622
+ project?: string;
623
+ user?: string;
624
+ };
625
+ }
626
+ export interface HarnessHookReadResponse {
627
+ source: HarnessHookSourceLocation;
628
+ matcher?: string;
629
+ config: HarnessHookConfig;
630
+ /** Raw JSONC text of `{ matcher?, hooks: [<this>] }` — used by the Raw editor toggle. */
631
+ raw: string;
632
+ mtime: string;
633
+ disabledByBackup: boolean;
634
+ }
635
+ /**
636
+ * Update request — exactly one of `config`/`matcher`/`raw`/`enabled` is required.
637
+ * `enabled` toggles backup-file movement (AC5 path).
638
+ * `matcher` updates the parent matcher group's matcher field; if `splitFromGroup` is true
639
+ * the hook is first extracted into a new single-hook group and the matcher applies to
640
+ * only that new group (sibling hooks keep the original matcher untouched).
641
+ */
642
+ export interface HarnessHookUpdateRequest {
643
+ config?: HarnessHookConfig;
644
+ /** null = unset (omit the field on disk). */
645
+ matcher?: string | null;
646
+ raw?: string;
647
+ enabled?: boolean;
648
+ /** STALE_WRITE guard for the main settings.json file. */
649
+ expectedMtime?: string;
650
+ /**
651
+ * AC5 two-file guard — STALE_WRITE guard for `hooks.disabled.json`. Required when
652
+ * `enabled` is being toggled AND the backup file already exists (per
653
+ * HarnessHookListResponse.backupMtimeByScope). Server returns 409 with
654
+ * `details.staleFile: 'main' | 'backup'` to disambiguate which file conflicted.
655
+ */
656
+ expectedBackupMtime?: string;
657
+ /**
658
+ * AC3 sibling protection — only meaningful when `matcher` is also set. When true and
659
+ * the parent group contains 2+ hooks, server first extracts this hook into a new
660
+ * single-hook group (preserving the original group for siblings) and then applies the
661
+ * new matcher to the extracted group only. False (default) keeps the existing behavior
662
+ * — matcher updates the parent group and affects all sibling hooks.
663
+ */
664
+ splitFromGroup?: boolean;
665
+ }
666
+ export interface HarnessHookUpdateResponse {
667
+ success: true;
668
+ mtime: string;
669
+ /**
670
+ * Present only when AC5 enabled-toggle path was taken — the backup file's new mtime
671
+ * after the two-file transaction. Clients persist this back into
672
+ * `HarnessHookListResponse.backupMtimeByScope` so the next toggle has the freshest guard.
673
+ */
674
+ backupMtime?: string;
675
+ /**
676
+ * Present only when `matcher` was updated AND server affected sibling hooks
677
+ * (group had 2+ hooks AND splitFromGroup was false/omitted). Tells the client how
678
+ * many other hooks now share the new matcher so it can show the post-save banner.
679
+ */
680
+ affectedSiblings?: number;
681
+ /**
682
+ * Present only when `matcher + splitFromGroup:true` extracted this hook to a new
683
+ * group; the new (groupIndex, hookIndex) replaces the request coordinates.
684
+ */
685
+ newGroupIndex?: number;
686
+ newHookIndex?: number;
687
+ }
688
+ export interface HarnessHookCopyRequest {
689
+ sourceScope: HarnessHookSourceScope;
690
+ sourceProjectSlug?: string;
691
+ sourcePluginKey?: string;
692
+ sourceEvent: HarnessHookEvent;
693
+ sourceGroupIndex: number;
694
+ sourceHookIndex: number;
695
+ /** plugin destinations forbidden — only project/user are allowed. */
696
+ targetScope: 'project' | 'user';
697
+ targetProjectSlug?: string;
698
+ onConflict: 'overwrite' | 'skip' | 'duplicate';
699
+ /** Client must echo `true` after showing the type-warning modal. */
700
+ acknowledgedWarning: boolean;
701
+ }
702
+ export interface HarnessHookCopyResponse {
703
+ success: true;
704
+ newGroupIndex: number;
705
+ newHookIndex: number;
706
+ skipped: boolean;
707
+ /** Returned when ${CLAUDE_PLUGIN_ROOT} appeared in source body. */
708
+ warnings?: Array<'plugin-root-reference'>;
709
+ }
710
+ export interface HarnessHookDeleteRequest {
711
+ scope: 'project' | 'user';
712
+ projectSlug?: string;
713
+ event: HarnessHookEvent;
714
+ groupIndex: number;
715
+ hookIndex: number;
716
+ expectedMtime?: string;
717
+ }
718
+ export interface HarnessHookCreateRequest {
719
+ scope: 'project' | 'user';
720
+ projectSlug?: string;
721
+ event: HarnessHookEvent;
722
+ matcher?: string;
723
+ config: HarnessHookConfig;
724
+ expectedMtime?: string;
725
+ }
726
+ export interface HarnessHookCreateResponse {
727
+ success: true;
728
+ newGroupIndex: number;
729
+ newHookIndex: number;
730
+ mtime: string;
731
+ }
732
+ export type HarnessCommandSourceScope = 'project' | 'user' | 'plugin';
733
+ export type HarnessCommandModel = 'inherit' | 'sonnet' | 'opus' | 'haiku';
734
+ /** Frontmatter — all four fields optional per official spec. */
735
+ export interface HarnessCommandFrontmatter {
736
+ description?: string;
737
+ 'argument-hint'?: string;
738
+ 'allowed-tools'?: string;
739
+ model?: HarnessCommandModel;
740
+ }
741
+ export interface HarnessCommandSourceLocation {
742
+ scope: HarnessCommandSourceScope;
743
+ /** Absolute path of the .md file. */
744
+ absoluteFile: string;
745
+ /** scope === 'plugin' → "<pluginName>@<marketplace>". */
746
+ pluginKey?: string;
747
+ /** scope === 'project' → the active project's slug. */
748
+ projectSlug?: string;
749
+ /** Path under the commands root, with `/` separator. e.g. "BMad/agents/sm.md". */
750
+ relativePath: string;
751
+ /** Slash-name derived from relativePath. e.g. "/BMad:agents:sm". */
752
+ slashName: string;
753
+ }
754
+ export interface HarnessCommandTokens {
755
+ usesPositionalArgs: boolean;
756
+ usesArgumentsAll: boolean;
757
+ usesFileRefs: boolean;
758
+ usesBashExec: boolean;
759
+ usesPluginRoot: boolean;
760
+ }
761
+ export interface HarnessCommandCard extends HarnessCommandSourceLocation {
762
+ frontmatter: HarnessCommandFrontmatter;
763
+ /** Token usage flags — driven by simple regex over body, used by AC1(c) badges. */
764
+ tokens: HarnessCommandTokens;
765
+ /** ISO mtime of `absoluteFile` — STALE_WRITE ETag. */
766
+ mtime: string;
767
+ /**
768
+ * True when the file body's first 10 lines contain `<!-- Powered by BMAD™ Core -->`
769
+ * (AC5.b). Real BMad mirrors place the marker at line 5, not line 1, so a
770
+ * leading-window substring match — not a "starts with" check — is required.
771
+ */
772
+ isBmadMirror: boolean;
773
+ }
774
+ export interface HarnessCommandMalformedEntry {
775
+ scope: HarnessCommandSourceScope;
776
+ absoluteFile: string;
777
+ pluginKey?: string;
778
+ projectSlug?: string;
779
+ reason: string;
780
+ }
781
+ export interface HarnessCommandListResponse {
782
+ cards: HarnessCommandCard[];
783
+ malformed: HarnessCommandMalformedEntry[];
784
+ /**
785
+ * Total count after de-dup with scanAgents/scanTasks (the chat slash palette merge layer).
786
+ * Used by the workbench panel header badge ("N개 커맨드가 채팅의 / 팔레트에 노출됩니다").
787
+ */
788
+ paletteVisibleCount: number;
789
+ }
790
+ export interface HarnessCommandReadResponse {
791
+ source: HarnessCommandSourceLocation;
792
+ frontmatter: HarnessCommandFrontmatter;
793
+ /** Body markdown after the closing `---` (frontmatter stripped). */
794
+ body: string;
795
+ /** Raw text of the entire file (frontmatter + body) — used by Raw editor toggle. */
796
+ raw: string;
797
+ mtime: string;
798
+ isBmadMirror: boolean;
799
+ }
800
+ /**
801
+ * Update request — exactly one of `frontmatter`/`body`/`raw` is required.
802
+ * `frontmatter` and `body` patch separately (frontmatter via yaml round-trip,
803
+ * body as plain text replacement). `raw` replaces the whole file.
804
+ */
805
+ export interface HarnessCommandUpdateRequest {
806
+ frontmatter?: HarnessCommandFrontmatter;
807
+ body?: string;
808
+ raw?: string;
809
+ /** STALE_WRITE guard. */
810
+ expectedMtime?: string;
811
+ }
812
+ export interface HarnessCommandUpdateResponse {
813
+ success: true;
814
+ mtime: string;
815
+ slashName: string;
816
+ tokens: HarnessCommandTokens;
817
+ }
818
+ export interface HarnessCommandCreateRequest {
819
+ scope: 'project' | 'user';
820
+ projectSlug?: string;
821
+ /** Relative path under commands root. Must end in `.md`. */
822
+ relativePath: string;
823
+ frontmatter?: HarnessCommandFrontmatter;
824
+ body?: string;
825
+ }
826
+ export interface HarnessCommandCreateResponse {
827
+ success: true;
828
+ source: HarnessCommandSourceLocation;
829
+ mtime: string;
830
+ }
831
+ export interface HarnessCommandCopyRequest {
832
+ sourceScope: HarnessCommandSourceScope;
833
+ sourceProjectSlug?: string;
834
+ sourcePluginKey?: string;
835
+ sourceRelativePath: string;
836
+ /** plugin destinations forbidden — only project/user allowed. */
837
+ targetScope: 'project' | 'user';
838
+ targetProjectSlug?: string;
839
+ /** When undefined, server uses sourceRelativePath. */
840
+ targetRelativePath?: string;
841
+ onConflict: 'overwrite' | 'skip' | 'rename';
842
+ /** Required when sensitive content is detected by the secret heuristic. */
843
+ acknowledgedSecret?: boolean;
844
+ }
845
+ export interface HarnessCommandCopyResponse {
846
+ success: true;
847
+ target: HarnessCommandSourceLocation;
848
+ skipped: boolean;
849
+ /** Returned when ${CLAUDE_PLUGIN_ROOT} appeared in source. */
850
+ warnings?: Array<'plugin-root-reference'>;
851
+ }
852
+ export interface HarnessCommandDirectoryCopyRequest {
853
+ sourceScope: HarnessCommandSourceScope;
854
+ sourceProjectSlug?: string;
855
+ sourcePluginKey?: string;
856
+ /** Directory path under commands root. e.g. "BMad/agents". */
857
+ sourceDirectoryPath: string;
858
+ targetScope: 'project' | 'user';
859
+ targetProjectSlug?: string;
860
+ targetDirectoryPath?: string;
861
+ onConflict: 'overwrite-all' | 'skip-all' | 'per-file';
862
+ /**
863
+ * When onConflict === 'per-file', the server returns 409 with a `details.conflicts`
864
+ * payload listing the relative paths. The client populates this map and re-issues.
865
+ */
866
+ perFileChoices?: Record<string, 'overwrite' | 'skip' | 'rename'>;
867
+ /** Renamed targets when 'rename' is chosen for any file. */
868
+ perFileRenames?: Record<string, string>;
869
+ acknowledgedSecret?: boolean;
870
+ }
871
+ export interface HarnessCommandDirectoryCopyResponse {
872
+ success: true;
873
+ copied: HarnessCommandSourceLocation[];
874
+ skipped: string[];
875
+ warnings?: Array<'plugin-root-reference'>;
876
+ }
877
+ export interface HarnessCommandDeleteRequest {
878
+ scope: 'project' | 'user';
879
+ projectSlug?: string;
880
+ relativePath: string;
881
+ expectedMtime?: string;
882
+ }
883
+ export type HarnessAgentSourceScope = 'project' | 'user' | 'plugin';
884
+ export type HarnessAgentModel = 'inherit' | 'sonnet' | 'opus' | 'haiku';
885
+ export type HarnessAgentColor = 'blue' | 'cyan' | 'green' | 'yellow' | 'magenta' | 'red';
886
+ /**
887
+ * Frontmatter — name/description/model/color are required per official spec.
888
+ * `tools` is optional and uses a 3-state model:
889
+ * - key absent → all tools allowed (omit on disk)
890
+ * - empty array → no tools allowed (preserved as `tools: []`)
891
+ * - populated array → explicit allowlist
892
+ * The discriminated `toolsState` field on the read response surfaces the
893
+ * three states explicitly so the form can render the right radio option
894
+ * without ambiguity.
895
+ */
896
+ export interface HarnessAgentFrontmatter {
897
+ name: string;
898
+ description: string;
899
+ model: HarnessAgentModel;
900
+ color: HarnessAgentColor;
901
+ /** undefined = key absent (state A), [] = state B, ['Read', ...] = state C. */
902
+ tools?: string[];
903
+ }
904
+ export type HarnessAgentToolsState = 'omitted' | 'empty' | 'populated';
905
+ export interface HarnessAgentSourceLocation {
906
+ scope: HarnessAgentSourceScope;
907
+ /** Absolute path of the .md file. */
908
+ absoluteFile: string;
909
+ /** scope === 'plugin' → "<pluginName>@<marketplace>". */
910
+ pluginKey?: string;
911
+ /** scope === 'project' → the active project's slug. */
912
+ projectSlug?: string;
913
+ /** Agent name = file stem (with .md stripped) — must equal frontmatter.name. */
914
+ name: string;
915
+ }
916
+ export interface HarnessAgentCard extends HarnessAgentSourceLocation {
917
+ /** Required frontmatter fields. */
918
+ description: string;
919
+ model: HarnessAgentModel;
920
+ color: HarnessAgentColor;
921
+ /** Resolved 3-state tools indicator — drives the AC1.c list badge. */
922
+ toolsState: HarnessAgentToolsState;
923
+ /** Tool names when toolsState === 'populated'; empty otherwise. */
924
+ tools: string[];
925
+ /** True when the body contains at least one `<example>` block — drives AC4.c warning badge. */
926
+ hasExampleBlock: boolean;
927
+ /** ISO mtime of `absoluteFile` — STALE_WRITE ETag. */
928
+ mtime: string;
929
+ }
930
+ export interface HarnessAgentMalformedEntry {
931
+ scope: HarnessAgentSourceScope;
932
+ absoluteFile: string;
933
+ pluginKey?: string;
934
+ projectSlug?: string;
935
+ /**
936
+ * Reason category — UI maps to an i18n key:
937
+ * 'invalid-frontmatter' — YAML parse failure or missing required field
938
+ * 'name-mismatch' — frontmatter.name !== file stem
939
+ * 'invalid-name-pattern' — frontmatter.name fails the lowercase-hyphen regex
940
+ * 'invalid-model' — model not in enum
941
+ * 'invalid-color' — color not in enum
942
+ * 'nested-directory' — file located under a subdirectory (flat-only policy, AC1.a)
943
+ */
944
+ reason: 'invalid-frontmatter' | 'name-mismatch' | 'invalid-name-pattern' | 'invalid-model' | 'invalid-color' | 'nested-directory';
945
+ /** Free-form detail (e.g. the offending value) — appended to the i18n message in tooltips. */
946
+ detail?: string;
947
+ }
948
+ export interface HarnessAgentListResponse {
949
+ cards: HarnessAgentCard[];
950
+ malformed: HarnessAgentMalformedEntry[];
951
+ }
952
+ export interface HarnessAgentReadResponse {
953
+ source: HarnessAgentSourceLocation;
954
+ frontmatter: HarnessAgentFrontmatter;
955
+ /** Body markdown after the closing `---` (frontmatter stripped) — the system prompt. */
956
+ body: string;
957
+ /** Raw text of the entire file (frontmatter + body) — used by Raw editor toggle. */
958
+ raw: string;
959
+ mtime: string;
960
+ /** Discriminated tools state for the form radio. */
961
+ toolsState: HarnessAgentToolsState;
962
+ /** True when body contains at least one <example>...</example> block. */
963
+ hasExampleBlock: boolean;
964
+ }
965
+ /**
966
+ * Update request — exactly one of `frontmatter`/`body`/`raw` is required.
967
+ * `frontmatter` and `body` patch separately (frontmatter via yaml round-trip
968
+ * with explicit tools-state preservation, body as plain text replacement).
969
+ * `raw` replaces the whole file.
970
+ */
971
+ export interface HarnessAgentUpdateRequest {
972
+ frontmatter?: HarnessAgentFrontmatter;
973
+ /**
974
+ * When `frontmatter` is present and `tools` is undefined in the object,
975
+ * the server uses this discriminator to decide between state A (omit on disk)
976
+ * and state B (write `tools: []`). When `tools` is a non-empty array this
977
+ * field is ignored and state C is implied.
978
+ */
979
+ toolsState?: HarnessAgentToolsState;
980
+ body?: string;
981
+ raw?: string;
982
+ /** STALE_WRITE guard. */
983
+ expectedMtime?: string;
984
+ }
985
+ export interface HarnessAgentUpdateResponse {
986
+ success: true;
987
+ mtime: string;
988
+ toolsState: HarnessAgentToolsState;
989
+ hasExampleBlock: boolean;
990
+ }
991
+ export interface HarnessAgentCreateRequest {
992
+ scope: 'project' | 'user';
993
+ projectSlug?: string;
994
+ /** File stem — must match frontmatter.name and pass the agent name regex. */
995
+ name: string;
996
+ frontmatter: HarnessAgentFrontmatter;
997
+ body?: string;
998
+ /** State A vs B discriminator — same semantics as update. */
999
+ toolsState?: HarnessAgentToolsState;
1000
+ }
1001
+ export interface HarnessAgentCreateResponse {
1002
+ success: true;
1003
+ source: HarnessAgentSourceLocation;
1004
+ mtime: string;
1005
+ }
1006
+ export interface HarnessAgentCopyRequest {
1007
+ sourceScope: HarnessAgentSourceScope;
1008
+ sourceProjectSlug?: string;
1009
+ sourcePluginKey?: string;
1010
+ /** Source agent name = file stem. */
1011
+ sourceName: string;
1012
+ /** plugin destinations forbidden — only project/user allowed. */
1013
+ targetScope: 'project' | 'user';
1014
+ targetProjectSlug?: string;
1015
+ /** When undefined, server uses sourceName. Must pass agent name regex. */
1016
+ targetName?: string;
1017
+ onConflict: 'overwrite' | 'skip' | 'rename';
1018
+ /** Required when sensitive content is detected by the secret heuristic. */
1019
+ acknowledgedSecret?: boolean;
1020
+ }
1021
+ export interface HarnessAgentCopyResponse {
1022
+ success: true;
1023
+ target: HarnessAgentSourceLocation;
1024
+ skipped: boolean;
1025
+ /** Returned when ${CLAUDE_PLUGIN_ROOT} appeared in source. */
1026
+ warnings?: Array<'plugin-root-reference'>;
1027
+ }
1028
+ export interface HarnessAgentDeleteRequest {
1029
+ scope: 'project' | 'user';
1030
+ projectSlug?: string;
1031
+ name: string;
1032
+ expectedMtime?: string;
1033
+ }
1034
+ export interface HarnessAgentDeleteResponse {
1035
+ success: true;
1036
+ }
1037
+ /**
1038
+ * Snippet scope:
1039
+ * - project → `<projectRoot>/.hammoc/snippets/<name>.md`
1040
+ * - user → `~/.hammoc/snippets/<name>.md`
1041
+ * - bundled → server-bundled snippet directory (read-only)
1042
+ */
1043
+ export type SnippetScope = 'project' | 'user' | 'bundled';
1044
+ export interface SnippetCard {
1045
+ scope: SnippetScope;
1046
+ name: string;
1047
+ /** First non-empty line of the body, capped to 80 chars. */
1048
+ preview?: string;
1049
+ /** ISO 8601 mtime — empty string for bundled snippets that lack a stat (rare). */
1050
+ mtime: string;
1051
+ /** Bytes on disk. */
1052
+ size: number;
1053
+ }
1054
+ export interface SnippetListResponse {
1055
+ snippets: SnippetCard[];
1056
+ }
1057
+ export interface SnippetReadResponse {
1058
+ scope: SnippetScope;
1059
+ name: string;
1060
+ content: string;
1061
+ mtime: string;
1062
+ size: number;
1063
+ /** Resolved absolute path on disk. */
1064
+ absolutePath: string;
1065
+ }
1066
+ export interface SnippetWriteRequest {
1067
+ content: string;
1068
+ /** Omit to force overwrite (new file creation or explicit bypass). */
1069
+ expectedMtime?: string;
1070
+ }
1071
+ export interface SnippetWriteResponse {
1072
+ success: true;
1073
+ size: number;
1074
+ mtime: string;
1075
+ }
1076
+ export interface SnippetDeleteRequest {
1077
+ expectedMtime?: string;
1078
+ }
1079
+ export interface SnippetDeleteResponse {
1080
+ success: true;
1081
+ }
1082
+ /**
1083
+ * 4-direction copy matrix:
1084
+ * project ↔ user → bi-directional
1085
+ * bundled → project → one-way clone (bundled is read-only)
1086
+ * bundled → user → one-way clone
1087
+ *
1088
+ * `targetName` defaults to `sourceName`. When the target file already exists
1089
+ * the request fails with HARNESS_FILE_EXISTS unless `onConflict` is set:
1090
+ * - 'abort' → 409 (default — client renders SnippetCopyConflictDialog)
1091
+ * - 'overwrite' → replace target body
1092
+ * - 'rename' → caller MUST supply a fresh `targetName` distinct from any existing target file
1093
+ */
1094
+ export interface SnippetCopyRequest {
1095
+ sourceScope: SnippetScope;
1096
+ sourceName: string;
1097
+ /** Required when sourceScope === 'project'. */
1098
+ sourceProjectSlug?: string;
1099
+ targetScope: 'project' | 'user';
1100
+ targetName?: string;
1101
+ /** Required when targetScope === 'project'. */
1102
+ targetProjectSlug?: string;
1103
+ onConflict?: 'abort' | 'overwrite' | 'rename';
1104
+ }
1105
+ export interface SnippetCopyResponse {
1106
+ success: true;
1107
+ target: {
1108
+ scope: 'project' | 'user';
1109
+ name: string;
1110
+ absolutePath: string;
1111
+ };
1112
+ }
1113
+ /**
1114
+ * Share-scope of a single harness file as inferred from `.gitignore`.
1115
+ *
1116
+ * - `shared` — file is tracked by git (committed to the team repo)
1117
+ * - `local` — file path is matched by `.gitignore` (personal-only)
1118
+ * - `fullyIgnored` — the project's `.claude/` directory itself is ignored
1119
+ * (Mode B project — nothing in `.claude/` reaches git)
1120
+ */
1121
+ export type ShareScope = 'shared' | 'local' | 'fullyIgnored';
1122
+ /**
1123
+ * Project-mode classification derived from running `.gitignore` against the
1124
+ * virtual `.claude/settings.json` path. Mode A = team-shared harness; Mode B =
1125
+ * private (the entire `.claude/` is ignored).
1126
+ */
1127
+ export type ShareMode = 'A' | 'B' | 'unknown';
1128
+ export interface HarnessShareScopeRequest {
1129
+ /** Currently always `'project'` — `.gitignore` does not apply to user scope. */
1130
+ scope: 'project';
1131
+ projectSlug: string;
1132
+ /** Project-relative POSIX paths inside `.claude/` (or sibling files like `.mcp.json`). */
1133
+ paths: string[];
1134
+ }
1135
+ export interface HarnessShareScopeResponse {
1136
+ /** Mode classification (derived from `.claude/settings.json` virtual path). */
1137
+ mode: ShareMode;
1138
+ /** Per-path verdict — keys mirror the `paths` request, values are `ShareScope`. */
1139
+ cards: Record<string, ShareScope>;
1140
+ }
1141
+ /**
1142
+ * Discriminated rule identifiers — 7 rules total. Each is also the i18n key
1143
+ * fragment under `harness.tools.lint.rule.<id>.{title,description,message}`
1144
+ * and the preferences toggle under `harness.tools.lint.preferences.ruleLabel.<id>`.
1145
+ */
1146
+ export type LintRuleId = 'naming/duplicate-across-sources' | 'hook/matcher-regex-invalid' | 'parse/yaml-json-error' | 'mcp/command-not-on-path' | 'mcp/url-invalid' | 'agent/tools-non-standard' | 'hook/env-var-undefined';
1147
+ export declare const LINT_RULE_IDS: readonly LintRuleId[];
1148
+ /**
1149
+ * JSON-safe rule id used in i18n keys. The canonical `LintRuleId` contains
1150
+ * `/` which collides with i18next's default `.` key separator, so we map to
1151
+ * camelCase segments for the locale files. The mapping is one-to-one and
1152
+ * the inverse is rarely needed (the rule id always travels with the issue
1153
+ * payload).
1154
+ */
1155
+ export declare const LINT_RULE_I18N_KEY: Readonly<Record<LintRuleId, string>>;
1156
+ export type LintSeverity = 'warn' | 'error';
1157
+ /**
1158
+ * Default ON/OFF state per rule. `mcp/command-not-on-path` is opt-in (default
1159
+ * OFF) per Story 30.2 AC4.b — the spike #2 (2026-05-11) measured ~67% server-
1160
+ * vs-CLI PATH match rate, below the 80% threshold for ON-by-default. The
1161
+ * other six rules default to ON.
1162
+ */
1163
+ export declare const LINT_RULE_DEFAULTS: Readonly<Record<LintRuleId, boolean>>;
1164
+ /** The 5 lint domains — matches the 5 sub-section nav slots that surface a count badge. */
1165
+ export type LintCardDomain = 'skill' | 'mcp' | 'hook' | 'command' | 'agent';
1166
+ export declare const LINT_CARD_DOMAINS: readonly LintCardDomain[];
1167
+ /**
1168
+ * Issue location — discriminated by source kind. `'line'` is used by parser
1169
+ * errors that already have a file/line position from the parser wrapper;
1170
+ * `'path'` is a dot/bracket path the panel resolves to a DOM ref via
1171
+ * `useCardFieldFocus()` (e.g. `['mcpServers', 'context7', 'command']`,
1172
+ * `['tools', '2']`, `['matcher']`).
1173
+ */
1174
+ export type LintIssueLocation = {
1175
+ kind: 'line';
1176
+ line: number;
1177
+ } | {
1178
+ kind: 'path';
1179
+ path: string[];
1180
+ };
1181
+ /**
1182
+ * One lint finding. Severity collapses into the `(error, warn)` count badge
1183
+ * for the section nav and the inline marker on the card header. The
1184
+ * `messageI18nKey` is fully resolved (already includes the `harness.tools.lint`
1185
+ * prefix) so the client just calls `t(key, vars)`.
1186
+ */
1187
+ export interface LintIssue {
1188
+ ruleId: LintRuleId;
1189
+ severity: LintSeverity;
1190
+ cardScope: 'project' | 'user' | 'plugin';
1191
+ /** Card name — `HarnessSkillCard.name`, `HarnessMcpCard.name`, etc. May be empty for parser errors that never produced a card. */
1192
+ cardName: string;
1193
+ cardDomain: LintCardDomain;
1194
+ /**
1195
+ * For hook issues only — the event group the matcher/config lives under.
1196
+ * Lets the marker uniquely identify a card when the same hook command appears
1197
+ * across multiple events.
1198
+ */
1199
+ hookEvent?: HarnessHookEvent;
1200
+ location: LintIssueLocation;
1201
+ messageI18nKey: string;
1202
+ messageI18nVars?: Record<string, string | number>;
1203
+ }
1204
+ export interface HarnessLintResponse {
1205
+ issues: LintIssue[];
1206
+ /** Rule preferences after server-side defaults are applied to the user's stored toggles. */
1207
+ rulePreferences: Record<LintRuleId, boolean>;
1208
+ /** ISO timestamp the evaluation completed — clients can show staleness if needed. */
1209
+ evaluatedAt: string;
1210
+ }
1211
+ //# sourceMappingURL=harness.d.ts.map