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,111 @@
1
+ /**
2
+ * Story 28.0.5: YAML / JSONC round-trip editor.
3
+ *
4
+ * The goal is to mutate a single key inside a structured config file while
5
+ * preserving the author's comments, blank lines, key order, and quoting style.
6
+ *
7
+ * - YAML → `yaml` (eemeli) `parseDocument` + `doc.setIn/deleteIn` + `doc.toString()`.
8
+ * The Document AST keeps comment & blank-line metadata attached to
9
+ * each node, and `toString()` re-emits them.
10
+ * NOTE: `js-yaml@4` remains a coexisting dependency for session-meta parsing
11
+ * elsewhere in the codebase, but has no comment-preservation path and must
12
+ * not be used for harness edits.
13
+ *
14
+ * - JSONC → `jsonc-parser` `modify` + `applyEdits`. This is the same path VS
15
+ * Code uses when it edits user `settings.json` — comments and
16
+ * formatting are preserved.
17
+ *
18
+ * Both entry points throw `HARNESS_PARSE_ERROR` on unparseable input so the
19
+ * harness controller can surface the envelope and the client can fall back to
20
+ * raw editing.
21
+ */
22
+ import { parseDocument } from 'yaml';
23
+ import { modify, applyEdits, parse, parseTree, findNodeAtLocation, printParseErrorCode, } from 'jsonc-parser';
24
+ import { HARNESS_ERRORS } from '@hammoc/shared';
25
+ function parseError(format, cause) {
26
+ const err = new Error(`failed to parse ${format}: ${cause?.message ?? String(cause)}`);
27
+ err.code = HARNESS_ERRORS.HARNESS_PARSE_ERROR.code;
28
+ return err;
29
+ }
30
+ /**
31
+ * Apply structured patches to a YAML source string while preserving comments,
32
+ * blank lines, and key order.
33
+ */
34
+ export function applyYamlPatch(source, ops) {
35
+ let doc;
36
+ try {
37
+ doc = parseDocument(source, { keepSourceTokens: true });
38
+ if (doc.errors.length > 0) {
39
+ throw doc.errors[0];
40
+ }
41
+ }
42
+ catch (cause) {
43
+ throw parseError('yaml', cause);
44
+ }
45
+ // A freshly-created empty document has `contents: null`; we need a map so
46
+ // setIn can plant new keys at the top level.
47
+ if (doc.contents == null) {
48
+ doc.contents = doc.createNode({});
49
+ }
50
+ for (const op of ops) {
51
+ if (!op.path || op.path.length === 0) {
52
+ throw parseError('yaml', new Error('patch op requires a non-empty path'));
53
+ }
54
+ if (op.value === undefined) {
55
+ // Idempotent delete: if any segment (including intermediates) is already
56
+ // absent, the target is effectively deleted — skip. `doc.deleteIn`
57
+ // itself only no-ops on a missing leaf; a missing intermediate throws.
58
+ if (!doc.hasIn(op.path))
59
+ continue;
60
+ doc.deleteIn(op.path);
61
+ }
62
+ else {
63
+ doc.setIn(op.path, op.value);
64
+ }
65
+ }
66
+ // toString() preserves original comments/blank lines/quote style for any
67
+ // node that was not explicitly replaced.
68
+ return doc.toString();
69
+ }
70
+ /**
71
+ * Apply structured patches to a JSONC source string while preserving comments
72
+ * and formatting. Inserts missing intermediate objects as needed (matches
73
+ * `jsonc-parser` `modify` default behavior).
74
+ */
75
+ export function applyJsoncPatch(source, ops) {
76
+ // Validate the source up front — `modify` silently starts from `{}` on
77
+ // garbage input, which would quietly erase the user's file. Feed the
78
+ // official errors array to catch unterminated strings, missing values, etc.
79
+ if (source.trim().length > 0) {
80
+ const errors = [];
81
+ parse(source, errors, { allowTrailingComma: true, disallowComments: false });
82
+ if (errors.length > 0) {
83
+ const first = errors[0];
84
+ throw parseError('jsonc', new Error(`${printParseErrorCode(first.error)} at offset ${first.offset}`));
85
+ }
86
+ }
87
+ const formattingOptions = {
88
+ insertSpaces: true,
89
+ tabSize: 2,
90
+ eol: source.includes('\r\n') ? '\r\n' : '\n',
91
+ };
92
+ let current = source;
93
+ for (const op of ops) {
94
+ if (!op.path || op.path.length === 0) {
95
+ throw parseError('jsonc', new Error('patch op requires a non-empty path'));
96
+ }
97
+ // Idempotent delete: `modify(undefined)` throws "Can not delete…" when the
98
+ // target (or any intermediate) does not exist; treat that as a no-op so
99
+ // callers can apply delete patches without first probing state.
100
+ if (op.value === undefined) {
101
+ const tree = parseTree(current, [], { allowTrailingComma: true, disallowComments: false });
102
+ if (!tree || !findNodeAtLocation(tree, op.path))
103
+ continue;
104
+ }
105
+ // `modify` takes `undefined` to mean "remove", matching HarnessStructuredPatchOp.value semantics.
106
+ const edits = modify(current, op.path, op.value, { formattingOptions });
107
+ current = applyEdits(current, edits);
108
+ }
109
+ return current;
110
+ }
111
+ //# sourceMappingURL=structuredEditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structuredEditor.js","sourceRoot":"","sources":["../../src/utils/structuredEditor.ts"],"names":[],"mappings":"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"}
@@ -15,22 +15,26 @@
15
15
  "test:all": "vitest run"
