hammoc 1.5.0 → 1.7.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 +12 -4
- package/package.json +2 -2
- package/packages/client/dist/assets/{agentExampleHighlight-BgwTm15v.js → agentExampleHighlight-7Olvqdpf.js} +1 -1
- package/packages/client/dist/assets/{commandTokenHighlight-BljHwnrK.js → commandTokenHighlight-DtKwh4lx.js} +1 -1
- package/packages/client/dist/assets/index-B09doO8H.js +139 -0
- package/packages/client/dist/assets/index-Bee52CKG.js +1569 -0
- package/packages/client/dist/assets/index-CVy582lU.css +32 -0
- package/packages/client/dist/assets/{index-D3LxqW3f.js → index-DLHBUw8c.js} +1 -1
- package/packages/client/dist/assets/{snippetTokenHighlight-DWsaQXX0.js → snippetTokenHighlight-C8O688f4.js} +1 -1
- package/packages/client/dist/index.html +2 -2
- package/packages/client/dist/sw.js +2 -2
- package/packages/server/dist/_dbg_agent_rows.d.ts +2 -0
- package/packages/server/dist/_dbg_agent_rows.d.ts.map +1 -0
- package/packages/server/dist/_dbg_agent_rows.js +60 -0
- package/packages/server/dist/_dbg_agent_rows.js.map +1 -0
- package/packages/server/dist/_dbg_flicker.d.ts +2 -0
- package/packages/server/dist/_dbg_flicker.d.ts.map +1 -0
- package/packages/server/dist/_dbg_flicker.js +38 -0
- package/packages/server/dist/_dbg_flicker.js.map +1 -0
- package/packages/server/dist/_harness_cli.d.ts +2 -0
- package/packages/server/dist/_harness_cli.d.ts.map +1 -0
- package/packages/server/dist/_harness_cli.js +81 -0
- package/packages/server/dist/_harness_cli.js.map +1 -0
- package/packages/server/dist/_harness_provcard.d.ts +2 -0
- package/packages/server/dist/_harness_provcard.d.ts.map +1 -0
- package/packages/server/dist/_harness_provcard.js +67 -0
- package/packages/server/dist/_harness_provcard.js.map +1 -0
- package/packages/server/dist/_replay_dump.d.ts +2 -0
- package/packages/server/dist/_replay_dump.d.ts.map +1 -0
- package/packages/server/dist/_replay_dump.js +62 -0
- package/packages/server/dist/_replay_dump.js.map +1 -0
- package/packages/server/dist/app.d.ts.map +1 -1
- package/packages/server/dist/app.js +6 -0
- package/packages/server/dist/app.js.map +1 -1
- package/packages/server/dist/config/index.d.ts.map +1 -1
- package/packages/server/dist/config/index.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/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 +7 -0
- package/packages/server/dist/controllers/harnessAgentController.d.ts.map +1 -1
- package/packages/server/dist/controllers/harnessAgentController.js +33 -0
- package/packages/server/dist/controllers/harnessAgentController.js.map +1 -1
- 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 +7 -0
- package/packages/server/dist/controllers/harnessCommandController.d.ts.map +1 -1
- package/packages/server/dist/controllers/harnessCommandController.js +33 -0
- package/packages/server/dist/controllers/harnessCommandController.js.map +1 -1
- package/packages/server/dist/controllers/harnessHookController.d.ts.map +1 -1
- package/packages/server/dist/controllers/harnessHookController.js +44 -1
- package/packages/server/dist/controllers/harnessHookController.js.map +1 -1
- package/packages/server/dist/controllers/harnessMcpController.d.ts.map +1 -1
- package/packages/server/dist/controllers/harnessMcpController.js +62 -1
- package/packages/server/dist/controllers/harnessMcpController.js.map +1 -1
- package/packages/server/dist/controllers/harnessShareScopeController.d.ts +9 -0
- package/packages/server/dist/controllers/harnessShareScopeController.d.ts.map +1 -1
- package/packages/server/dist/controllers/harnessShareScopeController.js +48 -1
- package/packages/server/dist/controllers/harnessShareScopeController.js.map +1 -1
- 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 +7 -1
- package/packages/server/dist/controllers/projectController.js.map +1 -1
- package/packages/server/dist/controllers/sessionController.d.ts.map +1 -1
- package/packages/server/dist/controllers/sessionController.js +16 -4
- package/packages/server/dist/controllers/sessionController.js.map +1 -1
- package/packages/server/dist/controllers/systemBrowseController.d.ts +33 -0
- package/packages/server/dist/controllers/systemBrowseController.d.ts.map +1 -0
- package/packages/server/dist/controllers/systemBrowseController.js +105 -0
- package/packages/server/dist/controllers/systemBrowseController.js.map +1 -0
- package/packages/server/dist/handlers/streamCallbacks.d.ts +10 -0
- package/packages/server/dist/handlers/streamCallbacks.d.ts.map +1 -1
- package/packages/server/dist/handlers/streamCallbacks.js +25 -4
- package/packages/server/dist/handlers/streamCallbacks.js.map +1 -1
- package/packages/server/dist/handlers/websocket.d.ts +43 -3
- package/packages/server/dist/handlers/websocket.d.ts.map +1 -1
- package/packages/server/dist/handlers/websocket.js +385 -93
- package/packages/server/dist/handlers/websocket.js.map +1 -1
- package/packages/server/dist/index.js +2 -0
- package/packages/server/dist/index.js.map +1 -1
- package/packages/server/dist/locales/en/server.json +17 -0
- package/packages/server/dist/locales/es/server.json +17 -0
- package/packages/server/dist/locales/ja/server.json +17 -0
- package/packages/server/dist/locales/ko/server.json +17 -0
- package/packages/server/dist/locales/pt/server.json +17 -0
- package/packages/server/dist/locales/zh-CN/server.json +17 -0
- package/packages/server/dist/routes/harness.d.ts.map +1 -1
- package/packages/server/dist/routes/harness.js +58 -0
- package/packages/server/dist/routes/harness.js.map +1 -1
- package/packages/server/dist/routes/preferences.d.ts.map +1 -1
- package/packages/server/dist/routes/preferences.js +12 -2
- package/packages/server/dist/routes/preferences.js.map +1 -1
- package/packages/server/dist/routes/systemBrowse.d.ts +17 -0
- package/packages/server/dist/routes/systemBrowse.d.ts.map +1 -0
- package/packages/server/dist/routes/systemBrowse.js +22 -0
- package/packages/server/dist/routes/systemBrowse.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 +9 -0
- package/packages/server/dist/services/bmadStatusService.d.ts.map +1 -1
- package/packages/server/dist/services/bmadStatusService.js +77 -13
- package/packages/server/dist/services/bmadStatusService.js.map +1 -1
- package/packages/server/dist/services/chatEngine.d.ts +81 -0
- package/packages/server/dist/services/chatEngine.d.ts.map +1 -0
- package/packages/server/dist/services/chatEngine.js +2 -0
- package/packages/server/dist/services/chatEngine.js.map +1 -0
- package/packages/server/dist/services/chatEngineFactory.d.ts +15 -0
- package/packages/server/dist/services/chatEngineFactory.d.ts.map +1 -0
- package/packages/server/dist/services/chatEngineFactory.js +28 -0
- package/packages/server/dist/services/chatEngineFactory.js.map +1 -0
- package/packages/server/dist/services/chatService.d.ts +34 -26
- package/packages/server/dist/services/chatService.d.ts.map +1 -1
- package/packages/server/dist/services/chatService.js +44 -104
- package/packages/server/dist/services/chatService.js.map +1 -1
- package/packages/server/dist/services/cliChatEngine.d.ts +198 -0
- package/packages/server/dist/services/cliChatEngine.d.ts.map +1 -0
- package/packages/server/dist/services/cliChatEngine.js +2977 -0
- package/packages/server/dist/services/cliChatEngine.js.map +1 -0
- package/packages/server/dist/services/cliGridCards.d.ts +87 -0
- package/packages/server/dist/services/cliGridCards.d.ts.map +1 -0
- package/packages/server/dist/services/cliGridCards.js +298 -0
- package/packages/server/dist/services/cliGridCards.js.map +1 -0
- package/packages/server/dist/services/cliGridRegion.d.ts +44 -0
- package/packages/server/dist/services/cliGridRegion.d.ts.map +1 -0
- package/packages/server/dist/services/cliGridRegion.js +94 -0
- package/packages/server/dist/services/cliGridRegion.js.map +1 -0
- package/packages/server/dist/services/cliModalDetect.d.ts +299 -0
- package/packages/server/dist/services/cliModalDetect.d.ts.map +1 -0
- package/packages/server/dist/services/cliModalDetect.js +583 -0
- package/packages/server/dist/services/cliModalDetect.js.map +1 -0
- package/packages/server/dist/services/cliScreenCache.d.ts +33 -0
- package/packages/server/dist/services/cliScreenCache.d.ts.map +1 -0
- package/packages/server/dist/services/cliScreenCache.js +48 -0
- package/packages/server/dist/services/cliScreenCache.js.map +1 -0
- package/packages/server/dist/services/cliScreenModel.d.ts +141 -0
- package/packages/server/dist/services/cliScreenModel.d.ts.map +1 -0
- package/packages/server/dist/services/cliScreenModel.js +196 -0
- package/packages/server/dist/services/cliScreenModel.js.map +1 -0
- package/packages/server/dist/services/cliScreenStallWatchdog.d.ts +41 -0
- package/packages/server/dist/services/cliScreenStallWatchdog.d.ts.map +1 -0
- package/packages/server/dist/services/cliScreenStallWatchdog.js +45 -0
- package/packages/server/dist/services/cliScreenStallWatchdog.js.map +1 -0
- package/packages/server/dist/services/cliSessionPool.d.ts +97 -0
- package/packages/server/dist/services/cliSessionPool.d.ts.map +1 -0
- package/packages/server/dist/services/cliSessionPool.js +278 -0
- package/packages/server/dist/services/cliSessionPool.js.map +1 -0
- package/packages/server/dist/services/cliSpinnerProgress.d.ts +41 -0
- package/packages/server/dist/services/cliSpinnerProgress.d.ts.map +1 -0
- package/packages/server/dist/services/cliSpinnerProgress.js +131 -0
- package/packages/server/dist/services/cliSpinnerProgress.js.map +1 -0
- 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/fileRewind.d.ts +46 -0
- package/packages/server/dist/services/fileRewind.d.ts.map +1 -0
- package/packages/server/dist/services/fileRewind.js +77 -0
- package/packages/server/dist/services/fileRewind.js.map +1 -0
- package/packages/server/dist/services/fileWatcherService.d.ts.map +1 -1
- package/packages/server/dist/services/fileWatcherService.js +40 -0
- package/packages/server/dist/services/fileWatcherService.js.map +1 -1
- package/packages/server/dist/services/harnessAgentService.d.ts +18 -0
- package/packages/server/dist/services/harnessAgentService.d.ts.map +1 -1
- package/packages/server/dist/services/harnessAgentService.js +55 -0
- package/packages/server/dist/services/harnessAgentService.js.map +1 -1
- 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 +21 -0
- package/packages/server/dist/services/harnessCommandService.d.ts.map +1 -1
- package/packages/server/dist/services/harnessCommandService.js +64 -0
- package/packages/server/dist/services/harnessCommandService.js.map +1 -1
- package/packages/server/dist/services/harnessHookService.d.ts +27 -0
- package/packages/server/dist/services/harnessHookService.d.ts.map +1 -1
- package/packages/server/dist/services/harnessHookService.js +52 -0
- package/packages/server/dist/services/harnessHookService.js.map +1 -1
- package/packages/server/dist/services/harnessMcpService.d.ts +24 -1
- package/packages/server/dist/services/harnessMcpService.d.ts.map +1 -1
- package/packages/server/dist/services/harnessMcpService.js +70 -0
- package/packages/server/dist/services/harnessMcpService.js.map +1 -1
- package/packages/server/dist/services/harnessShareScopeService.d.ts +19 -0
- package/packages/server/dist/services/harnessShareScopeService.d.ts.map +1 -1
- package/packages/server/dist/services/harnessShareScopeService.js +65 -0
- package/packages/server/dist/services/harnessShareScopeService.js.map +1 -1
- package/packages/server/dist/services/historyParser.d.ts +11 -0
- package/packages/server/dist/services/historyParser.d.ts.map +1 -1
- package/packages/server/dist/services/historyParser.js +10 -8
- package/packages/server/dist/services/historyParser.js.map +1 -1
- package/packages/server/dist/services/imageStorageService.d.ts +12 -0
- package/packages/server/dist/services/imageStorageService.d.ts.map +1 -1
- package/packages/server/dist/services/imageStorageService.js +22 -0
- package/packages/server/dist/services/imageStorageService.js.map +1 -1
- package/packages/server/dist/services/issueService.d.ts.map +1 -1
- package/packages/server/dist/services/issueService.js +1 -0
- package/packages/server/dist/services/issueService.js.map +1 -1
- 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/projectService.d.ts +13 -1
- package/packages/server/dist/services/projectService.d.ts.map +1 -1
- package/packages/server/dist/services/projectService.js +32 -0
- package/packages/server/dist/services/projectService.js.map +1 -1
- package/packages/server/dist/services/queueService.d.ts.map +1 -1
- package/packages/server/dist/services/queueService.js +12 -3
- package/packages/server/dist/services/queueService.js.map +1 -1
- package/packages/server/dist/services/rateLimitProbeService.d.ts +15 -0
- package/packages/server/dist/services/rateLimitProbeService.d.ts.map +1 -1
- package/packages/server/dist/services/rateLimitProbeService.js +48 -19
- package/packages/server/dist/services/rateLimitProbeService.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/streamHandler.d.ts +8 -1
- package/packages/server/dist/services/streamHandler.d.ts.map +1 -1
- package/packages/server/dist/services/streamHandler.js +12 -5
- package/packages/server/dist/services/streamHandler.js.map +1 -1
- package/packages/server/dist/services/systemBrowseService.d.ts +91 -0
- package/packages/server/dist/services/systemBrowseService.d.ts.map +1 -0
- package/packages/server/dist/services/systemBrowseService.js +372 -0
- package/packages/server/dist/services/systemBrowseService.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/workspaceContext.d.ts +24 -0
- package/packages/server/dist/services/workspaceContext.d.ts.map +1 -0
- package/packages/server/dist/services/workspaceContext.js +109 -0
- package/packages/server/dist/services/workspaceContext.js.map +1 -0
- package/packages/server/dist/snippets/apply-qa-fixes +7 -5
- package/packages/server/dist/snippets/qa-review +7 -1
- 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/backgroundBlock.d.ts +29 -0
- package/packages/server/dist/utils/backgroundBlock.d.ts.map +1 -0
- package/packages/server/dist/utils/backgroundBlock.js +33 -0
- package/packages/server/dist/utils/backgroundBlock.js.map +1 -0
- package/packages/server/dist/utils/backgroundTaskTracker.d.ts +20 -0
- package/packages/server/dist/utils/backgroundTaskTracker.d.ts.map +1 -0
- package/packages/server/dist/utils/backgroundTaskTracker.js +40 -0
- package/packages/server/dist/utils/backgroundTaskTracker.js.map +1 -0
- package/packages/server/dist/utils/bundledBinaryModelSupport.d.ts +14 -0
- package/packages/server/dist/utils/bundledBinaryModelSupport.d.ts.map +1 -0
- package/packages/server/dist/utils/bundledBinaryModelSupport.js +112 -0
- package/packages/server/dist/utils/bundledBinaryModelSupport.js.map +1 -0
- package/packages/server/dist/utils/cliDebugLog.d.ts +38 -0
- package/packages/server/dist/utils/cliDebugLog.d.ts.map +1 -0
- package/packages/server/dist/utils/cliDebugLog.js +65 -0
- package/packages/server/dist/utils/cliDebugLog.js.map +1 -0
- package/packages/server/dist/utils/cliEngineUtils.d.ts +35 -0
- package/packages/server/dist/utils/cliEngineUtils.d.ts.map +1 -0
- package/packages/server/dist/utils/cliEngineUtils.js +38 -0
- package/packages/server/dist/utils/cliEngineUtils.js.map +1 -0
- package/packages/server/dist/utils/effortUtils.d.ts +2 -2
- package/packages/server/dist/utils/effortUtils.d.ts.map +1 -1
- package/packages/server/dist/utils/effortUtils.js +7 -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/harnessBundleSchema.d.ts +14 -12
- package/packages/server/dist/utils/harnessBundleSchema.d.ts.map +1 -1
- package/packages/server/dist/utils/harnessBundleSchema.js +11 -1
- package/packages/server/dist/utils/harnessBundleSchema.js.map +1 -1
- package/packages/server/dist/utils/harnessPaths.d.ts +40 -0
- package/packages/server/dist/utils/harnessPaths.d.ts.map +1 -1
- package/packages/server/dist/utils/harnessPaths.js +123 -0
- package/packages/server/dist/utils/harnessPaths.js.map +1 -1
- package/packages/server/dist/utils/trailingThrottle.d.ts +21 -0
- package/packages/server/dist/utils/trailingThrottle.d.ts.map +1 -0
- package/packages/server/dist/utils/trailingThrottle.js +36 -0
- package/packages/server/dist/utils/trailingThrottle.js.map +1 -0
- package/packages/server/package.json +61 -58
- package/packages/server/resources/internals/INDEX.md +3 -1
- package/packages/server/resources/internals/bmad-qa-fix-marker.md +32 -0
- package/packages/server/resources/internals/harness-files.md +22 -0
- package/packages/server/resources/internals/image-storage.md +9 -0
- package/packages/server/resources/internals/observability-storage.md +23 -0
- package/packages/server/resources/manual/02-chat.md +23 -4
- package/packages/server/resources/manual/03-sessions.md +1 -0
- package/packages/server/resources/manual/05-projects.md +15 -2
- package/packages/server/resources/manual/10-project-board.md +4 -3
- package/packages/server/resources/manual/11-bmad-method-integration.md +12 -8
- package/packages/server/resources/manual/12-harness-workbench.md +82 -1
- package/packages/server/resources/manual/13-settings.md +61 -9
- 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 +26 -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/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/harnessBundle.d.ts +35 -0
- package/packages/shared/dist/types/harnessBundle.d.ts.map +1 -1
- 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 +16 -2
- package/packages/shared/dist/types/preferences.d.ts.map +1 -1
- package/packages/shared/dist/types/preferences.js +1 -0
- package/packages/shared/dist/types/preferences.js.map +1 -1
- package/packages/shared/dist/types/project.d.ts +7 -1
- package/packages/shared/dist/types/project.d.ts.map +1 -1
- package/packages/shared/dist/types/project.js.map +1 -1
- package/packages/shared/dist/types/sdk.d.ts +124 -12
- package/packages/shared/dist/types/sdk.d.ts.map +1 -1
- package/packages/shared/dist/types/sdk.js +64 -19
- package/packages/shared/dist/types/sdk.js.map +1 -1
- package/packages/shared/dist/types/streaming.d.ts +2 -2
- package/packages/shared/dist/types/streaming.d.ts.map +1 -1
- package/packages/shared/dist/types/streaming.js.map +1 -1
- package/packages/shared/dist/types/systemBrowse.d.ts +120 -0
- package/packages/shared/dist/types/systemBrowse.d.ts.map +1 -0
- package/packages/shared/dist/types/systemBrowse.js +57 -0
- package/packages/shared/dist/types/systemBrowse.js.map +1 -0
- package/packages/shared/dist/types/websocket.d.ts +38 -0
- package/packages/shared/dist/types/websocket.d.ts.map +1 -1
- package/packages/shared/dist/utils/interruptFiller.d.ts +30 -0
- package/packages/shared/dist/utils/interruptFiller.d.ts.map +1 -0
- package/packages/shared/dist/utils/interruptFiller.js +38 -0
- package/packages/shared/dist/utils/interruptFiller.js.map +1 -0
- package/packages/shared/dist/utils/toolResultContent.d.ts +22 -0
- package/packages/shared/dist/utils/toolResultContent.d.ts.map +1 -0
- package/packages/shared/dist/utils/toolResultContent.js +29 -0
- package/packages/shared/dist/utils/toolResultContent.js.map +1 -0
- package/scripts/run-integration-test.mjs +362 -362
- package/packages/client/dist/assets/index-CjyjnXB8.css +0 -32
- package/packages/client/dist/assets/index-NqJdhlek.js +0 -1498
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Session Pool (Epic 32 — Story 32.4)
|
|
3
|
+
*
|
|
4
|
+
* Owns the PTY processes for the CLI conversation engine (`CliChatEngine`), one
|
|
5
|
+
* per in-flight turn. This pool is **deliberately a separate module singleton
|
|
6
|
+
* from `ptyService`** (the web terminal pool): the dashboard's "active terminals"
|
|
7
|
+
* count is derived from `ptyService`'s session map, so routing CLI-engine PTYs
|
|
8
|
+
* through `ptyService` would pollute that count (Sprint Change Proposal §9.2 #3,
|
|
9
|
+
* spike §9-3). Keeping a distinct instance guarantees the CLI engine's PTYs never
|
|
10
|
+
* leak into the terminal count — isolation by construction.
|
|
11
|
+
*
|
|
12
|
+
* The Windows PATH normalization and binary-discovery patterns are *borrowed*
|
|
13
|
+
* from `ptyService` (which stays unmodified). They are duplicated here on purpose
|
|
14
|
+
* for file independence and isolation — the same convention `chatService.ts` and
|
|
15
|
+
* `streamHandler.ts` already use for `extractContextWindow`.
|
|
16
|
+
*/
|
|
17
|
+
import * as pty from 'node-pty';
|
|
18
|
+
import { randomUUID } from 'crypto';
|
|
19
|
+
import { execSync } from 'child_process';
|
|
20
|
+
import os from 'os';
|
|
21
|
+
import path from 'path';
|
|
22
|
+
import { existsSync, statSync, accessSync, constants as fsConstants } from 'fs';
|
|
23
|
+
import { createLogger } from '../utils/logger.js';
|
|
24
|
+
import { resolveBundledBinaryPath } from '../utils/bundledBinaryModelSupport.js';
|
|
25
|
+
const log = createLogger('cliSessionPool');
|
|
26
|
+
/**
|
|
27
|
+
* "I am running inside claude" environment signals. Stripped before spawning a
|
|
28
|
+
* fresh interactive claude so it starts a clean session rather than trying to
|
|
29
|
+
* attach to the host Hammoc process (spike §2).
|
|
30
|
+
*
|
|
31
|
+
* CHILD_SESSION / SESSION_ID matter when Hammoc itself is launched FROM INSIDE a claude session:
|
|
32
|
+
* the spawned CLI claude would inherit "I am a child session" and then NOT write its own session
|
|
33
|
+
* JSONL transcript — which the engine drains for chat content, so every turn would look empty
|
|
34
|
+
* (verified 2026-06-15: a probe that spawned claude under these inherited vars produced no
|
|
35
|
+
* transcript until they were stripped). Production Hammoc is not nested so it never hits this, but
|
|
36
|
+
* stripping them is the correct defensive posture for in-session launches.
|
|
37
|
+
*/
|
|
38
|
+
const CLAUDE_ENV_SIGNALS = [
|
|
39
|
+
'CLAUDECODE',
|
|
40
|
+
'CLAUDE_CODE_ENTRYPOINT',
|
|
41
|
+
'CLAUDE_CODE_SSE_PORT',
|
|
42
|
+
'CLAUDE_CODE_CHILD_SESSION',
|
|
43
|
+
'CLAUDE_CODE_SESSION_ID',
|
|
44
|
+
];
|
|
45
|
+
class CliSessionPool {
|
|
46
|
+
sessions = new Map();
|
|
47
|
+
// On Windows the server may be started from bash/MINGW with an incomplete PATH.
|
|
48
|
+
// Read the real Windows system PATH once via PowerShell+registry so spawned
|
|
49
|
+
// claude sessions inherit a complete environment regardless of launch shell.
|
|
50
|
+
// (Pattern borrowed from ptyService — kept private here for isolation.)
|
|
51
|
+
windowsSystemPath = (() => {
|
|
52
|
+
if (process.platform !== 'win32')
|
|
53
|
+
return null;
|
|
54
|
+
try {
|
|
55
|
+
const sysRoot = process.env.SystemRoot || 'C:\\Windows';
|
|
56
|
+
const ps = `${sysRoot}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
|
57
|
+
const cmd = `[System.Environment]::GetEnvironmentVariable('Path','Machine')+';'+[System.Environment]::GetEnvironmentVariable('Path','User')`;
|
|
58
|
+
return execSync(`"${ps}" -NoProfile -Command "${cmd}"`, { encoding: 'utf8' }).trim();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
})();
|
|
64
|
+
/**
|
|
65
|
+
* Convert MINGW64 Unix-style PATH entries to Windows format and merge in the
|
|
66
|
+
* real Windows system PATH. (Borrowed verbatim in spirit from ptyService.)
|
|
67
|
+
*/
|
|
68
|
+
normalizePathForWindows(env) {
|
|
69
|
+
if (process.platform !== 'win32')
|
|
70
|
+
return env;
|
|
71
|
+
const pathKeys = Object.keys(env).filter((k) => k.toUpperCase() === 'PATH');
|
|
72
|
+
const parts = pathKeys.map((k) => env[k]).filter(Boolean);
|
|
73
|
+
if (this.windowsSystemPath)
|
|
74
|
+
parts.push(this.windowsSystemPath);
|
|
75
|
+
if (parts.length === 0)
|
|
76
|
+
return env;
|
|
77
|
+
const merged = parts.join(';');
|
|
78
|
+
if (!merged)
|
|
79
|
+
return env;
|
|
80
|
+
const normalized = { ...env };
|
|
81
|
+
for (const k of pathKeys) {
|
|
82
|
+
delete normalized[k];
|
|
83
|
+
}
|
|
84
|
+
const entries = [];
|
|
85
|
+
for (const rawSegment of merged.split(';')) {
|
|
86
|
+
const segment = rawSegment.trim().replace(/^"|"$/g, '');
|
|
87
|
+
if (!segment)
|
|
88
|
+
continue;
|
|
89
|
+
const segParts = segment.split(':');
|
|
90
|
+
let i = 0;
|
|
91
|
+
while (i < segParts.length) {
|
|
92
|
+
const part = segParts[i];
|
|
93
|
+
if (part.length === 1 && /^[a-zA-Z]$/.test(part) && i + 1 < segParts.length && /^[/\\]/.test(segParts[i + 1])) {
|
|
94
|
+
entries.push(`${part}:${segParts[i + 1]}`);
|
|
95
|
+
i += 2;
|
|
96
|
+
}
|
|
97
|
+
else if (part) {
|
|
98
|
+
entries.push(part);
|
|
99
|
+
i++;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
i++;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const windowsEntries = entries.map((p) => {
|
|
107
|
+
const match = p.match(/^\/([a-zA-Z])\/(.*)/);
|
|
108
|
+
if (match) {
|
|
109
|
+
return `${match[1].toUpperCase()}:\\${match[2].replace(/\//g, '\\')}`;
|
|
110
|
+
}
|
|
111
|
+
return p;
|
|
112
|
+
});
|
|
113
|
+
normalized['Path'] = windowsEntries.join(';');
|
|
114
|
+
return normalized;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Build the spawn environment: process.env minus undefined values and minus
|
|
118
|
+
* the "inside claude" signal vars, with Windows PATH normalized.
|
|
119
|
+
*/
|
|
120
|
+
buildEnv() {
|
|
121
|
+
const base = Object.fromEntries(Object.entries(process.env).filter((e) => e[1] != null));
|
|
122
|
+
for (const signal of CLAUDE_ENV_SIGNALS) {
|
|
123
|
+
delete base[signal];
|
|
124
|
+
}
|
|
125
|
+
return this.normalizePathForWindows(base);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Best-effort sanity check for a user-supplied binary override (Story 33.3): exists,
|
|
129
|
+
* is a regular file, and (POSIX only) is executable by this process. Windows has no
|
|
130
|
+
* comparable execute bit, so `.exe`/file existence is sufficient there. Intentionally
|
|
131
|
+
* shallow — no signature / "is this really claude" inspection (out of scope).
|
|
132
|
+
*/
|
|
133
|
+
isValidBinaryOverride(candidate) {
|
|
134
|
+
try {
|
|
135
|
+
if (!statSync(candidate).isFile())
|
|
136
|
+
return false;
|
|
137
|
+
if (process.platform !== 'win32') {
|
|
138
|
+
accessSync(candidate, fsConstants.X_OK);
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolve an executable path for `claude`. PATH lookup can fail in the server's
|
|
148
|
+
* child process (spike §9-5: `where claude` failed; the fallback resolved it),
|
|
149
|
+
* so known install locations are tried first, then a PATH probe with the
|
|
150
|
+
* corrected env, then a bare name as a last resort (pty resolves via env PATH).
|
|
151
|
+
*
|
|
152
|
+
* Story 33.3: when a non-empty `override` is supplied it is checked first and used
|
|
153
|
+
* if valid. An *invalid* override never hard-fails the turn — it logs a warning and
|
|
154
|
+
* falls through to the normal chain (auto-detect is the better UX than blocking CLI
|
|
155
|
+
* mode over a bad path). Empty / undefined skips the override entirely.
|
|
156
|
+
*/
|
|
157
|
+
resolveClaudeBinary(env, override) {
|
|
158
|
+
const trimmedOverride = override?.trim();
|
|
159
|
+
if (trimmedOverride) {
|
|
160
|
+
if (this.isValidBinaryOverride(trimmedOverride))
|
|
161
|
+
return trimmedOverride;
|
|
162
|
+
log.warn(`Configured claude binary path is invalid (missing / not a file / not executable): "${trimmedOverride}" — falling back to auto-detect.`);
|
|
163
|
+
}
|
|
164
|
+
// Prefer the bundled engine binary shipped inside @anthropic-ai/claude-agent-sdk: it is the
|
|
165
|
+
// SAME Claude Code CLI as a system install (interactive by default) but version-pinned by
|
|
166
|
+
// Hammoc's package.json, so CLI mode and SDK mode run the identical engine — both recognize
|
|
167
|
+
// newly-released models (e.g. Fable 5). Auth/session are unaffected: the spawn inherits the
|
|
168
|
+
// same env, hence the same ~/.claude. A valid user override above still takes precedence.
|
|
169
|
+
const bundled = resolveBundledBinaryPath();
|
|
170
|
+
if (bundled && existsSync(bundled))
|
|
171
|
+
return bundled;
|
|
172
|
+
const home = os.homedir();
|
|
173
|
+
const isWin = process.platform === 'win32';
|
|
174
|
+
const candidates = isWin
|
|
175
|
+
? [path.join(home, '.local', 'bin', 'claude.exe'), path.join(home, '.local', 'bin', 'claude')]
|
|
176
|
+
: [path.join(home, '.local', 'bin', 'claude')];
|
|
177
|
+
for (const candidate of candidates) {
|
|
178
|
+
if (existsSync(candidate))
|
|
179
|
+
return candidate;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const probe = isWin ? 'where claude' : 'command -v claude';
|
|
183
|
+
const resolved = execSync(probe, { env, encoding: 'utf8' })
|
|
184
|
+
.split(/\r?\n/)
|
|
185
|
+
.map((s) => s.trim())
|
|
186
|
+
.find((s) => s && existsSync(s));
|
|
187
|
+
if (resolved)
|
|
188
|
+
return resolved;
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Not resolvable via PATH — fall through to bare name.
|
|
192
|
+
}
|
|
193
|
+
return isWin ? 'claude.exe' : 'claude';
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Spawn an interactive claude TUI in a PTY and register it in the pool.
|
|
197
|
+
* The caller drives stdin (prompt injection), wires `pty.onData`, and attaches
|
|
198
|
+
* a watcher disposer via `registerDisposer`.
|
|
199
|
+
*/
|
|
200
|
+
spawnClaude(opts) {
|
|
201
|
+
const env = this.buildEnv();
|
|
202
|
+
const bin = this.resolveClaudeBinary(env, opts.binaryPathOverride);
|
|
203
|
+
const handle = randomUUID();
|
|
204
|
+
const ptyProcess = pty.spawn(bin, opts.args, {
|
|
205
|
+
name: 'xterm-256color',
|
|
206
|
+
cols: opts.cols ?? 120,
|
|
207
|
+
rows: opts.rows ?? 40,
|
|
208
|
+
cwd: opts.cwd,
|
|
209
|
+
env,
|
|
210
|
+
});
|
|
211
|
+
this.sessions.set(handle, { pty: ptyProcess, handle, createdAt: Date.now() });
|
|
212
|
+
log.info(`CLI PTY spawned: handle=${handle} bin=${bin} args=[${opts.args.join(' ')}] cwd=${opts.cwd ?? '(inherit)'}`);
|
|
213
|
+
return { handle, pty: ptyProcess };
|
|
214
|
+
}
|
|
215
|
+
/** Attach the watcher teardown so dispose() tears down PTY + watcher together. */
|
|
216
|
+
registerDisposer(handle, dispose) {
|
|
217
|
+
const entry = this.sessions.get(handle);
|
|
218
|
+
if (entry)
|
|
219
|
+
entry.dispose = dispose;
|
|
220
|
+
}
|
|
221
|
+
/** Send Ctrl+C (interrupt) to the PTY without killing it. */
|
|
222
|
+
interrupt(handle) {
|
|
223
|
+
const entry = this.sessions.get(handle);
|
|
224
|
+
if (!entry)
|
|
225
|
+
return;
|
|
226
|
+
try {
|
|
227
|
+
entry.pty.write('\x03');
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// PTY may already be gone.
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Tear down a CLI PTY: run the watcher disposer, kill the process, remove from
|
|
235
|
+
* the pool. Removal happens first so any onExit listener's dispose is a no-op.
|
|
236
|
+
* The kill is wrapped in try/catch to absorb Windows ConPTY shutdown noise
|
|
237
|
+
* (`AttachConsole failed`, spike §9-6 — `ptyService.killSession` pattern).
|
|
238
|
+
*/
|
|
239
|
+
dispose(handle) {
|
|
240
|
+
const entry = this.sessions.get(handle);
|
|
241
|
+
if (!entry)
|
|
242
|
+
return;
|
|
243
|
+
this.sessions.delete(handle);
|
|
244
|
+
try {
|
|
245
|
+
entry.dispose?.();
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
// Watcher teardown best-effort.
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
entry.pty.kill();
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
// PTY may already be dead / ConPTY shutdown noise — ignore.
|
|
255
|
+
}
|
|
256
|
+
log.debug(`CLI PTY disposed: handle=${handle}`);
|
|
257
|
+
}
|
|
258
|
+
/** Destroy every CLI PTY (server shutdown). Symmetric with ptyService.destroyAll. */
|
|
259
|
+
destroyAll() {
|
|
260
|
+
if (this.sessions.size > 0) {
|
|
261
|
+
log.info(`Destroying all CLI PTYs (${this.sessions.size} active)`);
|
|
262
|
+
}
|
|
263
|
+
for (const handle of [...this.sessions.keys()]) {
|
|
264
|
+
this.dispose(handle);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/** Number of live CLI PTYs (for tests / introspection). */
|
|
268
|
+
get size() {
|
|
269
|
+
return this.sessions.size;
|
|
270
|
+
}
|
|
271
|
+
/** Whether a handle is still live in the pool. */
|
|
272
|
+
has(handle) {
|
|
273
|
+
return this.sessions.has(handle);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/** Module singleton — isolated from the web terminal pool (`ptyService`). */
|
|
277
|
+
export const cliSessionPool = new CliSessionPool();
|
|
278
|
+
//# sourceMappingURL=cliSessionPool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliSessionPool.js","sourceRoot":"","sources":["../../src/services/cliSessionPool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI spinner-progress grid reader (Epic 37 — Story 37.2)
|
|
3
|
+
*
|
|
4
|
+
* Reads the generation "↓ N tokens" counter (and the optional leading "(Ns ·" elapsed
|
|
5
|
+
* clock) from a *settled screen grid* produced by the headless screen model (Story
|
|
6
|
+
* 37.1). This is the token data source that replaces the linear ANSI-stripped buffer
|
|
7
|
+
* scan: claude overwrites the spinner counter **in place** (the same screen cell), so a
|
|
8
|
+
* settled grid carries one final value per row — the "365" + "366" → "365366" fusion
|
|
9
|
+
* the linear path suffered is **structurally impossible**, and the old fusion-defense
|
|
10
|
+
* guards (digit cap, malformed-grouping, implausible-jump) are no longer needed.
|
|
11
|
+
*
|
|
12
|
+
* Pure — input is the grid rows, output is the parsed progress or null. The CLI engine
|
|
13
|
+
* schedules a `flush()` and then calls this on the settled grid; the callback contract
|
|
14
|
+
* (`{ tokens, elapsedSeconds }`, emit-on-change) is unchanged.
|
|
15
|
+
*
|
|
16
|
+
* @see docs/stories/37.2.story.md
|
|
17
|
+
* [Source: docs/prd/epic-37-cli-terminal-emulation.md#story-372]
|
|
18
|
+
*/
|
|
19
|
+
export interface SpinnerProgress {
|
|
20
|
+
tokens: number;
|
|
21
|
+
elapsedSeconds: number;
|
|
22
|
+
/**
|
|
23
|
+
* True only when this spinner frame is in the THINKING phase (status segment reads
|
|
24
|
+
* "… · [still ]thinking …" after the token counter). Additive/optional — ABSENT means
|
|
25
|
+
* "not a recognized thinking phase" (generic generation), so existing callers/tests that
|
|
26
|
+
* read just `{ tokens, elapsedSeconds }` are unaffected. The client uses it to label the
|
|
27
|
+
* live progress indicator "Thinking…" (Story 37.11 AC1, achievable tier). See THINKING_PHASE_RE.
|
|
28
|
+
*/
|
|
29
|
+
thinking?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Read the freshest spinner counter from a settled screen grid. Returns null when no
|
|
33
|
+
* counter row is present (e.g. a thinking-phase spinner with no "↓ N tokens") — the
|
|
34
|
+
* caller treats null as "no emit", preserving the false-0 guard.
|
|
35
|
+
*
|
|
36
|
+
* Since claude overwrites the same cell, a settled grid has at most one counter row; if
|
|
37
|
+
* more than one matches, the BOTTOM-most (freshest rendered) row wins. Rows are never
|
|
38
|
+
* merged or concatenated — a single row already holds the whole current value.
|
|
39
|
+
*/
|
|
40
|
+
export declare function readSpinnerProgress(grid: string[]): SpinnerProgress | null;
|
|
41
|
+
//# sourceMappingURL=cliSpinnerProgress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliSpinnerProgress.d.ts","sourceRoot":"","sources":["../../src/services/cliSpinnerProgress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAqEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,eAAe,GAAG,IAAI,CAoC1E"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI spinner-progress grid reader (Epic 37 — Story 37.2)
|
|
3
|
+
*
|
|
4
|
+
* Reads the generation "↓ N tokens" counter (and the optional leading "(Ns ·" elapsed
|
|
5
|
+
* clock) from a *settled screen grid* produced by the headless screen model (Story
|
|
6
|
+
* 37.1). This is the token data source that replaces the linear ANSI-stripped buffer
|
|
7
|
+
* scan: claude overwrites the spinner counter **in place** (the same screen cell), so a
|
|
8
|
+
* settled grid carries one final value per row — the "365" + "366" → "365366" fusion
|
|
9
|
+
* the linear path suffered is **structurally impossible**, and the old fusion-defense
|
|
10
|
+
* guards (digit cap, malformed-grouping, implausible-jump) are no longer needed.
|
|
11
|
+
*
|
|
12
|
+
* Pure — input is the grid rows, output is the parsed progress or null. The CLI engine
|
|
13
|
+
* schedules a `flush()` and then calls this on the settled grid; the callback contract
|
|
14
|
+
* (`{ tokens, elapsedSeconds }`, emit-on-change) is unchanged.
|
|
15
|
+
*
|
|
16
|
+
* @see docs/stories/37.2.story.md
|
|
17
|
+
* [Source: docs/prd/epic-37-cli-terminal-emulation.md#story-372]
|
|
18
|
+
*/
|
|
19
|
+
import { liveFooterRows } from './cliGridRegion.js';
|
|
20
|
+
/**
|
|
21
|
+
* The spinner counter as RENDERED in the grid. Captures both the raw ("↓ 108 tokens")
|
|
22
|
+
* and abbreviated ("↓ 1.4k tokens") shapes claude paints — matching the Story 37.1
|
|
23
|
+
* realframes counter regex `↓ ?[\d.,]+k? tokens`. The old linear CLI_PROGRESS_RE used
|
|
24
|
+
* `[\d,]+`, which breaks at `.`/`k` and so MISSED the abbreviated form entirely; reading
|
|
25
|
+
* the grid lets us capture it. The rotating glyph word (Flowing…/Crunched/Brewed/
|
|
26
|
+
* Moseying…) is deliberately NOT part of the match — it is version-fragile, so the row
|
|
27
|
+
* is identified by the counter alone.
|
|
28
|
+
*
|
|
29
|
+
* Both arrow directions are accepted (`[↑↓]`): claude renders the counter as "↓ N tokens"
|
|
30
|
+
* for some phases and "↑ N tokens" for others (실측 2026-06-14 — a long step showed
|
|
31
|
+
* "↑ 95.6k tokens"). The ↓-only regex MISSED the ↑ form, so a long ↑-phase emitted no
|
|
32
|
+
* progress at all and the UI looked frozen ("멈춤 vs 느림" 구분 불가). The arrow is required
|
|
33
|
+
* (not optional) so a bare "N tokens" in prose can't flash a phantom counter.
|
|
34
|
+
*/
|
|
35
|
+
const GRID_COUNTER_RE = /[↑↓]\s*([\d.,]+k?)\s*tokens/i;
|
|
36
|
+
/**
|
|
37
|
+
* The leading elapsed clock, paren-anchored (Story 37.3 — "Xm Ys" summation). claude
|
|
38
|
+
* renders the clock as the FIRST thing after the spinner's "(" — either bare seconds
|
|
39
|
+
* "(9s ·" or a minute form "(1m 36s ·". Both the minute and second segments are optional
|
|
40
|
+
* and captured separately; an absent segment counts as 0, so bare seconds preserve their
|
|
41
|
+
* old value ("9s" → 9) and a missing clock yields 0. The "(" anchor is load-bearing: the
|
|
42
|
+
* time is always rendered right after the opening paren, so anchoring keeps a counter or
|
|
43
|
+
* prose number ("↓ 365 tokens", "thinking") from being mistaken for the clock.
|
|
44
|
+
*/
|
|
45
|
+
const GRID_ELAPSED_RE = /\((?:(\d+)m\s*)?(?:(\d+)s\b)?/;
|
|
46
|
+
/**
|
|
47
|
+
* The THINKING-phase status segment claude renders INSIDE the spinner's paren group, AFTER the
|
|
48
|
+
* token counter: "↓ 143 tokens · thinking with high effort)" / "· still thinking with high effort)"
|
|
49
|
+
* (실측 2026-06-16, verbose:on AND verbose:off real PTY — `cli-verbose-on/off-long-thinking` fixtures).
|
|
50
|
+
*
|
|
51
|
+
* Why a *phase* flag and not a body thinking card: in verbose:true mode (Hammoc's spawn) claude paints
|
|
52
|
+
* NO live thinking *content* into the screen body — only this bottom spinner advances (elapsed clock +
|
|
53
|
+
* token counter + this phrase); the reasoning block lands WHOLE at completion. So the only live
|
|
54
|
+
* "Claude is thinking" signal is this spinner segment. Surfacing it lets the client LABEL the
|
|
55
|
+
* already-live generation-progress indicator as "Thinking…" (vs generic generation) WITHOUT inventing
|
|
56
|
+
* a card from the version-fragile, region-EXCLUDED footer spinner (which `scrollbackBodyRows` drops to
|
|
57
|
+
* avoid resume-repaint poisoning).
|
|
58
|
+
*
|
|
59
|
+
* Anchored `tokens … thinking` WITHIN the paren (`[^)]*`, no `)` crossing) so a rotating gerund word
|
|
60
|
+
* BEFORE the counter (a hypothetical "Thinking…" spinner glyph) can't false-positive — only the
|
|
61
|
+
* post-counter phase label counts. Effort-suffix agnostic ("with high effort" optional). A
|
|
62
|
+
* response-phase row ("↓ 1.3k tokens)") carries no such segment → not thinking.
|
|
63
|
+
*/
|
|
64
|
+
const THINKING_PHASE_RE = /\btokens\b[^)]*\bthinking\b/i;
|
|
65
|
+
/**
|
|
66
|
+
* Sum the paren-anchored elapsed clock on a spinner row to integer seconds. Pure — input
|
|
67
|
+
* is the rendered row, output is `minutes * 60 + seconds`. A minute form "(1m 36s ·" → 96,
|
|
68
|
+
* bare seconds "(9s ·" → 9 (minutes default to 0), and a row with no clock segment → 0
|
|
69
|
+
* (Story 37.3 AC3). Hour ("Xh") forms are unobserved and out of scope; if claude ever
|
|
70
|
+
* renders them, the same anchored-sum pattern extends. The grid overwrites the spinner
|
|
71
|
+
* cell in place, so an in-place "(1m 36s" → "(1m 37s" redraw reads as the latest value
|
|
72
|
+
* (97), never a fused "136137" — fusion is structurally impossible here too.
|
|
73
|
+
*/
|
|
74
|
+
function sumElapsedSeconds(row) {
|
|
75
|
+
const m = GRID_ELAPSED_RE.exec(row);
|
|
76
|
+
if (!m)
|
|
77
|
+
return 0;
|
|
78
|
+
const minutes = m[1] ? parseInt(m[1], 10) : 0;
|
|
79
|
+
const seconds = m[2] ? parseInt(m[2], 10) : 0;
|
|
80
|
+
return minutes * 60 + seconds;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Read the freshest spinner counter from a settled screen grid. Returns null when no
|
|
84
|
+
* counter row is present (e.g. a thinking-phase spinner with no "↓ N tokens") — the
|
|
85
|
+
* caller treats null as "no emit", preserving the false-0 guard.
|
|
86
|
+
*
|
|
87
|
+
* Since claude overwrites the same cell, a settled grid has at most one counter row; if
|
|
88
|
+
* more than one matches, the BOTTOM-most (freshest rendered) row wins. Rows are never
|
|
89
|
+
* merged or concatenated — a single row already holds the whole current value.
|
|
90
|
+
*/
|
|
91
|
+
export function readSpinnerProgress(grid) {
|
|
92
|
+
// Live region only: the spinner counter renders at the bottom of the screen, so a "↓ N tokens"
|
|
93
|
+
// value QUOTED in resume-repaint scrollback can't flash a phantom counter during the pre-generation
|
|
94
|
+
// thinking phase (no live counter row yet). Bottom-most (freshest) within the region wins.
|
|
95
|
+
const region = liveFooterRows(grid);
|
|
96
|
+
for (let y = region.length - 1; y >= 0; y--) {
|
|
97
|
+
const counter = GRID_COUNTER_RE.exec(region[y]);
|
|
98
|
+
if (!counter)
|
|
99
|
+
continue;
|
|
100
|
+
const raw = counter[1];
|
|
101
|
+
// Normalize to an integer token count: strip thousands separators, then expand a
|
|
102
|
+
// "k" suffix ("1.4k" → 1400). The grid never fuses values, so this is plain parsing.
|
|
103
|
+
const tokens = /k$/i.test(raw)
|
|
104
|
+
? Math.round(parseFloat(raw.slice(0, -1).replace(/,/g, '')) * 1000)
|
|
105
|
+
: parseInt(raw.replace(/,/g, ''), 10);
|
|
106
|
+
if (!Number.isFinite(tokens))
|
|
107
|
+
return null;
|
|
108
|
+
// Phase label rides the SAME counter row we already matched (no extra scan, same region —
|
|
109
|
+
// so no new resume-poisoning surface). Set only when true to keep the shape additive.
|
|
110
|
+
const thinking = THINKING_PHASE_RE.test(region[y]);
|
|
111
|
+
return { tokens, elapsedSeconds: sumElapsedSeconds(region[y]), ...(thinking ? { thinking: true } : {}) };
|
|
112
|
+
}
|
|
113
|
+
// Fallback: no token counter yet, but an elapsed clock is on screen → emit time-only (tokens 0). claude
|
|
114
|
+
// paints "(Ns ·" the moment generation starts, BEFORE the first "↓ N tokens" counter appears — without
|
|
115
|
+
// this the live timer stays frozen until tokens show up (the token-less "(12s" the user saw not parsed).
|
|
116
|
+
// Require a real minute/second digit (GRID_ELAPSED_RE leaves both groups undefined for a bare "("), so a
|
|
117
|
+
// stray paren in prose can't flash a phantom. Bottom-most (freshest) within the live region wins.
|
|
118
|
+
for (let y = region.length - 1; y >= 0; y--) {
|
|
119
|
+
// A counter ARROW on the row means a counter is mid-write ("↓ 36" before "tokens" settles, split across
|
|
120
|
+
// PTY chunks) — wait for it to settle rather than flashing a time-only reading. Fall back ONLY when the
|
|
121
|
+
// row carries no counter glyph at all (the genuine pre-counter "(12s" before any counter appears).
|
|
122
|
+
if (/[↑↓]/.test(region[y]))
|
|
123
|
+
continue;
|
|
124
|
+
const m = GRID_ELAPSED_RE.exec(region[y]);
|
|
125
|
+
if (m && (m[1] !== undefined || m[2] !== undefined)) {
|
|
126
|
+
return { tokens: 0, elapsedSeconds: sumElapsedSeconds(region[y]) };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=cliSpinnerProgress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cliSpinnerProgress.js","sourceRoot":"","sources":["../../src/services/cliSpinnerProgress.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
import type { ContextBuilderManifest } from '@hammoc/shared';
|
|
19
|
+
/**
|
|
20
|
+
* Build the `.mjs` script text for the given project root + manifest. Only
|
|
21
|
+
* acknowledged custom commands are baked in (AC5.b).
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildContextBuilderScript(projectRoot: string, manifest: ContextBuilderManifest): string;
|
|
24
|
+
//# sourceMappingURL=contextBuilderScriptTemplate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contextBuilderScriptTemplate.d.ts","sourceRoot":"","sources":["../../src/services/contextBuilderScriptTemplate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AA0J7D;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,sBAAsB,GAC/B,MAAM,CAkBR"}
|