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