hammoc 1.4.0 → 1.6.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 +428 -405
- package/bin/hammoc.js +0 -6
- package/package.json +100 -94
- package/packages/client/dist/assets/agentExampleHighlight-ltj9ce0U.js +1 -0
- package/packages/client/dist/assets/commandTokenHighlight-ji_ViMb4.js +1 -0
- package/packages/client/dist/assets/index-B-DiRGuz.js +2 -0
- package/packages/client/dist/assets/index-B09doO8H.js +139 -0
- package/packages/client/dist/assets/index-BT4RIi0U.js +1523 -0
- package/packages/client/dist/assets/index-DyNJ5jEW.css +32 -0
- package/packages/client/dist/assets/snippetTokenHighlight-CP3v4o2g.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 +13 -21
- package/packages/server/dist/app.js.map +1 -1
- package/packages/server/dist/controllers/bmadCoreConfigController.d.ts +41 -0
- package/packages/server/dist/controllers/bmadCoreConfigController.d.ts.map +1 -0
- package/packages/server/dist/controllers/bmadCoreConfigController.js +172 -0
- package/packages/server/dist/controllers/bmadCoreConfigController.js.map +1 -0
- 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/contextBuilderController.d.ts +43 -0
- package/packages/server/dist/controllers/contextBuilderController.d.ts.map +1 -0
- package/packages/server/dist/controllers/contextBuilderController.js +159 -0
- package/packages/server/dist/controllers/contextBuilderController.js.map +1 -0
- package/packages/server/dist/controllers/harnessAgentController.d.ts +35 -0
- package/packages/server/dist/controllers/harnessAgentController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessAgentController.js +372 -0
- package/packages/server/dist/controllers/harnessAgentController.js.map +1 -0
- package/packages/server/dist/controllers/harnessBundleController.d.ts +37 -0
- package/packages/server/dist/controllers/harnessBundleController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessBundleController.js +312 -0
- package/packages/server/dist/controllers/harnessBundleController.js.map +1 -0
- package/packages/server/dist/controllers/harnessCommandController.d.ts +35 -0
- package/packages/server/dist/controllers/harnessCommandController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessCommandController.js +415 -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 +406 -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 +371 -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 +24 -0
- package/packages/server/dist/controllers/harnessShareScopeController.d.ts.map +1 -0
- package/packages/server/dist/controllers/harnessShareScopeController.js +120 -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/marketplaceController.d.ts +19 -0
- package/packages/server/dist/controllers/marketplaceController.d.ts.map +1 -0
- package/packages/server/dist/controllers/marketplaceController.js +74 -0
- package/packages/server/dist/controllers/marketplaceController.js.map +1 -0
- package/packages/server/dist/controllers/observabilityController.d.ts +32 -0
- package/packages/server/dist/controllers/observabilityController.d.ts.map +1 -0
- package/packages/server/dist/controllers/observabilityController.js +148 -0
- package/packages/server/dist/controllers/observabilityController.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/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/streamCallbacks.d.ts +8 -0
- package/packages/server/dist/handlers/streamCallbacks.d.ts.map +1 -1
- package/packages/server/dist/handlers/streamCallbacks.js +8 -0
- package/packages/server/dist/handlers/streamCallbacks.js.map +1 -1
- package/packages/server/dist/handlers/websocket.d.ts +15 -0
- package/packages/server/dist/handlers/websocket.d.ts.map +1 -1
- package/packages/server/dist/handlers/websocket.js +103 -2
- package/packages/server/dist/handlers/websocket.js.map +1 -1
- package/packages/server/dist/index.js +5 -0
- package/packages/server/dist/index.js.map +1 -1
- package/packages/server/dist/locales/en/server.json +37 -4
- package/packages/server/dist/locales/es/server.json +0 -4
- package/packages/server/dist/locales/ja/server.json +0 -4
- package/packages/server/dist/locales/ko/server.json +0 -4
- package/packages/server/dist/locales/pt/server.json +0 -4
- package/packages/server/dist/locales/zh-CN/server.json +0 -4
- 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 +150 -0
- package/packages/server/dist/routes/harness.js.map +1 -0
- 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/bmadCoreConfigService.d.ts +86 -0
- package/packages/server/dist/services/bmadCoreConfigService.d.ts.map +1 -0
- package/packages/server/dist/services/bmadCoreConfigService.js +175 -0
- package/packages/server/dist/services/bmadCoreConfigService.js.map +1 -0
- package/packages/server/dist/services/bmadStatusService.d.ts +15 -2
- package/packages/server/dist/services/bmadStatusService.d.ts.map +1 -1
- package/packages/server/dist/services/bmadStatusService.js +146 -37
- 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 +28 -7
- 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/contextBuilderScriptTemplate.d.ts +24 -0
- package/packages/server/dist/services/contextBuilderScriptTemplate.d.ts.map +1 -0
- package/packages/server/dist/services/contextBuilderScriptTemplate.js +181 -0
- package/packages/server/dist/services/contextBuilderScriptTemplate.js.map +1 -0
- package/packages/server/dist/services/contextBuilderService.d.ts +68 -0
- package/packages/server/dist/services/contextBuilderService.d.ts.map +1 -0
- package/packages/server/dist/services/contextBuilderService.js +345 -0
- package/packages/server/dist/services/contextBuilderService.js.map +1 -0
- package/packages/server/dist/services/fileWatcherService.d.ts +24 -0
- package/packages/server/dist/services/fileWatcherService.d.ts.map +1 -1
- package/packages/server/dist/services/fileWatcherService.js +232 -1
- package/packages/server/dist/services/fileWatcherService.js.map +1 -1
- package/packages/server/dist/services/harnessAgentService.d.ts +97 -0
- package/packages/server/dist/services/harnessAgentService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessAgentService.js +988 -0
- package/packages/server/dist/services/harnessAgentService.js.map +1 -0
- package/packages/server/dist/services/harnessBundleService.d.ts +145 -0
- package/packages/server/dist/services/harnessBundleService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessBundleService.js +1318 -0
- package/packages/server/dist/services/harnessBundleService.js.map +1 -0
- package/packages/server/dist/services/harnessCommandService.d.ts +81 -0
- package/packages/server/dist/services/harnessCommandService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessCommandService.js +917 -0
- package/packages/server/dist/services/harnessCommandService.js.map +1 -0
- package/packages/server/dist/services/harnessHookService.d.ts +82 -0
- package/packages/server/dist/services/harnessHookService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessHookService.js +1112 -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 +100 -0
- package/packages/server/dist/services/harnessMcpService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessMcpService.js +884 -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 +50 -0
- package/packages/server/dist/services/harnessShareScopeService.d.ts.map +1 -0
- package/packages/server/dist/services/harnessShareScopeService.js +158 -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/issueService.d.ts.map +1 -1
- package/packages/server/dist/services/issueService.js +3 -1
- 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/marketplaceService.d.ts +50 -0
- package/packages/server/dist/services/marketplaceService.d.ts.map +1 -0
- package/packages/server/dist/services/marketplaceService.js +326 -0
- package/packages/server/dist/services/marketplaceService.js.map +1 -0
- package/packages/server/dist/services/observabilityService.d.ts +87 -0
- package/packages/server/dist/services/observabilityService.d.ts.map +1 -0
- package/packages/server/dist/services/observabilityService.js +0 -0
- package/packages/server/dist/services/observabilityService.js.map +1 -0
- package/packages/server/dist/services/queueService.d.ts.map +1 -1
- package/packages/server/dist/services/queueService.js +48 -2
- package/packages/server/dist/services/queueService.js.map +1 -1
- package/packages/server/dist/services/sessionService.d.ts +16 -0
- package/packages/server/dist/services/sessionService.d.ts.map +1 -1
- package/packages/server/dist/services/sessionService.js +125 -0
- 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/tokenCountService.d.ts +71 -0
- package/packages/server/dist/services/tokenCountService.d.ts.map +1 -0
- package/packages/server/dist/services/tokenCountService.js +313 -0
- package/packages/server/dist/services/tokenCountService.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/snippets/apply-qa-fixes +7 -5
- package/packages/server/dist/snippets/qa-review +5 -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/assertSafeBundlePath.d.ts +29 -0
- package/packages/server/dist/utils/assertSafeBundlePath.d.ts.map +1 -0
- package/packages/server/dist/utils/assertSafeBundlePath.js +53 -0
- package/packages/server/dist/utils/assertSafeBundlePath.js.map +1 -0
- package/packages/server/dist/utils/bundledBinaryModelSupport.d.ts +7 -0
- package/packages/server/dist/utils/bundledBinaryModelSupport.d.ts.map +1 -0
- package/packages/server/dist/utils/bundledBinaryModelSupport.js +107 -0
- package/packages/server/dist/utils/bundledBinaryModelSupport.js.map +1 -0
- package/packages/server/dist/utils/effortUtils.d.ts +2 -2
- package/packages/server/dist/utils/effortUtils.js +5 -5
- package/packages/server/dist/utils/effortUtils.js.map +1 -1
- package/packages/server/dist/utils/errors.d.ts +1 -0
- package/packages/server/dist/utils/errors.d.ts.map +1 -1
- package/packages/server/dist/utils/errors.js +17 -0
- package/packages/server/dist/utils/errors.js.map +1 -1
- 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 +107 -0
- package/packages/server/dist/utils/harnessBundleSchema.d.ts.map +1 -0
- package/packages/server/dist/utils/harnessBundleSchema.js +89 -0
- package/packages/server/dist/utils/harnessBundleSchema.js.map +1 -0
- package/packages/server/dist/utils/harnessPaths.d.ts +74 -0
- package/packages/server/dist/utils/harnessPaths.d.ts.map +1 -0
- package/packages/server/dist/utils/harnessPaths.js +247 -0
- package/packages/server/dist/utils/harnessPaths.js.map +1 -0
- 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 +25 -0
- package/packages/server/resources/internals/bmad-qa-fix-marker.md +32 -0
- package/packages/server/resources/internals/harness-files.md +85 -0
- package/packages/server/resources/internals/image-storage.md +43 -0
- package/packages/server/resources/internals/observability-storage.md +23 -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 +76 -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 +194 -0
- package/packages/server/resources/manual/11-bmad-method-integration.md +130 -0
- package/packages/server/resources/manual/12-harness-workbench.md +256 -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 +7 -0
- package/packages/shared/dist/index.d.ts.map +1 -1
- package/packages/shared/dist/index.js +14 -0
- package/packages/shared/dist/index.js.map +1 -1
- package/packages/shared/dist/types/bmadCoreConfig.d.ts +71 -0
- package/packages/shared/dist/types/bmadCoreConfig.d.ts.map +1 -0
- package/packages/shared/dist/types/bmadCoreConfig.js +30 -0
- package/packages/shared/dist/types/bmadCoreConfig.js.map +1 -0
- package/packages/shared/dist/types/bmadStatus.d.ts +10 -0
- package/packages/shared/dist/types/bmadStatus.d.ts.map +1 -1
- package/packages/shared/dist/types/bmadStatus.js.map +1 -1
- package/packages/shared/dist/types/board.d.ts +6 -0
- package/packages/shared/dist/types/board.d.ts.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/contextBuilder.d.ts +102 -0
- package/packages/shared/dist/types/contextBuilder.d.ts.map +1 -0
- package/packages/shared/dist/types/contextBuilder.js +55 -0
- package/packages/shared/dist/types/contextBuilder.js.map +1 -0
- 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 +205 -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/marketplace.d.ts +83 -0
- package/packages/shared/dist/types/marketplace.d.ts.map +1 -0
- package/packages/shared/dist/types/marketplace.js +18 -0
- package/packages/shared/dist/types/marketplace.js.map +1 -0
- package/packages/shared/dist/types/observability.d.ts +148 -0
- package/packages/shared/dist/types/observability.d.ts.map +1 -0
- package/packages/shared/dist/types/observability.js +24 -0
- package/packages/shared/dist/types/observability.js.map +1 -0
- package/packages/shared/dist/types/preferences.d.ts +4 -0
- package/packages/shared/dist/types/preferences.d.ts.map +1 -1
- 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 +1 -1
- package/packages/shared/dist/types/sdk.d.ts.map +1 -1
- package/packages/shared/dist/types/sdk.js +1 -1
- package/packages/shared/dist/types/sdk.js.map +1 -1
- package/packages/shared/dist/types/websocket.d.ts +10 -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/packages/client/dist/assets/index-6jREnVYd.js +0 -2
- package/packages/client/dist/assets/index-BFF0iqyW.css +0 -32
- package/packages/client/dist/assets/index-BcI4y-fU.js +0 -1454
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 31.2 (Task A.3): generator for the standalone SessionStart hook script
|
|
3
|
+
* `<projectRoot>/.hammoc/hooks/context-builder.mjs`.
|
|
4
|
+
*
|
|
5
|
+
* The generated `.mjs` runs independently of the Hammoc server at every session
|
|
6
|
+
* start. It is REGENERATED on every manifest save, so the declared file list /
|
|
7
|
+
* variable toggles / acknowledged commands are baked in as a CONFIG literal,
|
|
8
|
+
* while the actual VALUES (file contents, git output, today's date, active BMad
|
|
9
|
+
* story, command stdout) are computed FRESH at runtime (AC2.b/2.c — never
|
|
10
|
+
* snapshotted at generation time).
|
|
11
|
+
*
|
|
12
|
+
* Implementation note — the script body is a `String.raw` template so the regex
|
|
13
|
+
* backslashes (`\s`, `\r`, `\n`) survive into the emitted file verbatim. The two
|
|
14
|
+
* injected values are spliced in via function-replacement (not `${}`
|
|
15
|
+
* interpolation) so a `$` inside a path or command cannot trigger a replacement
|
|
16
|
+
* pattern, and so the body can stay free of `${` entirely.
|
|
17
|
+
*/
|
|
18
|
+
const SCRIPT_BODY = String.raw `// AUTO-GENERATED by Hammoc Context Builder (Story 31.2). DO NOT EDIT BY HAND.
|
|
19
|
+
// Source of truth: <projectRoot>/.hammoc/context-builder.json
|
|
20
|
+
// This file is overwritten on every manifest save. Edits here are lost.
|
|
21
|
+
//
|
|
22
|
+
// At every Claude Code SessionStart it prints a JSON envelope on stdout:
|
|
23
|
+
// { "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": "<assembled>" } }
|
|
24
|
+
import fs from 'node:fs';
|
|
25
|
+
import path from 'node:path';
|
|
26
|
+
import { execSync } from 'node:child_process';
|
|
27
|
+
|
|
28
|
+
const PROJECT_ROOT = __PROJECT_ROOT_JSON__;
|
|
29
|
+
const CONFIG = __CONFIG_JSON__;
|
|
30
|
+
|
|
31
|
+
function gitOutput(args) {
|
|
32
|
+
return execSync('git ' + args, {
|
|
33
|
+
cwd: PROJECT_ROOT,
|
|
34
|
+
encoding: 'utf8',
|
|
35
|
+
timeout: 5000,
|
|
36
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
37
|
+
}).trim();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readDevStoryLocation() {
|
|
41
|
+
// Resolve devStoryLocation from .bmad-core/core-config.yaml at runtime (no YAML
|
|
42
|
+
// dependency — a single-line regex is enough). Fallback: docs/stories.
|
|
43
|
+
try {
|
|
44
|
+
const cfg = fs.readFileSync(path.join(PROJECT_ROOT, '.bmad-core', 'core-config.yaml'), 'utf8');
|
|
45
|
+
const lines = cfg.split(/\r?\n/);
|
|
46
|
+
for (const ln of lines) {
|
|
47
|
+
const m = ln.match(/^devStoryLocation:\s*(.+?)\s*$/);
|
|
48
|
+
if (m) return m[1].replace(/^['"]|['"]$/g, '').trim();
|
|
49
|
+
}
|
|
50
|
+
} catch (e) {
|
|
51
|
+
// ignore — fall through to default
|
|
52
|
+
}
|
|
53
|
+
return 'docs/stories';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function parseTitle(text, fallback) {
|
|
57
|
+
const lines = text.split(/\r?\n/);
|
|
58
|
+
for (const ln of lines) {
|
|
59
|
+
const m = ln.match(/^#\s+(.+?)\s*$/);
|
|
60
|
+
if (m) return m[1];
|
|
61
|
+
}
|
|
62
|
+
return fallback;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function parseStatus(text) {
|
|
66
|
+
const lines = text.split(/\r?\n/);
|
|
67
|
+
for (let i = 0; i < lines.length; i++) {
|
|
68
|
+
if (/^##\s+Status\s*$/.test(lines[i])) {
|
|
69
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
70
|
+
const t = lines[j].trim();
|
|
71
|
+
if (t) return t;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return 'unknown';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function activeBmadStory() {
|
|
79
|
+
// PO-confirmed definition: the latest-mtime .story.md in devStoryLocation,
|
|
80
|
+
// surfaced as "<title> (Status: <status>)".
|
|
81
|
+
try {
|
|
82
|
+
const storyDir = readDevStoryLocation();
|
|
83
|
+
const dirAbs = path.resolve(PROJECT_ROOT, storyDir);
|
|
84
|
+
const files = fs.readdirSync(dirAbs).filter(function (f) { return f.endsWith('.story.md'); });
|
|
85
|
+
if (files.length === 0) return '(no .story.md files in ' + storyDir + ')';
|
|
86
|
+
let latest = files[0];
|
|
87
|
+
let latestMs = -1;
|
|
88
|
+
for (const f of files) {
|
|
89
|
+
const st = fs.statSync(path.join(dirAbs, f));
|
|
90
|
+
if (st.mtimeMs > latestMs) { latestMs = st.mtimeMs; latest = f; }
|
|
91
|
+
}
|
|
92
|
+
const text = fs.readFileSync(path.join(dirAbs, latest), 'utf8');
|
|
93
|
+
return parseTitle(text, latest) + ' (Status: ' + parseStatus(text) + ')';
|
|
94
|
+
} catch (e) {
|
|
95
|
+
return '(unable to resolve active BMad story)';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const blocks = [];
|
|
100
|
+
|
|
101
|
+
// (a) Reference files — read fresh; missing files become a placeholder so the
|
|
102
|
+
// whole script never fails (AC2.c).
|
|
103
|
+
for (const rel of CONFIG.files) {
|
|
104
|
+
const abs = path.resolve(PROJECT_ROOT, rel);
|
|
105
|
+
try {
|
|
106
|
+
const content = fs.readFileSync(abs, 'utf8');
|
|
107
|
+
blocks.push('## Reference file: ' + rel + '\n\n' + content);
|
|
108
|
+
} catch (e) {
|
|
109
|
+
blocks.push('## Reference file: ' + rel + '\n\n(파일을 찾을 수 없음: ' + rel + ')');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// (b) Built-in dynamic variables — recomputed every run (AC2.b).
|
|
114
|
+
if (CONFIG.variables.gitBranch) {
|
|
115
|
+
let v;
|
|
116
|
+
try { v = gitOutput('rev-parse --abbrev-ref HEAD'); } catch (e) { v = '(git unavailable)'; }
|
|
117
|
+
blocks.push('## Current git branch\n\n' + v);
|
|
118
|
+
}
|
|
119
|
+
if (CONFIG.variables.recentCommits) {
|
|
120
|
+
const n = CONFIG.recentCommitsCount || 5;
|
|
121
|
+
let v;
|
|
122
|
+
try { v = gitOutput('log -n ' + n + ' --pretty=format:%h %s'); } catch (e) { v = '(git unavailable)'; }
|
|
123
|
+
blocks.push('## Recent ' + n + ' commit(s)\n\n' + v);
|
|
124
|
+
}
|
|
125
|
+
if (CONFIG.variables.uncommittedCount) {
|
|
126
|
+
let v;
|
|
127
|
+
try {
|
|
128
|
+
const out = gitOutput('status --short');
|
|
129
|
+
v = out ? out.split(/\r?\n/).filter(Boolean).length : 0;
|
|
130
|
+
} catch (e) { v = '(git unavailable)'; }
|
|
131
|
+
blocks.push('## Uncommitted file count\n\n' + String(v));
|
|
132
|
+
}
|
|
133
|
+
if (CONFIG.variables.today) {
|
|
134
|
+
blocks.push('## Today\n\n' + new Date().toISOString().slice(0, 10));
|
|
135
|
+
}
|
|
136
|
+
if (CONFIG.variables.activeBmadStory) {
|
|
137
|
+
blocks.push('## Active BMad story\n\n' + activeBmadStory());
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// (c) Acknowledged custom commands (AC5.b) — only acknowledged commands were
|
|
141
|
+
// baked into CONFIG.
|
|
142
|
+
for (const cc of CONFIG.customCommands) {
|
|
143
|
+
let out;
|
|
144
|
+
try {
|
|
145
|
+
out = execSync(cc.command, { cwd: PROJECT_ROOT, encoding: 'utf8', timeout: 10000 }).trim();
|
|
146
|
+
} catch (e) {
|
|
147
|
+
out = '(command failed: ' + (e && e.message ? e.message : 'error') + ')';
|
|
148
|
+
}
|
|
149
|
+
blocks.push('## Command: ' + cc.command + '\n\n' + out);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const additionalContext = blocks.join('\n\n');
|
|
153
|
+
process.stdout.write(JSON.stringify({
|
|
154
|
+
hookSpecificOutput: {
|
|
155
|
+
hookEventName: 'SessionStart',
|
|
156
|
+
additionalContext: additionalContext,
|
|
157
|
+
},
|
|
158
|
+
}));
|
|
159
|
+
`;
|
|
160
|
+
/**
|
|
161
|
+
* Build the `.mjs` script text for the given project root + manifest. Only
|
|
162
|
+
* acknowledged custom commands are baked in (AC5.b).
|
|
163
|
+
*/
|
|
164
|
+
export function buildContextBuilderScript(projectRoot, manifest) {
|
|
165
|
+
const config = {
|
|
166
|
+
files: manifest.files,
|
|
167
|
+
variables: manifest.variables,
|
|
168
|
+
recentCommitsCount: manifest.recentCommitsCount ?? 5,
|
|
169
|
+
customCommands: manifest.customCommands
|
|
170
|
+
.filter((c) => c.acknowledged)
|
|
171
|
+
.map((c) => ({ command: c.command })),
|
|
172
|
+
};
|
|
173
|
+
// Function replacements so a `$` inside a path/command is never treated as a
|
|
174
|
+
// replacement pattern (`$&`, `$1`, ...).
|
|
175
|
+
const projectRootJson = JSON.stringify(projectRoot);
|
|
176
|
+
const configJson = JSON.stringify(config, null, 2);
|
|
177
|
+
return SCRIPT_BODY
|
|
178
|
+
.replace('__PROJECT_ROOT_JSON__', () => projectRootJson)
|
|
179
|
+
.replace('__CONFIG_JSON__', () => configJson);
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=contextBuilderScriptTemplate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextBuilderScriptTemplate.js","sourceRoot":"","sources":["../../src/services/contextBuilderScriptTemplate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAaH,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6I7B,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,WAAmB,EACnB,QAAgC;IAEhC,MAAM,MAAM,GAAgB;QAC1B,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,SAAS,EAAE,QAAQ,CAAC,SAAS;QAC7B,kBAAkB,EAAE,QAAQ,CAAC,kBAAkB,IAAI,CAAC;QACpD,cAAc,EAAE,QAAQ,CAAC,cAAc;aACpC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC;aAC7B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;KACxC,CAAC;IAEF,6EAA6E;IAC7E,yCAAyC;IACzC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEnD,OAAO,WAAW;SACf,OAAO,CAAC,uBAAuB,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC;SACvD,OAAO,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 31.2: SessionStart context-builder service (Epic 31).
|
|
3
|
+
*
|
|
4
|
+
* Domain: the declarative `<projectRoot>/.hammoc/context-builder.json` manifest
|
|
5
|
+
* (single source of truth) and its two GENERATED artifacts —
|
|
6
|
+
* - `<projectRoot>/.hammoc/hooks/context-builder.mjs` (the SessionStart script)
|
|
7
|
+
* - `<projectRoot>/.claude/settings.json` `hooks.SessionStart` entry pointing at it
|
|
8
|
+
*
|
|
9
|
+
* The manifest + script live under `.hammoc/`, a SIBLING of `.claude/` (outside
|
|
10
|
+
* the harness whitelist), so they get dedicated canonical-path resolvers
|
|
11
|
+
* (`resolveContextBuilderManifestPath` / `resolveContextBuilderScriptPath`) and
|
|
12
|
+
* are read/written with direct `fs` — exactly like Story 31.1's
|
|
13
|
+
* `.bmad-core/core-config.yaml`. `settings.json` IS inside `.claude/`, so its
|
|
14
|
+
* entry registration routes through `harnessService` + `applyJsoncPatch` (JSONC
|
|
15
|
+
* round-trip preserving comments/order).
|
|
16
|
+
*
|
|
17
|
+
* Ownership is identified purely by the command path marker
|
|
18
|
+
* (`CONTEXT_BUILDER_SCRIPT_MARKER`) — no extra metadata key is written into
|
|
19
|
+
* settings.json (AC1.e / AC3.a: the path IS the ownership identifier). A
|
|
20
|
+
* Hammoc-managed SessionStart group is updated in place; foreign (user-authored)
|
|
21
|
+
* groups are never touched.
|
|
22
|
+
*/
|
|
23
|
+
import { type ContextBuilderReadResponse, type ContextBuilderGenerateResponse } from '@hammoc/shared';
|
|
24
|
+
declare class ContextBuilderService {
|
|
25
|
+
/**
|
|
26
|
+
* Read the manifest + derived artifact state. Missing manifest → a default
|
|
27
|
+
* (disabled, empty) manifest with `mtime: ''` so the panel opens empty
|
|
28
|
+
* instead of erroring.
|
|
29
|
+
*/
|
|
30
|
+
readManifest(projectSlug: string): Promise<ContextBuilderReadResponse>;
|
|
31
|
+
/**
|
|
32
|
+
* Persist the manifest (SSoT) then regenerate its artifacts. When
|
|
33
|
+
* `manifest.enabled` is false this is equivalent to `disable` (artifacts are
|
|
34
|
+
* removed). Returns the new manifest mtime + generated artifact locations +
|
|
35
|
+
* any non-blocking secret warnings (AC5.c).
|
|
36
|
+
*/
|
|
37
|
+
writeManifest(projectSlug: string, input: unknown, expectedMtime?: string): Promise<ContextBuilderGenerateResponse>;
|
|
38
|
+
/**
|
|
39
|
+
* AC1.f — disable: retain the declaration (`enabled: false`) but remove the
|
|
40
|
+
* generated script + the Hammoc-managed SessionStart entry (other entries
|
|
41
|
+
* preserved).
|
|
42
|
+
*/
|
|
43
|
+
disable(projectSlug: string, expectedMtime?: string): Promise<{
|
|
44
|
+
mtime: string;
|
|
45
|
+
}>;
|
|
46
|
+
/** STALE_WRITE-guarded write of the manifest JSON via direct fs. */
|
|
47
|
+
private writeManifestFile;
|
|
48
|
+
/**
|
|
49
|
+
* Generate the `.mjs` script from the manifest, write it to disk, and
|
|
50
|
+
* register/refresh the SessionStart entry in settings.json.
|
|
51
|
+
*/
|
|
52
|
+
private generate;
|
|
53
|
+
/**
|
|
54
|
+
* Register (or refresh) the Hammoc-managed SessionStart entry. Updates the
|
|
55
|
+
* managed group in place when present; otherwise appends a new group, leaving
|
|
56
|
+
* any foreign groups untouched (AC1.e).
|
|
57
|
+
*/
|
|
58
|
+
private registerEntry;
|
|
59
|
+
/**
|
|
60
|
+
* Remove the Hammoc-managed SessionStart entry (preserving foreign groups)
|
|
61
|
+
* and delete the generated script. Returns the new settings.json mtime (or
|
|
62
|
+
* the unchanged/empty value when settings.json does not exist).
|
|
63
|
+
*/
|
|
64
|
+
private removeEntryAndScript;
|
|
65
|
+
}
|
|
66
|
+
export declare const contextBuilderService: ContextBuilderService;
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=contextBuilderService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextBuilderService.d.ts","sourceRoot":"","sources":["../../src/services/contextBuilderService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,OAAO,EAML,KAAK,0BAA0B,EAC/B,KAAK,8BAA8B,EAGpC,MAAM,gBAAgB,CAAC;AAkIxB,cAAM,qBAAqB;IACzB;;;;OAIG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;IA0C5E;;;;;OAKG;IACG,aAAa,CACjB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,OAAO,EACd,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,8BAA8B,CAAC;IAsB1C;;;;OAIG;IACG,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAgBtF,oEAAoE;YACtD,iBAAiB;IAyC/B;;;OAGG;YACW,QAAQ;IAoBtB;;;;OAIG;YACW,aAAa;IAoC3B;;;;OAIG;YACW,oBAAoB;CA8BnC;AAED,eAAO,MAAM,qBAAqB,uBAA8B,CAAC"}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 31.2: SessionStart context-builder service (Epic 31).
|
|
3
|
+
*
|
|
4
|
+
* Domain: the declarative `<projectRoot>/.hammoc/context-builder.json` manifest
|
|
5
|
+
* (single source of truth) and its two GENERATED artifacts —
|
|
6
|
+
* - `<projectRoot>/.hammoc/hooks/context-builder.mjs` (the SessionStart script)
|
|
7
|
+
* - `<projectRoot>/.claude/settings.json` `hooks.SessionStart` entry pointing at it
|
|
8
|
+
*
|
|
9
|
+
* The manifest + script live under `.hammoc/`, a SIBLING of `.claude/` (outside
|
|
10
|
+
* the harness whitelist), so they get dedicated canonical-path resolvers
|
|
11
|
+
* (`resolveContextBuilderManifestPath` / `resolveContextBuilderScriptPath`) and
|
|
12
|
+
* are read/written with direct `fs` — exactly like Story 31.1's
|
|
13
|
+
* `.bmad-core/core-config.yaml`. `settings.json` IS inside `.claude/`, so its
|
|
14
|
+
* entry registration routes through `harnessService` + `applyJsoncPatch` (JSONC
|
|
15
|
+
* round-trip preserving comments/order).
|
|
16
|
+
*
|
|
17
|
+
* Ownership is identified purely by the command path marker
|
|
18
|
+
* (`CONTEXT_BUILDER_SCRIPT_MARKER`) — no extra metadata key is written into
|
|
19
|
+
* settings.json (AC1.e / AC3.a: the path IS the ownership identifier). A
|
|
20
|
+
* Hammoc-managed SessionStart group is updated in place; foreign (user-authored)
|
|
21
|
+
* groups are never touched.
|
|
22
|
+
*/
|
|
23
|
+
import fs from 'fs/promises';
|
|
24
|
+
import path from 'path';
|
|
25
|
+
import { parse as parseJsonc } from 'jsonc-parser';
|
|
26
|
+
import { HARNESS_ERRORS, CONTEXT_BUILDER_SCRIPT_MARKER, CONTEXT_BUILDER_VARIABLE_IDS, createDefaultContextBuilderManifest, } from '@hammoc/shared';
|
|
27
|
+
import { resolveContextBuilderManifestPath, resolveContextBuilderScriptPath, } from '../utils/harnessPaths.js';
|
|
28
|
+
import { harnessService } from './harnessService.js';
|
|
29
|
+
import { applyJsoncPatch } from '../utils/structuredEditor.js';
|
|
30
|
+
import { detectSecretsInText } from '../utils/secretHeuristic.js';
|
|
31
|
+
import { fileWatcherService } from './fileWatcherService.js';
|
|
32
|
+
import { buildContextBuilderScript } from './contextBuilderScriptTemplate.js';
|
|
33
|
+
function throwMapped(code, message, extras) {
|
|
34
|
+
const err = new Error(message);
|
|
35
|
+
err.code = code;
|
|
36
|
+
if (extras)
|
|
37
|
+
Object.assign(err, extras);
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
function isFileNotFound(err) {
|
|
41
|
+
const code = err?.code;
|
|
42
|
+
return code === 'ENOENT' || code === HARNESS_ERRORS.HARNESS_FILE_NOT_FOUND.code;
|
|
43
|
+
}
|
|
44
|
+
/** Forward-slash a path so the ownership marker match works cross-platform. */
|
|
45
|
+
function normalizeSlashes(p) {
|
|
46
|
+
return p.replace(/\\/g, '/');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Normalize an arbitrary parsed manifest into a fully-populated, well-typed
|
|
50
|
+
* shape: all 5 variable keys present, arrays defaulted, version pinned. Guards
|
|
51
|
+
* against partial on-disk manifests and hand-edits.
|
|
52
|
+
*/
|
|
53
|
+
function normalizeManifest(input) {
|
|
54
|
+
const base = createDefaultContextBuilderManifest();
|
|
55
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) {
|
|
56
|
+
return base;
|
|
57
|
+
}
|
|
58
|
+
const raw = input;
|
|
59
|
+
const files = Array.isArray(raw.files)
|
|
60
|
+
? raw.files.filter((f) => typeof f === 'string')
|
|
61
|
+
: base.files;
|
|
62
|
+
const variables = { ...base.variables };
|
|
63
|
+
if (raw.variables && typeof raw.variables === 'object' && !Array.isArray(raw.variables)) {
|
|
64
|
+
const rv = raw.variables;
|
|
65
|
+
for (const id of CONTEXT_BUILDER_VARIABLE_IDS) {
|
|
66
|
+
if (typeof rv[id] === 'boolean')
|
|
67
|
+
variables[id] = rv[id];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const customCommands = Array.isArray(raw.customCommands)
|
|
71
|
+
? raw.customCommands
|
|
72
|
+
.filter((c) => !!c && typeof c === 'object')
|
|
73
|
+
.map((c) => ({
|
|
74
|
+
command: typeof c.command === 'string' ? c.command : '',
|
|
75
|
+
acknowledged: c.acknowledged === true,
|
|
76
|
+
}))
|
|
77
|
+
.filter((c) => c.command.length > 0)
|
|
78
|
+
: base.customCommands;
|
|
79
|
+
const recentCommitsCount = typeof raw.recentCommitsCount === 'number' && raw.recentCommitsCount > 0
|
|
80
|
+
? Math.floor(raw.recentCommitsCount)
|
|
81
|
+
: base.recentCommitsCount;
|
|
82
|
+
return {
|
|
83
|
+
version: 1,
|
|
84
|
+
enabled: raw.enabled === true,
|
|
85
|
+
files,
|
|
86
|
+
variables,
|
|
87
|
+
recentCommitsCount,
|
|
88
|
+
customCommands,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const SETTINGS_REL = 'settings.json';
|
|
92
|
+
function settingsRef(projectSlug) {
|
|
93
|
+
return { scope: 'project', projectSlug, relativePath: SETTINGS_REL };
|
|
94
|
+
}
|
|
95
|
+
/** Read settings.json via harnessService; missing file → empty content. */
|
|
96
|
+
async function readSettings(projectSlug) {
|
|
97
|
+
try {
|
|
98
|
+
const res = await harnessService.read(settingsRef(projectSlug));
|
|
99
|
+
return { content: res.content ?? '', mtime: res.mtime, exists: true };
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (isFileNotFound(err))
|
|
103
|
+
return { content: '', mtime: '', exists: false };
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function parseSessionStartGroups(settingsContent) {
|
|
108
|
+
if (!settingsContent.trim())
|
|
109
|
+
return [];
|
|
110
|
+
let parsed;
|
|
111
|
+
try {
|
|
112
|
+
parsed = parseJsonc(settingsContent);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
const hooks = parsed?.hooks?.SessionStart;
|
|
118
|
+
return Array.isArray(hooks) ? hooks : [];
|
|
119
|
+
}
|
|
120
|
+
/** Index of the Hammoc-managed SessionStart group, or -1 when none exists. */
|
|
121
|
+
function findManagedIndex(groups) {
|
|
122
|
+
for (let i = 0; i < groups.length; i += 1) {
|
|
123
|
+
const hookList = groups[i]?.hooks;
|
|
124
|
+
if (Array.isArray(hookList) &&
|
|
125
|
+
hookList.some((h) => typeof h?.command === 'string' &&
|
|
126
|
+
normalizeSlashes(h.command).includes(CONTEXT_BUILDER_SCRIPT_MARKER))) {
|
|
127
|
+
return i;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return -1;
|
|
131
|
+
}
|
|
132
|
+
class ContextBuilderService {
|
|
133
|
+
/**
|
|
134
|
+
* Read the manifest + derived artifact state. Missing manifest → a default
|
|
135
|
+
* (disabled, empty) manifest with `mtime: ''` so the panel opens empty
|
|
136
|
+
* instead of erroring.
|
|
137
|
+
*/
|
|
138
|
+
async readManifest(projectSlug) {
|
|
139
|
+
const { absolutePath } = await resolveContextBuilderManifestPath(projectSlug);
|
|
140
|
+
let manifest = createDefaultContextBuilderManifest();
|
|
141
|
+
let mtime = '';
|
|
142
|
+
try {
|
|
143
|
+
const stat = await fs.stat(absolutePath);
|
|
144
|
+
if (stat.isFile()) {
|
|
145
|
+
const text = await fs.readFile(absolutePath, 'utf-8');
|
|
146
|
+
try {
|
|
147
|
+
manifest = normalizeManifest(JSON.parse(text));
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// Corrupt JSON on disk — surface as PARSE_ERROR so the client can
|
|
151
|
+
// reset rather than silently dropping the user's declaration.
|
|
152
|
+
throwMapped(HARNESS_ERRORS.HARNESS_PARSE_ERROR.code, 'context-builder.json is not valid JSON');
|
|
153
|
+
}
|
|
154
|
+
mtime = stat.mtime.toISOString();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
if (!isFileNotFound(err)) {
|
|
159
|
+
if (err.code === HARNESS_ERRORS.HARNESS_PARSE_ERROR.code)
|
|
160
|
+
throw err;
|
|
161
|
+
const code = err.code;
|
|
162
|
+
if (code === 'EACCES')
|
|
163
|
+
throwMapped(HARNESS_ERRORS.HARNESS_FORBIDDEN.code, 'permission denied');
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const { absolutePath: scriptPath } = await resolveContextBuilderScriptPath(projectSlug);
|
|
168
|
+
let scriptExists = false;
|
|
169
|
+
try {
|
|
170
|
+
const st = await fs.stat(scriptPath);
|
|
171
|
+
scriptExists = st.isFile();
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
scriptExists = false;
|
|
175
|
+
}
|
|
176
|
+
const { content } = await readSettings(projectSlug);
|
|
177
|
+
const entryRegistered = findManagedIndex(parseSessionStartGroups(content)) >= 0;
|
|
178
|
+
return { manifest, mtime, scriptExists, entryRegistered };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Persist the manifest (SSoT) then regenerate its artifacts. When
|
|
182
|
+
* `manifest.enabled` is false this is equivalent to `disable` (artifacts are
|
|
183
|
+
* removed). Returns the new manifest mtime + generated artifact locations +
|
|
184
|
+
* any non-blocking secret warnings (AC5.c).
|
|
185
|
+
*/
|
|
186
|
+
async writeManifest(projectSlug, input, expectedMtime) {
|
|
187
|
+
const manifest = normalizeManifest(input);
|
|
188
|
+
// AC5.c — scan acknowledged command strings; NON-BLOCKING notice only.
|
|
189
|
+
const secretWarningCommandIndices = [];
|
|
190
|
+
manifest.customCommands.forEach((cc, idx) => {
|
|
191
|
+
if (cc.acknowledged && detectSecretsInText(cc.command).matched) {
|
|
192
|
+
secretWarningCommandIndices.push(idx);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
const mtime = await this.writeManifestFile(projectSlug, manifest, expectedMtime);
|
|
196
|
+
if (!manifest.enabled) {
|
|
197
|
+
const settingsMtime = await this.removeEntryAndScript(projectSlug);
|
|
198
|
+
return { mtime, scriptPath: '', settingsMtime, secretWarningCommandIndices };
|
|
199
|
+
}
|
|
200
|
+
const { scriptPath, settingsMtime } = await this.generate(projectSlug, manifest);
|
|
201
|
+
return { mtime, scriptPath, settingsMtime, secretWarningCommandIndices };
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* AC1.f — disable: retain the declaration (`enabled: false`) but remove the
|
|
205
|
+
* generated script + the Hammoc-managed SessionStart entry (other entries
|
|
206
|
+
* preserved).
|
|
207
|
+
*/
|
|
208
|
+
async disable(projectSlug, expectedMtime) {
|
|
209
|
+
const current = await this.readManifest(projectSlug);
|
|
210
|
+
const manifest = { ...current.manifest, enabled: false };
|
|
211
|
+
const mtime = await this.writeManifestFile(projectSlug, manifest, expectedMtime ?? (current.mtime || undefined));
|
|
212
|
+
await this.removeEntryAndScript(projectSlug);
|
|
213
|
+
return { mtime };
|
|
214
|
+
}
|
|
215
|
+
// -------------------------------------------------------------------------
|
|
216
|
+
// internals
|
|
217
|
+
// -------------------------------------------------------------------------
|
|
218
|
+
/** STALE_WRITE-guarded write of the manifest JSON via direct fs. */
|
|
219
|
+
async writeManifestFile(projectSlug, manifest, expectedMtime) {
|
|
220
|
+
const { absolutePath } = await resolveContextBuilderManifestPath(projectSlug);
|
|
221
|
+
if (expectedMtime !== undefined) {
|
|
222
|
+
try {
|
|
223
|
+
const existing = await fs.stat(absolutePath);
|
|
224
|
+
const currentMtime = existing.mtime.toISOString();
|
|
225
|
+
if (currentMtime !== expectedMtime) {
|
|
226
|
+
throwMapped(HARNESS_ERRORS.HARNESS_STALE_WRITE.code, 'manifest changed on disk', { currentMtime });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
const code = error.code;
|
|
231
|
+
if (code === 'ENOENT') {
|
|
232
|
+
// expectedMtime '' (the empty-state default) means "create" — only a
|
|
233
|
+
// non-empty expectedMtime against a missing file is a real stale.
|
|
234
|
+
if (expectedMtime !== '') {
|
|
235
|
+
throwMapped(HARNESS_ERRORS.HARNESS_STALE_WRITE.code, 'manifest missing on disk', { currentMtime: '' });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else if (code === HARNESS_ERRORS.HARNESS_STALE_WRITE.code) {
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
else if (code === 'EACCES') {
|
|
242
|
+
throwMapped(HARNESS_ERRORS.HARNESS_FORBIDDEN.code, 'permission denied');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
await fs.mkdir(path.dirname(absolutePath), { recursive: true });
|
|
247
|
+
try {
|
|
248
|
+
await fs.writeFile(absolutePath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
throwMapped(HARNESS_ERRORS.HARNESS_WRITE_ERROR.code, 'failed to write manifest');
|
|
252
|
+
}
|
|
253
|
+
const stat = await fs.stat(absolutePath);
|
|
254
|
+
fileWatcherService.noteLocalWrite(absolutePath);
|
|
255
|
+
return stat.mtime.toISOString();
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Generate the `.mjs` script from the manifest, write it to disk, and
|
|
259
|
+
* register/refresh the SessionStart entry in settings.json.
|
|
260
|
+
*/
|
|
261
|
+
async generate(projectSlug, manifest) {
|
|
262
|
+
const { resolvedRoot: projectRoot, absolutePath: scriptPath } = await resolveContextBuilderScriptPath(projectSlug);
|
|
263
|
+
const scriptText = buildContextBuilderScript(projectRoot, manifest);
|
|
264
|
+
await fs.mkdir(path.dirname(scriptPath), { recursive: true });
|
|
265
|
+
try {
|
|
266
|
+
await fs.writeFile(scriptPath, scriptText, 'utf-8');
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
throwMapped(HARNESS_ERRORS.HARNESS_WRITE_ERROR.code, 'failed to write script');
|
|
270
|
+
}
|
|
271
|
+
fileWatcherService.noteLocalWrite(scriptPath);
|
|
272
|
+
const settingsMtime = await this.registerEntry(projectSlug, projectRoot, scriptPath);
|
|
273
|
+
return { scriptPath, settingsMtime };
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Register (or refresh) the Hammoc-managed SessionStart entry. Updates the
|
|
277
|
+
* managed group in place when present; otherwise appends a new group, leaving
|
|
278
|
+
* any foreign groups untouched (AC1.e).
|
|
279
|
+
*/
|
|
280
|
+
async registerEntry(projectSlug, projectRoot, scriptPath) {
|
|
281
|
+
// Context builder is NOT BMad-gated — `.claude/` may not exist yet on a
|
|
282
|
+
// fresh project. Create it so the settings.json write has a parent dir.
|
|
283
|
+
await fs.mkdir(path.join(projectRoot, '.claude'), { recursive: true });
|
|
284
|
+
const { content, mtime, exists } = await readSettings(projectSlug);
|
|
285
|
+
const command = `node "${normalizeSlashes(scriptPath)}"`;
|
|
286
|
+
const group = { hooks: [{ type: 'command', command }] };
|
|
287
|
+
const groups = parseSessionStartGroups(content);
|
|
288
|
+
const managedIdx = findManagedIndex(groups);
|
|
289
|
+
let patchOp;
|
|
290
|
+
if (managedIdx >= 0) {
|
|
291
|
+
patchOp = { path: ['hooks', 'SessionStart', managedIdx], value: group };
|
|
292
|
+
}
|
|
293
|
+
else if (groups.length === 0) {
|
|
294
|
+
patchOp = { path: ['hooks', 'SessionStart'], value: [group] };
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
patchOp = { path: ['hooks', 'SessionStart', groups.length], value: group };
|
|
298
|
+
}
|
|
299
|
+
const source = content.trim().length === 0 ? '{}' : content;
|
|
300
|
+
const patched = applyJsoncPatch(source, [patchOp]);
|
|
301
|
+
const written = await harnessService.write(settingsRef(projectSlug), {
|
|
302
|
+
content: patched,
|
|
303
|
+
// AC1.e — guard against an external settings.json edit landing between
|
|
304
|
+
// our read and write. Omit on create (file did not exist).
|
|
305
|
+
expectedMtime: exists ? mtime : undefined,
|
|
306
|
+
});
|
|
307
|
+
return written.mtime;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Remove the Hammoc-managed SessionStart entry (preserving foreign groups)
|
|
311
|
+
* and delete the generated script. Returns the new settings.json mtime (or
|
|
312
|
+
* the unchanged/empty value when settings.json does not exist).
|
|
313
|
+
*/
|
|
314
|
+
async removeEntryAndScript(projectSlug) {
|
|
315
|
+
// Delete the generated script (idempotent).
|
|
316
|
+
const { absolutePath: scriptPath } = await resolveContextBuilderScriptPath(projectSlug);
|
|
317
|
+
try {
|
|
318
|
+
await fs.unlink(scriptPath);
|
|
319
|
+
fileWatcherService.noteLocalWrite(scriptPath);
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
// already gone — fine.
|
|
323
|
+
}
|
|
324
|
+
const { content, mtime, exists } = await readSettings(projectSlug);
|
|
325
|
+
if (!exists)
|
|
326
|
+
return '';
|
|
327
|
+
const groups = parseSessionStartGroups(content);
|
|
328
|
+
const managedIdx = findManagedIndex(groups);
|
|
329
|
+
if (managedIdx < 0)
|
|
330
|
+
return mtime; // nothing to remove.
|
|
331
|
+
// Remove the managed group; if it was the only group, drop the SessionStart
|
|
332
|
+
// key entirely so we don't leave an empty array behind.
|
|
333
|
+
const ops = groups.length === 1
|
|
334
|
+
? [{ path: ['hooks', 'SessionStart'], value: undefined }]
|
|
335
|
+
: [{ path: ['hooks', 'SessionStart', managedIdx], value: undefined }];
|
|
336
|
+
const patched = applyJsoncPatch(content, ops);
|
|
337
|
+
const written = await harnessService.write(settingsRef(projectSlug), {
|
|
338
|
+
content: patched,
|
|
339
|
+
expectedMtime: mtime,
|
|
340
|
+
});
|
|
341
|
+
return written.mtime;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
export const contextBuilderService = new ContextBuilderService();
|
|
345
|
+
//# sourceMappingURL=contextBuilderService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextBuilderService.js","sourceRoot":"","sources":["../../src/services/contextBuilderService.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,9 +11,20 @@
|
|
|
11
11
|
* cause an "external change" banner on their own save. Callers must invoke
|
|
12
12
|
* noteLocalWrite(absolutePath) immediately after writing — events for paths
|
|
13
13
|
* noted within the last SELF_WRITE_WINDOW_MS are silently dropped.
|
|
14
|
+
*
|
|
15
|
+
* Story 28.0.5: extended with harness-scope watchers over ~/.claude (user) and
|
|
16
|
+
* <project>/.claude (project). Harness watchers emit `harness:external-change`
|
|
17
|
+
* on dedicated rooms and share the same self-write-suppression map so writes
|
|
18
|
+
* coming out of harnessService do not echo back to the originating client.
|
|
14
19
|
*/
|
|
20
|
+
import type { HarnessScope } from '@hammoc/shared';
|
|
21
|
+
interface HarnessRef {
|
|
22
|
+
scope: HarnessScope;
|
|
23
|
+
projectSlug?: string;
|
|
24
|
+
}
|
|
15
25
|
declare class FileWatcherService {
|
|
16
26
|
private watchers;
|
|
27
|
+
private harnessWatchers;
|
|
17
28
|
/** absolute path → timestamp (ms) of the last local write */
|
|
18
29
|
private pendingLocalWrites;
|
|
19
30
|
/** Events arriving within this window after a local write are treated as our own echo. */
|
|
@@ -25,6 +36,19 @@ declare class FileWatcherService {
|
|
|
25
36
|
ensureWatcher(projectSlug: string, projectRoot: string): void;
|
|
26
37
|
/** Decrement the ref count and close the watcher when it reaches zero. */
|
|
27
38
|
releaseWatcher(projectSlug: string): void;
|
|
39
|
+
/**
|
|
40
|
+
* Start (or increment the ref count of) a harness watcher for the given scope.
|
|
41
|
+
* - `scope='user'` → ~/.claude (via `getUserHarnessRoot()`)
|
|
42
|
+
* - `scope='project'` → <project>/.claude (via `getProjectHarnessRoot()`)
|
|
43
|
+
*
|
|
44
|
+
* Idempotent + reference-counted so concurrent subscribers share one chokidar.
|
|
45
|
+
* Unlike the project watcher, harness watchers subscribe to `add` in addition
|
|
46
|
+
* to `change`/`unlink` so they can fire the `'created'` type required by
|
|
47
|
+
* HarnessExternalChangeEvent.
|
|
48
|
+
*/
|
|
49
|
+
ensureHarnessWatcher(ref: HarnessRef): Promise<void>;
|
|
50
|
+
/** Decrement the harness watcher ref count, closing when it reaches zero. */
|
|
51
|
+
releaseHarnessWatcher(ref: HarnessRef): void;
|
|
28
52
|
/** Mark an absolute path as just-written so the next watcher event is ignored. */
|
|
29
53
|
noteLocalWrite(absolutePath: string): void;
|
|
30
54
|
/** Close every active watcher. Called on server shutdown. */
|