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,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 31.3 (Task A.3 / A.5): token attribution + exact count_tokens proxy.
|
|
3
|
+
*
|
|
4
|
+
* Two responsibilities, sharing one text-resolution path so the "exact count"
|
|
5
|
+
* input and the "approximation" input are always the same bytes (N-1):
|
|
6
|
+
*
|
|
7
|
+
* 1. listTokenAttribution(projectSlug) — enumerate the measured harness
|
|
8
|
+
* elements (project/global CLAUDE.md · each skill's SKILL.md · the
|
|
9
|
+
* Hammoc-managed context-builder injection) and report UTF-8 byte size +
|
|
10
|
+
* `approxTokens = ceil(bytes/4)` + a sha256 content hash (AC-B1 / AC-B2).
|
|
11
|
+
*
|
|
12
|
+
* 2. exactCount(projectSlug, req) — proxy the official `count_tokens` via the
|
|
13
|
+
* already-installed `@anthropic-ai/sdk` `messages.countTokens` (spike #2,
|
|
14
|
+
* §15 — no new dependency), keyed by a server-recomputed content hash
|
|
15
|
+
* (N-B: the request hash is only an optimistic hint). Failures are
|
|
16
|
+
* non-blocking (`failed: true`) so the client keeps the approximation
|
|
17
|
+
* (AC-B3.c).
|
|
18
|
+
*
|
|
19
|
+
* Enumeration REUSES existing controllers/services (claudeMdService,
|
|
20
|
+
* harnessSkillService, contextBuilderService) — no new file scanner (S-2). The
|
|
21
|
+
* context-builder injection is estimated from the Story 31.2 manifest WITHOUT
|
|
22
|
+
* executing the hook (dynamic variable / command values are placeholders).
|
|
23
|
+
*
|
|
24
|
+
* Per spike #1 (§14) the SERVER approximation tier is byte `size/4` only — the
|
|
25
|
+
* `@anthropic-ai/tokenizer` tier was NOT adopted (Task A.4 skipped).
|
|
26
|
+
*/
|
|
27
|
+
import fs from 'node:fs/promises';
|
|
28
|
+
import { readFileSync } from 'node:fs';
|
|
29
|
+
import path from 'node:path';
|
|
30
|
+
import os from 'node:os';
|
|
31
|
+
import { createHash } from 'node:crypto';
|
|
32
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
33
|
+
import { createLogger } from '../utils/logger.js';
|
|
34
|
+
import { claudeMdService } from './claudeMdService.js';
|
|
35
|
+
import { harnessSkillService } from './harnessSkillService.js';
|
|
36
|
+
import { contextBuilderService } from './contextBuilderService.js';
|
|
37
|
+
import { projectService } from './projectService.js';
|
|
38
|
+
const log = createLogger('tokenCountService');
|
|
39
|
+
/**
|
|
40
|
+
* Model passed to count_tokens. The count is tokenizer-family stable across
|
|
41
|
+
* Claude 4.x, so any current model works; overridable via env in case the
|
|
42
|
+
* default is later deprecated. spike #2 verified the call live.
|
|
43
|
+
*/
|
|
44
|
+
const COUNT_TOKENS_MODEL = process.env.OBSERVABILITY_COUNT_TOKENS_MODEL || 'claude-sonnet-4-6';
|
|
45
|
+
function sha256(text) {
|
|
46
|
+
return createHash('sha256').update(text, 'utf8').digest('hex');
|
|
47
|
+
}
|
|
48
|
+
function utf8Bytes(text) {
|
|
49
|
+
return Buffer.byteLength(text, 'utf8');
|
|
50
|
+
}
|
|
51
|
+
/** ceil(bytes / 4) — the size-based heuristic (§14). */
|
|
52
|
+
export function approxTokensFromBytes(bytes) {
|
|
53
|
+
return Math.ceil(Math.max(0, bytes) / 4);
|
|
54
|
+
}
|
|
55
|
+
function samePath(a, b) {
|
|
56
|
+
const na = path.normalize(a);
|
|
57
|
+
const nb = path.normalize(b);
|
|
58
|
+
return process.platform === 'win32' ? na.toLowerCase() === nb.toLowerCase() : na === nb;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Construct an Anthropic client for count_tokens (spike #2). Priority:
|
|
62
|
+
* `ANTHROPIC_API_KEY` → the Claude Code OAuth access token from
|
|
63
|
+
* `~/.claude/.credentials.json` (verified live). Returns null when neither is
|
|
64
|
+
* available — the caller degrades gracefully.
|
|
65
|
+
*/
|
|
66
|
+
function getAnthropicClient() {
|
|
67
|
+
if (process.env.ANTHROPIC_API_KEY)
|
|
68
|
+
return new Anthropic();
|
|
69
|
+
try {
|
|
70
|
+
const credPath = path.join(os.homedir(), '.claude', '.credentials.json');
|
|
71
|
+
const cred = JSON.parse(readFileSync(credPath, 'utf8'));
|
|
72
|
+
const token = cred?.claudeAiOauth?.accessToken;
|
|
73
|
+
if (token)
|
|
74
|
+
return new Anthropic({ authToken: token });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// no credentials — fall through.
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
class TokenCountService {
|
|
82
|
+
/** sha256(text) → token count. In-memory; persisted best-effort to disk. */
|
|
83
|
+
cache = new Map();
|
|
84
|
+
cacheLoaded = false;
|
|
85
|
+
cacheFilePath() {
|
|
86
|
+
return path.join(os.homedir(), '.hammoc', 'observability', 'token-count-cache.json');
|
|
87
|
+
}
|
|
88
|
+
async loadCache() {
|
|
89
|
+
if (this.cacheLoaded)
|
|
90
|
+
return;
|
|
91
|
+
this.cacheLoaded = true;
|
|
92
|
+
try {
|
|
93
|
+
const text = await fs.readFile(this.cacheFilePath(), 'utf8');
|
|
94
|
+
const obj = JSON.parse(text);
|
|
95
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
96
|
+
if (typeof v === 'number')
|
|
97
|
+
this.cache.set(k, v);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// missing/corrupt — start empty.
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async persistCache() {
|
|
105
|
+
try {
|
|
106
|
+
const file = this.cacheFilePath();
|
|
107
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
108
|
+
await fs.writeFile(file, JSON.stringify(Object.fromEntries(this.cache)), 'utf8');
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
log.warn(`token cache persist failed: ${err.message}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Enumerate measured harness elements (AC-B1.a). Missing CLAUDE.md files and a
|
|
116
|
+
* disabled/empty context builder are omitted (they contribute no tokens).
|
|
117
|
+
*/
|
|
118
|
+
async listTokenAttribution(projectSlug) {
|
|
119
|
+
const items = [];
|
|
120
|
+
// project / global CLAUDE.md
|
|
121
|
+
const projectMd = await this.readClaudeMd({ scope: 'project', projectSlug });
|
|
122
|
+
if (projectMd)
|
|
123
|
+
items.push(this.makeItem('claudeMd-project', 'CLAUDE.md (project)', projectMd.text, projectMd.path));
|
|
124
|
+
const globalMd = await this.readClaudeMd({ scope: 'user' });
|
|
125
|
+
if (globalMd)
|
|
126
|
+
items.push(this.makeItem('claudeMd-global', 'CLAUDE.md (global)', globalMd.text, globalMd.path));
|
|
127
|
+
// each skill's SKILL.md (active source only)
|
|
128
|
+
try {
|
|
129
|
+
const { cards } = await harnessSkillService.listCards(projectSlug);
|
|
130
|
+
for (const card of cards) {
|
|
131
|
+
const root = card.sources[0]?.absoluteRoot;
|
|
132
|
+
if (!root)
|
|
133
|
+
continue;
|
|
134
|
+
const skillMd = path.join(root, 'SKILL.md');
|
|
135
|
+
try {
|
|
136
|
+
const text = await fs.readFile(skillMd, 'utf8');
|
|
137
|
+
items.push(this.makeItem('skill', `skill: ${card.name}`, text, skillMd));
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// SKILL.md unreadable — skip this card.
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
log.warn(`skill enumeration failed: ${err.message}`);
|
|
146
|
+
}
|
|
147
|
+
// Hammoc-managed context builder injection (manifest-assembled, no execution)
|
|
148
|
+
const cbText = await this.assembleContextBuilderText(projectSlug);
|
|
149
|
+
if (cbText)
|
|
150
|
+
items.push(this.makeItem('contextBuilder', 'Context builder injection', cbText));
|
|
151
|
+
return items;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Exact count for one element (AC-B3). The text is re-resolved server-side and
|
|
155
|
+
* its sha256 is the AUTHORITATIVE cache key (N-B) — the request `contentHash`
|
|
156
|
+
* is only an optimistic hint. count_tokens failures return `failed: true`.
|
|
157
|
+
*/
|
|
158
|
+
async exactCount(projectSlug, req) {
|
|
159
|
+
const text = await this.resolveElementText(projectSlug, req.kind, req.path);
|
|
160
|
+
if (text == null)
|
|
161
|
+
return { tokens: 0, cached: false, failed: true };
|
|
162
|
+
const key = sha256(text);
|
|
163
|
+
await this.loadCache();
|
|
164
|
+
const hit = this.cache.get(key);
|
|
165
|
+
if (hit !== undefined)
|
|
166
|
+
return { tokens: hit, cached: true };
|
|
167
|
+
const tokens = await this.callCountTokens(text);
|
|
168
|
+
if (tokens == null)
|
|
169
|
+
return { tokens: 0, cached: false, failed: true };
|
|
170
|
+
this.cache.set(key, tokens);
|
|
171
|
+
void this.persistCache();
|
|
172
|
+
return { tokens, cached: false };
|
|
173
|
+
}
|
|
174
|
+
// -------------------------------------------------------------------------
|
|
175
|
+
// internals
|
|
176
|
+
// -------------------------------------------------------------------------
|
|
177
|
+
makeItem(kind, label, text, filePath) {
|
|
178
|
+
const bytes = utf8Bytes(text);
|
|
179
|
+
return {
|
|
180
|
+
kind,
|
|
181
|
+
label,
|
|
182
|
+
...(filePath ? { path: filePath } : {}),
|
|
183
|
+
bytes,
|
|
184
|
+
approxTokens: approxTokensFromBytes(bytes),
|
|
185
|
+
contentHash: sha256(text),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/** Resolve the text used for BOTH attribution and exact-count (N-1). */
|
|
189
|
+
async resolveElementText(projectSlug, kind, elementPath) {
|
|
190
|
+
switch (kind) {
|
|
191
|
+
case 'claudeMd-project':
|
|
192
|
+
return (await this.readClaudeMd({ scope: 'project', projectSlug }))?.text ?? null;
|
|
193
|
+
case 'claudeMd-global':
|
|
194
|
+
return (await this.readClaudeMd({ scope: 'user' }))?.text ?? null;
|
|
195
|
+
case 'contextBuilder': {
|
|
196
|
+
const t = await this.assembleContextBuilderText(projectSlug);
|
|
197
|
+
return t || null;
|
|
198
|
+
}
|
|
199
|
+
case 'skill':
|
|
200
|
+
return this.readSkillTextByPath(projectSlug, elementPath);
|
|
201
|
+
default:
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async readClaudeMd(ref) {
|
|
206
|
+
try {
|
|
207
|
+
const res = await claudeMdService.read(ref);
|
|
208
|
+
return { text: res.content ?? '', path: res.absolutePath ?? 'CLAUDE.md' };
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return null; // missing / not-a-file → omit.
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Read a skill's SKILL.md, validating `elementPath` against the enumerated
|
|
216
|
+
* skills so an arbitrary client path can never be read (the path must be one
|
|
217
|
+
* the server itself vouched for in listTokenAttribution).
|
|
218
|
+
*/
|
|
219
|
+
async readSkillTextByPath(projectSlug, elementPath) {
|
|
220
|
+
if (!elementPath)
|
|
221
|
+
return null;
|
|
222
|
+
try {
|
|
223
|
+
const { cards } = await harnessSkillService.listCards(projectSlug);
|
|
224
|
+
for (const card of cards) {
|
|
225
|
+
const root = card.sources[0]?.absoluteRoot;
|
|
226
|
+
if (!root)
|
|
227
|
+
continue;
|
|
228
|
+
const skillMd = path.join(root, 'SKILL.md');
|
|
229
|
+
if (samePath(skillMd, elementPath)) {
|
|
230
|
+
return await fs.readFile(skillMd, 'utf8');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// fall through.
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Assemble the context-builder `additionalContext` text WITHOUT executing the
|
|
241
|
+
* hook (N-1). Reference files are read (their content dominates the size);
|
|
242
|
+
* dynamic variables / acknowledged commands contribute only their block
|
|
243
|
+
* headers with a `(dynamic)` placeholder. Mirrors the block format of
|
|
244
|
+
* `contextBuilderScriptTemplate` for the statically-knowable parts. Returns ''
|
|
245
|
+
* when the builder is disabled or empty.
|
|
246
|
+
*/
|
|
247
|
+
async assembleContextBuilderText(projectSlug) {
|
|
248
|
+
let manifest;
|
|
249
|
+
try {
|
|
250
|
+
({ manifest } = await contextBuilderService.readManifest(projectSlug));
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
return '';
|
|
254
|
+
}
|
|
255
|
+
if (!manifest.enabled)
|
|
256
|
+
return '';
|
|
257
|
+
let projectRoot;
|
|
258
|
+
try {
|
|
259
|
+
projectRoot = await projectService.resolveOriginalPath(projectSlug);
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
return '';
|
|
263
|
+
}
|
|
264
|
+
const blocks = [];
|
|
265
|
+
for (const rel of manifest.files) {
|
|
266
|
+
const abs = path.resolve(projectRoot, rel);
|
|
267
|
+
try {
|
|
268
|
+
const content = await fs.readFile(abs, 'utf8');
|
|
269
|
+
blocks.push(`## Reference file: ${rel}\n\n${content}`);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
blocks.push(`## Reference file: ${rel}\n\n(파일을 찾을 수 없음: ${rel})`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Dynamic variable headers (values are computed at hook runtime — placeholder here).
|
|
276
|
+
if (manifest.variables.gitBranch)
|
|
277
|
+
blocks.push('## Current git branch\n\n(dynamic)');
|
|
278
|
+
if (manifest.variables.recentCommits) {
|
|
279
|
+
blocks.push(`## Recent ${manifest.recentCommitsCount ?? 5} commit(s)\n\n(dynamic)`);
|
|
280
|
+
}
|
|
281
|
+
if (manifest.variables.uncommittedCount)
|
|
282
|
+
blocks.push('## Uncommitted file count\n\n(dynamic)');
|
|
283
|
+
if (manifest.variables.today)
|
|
284
|
+
blocks.push('## Today\n\n(dynamic)');
|
|
285
|
+
if (manifest.variables.activeBmadStory)
|
|
286
|
+
blocks.push('## Active BMad story\n\n(dynamic)');
|
|
287
|
+
for (const cc of manifest.customCommands) {
|
|
288
|
+
if (cc.acknowledged)
|
|
289
|
+
blocks.push(`## Command: ${cc.command}\n\n(dynamic)`);
|
|
290
|
+
}
|
|
291
|
+
return blocks.join('\n\n');
|
|
292
|
+
}
|
|
293
|
+
async callCountTokens(text) {
|
|
294
|
+
const client = getAnthropicClient();
|
|
295
|
+
if (!client) {
|
|
296
|
+
log.warn('count_tokens unavailable — no ANTHROPIC_API_KEY and no OAuth credentials');
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
try {
|
|
300
|
+
const res = await client.messages.countTokens({
|
|
301
|
+
model: COUNT_TOKENS_MODEL,
|
|
302
|
+
messages: [{ role: 'user', content: text }],
|
|
303
|
+
});
|
|
304
|
+
return res.input_tokens;
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
log.warn(`count_tokens failed: ${err.message}`);
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
export const tokenCountService = new TokenCountService();
|
|
313
|
+
//# sourceMappingURL=tokenCountService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenCountService.js","sourceRoot":"","sources":["../../src/services/tokenCountService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 28.5: YAML frontmatter round-trip helper.
|
|
3
|
+
*
|
|
4
|
+
* Slash command files (`.claude/commands/**\/*.md`) are markdown documents with
|
|
5
|
+
* an optional `--- ... ---` YAML frontmatter block at the top. To preserve
|
|
6
|
+
* comments / key order / blank lines inside the frontmatter while leaving the
|
|
7
|
+
* markdown body byte-for-byte intact, we round-trip just the frontmatter slice
|
|
8
|
+
* via `yaml`(eemeli) `parseDocument`.
|
|
9
|
+
*
|
|
10
|
+
* Behaviour:
|
|
11
|
+
* - File has no frontmatter + patch is empty (all keys absent) → return source
|
|
12
|
+
* unchanged.
|
|
13
|
+
* - File has no frontmatter + patch contains keys → prepend a
|
|
14
|
+
* fresh `--- ... ---` block.
|
|
15
|
+
* - File has frontmatter + patch is empty → strip the
|
|
16
|
+
* block entirely (matches AC3.a "all four fields absent ⇒ no frontmatter").
|
|
17
|
+
* - File has frontmatter + patch sets keys → mutate keys
|
|
18
|
+
* in place, preserving comments / order / blank lines for untouched keys.
|
|
19
|
+
*
|
|
20
|
+
* The body region (everything after the closing `---`) is taken from the source
|
|
21
|
+
* via raw substring slicing so byte-level equality holds — this is asserted by
|
|
22
|
+
* the unit tests with `result.slice(boundary) === source.slice(boundary)`.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Apply key-level patches to the YAML frontmatter block of a markdown file.
|
|
26
|
+
* Body markdown is preserved byte-for-byte. Pass `undefined` to delete a key.
|
|
27
|
+
*
|
|
28
|
+
* - When the resulting frontmatter has no keys left, the entire `--- ... ---`
|
|
29
|
+
* block (including the closing newline) is stripped.
|
|
30
|
+
* - When the source has no frontmatter and `newFrontmatter` carries at least
|
|
31
|
+
* one defined value, a `--- ... ---` block is prepended with a single
|
|
32
|
+
* trailing newline before the body.
|
|
33
|
+
*
|
|
34
|
+
* @throws HARNESS_PARSE_ERROR when the existing frontmatter is malformed YAML.
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyYamlFrontmatterPatch(source: string, newFrontmatter: Record<string, unknown>): string;
|
|
37
|
+
/**
|
|
38
|
+
* Strip the `--- ... ---` block (if any) and return the remaining body.
|
|
39
|
+
* Convenience helper — used by the service to surface the body separately
|
|
40
|
+
* from frontmatter on the read path.
|
|
41
|
+
*/
|
|
42
|
+
export declare function splitFrontmatterAndBody(source: string): {
|
|
43
|
+
frontmatterRaw: string | null;
|
|
44
|
+
body: string;
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=applyYamlFrontmatterPatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyYamlFrontmatterPatch.d.ts","sourceRoot":"","sources":["../../../src/services/utils/applyYamlFrontmatterPatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAuCH;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACtC,MAAM,CAuDR;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG;IACvD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;CACd,CAIA"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 28.5: YAML frontmatter round-trip helper.
|
|
3
|
+
*
|
|
4
|
+
* Slash command files (`.claude/commands/**\/*.md`) are markdown documents with
|
|
5
|
+
* an optional `--- ... ---` YAML frontmatter block at the top. To preserve
|
|
6
|
+
* comments / key order / blank lines inside the frontmatter while leaving the
|
|
7
|
+
* markdown body byte-for-byte intact, we round-trip just the frontmatter slice
|
|
8
|
+
* via `yaml`(eemeli) `parseDocument`.
|
|
9
|
+
*
|
|
10
|
+
* Behaviour:
|
|
11
|
+
* - File has no frontmatter + patch is empty (all keys absent) → return source
|
|
12
|
+
* unchanged.
|
|
13
|
+
* - File has no frontmatter + patch contains keys → prepend a
|
|
14
|
+
* fresh `--- ... ---` block.
|
|
15
|
+
* - File has frontmatter + patch is empty → strip the
|
|
16
|
+
* block entirely (matches AC3.a "all four fields absent ⇒ no frontmatter").
|
|
17
|
+
* - File has frontmatter + patch sets keys → mutate keys
|
|
18
|
+
* in place, preserving comments / order / blank lines for untouched keys.
|
|
19
|
+
*
|
|
20
|
+
* The body region (everything after the closing `---`) is taken from the source
|
|
21
|
+
* via raw substring slicing so byte-level equality holds — this is asserted by
|
|
22
|
+
* the unit tests with `result.slice(boundary) === source.slice(boundary)`.
|
|
23
|
+
*/
|
|
24
|
+
import { parseDocument } from 'yaml';
|
|
25
|
+
import { HARNESS_ERRORS } from '@hammoc/shared';
|
|
26
|
+
/** Match a leading `---\n...---\n?` frontmatter block. */
|
|
27
|
+
const FRONTMATTER_RE = /^---\s*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n)?/;
|
|
28
|
+
function findFrontmatter(source) {
|
|
29
|
+
const match = FRONTMATTER_RE.exec(source);
|
|
30
|
+
if (!match)
|
|
31
|
+
return null;
|
|
32
|
+
const eol = source.includes('\r\n') ? '\r\n' : '\n';
|
|
33
|
+
return { inner: match[1], bodyStart: match[0].length, eol };
|
|
34
|
+
}
|
|
35
|
+
function frontmatterIsEmpty(values) {
|
|
36
|
+
for (const v of Object.values(values)) {
|
|
37
|
+
if (v !== undefined)
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
function throwParseError(cause) {
|
|
43
|
+
const err = new Error(`failed to parse frontmatter: ${cause?.message ?? String(cause)}`);
|
|
44
|
+
err.code = HARNESS_ERRORS.HARNESS_PARSE_ERROR.code;
|
|
45
|
+
throw err;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Apply key-level patches to the YAML frontmatter block of a markdown file.
|
|
49
|
+
* Body markdown is preserved byte-for-byte. Pass `undefined` to delete a key.
|
|
50
|
+
*
|
|
51
|
+
* - When the resulting frontmatter has no keys left, the entire `--- ... ---`
|
|
52
|
+
* block (including the closing newline) is stripped.
|
|
53
|
+
* - When the source has no frontmatter and `newFrontmatter` carries at least
|
|
54
|
+
* one defined value, a `--- ... ---` block is prepended with a single
|
|
55
|
+
* trailing newline before the body.
|
|
56
|
+
*
|
|
57
|
+
* @throws HARNESS_PARSE_ERROR when the existing frontmatter is malformed YAML.
|
|
58
|
+
*/
|
|
59
|
+
export function applyYamlFrontmatterPatch(source, newFrontmatter) {
|
|
60
|
+
const slice = findFrontmatter(source);
|
|
61
|
+
const allEmpty = frontmatterIsEmpty(newFrontmatter);
|
|
62
|
+
if (!slice) {
|
|
63
|
+
if (allEmpty)
|
|
64
|
+
return source;
|
|
65
|
+
const eol = source.includes('\r\n') ? '\r\n' : '\n';
|
|
66
|
+
let doc;
|
|
67
|
+
try {
|
|
68
|
+
doc = parseDocument('', { keepSourceTokens: true });
|
|
69
|
+
}
|
|
70
|
+
catch (cause) {
|
|
71
|
+
throwParseError(cause);
|
|
72
|
+
}
|
|
73
|
+
if (doc.contents == null) {
|
|
74
|
+
doc.contents = doc.createNode({});
|
|
75
|
+
}
|
|
76
|
+
for (const [key, value] of Object.entries(newFrontmatter)) {
|
|
77
|
+
if (value === undefined)
|
|
78
|
+
continue;
|
|
79
|
+
doc.setIn([key], value);
|
|
80
|
+
}
|
|
81
|
+
const yamlText = doc.toString().replace(/\r?\n$/, '');
|
|
82
|
+
return `---${eol}${yamlText}${eol}---${eol}${source}`;
|
|
83
|
+
}
|
|
84
|
+
let doc;
|
|
85
|
+
try {
|
|
86
|
+
doc = parseDocument(slice.inner, { keepSourceTokens: true });
|
|
87
|
+
if (doc.errors.length > 0) {
|
|
88
|
+
throw doc.errors[0];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (cause) {
|
|
92
|
+
throwParseError(cause);
|
|
93
|
+
}
|
|
94
|
+
if (doc.contents == null) {
|
|
95
|
+
doc.contents = doc.createNode({});
|
|
96
|
+
}
|
|
97
|
+
for (const [key, value] of Object.entries(newFrontmatter)) {
|
|
98
|
+
if (value === undefined) {
|
|
99
|
+
if (doc.hasIn([key]))
|
|
100
|
+
doc.deleteIn([key]);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
doc.setIn([key], value);
|
|
104
|
+
}
|
|
105
|
+
// If the patched document is empty (no top-level keys left), strip the block.
|
|
106
|
+
const docContents = doc.contents;
|
|
107
|
+
const remainingKeys = docContents?.items?.length ?? 0;
|
|
108
|
+
if (remainingKeys === 0) {
|
|
109
|
+
return source.slice(slice.bodyStart);
|
|
110
|
+
}
|
|
111
|
+
const yamlText = doc.toString().replace(/\r?\n$/, '');
|
|
112
|
+
return `---${slice.eol}${yamlText}${slice.eol}---${slice.eol}${source.slice(slice.bodyStart)}`;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Strip the `--- ... ---` block (if any) and return the remaining body.
|
|
116
|
+
* Convenience helper — used by the service to surface the body separately
|
|
117
|
+
* from frontmatter on the read path.
|
|
118
|
+
*/
|
|
119
|
+
export function splitFrontmatterAndBody(source) {
|
|
120
|
+
const slice = findFrontmatter(source);
|
|
121
|
+
if (!slice)
|
|
122
|
+
return { frontmatterRaw: null, body: source };
|
|
123
|
+
return { frontmatterRaw: slice.inner, body: source.slice(slice.bodyStart) };
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=applyYamlFrontmatterPatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyYamlFrontmatterPatch.js","sourceRoot":"","sources":["../../../src/services/utils/applyYamlFrontmatterPatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,aAAa,EAAiB,MAAM,MAAM,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,0DAA0D;AAC1D,MAAM,cAAc,GAAG,gDAAgD,CAAC;AAWxE,SAAS,eAAe,CAAC,MAAc;IACrC,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,GAAG,GAAkB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACnE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;AAC9D,CAAC;AAED,SAAS,kBAAkB,CAAC,MAA+B;IACzD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,MAAM,GAAG,GAAG,IAAI,KAAK,CACnB,gCAAiC,KAAe,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CACpD,CAAC;IAC3B,GAAG,CAAC,IAAI,GAAG,cAAc,CAAC,mBAAmB,CAAC,IAAI,CAAC;IACnD,MAAM,GAAG,CAAC;AACZ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAc,EACd,cAAuC;IAEvC,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAEpD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,QAAQ;YAAE,OAAO,MAAM,CAAC;QAC5B,MAAM,GAAG,GAAkB,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACnE,IAAI,GAAoB,CAAC;QACzB,IAAI,CAAC;YACH,GAAG,GAAG,aAAa,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,eAAe,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,GAAI,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;YAC1B,GAAI,CAAC,QAAQ,GAAG,GAAI,CAAC,UAAU,CAAC,EAAE,CAAmC,CAAC;QACxE,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAC1D,IAAI,KAAK,KAAK,SAAS;gBAAE,SAAS;YAClC,GAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QAC3B,CAAC;QACD,MAAM,QAAQ,GAAG,GAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACvD,OAAO,MAAM,GAAG,GAAG,QAAQ,GAAG,GAAG,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACxD,CAAC;IAED,IAAI,GAAoB,CAAC;IACzB,IAAI,CAAC;QACH,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,eAAe,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,GAAI,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC1B,GAAI,CAAC,QAAQ,GAAG,GAAI,CAAC,UAAU,CAAC,EAAE,CAAmC,CAAC;IACxE,CAAC;IAED,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QAC1D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,GAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;gBAAE,GAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5C,SAAS;QACX,CAAC;QACD,GAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,8EAA8E;IAC9E,MAAM,WAAW,GAAG,GAAI,CAAC,QAAmD,CAAC;IAC7E,MAAM,aAAa,GAAG,WAAW,EAAE,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC;IACtD,IAAI,aAAa,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,QAAQ,GAAG,GAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACvD,OAAO,MAAM,KAAK,CAAC,GAAG,GAAG,QAAQ,GAAG,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;AACjG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAc;IAIpD,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1D,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;AAC9E,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
/BMad:agents:dev
|
|
2
|
-
---
|
|
3
|
-
*review-qa {arg1}
|
|
4
|
-
|
|
5
|
-
After
|
|
1
|
+
/BMad:agents:dev
|
|
2
|
+
---
|
|
3
|
+
*review-qa {arg1}
|
|
4
|
+
|
|
5
|
+
After the fixes are applied and you update the story's Dev Agent Record, record which QA gate you addressed so Hammoc can track it. Read the `updated:` value from this story's QA gate YAML, then append this exact line inside the Completion Notes — replace the placeholder with that value. Do NOT change Status and do NOT edit the gate file:
|
|
6
|
+
<!-- hammoc:qa-fix gate="<paste the gate's updated value>" applied="true" -->
|
|
7
|
+
This flips the story from "apply QA fixes" to "request QA re-review" in Hammoc.
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
/BMad:agents:qa
|
|
2
2
|
---
|
|
3
|
-
*review {arg1}
|
|
3
|
+
*review {arg1}
|
|
4
|
+
|
|
5
|
+
When you write the quality gate, if the gate decision is CONCERNS or FAIL, also record it in the story so Hammoc tracks that a fix is pending. Append this exact line inside the story's QA Results section, replacing the placeholder with the gate's `updated:` value you just wrote:
|
|
6
|
+
<!-- hammoc:qa-fix gate="<paste the gate's updated value>" applied="false" -->
|
|
7
|
+
For a PASS or WAIVED gate, do not add this marker.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Review the current working tree with `git status` and `git diff` (both staged and unstaged). Group the changes into logically coherent units so that each commit represents a single concern (one feature, one fix, one refactor, etc.). For each group:
|
|
2
|
+
|
|
3
|
+
1. Stage only the files (or hunks, via `git add -p`, when a single file mixes concerns) that belong to the group.
|
|
4
|
+
2. Commit with a clear conventional-commit style message that explains *why* the change exists, not just *what* changed.
|
|
5
|
+
3. Move on to the next group.
|
|
6
|
+
|
|
7
|
+
Do not push. Do not amend existing commits. If the changes are already coherent as a single commit, say so and make one commit instead of forcing a split.
|
|
8
|
+
|
|
9
|
+
When you finish, list the resulting commits (hash + subject line) as a summary.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Story 30.3 (Task 2.2): apply the three `secretsPolicy` modes to a payload
|
|
3
|
+
* before it is written into the bundle.
|
|
4
|
+
*
|
|
5
|
+
* Two operating shapes, mirroring `detectSecretsInValue` / `detectSecretsInText`:
|
|
6
|
+
*
|
|
7
|
+
* 1. `applyPolicyToValue` walks a JSON-like value (mcp config, settings.json
|
|
8
|
+
* hooks block). For `excluded` the matched leaf is deleted from its
|
|
9
|
+
* parent; for `placeholder` it is rewritten as `${ENV_REF_NAME}` using
|
|
10
|
+
* `secretPlaceholderNamer`; for `included-explicit` the value is left
|
|
11
|
+
* untouched.
|
|
12
|
+
*
|
|
13
|
+
* 2. `applyPolicyToText` walks line-oriented text (CLAUDE.md, agent body,
|
|
14
|
+
* command body). For `excluded` the offending line is replaced with the
|
|
15
|
+
* sentinel `<< SECRET REMOVED >>` so line numbers stay stable; for
|
|
16
|
+
* `placeholder` every secret substring on that line is rewritten as
|
|
17
|
+
* `${ENV_REF_NAME}`; for `included-explicit` the text is unchanged.
|
|
18
|
+
*
|
|
19
|
+
* Both return per-call counters that the caller aggregates into the
|
|
20
|
+
* `ImportApplySummary` (well, the export equivalent — same idea: surface to
|
|
21
|
+
* the user how many secrets were affected).
|
|
22
|
+
*/
|
|
23
|
+
import type { BundleItemDomain, SecretsPolicy } from '@hammoc/shared';
|
|
24
|
+
export declare const SECRET_REMOVED_TEXT_PLACEHOLDER = "<< SECRET REMOVED >>";
|
|
25
|
+
export interface ApplyPolicyValueInput {
|
|
26
|
+
policy: SecretsPolicy;
|
|
27
|
+
domain: BundleItemDomain;
|
|
28
|
+
cardName: string;
|
|
29
|
+
hookEvent?: string;
|
|
30
|
+
/** Root-relative path prefix for matched dot-paths (e.g. `mcpServers.context7`). */
|
|
31
|
+
pathPrefix?: string[];
|
|
32
|
+
value: unknown;
|
|
33
|
+
}
|
|
34
|
+
export interface ApplyPolicyValueResult {
|
|
35
|
+
value: unknown;
|
|
36
|
+
removedCount: number;
|
|
37
|
+
replacedCount: number;
|
|
38
|
+
}
|
|
39
|
+
export interface ApplyPolicyTextInput {
|
|
40
|
+
policy: SecretsPolicy;
|
|
41
|
+
domain: BundleItemDomain;
|
|
42
|
+
cardName: string;
|
|
43
|
+
hookEvent?: string;
|
|
44
|
+
text: string;
|
|
45
|
+
}
|
|
46
|
+
export interface ApplyPolicyTextResult {
|
|
47
|
+
text: string;
|
|
48
|
+
removedCount: number;
|
|
49
|
+
replacedCount: number;
|
|
50
|
+
}
|
|
51
|
+
export declare function applyPolicyToText(input: ApplyPolicyTextInput): ApplyPolicyTextResult;
|
|
52
|
+
export declare function applyPolicyToValue(input: ApplyPolicyValueInput): ApplyPolicyValueResult;
|
|
53
|
+
//# sourceMappingURL=applySecretsPolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applySecretsPolicy.d.ts","sourceRoot":"","sources":["../../src/utils/applySecretsPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEtE,eAAO,MAAM,+BAA+B,yBAAyB,CAAC;AAEtE,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,gBAAgB,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;CACvB;AAwFD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,GAAG,qBAAqB,CAsCpF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CA4DvF"}
|