@yjjeong/omg 0.1.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/CHANGELOG.md +85 -0
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/dist/cli/args.d.ts +39 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +129 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/autoCommit.d.ts +20 -0
- package/dist/cli/autoCommit.d.ts.map +1 -0
- package/dist/cli/autoCommit.js +121 -0
- package/dist/cli/autoCommit.js.map +1 -0
- package/dist/cli/bgTasks.d.ts +57 -0
- package/dist/cli/bgTasks.d.ts.map +1 -0
- package/dist/cli/bgTasks.js +193 -0
- package/dist/cli/bgTasks.js.map +1 -0
- package/dist/cli/compactor.d.ts +48 -0
- package/dist/cli/compactor.d.ts.map +1 -0
- package/dist/cli/compactor.js +73 -0
- package/dist/cli/compactor.js.map +1 -0
- package/dist/cli/doctor.d.ts +77 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +279 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/gitStatus.d.ts +7 -0
- package/dist/cli/gitStatus.d.ts.map +1 -0
- package/dist/cli/gitStatus.js +70 -0
- package/dist/cli/gitStatus.js.map +1 -0
- package/dist/cli/handoff.d.ts +36 -0
- package/dist/cli/handoff.d.ts.map +1 -0
- package/dist/cli/handoff.js +60 -0
- package/dist/cli/handoff.js.map +1 -0
- package/dist/cli/interactive/brokers.d.ts +31 -0
- package/dist/cli/interactive/brokers.d.ts.map +1 -0
- package/dist/cli/interactive/brokers.js +259 -0
- package/dist/cli/interactive/brokers.js.map +1 -0
- package/dist/cli/interactive/index.d.ts +8 -0
- package/dist/cli/interactive/index.d.ts.map +1 -0
- package/dist/cli/interactive/index.js +731 -0
- package/dist/cli/interactive/index.js.map +1 -0
- package/dist/cli/interactive/proxyQuestions.d.ts +15 -0
- package/dist/cli/interactive/proxyQuestions.d.ts.map +1 -0
- package/dist/cli/interactive/proxyQuestions.js +48 -0
- package/dist/cli/interactive/proxyQuestions.js.map +1 -0
- package/dist/cli/interactive/tabManager.d.ts +32 -0
- package/dist/cli/interactive/tabManager.d.ts.map +1 -0
- package/dist/cli/interactive/tabManager.js +244 -0
- package/dist/cli/interactive/tabManager.js.map +1 -0
- package/dist/cli/interactive/teamHint.d.ts +2 -0
- package/dist/cli/interactive/teamHint.d.ts.map +1 -0
- package/dist/cli/interactive/teamHint.js +14 -0
- package/dist/cli/interactive/teamHint.js.map +1 -0
- package/dist/cli/login.d.ts +13 -0
- package/dist/cli/login.d.ts.map +1 -0
- package/dist/cli/login.js +53 -0
- package/dist/cli/login.js.map +1 -0
- package/dist/cli/modes/demo.d.ts +12 -0
- package/dist/cli/modes/demo.d.ts.map +1 -0
- package/dist/cli/modes/demo.js +48 -0
- package/dist/cli/modes/demo.js.map +1 -0
- package/dist/cli/modes/doctor.d.ts +28 -0
- package/dist/cli/modes/doctor.d.ts.map +1 -0
- package/dist/cli/modes/doctor.js +79 -0
- package/dist/cli/modes/doctor.js.map +1 -0
- package/dist/cli/modes/login.d.ts +5 -0
- package/dist/cli/modes/login.d.ts.map +1 -0
- package/dist/cli/modes/login.js +40 -0
- package/dist/cli/modes/login.js.map +1 -0
- package/dist/cli/modes/mcpServe.d.ts +9 -0
- package/dist/cli/modes/mcpServe.d.ts.map +1 -0
- package/dist/cli/modes/mcpServe.js +112 -0
- package/dist/cli/modes/mcpServe.js.map +1 -0
- package/dist/cli/modes/orchestrator.d.ts +14 -0
- package/dist/cli/modes/orchestrator.d.ts.map +1 -0
- package/dist/cli/modes/orchestrator.js +64 -0
- package/dist/cli/modes/orchestrator.js.map +1 -0
- package/dist/cli/modes/team.d.ts +14 -0
- package/dist/cli/modes/team.d.ts.map +1 -0
- package/dist/cli/modes/team.js +87 -0
- package/dist/cli/modes/team.js.map +1 -0
- package/dist/cli/registry.d.ts +3 -0
- package/dist/cli/registry.d.ts.map +1 -0
- package/dist/cli/registry.js +15 -0
- package/dist/cli/registry.js.map +1 -0
- package/dist/cli/slash/core.d.ts +3 -0
- package/dist/cli/slash/core.d.ts.map +1 -0
- package/dist/cli/slash/core.js +509 -0
- package/dist/cli/slash/core.js.map +1 -0
- package/dist/cli/slash/index.d.ts +3 -0
- package/dist/cli/slash/index.d.ts.map +1 -0
- package/dist/cli/slash/index.js +28 -0
- package/dist/cli/slash/index.js.map +1 -0
- package/dist/cli/slash/modes.d.ts +3 -0
- package/dist/cli/slash/modes.d.ts.map +1 -0
- package/dist/cli/slash/modes.js +530 -0
- package/dist/cli/slash/modes.js.map +1 -0
- package/dist/cli/slash/session.d.ts +3 -0
- package/dist/cli/slash/session.d.ts.map +1 -0
- package/dist/cli/slash/session.js +376 -0
- package/dist/cli/slash/session.js.map +1 -0
- package/dist/cli/slash/shared.d.ts +43 -0
- package/dist/cli/slash/shared.d.ts.map +1 -0
- package/dist/cli/slash/shared.js +6 -0
- package/dist/cli/slash/shared.js.map +1 -0
- package/dist/cli/slash/tabs.d.ts +3 -0
- package/dist/cli/slash/tabs.d.ts.map +1 -0
- package/dist/cli/slash/tabs.js +497 -0
- package/dist/cli/slash/tabs.js.map +1 -0
- package/dist/cli/slash/team.d.ts +3 -0
- package/dist/cli/slash/team.d.ts.map +1 -0
- package/dist/cli/slash/team.js +85 -0
- package/dist/cli/slash/team.js.map +1 -0
- package/dist/cli/slash.d.ts +3 -0
- package/dist/cli/slash.d.ts.map +1 -0
- package/dist/cli/slash.js +8 -0
- package/dist/cli/slash.js.map +1 -0
- package/dist/cli/teamPipeline.d.ts +42 -0
- package/dist/cli/teamPipeline.d.ts.map +1 -0
- package/dist/cli/teamPipeline.js +406 -0
- package/dist/cli/teamPipeline.js.map +1 -0
- package/dist/cli/touchedFiles.d.ts +14 -0
- package/dist/cli/touchedFiles.d.ts.map +1 -0
- package/dist/cli/touchedFiles.js +66 -0
- package/dist/cli/touchedFiles.js.map +1 -0
- package/dist/cli/turn.d.ts +47 -0
- package/dist/cli/turn.d.ts.map +1 -0
- package/dist/cli/turn.js +626 -0
- package/dist/cli/turn.js.map +1 -0
- package/dist/cli/types.d.ts +47 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +5 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/uiSession.d.ts +10 -0
- package/dist/cli/uiSession.d.ts.map +1 -0
- package/dist/cli/uiSession.js +66 -0
- package/dist/cli/uiSession.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +128 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/adapter.d.ts +47 -0
- package/dist/core/adapter.d.ts.map +1 -0
- package/dist/core/adapter.js +48 -0
- package/dist/core/adapter.js.map +1 -0
- package/dist/core/adapters/anthropic.d.ts +35 -0
- package/dist/core/adapters/anthropic.d.ts.map +1 -0
- package/dist/core/adapters/anthropic.js +203 -0
- package/dist/core/adapters/anthropic.js.map +1 -0
- package/dist/core/adapters/claudeCli.d.ts +126 -0
- package/dist/core/adapters/claudeCli.d.ts.map +1 -0
- package/dist/core/adapters/claudeCli.js +584 -0
- package/dist/core/adapters/claudeCli.js.map +1 -0
- package/dist/core/adapters/cliAdapterBase.d.ts +48 -0
- package/dist/core/adapters/cliAdapterBase.d.ts.map +1 -0
- package/dist/core/adapters/cliAdapterBase.js +105 -0
- package/dist/core/adapters/cliAdapterBase.js.map +1 -0
- package/dist/core/adapters/cliStderr.d.ts +35 -0
- package/dist/core/adapters/cliStderr.d.ts.map +1 -0
- package/dist/core/adapters/cliStderr.js +87 -0
- package/dist/core/adapters/cliStderr.js.map +1 -0
- package/dist/core/adapters/codexCli.d.ts +113 -0
- package/dist/core/adapters/codexCli.d.ts.map +1 -0
- package/dist/core/adapters/codexCli.js +424 -0
- package/dist/core/adapters/codexCli.js.map +1 -0
- package/dist/core/adapters/gemini.d.ts +17 -0
- package/dist/core/adapters/gemini.d.ts.map +1 -0
- package/dist/core/adapters/gemini.js +133 -0
- package/dist/core/adapters/gemini.js.map +1 -0
- package/dist/core/adapters/geminiCli.d.ts +91 -0
- package/dist/core/adapters/geminiCli.d.ts.map +1 -0
- package/dist/core/adapters/geminiCli.js +276 -0
- package/dist/core/adapters/geminiCli.js.map +1 -0
- package/dist/core/adapters/nudges.d.ts +21 -0
- package/dist/core/adapters/nudges.d.ts.map +1 -0
- package/dist/core/adapters/nudges.js +75 -0
- package/dist/core/adapters/nudges.js.map +1 -0
- package/dist/core/adapters/openai.d.ts +17 -0
- package/dist/core/adapters/openai.d.ts.map +1 -0
- package/dist/core/adapters/openai.js +138 -0
- package/dist/core/adapters/openai.js.map +1 -0
- package/dist/core/adapters/parseFailures.d.ts +10 -0
- package/dist/core/adapters/parseFailures.d.ts.map +1 -0
- package/dist/core/adapters/parseFailures.js +35 -0
- package/dist/core/adapters/parseFailures.js.map +1 -0
- package/dist/core/adapters/utils.d.ts +11 -0
- package/dist/core/adapters/utils.d.ts.map +1 -0
- package/dist/core/adapters/utils.js +33 -0
- package/dist/core/adapters/utils.js.map +1 -0
- package/dist/core/askBroker.d.ts +11 -0
- package/dist/core/askBroker.d.ts.map +1 -0
- package/dist/core/askBroker.js +78 -0
- package/dist/core/askBroker.js.map +1 -0
- package/dist/core/atomicWrite.d.ts +5 -0
- package/dist/core/atomicWrite.d.ts.map +1 -0
- package/dist/core/atomicWrite.js +18 -0
- package/dist/core/atomicWrite.js.map +1 -0
- package/dist/core/brokers/askBroker.d.ts +11 -0
- package/dist/core/brokers/askBroker.d.ts.map +1 -0
- package/dist/core/brokers/askBroker.js +78 -0
- package/dist/core/brokers/askBroker.js.map +1 -0
- package/dist/core/brokers/permissionBroker.d.ts +7 -0
- package/dist/core/brokers/permissionBroker.d.ts.map +1 -0
- package/dist/core/brokers/permissionBroker.js +63 -0
- package/dist/core/brokers/permissionBroker.js.map +1 -0
- package/dist/core/brokers/socketBroker.d.ts +35 -0
- package/dist/core/brokers/socketBroker.d.ts.map +1 -0
- package/dist/core/brokers/socketBroker.js +74 -0
- package/dist/core/brokers/socketBroker.js.map +1 -0
- package/dist/core/clipboard.d.ts +4 -0
- package/dist/core/clipboard.d.ts.map +1 -0
- package/dist/core/clipboard.js +46 -0
- package/dist/core/clipboard.js.map +1 -0
- package/dist/core/compactor.d.ts +32 -0
- package/dist/core/compactor.d.ts.map +1 -0
- package/dist/core/compactor.js +91 -0
- package/dist/core/compactor.js.map +1 -0
- package/dist/core/consensusEngine.d.ts +21 -0
- package/dist/core/consensusEngine.d.ts.map +1 -0
- package/dist/core/consensusEngine.js +116 -0
- package/dist/core/consensusEngine.js.map +1 -0
- package/dist/core/context/contextCompressor.d.ts +10 -0
- package/dist/core/context/contextCompressor.d.ts.map +1 -0
- package/dist/core/context/contextCompressor.js +54 -0
- package/dist/core/context/contextCompressor.js.map +1 -0
- package/dist/core/context/contextWindows.d.ts +25 -0
- package/dist/core/context/contextWindows.d.ts.map +1 -0
- package/dist/core/context/contextWindows.js +101 -0
- package/dist/core/context/contextWindows.js.map +1 -0
- package/dist/core/context/summarizer.d.ts +65 -0
- package/dist/core/context/summarizer.d.ts.map +1 -0
- package/dist/core/context/summarizer.js +184 -0
- package/dist/core/context/summarizer.js.map +1 -0
- package/dist/core/context/usageCache.d.ts +19 -0
- package/dist/core/context/usageCache.d.ts.map +1 -0
- package/dist/core/context/usageCache.js +157 -0
- package/dist/core/context/usageCache.js.map +1 -0
- package/dist/core/context/usageWindow.d.ts +19 -0
- package/dist/core/context/usageWindow.d.ts.map +1 -0
- package/dist/core/context/usageWindow.js +73 -0
- package/dist/core/context/usageWindow.js.map +1 -0
- package/dist/core/contextCompressor.d.ts +10 -0
- package/dist/core/contextCompressor.d.ts.map +1 -0
- package/dist/core/contextCompressor.js +54 -0
- package/dist/core/contextCompressor.js.map +1 -0
- package/dist/core/contextWindows.d.ts +5 -0
- package/dist/core/contextWindows.d.ts.map +1 -0
- package/dist/core/contextWindows.js +60 -0
- package/dist/core/contextWindows.js.map +1 -0
- package/dist/core/continuum/digest.d.ts +35 -0
- package/dist/core/continuum/digest.d.ts.map +1 -0
- package/dist/core/continuum/digest.js +91 -0
- package/dist/core/continuum/digest.js.map +1 -0
- package/dist/core/continuum/index.d.ts +6 -0
- package/dist/core/continuum/index.d.ts.map +1 -0
- package/dist/core/continuum/index.js +7 -0
- package/dist/core/continuum/index.js.map +1 -0
- package/dist/core/continuum/inject.d.ts +9 -0
- package/dist/core/continuum/inject.d.ts.map +1 -0
- package/dist/core/continuum/inject.js +78 -0
- package/dist/core/continuum/inject.js.map +1 -0
- package/dist/core/continuum/projectId.d.ts +10 -0
- package/dist/core/continuum/projectId.d.ts.map +1 -0
- package/dist/core/continuum/projectId.js +60 -0
- package/dist/core/continuum/projectId.js.map +1 -0
- package/dist/core/continuum/store.d.ts +24 -0
- package/dist/core/continuum/store.d.ts.map +1 -0
- package/dist/core/continuum/store.js +144 -0
- package/dist/core/continuum/store.js.map +1 -0
- package/dist/core/continuum/types.d.ts +87 -0
- package/dist/core/continuum/types.d.ts.map +1 -0
- package/dist/core/continuum/types.js +9 -0
- package/dist/core/continuum/types.js.map +1 -0
- package/dist/core/dag.d.ts +21 -0
- package/dist/core/dag.d.ts.map +1 -0
- package/dist/core/dag.js +71 -0
- package/dist/core/dag.js.map +1 -0
- package/dist/core/director.d.ts +11 -0
- package/dist/core/director.d.ts.map +1 -0
- package/dist/core/director.js +37 -0
- package/dist/core/director.js.map +1 -0
- package/dist/core/hookedToolBroker.d.ts +25 -0
- package/dist/core/hookedToolBroker.d.ts.map +1 -0
- package/dist/core/hookedToolBroker.js +95 -0
- package/dist/core/hookedToolBroker.js.map +1 -0
- package/dist/core/langHint.d.ts +9 -0
- package/dist/core/langHint.d.ts.map +1 -0
- package/dist/core/langHint.js +33 -0
- package/dist/core/langHint.js.map +1 -0
- package/dist/core/mcp/mcpClient.d.ts +42 -0
- package/dist/core/mcp/mcpClient.d.ts.map +1 -0
- package/dist/core/mcp/mcpClient.js +134 -0
- package/dist/core/mcp/mcpClient.js.map +1 -0
- package/dist/core/mcp/mcpConfig.d.ts +58 -0
- package/dist/core/mcp/mcpConfig.d.ts.map +1 -0
- package/dist/core/mcp/mcpConfig.js +148 -0
- package/dist/core/mcp/mcpConfig.js.map +1 -0
- package/dist/core/mcp/mcpManager.d.ts +31 -0
- package/dist/core/mcp/mcpManager.d.ts.map +1 -0
- package/dist/core/mcp/mcpManager.js +83 -0
- package/dist/core/mcp/mcpManager.js.map +1 -0
- package/dist/core/mcpClient.d.ts +42 -0
- package/dist/core/mcpClient.d.ts.map +1 -0
- package/dist/core/mcpClient.js +134 -0
- package/dist/core/mcpClient.js.map +1 -0
- package/dist/core/mcpConfig.d.ts +24 -0
- package/dist/core/mcpConfig.d.ts.map +1 -0
- package/dist/core/mcpConfig.js +74 -0
- package/dist/core/mcpConfig.js.map +1 -0
- package/dist/core/mcpManager.d.ts +31 -0
- package/dist/core/mcpManager.d.ts.map +1 -0
- package/dist/core/mcpManager.js +83 -0
- package/dist/core/mcpManager.js.map +1 -0
- package/dist/core/memory.d.ts +22 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +102 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/omgToolManifest.d.ts +34 -0
- package/dist/core/omgToolManifest.d.ts.map +1 -0
- package/dist/core/omgToolManifest.js +59 -0
- package/dist/core/omgToolManifest.js.map +1 -0
- package/dist/core/orchestration/consensusEngine.d.ts +21 -0
- package/dist/core/orchestration/consensusEngine.d.ts.map +1 -0
- package/dist/core/orchestration/consensusEngine.js +116 -0
- package/dist/core/orchestration/consensusEngine.js.map +1 -0
- package/dist/core/orchestration/dag.d.ts +21 -0
- package/dist/core/orchestration/dag.d.ts.map +1 -0
- package/dist/core/orchestration/dag.js +71 -0
- package/dist/core/orchestration/dag.js.map +1 -0
- package/dist/core/orchestration/director.d.ts +11 -0
- package/dist/core/orchestration/director.d.ts.map +1 -0
- package/dist/core/orchestration/director.js +37 -0
- package/dist/core/orchestration/director.js.map +1 -0
- package/dist/core/orchestration/orchestrator.d.ts +32 -0
- package/dist/core/orchestration/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestration/orchestrator.js +214 -0
- package/dist/core/orchestration/orchestrator.js.map +1 -0
- package/dist/core/orchestration/roleRouter.d.ts +28 -0
- package/dist/core/orchestration/roleRouter.d.ts.map +1 -0
- package/dist/core/orchestration/roleRouter.js +64 -0
- package/dist/core/orchestration/roleRouter.js.map +1 -0
- package/dist/core/orchestration/teamRunner.d.ts +69 -0
- package/dist/core/orchestration/teamRunner.d.ts.map +1 -0
- package/dist/core/orchestration/teamRunner.js +477 -0
- package/dist/core/orchestration/teamRunner.js.map +1 -0
- package/dist/core/orchestration/types.d.ts +115 -0
- package/dist/core/orchestration/types.d.ts.map +1 -0
- package/dist/core/orchestration/types.js +71 -0
- package/dist/core/orchestration/types.js.map +1 -0
- package/dist/core/orchestrator.d.ts +32 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +214 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/permissionBroker.d.ts +7 -0
- package/dist/core/permissionBroker.d.ts.map +1 -0
- package/dist/core/permissionBroker.js +63 -0
- package/dist/core/permissionBroker.js.map +1 -0
- package/dist/core/planConfig.d.ts +15 -0
- package/dist/core/planConfig.d.ts.map +1 -0
- package/dist/core/planConfig.js +98 -0
- package/dist/core/planConfig.js.map +1 -0
- package/dist/core/presetPersistence.d.ts +4 -0
- package/dist/core/presetPersistence.d.ts.map +1 -0
- package/dist/core/presetPersistence.js +64 -0
- package/dist/core/presetPersistence.js.map +1 -0
- package/dist/core/roleRouter.d.ts +26 -0
- package/dist/core/roleRouter.d.ts.map +1 -0
- package/dist/core/roleRouter.js +62 -0
- package/dist/core/roleRouter.js.map +1 -0
- package/dist/core/sessionList.d.ts +26 -0
- package/dist/core/sessionList.d.ts.map +1 -0
- package/dist/core/sessionList.js +278 -0
- package/dist/core/sessionList.js.map +1 -0
- package/dist/core/slugify.d.ts +2 -0
- package/dist/core/slugify.d.ts.map +1 -0
- package/dist/core/slugify.js +17 -0
- package/dist/core/slugify.js.map +1 -0
- package/dist/core/socketBroker.d.ts +19 -0
- package/dist/core/socketBroker.d.ts.map +1 -0
- package/dist/core/socketBroker.js +48 -0
- package/dist/core/socketBroker.js.map +1 -0
- package/dist/core/state/agentsMdScaffold.d.ts +15 -0
- package/dist/core/state/agentsMdScaffold.d.ts.map +1 -0
- package/dist/core/state/agentsMdScaffold.js +118 -0
- package/dist/core/state/agentsMdScaffold.js.map +1 -0
- package/dist/core/state/atomicWrite.d.ts +5 -0
- package/dist/core/state/atomicWrite.d.ts.map +1 -0
- package/dist/core/state/atomicWrite.js +18 -0
- package/dist/core/state/atomicWrite.js.map +1 -0
- package/dist/core/state/handoff.d.ts +20 -0
- package/dist/core/state/handoff.d.ts.map +1 -0
- package/dist/core/state/handoff.js +71 -0
- package/dist/core/state/handoff.js.map +1 -0
- package/dist/core/state/mcpCatalog.d.ts +11 -0
- package/dist/core/state/mcpCatalog.d.ts.map +1 -0
- package/dist/core/state/mcpCatalog.js +51 -0
- package/dist/core/state/mcpCatalog.js.map +1 -0
- package/dist/core/state/mcpRecommendations.d.ts +7 -0
- package/dist/core/state/mcpRecommendations.d.ts.map +1 -0
- package/dist/core/state/mcpRecommendations.js +57 -0
- package/dist/core/state/mcpRecommendations.js.map +1 -0
- package/dist/core/state/memory.d.ts +22 -0
- package/dist/core/state/memory.d.ts.map +1 -0
- package/dist/core/state/memory.js +102 -0
- package/dist/core/state/memory.js.map +1 -0
- package/dist/core/state/planConfig.d.ts +15 -0
- package/dist/core/state/planConfig.d.ts.map +1 -0
- package/dist/core/state/planConfig.js +98 -0
- package/dist/core/state/planConfig.js.map +1 -0
- package/dist/core/state/presetPersistence.d.ts +4 -0
- package/dist/core/state/presetPersistence.d.ts.map +1 -0
- package/dist/core/state/presetPersistence.js +67 -0
- package/dist/core/state/presetPersistence.js.map +1 -0
- package/dist/core/state/sessionList.d.ts +26 -0
- package/dist/core/state/sessionList.d.ts.map +1 -0
- package/dist/core/state/sessionList.js +278 -0
- package/dist/core/state/sessionList.js.map +1 -0
- package/dist/core/state/stackDetect.d.ts +8 -0
- package/dist/core/state/stackDetect.d.ts.map +1 -0
- package/dist/core/state/stackDetect.js +40 -0
- package/dist/core/state/stackDetect.js.map +1 -0
- package/dist/core/state/tabPersistence.d.ts +29 -0
- package/dist/core/state/tabPersistence.d.ts.map +1 -0
- package/dist/core/state/tabPersistence.js +65 -0
- package/dist/core/state/tabPersistence.js.map +1 -0
- package/dist/core/tabPersistence.d.ts +29 -0
- package/dist/core/tabPersistence.d.ts.map +1 -0
- package/dist/core/tabPersistence.js +65 -0
- package/dist/core/tabPersistence.js.map +1 -0
- package/dist/core/teamRunner.d.ts +42 -0
- package/dist/core/teamRunner.d.ts.map +1 -0
- package/dist/core/teamRunner.js +248 -0
- package/dist/core/teamRunner.js.map +1 -0
- package/dist/core/toolGate.d.ts +23 -0
- package/dist/core/toolGate.d.ts.map +1 -0
- package/dist/core/toolGate.js +51 -0
- package/dist/core/toolGate.js.map +1 -0
- package/dist/core/toolInterceptor.d.ts +7 -0
- package/dist/core/toolInterceptor.d.ts.map +1 -0
- package/dist/core/toolInterceptor.js +108 -0
- package/dist/core/toolInterceptor.js.map +1 -0
- package/dist/core/tools/hookedToolBroker.d.ts +25 -0
- package/dist/core/tools/hookedToolBroker.d.ts.map +1 -0
- package/dist/core/tools/hookedToolBroker.js +95 -0
- package/dist/core/tools/hookedToolBroker.js.map +1 -0
- package/dist/core/tools/omgToolManifest.d.ts +42 -0
- package/dist/core/tools/omgToolManifest.d.ts.map +1 -0
- package/dist/core/tools/omgToolManifest.js +66 -0
- package/dist/core/tools/omgToolManifest.js.map +1 -0
- package/dist/core/tools/toolGate.d.ts +23 -0
- package/dist/core/tools/toolGate.d.ts.map +1 -0
- package/dist/core/tools/toolGate.js +51 -0
- package/dist/core/tools/toolGate.js.map +1 -0
- package/dist/core/tools/toolInterceptor.d.ts +7 -0
- package/dist/core/tools/toolInterceptor.d.ts.map +1 -0
- package/dist/core/tools/toolInterceptor.js +108 -0
- package/dist/core/tools/toolInterceptor.js.map +1 -0
- package/dist/core/tools/tools.d.ts +34 -0
- package/dist/core/tools/tools.d.ts.map +1 -0
- package/dist/core/tools/tools.js +328 -0
- package/dist/core/tools/tools.js.map +1 -0
- package/dist/core/tools.d.ts +34 -0
- package/dist/core/tools.d.ts.map +1 -0
- package/dist/core/tools.js +300 -0
- package/dist/core/tools.js.map +1 -0
- package/dist/core/types.d.ts +107 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +55 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/usageCache.d.ts +19 -0
- package/dist/core/usageCache.d.ts.map +1 -0
- package/dist/core/usageCache.js +157 -0
- package/dist/core/usageCache.js.map +1 -0
- package/dist/core/usageWindow.d.ts +19 -0
- package/dist/core/usageWindow.d.ts.map +1 -0
- package/dist/core/usageWindow.js +73 -0
- package/dist/core/usageWindow.js.map +1 -0
- package/dist/core/util/bgProtocol.d.ts +5 -0
- package/dist/core/util/bgProtocol.d.ts.map +1 -0
- package/dist/core/util/bgProtocol.js +20 -0
- package/dist/core/util/bgProtocol.js.map +1 -0
- package/dist/core/util/clipboard.d.ts +4 -0
- package/dist/core/util/clipboard.d.ts.map +1 -0
- package/dist/core/util/clipboard.js +46 -0
- package/dist/core/util/clipboard.js.map +1 -0
- package/dist/core/util/clipboardImage.d.ts +3 -0
- package/dist/core/util/clipboardImage.d.ts.map +1 -0
- package/dist/core/util/clipboardImage.js +58 -0
- package/dist/core/util/clipboardImage.js.map +1 -0
- package/dist/core/util/langHint.d.ts +9 -0
- package/dist/core/util/langHint.d.ts.map +1 -0
- package/dist/core/util/langHint.js +33 -0
- package/dist/core/util/langHint.js.map +1 -0
- package/dist/core/util/slugify.d.ts +2 -0
- package/dist/core/util/slugify.d.ts.map +1 -0
- package/dist/core/util/slugify.js +28 -0
- package/dist/core/util/slugify.js.map +1 -0
- package/dist/hooks/hookedToolProxy.mjs +118 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc/dispatcher.d.ts +21 -0
- package/dist/ipc/dispatcher.d.ts.map +1 -0
- package/dist/ipc/dispatcher.js +160 -0
- package/dist/ipc/dispatcher.js.map +1 -0
- package/dist/ipc/events.d.ts +33 -0
- package/dist/ipc/events.d.ts.map +1 -0
- package/dist/ipc/events.js +42 -0
- package/dist/ipc/events.js.map +1 -0
- package/dist/ipc/rpc.d.ts +31 -0
- package/dist/ipc/rpc.d.ts.map +1 -0
- package/dist/ipc/rpc.js +110 -0
- package/dist/ipc/rpc.js.map +1 -0
- package/dist/ipc/stdio.d.ts +11 -0
- package/dist/ipc/stdio.d.ts.map +1 -0
- package/dist/ipc/stdio.js +52 -0
- package/dist/ipc/stdio.js.map +1 -0
- package/dist/mcp/askClient.d.ts +9 -0
- package/dist/mcp/askClient.d.ts.map +1 -0
- package/dist/mcp/askClient.js +70 -0
- package/dist/mcp/askClient.js.map +1 -0
- package/dist/mcp/constants.d.ts +6 -0
- package/dist/mcp/constants.d.ts.map +1 -0
- package/dist/mcp/constants.js +8 -0
- package/dist/mcp/constants.js.map +1 -0
- package/dist/mcp/permissionClient.d.ts +5 -0
- package/dist/mcp/permissionClient.d.ts.map +1 -0
- package/dist/mcp/permissionClient.js +71 -0
- package/dist/mcp/permissionClient.js.map +1 -0
- package/dist/mcp/schemas.d.ts +9 -0
- package/dist/mcp/schemas.d.ts.map +1 -0
- package/dist/mcp/schemas.js +121 -0
- package/dist/mcp/schemas.js.map +1 -0
- package/dist/mcp/server.d.ts +41 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +204 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/policy/loader.d.ts +27 -0
- package/dist/policy/loader.d.ts.map +1 -0
- package/dist/policy/loader.js +89 -0
- package/dist/policy/loader.js.map +1 -0
- package/dist/policy/team-claude-only.yaml +46 -0
- package/dist/policy/team-codex-only.yaml +46 -0
- package/dist/policy/team-codex.yaml +54 -0
- package/dist/policy/team.yaml +104 -0
- package/dist/toolhook/hookedToolProxy.mjs +118 -0
- package/dist/ui/components/App.d.ts +14 -0
- package/dist/ui/components/App.d.ts.map +1 -0
- package/dist/ui/components/App.js +803 -0
- package/dist/ui/components/App.js.map +1 -0
- package/dist/ui/components/AskPicker.d.ts +8 -0
- package/dist/ui/components/AskPicker.d.ts.map +1 -0
- package/dist/ui/components/AskPicker.js +202 -0
- package/dist/ui/components/AskPicker.js.map +1 -0
- package/dist/ui/components/CommandInput.d.ts +63 -0
- package/dist/ui/components/CommandInput.d.ts.map +1 -0
- package/dist/ui/components/CommandInput.js +994 -0
- package/dist/ui/components/CommandInput.js.map +1 -0
- package/dist/ui/components/DiffView.d.ts +19 -0
- package/dist/ui/components/DiffView.d.ts.map +1 -0
- package/dist/ui/components/DiffView.js +93 -0
- package/dist/ui/components/DiffView.js.map +1 -0
- package/dist/ui/components/Dock.d.ts +49 -0
- package/dist/ui/components/Dock.d.ts.map +1 -0
- package/dist/ui/components/Dock.js +52 -0
- package/dist/ui/components/Dock.js.map +1 -0
- package/dist/ui/components/EventLog.d.ts +42 -0
- package/dist/ui/components/EventLog.d.ts.map +1 -0
- package/dist/ui/components/EventLog.js +450 -0
- package/dist/ui/components/EventLog.js.map +1 -0
- package/dist/ui/components/FileSuggest.d.ts +8 -0
- package/dist/ui/components/FileSuggest.d.ts.map +1 -0
- package/dist/ui/components/FileSuggest.js +19 -0
- package/dist/ui/components/FileSuggest.js.map +1 -0
- package/dist/ui/components/HRule.d.ts +27 -0
- package/dist/ui/components/HRule.d.ts.map +1 -0
- package/dist/ui/components/HRule.js +75 -0
- package/dist/ui/components/HRule.js.map +1 -0
- package/dist/ui/components/HintBar.d.ts +2 -0
- package/dist/ui/components/HintBar.d.ts.map +1 -0
- package/dist/ui/components/HintBar.js +19 -0
- package/dist/ui/components/HintBar.js.map +1 -0
- package/dist/ui/components/MarkdownText.d.ts +13 -0
- package/dist/ui/components/MarkdownText.d.ts.map +1 -0
- package/dist/ui/components/MarkdownText.js +255 -0
- package/dist/ui/components/MarkdownText.js.map +1 -0
- package/dist/ui/components/PermissionPrompt.d.ts +8 -0
- package/dist/ui/components/PermissionPrompt.d.ts.map +1 -0
- package/dist/ui/components/PermissionPrompt.js +37 -0
- package/dist/ui/components/PermissionPrompt.js.map +1 -0
- package/dist/ui/components/SessionPicker.d.ts +16 -0
- package/dist/ui/components/SessionPicker.d.ts.map +1 -0
- package/dist/ui/components/SessionPicker.js +116 -0
- package/dist/ui/components/SessionPicker.js.map +1 -0
- package/dist/ui/components/SlashPalette.d.ts +8 -0
- package/dist/ui/components/SlashPalette.d.ts.map +1 -0
- package/dist/ui/components/SlashPalette.js +41 -0
- package/dist/ui/components/SlashPalette.js.map +1 -0
- package/dist/ui/components/Spinner.d.ts +37 -0
- package/dist/ui/components/Spinner.d.ts.map +1 -0
- package/dist/ui/components/Spinner.js +139 -0
- package/dist/ui/components/Spinner.js.map +1 -0
- package/dist/ui/components/StatusBar.d.ts +92 -0
- package/dist/ui/components/StatusBar.d.ts.map +1 -0
- package/dist/ui/components/StatusBar.js +268 -0
- package/dist/ui/components/StatusBar.js.map +1 -0
- package/dist/ui/components/TabChip.d.ts +11 -0
- package/dist/ui/components/TabChip.d.ts.map +1 -0
- package/dist/ui/components/TabChip.js +23 -0
- package/dist/ui/components/TabChip.js.map +1 -0
- package/dist/ui/components/TeamIndicator.d.ts +6 -0
- package/dist/ui/components/TeamIndicator.d.ts.map +1 -0
- package/dist/ui/components/TeamIndicator.js +17 -0
- package/dist/ui/components/TeamIndicator.js.map +1 -0
- package/dist/ui/components/TeamStatusPanel.d.ts +14 -0
- package/dist/ui/components/TeamStatusPanel.d.ts.map +1 -0
- package/dist/ui/components/TeamStatusPanel.js +65 -0
- package/dist/ui/components/TeamStatusPanel.js.map +1 -0
- package/dist/ui/components/ThinkingBlock.d.ts +10 -0
- package/dist/ui/components/ThinkingBlock.d.ts.map +1 -0
- package/dist/ui/components/ThinkingBlock.js +21 -0
- package/dist/ui/components/ThinkingBlock.js.map +1 -0
- package/dist/ui/components/TodoIndicator.d.ts +11 -0
- package/dist/ui/components/TodoIndicator.d.ts.map +1 -0
- package/dist/ui/components/TodoIndicator.js +37 -0
- package/dist/ui/components/TodoIndicator.js.map +1 -0
- package/dist/ui/components/ToolCallCard.d.ts +16 -0
- package/dist/ui/components/ToolCallCard.d.ts.map +1 -0
- package/dist/ui/components/ToolCallCard.js +195 -0
- package/dist/ui/components/ToolCallCard.js.map +1 -0
- package/dist/ui/components/Welcome.d.ts +8 -0
- package/dist/ui/components/Welcome.d.ts.map +1 -0
- package/dist/ui/components/Welcome.js +53 -0
- package/dist/ui/components/Welcome.js.map +1 -0
- package/dist/ui/cursorState.d.ts +29 -0
- package/dist/ui/cursorState.d.ts.map +1 -0
- package/dist/ui/cursorState.js +49 -0
- package/dist/ui/cursorState.js.map +1 -0
- package/dist/ui/diff.d.ts +34 -0
- package/dist/ui/diff.d.ts.map +1 -0
- package/dist/ui/diff.js +184 -0
- package/dist/ui/diff.js.map +1 -0
- package/dist/ui/diffLang.d.ts +2 -0
- package/dist/ui/diffLang.d.ts.map +1 -0
- package/dist/ui/diffLang.js +36 -0
- package/dist/ui/diffLang.js.map +1 -0
- package/dist/ui/emoji.d.ts +4 -0
- package/dist/ui/emoji.d.ts.map +1 -0
- package/dist/ui/emoji.js +73 -0
- package/dist/ui/emoji.js.map +1 -0
- package/dist/ui/fileMentions.d.ts +41 -0
- package/dist/ui/fileMentions.d.ts.map +1 -0
- package/dist/ui/fileMentions.js +135 -0
- package/dist/ui/fileMentions.js.map +1 -0
- package/dist/ui/hooks/useLineEditor.d.ts +44 -0
- package/dist/ui/hooks/useLineEditor.d.ts.map +1 -0
- package/dist/ui/hooks/useLineEditor.js +142 -0
- package/dist/ui/hooks/useLineEditor.js.map +1 -0
- package/dist/ui/inputHistory.d.ts +8 -0
- package/dist/ui/inputHistory.d.ts.map +1 -0
- package/dist/ui/inputHistory.js +56 -0
- package/dist/ui/inputHistory.js.map +1 -0
- package/dist/ui/jsonrpc.d.ts +17 -0
- package/dist/ui/jsonrpc.d.ts.map +1 -0
- package/dist/ui/jsonrpc.js +41 -0
- package/dist/ui/jsonrpc.js.map +1 -0
- package/dist/ui/launcher.d.ts +20 -0
- package/dist/ui/launcher.d.ts.map +1 -0
- package/dist/ui/launcher.js +185 -0
- package/dist/ui/launcher.js.map +1 -0
- package/dist/ui/markdown.d.ts +104 -0
- package/dist/ui/markdown.d.ts.map +1 -0
- package/dist/ui/markdown.js +449 -0
- package/dist/ui/markdown.js.map +1 -0
- package/dist/ui/mouse.d.ts +22 -0
- package/dist/ui/mouse.d.ts.map +1 -0
- package/dist/ui/mouse.js +31 -0
- package/dist/ui/mouse.js.map +1 -0
- package/dist/ui/outbound.d.ts +20 -0
- package/dist/ui/outbound.d.ts.map +1 -0
- package/dist/ui/outbound.js +49 -0
- package/dist/ui/outbound.js.map +1 -0
- package/dist/ui/screenMode.d.ts +25 -0
- package/dist/ui/screenMode.d.ts.map +1 -0
- package/dist/ui/screenMode.js +43 -0
- package/dist/ui/screenMode.js.map +1 -0
- package/dist/ui/slashCatalog.d.ts +18 -0
- package/dist/ui/slashCatalog.d.ts.map +1 -0
- package/dist/ui/slashCatalog.js +243 -0
- package/dist/ui/slashCatalog.js.map +1 -0
- package/dist/ui/syntax.d.ts +11 -0
- package/dist/ui/syntax.d.ts.map +1 -0
- package/dist/ui/syntax.js +78 -0
- package/dist/ui/syntax.js.map +1 -0
- package/dist/ui/theme.d.ts +165 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +394 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/types.d.ts +203 -0
- package/dist/ui/types.d.ts.map +1 -0
- package/dist/ui/types.js +53 -0
- package/dist/ui/types.js.map +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { Box, Text, useInput, useStdin, useStdout } from "ink";
|
|
4
|
+
import { EventLog } from "./EventLog.js";
|
|
5
|
+
import { CommandInput } from "./CommandInput.js";
|
|
6
|
+
import { Dock } from "./Dock.js";
|
|
7
|
+
import { StatusBar } from "./StatusBar.js";
|
|
8
|
+
import { HintBar } from "./HintBar.js";
|
|
9
|
+
import { HRule } from "./HRule.js";
|
|
10
|
+
import { Welcome } from "./Welcome.js";
|
|
11
|
+
import { shellActivityVerb } from "./Spinner.js";
|
|
12
|
+
import { TabChip } from "./TabChip.js";
|
|
13
|
+
import { setTheme, theme } from "../theme.js";
|
|
14
|
+
import { sendPickerClose } from "../outbound.js";
|
|
15
|
+
import { wantsAltScreen } from "../screenMode.js";
|
|
16
|
+
import { parseMouseWheel } from "../mouse.js";
|
|
17
|
+
import { isAskRequest, isPermissionRequest } from "../types.js";
|
|
18
|
+
const CURSOR_LAYOUT_SETTLE_MS = 120;
|
|
19
|
+
// Phase 248/295: cap the in-memory event log. Alt-screen front-trims its
|
|
20
|
+
// bounded viewport; transcript mode never front-trims (that corrupts the
|
|
21
|
+
// append-only <Static>) and instead checkpoints at idle — see
|
|
22
|
+
// shouldCheckpointTranscript.
|
|
23
|
+
const EVENTS_CAP = 5000;
|
|
24
|
+
const EVENTS_TRIM = 1000;
|
|
25
|
+
// Phase 310: transcript mode re-derives every group from the full events
|
|
26
|
+
// array on each 32ms flush (groupEvents is O(events) and uncached), so the
|
|
27
|
+
// repaint cost scales with events.length — the source of the "laggy after an
|
|
28
|
+
// hour" creep. In normal-screen mode settled rows already live in native
|
|
29
|
+
// scrollback, so we can checkpoint (drop the React log + remount <Static>)
|
|
30
|
+
// far below EVENTS_CAP without losing any visible history. A low softcap
|
|
31
|
+
// keeps N — and therefore per-flush cost — bounded across a long session.
|
|
32
|
+
// Alt-screen keeps the 5000 cap (its viewport front-trims and PageUp reads
|
|
33
|
+
// from this array, so it needs the deeper backlog).
|
|
34
|
+
const TRANSCRIPT_EVENTS_SOFTCAP = 1200;
|
|
35
|
+
// Phase 295: decide whether to checkpoint the transcript-mode event log.
|
|
36
|
+
// In normal-screen mode settled rows are owned by native terminal
|
|
37
|
+
// scrollback (Ink <Static> emitted them once), so once the React-side
|
|
38
|
+
// log crosses the cap at an IDLE boundary we drop it wholesale and remount
|
|
39
|
+
// <Static> with a fresh key: the old rows stay in scrollback (re-emitted
|
|
40
|
+
// nowhere → no duplicate, no scroll jump) and the array restarts empty so
|
|
41
|
+
// later appends stay strictly append-only. Never while streaming (the
|
|
42
|
+
// live tail isn't settled yet) and never in alt-screen (its viewport
|
|
43
|
+
// re-derives every frame and front-trims safely).
|
|
44
|
+
export function shouldCheckpointTranscript(opts) {
|
|
45
|
+
return (!opts.altScreenMode &&
|
|
46
|
+
!opts.streaming &&
|
|
47
|
+
opts.eventsLength > (opts.cap ?? EVENTS_CAP));
|
|
48
|
+
}
|
|
49
|
+
// Phase 277: cheap value-equality for a single event/status field.
|
|
50
|
+
// Status payloads are tiny (git info, tabsState, token counts) and the
|
|
51
|
+
// cli emits each object with stable key order, so a structural compare
|
|
52
|
+
// via JSON is sufficient to tell an unchanged 5s git refresh apart from
|
|
53
|
+
// a real status change.
|
|
54
|
+
function statusValueEqual(a, b) {
|
|
55
|
+
if (a === b)
|
|
56
|
+
return true;
|
|
57
|
+
if (typeof a !== "object" ||
|
|
58
|
+
typeof b !== "object" ||
|
|
59
|
+
a === null ||
|
|
60
|
+
b === null) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
64
|
+
}
|
|
65
|
+
// Phase 67 layout (claude-code style):
|
|
66
|
+
// [ EventLog ] - scrolling event history
|
|
67
|
+
// [ Spinner ] - shown only while streaming
|
|
68
|
+
// [ Permission prompt? ] - blocks input when active
|
|
69
|
+
// [ ─── HRule ]
|
|
70
|
+
// [ CommandInput ] - ❯ prompt
|
|
71
|
+
// [ ─── HRule ]
|
|
72
|
+
// [ StatusBar ] - role/provider/model/session/cwd/tokens
|
|
73
|
+
// [ HintBar ] - key hints
|
|
74
|
+
export function App({ reader, onClose }) {
|
|
75
|
+
const [events, setEvents] = useState([]);
|
|
76
|
+
// Phase 305: repaint nonce. Toggled on every idle flush so the Ink
|
|
77
|
+
// output string changes even when the committed-group count doesn't
|
|
78
|
+
// grow (e.g. consecutive idle event/text events merge into the same
|
|
79
|
+
// Static group). A changed output string guarantees
|
|
80
|
+
// `output !== this.lastOutput` in Ink's else-if branch, which
|
|
81
|
+
// triggers throttledLog and redraws the dynamic chrome.
|
|
82
|
+
const [idleNonce, setIdleNonce] = useState(0);
|
|
83
|
+
const [pending, setPending] = useState([]);
|
|
84
|
+
const [asking, setAsking] = useState([]);
|
|
85
|
+
const [status, setStatus] = useState({ mode: "chat" });
|
|
86
|
+
// Phase 277: authoritative mirror of `status` for synchronous
|
|
87
|
+
// value-comparison in the event/status handler. setStatus is only
|
|
88
|
+
// ever called from that handler, so this ref stays in lockstep.
|
|
89
|
+
const statusRef = useRef(status);
|
|
90
|
+
// Phase 200a (F5.2): streaming label sits in state (changes on
|
|
91
|
+
// stream start/end only). The live char counter lives in a ref so
|
|
92
|
+
// each event/text chunk doesn't bump App's state — that used to
|
|
93
|
+
// re-render the whole tree per chunk and bypassed EventLog's memo.
|
|
94
|
+
// Spinner reads the ref on its own interval tick.
|
|
95
|
+
// Phase 200a (F5.2): streaming label sits in state (changes on
|
|
96
|
+
// stream start/end only). The live char counter lives in a ref so
|
|
97
|
+
// each event/text chunk doesn't bump App's state — that used to
|
|
98
|
+
// re-render the whole tree per chunk and bypassed EventLog's memo.
|
|
99
|
+
// Spinner reads the ref on its own interval tick.
|
|
100
|
+
//
|
|
101
|
+
// Phase 236c: this state still mirrors stream_start/end as before
|
|
102
|
+
// so single-tab callers and the stub renderer keep working without
|
|
103
|
+
// a tabsState snapshot. A follow-up useEffect (below, on
|
|
104
|
+
// status.activeTab change) cross-checks against tabsState — if the
|
|
105
|
+
// destination tab isn't actually running per the per-tab snapshot,
|
|
106
|
+
// we drop the stale streaming state so the spinner doesn't carry
|
|
107
|
+
// the previous tab's label and elapsed time across the switch.
|
|
108
|
+
const [streaming, setStreaming] = useState(null);
|
|
109
|
+
// Phase 304: mirror `streaming` into a ref so flushPending (a stable
|
|
110
|
+
// useCallback) can read the live value without a stale closure — it
|
|
111
|
+
// only nudges an idle redraw when no stream is active.
|
|
112
|
+
const streamingRef = useRef(false);
|
|
113
|
+
streamingRef.current = streaming !== null;
|
|
114
|
+
const streamingCharsRef = useRef(0);
|
|
115
|
+
// Phase 332: the Spinner's current work activity. A ref (like
|
|
116
|
+
// streamingCharsRef) so updating it as the turn moves through
|
|
117
|
+
// thinking → tool → streaming never re-renders App / disturbs the cursor.
|
|
118
|
+
const activityRef = useRef({ kind: "streaming" });
|
|
119
|
+
const [picker, setPicker] = useState(null);
|
|
120
|
+
// Phase 34: thinking visibility toggled by /think. Default visible.
|
|
121
|
+
const [thinkVisible, setThinkVisible] = useState(true);
|
|
122
|
+
// Phase 101: /verbose renders every tool card in full (no collapse).
|
|
123
|
+
const [verbose, setVerbose] = useState(false);
|
|
124
|
+
// Phase 308: /reasoning expands reasoning/thinking blocks inline (live
|
|
125
|
+
// progress) without the full /verbose tool-card blast. Off by default.
|
|
126
|
+
const [reasoningExpanded, setReasoningExpanded] = useState(false);
|
|
127
|
+
// Phase 270: EventLog uses append-only <Static> in normal-screen mode
|
|
128
|
+
// so settled transcript rows go to native terminal scrollback once,
|
|
129
|
+
// while only the live tail repaints. When the source log is replaced
|
|
130
|
+
// (/switch, /clear), bump this key because <Static> is intentionally
|
|
131
|
+
// append-only and indexes by item count.
|
|
132
|
+
const [eventLogResetKey, setEventLogResetKey] = useState(0);
|
|
133
|
+
// Phase 120: predicted next message (opt-in /predict). Shown as a
|
|
134
|
+
// ghost on the empty prompt; cleared when a new turn starts or the
|
|
135
|
+
// user submits.
|
|
136
|
+
const [prediction, setPrediction] = useState("");
|
|
137
|
+
// Phase 272: hardware cursor is safe only after the dynamic Ink
|
|
138
|
+
// layout has settled. In normal-screen transcript mode Ink writes
|
|
139
|
+
// <Static> rows outside the dynamic output, while useCursor
|
|
140
|
+
// positions are relative to that dynamic output. A child-measured
|
|
141
|
+
// cursor origin can therefore be one commit stale while EventLog,
|
|
142
|
+
// Dock, ask/permission pickers, or status chrome changes height.
|
|
143
|
+
// Hide the terminal cursor during those mutation windows and show
|
|
144
|
+
// it again only after one settled frame, matching full-screen TUIs'
|
|
145
|
+
// "draw frame, then place cursor" invariant.
|
|
146
|
+
const [cursorStable, setCursorStable] = useState(true);
|
|
147
|
+
const cursorSettleTimerRef = useRef(null);
|
|
148
|
+
const markCursorLayoutUnstable = useCallback(() => {
|
|
149
|
+
setCursorStable(false);
|
|
150
|
+
if (cursorSettleTimerRef.current) {
|
|
151
|
+
clearTimeout(cursorSettleTimerRef.current);
|
|
152
|
+
}
|
|
153
|
+
cursorSettleTimerRef.current = setTimeout(() => {
|
|
154
|
+
cursorSettleTimerRef.current = null;
|
|
155
|
+
setCursorStable(true);
|
|
156
|
+
}, CURSOR_LAYOUT_SETTLE_MS);
|
|
157
|
+
}, []);
|
|
158
|
+
useEffect(() => () => {
|
|
159
|
+
if (cursorSettleTimerRef.current) {
|
|
160
|
+
clearTimeout(cursorSettleTimerRef.current);
|
|
161
|
+
cursorSettleTimerRef.current = null;
|
|
162
|
+
}
|
|
163
|
+
}, []);
|
|
164
|
+
// Phase 186: latest active tab name in a ref so the reader handler
|
|
165
|
+
// (closure-captured at mount) can compare incoming predictions
|
|
166
|
+
// against the current tab without restating effect deps.
|
|
167
|
+
const activeTabRef = useRef(undefined);
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
markCursorLayoutUnstable();
|
|
170
|
+
activeTabRef.current = status.activeTab;
|
|
171
|
+
// Switching tabs invalidates any in-flight prediction — the new
|
|
172
|
+
// tab will produce its own at its next turn end. Without this, the
|
|
173
|
+
// ghost from the tab we just left would linger on the new prompt.
|
|
174
|
+
setPrediction("");
|
|
175
|
+
// Phase 236c (audit): the streamed-char counter is a global ref.
|
|
176
|
+
// Pre-236c it only reset on `event/stream_start`; if the user
|
|
177
|
+
// switched tabs mid-stream, the counter kept the old tab's value
|
|
178
|
+
// and the new tab's chars piled on top — Spinner showed an
|
|
179
|
+
// inflated number that didn't match either tab. Reset on switch
|
|
180
|
+
// so each tab's spinner starts fresh.
|
|
181
|
+
streamingCharsRef.current = 0;
|
|
182
|
+
// Phase 236c (audit): TodoIndicator's source-of-truth is the most
|
|
183
|
+
// recent TodoWrite. event/tool_use_start from a background tab is
|
|
184
|
+
// already filtered out by pushNotif, but the previous tab's todos
|
|
185
|
+
// lingered after switching. Clear so the destination tab starts
|
|
186
|
+
// empty and re-populates when its next TodoWrite fires.
|
|
187
|
+
setTodos([]);
|
|
188
|
+
// Phase 250 (3rd-round audit): `streaming` (legacy) holds the
|
|
189
|
+
// last stream_start's label. When the user /switches to a tab
|
|
190
|
+
// whose stream_start they never saw (it fired while another tab
|
|
191
|
+
// was active and got filtered), the destination tab's spinner
|
|
192
|
+
// pulled the stale label from this ref. Drop it on every switch
|
|
193
|
+
// so Spinner falls back to its theme default until the next
|
|
194
|
+
// stream_start arrives for the now-active tab. Visibility +
|
|
195
|
+
// startedAt continue to come from tabsState (Phase 236c).
|
|
196
|
+
setStreaming(null);
|
|
197
|
+
// Phase 251 (3rd-round audit): session picker was App-level
|
|
198
|
+
// state (not per-tab). An open picker survived /switch and
|
|
199
|
+
// would render on the wrong tab — selecting a session there
|
|
200
|
+
// would rebuild THIS tab's adapter, not the originally-asking
|
|
201
|
+
// tab. Dismiss on switch + notify cli to clear its pending
|
|
202
|
+
// picker side-state.
|
|
203
|
+
setPicker((cur) => {
|
|
204
|
+
if (cur)
|
|
205
|
+
sendPickerClose();
|
|
206
|
+
return null;
|
|
207
|
+
});
|
|
208
|
+
}, [status.activeTab, markCursorLayoutUnstable]);
|
|
209
|
+
// Phase 81: active theme. The theme module owns the actual color
|
|
210
|
+
// state (components read theme.x.y at render); this state exists
|
|
211
|
+
// only to force the re-render after setTheme mutates the colors.
|
|
212
|
+
const [themeName, setThemeName] = useState("dark");
|
|
213
|
+
// Phase 98: latest TodoWrite tool input. The in-progress task is
|
|
214
|
+
// rendered above the prompt so the user can see what the agent is
|
|
215
|
+
// working on at a glance.
|
|
216
|
+
const [todos, setTodos] = useState([]);
|
|
217
|
+
const handleSetTheme = useCallback((next) => {
|
|
218
|
+
markCursorLayoutUnstable();
|
|
219
|
+
setTheme(next);
|
|
220
|
+
setThemeName(next);
|
|
221
|
+
}, [markCursorLayoutUnstable]);
|
|
222
|
+
const { isRawModeSupported } = useStdin();
|
|
223
|
+
const { stdout } = useStdout();
|
|
224
|
+
const rawModeSupported = Boolean(isRawModeSupported);
|
|
225
|
+
// Phase 236b: PageUp/PageDown slide a viewport over EventLog's
|
|
226
|
+
// grouped event list. `scrollOffset = 0` keeps the latest groups
|
|
227
|
+
// anchored at the bottom (default sticky-bottom). PageUp grows the
|
|
228
|
+
// offset → older groups come into view from the bottom of the
|
|
229
|
+
// window. Reset to 0 on tab switch (log_replace, below) so each tab
|
|
230
|
+
// starts at its newest event.
|
|
231
|
+
const [scrollOffset, setScrollOffset] = useState(0);
|
|
232
|
+
const SCROLL_PAGE = 10;
|
|
233
|
+
const SCROLL_WHEEL = 3;
|
|
234
|
+
useInput((input, key) => {
|
|
235
|
+
const mouseWheel = parseMouseWheel(input);
|
|
236
|
+
if (mouseWheel) {
|
|
237
|
+
markCursorLayoutUnstable();
|
|
238
|
+
setScrollOffset((offset) => mouseWheel.direction === "up"
|
|
239
|
+
? offset + SCROLL_WHEEL
|
|
240
|
+
: Math.max(0, offset - SCROLL_WHEEL));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (key.pageUp) {
|
|
244
|
+
markCursorLayoutUnstable();
|
|
245
|
+
setScrollOffset((o) => o + SCROLL_PAGE);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (key.pageDown) {
|
|
249
|
+
markCursorLayoutUnstable();
|
|
250
|
+
setScrollOffset((o) => Math.max(0, o - SCROLL_PAGE));
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
}, { isActive: rawModeSupported });
|
|
254
|
+
// Phase 148: batch streamed event appends. A turn emits many tiny
|
|
255
|
+
// event/text chunks; appending each one immediately re-rendered (and
|
|
256
|
+
// re-grouped) the whole log per chunk, and Ink repainted the live
|
|
257
|
+
// region in place — read as flicker. We coalesce appends and flush at
|
|
258
|
+
// ~30fps, so the heavy EventLog re-renders at most ~30×/s regardless
|
|
259
|
+
// of chunk rate.
|
|
260
|
+
const pendingRef = useRef([]);
|
|
261
|
+
const flushTimerRef = useRef(null);
|
|
262
|
+
// Phase 248 (2nd-round audit): mirror the cli-side EVENTS_CAP from
|
|
263
|
+
// Phase 240. The cli caps t.events for memory, but App.events grew
|
|
264
|
+
// unbounded between /switches because each batch flush only
|
|
265
|
+
// appends. A single-tab session that never switches would balloon
|
|
266
|
+
// App.events indefinitely and eat heap with every streamed chunk.
|
|
267
|
+
// Trim from the front when we cross the cap; matches cli-side
|
|
268
|
+
// behavior so /switch round-trips don't appear to "shrink" the
|
|
269
|
+
// displayed history compared to live state.
|
|
270
|
+
const flushPending = useCallback(() => {
|
|
271
|
+
if (flushTimerRef.current) {
|
|
272
|
+
clearTimeout(flushTimerRef.current);
|
|
273
|
+
flushTimerRef.current = null;
|
|
274
|
+
}
|
|
275
|
+
if (pendingRef.current.length === 0)
|
|
276
|
+
return;
|
|
277
|
+
const batch = pendingRef.current;
|
|
278
|
+
pendingRef.current = [];
|
|
279
|
+
setEvents((prev) => {
|
|
280
|
+
const next = [...prev, ...batch];
|
|
281
|
+
// Phase 295: only the alt-screen bounded viewport front-trims here.
|
|
282
|
+
// Transcript mode must NOT — front-trimming the array <Static> reads
|
|
283
|
+
// breaks its append-only watermark, so Ink re-emits the tail and the
|
|
284
|
+
// terminal jumps (worse the longer the session). Transcript memory is
|
|
285
|
+
// bounded by the idle checkpoint effect instead.
|
|
286
|
+
if (wantsAltScreen() && next.length > EVENTS_CAP) {
|
|
287
|
+
next.splice(0, EVENTS_TRIM);
|
|
288
|
+
}
|
|
289
|
+
return next;
|
|
290
|
+
});
|
|
291
|
+
// Phase 304: when IDLE (no active stream), nudge a dynamic-region
|
|
292
|
+
// redraw. A lone idle append renders only the <Static> rows — Ink's
|
|
293
|
+
// static path clears the dynamic region (input/status) and skips
|
|
294
|
+
// redrawing it because the dynamic output string is unchanged, so the
|
|
295
|
+
// new text shows but the chrome blanks until the next state change
|
|
296
|
+
// (which is why /preset output only appeared after the user typed).
|
|
297
|
+
// markCursorLayoutUnstable flips a flag that changes the dynamic
|
|
298
|
+
// output → forces the redraw. Skipped while streaming: the spinner's
|
|
299
|
+
// heartbeat already repaints, and flipping the cursor flag mid-stream
|
|
300
|
+
// reintroduces the IME-compose flicker appendEvent deliberately avoids.
|
|
301
|
+
if (!streamingRef.current) {
|
|
302
|
+
// Phase 305: increment the repaint nonce so the Ink output string
|
|
303
|
+
// changes unconditionally, ensuring throttledLog rewrites the
|
|
304
|
+
// dynamic chrome even when the committed-group count is unchanged
|
|
305
|
+
// (consecutive idle event/text events merge into the same group).
|
|
306
|
+
setIdleNonce((n) => n + 1);
|
|
307
|
+
// Keep the cursor settle: suppresses then restores the hardware
|
|
308
|
+
// cursor so useCursor's position is re-measured after the static
|
|
309
|
+
// write rather than holding a stale Yoga origin.
|
|
310
|
+
markCursorLayoutUnstable();
|
|
311
|
+
}
|
|
312
|
+
}, [markCursorLayoutUnstable]);
|
|
313
|
+
const appendEvent = useCallback((msg) => {
|
|
314
|
+
// Transcript-only appends must not continually invalidate the
|
|
315
|
+
// bottom cursor while the agent streams. In alt-screen mode the
|
|
316
|
+
// EventLog is a bounded viewport above the anchored composer, so
|
|
317
|
+
// text growth does not move the input row. Layout-affecting
|
|
318
|
+
// chrome transitions (stream start/end, status, pickers, todos,
|
|
319
|
+
// tab switches) call markCursorLayoutUnstable at their source.
|
|
320
|
+
pendingRef.current.push(msg);
|
|
321
|
+
if (!flushTimerRef.current) {
|
|
322
|
+
flushTimerRef.current = setTimeout(() => {
|
|
323
|
+
flushTimerRef.current = null;
|
|
324
|
+
flushPending();
|
|
325
|
+
}, 32);
|
|
326
|
+
}
|
|
327
|
+
}, [flushPending]);
|
|
328
|
+
// Flush any batched appends on unmount so nothing is lost.
|
|
329
|
+
useEffect(() => () => flushPending(), [flushPending]);
|
|
330
|
+
useEffect(() => {
|
|
331
|
+
reader.onMessage((msg) => {
|
|
332
|
+
if (isAskRequest(msg)) {
|
|
333
|
+
markCursorLayoutUnstable();
|
|
334
|
+
setAsking((prev) => [...prev, msg]);
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (isPermissionRequest(msg)) {
|
|
338
|
+
markCursorLayoutUnstable();
|
|
339
|
+
setPending((prev) => [...prev, msg]);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
// Status updates merge in; never go into the log.
|
|
343
|
+
if (msg.method === "event/status") {
|
|
344
|
+
// Phase 277: status pushes must not gratuitously disturb the
|
|
345
|
+
// hardware cursor, or macOS IME drops the Hangul compose to the
|
|
346
|
+
// bottom info bar whenever one lands mid-keystroke.
|
|
347
|
+
//
|
|
348
|
+
// Two guards:
|
|
349
|
+
// 1. Skip entirely when the delta is value-identical (e.g. the
|
|
350
|
+
// 5s git refresh on an unchanged tree) — avoids a needless
|
|
351
|
+
// re-render + cursor settle while fully idle.
|
|
352
|
+
// 2. Only call markCursorLayoutUnstable() when a field that
|
|
353
|
+
// actually changes chrome HEIGHT changed. `plan`/`ask`
|
|
354
|
+
// toggle the TabChip row above the input, so they move it;
|
|
355
|
+
// everything else (git, tokensIn/Out, tabsState counts,
|
|
356
|
+
// model, ctx, sessionId…) renders into fixed-height chrome
|
|
357
|
+
// and leaves the input row put. During a stream the cli
|
|
358
|
+
// pushes token/tabsState updates constantly — marking on
|
|
359
|
+
// those hid the cursor over and over, which is exactly what
|
|
360
|
+
// bounced the IME compose to the info bar. Spinner/team
|
|
361
|
+
// panel height transitions are still settled by their own
|
|
362
|
+
// handlers (stream_start/stream_end, todos, pickers).
|
|
363
|
+
const params = msg.params;
|
|
364
|
+
const cur = statusRef.current;
|
|
365
|
+
let changed = false;
|
|
366
|
+
let layoutChanged = false;
|
|
367
|
+
for (const k of Object.keys(params)) {
|
|
368
|
+
if (statusValueEqual(cur[k], params[k]))
|
|
369
|
+
continue;
|
|
370
|
+
changed = true;
|
|
371
|
+
if (k === "plan" || k === "ask")
|
|
372
|
+
layoutChanged = true;
|
|
373
|
+
}
|
|
374
|
+
if (!changed)
|
|
375
|
+
return;
|
|
376
|
+
const next = { ...statusRef.current, ...msg.params };
|
|
377
|
+
statusRef.current = next;
|
|
378
|
+
if (layoutChanged)
|
|
379
|
+
markCursorLayoutUnstable();
|
|
380
|
+
setStatus(next);
|
|
381
|
+
// Phase 332: while a team pipeline runs, the spinner shows the team
|
|
382
|
+
// phase (the per-role TeamStatusPanel carries the detail). Cleared
|
|
383
|
+
// when teamPhase empties.
|
|
384
|
+
const tp = typeof next.teamPhase === "string" ? next.teamPhase : "";
|
|
385
|
+
if (tp)
|
|
386
|
+
activityRef.current = { kind: "team", detail: tp };
|
|
387
|
+
else if (activityRef.current.kind === "team")
|
|
388
|
+
activityRef.current = { kind: "streaming" };
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
if (msg.method === "event/stream_start") {
|
|
392
|
+
markCursorLayoutUnstable();
|
|
393
|
+
streamingCharsRef.current = 0;
|
|
394
|
+
// Phase 332: seed the activity from the start label so the spinner
|
|
395
|
+
// shows the work type immediately (then tool/thinking events refine).
|
|
396
|
+
const lbl = msg.params.label;
|
|
397
|
+
activityRef.current =
|
|
398
|
+
lbl === "compacting"
|
|
399
|
+
? { kind: "compacting" }
|
|
400
|
+
: lbl === "handing off"
|
|
401
|
+
? { kind: "handoff" }
|
|
402
|
+
: { kind: "streaming" };
|
|
403
|
+
setStreaming({ label: msg.params.label });
|
|
404
|
+
// Phase 120: a new turn invalidates any pending prediction.
|
|
405
|
+
setPrediction("");
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (msg.method === "event/predict") {
|
|
409
|
+
// Phase 120 + 186: transient — never recorded into the log.
|
|
410
|
+
// Drop predictions tagged with a tab that isn't the active one
|
|
411
|
+
// so a background tab's ghost can't leak into another tab's
|
|
412
|
+
// input prompt.
|
|
413
|
+
const owning = msg.params.tabName;
|
|
414
|
+
const active = activeTabRef.current;
|
|
415
|
+
if (owning && active && owning !== active)
|
|
416
|
+
return;
|
|
417
|
+
setPrediction(msg.params.text);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
if (msg.method === "event/stream_end" || msg.method === "event/end") {
|
|
421
|
+
markCursorLayoutUnstable();
|
|
422
|
+
setStreaming(null);
|
|
423
|
+
if (msg.method === "event/end") {
|
|
424
|
+
appendEvent(msg);
|
|
425
|
+
}
|
|
426
|
+
// Turn boundary — show the final state immediately, no lag.
|
|
427
|
+
flushPending();
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (msg.method === "event/text") {
|
|
431
|
+
// Phase 94 / Phase 200a: tally streamed text for the Spinner's
|
|
432
|
+
// progress readout. Lives in a ref — the Spinner reads it on
|
|
433
|
+
// its own 80ms interval tick, so the per-chunk append doesn't
|
|
434
|
+
// need to bump App state.
|
|
435
|
+
const text = typeof msg.params?.text === "string" ? msg.params.text : "";
|
|
436
|
+
if (text)
|
|
437
|
+
streamingCharsRef.current += text.length;
|
|
438
|
+
// Phase 332: text arriving = the model is producing its reply.
|
|
439
|
+
// Don't clobber a non-turn activity (compaction streams text too).
|
|
440
|
+
// Phase 336: do NOT flip a running "tool" back to streaming on text
|
|
441
|
+
// — a long build keeps its "building…" label until tool_use_end
|
|
442
|
+
// resets it. (Pre-336 a stray text chunk mid-tool reset the label to
|
|
443
|
+
// the bare model name, so a 7-min docker build read as "codex-cli
|
|
444
|
+
// gpt-5.5…" instead of "building…".) thinking→streaming still flips.
|
|
445
|
+
if (text && activityRef.current.kind === "thinking") {
|
|
446
|
+
activityRef.current = { kind: "streaming" };
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (msg.method === "event/stream_progress") {
|
|
450
|
+
// Phase 318: compaction streams its summary in-process, so its
|
|
451
|
+
// output never hits event/text. Mirror the cumulative char count
|
|
452
|
+
// here so the "compacting…" Spinner shows real "↓ Ntok" motion.
|
|
453
|
+
// Set (not add) — the count is already cumulative. The Spinner
|
|
454
|
+
// reads the ref on its own tick, so no App re-render needed.
|
|
455
|
+
const chars = typeof msg.params?.chars === "number" ? msg.params.chars : 0;
|
|
456
|
+
streamingCharsRef.current = chars;
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
// Phase 332: reflect the running tool in the spinner — esp. a long
|
|
460
|
+
// foreground build, which otherwise looks like a hang. TodoWrite is a
|
|
461
|
+
// meta tool (it has its own indicator) so it doesn't change activity.
|
|
462
|
+
if (msg.method === "event/tool_use_start") {
|
|
463
|
+
const tname = typeof msg.params?.name === "string" ? msg.params.name : "";
|
|
464
|
+
if (tname && tname !== "TodoWrite") {
|
|
465
|
+
// Phase 336: extract the command for ANY shell tool that carries
|
|
466
|
+
// one — not just claude's "Bash". codex's "shell"/run_shell and
|
|
467
|
+
// gemini's shell all put it in input.command, so before this they
|
|
468
|
+
// showed a bare "shell…" with no hint what was running.
|
|
469
|
+
const tin = msg.params?.input;
|
|
470
|
+
const cmd = typeof tin?.command === "string"
|
|
471
|
+
? tin.command.replace(/\s+/g, " ").trim()
|
|
472
|
+
: "";
|
|
473
|
+
// Phase 336: a recognizable build/test/install/deploy reads as a
|
|
474
|
+
// verb ("building…") rather than a raw command — clearer while
|
|
475
|
+
// omg just waits on a long external build. Otherwise show the cmd.
|
|
476
|
+
const verb = cmd ? shellActivityVerb(cmd) : null;
|
|
477
|
+
const detail = verb
|
|
478
|
+
? verb
|
|
479
|
+
: cmd
|
|
480
|
+
? `${tname}: ${cmd.length > 48 ? cmd.slice(0, 47) + "…" : cmd}`
|
|
481
|
+
: tname;
|
|
482
|
+
activityRef.current = { kind: "tool", detail };
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (msg.method === "event/tool_use_end") {
|
|
486
|
+
// Tool finished → back to the model's reply (until the next signal).
|
|
487
|
+
if (activityRef.current.kind === "tool") {
|
|
488
|
+
activityRef.current = { kind: "streaming" };
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
if (msg.method === "event/thinking" &&
|
|
492
|
+
activityRef.current.kind !== "tool") {
|
|
493
|
+
activityRef.current = { kind: "thinking" };
|
|
494
|
+
}
|
|
495
|
+
// Phase 98: capture TodoWrite calls so the in-progress task
|
|
496
|
+
// can render under the spinner. The host CLI's tool name is
|
|
497
|
+
// "TodoWrite"; input shape is { todos: [{content, status, activeForm}] }.
|
|
498
|
+
if (msg.method === "event/tool_use_start" &&
|
|
499
|
+
msg.params?.name === "TodoWrite") {
|
|
500
|
+
const raw = msg.params.input?.todos;
|
|
501
|
+
if (Array.isArray(raw)) {
|
|
502
|
+
const parsed = [];
|
|
503
|
+
for (const t of raw) {
|
|
504
|
+
if (typeof t !== "object" || t === null)
|
|
505
|
+
continue;
|
|
506
|
+
const obj = t;
|
|
507
|
+
const content = typeof obj.content === "string" ? obj.content : "";
|
|
508
|
+
const status = obj.status;
|
|
509
|
+
const activeForm = typeof obj.activeForm === "string" ? obj.activeForm : undefined;
|
|
510
|
+
if (content &&
|
|
511
|
+
(status === "pending" ||
|
|
512
|
+
status === "in_progress" ||
|
|
513
|
+
status === "completed")) {
|
|
514
|
+
parsed.push({ content, status, activeForm });
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
markCursorLayoutUnstable();
|
|
518
|
+
setTodos(parsed);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (msg.method === "event/session_picker") {
|
|
522
|
+
markCursorLayoutUnstable();
|
|
523
|
+
setPicker({
|
|
524
|
+
provider: msg.params.provider,
|
|
525
|
+
sessions: msg.params.sessions,
|
|
526
|
+
});
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
if (msg.method === "event/log_replace") {
|
|
530
|
+
// Phase 47: a tab switch wants to swap the whole log. Replace
|
|
531
|
+
// wholesale in one render; Static commits past entries
|
|
532
|
+
// anyway, so this looks like one repaint.
|
|
533
|
+
// Phase 148: drop any batched appends queued for the tab we're
|
|
534
|
+
// leaving — the replacement is the new tab's full history.
|
|
535
|
+
// Phase 247 (2nd-round audit): clone the inbound array. The
|
|
536
|
+
// cli side passes `t.events` by reference. If we stored that
|
|
537
|
+
// reference in React state, the next pushNotif's
|
|
538
|
+
// `target.events.push(n)` would mutate the array React still
|
|
539
|
+
// believes is its state — and the very next flushPending's
|
|
540
|
+
// `setEvents(prev => [...prev, ...batch])` would see `prev`
|
|
541
|
+
// already containing `n` (from the mutation), then re-append
|
|
542
|
+
// `n` (from `batch`). Result: every event arriving within the
|
|
543
|
+
// first 32ms batch window after a /switch rendered TWICE in
|
|
544
|
+
// the chat. Cloning here decouples App.events from t.events
|
|
545
|
+
// so neither side mutates the other's view.
|
|
546
|
+
if (flushTimerRef.current) {
|
|
547
|
+
clearTimeout(flushTimerRef.current);
|
|
548
|
+
flushTimerRef.current = null;
|
|
549
|
+
}
|
|
550
|
+
markCursorLayoutUnstable();
|
|
551
|
+
pendingRef.current = [];
|
|
552
|
+
setEvents([...msg.params.events]);
|
|
553
|
+
setEventLogResetKey((k) => k + 1);
|
|
554
|
+
// Phase 236b: switching tabs resets the scroll viewport. The
|
|
555
|
+
// user's "where I was reading" is per-tab and Phase 236e will
|
|
556
|
+
// restore it; for now snap to the destination tab's latest.
|
|
557
|
+
setScrollOffset(0);
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
appendEvent(msg);
|
|
561
|
+
});
|
|
562
|
+
if (onClose)
|
|
563
|
+
reader.onClose(onClose);
|
|
564
|
+
}, [reader, onClose, appendEvent, flushPending, markCursorLayoutUnstable]);
|
|
565
|
+
const addLocalText = useCallback((text) => {
|
|
566
|
+
markCursorLayoutUnstable();
|
|
567
|
+
flushPending(); // keep ordering with any batched stream output
|
|
568
|
+
setEvents((prev) => [
|
|
569
|
+
...prev,
|
|
570
|
+
{
|
|
571
|
+
jsonrpc: "2.0",
|
|
572
|
+
method: "event/text",
|
|
573
|
+
params: { text },
|
|
574
|
+
},
|
|
575
|
+
]);
|
|
576
|
+
}, [flushPending, markCursorLayoutUnstable]);
|
|
577
|
+
// Phase 115 → 225 (hotfix, root cause): the actual user_echo event
|
|
578
|
+
// now ships from cli.ts via pushNotif so tab.events is the source
|
|
579
|
+
// of truth — App still receives it through the normal ink stream
|
|
580
|
+
// and lands it via appendEvent. Pre-225 this callback inserted the
|
|
581
|
+
// echo into App's local events directly; tab.events never got it,
|
|
582
|
+
// and /switch's log_replace wiped the echo on return. We keep the
|
|
583
|
+
// hook so prediction is cleared on submit (transient UI concern
|
|
584
|
+
// that doesn't belong in cli.ts).
|
|
585
|
+
const addUserMessage = useCallback((_text) => {
|
|
586
|
+
markCursorLayoutUnstable();
|
|
587
|
+
flushPending();
|
|
588
|
+
setPrediction(""); // Phase 120: submitting consumes the prediction.
|
|
589
|
+
}, [flushPending, markCursorLayoutUnstable]);
|
|
590
|
+
const dequeueRequest = useCallback(() => {
|
|
591
|
+
markCursorLayoutUnstable();
|
|
592
|
+
setPending((prev) => prev.slice(1));
|
|
593
|
+
}, [markCursorLayoutUnstable]);
|
|
594
|
+
const dequeueAsk = useCallback(() => {
|
|
595
|
+
markCursorLayoutUnstable();
|
|
596
|
+
setAsking((prev) => prev.slice(1));
|
|
597
|
+
}, [markCursorLayoutUnstable]);
|
|
598
|
+
const clearEvents = useCallback(() => {
|
|
599
|
+
markCursorLayoutUnstable();
|
|
600
|
+
if (flushTimerRef.current) {
|
|
601
|
+
clearTimeout(flushTimerRef.current);
|
|
602
|
+
flushTimerRef.current = null;
|
|
603
|
+
}
|
|
604
|
+
pendingRef.current = [];
|
|
605
|
+
setEvents([]);
|
|
606
|
+
setTodos([]);
|
|
607
|
+
setEventLogResetKey((k) => k + 1);
|
|
608
|
+
}, [markCursorLayoutUnstable]);
|
|
609
|
+
const toggleThink = useCallback((force) => {
|
|
610
|
+
markCursorLayoutUnstable();
|
|
611
|
+
setThinkVisible((prev) => {
|
|
612
|
+
const next = force === undefined ? !prev : force;
|
|
613
|
+
// Echo state into the log so the change is visible in scrollback.
|
|
614
|
+
setEvents((es) => [
|
|
615
|
+
...es,
|
|
616
|
+
{
|
|
617
|
+
jsonrpc: "2.0",
|
|
618
|
+
method: "event/text",
|
|
619
|
+
params: {
|
|
620
|
+
text: next
|
|
621
|
+
? "[think] ON — reasoning blocks will render.\n"
|
|
622
|
+
: "[think] off — reasoning blocks hidden.\n",
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
]);
|
|
626
|
+
return next;
|
|
627
|
+
});
|
|
628
|
+
}, [markCursorLayoutUnstable]);
|
|
629
|
+
const head = pending[0];
|
|
630
|
+
const askHead = asking[0];
|
|
631
|
+
// Phase 236c: tabsState is the per-tab source-of-truth for running
|
|
632
|
+
// state. Pre-236c App.streaming was a free-floating mirror of the
|
|
633
|
+
// last stream_start/end on this stdin; on a tab switch it kept the
|
|
634
|
+
// prior tab's label + (via a useRef) startedAt and the spinner
|
|
635
|
+
// showed "1m 13s" on a tab that just opened. We splice tabsState
|
|
636
|
+
// back in by:
|
|
637
|
+
// - reading the active tab's runningSince and forwarding it to
|
|
638
|
+
// Spinner so the elapsed counter resets per tab;
|
|
639
|
+
// - using `streamingFromTab` (below) when the local mirror is
|
|
640
|
+
// out of sync — if tabsState says the active tab isn't running,
|
|
641
|
+
// hide the spinner regardless of stale App.streaming. This
|
|
642
|
+
// handles the case where the destination tab is idle but the
|
|
643
|
+
// source tab is still emitting events App can't see.
|
|
644
|
+
const activeTabState = status.tabsState?.find((t) => t.name === status.activeTab);
|
|
645
|
+
const tabRunning = activeTabState?.running ?? null;
|
|
646
|
+
// If tabsState is unavailable (no status push yet, stub renderer,
|
|
647
|
+
// standalone unit tests) fall back to App.streaming — back-compat
|
|
648
|
+
// with the pre-236c mental model.
|
|
649
|
+
const streamingVisible = tabRunning === null ? streaming !== null : tabRunning;
|
|
650
|
+
const streamingForDock = streamingVisible
|
|
651
|
+
? {
|
|
652
|
+
label: streaming?.label,
|
|
653
|
+
startedAt: activeTabState?.runningSince,
|
|
654
|
+
}
|
|
655
|
+
: null;
|
|
656
|
+
const altScreenMode = wantsAltScreen() && Boolean(stdout?.isTTY);
|
|
657
|
+
// Phase 295: transcript-mode memory checkpoint. Runs post-commit, so at
|
|
658
|
+
// an idle boundary the final group of the just-ended turn is already
|
|
659
|
+
// emitted to native scrollback (stream_end flushPending()s synchronously
|
|
660
|
+
// before this). Dropping the React log + remounting <Static> with a
|
|
661
|
+
// fresh key re-emits nothing (no dupe, no jump) and resets memory.
|
|
662
|
+
useEffect(() => {
|
|
663
|
+
if (!shouldCheckpointTranscript({
|
|
664
|
+
altScreenMode,
|
|
665
|
+
streaming: streaming !== null,
|
|
666
|
+
eventsLength: events.length,
|
|
667
|
+
cap: TRANSCRIPT_EVENTS_SOFTCAP,
|
|
668
|
+
})) {
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
setEvents([]);
|
|
672
|
+
setEventLogResetKey((k) => k + 1);
|
|
673
|
+
}, [altScreenMode, streaming, events.length]);
|
|
674
|
+
const rootHeight = altScreenMode && typeof stdout?.rows === "number" && stdout.rows > 0
|
|
675
|
+
? stdout.rows
|
|
676
|
+
: undefined;
|
|
677
|
+
// Cursor invariant: only place the terminal cursor after the final
|
|
678
|
+
// frame layout is stable. Codex/ratatui draws the frame and sets the
|
|
679
|
+
// cursor from the same resolved layout; Ink's useCursor needs the
|
|
680
|
+
// previous render's Yoga origin, so Dock/status/input-height
|
|
681
|
+
// transitions can be one frame stale. Hide during those short
|
|
682
|
+
// mutation windows in every screen mode.
|
|
683
|
+
//
|
|
684
|
+
// Phase 277: do NOT hard-hide the input cursor for the whole stream
|
|
685
|
+
// in normal-screen mode. The live tail grows while the agent works,
|
|
686
|
+
// nudging the input row down each frame — so the older code hid the
|
|
687
|
+
// cursor outright to avoid it chasing a stale row. But a user who
|
|
688
|
+
// types DURING a stream (queuing a message) needs the hardware
|
|
689
|
+
// cursor parked at the input, or macOS IME draws the Hangul compose
|
|
690
|
+
// preview at the cursor's resting position — below the HintBar.
|
|
691
|
+
// `suppressEmptyInputCursor` already hides the cursor while the input
|
|
692
|
+
// is empty (nothing to compose), so streaming-with-empty-input stays
|
|
693
|
+
// jitter-free; once the buffer is non-empty the cursor follows the
|
|
694
|
+
// input (origin is re-measured per render) so IME lands in the box.
|
|
695
|
+
const suppressInputHardwareCursor = !cursorStable;
|
|
696
|
+
const suppressEmptyInputCursor = !altScreenMode && streamingVisible;
|
|
697
|
+
const transcript = (_jsxs(_Fragment, { children: [events.length === 0 && (_jsx(Welcome, { provider: status.provider, model: status.model, cwd: status.cwd })), _jsx(EventLog, { events: events, thinkVisible: thinkVisible, reasoningExpanded: reasoningExpanded, streaming: streamingVisible, verbose: verbose, scrollOffset: scrollOffset, transcriptMode: !altScreenMode, transcriptResetKey: eventLogResetKey,
|
|
698
|
+
// Codex-style UX keeps the visible cursor owned by the bottom
|
|
699
|
+
// composer. A moving assistant-tail block in the transcript
|
|
700
|
+
// reads like the chat cursor jumping while the agent works.
|
|
701
|
+
showLiveCursor: false })] }));
|
|
702
|
+
return (_jsxs(Box, { flexDirection: "column", height: rootHeight, overflowY: altScreenMode ? "hidden" : "visible", children: [altScreenMode ? (_jsx(Box, { flexDirection: "column", flexGrow: 1, flexShrink: 1, justifyContent: "flex-end", overflowY: "hidden", children: transcript })) : (transcript), _jsx(Dock, { status: status, streaming: streamingForDock, streamedCharsRef: streamingCharsRef, activityRef: activityRef, todos: todos, askHead: askHead, permHead: head, sessionPicker: picker, isRawModeSupported: rawModeSupported, stableActivityHeight: altScreenMode, onAskResolved: dequeueAsk, onPermResolved: dequeueRequest, onSessionPickerClose: () => {
|
|
703
|
+
markCursorLayoutUnstable();
|
|
704
|
+
setPicker(null);
|
|
705
|
+
} }), _jsx(HRule, { ...upperRuleLabel(status) }), altScreenMode ? (_jsx(Box, { height: 1, overflowY: "hidden", children: _jsx(TabChip, { planMode: status.plan, askMode: status.ask, thinkVisible: thinkVisible }) })) : (_jsx(TabChip, { planMode: status.plan, askMode: status.ask, thinkVisible: thinkVisible })), rawModeSupported && !head && !askHead && !picker && (_jsx(CommandInput, { onLocalLine: addLocalText, onClearEvents: clearEvents, onToggleThink: toggleThink, cwd: status.cwd, onSetTheme: handleSetTheme, onUserMessage: addUserMessage, prediction: prediction, suppressCursorWhenEmpty: suppressEmptyInputCursor, suppressHardwareCursor: suppressInputHardwareCursor, fullscreenCursorMode: altScreenMode, onToggleVerbose: (force) => setVerbose((prev) => {
|
|
706
|
+
markCursorLayoutUnstable();
|
|
707
|
+
const next = force === undefined ? !prev : force;
|
|
708
|
+
addLocalText(next
|
|
709
|
+
? "[verbose] ON — tool cards show full output."
|
|
710
|
+
: "[verbose] off — tool cards collapse again.");
|
|
711
|
+
return next;
|
|
712
|
+
}), onToggleReasoning: (force) => setReasoningExpanded((prev) => {
|
|
713
|
+
markCursorLayoutUnstable();
|
|
714
|
+
const next = force === undefined ? !prev : force;
|
|
715
|
+
addLocalText(next
|
|
716
|
+
? "[reasoning] ON — reasoning shows expanded live (progress)."
|
|
717
|
+
: "[reasoning] off — reasoning collapses to a header.");
|
|
718
|
+
return next;
|
|
719
|
+
}) }, `input-${themeName}`)), _jsx(HRule, {}), altScreenMode ? (_jsx(Box, { height: 2, overflowY: "hidden", children: _jsx(StatusBar, { status: { ...status, thinkVisible } }) })) : (_jsx(StatusBar, { status: { ...status, thinkVisible } })), _jsxs(Box, { height: 1, overflowY: "hidden", children: [_jsx(HintBar, {}), _jsx(Text, { children: idleNonce % 2 ? "" : "" })] })] }));
|
|
720
|
+
}
|
|
721
|
+
/** Phase 199 → 230: compose the upper-HRule chip from the status
|
|
722
|
+
* snapshot. Phase 230 redesign — show ALL tab names as colored
|
|
723
|
+
* segments (active = green, running = animated spinner glyph, ready
|
|
724
|
+
* = `▒`, asking = `?`), plus the ctx-pressure warning when active.
|
|
725
|
+
* Returns segment list for HRule's multi-color renderer. */
|
|
726
|
+
const TAB_NAME_MAX = 10;
|
|
727
|
+
function truncTab(name) {
|
|
728
|
+
if ([...name].length <= TAB_NAME_MAX)
|
|
729
|
+
return name;
|
|
730
|
+
return name.slice(0, TAB_NAME_MAX - 1) + "…";
|
|
731
|
+
}
|
|
732
|
+
function upperRuleLabel(status) {
|
|
733
|
+
const segs = [];
|
|
734
|
+
const tabs = status.tabsState ?? [];
|
|
735
|
+
const chipFg = theme.prompt.chipFg;
|
|
736
|
+
// Phase 230: every tab gets a segment. Active tab in green
|
|
737
|
+
// (status.tabColor / readyColor), running tabs prefixed by an
|
|
738
|
+
// animated spinner glyph, ready tabs by `▒`, asking by `?`. Idle
|
|
739
|
+
// background tabs render in default chip color so the eye still
|
|
740
|
+
// sees them but they don't compete for attention.
|
|
741
|
+
for (let i = 0; i < tabs.length; i++) {
|
|
742
|
+
if (i > 0) {
|
|
743
|
+
segs.push({ text: " · ", color: chipFg });
|
|
744
|
+
}
|
|
745
|
+
const t = tabs[i];
|
|
746
|
+
const isActive = t.name === status.activeTab;
|
|
747
|
+
if (t.running && !isActive) {
|
|
748
|
+
// Animated spinner glyph; HRule's own timer cycles it. We pass
|
|
749
|
+
// a placeholder text — HRule overrides with the current frame.
|
|
750
|
+
segs.push({
|
|
751
|
+
text: "⠋",
|
|
752
|
+
color: theme.spinner.color,
|
|
753
|
+
spinner: true,
|
|
754
|
+
});
|
|
755
|
+
segs.push({ text: " " + truncTab(t.name), color: chipFg });
|
|
756
|
+
}
|
|
757
|
+
else if (t.asking && !isActive) {
|
|
758
|
+
segs.push({ text: "? ", color: theme.status.askColor, bold: true });
|
|
759
|
+
segs.push({ text: truncTab(t.name), color: chipFg });
|
|
760
|
+
}
|
|
761
|
+
else if (t.ready && !isActive) {
|
|
762
|
+
segs.push({ text: "▒ ", color: theme.status.readyColor });
|
|
763
|
+
segs.push({ text: truncTab(t.name), color: chipFg });
|
|
764
|
+
}
|
|
765
|
+
else if (isActive) {
|
|
766
|
+
// Active tab in the readyColor green so "where am I" is the
|
|
767
|
+
// strongest visual signal in the chip. Bold further pops it.
|
|
768
|
+
segs.push({
|
|
769
|
+
text: truncTab(t.name),
|
|
770
|
+
color: theme.status.readyColor,
|
|
771
|
+
bold: true,
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
775
|
+
// Idle non-active tab — dim color so the eye treats it as
|
|
776
|
+
// available-but-quiet.
|
|
777
|
+
segs.push({ text: truncTab(t.name), color: theme.status.labelColor });
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
// Phase 190/222: ctx warning piggybacks on the chip when occupancy
|
|
781
|
+
// is high. Cap display at "100%+" so a stale or wrongly-attributed
|
|
782
|
+
// token count doesn't surface "ctx 147%".
|
|
783
|
+
if (status.tokensIn && status.contextWindow && status.contextWindow > 0) {
|
|
784
|
+
const ratio = status.tokensIn / status.contextWindow;
|
|
785
|
+
if (ratio >= 0.7) {
|
|
786
|
+
const pct = Math.round(ratio * 100);
|
|
787
|
+
const label = pct > 100 ? "⚠ ctx 100%+" : `⚠ ctx ${pct}%`;
|
|
788
|
+
const ctxColor = ratio >= 0.9
|
|
789
|
+
? theme.status.tokenCritColor
|
|
790
|
+
: theme.status.tokenWarnColor;
|
|
791
|
+
if (segs.length > 0)
|
|
792
|
+
segs.push({ text: " · ", color: chipFg });
|
|
793
|
+
segs.push({ text: label, color: ctxColor, bold: true });
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
if (segs.length === 0)
|
|
797
|
+
return {};
|
|
798
|
+
return {
|
|
799
|
+
rightSegments: segs,
|
|
800
|
+
rightLabelBg: theme.prompt.chipBg,
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
//# sourceMappingURL=App.js.map
|