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.
- package/README.md +422 -403
- package/bin/hammoc.js +0 -6
- package/package.json +100 -93
- package/packages/client/dist/assets/agentExampleHighlight-BgwTm15v.js +1 -0
- package/packages/client/dist/assets/commandTokenHighlight-BljHwnrK.js +1 -0
- package/packages/client/dist/assets/index-CjyjnXB8.css +32 -0
- package/packages/client/dist/assets/index-D3LxqW3f.js +2 -0
- package/packages/client/dist/assets/index-NqJdhlek.js +1498 -0
- package/packages/client/dist/assets/snippetTokenHighlight-DWsaQXX0.js +1 -0
- package/packages/client/dist/index.html +2 -2
- package/packages/client/dist/sw.js +1 -1
- package/packages/server/dist/app.d.ts.map +1 -1
- package/packages/server/dist/app.js +24 -24
- package/packages/server/dist/app.js.map +1 -1
- package/packages/server/dist/controllers/boardController.d.ts.map +1 -1
- package/packages/server/dist/controllers/boardController.js +0 -5
- package/packages/server/dist/controllers/boardController.js.map +1 -1
- package/packages/server/dist/controllers/claudeMdController.d.ts +26 -0
- package/packages/server/dist/controllers/claudeMdController.d.ts.map +1 -0
- package/packages/server/dist/controllers/claudeMdController.js +158 -0
- package/packages/server/dist/controllers/claudeMdController.js.map +1 -0
- package/packages/server/dist/controllers/fileSystemController.d.ts +4 -0
- package/packages/server/dist/controllers/fileSystemController.d.ts.map +1 -1
- package/packages/server/dist/controllers/fileSystemController.js +20 -2
- package/packages/server/dist/controllers/fileSystemController.js.map +1 -1
- package/packages/server/dist/controllers/harnessAgentController.d.ts +28 -0
- package/packages/server/dist/controllers/harnessAgentController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessAgentController.js +339 -0
- package/packages/server/dist/controllers/harnessAgentController.js.map +1 -0
- package/packages/server/dist/controllers/harnessCommandController.d.ts +28 -0
- package/packages/server/dist/controllers/harnessCommandController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessCommandController.js +382 -0
- package/packages/server/dist/controllers/harnessCommandController.js.map +1 -0
- package/packages/server/dist/controllers/harnessController.d.ts +21 -0
- package/packages/server/dist/controllers/harnessController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessController.js +176 -0
- package/packages/server/dist/controllers/harnessController.js.map +1 -0
- package/packages/server/dist/controllers/harnessHookController.d.ts +32 -0
- package/packages/server/dist/controllers/harnessHookController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessHookController.js +363 -0
- package/packages/server/dist/controllers/harnessHookController.js.map +1 -0
- package/packages/server/dist/controllers/harnessLintController.d.ts +18 -0
- package/packages/server/dist/controllers/harnessLintController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessLintController.js +72 -0
- package/packages/server/dist/controllers/harnessLintController.js.map +1 -0
- package/packages/server/dist/controllers/harnessMcpController.d.ts +28 -0
- package/packages/server/dist/controllers/harnessMcpController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessMcpController.js +310 -0
- package/packages/server/dist/controllers/harnessMcpController.js.map +1 -0
- package/packages/server/dist/controllers/harnessPluginController.d.ts +17 -0
- package/packages/server/dist/controllers/harnessPluginController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessPluginController.js +115 -0
- package/packages/server/dist/controllers/harnessPluginController.js.map +1 -0
- package/packages/server/dist/controllers/harnessShareScopeController.d.ts +15 -0
- package/packages/server/dist/controllers/harnessShareScopeController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessShareScopeController.js +73 -0
- package/packages/server/dist/controllers/harnessShareScopeController.js.map +1 -0
- package/packages/server/dist/controllers/harnessSkillController.d.ts +32 -0
- package/packages/server/dist/controllers/harnessSkillController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessSkillController.js +453 -0
- package/packages/server/dist/controllers/harnessSkillController.js.map +1 -0
- package/packages/server/dist/controllers/projectController.d.ts.map +1 -1
- package/packages/server/dist/controllers/projectController.js +11 -0
- package/packages/server/dist/controllers/projectController.js.map +1 -1
- package/packages/server/dist/controllers/serverController.d.ts.map +1 -1
- package/packages/server/dist/controllers/serverController.js +84 -49
- package/packages/server/dist/controllers/serverController.js.map +1 -1
- package/packages/server/dist/controllers/snippetController.d.ts +35 -0
- package/packages/server/dist/controllers/snippetController.d.ts.map +1 -0
- package/packages/server/dist/controllers/snippetController.js +294 -0
- package/packages/server/dist/controllers/snippetController.js.map +1 -0
- package/packages/server/dist/handlers/websocket.d.ts +16 -0
- package/packages/server/dist/handlers/websocket.d.ts.map +1 -1
- package/packages/server/dist/handlers/websocket.js +221 -8
- package/packages/server/dist/handlers/websocket.js.map +1 -1
- package/packages/server/dist/index.js +66 -0
- package/packages/server/dist/index.js.map +1 -1
- package/packages/server/dist/locales/en/server.json +41 -6
- package/packages/server/dist/locales/es/server.json +3 -5
- package/packages/server/dist/locales/ja/server.json +3 -5
- package/packages/server/dist/locales/ko/server.json +4 -6
- package/packages/server/dist/locales/pt/server.json +3 -5
- package/packages/server/dist/locales/zh-CN/server.json +3 -5
- package/packages/server/dist/routes/account.d.ts +7 -0
- package/packages/server/dist/routes/account.d.ts.map +1 -0
- package/packages/server/dist/routes/account.js +35 -0
- package/packages/server/dist/routes/account.js.map +1 -0
- package/packages/server/dist/routes/debug.d.ts +1 -1
- package/packages/server/dist/routes/debug.d.ts.map +1 -1
- package/packages/server/dist/routes/debug.js +60 -1
- package/packages/server/dist/routes/debug.js.map +1 -1
- package/packages/server/dist/routes/harness.d.ts +8 -0
- package/packages/server/dist/routes/harness.d.ts.map +1 -0
- package/packages/server/dist/routes/harness.js +92 -0
- package/packages/server/dist/routes/harness.js.map +1 -0
- package/packages/server/dist/routes/preferences.d.ts.map +1 -1
- package/packages/server/dist/routes/preferences.js +11 -2
- package/packages/server/dist/routes/preferences.js.map +1 -1
- package/packages/server/dist/routes/projects.d.ts.map +1 -1
- package/packages/server/dist/routes/projects.js +5 -60
- package/packages/server/dist/routes/projects.js.map +1 -1
- package/packages/server/dist/routes/snippets.d.ts +14 -0
- package/packages/server/dist/routes/snippets.d.ts.map +1 -0
- package/packages/server/dist/routes/snippets.js +27 -0
- package/packages/server/dist/routes/snippets.js.map +1 -0
- package/packages/server/dist/services/accountInfoService.d.ts +38 -0
- package/packages/server/dist/services/accountInfoService.d.ts.map +1 -0
- package/packages/server/dist/services/accountInfoService.js +118 -0
- package/packages/server/dist/services/accountInfoService.js.map +1 -0
- package/packages/server/dist/services/bmadStatusService.d.ts +6 -2
- package/packages/server/dist/services/bmadStatusService.d.ts.map +1 -1
- package/packages/server/dist/services/bmadStatusService.js +88 -32
- package/packages/server/dist/services/bmadStatusService.js.map +1 -1
- package/packages/server/dist/services/chatService.d.ts +3 -0
- package/packages/server/dist/services/chatService.d.ts.map +1 -1
- package/packages/server/dist/services/chatService.js +36 -8
- package/packages/server/dist/services/chatService.js.map +1 -1
- package/packages/server/dist/services/claudeMdService.d.ts +48 -0
- package/packages/server/dist/services/claudeMdService.d.ts.map +1 -0
- package/packages/server/dist/services/claudeMdService.js +240 -0
- package/packages/server/dist/services/claudeMdService.js.map +1 -0
- package/packages/server/dist/services/commandService.d.ts +10 -0
- package/packages/server/dist/services/commandService.d.ts.map +1 -1
- package/packages/server/dist/services/commandService.js +129 -4
- package/packages/server/dist/services/commandService.js.map +1 -1
- package/packages/server/dist/services/fileSystemService.d.ts +7 -1
- package/packages/server/dist/services/fileSystemService.d.ts.map +1 -1
- package/packages/server/dist/services/fileSystemService.js +67 -8
- package/packages/server/dist/services/fileSystemService.js.map +1 -1
- package/packages/server/dist/services/fileWatcherService.d.ts +59 -0
- package/packages/server/dist/services/fileWatcherService.d.ts.map +1 -0
- package/packages/server/dist/services/fileWatcherService.js +329 -0
- package/packages/server/dist/services/fileWatcherService.js.map +1 -0
- package/packages/server/dist/services/gitService.d.ts.map +1 -1
- package/packages/server/dist/services/gitService.js +67 -7
- package/packages/server/dist/services/gitService.js.map +1 -1
- package/packages/server/dist/services/harnessAgentService.d.ts +79 -0
- package/packages/server/dist/services/harnessAgentService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessAgentService.js +933 -0
- package/packages/server/dist/services/harnessAgentService.js.map +1 -0
- package/packages/server/dist/services/harnessCommandService.d.ts +60 -0
- package/packages/server/dist/services/harnessCommandService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessCommandService.js +853 -0
- package/packages/server/dist/services/harnessCommandService.js.map +1 -0
- package/packages/server/dist/services/harnessHookService.d.ts +55 -0
- package/packages/server/dist/services/harnessHookService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessHookService.js +1060 -0
- package/packages/server/dist/services/harnessHookService.js.map +1 -0
- package/packages/server/dist/services/harnessLintService.d.ts +49 -0
- package/packages/server/dist/services/harnessLintService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessLintService.js +628 -0
- package/packages/server/dist/services/harnessLintService.js.map +1 -0
- package/packages/server/dist/services/harnessMcpService.d.ts +77 -0
- package/packages/server/dist/services/harnessMcpService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessMcpService.js +814 -0
- package/packages/server/dist/services/harnessMcpService.js.map +1 -0
- package/packages/server/dist/services/harnessPluginService.d.ts +66 -0
- package/packages/server/dist/services/harnessPluginService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessPluginService.js +559 -0
- package/packages/server/dist/services/harnessPluginService.js.map +1 -0
- package/packages/server/dist/services/harnessService.d.ts +40 -0
- package/packages/server/dist/services/harnessService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessService.js +222 -0
- package/packages/server/dist/services/harnessService.js.map +1 -0
- package/packages/server/dist/services/harnessShareScopeService.d.ts +31 -0
- package/packages/server/dist/services/harnessShareScopeService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessShareScopeService.js +93 -0
- package/packages/server/dist/services/harnessShareScopeService.js.map +1 -0
- package/packages/server/dist/services/harnessSkillService.d.ts +70 -0
- package/packages/server/dist/services/harnessSkillService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessSkillService.js +636 -0
- package/packages/server/dist/services/harnessSkillService.js.map +1 -0
- package/packages/server/dist/services/historyParser.d.ts +4 -14
- package/packages/server/dist/services/historyParser.d.ts.map +1 -1
- package/packages/server/dist/services/historyParser.js +60 -5
- package/packages/server/dist/services/historyParser.js.map +1 -1
- package/packages/server/dist/services/issueService.d.ts.map +1 -1
- package/packages/server/dist/services/issueService.js +10 -2
- package/packages/server/dist/services/issueService.js.map +1 -1
- package/packages/server/dist/services/manualSyncService.d.ts +19 -0
- package/packages/server/dist/services/manualSyncService.d.ts.map +1 -0
- package/packages/server/dist/services/manualSyncService.js +110 -0
- package/packages/server/dist/services/manualSyncService.js.map +1 -0
- package/packages/server/dist/services/notificationService.d.ts.map +1 -1
- package/packages/server/dist/services/notificationService.js +34 -9
- package/packages/server/dist/services/notificationService.js.map +1 -1
- package/packages/server/dist/services/preferencesService.d.ts.map +1 -1
- package/packages/server/dist/services/preferencesService.js +8 -1
- package/packages/server/dist/services/preferencesService.js.map +1 -1
- package/packages/server/dist/services/projectService.d.ts +5 -0
- package/packages/server/dist/services/projectService.d.ts.map +1 -1
- package/packages/server/dist/services/projectService.js +42 -2
- package/packages/server/dist/services/projectService.js.map +1 -1
- package/packages/server/dist/services/ptyService.d.ts +1 -0
- package/packages/server/dist/services/ptyService.d.ts.map +1 -1
- package/packages/server/dist/services/ptyService.js +36 -5
- package/packages/server/dist/services/ptyService.js.map +1 -1
- package/packages/server/dist/services/queueService.d.ts.map +1 -1
- package/packages/server/dist/services/queueService.js +83 -14
- package/packages/server/dist/services/queueService.js.map +1 -1
- package/packages/server/dist/services/sessionBufferManager.d.ts.map +1 -1
- package/packages/server/dist/services/sessionBufferManager.js +26 -0
- package/packages/server/dist/services/sessionBufferManager.js.map +1 -1
- package/packages/server/dist/services/sessionService.d.ts +4 -3
- package/packages/server/dist/services/sessionService.d.ts.map +1 -1
- package/packages/server/dist/services/sessionService.js +5 -4
- package/packages/server/dist/services/sessionService.js.map +1 -1
- package/packages/server/dist/services/snippetService.d.ts +54 -0
- package/packages/server/dist/services/snippetService.d.ts.map +1 -0
- package/packages/server/dist/services/snippetService.js +371 -0
- package/packages/server/dist/services/snippetService.js.map +1 -0
- package/packages/server/dist/services/utils/applyYamlFrontmatterPatch.d.ts +46 -0
- package/packages/server/dist/services/utils/applyYamlFrontmatterPatch.d.ts.map +1 -0
- package/packages/server/dist/services/utils/applyYamlFrontmatterPatch.js +125 -0
- package/packages/server/dist/services/utils/applyYamlFrontmatterPatch.js.map +1 -0
- package/packages/server/dist/services/webPushService.d.ts.map +1 -1
- package/packages/server/dist/services/webPushService.js +8 -1
- package/packages/server/dist/services/webPushService.js.map +1 -1
- package/packages/server/dist/snippets/split-commit +9 -0
- package/packages/server/dist/utils/applySecretsPolicy.d.ts +53 -0
- package/packages/server/dist/utils/applySecretsPolicy.d.ts.map +1 -0
- package/packages/server/dist/utils/applySecretsPolicy.js +204 -0
- package/packages/server/dist/utils/applySecretsPolicy.js.map +1 -0
- package/packages/server/dist/utils/assertNoSecretOnShared.d.ts +40 -0
- package/packages/server/dist/utils/assertNoSecretOnShared.d.ts.map +1 -0
- package/packages/server/dist/utils/assertNoSecretOnShared.js +47 -0
- package/packages/server/dist/utils/assertNoSecretOnShared.js.map +1 -0
- package/packages/server/dist/utils/effortUtils.d.ts +21 -0
- package/packages/server/dist/utils/effortUtils.d.ts.map +1 -0
- package/packages/server/dist/utils/effortUtils.js +36 -0
- package/packages/server/dist/utils/effortUtils.js.map +1 -0
- package/packages/server/dist/utils/gitignoreFilter.d.ts +23 -0
- package/packages/server/dist/utils/gitignoreFilter.d.ts.map +1 -0
- package/packages/server/dist/utils/gitignoreFilter.js +42 -0
- package/packages/server/dist/utils/gitignoreFilter.js.map +1 -0
- package/packages/server/dist/utils/harnessBundleSchema.d.ts +105 -0
- package/packages/server/dist/utils/harnessBundleSchema.d.ts.map +1 -0
- package/packages/server/dist/utils/harnessBundleSchema.js +79 -0
- package/packages/server/dist/utils/harnessBundleSchema.js.map +1 -0
- package/packages/server/dist/utils/harnessPaths.d.ts +34 -0
- package/packages/server/dist/utils/harnessPaths.d.ts.map +1 -0
- package/packages/server/dist/utils/harnessPaths.js +124 -0
- package/packages/server/dist/utils/harnessPaths.js.map +1 -0
- package/packages/server/dist/utils/pathUtils.d.ts +3 -2
- package/packages/server/dist/utils/pathUtils.d.ts.map +1 -1
- package/packages/server/dist/utils/pathUtils.js +26 -2
- package/packages/server/dist/utils/pathUtils.js.map +1 -1
- package/packages/server/dist/utils/secretHeuristic.d.ts +72 -0
- package/packages/server/dist/utils/secretHeuristic.d.ts.map +1 -0
- package/packages/server/dist/utils/secretHeuristic.js +163 -0
- package/packages/server/dist/utils/secretHeuristic.js.map +1 -0
- package/packages/server/dist/utils/secretPlaceholderNamer.d.ts +41 -0
- package/packages/server/dist/utils/secretPlaceholderNamer.d.ts.map +1 -0
- package/packages/server/dist/utils/secretPlaceholderNamer.js +81 -0
- package/packages/server/dist/utils/secretPlaceholderNamer.js.map +1 -0
- package/packages/server/dist/utils/serverPathResolver.d.ts +29 -0
- package/packages/server/dist/utils/serverPathResolver.d.ts.map +1 -0
- package/packages/server/dist/utils/serverPathResolver.js +59 -0
- package/packages/server/dist/utils/serverPathResolver.js.map +1 -0
- package/packages/server/dist/utils/snippetPaths.d.ts +61 -0
- package/packages/server/dist/utils/snippetPaths.d.ts.map +1 -0
- package/packages/server/dist/utils/snippetPaths.js +123 -0
- package/packages/server/dist/utils/snippetPaths.js.map +1 -0
- package/packages/server/dist/utils/structuredEditor.d.ts +34 -0
- package/packages/server/dist/utils/structuredEditor.d.ts.map +1 -0
- package/packages/server/dist/utils/structuredEditor.js +111 -0
- package/packages/server/dist/utils/structuredEditor.js.map +1 -0
- package/packages/server/package.json +6 -2
- package/packages/server/resources/internals/INDEX.md +23 -0
- package/packages/server/resources/internals/harness-files.md +63 -0
- package/packages/server/resources/internals/image-storage.md +43 -0
- package/packages/server/resources/manual/01-getting-started.md +104 -0
- package/packages/server/resources/manual/02-chat.md +285 -0
- package/packages/server/resources/manual/03-sessions.md +48 -0
- package/packages/server/resources/manual/04-slash-commands-favorites.md +152 -0
- package/packages/server/resources/manual/05-projects.md +74 -0
- package/packages/server/resources/manual/06-file-explorer-editor.md +90 -0
- package/packages/server/resources/manual/07-git.md +94 -0
- package/packages/server/resources/manual/08-terminal.md +59 -0
- package/packages/server/resources/manual/09-queue-runner.md +262 -0
- package/packages/server/resources/manual/10-project-board.md +193 -0
- package/packages/server/resources/manual/11-bmad-method-integration.md +128 -0
- package/packages/server/resources/manual/12-harness-workbench.md +175 -0
- package/packages/server/resources/manual/13-settings.md +241 -0
- package/packages/server/resources/manual/14-keyboard-shortcuts.md +68 -0
- package/packages/server/resources/manual/15-environment-variables.md +28 -0
- package/packages/server/resources/manual/16-troubleshooting.md +110 -0
- package/packages/server/resources/manual/INDEX.md +60 -0
- package/packages/shared/dist/index.d.ts +3 -0
- package/packages/shared/dist/index.d.ts.map +1 -1
- package/packages/shared/dist/index.js +6 -0
- package/packages/shared/dist/index.js.map +1 -1
- package/packages/shared/dist/types/command.d.ts +3 -3
- package/packages/shared/dist/types/command.d.ts.map +1 -1
- package/packages/shared/dist/types/fileSystem.d.ts +19 -0
- package/packages/shared/dist/types/fileSystem.d.ts.map +1 -1
- package/packages/shared/dist/types/fileSystem.js +5 -0
- package/packages/shared/dist/types/fileSystem.js.map +1 -1
- package/packages/shared/dist/types/git.d.ts +6 -1
- package/packages/shared/dist/types/git.d.ts.map +1 -1
- package/packages/shared/dist/types/git.js.map +1 -1
- package/packages/shared/dist/types/harness.d.ts +1211 -0
- package/packages/shared/dist/types/harness.d.ts.map +1 -0
- package/packages/shared/dist/types/harness.js +107 -0
- package/packages/shared/dist/types/harness.js.map +1 -0
- package/packages/shared/dist/types/harnessBundle.d.ts +170 -0
- package/packages/shared/dist/types/harnessBundle.d.ts.map +1 -0
- package/packages/shared/dist/types/harnessBundle.js +18 -0
- package/packages/shared/dist/types/harnessBundle.js.map +1 -0
- package/packages/shared/dist/types/history.d.ts +7 -0
- package/packages/shared/dist/types/history.d.ts.map +1 -1
- package/packages/shared/dist/types/preferences.d.ts +4 -1
- package/packages/shared/dist/types/preferences.d.ts.map +1 -1
- package/packages/shared/dist/types/preferences.js +1 -0
- package/packages/shared/dist/types/preferences.js.map +1 -1
- package/packages/shared/dist/types/queue.d.ts +9 -0
- package/packages/shared/dist/types/queue.d.ts.map +1 -1
- package/packages/shared/dist/types/sdk.d.ts +42 -1
- package/packages/shared/dist/types/sdk.d.ts.map +1 -1
- package/packages/shared/dist/types/sdk.js +26 -2
- package/packages/shared/dist/types/sdk.js.map +1 -1
- package/packages/shared/dist/types/websocket.d.ts +24 -0
- package/packages/shared/dist/types/websocket.d.ts.map +1 -1
- package/packages/shared/dist/utils/markdownSections.d.ts +50 -0
- package/packages/shared/dist/utils/markdownSections.d.ts.map +1 -0
- package/packages/shared/dist/utils/markdownSections.js +111 -0
- package/packages/shared/dist/utils/markdownSections.js.map +1 -0
- package/packages/shared/dist/utils/queueParser.d.ts.map +1 -1
- package/packages/shared/dist/utils/queueParser.js +104 -0
- package/packages/shared/dist/utils/queueParser.js.map +1 -1
- package/scripts/build-manual-shards.mjs +100 -0
- package/scripts/mock-telegram.mjs +172 -0
- package/scripts/run-integration-test.mjs +362 -0
- package/packages/client/dist/assets/index-Bf0D9oVJ.css +0 -32
- package/packages/client/dist/assets/index-CRmzoqHy.js +0 -2
- package/packages/client/dist/assets/index-CszGQ29O.js +0 -1432
|
@@ -21,11 +21,13 @@ import { notificationService, formatAskQuestionPrompt } from '../services/notifi
|
|
|
21
21
|
import { preferencesService } from '../services/preferencesService.js';
|
|
22
22
|
import { getOrCreateQueueService, getQueueInstances } from '../controllers/queueController.js';
|
|
23
23
|
import { createLogger } from '../utils/logger.js';
|
|
24
|
+
import { clampEffortForModel, supportsAdaptiveThinking } from '../utils/effortUtils.js';
|
|
24
25
|
import { buildStreamCallbacks } from './streamCallbacks.js';
|
|
25
26
|
import { rateLimitProbeService } from '../services/rateLimitProbeService.js';
|
|
26
27
|
import { ptyService } from '../services/ptyService.js';
|
|
27
28
|
import { projectService } from '../services/projectService.js';
|
|
28
29
|
import { dashboardService } from '../services/dashboardService.js';
|
|
30
|
+
import { fileWatcherService } from '../services/fileWatcherService.js';
|
|
29
31
|
import { summarize } from '../services/summarizeService.js';
|
|
30
32
|
import { parseJSONLFile, transformToHistoryMessages } from '../services/historyParser.js';
|
|
31
33
|
import { buildRawMessageTree, getActiveRawBranch, getDefaultRawBranchSelections, findBranchSelectionsForUuid } from '../utils/messageTree.js';
|
|
@@ -93,6 +95,10 @@ const socketToSession = new Map();
|
|
|
93
95
|
const socketSessionRoom = new Map();
|
|
94
96
|
// Track which project room each socket joined (for leave on session switch)
|
|
95
97
|
const socketProjectRoom = new Map();
|
|
98
|
+
// Story 28.0.5: Track harness rooms each socket has subscribed to, so we can
|
|
99
|
+
// release watcher ref counts on disconnect without leaking chokidar instances.
|
|
100
|
+
// Key: socket.id → Set of "harness:user" | "harness:project:<slug>" room strings.
|
|
101
|
+
const socketHarnessRooms = new Map();
|
|
96
102
|
const chainState = new Map();
|
|
97
103
|
// Per-session drain generation counter for race guard
|
|
98
104
|
const chainDrainGeneration = new Map();
|
|
@@ -101,6 +107,30 @@ const chainResumableSessions = new Set();
|
|
|
101
107
|
let chainItemCounter = 0;
|
|
102
108
|
const CHAIN_MAX_RETRIES = 3;
|
|
103
109
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
110
|
+
// Debug hook: synthetic failure injection for chain drain (G-02-02 retry test).
|
|
111
|
+
// Only consumed when ENABLE_TEST_ENDPOINTS=true; the POST /api/debug route
|
|
112
|
+
// validates the flag before writing to this map.
|
|
113
|
+
const chainDrainFailureInjection = new Map();
|
|
114
|
+
export function setChainDrainFailureInjection(sessionId, count) {
|
|
115
|
+
if (count <= 0) {
|
|
116
|
+
chainDrainFailureInjection.delete(sessionId);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
chainDrainFailureInjection.set(sessionId, count);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function consumeChainDrainFailureInjection(sessionId) {
|
|
123
|
+
const remaining = chainDrainFailureInjection.get(sessionId) ?? 0;
|
|
124
|
+
if (remaining <= 0)
|
|
125
|
+
return false;
|
|
126
|
+
if (remaining === 1) {
|
|
127
|
+
chainDrainFailureInjection.delete(sessionId);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
chainDrainFailureInjection.set(sessionId, remaining - 1);
|
|
131
|
+
}
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
104
134
|
// Story 25.9: Per-socket summarizing state — requestId prevents race between cancel + new request
|
|
105
135
|
const socketSummarizing = new Map();
|
|
106
136
|
/** Generate a unique chain item ID */
|
|
@@ -232,6 +262,11 @@ function scheduleChainDrain(sessionId, lang) {
|
|
|
232
262
|
const abortController = new AbortController();
|
|
233
263
|
let stream;
|
|
234
264
|
try {
|
|
265
|
+
// Debug: synthetic failure injection for retry tests (G-02-02).
|
|
266
|
+
// Throws before creating the stream so the retry path is exercised cleanly.
|
|
267
|
+
if (consumeChainDrainFailureInjection(sessionId)) {
|
|
268
|
+
throw new Error('Injected chain drain failure (debug)');
|
|
269
|
+
}
|
|
235
270
|
// Create headless stream inside try — if this throws, sending status is recovered below
|
|
236
271
|
const headless = createHeadlessStream(sessionId, abortController);
|
|
237
272
|
stream = headless.stream;
|
|
@@ -701,6 +736,29 @@ export async function initializeWebSocket(httpServer) {
|
|
|
701
736
|
cors: config.cors,
|
|
702
737
|
maxHttpBufferSize: 100 * 1024 * 1024, // 100MB for base64 image payloads
|
|
703
738
|
});
|
|
739
|
+
// Mirror project-room membership into fileWatcherService so every code path
|
|
740
|
+
// that calls socket.join/leave with a `project:<slug>` room transparently
|
|
741
|
+
// starts or stops the chokidar watcher for that project. socket.io emits
|
|
742
|
+
// join-room/leave-room exactly once per (socket, room) transition, so the
|
|
743
|
+
// service's ref count aligns with the number of sockets currently in the room.
|
|
744
|
+
const projectRoomAdapter = io.of('/').adapter;
|
|
745
|
+
projectRoomAdapter.on('join-room', (room, _id) => {
|
|
746
|
+
if (!room.startsWith('project:'))
|
|
747
|
+
return;
|
|
748
|
+
const slug = room.slice('project:'.length);
|
|
749
|
+
projectService
|
|
750
|
+
.resolveOriginalPath(slug)
|
|
751
|
+
.then((projectRoot) => fileWatcherService.ensureWatcher(slug, projectRoot))
|
|
752
|
+
.catch(() => {
|
|
753
|
+
// Project not found — nothing to watch; silently skip.
|
|
754
|
+
});
|
|
755
|
+
});
|
|
756
|
+
projectRoomAdapter.on('leave-room', (room, _id) => {
|
|
757
|
+
if (!room.startsWith('project:'))
|
|
758
|
+
return;
|
|
759
|
+
const slug = room.slice('project:'.length);
|
|
760
|
+
fileWatcherService.releaseWatcher(slug);
|
|
761
|
+
});
|
|
704
762
|
// Session middleware for WebSocket (Story 2.5 - Task 4)
|
|
705
763
|
const sessionMiddleware = await createSessionMiddleware();
|
|
706
764
|
// Parse session from cookie for Socket.io connections
|
|
@@ -765,6 +823,28 @@ export async function initializeWebSocket(httpServer) {
|
|
|
765
823
|
});
|
|
766
824
|
}
|
|
767
825
|
})();
|
|
826
|
+
// Allow clients to re-request terminal access info (e.g., after late listener registration)
|
|
827
|
+
socket.on('terminal:access:request', () => {
|
|
828
|
+
try {
|
|
829
|
+
const lang = socket.data.language || 'en';
|
|
830
|
+
const t = i18next.getFixedT(lang);
|
|
831
|
+
const clientIP = extractClientIP(socket);
|
|
832
|
+
const isLocal = isLocalIP(clientIP);
|
|
833
|
+
const terminalEnabled = preferencesService.getTerminalEnabled();
|
|
834
|
+
socket.emit('terminal:access', {
|
|
835
|
+
allowed: terminalEnabled && isLocal,
|
|
836
|
+
enabled: terminalEnabled,
|
|
837
|
+
reason: !terminalEnabled
|
|
838
|
+
? t('ws.error.terminalDisabled')
|
|
839
|
+
: !isLocal
|
|
840
|
+
? t('ws.error.terminalAccessDenied')
|
|
841
|
+
: undefined,
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
catch {
|
|
845
|
+
socket.emit('terminal:access', { allowed: false, enabled: false });
|
|
846
|
+
}
|
|
847
|
+
});
|
|
768
848
|
// Start rate limit polling on first client connection
|
|
769
849
|
if (connectedClients === 1) {
|
|
770
850
|
rateLimitProbeService.startPolling((data) => { io.emit('rateLimit:update', data); }, (data) => { io.emit('apiHealth:update', data); });
|
|
@@ -1026,6 +1106,12 @@ export async function initializeWebSocket(httpServer) {
|
|
|
1026
1106
|
// Handle session:join event — attach socket to active running stream (broadcast)
|
|
1027
1107
|
// Also joins a persistent Socket.io room so future streams auto-include this socket.
|
|
1028
1108
|
socket.on('session:join', (sessionId, projectSlug) => {
|
|
1109
|
+
// Dedup guard: if the same socket re-emits session:join for the same
|
|
1110
|
+
// session it's already in, skip the history / buffer-replay emissions
|
|
1111
|
+
// below. Room and stream.sockets membership are already correct, and
|
|
1112
|
+
// redundant replays on every reconnect (see ea66988 client-side change)
|
|
1113
|
+
// would cost extra bandwidth and trigger unnecessary client re-renders.
|
|
1114
|
+
const alreadyJoinedSame = socketSessionRoom.get(socket.id) === sessionId;
|
|
1029
1115
|
// Detach this socket from any previously-attached stream to prevent
|
|
1030
1116
|
// events from the old stream leaking to a different session's listeners
|
|
1031
1117
|
const prevSessionId = socketToSession.get(socket.id);
|
|
@@ -1043,7 +1129,8 @@ export async function initializeWebSocket(httpServer) {
|
|
|
1043
1129
|
if (prevRoomSessionId && prevRoomSessionId !== sessionId && prevRoomSessionId !== prevSessionId) {
|
|
1044
1130
|
socket.leave(`session:${prevRoomSessionId}`);
|
|
1045
1131
|
}
|
|
1046
|
-
// Join persistent session room (survives beyond ActiveStream lifecycle)
|
|
1132
|
+
// Join persistent session room (survives beyond ActiveStream lifecycle).
|
|
1133
|
+
// socket.join() is idempotent — safe to call even if already joined.
|
|
1047
1134
|
socket.join(`session:${sessionId}`);
|
|
1048
1135
|
// Leave previous project room if switching projects (or if new join has no projectSlug)
|
|
1049
1136
|
const prevProjectRoom = socketProjectRoom.get(socket.id);
|
|
@@ -1091,6 +1178,13 @@ export async function initializeWebSocket(httpServer) {
|
|
|
1091
1178
|
const freshItems = (chainState.get(sessionId) || []).map(toPublicChainItem);
|
|
1092
1179
|
socket.emit('chain:update', { sessionId, items: freshItems });
|
|
1093
1180
|
}
|
|
1181
|
+
// Dedup: a duplicate session:join from the already-present socket for
|
|
1182
|
+
// the same session doesn't need history / buffer-replay — the socket
|
|
1183
|
+
// already has them. Room membership and chain:update above are idempotent
|
|
1184
|
+
// and cheap, so we let those run.
|
|
1185
|
+
if (alreadyJoinedSame) {
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1094
1188
|
if (!stream || stream.status !== 'running') {
|
|
1095
1189
|
// Story 27.1: Deliver buffer messages via stream:history (no HTTP fetch needed).
|
|
1096
1190
|
// Wrapped in a helper that re-checks activeStreams because the async
|
|
@@ -1382,6 +1476,39 @@ export async function initializeWebSocket(httpServer) {
|
|
|
1382
1476
|
log.error(`Failed to remove persisted failure ${id} for session ${sessionId}:`, err);
|
|
1383
1477
|
});
|
|
1384
1478
|
});
|
|
1479
|
+
socket.on('chain:reorder', (data) => {
|
|
1480
|
+
if (!data || typeof data !== 'object')
|
|
1481
|
+
return;
|
|
1482
|
+
const { sessionId, ids } = data;
|
|
1483
|
+
if (!sessionId || typeof sessionId !== 'string' || !UUID_RE.test(sessionId))
|
|
1484
|
+
return;
|
|
1485
|
+
if (!Array.isArray(ids) || ids.length === 0)
|
|
1486
|
+
return;
|
|
1487
|
+
if (!ids.every(id => typeof id === 'string'))
|
|
1488
|
+
return;
|
|
1489
|
+
if (!socket.rooms.has(`session:${sessionId}`))
|
|
1490
|
+
return;
|
|
1491
|
+
const currentItems = chainState.get(sessionId);
|
|
1492
|
+
if (!currentItems)
|
|
1493
|
+
return;
|
|
1494
|
+
// Only reorder pending items — sending/sent items are already processed.
|
|
1495
|
+
const nonPending = currentItems.filter(item => item.status !== 'pending');
|
|
1496
|
+
const pendingById = new Map(currentItems.filter(item => item.status === 'pending').map(item => [item.id, item]));
|
|
1497
|
+
const reordered = [];
|
|
1498
|
+
for (const id of ids) {
|
|
1499
|
+
const item = pendingById.get(id);
|
|
1500
|
+
if (item) {
|
|
1501
|
+
reordered.push(item);
|
|
1502
|
+
pendingById.delete(id);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
// Append any pending items not present in ids (safety: preserve unknowns)
|
|
1506
|
+
for (const item of pendingById.values()) {
|
|
1507
|
+
reordered.push(item);
|
|
1508
|
+
}
|
|
1509
|
+
chainState.set(sessionId, [...nonPending, ...reordered]);
|
|
1510
|
+
broadcastChainUpdate(sessionId);
|
|
1511
|
+
});
|
|
1385
1512
|
socket.on('chain:clear', (data) => {
|
|
1386
1513
|
if (!data || typeof data !== 'object')
|
|
1387
1514
|
return;
|
|
@@ -1667,6 +1794,10 @@ export async function initializeWebSocket(httpServer) {
|
|
|
1667
1794
|
socket.emit('snippets:list', { snippets: [] });
|
|
1668
1795
|
}
|
|
1669
1796
|
});
|
|
1797
|
+
// Story 29.2: re-emit `snippets:list` after a snippet CRUD so the
|
|
1798
|
+
// originating client's autocomplete surfaces stay in sync without an
|
|
1799
|
+
// explicit refresh round-trip. This is the same channel the existing
|
|
1800
|
+
// listener above answers, so consumers don't need a new event handler.
|
|
1670
1801
|
// Handle project:join/leave — room for queue event delivery (Story 15.2)
|
|
1671
1802
|
socket.on('project:join', (projectSlug) => {
|
|
1672
1803
|
socket.join(`project:${projectSlug}`);
|
|
@@ -1679,6 +1810,37 @@ export async function initializeWebSocket(httpServer) {
|
|
|
1679
1810
|
socketProjectRoom.delete(socket.id);
|
|
1680
1811
|
}
|
|
1681
1812
|
});
|
|
1813
|
+
// Story 28.0.5: Harness workbench subscription — one room per scope.
|
|
1814
|
+
socket.on('harness:subscribe', async ({ scope, projectSlug }) => {
|
|
1815
|
+
const room = scope === 'user' ? 'harness:user' : `harness:project:${projectSlug ?? ''}`;
|
|
1816
|
+
await socket.join(room);
|
|
1817
|
+
let rooms = socketHarnessRooms.get(socket.id);
|
|
1818
|
+
if (!rooms) {
|
|
1819
|
+
rooms = new Set();
|
|
1820
|
+
socketHarnessRooms.set(socket.id, rooms);
|
|
1821
|
+
}
|
|
1822
|
+
// Idempotent subscribe: increment the watcher ref count only on the
|
|
1823
|
+
// first join so disconnect cleanup matches exactly.
|
|
1824
|
+
if (!rooms.has(room)) {
|
|
1825
|
+
rooms.add(room);
|
|
1826
|
+
try {
|
|
1827
|
+
await fileWatcherService.ensureHarnessWatcher({ scope, projectSlug });
|
|
1828
|
+
}
|
|
1829
|
+
catch (err) {
|
|
1830
|
+
log.warn(`harness:subscribe watcher failed for ${room}: ${String(err)}`);
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
});
|
|
1834
|
+
socket.on('harness:unsubscribe', async ({ scope, projectSlug }) => {
|
|
1835
|
+
const room = scope === 'user' ? 'harness:user' : `harness:project:${projectSlug ?? ''}`;
|
|
1836
|
+
await socket.leave(room);
|
|
1837
|
+
const rooms = socketHarnessRooms.get(socket.id);
|
|
1838
|
+
if (rooms && rooms.delete(room)) {
|
|
1839
|
+
fileWatcherService.releaseHarnessWatcher({ scope, projectSlug });
|
|
1840
|
+
if (rooms.size === 0)
|
|
1841
|
+
socketHarnessRooms.delete(socket.id);
|
|
1842
|
+
}
|
|
1843
|
+
});
|
|
1682
1844
|
// Handle queue events via WebSocket (Story 15.2)
|
|
1683
1845
|
socket.on('queue:start', async (data) => {
|
|
1684
1846
|
const { items, sessionId, projectSlug, permissionMode } = data;
|
|
@@ -1946,6 +2108,21 @@ export async function initializeWebSocket(httpServer) {
|
|
|
1946
2108
|
}
|
|
1947
2109
|
}
|
|
1948
2110
|
socketProjectRoom.delete(socket.id);
|
|
2111
|
+
// Story 28.0.5: Release any harness watcher refs held by this socket so
|
|
2112
|
+
// chokidar instances don't leak when a client drops without unsubscribing.
|
|
2113
|
+
const harnessRooms = socketHarnessRooms.get(socket.id);
|
|
2114
|
+
if (harnessRooms) {
|
|
2115
|
+
for (const room of harnessRooms) {
|
|
2116
|
+
if (room === 'harness:user') {
|
|
2117
|
+
fileWatcherService.releaseHarnessWatcher({ scope: 'user' });
|
|
2118
|
+
}
|
|
2119
|
+
else if (room.startsWith('harness:project:')) {
|
|
2120
|
+
const slug = room.slice('harness:project:'.length);
|
|
2121
|
+
fileWatcherService.releaseHarnessWatcher({ scope: 'project', projectSlug: slug });
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
socketHarnessRooms.delete(socket.id);
|
|
2125
|
+
}
|
|
1949
2126
|
// Story 25.9: Cleanup summarizing state on disconnect
|
|
1950
2127
|
const sumState = socketSummarizing.get(socket.id);
|
|
1951
2128
|
if (sumState?.abortController) {
|
|
@@ -1981,6 +2158,31 @@ export function getIO() {
|
|
|
1981
2158
|
}
|
|
1982
2159
|
return io;
|
|
1983
2160
|
}
|
|
2161
|
+
/**
|
|
2162
|
+
* Story 29.2 (AC1.e Phase 1): emit a fresh `snippets:list` payload to the
|
|
2163
|
+
* single socket that triggered a mutation, so the originating client's
|
|
2164
|
+
* SnippetPalette / useSnippets cache picks up the new state without an
|
|
2165
|
+
* explicit refresh round-trip.
|
|
2166
|
+
*
|
|
2167
|
+
* Phase-1 limitation: only the origin socket is notified. Other tabs / browsers
|
|
2168
|
+
* connected to the same project see stale data until their next user action
|
|
2169
|
+
* (panel open, page reload). The Phase-2 `project:${slug}` room fan-out is
|
|
2170
|
+
* deferred until ≥ 3 user reports of multi-tab divergence.
|
|
2171
|
+
*
|
|
2172
|
+
* Failures are swallowed — broadcast is best-effort and must not affect the
|
|
2173
|
+
* REST mutation's success/failure semantics.
|
|
2174
|
+
*/
|
|
2175
|
+
export async function broadcastSnippetList(workingDirectory, originSocketId) {
|
|
2176
|
+
if (!workingDirectory || !originSocketId || !io)
|
|
2177
|
+
return;
|
|
2178
|
+
try {
|
|
2179
|
+
const snippets = await listSnippets(workingDirectory);
|
|
2180
|
+
io.to(originSocketId).emit('snippets:list', { snippets });
|
|
2181
|
+
}
|
|
2182
|
+
catch (err) {
|
|
2183
|
+
log.warn(`broadcastSnippetList failed for socket ${originSocketId}: ${String(err)}`);
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
1984
2186
|
/**
|
|
1985
2187
|
* Get the current number of connected clients
|
|
1986
2188
|
* @returns Number of connected clients
|
|
@@ -2182,10 +2384,17 @@ async function handleChatSend(stream, data, abortController, lang) {
|
|
|
2182
2384
|
stream.chatService = chatService;
|
|
2183
2385
|
// Load preferences early for advanced settings + timeout
|
|
2184
2386
|
const effectivePrefs = await preferencesService.getEffectivePreferences();
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2387
|
+
const effectiveEffort = clampEffortForModel(effort ?? effectivePrefs.defaultEffort, model);
|
|
2388
|
+
// Opus 4.7 flipped `thinking.display` default to 'omitted' — ThinkingBlock UI stays blank
|
|
2389
|
+
// unless we explicitly opt in. For adaptive-thinking models, forward an explicit `thinking`
|
|
2390
|
+
// config based on the user's showThinkingBlocks preference (Hammoc default: true).
|
|
2391
|
+
// Legacy models (Sonnet 4.5, Opus 4.5, Haiku, Sonnet 4) keep the `maxThinkingTokens` path
|
|
2392
|
+
// since they don't accept `thinking.type: 'adaptive'`.
|
|
2393
|
+
const adaptiveCapable = supportsAdaptiveThinking(model);
|
|
2394
|
+
const showThinkingBlocks = effectivePrefs.showThinkingBlocks ?? true;
|
|
2395
|
+
const thinkingConfig = adaptiveCapable
|
|
2396
|
+
? { type: 'adaptive', display: (showThinkingBlocks ? 'summarized' : 'omitted') }
|
|
2397
|
+
: undefined;
|
|
2189
2398
|
const chatOptions = {
|
|
2190
2399
|
...(isResuming ? { resume: sessionId } : { sessionId }),
|
|
2191
2400
|
abortController,
|
|
@@ -2193,7 +2402,11 @@ async function handleChatSend(stream, data, abortController, lang) {
|
|
|
2193
2402
|
images,
|
|
2194
2403
|
// Advanced settings from preferences
|
|
2195
2404
|
customSystemPrompt: effectivePrefs.customSystemPrompt,
|
|
2196
|
-
maxThinkingTokens:
|
|
2405
|
+
// maxThinkingTokens: legacy path; SDK docs say it takes precedence for backward-compat,
|
|
2406
|
+
// which conflicts with adaptive mode on Opus 4.7 (rejects enabled+budget). Skip on
|
|
2407
|
+
// adaptive-capable models so the explicit `thinking` field governs.
|
|
2408
|
+
...(!adaptiveCapable && { maxThinkingTokens: effectivePrefs.maxThinkingTokens }),
|
|
2409
|
+
...(thinkingConfig && { thinking: thinkingConfig }),
|
|
2197
2410
|
maxTurns: effectivePrefs.maxTurns,
|
|
2198
2411
|
maxBudgetUsd: effectivePrefs.maxBudgetUsd,
|
|
2199
2412
|
effort: effectiveEffort,
|
|
@@ -2280,9 +2493,9 @@ async function handleChatSend(stream, data, abortController, lang) {
|
|
|
2280
2493
|
};
|
|
2281
2494
|
// Activity-based timeout: resets on every SDK callback event
|
|
2282
2495
|
// Prevents cancellation while SDK is actively working (e.g., large Write input streaming)
|
|
2283
|
-
// Timeout value from preferences (with env var override), clamped to
|
|
2496
|
+
// Timeout value from preferences (with env var override), clamped to 5s–30min range
|
|
2284
2497
|
const rawTimeoutMs = effectivePrefs.chatTimeoutMs ?? config.chat.timeoutMs;
|
|
2285
|
-
const timeoutMs = (rawTimeoutMs >=
|
|
2498
|
+
const timeoutMs = (rawTimeoutMs >= 5000 && rawTimeoutMs <= 1800000) ? rawTimeoutMs : 300000;
|
|
2286
2499
|
let lastResetSource = 'initial';
|
|
2287
2500
|
const resetTimeout = (source) => {
|
|
2288
2501
|
if (source)
|