wiggum-cli 0.12.0 → 0.13.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/dist/ai/agents/codebase-analyst.d.ts +0 -1
- package/dist/ai/agents/codebase-analyst.js +0 -1
- package/dist/ai/agents/codebase-analyzer.d.ts +0 -1
- package/dist/ai/agents/codebase-analyzer.js +0 -1
- package/dist/ai/agents/context-enricher.d.ts +0 -1
- package/dist/ai/agents/context-enricher.js +0 -1
- package/dist/ai/agents/evaluator-optimizer.d.ts +0 -1
- package/dist/ai/agents/evaluator-optimizer.js +0 -1
- package/dist/ai/agents/index.d.ts +0 -1
- package/dist/ai/agents/index.js +0 -1
- package/dist/ai/agents/mcp-detector.d.ts +0 -1
- package/dist/ai/agents/mcp-detector.js +0 -1
- package/dist/ai/agents/orchestrator.d.ts +0 -1
- package/dist/ai/agents/orchestrator.js +0 -1
- package/dist/ai/agents/planning-orchestrator.d.ts +0 -1
- package/dist/ai/agents/planning-orchestrator.js +0 -1
- package/dist/ai/agents/stack-researcher.d.ts +0 -1
- package/dist/ai/agents/stack-researcher.js +0 -1
- package/dist/ai/agents/stack-utils.d.ts +0 -1
- package/dist/ai/agents/stack-utils.js +0 -1
- package/dist/ai/agents/synthesis-agent.d.ts +0 -1
- package/dist/ai/agents/synthesis-agent.js +0 -1
- package/dist/ai/agents/tech-researcher.d.ts +0 -1
- package/dist/ai/agents/tech-researcher.js +0 -1
- package/dist/ai/agents/types.d.ts +0 -1
- package/dist/ai/agents/types.js +0 -1
- package/dist/ai/conversation/conversation-manager.d.ts +0 -1
- package/dist/ai/conversation/conversation-manager.js +0 -1
- package/dist/ai/conversation/index.d.ts +0 -1
- package/dist/ai/conversation/index.js +0 -1
- package/dist/ai/conversation/interview-tools.d.ts +0 -1
- package/dist/ai/conversation/interview-tools.js +0 -1
- package/dist/ai/conversation/spec-generator.d.ts +0 -1
- package/dist/ai/conversation/spec-generator.js +0 -1
- package/dist/ai/conversation/url-fetcher.d.ts +0 -1
- package/dist/ai/conversation/url-fetcher.js +0 -1
- package/dist/ai/enhancer.d.ts +0 -1
- package/dist/ai/enhancer.js +0 -1
- package/dist/ai/index.d.ts +0 -1
- package/dist/ai/index.js +0 -1
- package/dist/ai/prompts.d.ts +0 -1
- package/dist/ai/prompts.js +0 -1
- package/dist/ai/providers.d.ts +0 -1
- package/dist/ai/providers.js +0 -1
- package/dist/ai/tools/context7.d.ts +0 -1
- package/dist/ai/tools/context7.js +0 -1
- package/dist/ai/tools/index.d.ts +0 -1
- package/dist/ai/tools/index.js +0 -1
- package/dist/ai/tools/tavily.d.ts +0 -1
- package/dist/ai/tools/tavily.js +0 -1
- package/dist/ai/tools.d.ts +0 -1
- package/dist/ai/tools.js +0 -1
- package/dist/commands/config.d.ts +0 -1
- package/dist/commands/config.js +0 -1
- package/dist/commands/init.d.ts +0 -1
- package/dist/commands/init.js +0 -1
- package/dist/commands/monitor.d.ts +0 -1
- package/dist/commands/monitor.js +0 -1
- package/dist/commands/new.d.ts +0 -1
- package/dist/commands/new.js +0 -1
- package/dist/commands/run.d.ts +0 -1
- package/dist/commands/run.js +0 -1
- package/dist/context/convert.d.ts +0 -1
- package/dist/context/convert.js +0 -1
- package/dist/context/index.d.ts +0 -1
- package/dist/context/index.js +0 -1
- package/dist/context/storage.d.ts +0 -1
- package/dist/context/storage.js +0 -1
- package/dist/context/types.d.ts +0 -1
- package/dist/context/types.js +0 -1
- package/dist/generator/config.d.ts +0 -1
- package/dist/generator/config.js +0 -1
- package/dist/generator/index.d.ts +0 -1
- package/dist/generator/index.js +0 -1
- package/dist/generator/templates.d.ts +0 -1
- package/dist/generator/templates.js +0 -1
- package/dist/generator/writer.d.ts +0 -1
- package/dist/generator/writer.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +7 -7
- package/dist/repl/command-parser.d.ts +0 -1
- package/dist/repl/command-parser.js +0 -1
- package/dist/repl/index.d.ts +0 -1
- package/dist/repl/index.js +0 -1
- package/dist/repl/session-state.d.ts +0 -1
- package/dist/repl/session-state.js +0 -1
- package/dist/scanner/detectors/core/framework.d.ts +0 -1
- package/dist/scanner/detectors/core/framework.js +0 -1
- package/dist/scanner/detectors/core/packageManager.d.ts +0 -1
- package/dist/scanner/detectors/core/packageManager.js +0 -1
- package/dist/scanner/detectors/core/styling.d.ts +0 -1
- package/dist/scanner/detectors/core/styling.js +0 -1
- package/dist/scanner/detectors/core/testing.d.ts +0 -1
- package/dist/scanner/detectors/core/testing.js +0 -1
- package/dist/scanner/detectors/data/api.d.ts +0 -1
- package/dist/scanner/detectors/data/api.js +0 -1
- package/dist/scanner/detectors/data/database.d.ts +0 -1
- package/dist/scanner/detectors/data/database.js +0 -1
- package/dist/scanner/detectors/data/orm.d.ts +0 -1
- package/dist/scanner/detectors/data/orm.js +0 -1
- package/dist/scanner/detectors/frontend/formHandling.d.ts +0 -1
- package/dist/scanner/detectors/frontend/formHandling.js +0 -1
- package/dist/scanner/detectors/frontend/stateManagement.d.ts +0 -1
- package/dist/scanner/detectors/frontend/stateManagement.js +0 -1
- package/dist/scanner/detectors/frontend/uiComponents.d.ts +0 -1
- package/dist/scanner/detectors/frontend/uiComponents.js +0 -1
- package/dist/scanner/detectors/infra/deployment.d.ts +0 -1
- package/dist/scanner/detectors/infra/deployment.js +0 -1
- package/dist/scanner/detectors/infra/monorepo.d.ts +0 -1
- package/dist/scanner/detectors/infra/monorepo.js +0 -1
- package/dist/scanner/detectors/mcp/mcpProject.d.ts +0 -1
- package/dist/scanner/detectors/mcp/mcpProject.js +0 -1
- package/dist/scanner/detectors/mcp/mcpServers.d.ts +0 -1
- package/dist/scanner/detectors/mcp/mcpServers.js +0 -1
- package/dist/scanner/detectors/services/analytics.d.ts +0 -1
- package/dist/scanner/detectors/services/analytics.js +0 -1
- package/dist/scanner/detectors/services/auth.d.ts +0 -1
- package/dist/scanner/detectors/services/auth.js +0 -1
- package/dist/scanner/detectors/services/email.d.ts +0 -1
- package/dist/scanner/detectors/services/email.js +0 -1
- package/dist/scanner/detectors/services/payments.d.ts +0 -1
- package/dist/scanner/detectors/services/payments.js +0 -1
- package/dist/scanner/detectors/utils.d.ts +0 -1
- package/dist/scanner/detectors/utils.js +0 -1
- package/dist/scanner/index.d.ts +0 -1
- package/dist/scanner/index.js +0 -1
- package/dist/scanner/registry.d.ts +0 -1
- package/dist/scanner/registry.js +0 -1
- package/dist/scanner/types.d.ts +0 -1
- package/dist/scanner/types.js +0 -1
- package/dist/tui/app.d.ts +12 -23
- package/dist/tui/app.js +130 -315
- package/dist/tui/components/ActionOutput.d.ts +0 -1
- package/dist/tui/components/ActionOutput.js +0 -1
- package/dist/tui/components/AppShell.d.ts +47 -0
- package/dist/tui/components/AppShell.js +19 -0
- package/dist/tui/components/ChatInput.d.ts +0 -1
- package/dist/tui/components/ChatInput.js +0 -1
- package/dist/tui/components/CommandDropdown.d.ts +0 -1
- package/dist/tui/components/CommandDropdown.js +0 -1
- package/dist/tui/components/Confirm.d.ts +0 -1
- package/dist/tui/components/Confirm.js +0 -1
- package/dist/tui/components/ErrorCard.d.ts +0 -1
- package/dist/tui/components/ErrorCard.js +0 -1
- package/dist/tui/components/FooterStatusBar.d.ts +0 -1
- package/dist/tui/components/FooterStatusBar.js +2 -4
- package/dist/tui/components/HeaderContent.d.ts +28 -0
- package/dist/tui/components/HeaderContent.js +16 -0
- package/dist/tui/components/MessageList.d.ts +9 -8
- package/dist/tui/components/MessageList.js +23 -18
- package/dist/tui/components/MultiSelect.d.ts +0 -1
- package/dist/tui/components/MultiSelect.js +0 -1
- package/dist/tui/components/PasswordInput.d.ts +0 -1
- package/dist/tui/components/PasswordInput.js +0 -1
- package/dist/tui/components/PhaseHeader.d.ts +0 -1
- package/dist/tui/components/PhaseHeader.js +0 -1
- package/dist/tui/components/RunCompletionSummary.d.ts +22 -0
- package/dist/tui/components/RunCompletionSummary.js +23 -0
- package/dist/tui/components/Select.d.ts +0 -1
- package/dist/tui/components/Select.js +0 -1
- package/dist/tui/components/SpecCompletionSummary.d.ts +47 -0
- package/dist/tui/components/SpecCompletionSummary.js +124 -0
- package/dist/tui/components/StatusLine.d.ts +0 -1
- package/dist/tui/components/StatusLine.js +0 -1
- package/dist/tui/components/StreamingText.d.ts +0 -1
- package/dist/tui/components/StreamingText.js +0 -1
- package/dist/tui/components/TipsBar.d.ts +24 -0
- package/dist/tui/components/TipsBar.js +23 -0
- package/dist/tui/components/ToolCallCard.d.ts +0 -1
- package/dist/tui/components/ToolCallCard.js +0 -1
- package/dist/tui/components/WiggumBanner.d.ts +0 -1
- package/dist/tui/components/WiggumBanner.js +8 -4
- package/dist/tui/components/WorkingIndicator.d.ts +0 -1
- package/dist/tui/components/WorkingIndicator.js +0 -1
- package/dist/tui/components/index.d.ts +0 -1
- package/dist/tui/components/index.js +0 -1
- package/dist/tui/hooks/index.d.ts +0 -1
- package/dist/tui/hooks/index.js +0 -1
- package/dist/tui/hooks/useBackgroundRuns.d.ts +52 -0
- package/dist/tui/hooks/useBackgroundRuns.js +121 -0
- package/dist/tui/hooks/useCommandHistory.d.ts +0 -1
- package/dist/tui/hooks/useCommandHistory.js +0 -1
- package/dist/tui/hooks/useInit.d.ts +0 -1
- package/dist/tui/hooks/useInit.js +0 -1
- package/dist/tui/hooks/useSpecGenerator.d.ts +0 -1
- package/dist/tui/hooks/useSpecGenerator.js +0 -1
- package/dist/tui/hooks/useSync.d.ts +0 -1
- package/dist/tui/hooks/useSync.js +0 -1
- package/dist/tui/index.d.ts +0 -1
- package/dist/tui/index.js +0 -1
- package/dist/tui/orchestration/index.d.ts +0 -1
- package/dist/tui/orchestration/index.js +0 -1
- package/dist/tui/orchestration/interview-orchestrator.d.ts +0 -1
- package/dist/tui/orchestration/interview-orchestrator.js +1 -2
- package/dist/tui/screens/InitScreen.d.ts +13 -9
- package/dist/tui/screens/InitScreen.js +86 -88
- package/dist/tui/screens/InterviewScreen.d.ts +11 -9
- package/dist/tui/screens/InterviewScreen.js +145 -100
- package/dist/tui/screens/MainShell.d.ts +13 -13
- package/dist/tui/screens/MainShell.js +65 -70
- package/dist/tui/screens/RunScreen.d.ts +17 -2
- package/dist/tui/screens/RunScreen.js +235 -81
- package/dist/tui/screens/index.d.ts +0 -3
- package/dist/tui/screens/index.js +0 -2
- package/dist/tui/theme.d.ts +0 -1
- package/dist/tui/theme.js +0 -1
- package/dist/tui/types/interview.d.ts +0 -1
- package/dist/tui/types/interview.js +0 -1
- package/dist/tui/utils/input-utils.d.ts +0 -1
- package/dist/tui/utils/input-utils.js +0 -1
- package/dist/tui/utils/loop-status.d.ts +22 -4
- package/dist/tui/utils/loop-status.js +65 -16
- package/dist/utils/colors.d.ts +0 -1
- package/dist/utils/colors.js +0 -1
- package/dist/utils/config.d.ts +0 -1
- package/dist/utils/config.js +0 -1
- package/dist/utils/env.d.ts +0 -1
- package/dist/utils/env.js +0 -1
- package/dist/utils/header.d.ts +0 -1
- package/dist/utils/header.js +0 -1
- package/dist/utils/json-repair.d.ts +0 -1
- package/dist/utils/json-repair.js +0 -1
- package/dist/utils/logger.d.ts +0 -1
- package/dist/utils/logger.js +0 -1
- package/dist/utils/spinner.d.ts +0 -1
- package/dist/utils/spinner.js +0 -1
- package/dist/utils/tracing.d.ts +0 -1
- package/dist/utils/tracing.js +0 -1
- package/dist/utils/tui.d.ts +0 -1
- package/dist/utils/tui.js +0 -1
- package/dist/utils/update-check.d.ts +0 -1
- package/dist/utils/update-check.js +0 -1
- package/package.json +6 -4
- package/CONTRIBUTING.md +0 -162
- package/dist/__test-utils__/fixtures.d.ts +0 -17
- package/dist/__test-utils__/fixtures.d.ts.map +0 -1
- package/dist/__test-utils__/fixtures.js +0 -32
- package/dist/__test-utils__/fixtures.js.map +0 -1
- package/dist/__test-utils__/ink-helpers.d.ts +0 -43
- package/dist/__test-utils__/ink-helpers.d.ts.map +0 -1
- package/dist/__test-utils__/ink-helpers.js +0 -62
- package/dist/__test-utils__/ink-helpers.js.map +0 -1
- package/dist/__test-utils__/mock-ai.d.ts +0 -99
- package/dist/__test-utils__/mock-ai.d.ts.map +0 -1
- package/dist/__test-utils__/mock-ai.js +0 -75
- package/dist/__test-utils__/mock-ai.js.map +0 -1
- package/dist/__test-utils__/mock-tracing.d.ts +0 -18
- package/dist/__test-utils__/mock-tracing.d.ts.map +0 -1
- package/dist/__test-utils__/mock-tracing.js +0 -24
- package/dist/__test-utils__/mock-tracing.js.map +0 -1
- package/dist/__test-utils__/setup.d.ts +0 -8
- package/dist/__test-utils__/setup.d.ts.map +0 -1
- package/dist/__test-utils__/setup.js +0 -21
- package/dist/__test-utils__/setup.js.map +0 -1
- package/dist/ai/agents/codebase-analyst.d.ts.map +0 -1
- package/dist/ai/agents/codebase-analyst.js.map +0 -1
- package/dist/ai/agents/codebase-analyzer.d.ts.map +0 -1
- package/dist/ai/agents/codebase-analyzer.js.map +0 -1
- package/dist/ai/agents/context-enricher.d.ts.map +0 -1
- package/dist/ai/agents/context-enricher.js.map +0 -1
- package/dist/ai/agents/evaluator-optimizer.d.ts.map +0 -1
- package/dist/ai/agents/evaluator-optimizer.js.map +0 -1
- package/dist/ai/agents/index.d.ts.map +0 -1
- package/dist/ai/agents/index.js.map +0 -1
- package/dist/ai/agents/mcp-detector.d.ts.map +0 -1
- package/dist/ai/agents/mcp-detector.js.map +0 -1
- package/dist/ai/agents/orchestrator.d.ts.map +0 -1
- package/dist/ai/agents/orchestrator.js.map +0 -1
- package/dist/ai/agents/planning-orchestrator.d.ts.map +0 -1
- package/dist/ai/agents/planning-orchestrator.js.map +0 -1
- package/dist/ai/agents/stack-researcher.d.ts.map +0 -1
- package/dist/ai/agents/stack-researcher.js.map +0 -1
- package/dist/ai/agents/stack-utils.d.ts.map +0 -1
- package/dist/ai/agents/stack-utils.js.map +0 -1
- package/dist/ai/agents/synthesis-agent.d.ts.map +0 -1
- package/dist/ai/agents/synthesis-agent.js.map +0 -1
- package/dist/ai/agents/tech-researcher.d.ts.map +0 -1
- package/dist/ai/agents/tech-researcher.js.map +0 -1
- package/dist/ai/agents/types.d.ts.map +0 -1
- package/dist/ai/agents/types.js.map +0 -1
- package/dist/ai/conversation/conversation-manager.d.ts.map +0 -1
- package/dist/ai/conversation/conversation-manager.js.map +0 -1
- package/dist/ai/conversation/index.d.ts.map +0 -1
- package/dist/ai/conversation/index.js.map +0 -1
- package/dist/ai/conversation/interview-tools.d.ts.map +0 -1
- package/dist/ai/conversation/interview-tools.js.map +0 -1
- package/dist/ai/conversation/spec-generator.d.ts.map +0 -1
- package/dist/ai/conversation/spec-generator.js.map +0 -1
- package/dist/ai/conversation/url-fetcher.d.ts.map +0 -1
- package/dist/ai/conversation/url-fetcher.js.map +0 -1
- package/dist/ai/enhancer.d.ts.map +0 -1
- package/dist/ai/enhancer.js.map +0 -1
- package/dist/ai/index.d.ts.map +0 -1
- package/dist/ai/index.js.map +0 -1
- package/dist/ai/prompts.d.ts.map +0 -1
- package/dist/ai/prompts.js.map +0 -1
- package/dist/ai/providers.d.ts.map +0 -1
- package/dist/ai/providers.js.map +0 -1
- package/dist/ai/tools/context7.d.ts.map +0 -1
- package/dist/ai/tools/context7.js.map +0 -1
- package/dist/ai/tools/index.d.ts.map +0 -1
- package/dist/ai/tools/index.js.map +0 -1
- package/dist/ai/tools/tavily.d.ts.map +0 -1
- package/dist/ai/tools/tavily.js.map +0 -1
- package/dist/ai/tools.d.ts.map +0 -1
- package/dist/ai/tools.js.map +0 -1
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/monitor.d.ts.map +0 -1
- package/dist/commands/monitor.js.map +0 -1
- package/dist/commands/new.d.ts.map +0 -1
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/run.d.ts.map +0 -1
- package/dist/commands/run.js.map +0 -1
- package/dist/context/convert.d.ts.map +0 -1
- package/dist/context/convert.js.map +0 -1
- package/dist/context/index.d.ts.map +0 -1
- package/dist/context/index.js.map +0 -1
- package/dist/context/storage.d.ts.map +0 -1
- package/dist/context/storage.js.map +0 -1
- package/dist/context/types.d.ts.map +0 -1
- package/dist/context/types.js.map +0 -1
- package/dist/generator/config.d.ts.map +0 -1
- package/dist/generator/config.js.map +0 -1
- package/dist/generator/index.d.ts.map +0 -1
- package/dist/generator/index.js.map +0 -1
- package/dist/generator/templates.d.ts.map +0 -1
- package/dist/generator/templates.js.map +0 -1
- package/dist/generator/writer.d.ts.map +0 -1
- package/dist/generator/writer.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/repl/command-parser.d.ts.map +0 -1
- package/dist/repl/command-parser.js.map +0 -1
- package/dist/repl/index.d.ts.map +0 -1
- package/dist/repl/index.js.map +0 -1
- package/dist/repl/session-state.d.ts.map +0 -1
- package/dist/repl/session-state.js.map +0 -1
- package/dist/scanner/detectors/core/framework.d.ts.map +0 -1
- package/dist/scanner/detectors/core/framework.js.map +0 -1
- package/dist/scanner/detectors/core/packageManager.d.ts.map +0 -1
- package/dist/scanner/detectors/core/packageManager.js.map +0 -1
- package/dist/scanner/detectors/core/styling.d.ts.map +0 -1
- package/dist/scanner/detectors/core/styling.js.map +0 -1
- package/dist/scanner/detectors/core/testing.d.ts.map +0 -1
- package/dist/scanner/detectors/core/testing.js.map +0 -1
- package/dist/scanner/detectors/data/api.d.ts.map +0 -1
- package/dist/scanner/detectors/data/api.js.map +0 -1
- package/dist/scanner/detectors/data/database.d.ts.map +0 -1
- package/dist/scanner/detectors/data/database.js.map +0 -1
- package/dist/scanner/detectors/data/orm.d.ts.map +0 -1
- package/dist/scanner/detectors/data/orm.js.map +0 -1
- package/dist/scanner/detectors/frontend/formHandling.d.ts.map +0 -1
- package/dist/scanner/detectors/frontend/formHandling.js.map +0 -1
- package/dist/scanner/detectors/frontend/stateManagement.d.ts.map +0 -1
- package/dist/scanner/detectors/frontend/stateManagement.js.map +0 -1
- package/dist/scanner/detectors/frontend/uiComponents.d.ts.map +0 -1
- package/dist/scanner/detectors/frontend/uiComponents.js.map +0 -1
- package/dist/scanner/detectors/infra/deployment.d.ts.map +0 -1
- package/dist/scanner/detectors/infra/deployment.js.map +0 -1
- package/dist/scanner/detectors/infra/monorepo.d.ts.map +0 -1
- package/dist/scanner/detectors/infra/monorepo.js.map +0 -1
- package/dist/scanner/detectors/mcp/mcpProject.d.ts.map +0 -1
- package/dist/scanner/detectors/mcp/mcpProject.js.map +0 -1
- package/dist/scanner/detectors/mcp/mcpServers.d.ts.map +0 -1
- package/dist/scanner/detectors/mcp/mcpServers.js.map +0 -1
- package/dist/scanner/detectors/services/analytics.d.ts.map +0 -1
- package/dist/scanner/detectors/services/analytics.js.map +0 -1
- package/dist/scanner/detectors/services/auth.d.ts.map +0 -1
- package/dist/scanner/detectors/services/auth.js.map +0 -1
- package/dist/scanner/detectors/services/email.d.ts.map +0 -1
- package/dist/scanner/detectors/services/email.js.map +0 -1
- package/dist/scanner/detectors/services/payments.d.ts.map +0 -1
- package/dist/scanner/detectors/services/payments.js.map +0 -1
- package/dist/scanner/detectors/utils.d.ts.map +0 -1
- package/dist/scanner/detectors/utils.js.map +0 -1
- package/dist/scanner/index.d.ts.map +0 -1
- package/dist/scanner/index.js.map +0 -1
- package/dist/scanner/registry.d.ts.map +0 -1
- package/dist/scanner/registry.js.map +0 -1
- package/dist/scanner/types.d.ts.map +0 -1
- package/dist/scanner/types.js.map +0 -1
- package/dist/tui/app.d.ts.map +0 -1
- package/dist/tui/app.js.map +0 -1
- package/dist/tui/components/ActionOutput.d.ts.map +0 -1
- package/dist/tui/components/ActionOutput.js.map +0 -1
- package/dist/tui/components/ChatInput.d.ts.map +0 -1
- package/dist/tui/components/ChatInput.js.map +0 -1
- package/dist/tui/components/ChatInput.test.d.ts +0 -2
- package/dist/tui/components/ChatInput.test.d.ts.map +0 -1
- package/dist/tui/components/ChatInput.test.js +0 -75
- package/dist/tui/components/ChatInput.test.js.map +0 -1
- package/dist/tui/components/CommandDropdown.d.ts.map +0 -1
- package/dist/tui/components/CommandDropdown.js.map +0 -1
- package/dist/tui/components/Confirm.d.ts.map +0 -1
- package/dist/tui/components/Confirm.js.map +0 -1
- package/dist/tui/components/ErrorCard.d.ts.map +0 -1
- package/dist/tui/components/ErrorCard.js.map +0 -1
- package/dist/tui/components/FooterStatusBar.d.ts.map +0 -1
- package/dist/tui/components/FooterStatusBar.js.map +0 -1
- package/dist/tui/components/MessageList.d.ts.map +0 -1
- package/dist/tui/components/MessageList.js.map +0 -1
- package/dist/tui/components/MultiSelect.d.ts.map +0 -1
- package/dist/tui/components/MultiSelect.js.map +0 -1
- package/dist/tui/components/PasswordInput.d.ts.map +0 -1
- package/dist/tui/components/PasswordInput.js.map +0 -1
- package/dist/tui/components/PhaseHeader.d.ts.map +0 -1
- package/dist/tui/components/PhaseHeader.js.map +0 -1
- package/dist/tui/components/Select.d.ts.map +0 -1
- package/dist/tui/components/Select.js.map +0 -1
- package/dist/tui/components/StatusLine.d.ts.map +0 -1
- package/dist/tui/components/StatusLine.js.map +0 -1
- package/dist/tui/components/StreamingText.d.ts.map +0 -1
- package/dist/tui/components/StreamingText.js.map +0 -1
- package/dist/tui/components/ToolCallCard.d.ts.map +0 -1
- package/dist/tui/components/ToolCallCard.js.map +0 -1
- package/dist/tui/components/WiggumBanner.d.ts.map +0 -1
- package/dist/tui/components/WiggumBanner.js.map +0 -1
- package/dist/tui/components/WorkingIndicator.d.ts.map +0 -1
- package/dist/tui/components/WorkingIndicator.js.map +0 -1
- package/dist/tui/components/WorkingIndicator.test.d.ts +0 -2
- package/dist/tui/components/WorkingIndicator.test.d.ts.map +0 -1
- package/dist/tui/components/WorkingIndicator.test.js +0 -26
- package/dist/tui/components/WorkingIndicator.test.js.map +0 -1
- package/dist/tui/components/index.d.ts.map +0 -1
- package/dist/tui/components/index.js.map +0 -1
- package/dist/tui/demo.d.ts +0 -8
- package/dist/tui/demo.d.ts.map +0 -1
- package/dist/tui/demo.js +0 -69
- package/dist/tui/demo.js.map +0 -1
- package/dist/tui/hooks/index.d.ts.map +0 -1
- package/dist/tui/hooks/index.js.map +0 -1
- package/dist/tui/hooks/useCommandHistory.d.ts.map +0 -1
- package/dist/tui/hooks/useCommandHistory.js.map +0 -1
- package/dist/tui/hooks/useInit.d.ts.map +0 -1
- package/dist/tui/hooks/useInit.js.map +0 -1
- package/dist/tui/hooks/useSpecGenerator.d.ts.map +0 -1
- package/dist/tui/hooks/useSpecGenerator.js.map +0 -1
- package/dist/tui/hooks/useSync.d.ts.map +0 -1
- package/dist/tui/hooks/useSync.js.map +0 -1
- package/dist/tui/index.d.ts.map +0 -1
- package/dist/tui/index.js.map +0 -1
- package/dist/tui/orchestration/index.d.ts.map +0 -1
- package/dist/tui/orchestration/index.js.map +0 -1
- package/dist/tui/orchestration/interview-orchestrator.d.ts.map +0 -1
- package/dist/tui/orchestration/interview-orchestrator.js.map +0 -1
- package/dist/tui/screens/InitScreen.d.ts.map +0 -1
- package/dist/tui/screens/InitScreen.js.map +0 -1
- package/dist/tui/screens/InterviewScreen.d.ts.map +0 -1
- package/dist/tui/screens/InterviewScreen.integration.test.d.ts +0 -7
- package/dist/tui/screens/InterviewScreen.integration.test.d.ts.map +0 -1
- package/dist/tui/screens/InterviewScreen.integration.test.js +0 -149
- package/dist/tui/screens/InterviewScreen.integration.test.js.map +0 -1
- package/dist/tui/screens/InterviewScreen.js.map +0 -1
- package/dist/tui/screens/MainShell.d.ts.map +0 -1
- package/dist/tui/screens/MainShell.js.map +0 -1
- package/dist/tui/screens/MainShell.test.d.ts +0 -2
- package/dist/tui/screens/MainShell.test.d.ts.map +0 -1
- package/dist/tui/screens/MainShell.test.js +0 -103
- package/dist/tui/screens/MainShell.test.js.map +0 -1
- package/dist/tui/screens/RunScreen.d.ts.map +0 -1
- package/dist/tui/screens/RunScreen.js.map +0 -1
- package/dist/tui/screens/WelcomeScreen.d.ts +0 -45
- package/dist/tui/screens/WelcomeScreen.d.ts.map +0 -1
- package/dist/tui/screens/WelcomeScreen.js +0 -55
- package/dist/tui/screens/WelcomeScreen.js.map +0 -1
- package/dist/tui/screens/WelcomeScreen.test.d.ts +0 -2
- package/dist/tui/screens/WelcomeScreen.test.d.ts.map +0 -1
- package/dist/tui/screens/WelcomeScreen.test.js +0 -51
- package/dist/tui/screens/WelcomeScreen.test.js.map +0 -1
- package/dist/tui/screens/index.d.ts.map +0 -1
- package/dist/tui/screens/index.js.map +0 -1
- package/dist/tui/theme.d.ts.map +0 -1
- package/dist/tui/theme.js.map +0 -1
- package/dist/tui/types/interview.d.ts.map +0 -1
- package/dist/tui/types/interview.js.map +0 -1
- package/dist/tui/utils/input-utils.d.ts.map +0 -1
- package/dist/tui/utils/input-utils.js.map +0 -1
- package/dist/tui/utils/loop-status.d.ts.map +0 -1
- package/dist/tui/utils/loop-status.js.map +0 -1
- package/dist/utils/colors.d.ts.map +0 -1
- package/dist/utils/colors.js.map +0 -1
- package/dist/utils/config.d.ts.map +0 -1
- package/dist/utils/config.js.map +0 -1
- package/dist/utils/env.d.ts.map +0 -1
- package/dist/utils/env.js.map +0 -1
- package/dist/utils/header.d.ts.map +0 -1
- package/dist/utils/header.js.map +0 -1
- package/dist/utils/json-repair.d.ts.map +0 -1
- package/dist/utils/json-repair.js.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/spinner.d.ts.map +0 -1
- package/dist/utils/spinner.js.map +0 -1
- package/dist/utils/tracing.d.ts.map +0 -1
- package/dist/utils/tracing.js.map +0 -1
- package/dist/utils/tui.d.ts.map +0 -1
- package/dist/utils/tui.js.map +0 -1
- package/dist/utils/update-check.d.ts.map +0 -1
- package/dist/utils/update-check.js.map +0 -1
package/dist/tui/app.js
CHANGED
|
@@ -5,73 +5,43 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
* The root component for the Ink-based TUI. Routes to different screens
|
|
6
6
|
* based on the current screen state. Manages session state and navigation.
|
|
7
7
|
*
|
|
8
|
-
* Uses
|
|
9
|
-
*
|
|
8
|
+
* Uses an AppShell-based layout where each screen wraps itself in
|
|
9
|
+
* <AppShell> with a shared header element. No Static/thread model -
|
|
10
|
+
* screen transitions are clean React mount/unmount cycles.
|
|
10
11
|
*/
|
|
11
|
-
import { useState, useCallback, useEffect } from 'react';
|
|
12
|
-
import {
|
|
13
|
-
import { existsSync, mkdirSync, writeFileSync
|
|
12
|
+
import { useState, useCallback, useEffect, useMemo } from 'react';
|
|
13
|
+
import { Box, Text, render, useStdout } from 'ink';
|
|
14
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
14
15
|
import { join } from 'node:path';
|
|
15
16
|
import { loadConfigWithDefaults } from '../utils/config.js';
|
|
17
|
+
import { logger } from '../utils/logger.js';
|
|
16
18
|
import { InterviewScreen } from './screens/InterviewScreen.js';
|
|
17
19
|
import { InitScreen } from './screens/InitScreen.js';
|
|
18
20
|
import { RunScreen } from './screens/RunScreen.js';
|
|
19
21
|
import { MainShell } from './screens/MainShell.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import { PHASE_CONFIGS } from './hooks/useSpecGenerator.js';
|
|
23
|
-
import { colors, theme } from './theme.js';
|
|
24
|
-
import { formatNumber } from './utils/loop-status.js';
|
|
22
|
+
import { HeaderContent } from './components/HeaderContent.js';
|
|
23
|
+
import { useBackgroundRuns } from './hooks/useBackgroundRuns.js';
|
|
25
24
|
/**
|
|
26
25
|
* Main App component for the Ink-based TUI
|
|
27
26
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```tsx
|
|
33
|
-
* renderApp({
|
|
34
|
-
* screen: 'welcome',
|
|
35
|
-
* initialSessionState: sessionState,
|
|
36
|
-
* version: '0.8.0',
|
|
37
|
-
* onExit: () => process.exit(0),
|
|
38
|
-
* });
|
|
39
|
-
* ```
|
|
40
|
-
*/
|
|
41
|
-
/**
|
|
42
|
-
* Generate a unique ID for thread items
|
|
27
|
+
* Simple routing + shared state. Each screen wraps itself in AppShell
|
|
28
|
+
* and receives a shared headerElement prop.
|
|
43
29
|
*/
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
export function App({ screen: initialScreen, initialSessionState, version = '0.8.0', interviewProps, onComplete, onExit, }) {
|
|
30
|
+
export function App({ screen: initialScreen, initialSessionState, version = '0.12.1', // Fallback if package.json read fails (keep in sync with index.ts)
|
|
31
|
+
interviewProps, onComplete, onExit, }) {
|
|
48
32
|
const [currentScreen, setCurrentScreen] = useState(initialScreen);
|
|
49
33
|
const [screenProps, setScreenProps] = useState(interviewProps ? { featureName: interviewProps.featureName } : null);
|
|
50
34
|
const [sessionState, setSessionState] = useState(initialSessionState);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
return [];
|
|
63
|
-
});
|
|
64
|
-
const [completionQueue, setCompletionQueue] = useState(null);
|
|
65
|
-
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
66
|
-
const [threadResetKey, setThreadResetKey] = useState(0);
|
|
67
|
-
/**
|
|
68
|
-
* Add an item to the thread history
|
|
69
|
-
*/
|
|
70
|
-
const addToThread = useCallback((type, content) => {
|
|
71
|
-
const id = generateThreadId();
|
|
72
|
-
setThreadHistory(prev => [...prev, { id, type, content }]);
|
|
73
|
-
return id;
|
|
74
|
-
}, []);
|
|
35
|
+
// Background run tracking
|
|
36
|
+
const { runs: backgroundRuns, background, dismiss } = useBackgroundRuns();
|
|
37
|
+
// Terminal dimensions for compact mode and resize reactivity
|
|
38
|
+
const { stdout } = useStdout();
|
|
39
|
+
const columns = stdout?.columns ?? 80;
|
|
40
|
+
const rows = stdout?.rows ?? 24;
|
|
41
|
+
const compact = rows < 20 || columns < 60;
|
|
42
|
+
// Shared header element - includes columns/rows in deps so the
|
|
43
|
+
// header subtree re-renders on terminal resize (banner auto-compacts)
|
|
44
|
+
const headerElement = useMemo(() => (_jsx(HeaderContent, { version: version, sessionState: sessionState, backgroundRuns: backgroundRuns, compact: compact })), [version, sessionState, backgroundRuns, compact, columns, rows]);
|
|
75
45
|
/**
|
|
76
46
|
* Navigate to a different screen
|
|
77
47
|
*/
|
|
@@ -80,196 +50,63 @@ export function App({ screen: initialScreen, initialSessionState, version = '0.8
|
|
|
80
50
|
setCurrentScreen(target);
|
|
81
51
|
}, []);
|
|
82
52
|
/**
|
|
83
|
-
* Handle interview completion - save spec to disk and
|
|
53
|
+
* Handle interview completion - save spec to disk and navigate to shell
|
|
84
54
|
*/
|
|
85
|
-
const handleInterviewComplete = useCallback(async (spec, messages) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
55
|
+
const handleInterviewComplete = useCallback(async (spec, messages, specPath) => {
|
|
56
|
+
try {
|
|
57
|
+
const featureName = screenProps?.featureName || interviewProps?.featureName;
|
|
58
|
+
let savedPath = specPath;
|
|
59
|
+
if (featureName && typeof featureName === 'string') {
|
|
60
|
+
try {
|
|
61
|
+
const config = await loadConfigWithDefaults(sessionState.projectRoot);
|
|
62
|
+
const specsDir = join(sessionState.projectRoot, config.paths.specs);
|
|
63
|
+
if (!existsSync(specsDir)) {
|
|
64
|
+
mkdirSync(specsDir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
savedPath = join(specsDir, `${featureName}.md`);
|
|
67
|
+
writeFileSync(savedPath, spec, 'utf-8');
|
|
68
|
+
onComplete?.(savedPath);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
72
|
+
logger.error(`Failed to save spec: ${reason}`);
|
|
73
|
+
// Pass specPath (not raw spec content) to keep the onComplete contract consistent
|
|
74
|
+
onComplete?.(specPath);
|
|
75
|
+
if (initialScreen !== 'interview') {
|
|
76
|
+
navigate('shell', { message: `Warning: spec generated but could not be saved to disk (${reason}).` });
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
onExit?.();
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
97
82
|
}
|
|
98
|
-
// Write spec to file
|
|
99
|
-
specPath = join(specsDir, `${featureName}.md`);
|
|
100
|
-
writeFileSync(specPath, spec, 'utf-8');
|
|
101
|
-
// Call onComplete with the spec path for logging
|
|
102
|
-
onComplete?.(specPath);
|
|
103
83
|
}
|
|
104
|
-
|
|
105
|
-
// If saving fails, still call onComplete with spec content
|
|
84
|
+
else {
|
|
106
85
|
onComplete?.(spec);
|
|
107
86
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// Prefer previewing the spec from disk if available (ensures consistent output)
|
|
113
|
-
let specForPreview = typeof spec === 'string' ? spec : '';
|
|
114
|
-
if (specPath && existsSync(specPath)) {
|
|
115
|
-
try {
|
|
116
|
-
specForPreview = readFileSync(specPath, 'utf-8');
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
// Ignore read errors and fall back to in-memory spec
|
|
87
|
+
// If started on interview screen directly (--tui mode), exit
|
|
88
|
+
if (initialScreen === 'interview') {
|
|
89
|
+
onExit?.();
|
|
90
|
+
return;
|
|
120
91
|
}
|
|
92
|
+
navigate('shell', { message: `Spec saved to ${savedPath}` });
|
|
121
93
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const userMessages = messages
|
|
128
|
-
.filter((msg) => msg.role === 'user')
|
|
129
|
-
.map((msg) => msg.content.trim())
|
|
130
|
-
.filter((content) => content.length > 0 && content.length <= MAX_RECAP_SOURCE_LENGTH);
|
|
131
|
-
const nonUrlUserMessages = userMessages.filter((content) => !/^https?:\/\//i.test(content) && !/^www\./i.test(content));
|
|
132
|
-
const assistantParagraphs = messages
|
|
133
|
-
.filter((msg) => msg.role === 'assistant' && msg.content && msg.content.length <= MAX_RECAP_SOURCE_LENGTH)
|
|
134
|
-
.flatMap((msg) => msg.content.split('\n\n'))
|
|
135
|
-
.map((para) => para.replace(/\s+/g, ' ').trim())
|
|
136
|
-
.filter((para) => para.length > 0 && para.length <= 320);
|
|
137
|
-
const recapCandidates = assistantParagraphs
|
|
138
|
-
.map((para) => para.replace(/^[^a-z0-9]+/i, '').trim())
|
|
139
|
-
.filter((para) => /^(you want|understood|got it)/i.test(para))
|
|
140
|
-
.map((para) => para.split(/next question:/i)[0].trim())
|
|
141
|
-
.filter((para) => para.length > 0);
|
|
142
|
-
const normalizeRecap = (text) => {
|
|
143
|
-
let result = text.trim();
|
|
144
|
-
result = result.replace(/^[^a-z0-9]+/i, '');
|
|
145
|
-
result = result.replace(/^you want\s*/i, '');
|
|
146
|
-
result = result.replace(/^understood[:,]?\s*/i, '');
|
|
147
|
-
result = result.replace(/^got it[-—:]*\s*/i, '');
|
|
148
|
-
return result.charAt(0).toUpperCase() + result.slice(1);
|
|
149
|
-
};
|
|
150
|
-
const normalizeUserDecision = (text) => {
|
|
151
|
-
let result = text.trim();
|
|
152
|
-
result = result.replace(/^[^a-z0-9]+/i, '');
|
|
153
|
-
result = result.replace(/^i (?:would like|want|need|prefer|expect) to\s*/i, '');
|
|
154
|
-
result = result.replace(/^i (?:would like|want|need|prefer|expect)\s*/i, '');
|
|
155
|
-
result = result.replace(/^please\s*/i, '');
|
|
156
|
-
result = result.replace(/^up to you[:,]?\s*/i, '');
|
|
157
|
-
result = result.replace(/^both\s*/i, 'Both ');
|
|
158
|
-
if (result && !/[.!?]$/.test(result)) {
|
|
159
|
-
result += '.';
|
|
94
|
+
catch (err) {
|
|
95
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
96
|
+
logger.error(`Unexpected error in handleInterviewComplete: ${reason}`);
|
|
97
|
+
if (initialScreen !== 'interview') {
|
|
98
|
+
navigate('shell', { message: `Error completing interview: ${reason}` });
|
|
160
99
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
? normalizeRecap(recapCandidates[0])
|
|
165
|
-
: (nonUrlUserMessages.find((content) => content.length > 20)
|
|
166
|
-
? normalizeUserDecision(nonUrlUserMessages.find((content) => content.length > 20))
|
|
167
|
-
: (nonUrlUserMessages[0] ? normalizeUserDecision(nonUrlUserMessages[0]) : `Define "${featureName}"`));
|
|
168
|
-
const summarizeText = (text, max = 160) => {
|
|
169
|
-
if (text.length <= max)
|
|
170
|
-
return text;
|
|
171
|
-
return `${text.slice(0, max - 1)}…`;
|
|
172
|
-
};
|
|
173
|
-
const decisions = [];
|
|
174
|
-
const seen = new Set();
|
|
175
|
-
const isUsefulDecision = (entry) => {
|
|
176
|
-
const normalized = entry.trim().toLowerCase();
|
|
177
|
-
if (normalized.length < 8)
|
|
178
|
-
return false;
|
|
179
|
-
const wordCount = normalized.split(/\s+/).length;
|
|
180
|
-
if (wordCount < 3)
|
|
181
|
-
return false;
|
|
182
|
-
if (['yes', 'no', 'both', 'ok', 'okay'].includes(normalized))
|
|
183
|
-
return false;
|
|
184
|
-
return true;
|
|
185
|
-
};
|
|
186
|
-
for (let i = nonUrlUserMessages.length - 1; i >= 0; i -= 1) {
|
|
187
|
-
const entry = nonUrlUserMessages[i];
|
|
188
|
-
const normalized = entry.toLowerCase();
|
|
189
|
-
if (entry === goalCandidate)
|
|
190
|
-
continue;
|
|
191
|
-
if (!isUsefulDecision(entry))
|
|
192
|
-
continue;
|
|
193
|
-
if (entry.length > 160)
|
|
194
|
-
continue;
|
|
195
|
-
if (seen.has(normalized))
|
|
196
|
-
continue;
|
|
197
|
-
decisions.unshift(normalizeUserDecision(entry));
|
|
198
|
-
seen.add(normalized);
|
|
199
|
-
if (decisions.length >= 4)
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
if (recapCandidates.length > 1) {
|
|
203
|
-
decisions.length = 0;
|
|
204
|
-
seen.clear();
|
|
205
|
-
for (let i = 1; i < recapCandidates.length; i += 1) {
|
|
206
|
-
const entry = normalizeRecap(recapCandidates[i]);
|
|
207
|
-
const normalized = entry.toLowerCase();
|
|
208
|
-
if (!isUsefulDecision(entry))
|
|
209
|
-
continue;
|
|
210
|
-
if (seen.has(normalized))
|
|
211
|
-
continue;
|
|
212
|
-
decisions.push(entry);
|
|
213
|
-
seen.add(normalized);
|
|
214
|
-
if (decisions.length >= 4)
|
|
215
|
-
break;
|
|
100
|
+
else {
|
|
101
|
+
process.stderr.write(`\nError: ${reason}\n`);
|
|
102
|
+
onExit?.();
|
|
216
103
|
}
|
|
217
104
|
}
|
|
218
|
-
|
|
219
|
-
// Hide the live interview UI before appending to the static thread
|
|
220
|
-
setIsTransitioning(true);
|
|
221
|
-
setCompletionQueue({
|
|
222
|
-
summaryContent,
|
|
223
|
-
summaryType: 'spec-complete',
|
|
224
|
-
action: initialScreen === 'interview' ? 'exit' : 'shell',
|
|
225
|
-
});
|
|
226
|
-
}, [onComplete, navigate, initialScreen, onExit, screenProps, interviewProps, sessionState.projectRoot, addToThread]);
|
|
227
|
-
// Append completion items after the interview UI is hidden
|
|
228
|
-
useEffect(() => {
|
|
229
|
-
if (!isTransitioning || !completionQueue)
|
|
230
|
-
return;
|
|
231
|
-
const completionItem = {
|
|
232
|
-
id: generateThreadId(),
|
|
233
|
-
type: completionQueue.summaryType,
|
|
234
|
-
content: completionQueue.summaryContent,
|
|
235
|
-
};
|
|
236
|
-
const clearScrollback = completionQueue.summaryType === 'spec-complete' ? '\x1b[3J' : '';
|
|
237
|
-
process.stdout.write(`${clearScrollback}\x1b[2J\x1b[0;0H`);
|
|
238
|
-
if (completionQueue.summaryType === 'spec-complete') {
|
|
239
|
-
// Replace the interview thread with banner + completion summary only.
|
|
240
|
-
const bannerItem = {
|
|
241
|
-
id: generateThreadId(),
|
|
242
|
-
type: 'banner',
|
|
243
|
-
content: renderBannerContent(sessionState),
|
|
244
|
-
};
|
|
245
|
-
setThreadHistory([bannerItem, completionItem]);
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
setThreadHistory((prev) => [...prev, completionItem]);
|
|
249
|
-
}
|
|
250
|
-
setThreadResetKey((prev) => prev + 1);
|
|
251
|
-
const action = completionQueue.action;
|
|
252
|
-
setCompletionQueue(null);
|
|
253
|
-
setTimeout(() => {
|
|
254
|
-
if (action === 'exit') {
|
|
255
|
-
if (onExit) {
|
|
256
|
-
onExit();
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
navigate('shell');
|
|
260
|
-
setIsTransitioning(false);
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
navigate('shell');
|
|
264
|
-
setIsTransitioning(false);
|
|
265
|
-
}, 0);
|
|
266
|
-
}, [isTransitioning, completionQueue, navigate, onExit]);
|
|
105
|
+
}, [screenProps, interviewProps, sessionState.projectRoot, onComplete, initialScreen, onExit, navigate]);
|
|
267
106
|
/**
|
|
268
107
|
* Handle interview cancel
|
|
269
108
|
*/
|
|
270
109
|
const handleInterviewCancel = useCallback(() => {
|
|
271
|
-
// If started on interview (--tui mode), call onExit to resolve promise
|
|
272
|
-
// Otherwise, return to shell
|
|
273
110
|
if (initialScreen === 'interview') {
|
|
274
111
|
onExit?.();
|
|
275
112
|
}
|
|
@@ -278,109 +115,87 @@ export function App({ screen: initialScreen, initialSessionState, version = '0.8
|
|
|
278
115
|
}
|
|
279
116
|
}, [navigate, initialScreen, onExit]);
|
|
280
117
|
/**
|
|
281
|
-
* Handle
|
|
118
|
+
* Handle init completion - update state and navigate to shell
|
|
282
119
|
*/
|
|
283
|
-
const
|
|
284
|
-
navigate('shell');
|
|
285
|
-
}, [navigate]);
|
|
286
|
-
/**
|
|
287
|
-
* Handle session state changes
|
|
288
|
-
*/
|
|
289
|
-
const handleSessionStateChange = useCallback((newState) => {
|
|
120
|
+
const handleInitComplete = useCallback((newState, generatedFiles) => {
|
|
290
121
|
setSessionState(newState);
|
|
291
|
-
|
|
122
|
+
const fileCount = generatedFiles?.length ?? 0;
|
|
123
|
+
const msg = fileCount > 0
|
|
124
|
+
? `\u2713 Initialization complete. Generated ${fileCount} configuration file${fileCount === 1 ? '' : 's'}.`
|
|
125
|
+
: '\u2713 Initialization complete.';
|
|
126
|
+
navigate('shell', { message: msg, generatedFiles });
|
|
127
|
+
}, [navigate]);
|
|
292
128
|
/**
|
|
293
|
-
* Handle
|
|
129
|
+
* Handle run completion - dismiss background run if any, navigate to shell
|
|
294
130
|
*/
|
|
295
|
-
const
|
|
296
|
-
//
|
|
297
|
-
|
|
298
|
-
setSessionState(newState);
|
|
131
|
+
const handleRunComplete = useCallback((summary) => {
|
|
132
|
+
// Dismiss from background tracking if it was backgrounded
|
|
133
|
+
dismiss(summary.feature);
|
|
299
134
|
navigate('shell');
|
|
300
|
-
}, [
|
|
135
|
+
}, [dismiss, navigate]);
|
|
301
136
|
/**
|
|
302
|
-
* Handle run
|
|
137
|
+
* Handle run background - add to background tracking, navigate to shell
|
|
303
138
|
*/
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
const stoppedCodes = new Set([130, 143]);
|
|
307
|
-
const exitState = summary.exitCode === 0
|
|
308
|
-
? { label: 'Complete', color: colors.green, message: 'Done. Feature loop completed successfully.' }
|
|
309
|
-
: stoppedCodes.has(summary.exitCode)
|
|
310
|
-
? { label: 'Stopped', color: colors.orange, message: 'Stopped. Feature loop interrupted.' }
|
|
311
|
-
: { label: 'Failed', color: colors.pink, message: `Done. Feature loop exited with code ${summary.exitCode}.` };
|
|
312
|
-
addToThread('run-complete', (_jsxs(Box, { flexDirection: "column", marginY: 1, children: [_jsx(StatusLine, { action: "Run Loop", phase: exitState.label, path: summary.feature }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Summary" }), _jsxs(Text, { children: ["- Feature: ", summary.feature] }), _jsxs(Text, { children: ["- Iterations: ", summary.iterations, "/", summary.maxIterations] }), _jsxs(Text, { children: ["- Tasks: ", summary.tasksDone, "/", summary.tasksTotal] }), _jsxs(Text, { children: ["- Tokens: ", formatNumber(totalTokens), " (in:", formatNumber(summary.tokensInput), " out:", formatNumber(summary.tokensOutput), ")"] }), summary.branch && summary.branch !== '-' && (_jsxs(Text, { children: ["- Branch: ", summary.branch] }))] }), _jsxs(Box, { marginTop: 1, flexDirection: "row", children: [_jsxs(Text, { color: exitState.color, children: [theme.chars.bullet, " "] }), _jsx(Text, { children: exitState.message })] }), (summary.errorTail || summary.logPath) && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [summary.logPath && (_jsxs(Text, { dimColor: true, children: ["Log: ", summary.logPath] })), summary.errorTail && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Last output:" }), summary.errorTail.split('\n').map((line, idx) => (_jsx(Text, { dimColor: true, children: line }, `${line}-${idx}`)))] }))] })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "What's next:" }), _jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: colors.green, children: "\u203A" }), _jsx(Text, { dimColor: true, children: "Review changes and open a PR if needed" })] }), _jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: colors.green, children: "\u203A" }), _jsxs(Text, { color: colors.blue, children: ["/new ", '<feature>'] }), _jsx(Text, { dimColor: true, children: "Create another feature specification" })] }), _jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(Text, { color: colors.green, children: "\u203A" }), _jsx(Text, { color: colors.blue, children: "/help" }), _jsx(Text, { dimColor: true, children: "See all commands" })] })] })] })));
|
|
139
|
+
const handleRunBackground = useCallback((featureName) => {
|
|
140
|
+
background(featureName);
|
|
313
141
|
navigate('shell');
|
|
314
|
-
}, [
|
|
315
|
-
//
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
142
|
+
}, [background, navigate]);
|
|
143
|
+
// Guard: redirect to shell if screen has invalid props (avoids setState during render)
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (currentScreen === 'interview') {
|
|
146
|
+
const featureName = screenProps?.featureName || interviewProps?.featureName;
|
|
147
|
+
if (!featureName || typeof featureName !== 'string') {
|
|
148
|
+
navigate('shell', { message: 'Feature name is required for the interview screen.' });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (!sessionState.provider) {
|
|
152
|
+
navigate('shell', { message: 'No AI provider configured. Run /init first.' });
|
|
153
|
+
}
|
|
320
154
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return (_jsx(MainShell, { sessionState: sessionState, onNavigate: navigate, onSessionStateChange: handleSessionStateChange }));
|
|
326
|
-
case 'interview': {
|
|
327
|
-
// Get feature name from props or navigation
|
|
328
|
-
const featureName = screenProps?.featureName || interviewProps?.featureName;
|
|
329
|
-
if (!featureName || typeof featureName !== 'string') {
|
|
330
|
-
// Missing feature name, go back to shell
|
|
331
|
-
navigate('shell');
|
|
332
|
-
return null;
|
|
333
|
-
}
|
|
334
|
-
if (!sessionState.provider) {
|
|
335
|
-
// No provider configured, can't run interview
|
|
336
|
-
navigate('shell');
|
|
337
|
-
return null;
|
|
338
|
-
}
|
|
339
|
-
return (_jsx(InterviewScreen, { featureName: featureName, projectRoot: sessionState.projectRoot, provider: sessionState.provider, model: sessionState.model, scanResult: sessionState.scanResult, specsPath: sessionState.config?.paths.specs, onComplete: handleInterviewComplete, onCancel: handleInterviewCancel }));
|
|
155
|
+
else if (currentScreen === 'run') {
|
|
156
|
+
const featureName = screenProps?.featureName;
|
|
157
|
+
if (!featureName || typeof featureName !== 'string') {
|
|
158
|
+
navigate('shell', { message: 'Feature name is required for the run screen.' });
|
|
340
159
|
}
|
|
341
|
-
|
|
342
|
-
|
|
160
|
+
}
|
|
161
|
+
else if (currentScreen !== 'shell' && currentScreen !== 'init') {
|
|
162
|
+
// Unknown screen — redirect to shell on next tick
|
|
163
|
+
navigate('shell', { message: `Internal error: unknown screen "${currentScreen}". Returned to shell.` });
|
|
164
|
+
}
|
|
165
|
+
}, [currentScreen, screenProps, interviewProps, sessionState.provider, navigate]);
|
|
166
|
+
// Render current screen
|
|
167
|
+
switch (currentScreen) {
|
|
168
|
+
case 'shell':
|
|
169
|
+
return (_jsx(MainShell, { header: headerElement, sessionState: sessionState, onNavigate: navigate, backgroundRuns: backgroundRuns, initialMessage: typeof screenProps?.message === 'string' ? screenProps.message : undefined, initialFiles: Array.isArray(screenProps?.generatedFiles) ? screenProps.generatedFiles : undefined }, screenProps?.message ? String(screenProps.message) : 'shell'));
|
|
170
|
+
case 'interview': {
|
|
171
|
+
const featureName = screenProps?.featureName || interviewProps?.featureName;
|
|
172
|
+
if (!featureName || typeof featureName !== 'string' || !sessionState.provider) {
|
|
173
|
+
return null; // useEffect will redirect to shell
|
|
343
174
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
175
|
+
return (_jsx(InterviewScreen, { header: headerElement, featureName: featureName, projectRoot: sessionState.projectRoot, provider: sessionState.provider, model: sessionState.model, scanResult: sessionState.scanResult, specsPath: sessionState.config?.paths.specs, onComplete: handleInterviewComplete, onCancel: handleInterviewCancel }));
|
|
176
|
+
}
|
|
177
|
+
case 'init':
|
|
178
|
+
return (_jsx(InitScreen, { header: headerElement, projectRoot: sessionState.projectRoot, sessionState: sessionState, onComplete: handleInitComplete, onCancel: () => navigate('shell') }));
|
|
179
|
+
case 'run': {
|
|
180
|
+
const featureName = screenProps?.featureName;
|
|
181
|
+
const monitorOnly = screenProps?.monitorOnly === true;
|
|
182
|
+
if (!featureName || typeof featureName !== 'string') {
|
|
183
|
+
return null; // useEffect will redirect to shell
|
|
351
184
|
}
|
|
352
|
-
|
|
353
|
-
|
|
185
|
+
return (_jsx(RunScreen, { header: headerElement, featureName: featureName, projectRoot: sessionState.projectRoot, sessionState: sessionState, monitorOnly: monitorOnly, onComplete: handleRunComplete, onBackground: handleRunBackground, onCancel: () => navigate('shell') }));
|
|
186
|
+
}
|
|
187
|
+
default: {
|
|
188
|
+
// Return fallback UI instead of calling navigate() during render (which would be setState during render).
|
|
189
|
+
// The useEffect guard above will redirect to shell on next tick.
|
|
190
|
+
const unknownScreen = currentScreen;
|
|
191
|
+
logger.error(`Unknown screen: ${unknownScreen}`);
|
|
192
|
+
return (_jsx(Box, { flexDirection: "column", padding: 1, children: _jsxs(Text, { color: "red", children: ["Internal error: unknown screen \"", unknownScreen, "\". Redirecting to shell..."] }) }));
|
|
354
193
|
}
|
|
355
|
-
}
|
|
356
|
-
// Render with thread history (Static) + current screen
|
|
357
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: threadHistory, children: (item) => (_jsx(Box, { children: item.content }, item.id)) }, threadResetKey), !isTransitioning && renderCurrentScreen()] }));
|
|
194
|
+
}
|
|
358
195
|
}
|
|
359
196
|
/**
|
|
360
197
|
* Render the App component to the terminal
|
|
361
|
-
*
|
|
362
|
-
* Helper function that wraps Ink's render() to provide a clean API
|
|
363
|
-
* for starting the TUI from command handlers.
|
|
364
|
-
*
|
|
365
|
-
* @param options - Render options
|
|
366
|
-
* @returns Ink Instance that can be used to control/cleanup the render
|
|
367
|
-
*
|
|
368
|
-
* @example
|
|
369
|
-
* ```typescript
|
|
370
|
-
* const instance = renderApp({
|
|
371
|
-
* screen: 'welcome',
|
|
372
|
-
* initialSessionState: state,
|
|
373
|
-
* version: '0.8.0',
|
|
374
|
-
* onExit: () => instance.unmount(),
|
|
375
|
-
* });
|
|
376
|
-
*
|
|
377
|
-
* await instance.waitUntilExit();
|
|
378
|
-
* ```
|
|
379
198
|
*/
|
|
380
199
|
export function renderApp(options) {
|
|
381
|
-
if (options.screen === 'welcome') {
|
|
382
|
-
process.stdout.write('\x1b[3J\x1b[2J\x1b[0;0H');
|
|
383
|
-
}
|
|
384
200
|
return render(_jsx(App, { screen: options.screen, initialSessionState: options.initialSessionState, version: options.version, interviewProps: options.interviewProps, onComplete: options.onComplete, onExit: options.onExit }));
|
|
385
201
|
}
|
|
386
|
-
//# sourceMappingURL=app.js.map
|
|
@@ -99,4 +99,3 @@ export function ActionOutput({ actionName, description, status, output, error, p
|
|
|
99
99
|
export function ActionList({ actions, previewLines = 3, }) {
|
|
100
100
|
return (_jsx(Box, { flexDirection: "column", gap: 1, children: actions.map((action) => (_jsx(ActionOutput, { actionName: action.actionName, description: action.description, status: action.status, output: action.output, error: action.error, previewLines: previewLines }, action.id))) }));
|
|
101
101
|
}
|
|
102
|
-
//# sourceMappingURL=ActionOutput.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AppShell - Inline layout wrapper for TUI screens
|
|
3
|
+
*
|
|
4
|
+
* Provides a 6-zone inline layout that renders at natural height
|
|
5
|
+
* after the shell prompt. Screen transitions are clean React
|
|
6
|
+
* mount/unmount cycles.
|
|
7
|
+
*
|
|
8
|
+
* Zones:
|
|
9
|
+
* 1. Header: banner + status meta
|
|
10
|
+
* 2. TipsBar: contextual hints (1 row or 0)
|
|
11
|
+
* 3. Content: screen-specific (natural height)
|
|
12
|
+
* 4. Spinner: WorkingIndicator (1 row when active, 0 otherwise)
|
|
13
|
+
* 5. Error toast: error message (1 row when present, 0 otherwise)
|
|
14
|
+
* 6. Footer: input + status line
|
|
15
|
+
*/
|
|
16
|
+
import React from 'react';
|
|
17
|
+
import { type FooterStatusBarProps } from './FooterStatusBar.js';
|
|
18
|
+
/**
|
|
19
|
+
* Props for the AppShell component
|
|
20
|
+
*/
|
|
21
|
+
export interface AppShellProps {
|
|
22
|
+
/** Pre-built header element (HeaderContent) */
|
|
23
|
+
header: React.ReactNode;
|
|
24
|
+
/** Tip text (null/undefined to hide tips bar) */
|
|
25
|
+
tips?: string | null;
|
|
26
|
+
/** Content area - screen-specific */
|
|
27
|
+
children: React.ReactNode;
|
|
28
|
+
/** Show spinner bar */
|
|
29
|
+
isWorking?: boolean;
|
|
30
|
+
/** Spinner text */
|
|
31
|
+
workingStatus?: string;
|
|
32
|
+
/** Spinner hint (e.g. "esc to cancel") */
|
|
33
|
+
workingHint?: string;
|
|
34
|
+
/** Error message to display as a toast above the footer */
|
|
35
|
+
error?: string | null;
|
|
36
|
+
/** Input component: ChatInput, MultiSelect, Select, etc. */
|
|
37
|
+
input?: React.ReactNode;
|
|
38
|
+
/** Footer status bar props */
|
|
39
|
+
footerStatus: FooterStatusBarProps;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* AppShell component
|
|
43
|
+
*
|
|
44
|
+
* Compact inline layout. Renders at natural height right after
|
|
45
|
+
* the shell prompt. Each zone stacks vertically with gap spacing.
|
|
46
|
+
*/
|
|
47
|
+
export declare function AppShell({ header, tips, children, isWorking, workingStatus, workingHint, error, input, footerStatus, }: AppShellProps): React.ReactElement;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { TipsBar } from './TipsBar.js';
|
|
4
|
+
import { WorkingIndicator } from './WorkingIndicator.js';
|
|
5
|
+
import { FooterStatusBar } from './FooterStatusBar.js';
|
|
6
|
+
import { phase, theme } from '../theme.js';
|
|
7
|
+
/**
|
|
8
|
+
* AppShell component
|
|
9
|
+
*
|
|
10
|
+
* Compact inline layout. Renders at natural height right after
|
|
11
|
+
* the shell prompt. Each zone stacks vertically with gap spacing.
|
|
12
|
+
*/
|
|
13
|
+
export function AppShell({ header, tips, children, isWorking = false, workingStatus = '', workingHint, error, input, footerStatus, }) {
|
|
14
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { marginTop: 1, flexDirection: "column", children: header }), tips && _jsx(TipsBar, { text: tips }), children, isWorking && (_jsx(WorkingIndicator, { state: {
|
|
15
|
+
isWorking: true,
|
|
16
|
+
status: workingStatus,
|
|
17
|
+
hint: workingHint,
|
|
18
|
+
}, variant: "active" })), error && (_jsxs(Text, { color: theme.colors.error, children: [phase.error, " ", error] })), _jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [input, _jsx(FooterStatusBar, { ...footerStatus })] })] }));
|
|
19
|
+
}
|
|
@@ -252,4 +252,3 @@ export function ChatInput({ onSubmit, placeholder = 'Type your message...', disa
|
|
|
252
252
|
const remainder = rightText ? rightText.slice(1) : '';
|
|
253
253
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: theme.colors.prompt, bold: true, children: [theme.chars.prompt, ' '] }), value.length === 0 ? (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { inverse: true, children: ' ' }), _jsx(Text, { dimColor: true, children: placeholder })] })) : (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { children: leftText }), _jsx(Text, { inverse: true, children: cursorChar }), _jsx(Text, { children: remainder })] }))] }), showDropdown && isSlashCommand && !hasSpace && (_jsx(CommandDropdown, { commands: commands, filter: commandFilter, onSelect: handleCommandSelect, onCancel: handleDropdownCancel }))] }));
|
|
254
254
|
}
|
|
255
|
-
//# sourceMappingURL=ChatInput.js.map
|