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,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effort Utilities
|
|
3
|
+
* Shared resolution of ThinkingEffort levels against model capabilities.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Clamp unsupported effort levels:
|
|
7
|
+
* · 'max' → 'high' unless model supports it (Opus 4.6+, Sonnet 4.6)
|
|
8
|
+
* · 'xhigh' → 'high' unless model supports it (Opus 4.7 only)
|
|
9
|
+
* Other levels pass through unchanged.
|
|
10
|
+
*/
|
|
11
|
+
export function clampEffortForModel(effort, model) {
|
|
12
|
+
if (!effort)
|
|
13
|
+
return effort;
|
|
14
|
+
const supportsMax = !!model && (model === 'opus' || model === 'sonnet' ||
|
|
15
|
+
model.includes('opus-4-6') || model.includes('opus-4-7') || model.includes('sonnet-4-6'));
|
|
16
|
+
const supportsXHigh = !!model && (model === 'opus' || model.includes('opus-4-7'));
|
|
17
|
+
if (effort === 'max' && !supportsMax)
|
|
18
|
+
return 'high';
|
|
19
|
+
if (effort === 'xhigh' && !supportsXHigh)
|
|
20
|
+
return 'high';
|
|
21
|
+
return effort;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Whether the model supports Anthropic's adaptive thinking mode
|
|
25
|
+
* (`thinking: { type: 'adaptive' }`). Opus 4.7 requires adaptive;
|
|
26
|
+
* Opus 4.6 and Sonnet 4.6 accept adaptive as the recommended mode.
|
|
27
|
+
* Older models (Sonnet 4.5, Opus 4.5, Haiku, Sonnet 4, etc.) do NOT
|
|
28
|
+
* support adaptive and must stay on the legacy `maxThinkingTokens` path.
|
|
29
|
+
*/
|
|
30
|
+
export function supportsAdaptiveThinking(model) {
|
|
31
|
+
if (!model)
|
|
32
|
+
return false;
|
|
33
|
+
return (model === 'opus' || model === 'sonnet' ||
|
|
34
|
+
model.includes('opus-4-6') || model.includes('opus-4-7') || model.includes('sonnet-4-6'));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=effortUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effortUtils.js","sourceRoot":"","sources":["../../src/utils/effortUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAkC,EAAE,KAAyB;IAC/F,IAAI,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC;IAC3B,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,IAAI,CAC7B,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ;QACtC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CACzF,CAAC;IACF,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,KAAK,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IAClF,IAAI,MAAM,KAAK,KAAK,IAAI,CAAC,WAAW;QAAE,OAAO,MAAM,CAAC;IACpD,IAAI,MAAM,KAAK,OAAO,IAAI,CAAC,aAAa;QAAE,OAAO,MAAM,CAAC;IACxD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAyB;IAChE,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CACL,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ;QACtC,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC,CACzF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 28.0.5 (Task 5): thin wrapper around `ignore` (kaelzhang/node-ignore).
|
|
3
|
+
*
|
|
4
|
+
* Originally introduced as preemptive infrastructure under the placeholder
|
|
5
|
+
* label "Epic 30 Story 10" (the pre-BMad-renumbering forward reference);
|
|
6
|
+
* Story 30.1 fills the call-sites (`harnessShareScopeService` + the
|
|
7
|
+
* client-side `ShareBadge` / `ModeBanner`) by consuming `loadGitignore()` +
|
|
8
|
+
* `isIgnored()` to drive the "shared vs. local vs. fully-ignored" badges on
|
|
9
|
+
* the harness workbench tree.
|
|
10
|
+
*/
|
|
11
|
+
import { type Ignore } from 'ignore';
|
|
12
|
+
/**
|
|
13
|
+
* Load `<rootPath>/.gitignore` into an `Ignore` matcher. Missing files yield
|
|
14
|
+
* a matcher that never excludes anything (so callers can treat "no
|
|
15
|
+
* .gitignore" as "nothing is ignored" without a separate branch).
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadGitignore(rootPath: string): Promise<Ignore>;
|
|
18
|
+
/**
|
|
19
|
+
* Test a relative path against the matcher. Input paths are normalized to
|
|
20
|
+
* POSIX separators as required by `ignore`'s contract.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isIgnored(matcher: Ignore, relativePath: string): boolean;
|
|
23
|
+
//# sourceMappingURL=gitignoreFilter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignoreFilter.d.ts","sourceRoot":"","sources":["../../src/utils/gitignoreFilter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAsB,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEpD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAarE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAGxE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 28.0.5 (Task 5): thin wrapper around `ignore` (kaelzhang/node-ignore).
|
|
3
|
+
*
|
|
4
|
+
* Originally introduced as preemptive infrastructure under the placeholder
|
|
5
|
+
* label "Epic 30 Story 10" (the pre-BMad-renumbering forward reference);
|
|
6
|
+
* Story 30.1 fills the call-sites (`harnessShareScopeService` + the
|
|
7
|
+
* client-side `ShareBadge` / `ModeBanner`) by consuming `loadGitignore()` +
|
|
8
|
+
* `isIgnored()` to drive the "shared vs. local vs. fully-ignored" badges on
|
|
9
|
+
* the harness workbench tree.
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'fs/promises';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import ignoreFactory from 'ignore';
|
|
14
|
+
/**
|
|
15
|
+
* Load `<rootPath>/.gitignore` into an `Ignore` matcher. Missing files yield
|
|
16
|
+
* a matcher that never excludes anything (so callers can treat "no
|
|
17
|
+
* .gitignore" as "nothing is ignored" without a separate branch).
|
|
18
|
+
*/
|
|
19
|
+
export async function loadGitignore(rootPath) {
|
|
20
|
+
const matcher = ignoreFactory();
|
|
21
|
+
const gitignorePath = path.join(rootPath, '.gitignore');
|
|
22
|
+
try {
|
|
23
|
+
const content = await fs.readFile(gitignorePath, 'utf-8');
|
|
24
|
+
matcher.add(content);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error.code !== 'ENOENT') {
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
// No .gitignore — return an empty matcher.
|
|
31
|
+
}
|
|
32
|
+
return matcher;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Test a relative path against the matcher. Input paths are normalized to
|
|
36
|
+
* POSIX separators as required by `ignore`'s contract.
|
|
37
|
+
*/
|
|
38
|
+
export function isIgnored(matcher, relativePath) {
|
|
39
|
+
const posix = relativePath.replace(/\\/g, '/');
|
|
40
|
+
return matcher.ignores(posix);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=gitignoreFilter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignoreFilter.js","sourceRoot":"","sources":["../../src/utils/gitignoreFilter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,aAA8B,MAAM,QAAQ,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB;IAClD,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAChC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACxD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,2CAA2C;IAC7C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,YAAoB;IAC7D,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 30.3 (Task 4.2): Zod runtime validation of `manifest.json` inside the
|
|
3
|
+
* harness export/import bundle. Lives on the server because zod is a
|
|
4
|
+
* server-only dep — the shared package exposes only the TypeScript surface
|
|
5
|
+
* (`packages/shared/src/types/harnessBundle.ts`).
|
|
6
|
+
*
|
|
7
|
+
* Two boundaries call this schema:
|
|
8
|
+
* - the bundle service when unpacking an import ZIP (AC5.c "malformed
|
|
9
|
+
* manifest" branch)
|
|
10
|
+
* - the controller when accepting an export request body (AC1, AC2, AC5)
|
|
11
|
+
*
|
|
12
|
+
* Both reuse the discriminator/value sets exported from `@hammoc/shared` so
|
|
13
|
+
* the schema and types stay in lockstep.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
/**
|
|
17
|
+
* Strict manifest schema — `bundleVersion` is locked to the literal 1 so
|
|
18
|
+
* future-version bundles fall through to the AC5.a "futureBundle" branch
|
|
19
|
+
* before this schema is even consulted (the import service inspects the raw
|
|
20
|
+
* JSON's version field first, then runs full Zod validation).
|
|
21
|
+
*/
|
|
22
|
+
export declare const bundleManifestSchema: z.ZodObject<{
|
|
23
|
+
bundleVersion: z.ZodLiteral<1>;
|
|
24
|
+
hammocVersion: z.ZodString;
|
|
25
|
+
claudeCodeSpecVersion: z.ZodUnion<readonly [z.ZodString, z.ZodNull]>;
|
|
26
|
+
createdAt: z.ZodString;
|
|
27
|
+
sourceProjectSlug: z.ZodString;
|
|
28
|
+
includes: z.ZodArray<z.ZodEnum<{
|
|
29
|
+
agents: "agents";
|
|
30
|
+
hooks: "hooks";
|
|
31
|
+
commands: "commands";
|
|
32
|
+
skills: "skills";
|
|
33
|
+
mcp: "mcp";
|
|
34
|
+
"claude-md": "claude-md";
|
|
35
|
+
bmad: "bmad";
|
|
36
|
+
}>>;
|
|
37
|
+
secretsPolicy: z.ZodEnum<{
|
|
38
|
+
excluded: "excluded";
|
|
39
|
+
placeholder: "placeholder";
|
|
40
|
+
"included-explicit": "included-explicit";
|
|
41
|
+
}>;
|
|
42
|
+
pluginDependencies: z.ZodArray<z.ZodObject<{
|
|
43
|
+
name: z.ZodString;
|
|
44
|
+
marketplace: z.ZodString;
|
|
45
|
+
version: z.ZodOptional<z.ZodString>;
|
|
46
|
+
}, z.core.$strip>>;
|
|
47
|
+
items: z.ZodArray<z.ZodObject<{
|
|
48
|
+
domain: z.ZodEnum<{
|
|
49
|
+
agent: "agent";
|
|
50
|
+
command: "command";
|
|
51
|
+
skill: "skill";
|
|
52
|
+
mcp: "mcp";
|
|
53
|
+
hook: "hook";
|
|
54
|
+
"claude-md": "claude-md";
|
|
55
|
+
bmad: "bmad";
|
|
56
|
+
}>;
|
|
57
|
+
identity: z.ZodString;
|
|
58
|
+
relativePath: z.ZodString;
|
|
59
|
+
sourceShareScope: z.ZodEnum<{
|
|
60
|
+
local: "local";
|
|
61
|
+
shared: "shared";
|
|
62
|
+
fullyIgnored: "fullyIgnored";
|
|
63
|
+
}>;
|
|
64
|
+
}, z.core.$strip>>;
|
|
65
|
+
}, z.core.$strip>;
|
|
66
|
+
export type BundleManifestParsed = z.infer<typeof bundleManifestSchema>;
|
|
67
|
+
/**
|
|
68
|
+
* Loose schema used for "is this even a manifest?" detection before the
|
|
69
|
+
* strict schema runs. Lets the import service distinguish "totally garbage
|
|
70
|
+
* JSON" (no bundleVersion field at all) from "future bundle" (bundleVersion
|
|
71
|
+
* is a number outside our supported range).
|
|
72
|
+
*/
|
|
73
|
+
export declare const loosenedManifestSchema: z.ZodObject<{
|
|
74
|
+
bundleVersion: z.ZodOptional<z.ZodNumber>;
|
|
75
|
+
}, z.core.$strip>;
|
|
76
|
+
export declare const exportBundleRequestSchema: z.ZodObject<{
|
|
77
|
+
projectSlug: z.ZodString;
|
|
78
|
+
includes: z.ZodArray<z.ZodEnum<{
|
|
79
|
+
agents: "agents";
|
|
80
|
+
hooks: "hooks";
|
|
81
|
+
commands: "commands";
|
|
82
|
+
skills: "skills";
|
|
83
|
+
mcp: "mcp";
|
|
84
|
+
"claude-md": "claude-md";
|
|
85
|
+
bmad: "bmad";
|
|
86
|
+
}>>;
|
|
87
|
+
secretsPolicy: z.ZodEnum<{
|
|
88
|
+
excluded: "excluded";
|
|
89
|
+
placeholder: "placeholder";
|
|
90
|
+
"included-explicit": "included-explicit";
|
|
91
|
+
}>;
|
|
92
|
+
}, z.core.$strip>;
|
|
93
|
+
export declare const importApplyRequestSchema: z.ZodObject<{
|
|
94
|
+
bundleToken: z.ZodString;
|
|
95
|
+
itemActions: z.ZodRecord<z.ZodString, z.ZodEnum<{
|
|
96
|
+
rename: "rename";
|
|
97
|
+
overwrite: "overwrite";
|
|
98
|
+
skip: "skip";
|
|
99
|
+
appendSection: "appendSection";
|
|
100
|
+
}>>;
|
|
101
|
+
}, z.core.$strip>;
|
|
102
|
+
export declare const pluginDepsQuerySchema: z.ZodObject<{
|
|
103
|
+
projectSlug: z.ZodString;
|
|
104
|
+
}, z.core.$strip>;
|
|
105
|
+
//# sourceMappingURL=harnessBundleSchema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harnessBundleSchema.d.ts","sourceRoot":"","sources":["../../src/utils/harnessBundleSchema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA0CxB;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAU/B,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB;;iBAEjC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;iBAIpC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;iBAGnC,CAAC;AAEH,eAAO,MAAM,qBAAqB;;iBAEhC,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 30.3 (Task 4.2): Zod runtime validation of `manifest.json` inside the
|
|
3
|
+
* harness export/import bundle. Lives on the server because zod is a
|
|
4
|
+
* server-only dep — the shared package exposes only the TypeScript surface
|
|
5
|
+
* (`packages/shared/src/types/harnessBundle.ts`).
|
|
6
|
+
*
|
|
7
|
+
* Two boundaries call this schema:
|
|
8
|
+
* - the bundle service when unpacking an import ZIP (AC5.c "malformed
|
|
9
|
+
* manifest" branch)
|
|
10
|
+
* - the controller when accepting an export request body (AC1, AC2, AC5)
|
|
11
|
+
*
|
|
12
|
+
* Both reuse the discriminator/value sets exported from `@hammoc/shared` so
|
|
13
|
+
* the schema and types stay in lockstep.
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { BUNDLE_SECTIONS, HARNESS_BUNDLE_VERSION, } from '@hammoc/shared';
|
|
17
|
+
const sectionSchema = z.enum(BUNDLE_SECTIONS);
|
|
18
|
+
const secretsPolicySchema = z.enum(['excluded', 'placeholder', 'included-explicit']);
|
|
19
|
+
const itemDomainSchema = z.enum([
|
|
20
|
+
'claude-md',
|
|
21
|
+
'skill',
|
|
22
|
+
'mcp',
|
|
23
|
+
'hook',
|
|
24
|
+
'command',
|
|
25
|
+
'agent',
|
|
26
|
+
'bmad',
|
|
27
|
+
]);
|
|
28
|
+
const sourceShareScopeSchema = z.enum(['shared', 'local', 'fullyIgnored']);
|
|
29
|
+
const itemActionSchema = z.enum(['overwrite', 'skip', 'rename', 'appendSection']);
|
|
30
|
+
const pluginRefSchema = z.object({
|
|
31
|
+
name: z.string().min(1),
|
|
32
|
+
marketplace: z.string().min(1),
|
|
33
|
+
version: z.string().optional(),
|
|
34
|
+
});
|
|
35
|
+
const bundleItemSchema = z.object({
|
|
36
|
+
domain: itemDomainSchema,
|
|
37
|
+
identity: z.string().min(1),
|
|
38
|
+
relativePath: z.string().min(1),
|
|
39
|
+
sourceShareScope: sourceShareScopeSchema,
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* Strict manifest schema — `bundleVersion` is locked to the literal 1 so
|
|
43
|
+
* future-version bundles fall through to the AC5.a "futureBundle" branch
|
|
44
|
+
* before this schema is even consulted (the import service inspects the raw
|
|
45
|
+
* JSON's version field first, then runs full Zod validation).
|
|
46
|
+
*/
|
|
47
|
+
export const bundleManifestSchema = z.object({
|
|
48
|
+
bundleVersion: z.literal(HARNESS_BUNDLE_VERSION),
|
|
49
|
+
hammocVersion: z.string().min(1),
|
|
50
|
+
claudeCodeSpecVersion: z.union([z.string().min(1), z.null()]),
|
|
51
|
+
createdAt: z.string().min(1),
|
|
52
|
+
sourceProjectSlug: z.string().min(1),
|
|
53
|
+
includes: z.array(sectionSchema),
|
|
54
|
+
secretsPolicy: secretsPolicySchema,
|
|
55
|
+
pluginDependencies: z.array(pluginRefSchema),
|
|
56
|
+
items: z.array(bundleItemSchema),
|
|
57
|
+
});
|
|
58
|
+
/**
|
|
59
|
+
* Loose schema used for "is this even a manifest?" detection before the
|
|
60
|
+
* strict schema runs. Lets the import service distinguish "totally garbage
|
|
61
|
+
* JSON" (no bundleVersion field at all) from "future bundle" (bundleVersion
|
|
62
|
+
* is a number outside our supported range).
|
|
63
|
+
*/
|
|
64
|
+
export const loosenedManifestSchema = z.object({
|
|
65
|
+
bundleVersion: z.number().int().optional(),
|
|
66
|
+
});
|
|
67
|
+
export const exportBundleRequestSchema = z.object({
|
|
68
|
+
projectSlug: z.string().min(1),
|
|
69
|
+
includes: z.array(sectionSchema).min(1, 'at least one section is required'),
|
|
70
|
+
secretsPolicy: secretsPolicySchema,
|
|
71
|
+
});
|
|
72
|
+
export const importApplyRequestSchema = z.object({
|
|
73
|
+
bundleToken: z.string().min(1),
|
|
74
|
+
itemActions: z.record(z.string(), itemActionSchema),
|
|
75
|
+
});
|
|
76
|
+
export const pluginDepsQuerySchema = z.object({
|
|
77
|
+
projectSlug: z.string().min(1),
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=harnessBundleSchema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harnessBundleSchema.js","sourceRoot":"","sources":["../../src/utils/harnessBundleSchema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 28.0.5: Harness workbench path resolver.
|
|
3
|
+
*
|
|
4
|
+
* Resolves `~/.claude` (user scope) and `<projectRoot>/.claude` (project scope)
|
|
5
|
+
* into absolute paths and enforces that any relative path requested by the
|
|
6
|
+
* caller stays inside the resolved root. Every entry point into `harnessService`
|
|
7
|
+
* MUST route through `resolveHarnessPath` so that Windows/POSIX separator
|
|
8
|
+
* mixing, drive letters, UNC paths, and null-byte inputs cannot escape the
|
|
9
|
+
* subtree.
|
|
10
|
+
*/
|
|
11
|
+
import { type HarnessPathRef } from '@hammoc/shared';
|
|
12
|
+
/** Return the absolute path to the user-scope harness root (`~/.claude`). */
|
|
13
|
+
export declare function getUserHarnessRoot(): string;
|
|
14
|
+
/** Return the absolute path to the project-scope harness root (`<project>/.claude`). */
|
|
15
|
+
export declare function getProjectHarnessRoot(projectSlug: string): Promise<string>;
|
|
16
|
+
export interface ResolvedHarnessPath {
|
|
17
|
+
resolvedRoot: string;
|
|
18
|
+
absolutePath: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a `HarnessPathRef` to an absolute path, guaranteed to sit inside the
|
|
22
|
+
* resolved root. Throws `HARNESS_PATH_DENIED` for any traversal attempt.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveHarnessPath(ref: HarnessPathRef): Promise<ResolvedHarnessPath>;
|
|
25
|
+
/**
|
|
26
|
+
* Story 29.1 (AC6): resolve the project-root `<projectRoot>/CLAUDE.md` path —
|
|
27
|
+
* the single file in the harness workbench whose location sits OUTSIDE the
|
|
28
|
+
* project's `.claude/` subtree, so `resolveHarnessPath` would reject it as a
|
|
29
|
+
* traversal. This helper accepts only `projectSlug` (no caller-supplied
|
|
30
|
+
* relative path) and returns the canonical CLAUDE.md location alongside the
|
|
31
|
+
* project root, so traversal is impossible by construction.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveProjectClaudeMdPath(projectSlug: string): Promise<ResolvedHarnessPath>;
|
|
34
|
+
//# sourceMappingURL=harnessPaths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harnessPaths.d.ts","sourceRoot":"","sources":["../../src/utils/harnessPaths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAWrE,6EAA6E;AAC7E,wBAAgB,kBAAkB,IAAI,MAAM,CAO3C;AAED,wFAAwF;AACxF,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBhF;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAwC1F;AAED;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAyBlG"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 28.0.5: Harness workbench path resolver.
|
|
3
|
+
*
|
|
4
|
+
* Resolves `~/.claude` (user scope) and `<projectRoot>/.claude` (project scope)
|
|
5
|
+
* into absolute paths and enforces that any relative path requested by the
|
|
6
|
+
* caller stays inside the resolved root. Every entry point into `harnessService`
|
|
7
|
+
* MUST route through `resolveHarnessPath` so that Windows/POSIX separator
|
|
8
|
+
* mixing, drive letters, UNC paths, and null-byte inputs cannot escape the
|
|
9
|
+
* subtree.
|
|
10
|
+
*/
|
|
11
|
+
import os from 'os';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import { projectService } from '../services/projectService.js';
|
|
14
|
+
import { HARNESS_ERRORS } from '@hammoc/shared';
|
|
15
|
+
/**
|
|
16
|
+
* Test-only dependency-injection hook. When set, `getUserHarnessRoot()` returns
|
|
17
|
+
* this value instead of `~/.claude`. Production configurations leave it unset
|
|
18
|
+
* (no effect); unit tests in `harnessPaths.test.ts` / `harnessService.test.ts`
|
|
19
|
+
* redirect the user scope to a temp directory so they never touch the real
|
|
20
|
+
* home directory.
|
|
21
|
+
*/
|
|
22
|
+
const HOME_OVERRIDE_ENV = 'HAMMOC_HARNESS_HOME_OVERRIDE';
|
|
23
|
+
/** Return the absolute path to the user-scope harness root (`~/.claude`). */
|
|
24
|
+
export function getUserHarnessRoot() {
|
|
25
|
+
const override = process.env[HOME_OVERRIDE_ENV];
|
|
26
|
+
if (override && override.length > 0) {
|
|
27
|
+
return override;
|
|
28
|
+
}
|
|
29
|
+
// Node resolves %USERPROFILE% on Windows and $HOME on POSIX.
|
|
30
|
+
return path.join(os.homedir(), '.claude');
|
|
31
|
+
}
|
|
32
|
+
/** Return the absolute path to the project-scope harness root (`<project>/.claude`). */
|
|
33
|
+
export async function getProjectHarnessRoot(projectSlug) {
|
|
34
|
+
if (!projectSlug) {
|
|
35
|
+
const err = new Error('projectSlug is required for project scope');
|
|
36
|
+
err.code = HARNESS_ERRORS.HARNESS_ROOT_MISSING.code;
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const projectRoot = await projectService.resolveOriginalPath(projectSlug);
|
|
41
|
+
return path.join(projectRoot, '.claude');
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
// Any failure to resolve the project (unknown slug, missing index, etc.)
|
|
45
|
+
// maps to HARNESS_ROOT_MISSING so the controller can return a uniform 404.
|
|
46
|
+
const wrapped = new Error(`Unable to resolve harness root for project "${projectSlug}": ${error.message}`);
|
|
47
|
+
wrapped.code = HARNESS_ERRORS.HARNESS_ROOT_MISSING.code;
|
|
48
|
+
throw wrapped;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a `HarnessPathRef` to an absolute path, guaranteed to sit inside the
|
|
53
|
+
* resolved root. Throws `HARNESS_PATH_DENIED` for any traversal attempt.
|
|
54
|
+
*/
|
|
55
|
+
export async function resolveHarnessPath(ref) {
|
|
56
|
+
const rel = ref.relativePath ?? '';
|
|
57
|
+
// Reject absolute paths and null bytes before touching `path.join`, since
|
|
58
|
+
// join would otherwise discard the root prefix (POSIX absolute) or let a
|
|
59
|
+
// null byte slip through to fs APIs.
|
|
60
|
+
if (rel.includes('\0')) {
|
|
61
|
+
const err = new Error('null byte in relative path');
|
|
62
|
+
err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
|
|
63
|
+
throw err;
|
|
64
|
+
}
|
|
65
|
+
if (path.isAbsolute(rel)) {
|
|
66
|
+
const err = new Error('absolute path not allowed');
|
|
67
|
+
err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
// UNC inputs (`\\server\share`) on Windows: path.isAbsolute flags some of
|
|
71
|
+
// these, but on POSIX it would not — reject the prefix defensively.
|
|
72
|
+
if (rel.startsWith('\\\\') || rel.startsWith('//')) {
|
|
73
|
+
const err = new Error('UNC path not allowed');
|
|
74
|
+
err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
const resolvedRoot = ref.scope === 'user'
|
|
78
|
+
? path.resolve(getUserHarnessRoot())
|
|
79
|
+
: path.resolve(await getProjectHarnessRoot(ref.projectSlug ?? ''));
|
|
80
|
+
const absolutePath = path.resolve(resolvedRoot, rel);
|
|
81
|
+
// Containment check: absolutePath must be the root itself or sit beneath it.
|
|
82
|
+
// `startsWith(root + sep)` avoids the false match where root="/a" and
|
|
83
|
+
// absolutePath="/abc".
|
|
84
|
+
if (absolutePath !== resolvedRoot && !absolutePath.startsWith(resolvedRoot + path.sep)) {
|
|
85
|
+
const err = new Error('path escapes harness root');
|
|
86
|
+
err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
return { resolvedRoot, absolutePath };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Story 29.1 (AC6): resolve the project-root `<projectRoot>/CLAUDE.md` path —
|
|
93
|
+
* the single file in the harness workbench whose location sits OUTSIDE the
|
|
94
|
+
* project's `.claude/` subtree, so `resolveHarnessPath` would reject it as a
|
|
95
|
+
* traversal. This helper accepts only `projectSlug` (no caller-supplied
|
|
96
|
+
* relative path) and returns the canonical CLAUDE.md location alongside the
|
|
97
|
+
* project root, so traversal is impossible by construction.
|
|
98
|
+
*/
|
|
99
|
+
export async function resolveProjectClaudeMdPath(projectSlug) {
|
|
100
|
+
if (!projectSlug || projectSlug.includes('\0')) {
|
|
101
|
+
const err = new Error('invalid projectSlug');
|
|
102
|
+
err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
|
|
103
|
+
throw err;
|
|
104
|
+
}
|
|
105
|
+
// Reject traversal-bearing slugs before they reach projectService — defense in depth.
|
|
106
|
+
if (projectSlug.includes('..') || projectSlug.includes('/') || projectSlug.includes('\\')) {
|
|
107
|
+
const err = new Error('projectSlug must not contain path separators');
|
|
108
|
+
err.code = HARNESS_ERRORS.HARNESS_PATH_DENIED.code;
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
let projectRoot;
|
|
112
|
+
try {
|
|
113
|
+
projectRoot = await projectService.resolveOriginalPath(projectSlug);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
const wrapped = new Error(`Unable to resolve project root for "${projectSlug}": ${error.message}`);
|
|
117
|
+
wrapped.code = HARNESS_ERRORS.HARNESS_ROOT_MISSING.code;
|
|
118
|
+
throw wrapped;
|
|
119
|
+
}
|
|
120
|
+
const resolvedRoot = path.resolve(projectRoot);
|
|
121
|
+
const absolutePath = path.join(resolvedRoot, 'CLAUDE.md');
|
|
122
|
+
return { resolvedRoot, absolutePath };
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=harnessPaths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harnessPaths.js","sourceRoot":"","sources":["../../src/utils/harnessPaths.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,8 +15,9 @@ export declare function isProtectedPath(relativePath: string): boolean;
|
|
|
15
15
|
/** Maximum file size for full content response (1MB) */
|
|
16
16
|
export declare const MAX_FILE_SIZE: number;
|
|
17
17
|
/**
|
|
18
|
-
* Detect if a file is binary
|
|
19
|
-
*
|
|
18
|
+
* Detect if a file is binary.
|
|
19
|
+
* 1. Extension allowlist for formats whose headers lack null bytes (e.g. ZIP, PDF).
|
|
20
|
+
* 2. Fallback: read first 8192 bytes and check for null byte presence.
|
|
20
21
|
* @param filePath Absolute path to the file
|
|
21
22
|
* @returns true if the file appears to be binary
|
|
22
23
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pathUtils.d.ts","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,iDAAkD,CAAC;AAErF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAI7D;AAED,wDAAwD;AACxD,eAAO,MAAM,aAAa,QAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"pathUtils.d.ts","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,6DAA6D;AAC7D,eAAO,MAAM,qBAAqB,iDAAkD,CAAC;AAErF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAI7D;AAED,wDAAwD;AACxD,eAAO,MAAM,aAAa,QAAkB,CAAC;AAyB7C;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBrE;AA2BD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGpD"}
|
|
@@ -23,12 +23,36 @@ export const MAX_FILE_SIZE = 1 * 1024 * 1024;
|
|
|
23
23
|
/** Number of bytes to read for binary detection */
|
|
24
24
|
const BINARY_CHECK_BYTES = 8192;
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
26
|
+
* Extensions whose magic bytes do not contain null (0x00) and therefore
|
|
27
|
+
* evade the null-byte heuristic below. Detected by extension up front.
|
|
28
|
+
*/
|
|
29
|
+
const BINARY_EXTENSIONS = new Set([
|
|
30
|
+
// Archives
|
|
31
|
+
'.zip', '.gz', '.tar', '.tgz', '.bz2', '.7z', '.rar', '.xz',
|
|
32
|
+
// Documents
|
|
33
|
+
'.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
|
|
34
|
+
// Executables / libraries
|
|
35
|
+
'.exe', '.dll', '.so', '.dylib', '.class', '.jar', '.wasm',
|
|
36
|
+
// Databases
|
|
37
|
+
'.db', '.sqlite', '.sqlite3', '.mdb',
|
|
38
|
+
// Media (some already detected by null bytes, but listing for clarity)
|
|
39
|
+
'.mp3', '.mp4', '.avi', '.mov', '.wav', '.ogg', '.flac', '.webm',
|
|
40
|
+
'.webp', '.ico', '.bmp', '.tiff', '.heic',
|
|
41
|
+
// Fonts
|
|
42
|
+
'.ttf', '.otf', '.woff', '.woff2', '.eot',
|
|
43
|
+
]);
|
|
44
|
+
/**
|
|
45
|
+
* Detect if a file is binary.
|
|
46
|
+
* 1. Extension allowlist for formats whose headers lack null bytes (e.g. ZIP, PDF).
|
|
47
|
+
* 2. Fallback: read first 8192 bytes and check for null byte presence.
|
|
28
48
|
* @param filePath Absolute path to the file
|
|
29
49
|
* @returns true if the file appears to be binary
|
|
30
50
|
*/
|
|
31
51
|
export async function isBinaryFile(filePath) {
|
|
52
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
53
|
+
if (BINARY_EXTENSIONS.has(ext)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
32
56
|
const handle = await fs.open(filePath, 'r');
|
|
33
57
|
try {
|
|
34
58
|
const buffer = Buffer.alloc(BINARY_CHECK_BYTES);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pathUtils.js","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,6DAA6D;AAC7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,cAAc,EAAE,YAAY,CAAU,CAAC;AAErF;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,OAAO,qBAAqB,CAAC,QAAQ,CAAC,YAAoD,CAAC,CAAC;AAC9F,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7C,mDAAmD;AACnD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC
|
|
1
|
+
{"version":3,"file":"pathUtils.js","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 30.1 (Task 1): single source of truth for secret-pattern heuristics
|
|
3
|
+
* used by the harness write paths.
|
|
4
|
+
*
|
|
5
|
+
* Replaces four drifted SECRET_PATTERNS definitions (harnessAgentService,
|
|
6
|
+
* harnessCommandService, harnessHookService, harnessMcpService). Drift
|
|
7
|
+
* before this module:
|
|
8
|
+
*
|
|
9
|
+
* - agent / command / hook : 32-char base64 unanchored, Bearer unanchored
|
|
10
|
+
* - mcp : 40-char base64 anchored, Bearer anchored
|
|
11
|
+
*
|
|
12
|
+
* Canonical chosen here (Story 30.1 sub-spike 1.0, option (b)):
|
|
13
|
+
* - 32-char base64 unanchored, Bearer unanchored
|
|
14
|
+
*
|
|
15
|
+
* Rationale: detection-rate first; Story 30.1 AC4.c provides a per-save
|
|
16
|
+
* "mark not a secret" opt-out that absorbs false positives, whereas missed
|
|
17
|
+
* detections silently leak credentials. MCP's stricter anchors were a local
|
|
18
|
+
* accident, not a deliberate spec decision.
|
|
19
|
+
*
|
|
20
|
+
* Two entry points are exposed because the four services walk two distinct
|
|
21
|
+
* shapes:
|
|
22
|
+
*
|
|
23
|
+
* - detectSecretsInText → string body (agent / command / hook commands)
|
|
24
|
+
* returns matched line numbers (1-based)
|
|
25
|
+
* - detectSecretsInValue → arbitrary JSON-like value (mcp config)
|
|
26
|
+
* returns matched dot-paths
|
|
27
|
+
*
|
|
28
|
+
* Both strip `${ENV_VAR}` references first so legitimate env-var indirection
|
|
29
|
+
* (`Authorization: 'Bearer ${GH_TOKEN}'`) does not raise false positives.
|
|
30
|
+
*/
|
|
31
|
+
export interface SecretPattern {
|
|
32
|
+
name: string;
|
|
33
|
+
re: RegExp;
|
|
34
|
+
/**
|
|
35
|
+
* Optional minimum Shannon entropy (bits/char) gate for matched substrings.
|
|
36
|
+
* Story 30.3 spike #2: applies to the loose base64 pattern only. Natural
|
|
37
|
+
* English compounds (PascalCase identifiers, prose) sit at ~3.5–3.9; real
|
|
38
|
+
* base64-encoded tokens sit at ≥ 4.0 due to a-z/A-Z/0-9 uniform distribution.
|
|
39
|
+
* Other patterns keep their anchored prefixes (Bearer/sk-/AKIA/xox-) which
|
|
40
|
+
* already gate false positives — no entropy check needed.
|
|
41
|
+
*/
|
|
42
|
+
minEntropy?: number;
|
|
43
|
+
}
|
|
44
|
+
export declare const SECRET_PATTERNS: readonly SecretPattern[];
|
|
45
|
+
export declare const ENV_REF_RE: RegExp;
|
|
46
|
+
/**
|
|
47
|
+
* Shannon entropy in bits/char of an arbitrary string. Used by patterns that
|
|
48
|
+
* opt in via `minEntropy` (currently the loose base64 pattern only).
|
|
49
|
+
*/
|
|
50
|
+
export declare function shannonEntropy(s: string): number;
|
|
51
|
+
export interface DetectSecretsTextResult {
|
|
52
|
+
matched: boolean;
|
|
53
|
+
patternNames: string[];
|
|
54
|
+
lines: number[];
|
|
55
|
+
}
|
|
56
|
+
export interface DetectSecretsValueResult {
|
|
57
|
+
matched: boolean;
|
|
58
|
+
patternNames: string[];
|
|
59
|
+
paths: string[];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Line-based scanner for textual command / prompt bodies (agent system
|
|
63
|
+
* prompts, slash command bodies, hook command/prompt strings).
|
|
64
|
+
*/
|
|
65
|
+
export declare function detectSecretsInText(text: string): DetectSecretsTextResult;
|
|
66
|
+
/**
|
|
67
|
+
* Object-walk scanner for JSON-like values (mcp server config). Each string
|
|
68
|
+
* leaf is evaluated against the canonical patterns; matches are reported as
|
|
69
|
+
* dot-paths (`env.GITHUB_TOKEN`, `headers.Authorization`, ...).
|
|
70
|
+
*/
|
|
71
|
+
export declare function detectSecretsInValue(value: unknown, basePath?: string[]): DetectSecretsValueResult;
|
|
72
|
+
//# sourceMappingURL=secretHeuristic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secretHeuristic.d.ts","sourceRoot":"","sources":["../../src/utils/secretHeuristic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAMnD,CAAC;AAEF,eAAO,MAAM,UAAU,QAAkC,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAWhD;AAkCD,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAQD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,CA0BzE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,QAAQ,GAAE,MAAM,EAAO,GACtB,wBAAwB,CAgC1B"}
|