16
16
  },
17
17
  "dependencies": {
18
- "@anthropic-ai/claude-agent-sdk": "^0.2.34",
18
+ "@anthropic-ai/claude-agent-sdk": "^0.2.114",
19
19
  "@hammoc/shared": "*",
20
20
  "bcrypt": "^6.0.0",
21
+ "chokidar": "^5.0.0",
21
22
  "cookie-session": "^2.1.1",
22
23
  "cors": "^2.8.5",
23
24
  "express": "^4.21.0",
24
- "express-rate-limit": "^8.3.1",
25
25
  "helmet": "^8.1.0",
26
26
  "i18next": "^24.2.3",
27
+ "ignore": "^5.3.2",
27
28
  "js-yaml": "^4.1.1",
29
+ "jsonc-parser": "^3.3.1",
30
+ "jszip": "^3.10.1",
28
31
  "multer": "^2.1.1",
29
32
  "node-pty": "^1.0.0",
30
33
  "sharp": "^0.34.5",
31
34
  "simple-git": "^3.27.0",
32
35
  "socket.io": "^4.8.0",
33
36
  "web-push": "^3.6.7",
37
+ "yaml": "^2.8.3",
34
38
  "zod": "^4.3.6"
35
39
  },
36
40
  "devDependencies": {
@@ -0,0 +1,23 @@
1
+ # Hammoc Internals (Agent-Only Reference)
2
+
3
+ This folder documents Hammoc's internal mechanisms that an in-IDE agent may need to read or correlate, but that are deliberately omitted from the user-facing manual. The user does not need to know any of this; the agent does.
4
+
5
+ ## How to use
6
+
7
+ Read individual entries **on demand** when the user's request involves the underlying mechanism (for example: correlating an attached image with a file on disk, understanding how a session ID maps to a JSONL file). Do not pre-load this folder.
8
+
9
+ ## Entries
10
+
11
+ - [Image Storage](./image-storage.md) — On-disk path and filename scheme for chat-attached images
12
+ - [Harness File Layout](./harness-files.md) — Where `.claude/` items (skills, commands, agents, hooks, MCP servers, `CLAUDE.md`) live on disk, when changes take effect, and how the Secret-on-Shared guard relates to direct file writes
13
+
14
+ ## Maintenance
15
+
16
+ Add a new file here whenever there is internal behavior the agent needs to act on but the user does not need to see. Likely future entries:
17
+
18
+ - Session ID and project-path slug encoding under `~/.claude/projects/`
19
+ - JSONL message tree structure (parent/child UUIDs, branching)
20
+ - Permission-mode internal effects on the SDK call
21
+ - Snippet resolution order and substitution rules
22
+
23
+ Each new file should describe the on-disk reality (paths, formats, lifecycle), not the user-facing UI behavior — that belongs in the user manual.
@@ -0,0 +1,63 @@
1
+ # Harness File Layout
2
+
3
+ The Harness Workbench (user-facing, see manual §12) edits Claude Code's `.claude/` configuration trees in place. An agent can reach the same files directly with Read / Write / Edit and skip the UI when that's faster.
4
+
5
+ ## On-disk roots
6
+
7
+ Two trees, walked in this priority order:
8
+
9
+ ```
10
+ <projectRoot>/.claude/ # project scope (highest)
11
+ <homeDir>/.claude/ # global scope (user scope)
12
+ ```
13
+
14
+ When the same name (skill, command, agent, hook, MCP server, snippet) exists in both, the project copy is **active** and the global copy is **shadowed** but kept on disk.
15
+
16
+ `<homeDir>` must be resolved before use — Read / Write / Edit do not expand `~`. On Windows that is `C:\Users\<user>\`.
17
+
18
+ ## Per-item layout
19
+
20
+ | Item | Path (under either `.claude/` root) | Format |
21
+ |------|--------------------------------------|--------|
22
+ | Skill | `skills/<name>/SKILL.md` + bundle assets in the same directory | Markdown body + YAML frontmatter (`name`, `description`, `version`) |
23
+ | Slash command | `commands/<name>.md` | Markdown body + YAML frontmatter |
24
+ | Sub-agent | `agents/<name>.md` | Markdown body + YAML frontmatter (`name`, `description`, `tools`) |
25
+ | Hook | `settings.json` → `hooks.<EventName>[]` entries | JSON; one event name per array key (`PreToolUse`, `PostToolUse`, `Stop`, `SubagentStop`, `SessionStart`, `SessionEnd`, `UserPromptSubmit`, `PreCompact`, `Notification`) |
26
+ | MCP server | `.mcp.json` at the project root, or `<homeDir>/.claude/.mcp.json` | JSON; entries under `mcpServers.<name>` |
27
+ | `CLAUDE.md` | `<projectRoot>/.claude/CLAUDE.md`, `<homeDir>/.claude/CLAUDE.md` | Plain Markdown; both files load into every session, project wins on conflict |
28
+ | Plugin | `plugins/<vendor>__<name>/` | Plugin bundle directory; treated read-only by Hammoc — copy items out to project/global to customize |
29
+
30
+ Hammoc-native `%snippets` are a separate layer (see manual §4.6); they live under `<projectRoot>/.hammoc/snippets/` and `<homeDir>/.hammoc/snippets/`, **not** the `.claude/` tree.
31
+
32
+ ## Sharing scope
33
+
34
+ Each file's "share" status is computed from the project's `.gitignore`:
35
+
36
+ - **Shared** — File path is tracked by git
37
+ - **Local** — File path is untracked but `.claude/` is not ignored
38
+ - **Ignored** — A `.gitignore` rule excludes `.claude/` (or an ancestor)
39
+
40
+ The workbench shows a badge for each file. When an agent writes a file under `.claude/`, the resulting share scope is whatever the `.gitignore` already says — Hammoc does not rewrite `.gitignore` on the agent's behalf.
41
+
42
+ ## Secret-on-Shared guard
43
+
44
+ When the user saves a `Shared`-scope file through the UI, Hammoc scans for plaintext secrets (entropy + pattern heuristic) and blocks the save with a dialog. **An agent writing the file directly via Write / Edit bypasses that dialog.** If the agent is editing a `Shared` file under `.claude/`, it must avoid committing plaintext API keys, bearer tokens, etc. Use a sibling `*.local.<ext>` file (gitignored) and reference it from the shared file, or use `${ENV_VAR}` references that the hook / MCP runtime expands.
45
+
46
+ ## When changes take effect
47
+
48
+ - **Skills, commands, agents, CLAUDE.md, snippets** — Picked up on the next message in a chat turn (the system prompt and tool list re-resolve on each turn).
49
+ - **Hooks** — Same: next message in a chat turn.
50
+ - **MCP servers** — Picked up only on a **fresh session spawn**, not mid-session. The workbench UI shows a "Takes effect on your next user message" banner with a "Start new session" button after the user edits an MCP entry; an agent making MCP edits should remind the user to start a new session, or do so on their behalf.
51
+ - **Plugin enable/disable** — Same as MCP: fresh spawn required.
52
+
53
+ ## Static lint (informational)
54
+
55
+ The workbench runs seven static-lint rules over the trees (see manual §12.12). Agents writing harness files should keep these rules in mind even though writes are not blocked:
56
+
57
+ - duplicate names across scopes
58
+ - invalid hook matcher regex
59
+ - frontmatter / JSON parse errors
60
+ - MCP `stdio` command not on `PATH`
61
+ - malformed MCP URLs
62
+ - non-standard agent tool names
63
+ - hook bodies referencing undefined env vars
@@ -0,0 +1,43 @@
1
+ # Image Storage
2
+
3
+ When the user attaches an image to a chat message, Hammoc saves it under **Claude Code's per-project session data**, not inside the project being worked on. The user does not see this — they just attach and send. This document is for an agent that needs to read or correlate the file directly.
4
+
5
+ ## On-disk location
6
+
7
+ ```
8
+ <homeDir>/.claude/projects/<encoded-project-path>/images/<sessionId>/<filename>
9
+ ```
10
+
11
+ - `<homeDir>` — User home directory (Read/Edit tools do not expand `~`, so resolve to the absolute path first).
12
+ - `<encoded-project-path>` — Claude Code's project slug. Path separators (`/`, `\`) and colons (`:`) in the original project path are replaced with hyphens. Example: `D:\repo\hammoc` → `D--repo-hammoc`.
13
+ - `<sessionId>` — UUID of the chat session containing the message.
14
+ - `<filename>` — `<sha256-prefix-16chars>.<ext>` for the original. Thumbnails use `<sha256-prefix-16chars>_thumb.<ext>`.
15
+ - `<ext>` — One of `.png`, `.jpg`, `.gif`, `.webp`.
16
+
17
+ ## Supported MIME types
18
+
19
+ | MIME | Extension |
20
+ |---|---|
21
+ | image/png | .png |
22
+ | image/jpeg | .jpg |
23
+ | image/gif | .gif |
24
+ | image/webp | .webp |
25
+
26
+ Anything else is rejected at attach time.
27
+
28
+ ## How an agent reaches these files
29
+
30
+ - The chat message references each image via the API URL `/api/projects/<projectSlug>/sessions/<sessionId>/images/<filename>`. That URL is for the **browser** to render thumbnails — it is not a file-system path and Read tools cannot use it directly.
31
+ - To open the file from disk, build the absolute path under `<homeDir>/.claude/projects/...` using the rules above, then call Read with that path.
32
+
33
+ ## Lifecycle
34
+
35
+ - Images are written the moment the user sends a message with attachments.
36
+ - A session's `images/<sessionId>/` directory is removed when the session itself is deleted.
37
+ - Filenames are content-addressed (sha256 prefix), so attaching the same image bytes twice within a session reuses the same filename — automatic deduplication.
38
+
39
+ ## Limits
40
+
41
+ - 5 images per message
42
+ - 10 MB per image
43
+ - Total per-session storage is bounded only by disk; there is no automatic eviction other than session deletion.
@@ -0,0 +1,104 @@
1
+ ## 1. Getting Started
2
+
3
+ ### 1.1 Installation
4
+
5
+ **Option A: Run with npx (no install)**
6
+
7
+ ```bash
8
+ npx hammoc
9
+ ```
10
+
11
+ **Option B: Global install**
12
+
13
+ ```bash
14
+ npm install -g hammoc
15
+ hammoc
16
+ ```
17
+
18
+ **Option C: From source (development)**
19
+
20
+ ```bash
21
+ git clone https://github.com/starsh2001/hammoc.git
22
+ cd hammoc
23
+ npm install
24
+ npm run dev
25
+ ```
26
+
27
+ ### 1.2 System Requirements
28
+
29
+ - **Node.js** >= 18.0.0 (v22 LTS recommended)
30
+ - **Claude Code CLI** installed and authenticated
31
+ - Modern browser (Chrome, Firefox, Safari, Edge)
32
+
33
+ ### 1.3 First Launch
34
+
35
+ 1. Open http://localhost:3000 in your browser
36
+ 2. **Password Setup**: Set an admin password on first visit. This protects your instance from unauthorized access.
37
+ 3. **Login**: Enter your password to sign in. **"Stay signed in"** keeps you logged in for 30 days (checked by default). After too many failed attempts, login is temporarily locked with a countdown timer.
38
+ 4. **CLI Verification**: The onboarding wizard checks that Claude Code CLI is installed and authenticated. Follow the prompts if any step fails.
39
+ 5. **Project Selection**: Choose an existing Claude Code project or create a new one.
40
+
41
+ ### 1.4 Mobile Access
42
+
43
+ Hammoc is fully responsive. From any device on the same network:
44
+
45
+ ```
46
+ http://<your-computer-ip>:3000
47
+ ```
48
+
49
+ - Desktop: Enter sends message, Shift+Enter for new line
50
+ - Mobile (touch devices): Enter adds new line, tap the send button to send
51
+ - **Pull-to-refresh**: Swipe down on the session list to refresh
52
+
53
+ ### 1.5 CLI Options
54
+
55
+ ```bash
56
+ hammoc --port 8080 # Custom port
57
+ hammoc --host localhost # Bind to localhost only
58
+ hammoc --trust-proxy # Enable reverse proxy support
59
+ hammoc --cors-origin <url> # Restrict CORS to specific origin
60
+ hammoc --reset-password # Reset admin password
61
+ hammoc --version # Show version
62
+ hammoc --help # Show help
63
+ ```
64
+
65
+ All options are also available as environment variables (see [Environment Variables](#14-environment-variables)).
66
+
67
+ ### 1.6 Remote Access (Reverse Proxy)
68
+
69
+ If you need to expose Hammoc through a reverse proxy (Cloudflare Tunnel, nginx, etc.), use `--trust-proxy` and `--cors-origin`:
70
+
71
+ ```bash
72
+ npx hammoc --trust-proxy --cors-origin https://hammoc.yourdomain.com
73
+ ```
74
+
75
+ **What `--trust-proxy` enables:**
76
+ - Reads real client IP from proxy headers for access control (e.g. localhost-only endpoints)
77
+ - Sets session cookies with `Secure` flag (HTTPS-only)
78
+
79
+ **What `--cors-origin` does:**
80
+ - Restricts cross-origin requests to the specified URL only
81
+ - Without it, any website can make authenticated requests to your Hammoc instance
82
+
83
+ **Security features (always active, no configuration needed):**
84
+ - Security headers (CSP, X-Frame-Options, HSTS, etc.)
85
+ - Server management APIs (restart, update) restricted to localhost only
86
+ - Terminal access restricted to local network IPs
87
+ - Login brute-force protection (5 failed attempts → 30s lockout per IP)
88
+
89
+ > **Note:** Hammoc does not apply request-level rate limiting itself — traffic shaping is an infrastructure concern. Configure it at your reverse proxy / WAF / API gateway (nginx `limit_req`, Cloudflare WAF rules, etc.).
90
+
91
+ ### 1.7 HTTPS / TLS
92
+
93
+ Hammoc automatically enables HTTPS when TLS certificates are found:
94
+
95
+ 1. Place your certificate files in the `~/.hammoc/` directory:
96
+ - `~/.hammoc/key.pem` — Private key
97
+ - `~/.hammoc/cert.pem` — Certificate (or full chain)
98
+ 2. Restart Hammoc — it will detect the files and start an HTTPS server
99
+ 3. The startup log will show `TLS: enabled (certs from ~/.hammoc/)`
100
+
101
+ If no certificates are found, the server runs over HTTP as usual.
102
+
103
+ > **Tip:** For local development, you can generate self-signed certificates with `mkcert` or `openssl`. For production, use certificates from Let's Encrypt or your domain provider.
104
+
@@ -0,0 +1,285 @@
1
+ ## 2. Chat
2
+
3
+ The chat interface is the core of Hammoc. It provides a rich, real-time conversation experience with Claude.
4
+
5
+ ### 2.1 Sending Messages
6
+
7
+ - Type your message in the input area at the bottom
8
+ - **Desktop**: Press `Enter` to send, `Shift+Enter` for a new line
9
+ - **Mobile**: Press `Enter` for a new line, tap the send button to send
10
+ - The input area auto-expands as you type
11
+
12
+ ### 2.2 Streaming Responses
13
+
14
+ Claude's responses stream in real-time, character by character. You'll see:
15
+
16
+ - **Text content** — Rendered as markdown as it arrives
17
+ - **Tool calls** — Shown as expandable cards with tool name, inputs, and results
18
+ - **Thinking blocks** — Claude's extended reasoning displayed in collapsible sections
19
+ - **Timestamps** — Each message shows a relative timestamp (e.g., "2 hours ago")
20
+ - **Copy button** — Click the copy icon on any message to copy its content to the clipboard
21
+ - **Scroll to bottom** — When scrolled up, a down-arrow button appears to jump back to the latest message
22
+
23
+ ### 2.3 Markdown & Code Blocks
24
+
25
+ Messages support full GitHub-flavored markdown:
26
+
27
+ - Headers, bold, italic, strikethrough
28
+ - Ordered and unordered lists
29
+ - Tables
30
+ - Blockquotes
31
+ - Links (open in new tab)
32
+ - Inline code and fenced code blocks
33
+
34
+ **HTML support:**
35
+ - Inline HTML tags are rendered alongside markdown (e.g., `<div>`, `<span>`, `<table>`)
36
+ - Dangerous elements (`<script>`, `<iframe>`, `<style>`, event handlers) are automatically stripped for XSS protection
37
+
38
+ **Relative path resolution:**
39
+ - File links and image references in markdown resolve relative to the source file's directory
40
+ - Parent traversal (`../`) is supported (e.g., `../../config.json` navigates up two levels)
41
+ - Clicking resolved file links opens them in the text editor; images open in the image viewer
42
+
43
+ **Code blocks** have:
44
+ - Language-specific syntax highlighting
45
+ - Copy button (top-right corner)
46
+ - File reference links that open directly in the editor
47
+
48
+ ### 2.4 Image Attachments
49
+
50
+ Attach images to your messages for Claude to analyze:
51
+
52
+ - Click the attachment button (paperclip icon) in the input area
53
+ - Drag and drop images directly onto the input area
54
+ - Paste from clipboard (`Ctrl+V` / `Cmd+V`)
55
+ - Supported formats: PNG, JPEG, GIF, WebP
56
+ - Maximum: 5 images per message, 10MB per image
57
+ - Images preview in the input area before sending
58
+ - Sent images display as clickable thumbnails above the message text. Clicking a thumbnail opens the full image viewer with multi-image navigation (see §6.4)
59
+
60
+ ### 2.5 Tool Call Visualization
61
+
62
+ When Claude uses tools (reading files, editing code, running commands), each tool call is shown as a card:
63
+
64
+ - **Tool name** — e.g., Read, Edit, Bash, Grep
65
+ - **Input parameters** — What was passed to the tool
66
+ - **Status indicator** — Running (spinner), completed (checkmark), failed (X), denied (shield icon)
67
+ - **Execution time** — How long the tool took
68
+ - **Result** — Expandable section showing tool output
69
+ - **File paths** — Toggle between short and full path display
70
+
71
+ ### 2.6 Task Notifications
72
+
73
+ When Claude runs background tasks (e.g., Agent sub-tasks), a notification card appears in the message stream upon completion:
74
+
75
+ - **Status indicators** — Completed (green checkmark), Failed (red alert), Stopped (bell icon)
76
+ - **Summary text** — Brief description of the task outcome
77
+ - **Clickable** — When linked to a tool call, clicking the card scrolls to the associated Agent tool card and highlights it briefly
78
+
79
+ ### 2.7 Diff Viewer
80
+
81
+ When Claude modifies files, a diff viewer shows the changes:
82
+
83
+ - **Side-by-side mode** — Before and after comparison (wide screens)
84
+ - **Inline mode** — Unified diff view (narrow screens or mobile)
85
+ - **Syntax highlighting** — Language-aware coloring
86
+ - **Diff navigation** — `F7` next change, `Shift+F7` previous change
87
+ - **Large file handling** — Very large files are handled with optimized rendering
88
+ - **Responsive layout** — Automatically switches between side-by-side and inline modes based on screen width (768px breakpoint)
89
+ - **Manual layout toggle** — A toggle button in the viewer header (Columns2 / Rows2 icon) lets you force side-by-side or inline. The choice is persisted per user and overrides the responsive default until reset
90
+
91
+ ### 2.8 Permission Requests
92
+
93
+ Depending on your permission mode, Claude may ask for approval before modifying files:
94
+
95
+ - **Approve** — Allow the change
96
+ - **Reject** — Block the change
97
+ - View the diff before deciding
98
+ - See the list of requested permissions
99
+
100
+ ### 2.9 Prompt Chaining
101
+
102
+ Queue multiple prompts for sequential execution. Chain state is managed server-side, enabling multi-browser sync and background execution.
103
+
104
+ 1. Toggle **chain mode** ON via the chain button (link icon next to send) or hold `Ctrl`
105
+ 2. Type your first prompt and send it — the send button label changes to **"Add to chain"**
106
+ 3. While Claude is responding, type the next prompt and send — it enters the chain
107
+ 4. Up to **10** prompts can be queued
108
+ 5. A **violet banner** shows the chain status:
109
+ - **Collapsed mode** — First prompt preview + "+N" count indicator
110
+ - **Expanded mode** — Full list with individual **Remove** buttons (click to expand when 2+ items)
111
+ - **Drag-and-drop reorder** — In the expanded list, grab the grip handle (GripVertical icon) on the left of any pending item to drag it up or down. Items that are actively sending show a spinner instead of a grip and cannot be moved
112
+ - **Cancel all** — Clear the entire chain
113
+ 6. Each prompt auto-executes when the previous one completes
114
+
115
+ **Server-side features:**
116
+ - **Multi-browser sync** — Chain state is synchronized across all browser tabs/windows
117
+ - **Background execution** — Chain continues running even if all browsers are closed
118
+ - **Auto-retry** — Failed items are automatically retried before being marked as failed
119
+
120
+ ### 2.10 Context Usage
121
+
122
+ Monitor token usage in real-time:
123
+
124
+ - **Usage donut** — Visual indicator showing used/limit tokens and percentage
125
+ - **Cost display** — Estimated cost for the session
126
+ - **Cache tokens** — Cache creation and read token counts
127
+ - **Rate limit dots** — 5h/7d utilization indicators in the input area
128
+ - **Color thresholds** — Green (normal), Yellow (moderate), Red (high usage)
129
+ - **Context compaction** — Click the usage donut to trigger compaction, which summarizes the conversation to free up context space. At critical usage levels, clicking instead creates a new session
130
+ - **Auto-compact on overflow** — When message history hits the context window limit, Hammoc automatically compacts the context and retries the message instead of losing the session
131
+
132
+ ### 2.11 Aborting Responses
133
+
134
+ Stop Claude mid-response:
135
+
136
+ - Click the **Stop** button (appears during streaming)
137
+ - Press `ESC` key
138
+ - Press `Ctrl+C` (when no text is selected in the input)
139
+
140
+ ### 2.12 Prompt History
141
+
142
+ Navigate through your previous inputs:
143
+
144
+ - Press `↑` (Up arrow) to recall the previous prompt
145
+ - Press `↓` (Down arrow) to go forward
146
+ - History is per-session
147
+
148
+ ### 2.13 Voice Input (Speech Recognition)
149
+
150
+ Dictate messages using your browser's built-in speech recognition:
151
+
152
+ - **Microphone button** — Located inside the chat input area (right side). Only shown when the browser supports the Web Speech API (Chrome, Edge, Safari)
153
+ - **Toggle** — Click the mic button to start/stop listening
154
+ - **Visual indicator** — Green indicator while actively listening
155
+ - **Language-aware** — Automatically matches the app's language setting (English, Korean, Chinese, Japanese, Spanish, Portuguese)
156
+ - Recognized text is added to the current input without replacing existing text
157
+ - **Auto-stop** — Voice recognition stops automatically when sending a message or when the session becomes locked
158
+ - **Error handling** — Toast notification shown if microphone access is denied or recognition fails
159
+
160
+ ### 2.14 Extended Thinking
161
+
162
+ When Claude uses extended thinking, the reasoning is shown in a collapsible block:
163
+
164
+ - Click to expand/collapse
165
+ - Thinking content is visually distinct from the main response
166
+ - Useful for understanding Claude's decision-making process
167
+
168
+ ### 2.15 Model Selector
169
+
170
+ The model selector button is located in the chat input toolbar. It displays the current model family name (e.g., "Opus", "Sonnet", "Haiku") directly on the button. When using the default model, it shows "Default". Click to open a dropdown for choosing a different model and adjusting thinking effort.
171
+
172
+ ### 2.16 Thinking Effort
173
+
174
+ Control how much Claude "thinks" before responding. The intensity bar appears inside the model selector dropdown. The number of bars depends on the selected model:
175
+
176
+ - **Low / Medium / High** — 3 levels, available for all models
177
+ - **Max** — 4th level, added for Opus 4.6 / Sonnet 4.6
178
+ - **XHigh** — 5th level, added only for **Opus 4.7** (the default effort for this model is XHigh)
179
+
180
+ Behavior:
181
+
182
+ - Click the currently active level again to reset to default
183
+ - Cannot be changed while Claude is responding
184
+ - If you switch to a model that doesn't support the current level (e.g., XHigh → non-Opus-4.7, or Max → model without Max), the effort automatically resets to the highest supported level
185
+ - When the active model is temporarily unknown (e.g., right after switching projects before the resolved model arrives), the dropdown keeps your saved choice instead of resetting it. As soon as the model is known, the effort is reclamped if necessary
186
+
187
+ The default thinking effort for new sessions can be configured in Settings > Global.
188
+
189
+ ### 2.17 Message Actions
190
+
191
+ Each message has an action bar that appears at its bottom-right corner. Available actions depend on the message type:
192
+
193
+ **On all messages:**
194
+ - **Copy** — Copy the message text to clipboard
195
+
196
+ **On user messages:**
197
+ - **Edit** — Open an inline editor to modify the message (see §2.18)
198
+ - **Summarize & Continue** — Generate an AI summary of the conversation up to that point (see §2.19)
199
+ - **Rewind Code** — Restore the codebase to the state it was in when this message was sent (see §2.20)
200
+
201
+ **On assistant messages:**
202
+ - **Fork** — Create a new session branching from this response (see §2.21)
203
+
204
+ All action buttons are disabled during streaming, and while another action (edit, rewind, summarize) is in progress. Actions are also disabled when viewing an old branch or in branch viewer mode (see §2.23).
205
+
206
+ ### 2.18 Message Edit
207
+
208
+ Edit a previously sent user message to explore a different conversation path:
209
+
210
+ 1. Click the **Edit** button (pencil icon) on a user message
211
+ 2. The message transforms into an editable textarea with the original text
212
+ 3. Modify the text, then:
213
+ - **Accept** (checkmark button or `Ctrl+Enter`) — Send the edited message. Claude responds to the new version, creating a new conversation branch
214
+ - **Cancel** (X button or `Escape`) — Discard changes
215
+ 4. Empty messages cannot be submitted
216
+
217
+ After editing, you can navigate between the original and edited branches using branch pagination (see §2.22).
218
+
219
+ ### 2.19 Summarize & Continue
220
+
221
+ Compress a long conversation into a summary to free up context space while continuing the session:
222
+
223
+ 1. Click the **Summarize & Continue** button (sparkles icon) on a user message
224
+ 2. AI generates a summary of the conversation up to that point (spinner shown during generation)
225
+ 3. To cancel mid-generation, click the button again (shows X on hover)
226
+ 4. When complete, the inline edit form opens with the generated summary pre-filled
227
+ 5. Review, edit if needed, then **Accept** to continue with the summary or **Cancel** to discard
228
+
229
+ ### 2.20 Code Rewind
230
+
231
+ Revert project files to a previous state in the conversation:
232
+
233
+ 1. Click the **Rewind Code** button (undo icon) on a user message
234
+ 2. A dry-run preview shows how many files will change (insertions/deletions count)
235
+ 3. Review the file list and click **Rewind** to confirm, or **Cancel** to abort
236
+ 4. On success, a toast confirms the number of files restored
237
+
238
+ If no checkpoint is available for that message, or the code is already at that state, an error message is shown.
239
+
240
+ ### 2.21 Session Fork
241
+
242
+ Branch into a completely new session from any assistant response:
243
+
244
+ 1. Click the **Fork** button (git-fork icon) on an assistant message
245
+ 2. A dialog appears with an optional message field (defaults to "Continue from here")
246
+ 3. Click **Fork** to create the new session
247
+ 4. The new session starts with the full conversation history up to that point, plus your fork message
248
+ 5. You are automatically navigated to the new session
249
+
250
+ The original session remains unchanged.
251
+
252
+ ### 2.22 Conversation Branching
253
+
254
+ When you edit a message, the conversation splits into branches. Branch pagination controls appear at the bottom-left of user messages that have multiple branches:
255
+
256
+ - **← / →** arrows to navigate between branches
257
+ - **"X / Y"** indicator showing current branch number and total count
258
+ - Keyboard: **Left/Right arrow keys** to navigate (when the pagination is focused)
259
+ - Navigation is disabled during streaming
260
+
261
+ Switching branches replaces all messages from that point forward with the selected branch's history.
262
+
263
+ ### 2.23 Branch Viewer
264
+
265
+ Browse all conversation branches in a read-only mode:
266
+
267
+ 1. Click the **branch history button** (git-branch icon) in the chat header — only visible when the session has branches
268
+ 2. The chat enters read-only mode:
269
+ - Branch pagination controls become active at every branch point
270
+ - Navigate freely between branches using ← / → arrows
271
+ - The input area shows "Branch viewer mode (read-only)"
272
+ - All message actions (edit, rewind, summarize, fork) are disabled
273
+ 3. Click **"Exit branch viewer"** in the header to return to the active conversation
274
+
275
+ ### 2.24 Max Budget Warning Banner
276
+
277
+ When the **Max Budget (USD)** advanced setting (see §13.16) is configured, a sticky banner appears at the top of the chat area once the session cost approaches the limit:
278
+
279
+ - **Yellow warning** (80% threshold) — "Budget warning: $X.XXXX / $Y.YYYY used (ZZ%) — approaching Max Budget limit."
280
+ - **Red critical warning** (95% threshold) — "Budget critical: $X.XXXX / $Y.YYYY used (ZZ%) — stream will auto-stop when limit is exceeded."
281
+ - Cost is shown to 4 decimal places
282
+ - The banner is informational; the SDK auto-stops the stream once the limit is actually crossed
283
+
284
+ The banner disappears automatically once the running cost falls back below the warning threshold (for example, after starting a new session).
285
+