@zhijiewang/openharness 0.11.1 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +212 -23
- package/dist/DeferredTool.d.ts +34 -0
- package/dist/DeferredTool.js +62 -0
- package/dist/agents/roles.js +62 -6
- package/dist/commands/index.js +31 -2
- package/dist/harness/config.d.ts +15 -0
- package/dist/harness/config.js +45 -23
- package/dist/harness/memory.d.ts +12 -0
- package/dist/harness/memory.js +53 -2
- package/dist/harness/session.d.ts +19 -0
- package/dist/harness/session.js +53 -0
- package/dist/harness/verification.d.ts +41 -0
- package/dist/harness/verification.js +197 -0
- package/dist/mcp/registry.d.ts +31 -0
- package/dist/mcp/registry.js +180 -0
- package/dist/query/index.js +9 -1
- package/dist/query/tools.js +30 -4
- package/dist/repl.js +34 -0
- package/dist/services/AgentDispatcher.d.ts +1 -0
- package/dist/services/AgentDispatcher.js +10 -1
- package/dist/services/CronExecutor.d.ts +38 -0
- package/dist/services/CronExecutor.js +130 -0
- package/dist/services/StreamingToolExecutor.js +28 -0
- package/dist/services/cron.d.ts +4 -0
- package/dist/services/cron.js +27 -0
- package/dist/tools/AgentTool/index.d.ts +3 -0
- package/dist/tools/AgentTool/index.js +17 -4
- package/dist/tools/MemoryTool/index.d.ts +2 -2
- package/dist/tools/ToolSearchTool/index.js +7 -0
- package/dist/tools.d.ts +8 -0
- package/dist/tools.js +40 -41
- package/package.json +5 -2
- package/dist/Tool.d.ts.map +0 -1
- package/dist/Tool.js.map +0 -1
- package/dist/Tool.test.d.ts +0 -2
- package/dist/Tool.test.d.ts.map +0 -1
- package/dist/Tool.test.js +0 -48
- package/dist/Tool.test.js.map +0 -1
- package/dist/agents/roles.d.ts.map +0 -1
- package/dist/agents/roles.js.map +0 -1
- package/dist/agents/roles.test.d.ts +0 -2
- package/dist/agents/roles.test.d.ts.map +0 -1
- package/dist/agents/roles.test.js +0 -38
- package/dist/agents/roles.test.js.map +0 -1
- package/dist/commands/commands-new.test.d.ts +0 -5
- package/dist/commands/commands-new.test.d.ts.map +0 -1
- package/dist/commands/commands-new.test.js +0 -132
- package/dist/commands/commands-new.test.js.map +0 -1
- package/dist/commands/commands.test.d.ts +0 -2
- package/dist/commands/commands.test.d.ts.map +0 -1
- package/dist/commands/commands.test.js +0 -98
- package/dist/commands/commands.test.js.map +0 -1
- package/dist/commands/cybergotchi.d.ts.map +0 -1
- package/dist/commands/cybergotchi.js.map +0 -1
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js.map +0 -1
- package/dist/components/App.d.ts.map +0 -1
- package/dist/components/App.js.map +0 -1
- package/dist/components/CompanionFooter.d.ts.map +0 -1
- package/dist/components/CompanionFooter.js.map +0 -1
- package/dist/components/CybergotchiBubble.d.ts.map +0 -1
- package/dist/components/CybergotchiBubble.js.map +0 -1
- package/dist/components/CybergotchiPanel.d.ts.map +0 -1
- package/dist/components/CybergotchiPanel.js.map +0 -1
- package/dist/components/CybergotchiPanelConnected.d.ts.map +0 -1
- package/dist/components/CybergotchiPanelConnected.js.map +0 -1
- package/dist/components/CybergotchiSetup.d.ts.map +0 -1
- package/dist/components/CybergotchiSetup.js.map +0 -1
- package/dist/components/CybergotchiSprite.d.ts.map +0 -1
- package/dist/components/CybergotchiSprite.js.map +0 -1
- package/dist/components/DiffView.d.ts.map +0 -1
- package/dist/components/DiffView.js.map +0 -1
- package/dist/components/ErrorBoundary.d.ts.map +0 -1
- package/dist/components/ErrorBoundary.js.map +0 -1
- package/dist/components/InitWizard.d.ts.map +0 -1
- package/dist/components/InitWizard.js.map +0 -1
- package/dist/components/Markdown.d.ts.map +0 -1
- package/dist/components/Markdown.js.map +0 -1
- package/dist/components/Messages.d.ts.map +0 -1
- package/dist/components/Messages.js.map +0 -1
- package/dist/components/PermissionPrompt.d.ts.map +0 -1
- package/dist/components/PermissionPrompt.js.map +0 -1
- package/dist/components/REPL.d.ts.map +0 -1
- package/dist/components/REPL.js.map +0 -1
- package/dist/components/Spinner.d.ts.map +0 -1
- package/dist/components/Spinner.js.map +0 -1
- package/dist/components/TextInput.d.ts.map +0 -1
- package/dist/components/TextInput.js.map +0 -1
- package/dist/components/ToolCallDisplay.d.ts.map +0 -1
- package/dist/components/ToolCallDisplay.js.map +0 -1
- package/dist/cybergotchi/bones.d.ts.map +0 -1
- package/dist/cybergotchi/bones.js.map +0 -1
- package/dist/cybergotchi/bones.test.d.ts +0 -2
- package/dist/cybergotchi/bones.test.d.ts.map +0 -1
- package/dist/cybergotchi/bones.test.js +0 -100
- package/dist/cybergotchi/bones.test.js.map +0 -1
- package/dist/cybergotchi/config.d.ts.map +0 -1
- package/dist/cybergotchi/config.js.map +0 -1
- package/dist/cybergotchi/events.d.ts.map +0 -1
- package/dist/cybergotchi/events.js.map +0 -1
- package/dist/cybergotchi/needs.d.ts.map +0 -1
- package/dist/cybergotchi/needs.js.map +0 -1
- package/dist/cybergotchi/needs.test.d.ts +0 -2
- package/dist/cybergotchi/needs.test.d.ts.map +0 -1
- package/dist/cybergotchi/needs.test.js +0 -150
- package/dist/cybergotchi/needs.test.js.map +0 -1
- package/dist/cybergotchi/personality.d.ts.map +0 -1
- package/dist/cybergotchi/personality.js.map +0 -1
- package/dist/cybergotchi/species.d.ts.map +0 -1
- package/dist/cybergotchi/species.js.map +0 -1
- package/dist/cybergotchi/speech.d.ts.map +0 -1
- package/dist/cybergotchi/speech.js.map +0 -1
- package/dist/cybergotchi/types.d.ts.map +0 -1
- package/dist/cybergotchi/types.js.map +0 -1
- package/dist/cybergotchi/useCybergotchi.d.ts.map +0 -1
- package/dist/cybergotchi/useCybergotchi.js.map +0 -1
- package/dist/git/git.test.d.ts +0 -2
- package/dist/git/git.test.d.ts.map +0 -1
- package/dist/git/git.test.js +0 -141
- package/dist/git/git.test.js.map +0 -1
- package/dist/git/index.d.ts.map +0 -1
- package/dist/git/index.js.map +0 -1
- package/dist/harness/checkpoints.d.ts.map +0 -1
- package/dist/harness/checkpoints.js.map +0 -1
- package/dist/harness/config.d.ts.map +0 -1
- package/dist/harness/config.js.map +0 -1
- package/dist/harness/config.test.d.ts +0 -2
- package/dist/harness/config.test.d.ts.map +0 -1
- package/dist/harness/config.test.js +0 -107
- package/dist/harness/config.test.js.map +0 -1
- package/dist/harness/context-warning.d.ts.map +0 -1
- package/dist/harness/context-warning.js.map +0 -1
- package/dist/harness/context-warning.test.d.ts +0 -2
- package/dist/harness/context-warning.test.d.ts.map +0 -1
- package/dist/harness/context-warning.test.js +0 -72
- package/dist/harness/context-warning.test.js.map +0 -1
- package/dist/harness/cost.d.ts.map +0 -1
- package/dist/harness/cost.js.map +0 -1
- package/dist/harness/cost.test.d.ts +0 -2
- package/dist/harness/cost.test.d.ts.map +0 -1
- package/dist/harness/cost.test.js +0 -43
- package/dist/harness/cost.test.js.map +0 -1
- package/dist/harness/credentials.d.ts.map +0 -1
- package/dist/harness/credentials.js.map +0 -1
- package/dist/harness/credentials.test.d.ts +0 -2
- package/dist/harness/credentials.test.d.ts.map +0 -1
- package/dist/harness/credentials.test.js +0 -113
- package/dist/harness/credentials.test.js.map +0 -1
- package/dist/harness/hooks-env.test.d.ts +0 -5
- package/dist/harness/hooks-env.test.d.ts.map +0 -1
- package/dist/harness/hooks-env.test.js +0 -41
- package/dist/harness/hooks-env.test.js.map +0 -1
- package/dist/harness/hooks.d.ts.map +0 -1
- package/dist/harness/hooks.js.map +0 -1
- package/dist/harness/hooks.test.d.ts +0 -2
- package/dist/harness/hooks.test.d.ts.map +0 -1
- package/dist/harness/hooks.test.js +0 -24
- package/dist/harness/hooks.test.js.map +0 -1
- package/dist/harness/keybindings.d.ts.map +0 -1
- package/dist/harness/keybindings.js.map +0 -1
- package/dist/harness/keybindings.test.d.ts +0 -2
- package/dist/harness/keybindings.test.d.ts.map +0 -1
- package/dist/harness/keybindings.test.js +0 -38
- package/dist/harness/keybindings.test.js.map +0 -1
- package/dist/harness/memory.d.ts.map +0 -1
- package/dist/harness/memory.js.map +0 -1
- package/dist/harness/memory.test.d.ts +0 -2
- package/dist/harness/memory.test.d.ts.map +0 -1
- package/dist/harness/memory.test.js +0 -65
- package/dist/harness/memory.test.js.map +0 -1
- package/dist/harness/onboarding.d.ts.map +0 -1
- package/dist/harness/onboarding.js.map +0 -1
- package/dist/harness/onboarding.test.d.ts +0 -5
- package/dist/harness/onboarding.test.d.ts.map +0 -1
- package/dist/harness/onboarding.test.js +0 -93
- package/dist/harness/onboarding.test.js.map +0 -1
- package/dist/harness/plugins.d.ts.map +0 -1
- package/dist/harness/plugins.js.map +0 -1
- package/dist/harness/plugins.test.d.ts +0 -2
- package/dist/harness/plugins.test.d.ts.map +0 -1
- package/dist/harness/plugins.test.js +0 -97
- package/dist/harness/plugins.test.js.map +0 -1
- package/dist/harness/rules.d.ts.map +0 -1
- package/dist/harness/rules.js.map +0 -1
- package/dist/harness/rules.test.d.ts +0 -2
- package/dist/harness/rules.test.d.ts.map +0 -1
- package/dist/harness/rules.test.js +0 -54
- package/dist/harness/rules.test.js.map +0 -1
- package/dist/harness/session.d.ts.map +0 -1
- package/dist/harness/session.js.map +0 -1
- package/dist/harness/session.test.d.ts +0 -2
- package/dist/harness/session.test.d.ts.map +0 -1
- package/dist/harness/session.test.js +0 -37
- package/dist/harness/session.test.js.map +0 -1
- package/dist/harness/store.d.ts.map +0 -1
- package/dist/harness/store.js.map +0 -1
- package/dist/harness/store.test.d.ts +0 -2
- package/dist/harness/store.test.d.ts.map +0 -1
- package/dist/harness/store.test.js +0 -71
- package/dist/harness/store.test.js.map +0 -1
- package/dist/harness/submit-handler.d.ts.map +0 -1
- package/dist/harness/submit-handler.js.map +0 -1
- package/dist/harness/submit-handler.test.d.ts +0 -2
- package/dist/harness/submit-handler.test.d.ts.map +0 -1
- package/dist/harness/submit-handler.test.js +0 -62
- package/dist/harness/submit-handler.test.js.map +0 -1
- package/dist/lsp/client.d.ts.map +0 -1
- package/dist/lsp/client.js.map +0 -1
- package/dist/lsp/client.test.d.ts +0 -2
- package/dist/lsp/client.test.d.ts.map +0 -1
- package/dist/lsp/client.test.js +0 -44
- package/dist/lsp/client.test.js.map +0 -1
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/mcp/DeferredMcpTool.d.ts.map +0 -1
- package/dist/mcp/DeferredMcpTool.js.map +0 -1
- package/dist/mcp/McpTool.d.ts.map +0 -1
- package/dist/mcp/McpTool.js.map +0 -1
- package/dist/mcp/McpTool.test.d.ts +0 -2
- package/dist/mcp/McpTool.test.d.ts.map +0 -1
- package/dist/mcp/McpTool.test.js +0 -53
- package/dist/mcp/McpTool.test.js.map +0 -1
- package/dist/mcp/client.d.ts.map +0 -1
- package/dist/mcp/client.js.map +0 -1
- package/dist/mcp/loader.d.ts.map +0 -1
- package/dist/mcp/loader.js.map +0 -1
- package/dist/mcp/loader.test.d.ts +0 -7
- package/dist/mcp/loader.test.d.ts.map +0 -1
- package/dist/mcp/loader.test.js +0 -25
- package/dist/mcp/loader.test.js.map +0 -1
- package/dist/mcp/schema.d.ts.map +0 -1
- package/dist/mcp/schema.js.map +0 -1
- package/dist/mcp/schema.test.d.ts +0 -2
- package/dist/mcp/schema.test.d.ts.map +0 -1
- package/dist/mcp/schema.test.js +0 -33
- package/dist/mcp/schema.test.js.map +0 -1
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js.map +0 -1
- package/dist/mcp/server.test.d.ts +0 -2
- package/dist/mcp/server.test.d.ts.map +0 -1
- package/dist/mcp/server.test.js +0 -54
- package/dist/mcp/server.test.js.map +0 -1
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/mcp/types.js.map +0 -1
- package/dist/providers/anthropic-convert.test.d.ts +0 -5
- package/dist/providers/anthropic-convert.test.d.ts.map +0 -1
- package/dist/providers/anthropic-convert.test.js +0 -98
- package/dist/providers/anthropic-convert.test.js.map +0 -1
- package/dist/providers/anthropic.d.ts.map +0 -1
- package/dist/providers/anthropic.js.map +0 -1
- package/dist/providers/anthropic.test.d.ts +0 -2
- package/dist/providers/anthropic.test.d.ts.map +0 -1
- package/dist/providers/anthropic.test.js +0 -18
- package/dist/providers/anthropic.test.js.map +0 -1
- package/dist/providers/base.d.ts.map +0 -1
- package/dist/providers/base.js.map +0 -1
- package/dist/providers/index.d.ts.map +0 -1
- package/dist/providers/index.js.map +0 -1
- package/dist/providers/llamacpp.d.ts.map +0 -1
- package/dist/providers/llamacpp.js.map +0 -1
- package/dist/providers/llamacpp.test.d.ts +0 -2
- package/dist/providers/llamacpp.test.d.ts.map +0 -1
- package/dist/providers/llamacpp.test.js +0 -33
- package/dist/providers/llamacpp.test.js.map +0 -1
- package/dist/providers/message-format.test.d.ts +0 -2
- package/dist/providers/message-format.test.d.ts.map +0 -1
- package/dist/providers/message-format.test.js +0 -31
- package/dist/providers/message-format.test.js.map +0 -1
- package/dist/providers/ollama.d.ts.map +0 -1
- package/dist/providers/ollama.js.map +0 -1
- package/dist/providers/ollama.test.d.ts +0 -2
- package/dist/providers/ollama.test.d.ts.map +0 -1
- package/dist/providers/ollama.test.js +0 -40
- package/dist/providers/ollama.test.js.map +0 -1
- package/dist/providers/openai.d.ts.map +0 -1
- package/dist/providers/openai.js.map +0 -1
- package/dist/providers/openai.test.d.ts +0 -2
- package/dist/providers/openai.test.d.ts.map +0 -1
- package/dist/providers/openai.test.js +0 -23
- package/dist/providers/openai.test.js.map +0 -1
- package/dist/providers/openrouter.d.ts.map +0 -1
- package/dist/providers/openrouter.js.map +0 -1
- package/dist/providers/stream-parsing.test.d.ts +0 -6
- package/dist/providers/stream-parsing.test.d.ts.map +0 -1
- package/dist/providers/stream-parsing.test.js +0 -174
- package/dist/providers/stream-parsing.test.js.map +0 -1
- package/dist/query/compress.d.ts.map +0 -1
- package/dist/query/compress.js.map +0 -1
- package/dist/query/errors.d.ts.map +0 -1
- package/dist/query/errors.js.map +0 -1
- package/dist/query/index.d.ts.map +0 -1
- package/dist/query/index.js.map +0 -1
- package/dist/query/tools.d.ts.map +0 -1
- package/dist/query/tools.js.map +0 -1
- package/dist/query/types.d.ts.map +0 -1
- package/dist/query/types.js.map +0 -1
- package/dist/query.d.ts.map +0 -1
- package/dist/query.js.map +0 -1
- package/dist/query.test.d.ts +0 -2
- package/dist/query.test.d.ts.map +0 -1
- package/dist/query.test.js +0 -121
- package/dist/query.test.js.map +0 -1
- package/dist/remote/server.d.ts.map +0 -1
- package/dist/remote/server.js.map +0 -1
- package/dist/remote/server.test.d.ts +0 -2
- package/dist/remote/server.test.d.ts.map +0 -1
- package/dist/remote/server.test.js +0 -120
- package/dist/remote/server.test.js.map +0 -1
- package/dist/renderer/cells.d.ts.map +0 -1
- package/dist/renderer/cells.js.map +0 -1
- package/dist/renderer/cells.test.d.ts +0 -2
- package/dist/renderer/cells.test.d.ts.map +0 -1
- package/dist/renderer/cells.test.js +0 -69
- package/dist/renderer/cells.test.js.map +0 -1
- package/dist/renderer/colors.d.ts.map +0 -1
- package/dist/renderer/colors.js.map +0 -1
- package/dist/renderer/diff.d.ts.map +0 -1
- package/dist/renderer/diff.js.map +0 -1
- package/dist/renderer/diff.test.d.ts +0 -5
- package/dist/renderer/diff.test.d.ts.map +0 -1
- package/dist/renderer/diff.test.js +0 -140
- package/dist/renderer/diff.test.js.map +0 -1
- package/dist/renderer/differ.d.ts.map +0 -1
- package/dist/renderer/differ.js.map +0 -1
- package/dist/renderer/e2e.test.d.ts +0 -6
- package/dist/renderer/e2e.test.d.ts.map +0 -1
- package/dist/renderer/e2e.test.js +0 -702
- package/dist/renderer/e2e.test.js.map +0 -1
- package/dist/renderer/image.d.ts.map +0 -1
- package/dist/renderer/image.js.map +0 -1
- package/dist/renderer/image.test.d.ts +0 -5
- package/dist/renderer/image.test.d.ts.map +0 -1
- package/dist/renderer/image.test.js +0 -66
- package/dist/renderer/image.test.js.map +0 -1
- package/dist/renderer/index.d.ts.map +0 -1
- package/dist/renderer/index.js.map +0 -1
- package/dist/renderer/input.d.ts.map +0 -1
- package/dist/renderer/input.js.map +0 -1
- package/dist/renderer/input.test.d.ts +0 -5
- package/dist/renderer/input.test.d.ts.map +0 -1
- package/dist/renderer/input.test.js +0 -129
- package/dist/renderer/input.test.js.map +0 -1
- package/dist/renderer/layout.d.ts.map +0 -1
- package/dist/renderer/layout.js.map +0 -1
- package/dist/renderer/markdown.d.ts.map +0 -1
- package/dist/renderer/markdown.js.map +0 -1
- package/dist/renderer/markdown.test.d.ts +0 -2
- package/dist/renderer/markdown.test.d.ts.map +0 -1
- package/dist/renderer/markdown.test.js +0 -81
- package/dist/renderer/markdown.test.js.map +0 -1
- package/dist/renderer/perf.test.d.ts +0 -2
- package/dist/renderer/perf.test.d.ts.map +0 -1
- package/dist/renderer/perf.test.js +0 -128
- package/dist/renderer/perf.test.js.map +0 -1
- package/dist/renderer/session-browser.d.ts.map +0 -1
- package/dist/renderer/session-browser.js.map +0 -1
- package/dist/renderer/session-browser.test.d.ts +0 -6
- package/dist/renderer/session-browser.test.d.ts.map +0 -1
- package/dist/renderer/session-browser.test.js +0 -95
- package/dist/renderer/session-browser.test.js.map +0 -1
- package/dist/renderer/ui-ux.test.d.ts +0 -15
- package/dist/renderer/ui-ux.test.d.ts.map +0 -1
- package/dist/renderer/ui-ux.test.js +0 -470
- package/dist/renderer/ui-ux.test.js.map +0 -1
- package/dist/repl.d.ts.map +0 -1
- package/dist/repl.js.map +0 -1
- package/dist/services/AgentDispatcher.d.ts.map +0 -1
- package/dist/services/AgentDispatcher.js.map +0 -1
- package/dist/services/AgentDispatcher.test.d.ts +0 -2
- package/dist/services/AgentDispatcher.test.d.ts.map +0 -1
- package/dist/services/AgentDispatcher.test.js +0 -66
- package/dist/services/AgentDispatcher.test.js.map +0 -1
- package/dist/services/StreamingToolExecutor.d.ts.map +0 -1
- package/dist/services/StreamingToolExecutor.js.map +0 -1
- package/dist/services/StreamingToolExecutor.test.d.ts +0 -2
- package/dist/services/StreamingToolExecutor.test.d.ts.map +0 -1
- package/dist/services/StreamingToolExecutor.test.js +0 -103
- package/dist/services/StreamingToolExecutor.test.js.map +0 -1
- package/dist/services/agent-messaging.d.ts.map +0 -1
- package/dist/services/agent-messaging.js.map +0 -1
- package/dist/services/agent-messaging.test.d.ts +0 -2
- package/dist/services/agent-messaging.test.d.ts.map +0 -1
- package/dist/services/agent-messaging.test.js +0 -88
- package/dist/services/agent-messaging.test.js.map +0 -1
- package/dist/services/cron.d.ts.map +0 -1
- package/dist/services/cron.js.map +0 -1
- package/dist/services/cron.test.d.ts +0 -2
- package/dist/services/cron.test.d.ts.map +0 -1
- package/dist/services/cron.test.js +0 -49
- package/dist/services/cron.test.js.map +0 -1
- package/dist/test-helpers.d.ts +0 -31
- package/dist/test-helpers.d.ts.map +0 -1
- package/dist/test-helpers.js +0 -106
- package/dist/test-helpers.js.map +0 -1
- package/dist/tools/AgentTool/index.d.ts.map +0 -1
- package/dist/tools/AgentTool/index.js.map +0 -1
- package/dist/tools/AskUserTool/index.d.ts.map +0 -1
- package/dist/tools/AskUserTool/index.js.map +0 -1
- package/dist/tools/BashTool/index.d.ts.map +0 -1
- package/dist/tools/BashTool/index.js.map +0 -1
- package/dist/tools/CronTool/index.d.ts.map +0 -1
- package/dist/tools/CronTool/index.js.map +0 -1
- package/dist/tools/DiagnosticsTool/index.d.ts.map +0 -1
- package/dist/tools/DiagnosticsTool/index.js.map +0 -1
- package/dist/tools/EnterPlanModeTool/index.d.ts.map +0 -1
- package/dist/tools/EnterPlanModeTool/index.js.map +0 -1
- package/dist/tools/EnterWorktreeTool/index.d.ts.map +0 -1
- package/dist/tools/EnterWorktreeTool/index.js.map +0 -1
- package/dist/tools/ExitPlanModeTool/index.d.ts.map +0 -1
- package/dist/tools/ExitPlanModeTool/index.js.map +0 -1
- package/dist/tools/ExitWorktreeTool/index.d.ts.map +0 -1
- package/dist/tools/ExitWorktreeTool/index.js.map +0 -1
- package/dist/tools/FileEditTool/index.d.ts.map +0 -1
- package/dist/tools/FileEditTool/index.js.map +0 -1
- package/dist/tools/FileReadTool/index.d.ts.map +0 -1
- package/dist/tools/FileReadTool/index.js.map +0 -1
- package/dist/tools/FileWriteTool/index.d.ts.map +0 -1
- package/dist/tools/FileWriteTool/index.js.map +0 -1
- package/dist/tools/GlobTool/index.d.ts.map +0 -1
- package/dist/tools/GlobTool/index.js.map +0 -1
- package/dist/tools/GrepTool/index.d.ts.map +0 -1
- package/dist/tools/GrepTool/index.js.map +0 -1
- package/dist/tools/ImageReadTool/index.d.ts.map +0 -1
- package/dist/tools/ImageReadTool/index.js.map +0 -1
- package/dist/tools/KillProcessTool/index.d.ts.map +0 -1
- package/dist/tools/KillProcessTool/index.js.map +0 -1
- package/dist/tools/LSTool/index.d.ts.map +0 -1
- package/dist/tools/LSTool/index.js.map +0 -1
- package/dist/tools/MemoryTool/index.d.ts.map +0 -1
- package/dist/tools/MemoryTool/index.js.map +0 -1
- package/dist/tools/MultiEditTool/index.d.ts.map +0 -1
- package/dist/tools/MultiEditTool/index.js.map +0 -1
- package/dist/tools/NotebookEditTool/index.d.ts.map +0 -1
- package/dist/tools/NotebookEditTool/index.js.map +0 -1
- package/dist/tools/ParallelAgentTool/index.d.ts.map +0 -1
- package/dist/tools/ParallelAgentTool/index.js.map +0 -1
- package/dist/tools/RemoteTriggerTool/index.d.ts.map +0 -1
- package/dist/tools/RemoteTriggerTool/index.js.map +0 -1
- package/dist/tools/SendMessageTool/index.d.ts.map +0 -1
- package/dist/tools/SendMessageTool/index.js.map +0 -1
- package/dist/tools/SkillTool/index.d.ts.map +0 -1
- package/dist/tools/SkillTool/index.js.map +0 -1
- package/dist/tools/TaskCreateTool/index.d.ts.map +0 -1
- package/dist/tools/TaskCreateTool/index.js.map +0 -1
- package/dist/tools/TaskGetTool/index.d.ts.map +0 -1
- package/dist/tools/TaskGetTool/index.js.map +0 -1
- package/dist/tools/TaskListTool/index.d.ts.map +0 -1
- package/dist/tools/TaskListTool/index.js.map +0 -1
- package/dist/tools/TaskOutputTool/index.d.ts.map +0 -1
- package/dist/tools/TaskOutputTool/index.js.map +0 -1
- package/dist/tools/TaskStopTool/index.d.ts.map +0 -1
- package/dist/tools/TaskStopTool/index.js.map +0 -1
- package/dist/tools/TaskUpdateTool/index.d.ts.map +0 -1
- package/dist/tools/TaskUpdateTool/index.js.map +0 -1
- package/dist/tools/ToolSearchTool/index.d.ts.map +0 -1
- package/dist/tools/ToolSearchTool/index.js.map +0 -1
- package/dist/tools/WebFetchTool/index.d.ts.map +0 -1
- package/dist/tools/WebFetchTool/index.js.map +0 -1
- package/dist/tools/WebSearchTool/index.d.ts.map +0 -1
- package/dist/tools/WebSearchTool/index.js.map +0 -1
- package/dist/tools/file-edit.test.d.ts +0 -2
- package/dist/tools/file-edit.test.d.ts.map +0 -1
- package/dist/tools/file-edit.test.js +0 -35
- package/dist/tools/file-edit.test.js.map +0 -1
- package/dist/tools/tools-basic.test.d.ts +0 -6
- package/dist/tools/tools-basic.test.d.ts.map +0 -1
- package/dist/tools/tools-basic.test.js +0 -379
- package/dist/tools/tools-basic.test.js.map +0 -1
- package/dist/tools/web-fetch.test.d.ts +0 -2
- package/dist/tools/web-fetch.test.d.ts.map +0 -1
- package/dist/tools/web-fetch.test.js +0 -27
- package/dist/tools/web-fetch.test.js.map +0 -1
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js.map +0 -1
- package/dist/types/events.d.ts.map +0 -1
- package/dist/types/events.js.map +0 -1
- package/dist/types/message.d.ts.map +0 -1
- package/dist/types/message.js.map +0 -1
- package/dist/types/message.test.d.ts +0 -2
- package/dist/types/message.test.d.ts.map +0 -1
- package/dist/types/message.test.js +0 -46
- package/dist/types/message.test.js.map +0 -1
- package/dist/types/permissions.d.ts.map +0 -1
- package/dist/types/permissions.js.map +0 -1
- package/dist/types/permissions.test.d.ts +0 -2
- package/dist/types/permissions.test.d.ts.map +0 -1
- package/dist/types/permissions.test.js +0 -127
- package/dist/types/permissions.test.js.map +0 -1
- package/dist/utils/bash-safety.d.ts.map +0 -1
- package/dist/utils/bash-safety.js.map +0 -1
- package/dist/utils/bash-safety.test.d.ts +0 -2
- package/dist/utils/bash-safety.test.d.ts.map +0 -1
- package/dist/utils/bash-safety.test.js +0 -112
- package/dist/utils/bash-safety.test.js.map +0 -1
- package/dist/utils/diff-algorithm.d.ts.map +0 -1
- package/dist/utils/diff-algorithm.js.map +0 -1
- package/dist/utils/diff-algorithm.test.d.ts +0 -2
- package/dist/utils/diff-algorithm.test.d.ts.map +0 -1
- package/dist/utils/diff-algorithm.test.js +0 -49
- package/dist/utils/diff-algorithm.test.js.map +0 -1
- package/dist/utils/format.d.ts.map +0 -1
- package/dist/utils/format.js.map +0 -1
- package/dist/utils/fs.d.ts.map +0 -1
- package/dist/utils/fs.js.map +0 -1
- package/dist/utils/fs.test.d.ts +0 -5
- package/dist/utils/fs.test.d.ts.map +0 -1
- package/dist/utils/fs.test.js +0 -82
- package/dist/utils/fs.test.js.map +0 -1
- package/dist/utils/safe-env.d.ts.map +0 -1
- package/dist/utils/safe-env.js.map +0 -1
- package/dist/utils/theme-data.d.ts.map +0 -1
- package/dist/utils/theme-data.js.map +0 -1
- package/dist/utils/theme.d.ts.map +0 -1
- package/dist/utils/theme.js.map +0 -1
- package/dist/utils/tool-summary.d.ts.map +0 -1
- package/dist/utils/tool-summary.js.map +0 -1
- package/dist/utils/tool-summary.test.d.ts +0 -2
- package/dist/utils/tool-summary.test.d.ts.map +0 -1
- package/dist/utils/tool-summary.test.js +0 -93
- package/dist/utils/tool-summary.test.js.map +0 -1
|
@@ -1,702 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* End-to-end test for the cell renderer REPL.
|
|
3
|
-
* Tests the full state machine: message → render → tool call → complete.
|
|
4
|
-
*/
|
|
5
|
-
import { describe, it } from 'node:test';
|
|
6
|
-
import assert from 'node:assert';
|
|
7
|
-
import { CellGrid } from './cells.js';
|
|
8
|
-
import { rasterize, rasterizeLive } from './layout.js';
|
|
9
|
-
import { setActiveTheme } from '../utils/theme-data.js';
|
|
10
|
-
setActiveTheme('dark');
|
|
11
|
-
function makeState(overrides = {}) {
|
|
12
|
-
return {
|
|
13
|
-
messages: [],
|
|
14
|
-
streamingText: '',
|
|
15
|
-
thinkingText: '',
|
|
16
|
-
toolCalls: new Map(),
|
|
17
|
-
inputText: '',
|
|
18
|
-
inputCursor: 0,
|
|
19
|
-
companionLines: null,
|
|
20
|
-
companionColor: 'cyan',
|
|
21
|
-
statusHints: 'exit to quit',
|
|
22
|
-
statusLine: '',
|
|
23
|
-
contextWarning: null,
|
|
24
|
-
errorText: null,
|
|
25
|
-
loading: false,
|
|
26
|
-
spinnerFrame: 0,
|
|
27
|
-
thinkingStartedAt: null,
|
|
28
|
-
tokenCount: 0,
|
|
29
|
-
vimMode: null,
|
|
30
|
-
permissionBox: null,
|
|
31
|
-
permissionDiffVisible: false,
|
|
32
|
-
permissionDiffInfo: null,
|
|
33
|
-
expandedToolCalls: new Set(),
|
|
34
|
-
questionPrompt: null,
|
|
35
|
-
autocomplete: [],
|
|
36
|
-
autocompleteIndex: -1,
|
|
37
|
-
manualScroll: 0,
|
|
38
|
-
codeBlocksExpanded: false,
|
|
39
|
-
sessionBrowser: null,
|
|
40
|
-
bannerLines: null,
|
|
41
|
-
thinkingExpanded: false,
|
|
42
|
-
lastThinkingSummary: null,
|
|
43
|
-
autocompleteDescriptions: [],
|
|
44
|
-
notifications: [],
|
|
45
|
-
...overrides,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function gridText(grid, row) {
|
|
49
|
-
return grid.cells[row].map(c => c.char).join('').trimEnd();
|
|
50
|
-
}
|
|
51
|
-
describe('E2E: REPL state machine', () => {
|
|
52
|
-
it('renders empty state with input prompt', () => {
|
|
53
|
-
const state = makeState();
|
|
54
|
-
const grid = new CellGrid(80, 24);
|
|
55
|
-
const cursor = rasterize(state, grid);
|
|
56
|
-
// Should show input prompt
|
|
57
|
-
const inputLine = gridText(grid, cursor.cursorRow);
|
|
58
|
-
assert.ok(inputLine.includes('❯'), 'Should show input prompt');
|
|
59
|
-
});
|
|
60
|
-
it('renders user message', () => {
|
|
61
|
-
const state = makeState({
|
|
62
|
-
messages: [{
|
|
63
|
-
role: 'user',
|
|
64
|
-
content: 'hello world',
|
|
65
|
-
uuid: 'u1',
|
|
66
|
-
timestamp: Date.now(),
|
|
67
|
-
}],
|
|
68
|
-
});
|
|
69
|
-
const grid = new CellGrid(80, 24);
|
|
70
|
-
rasterize(state, grid);
|
|
71
|
-
const line0 = gridText(grid, 0);
|
|
72
|
-
assert.ok(line0.includes('hello world'), `Expected user message, got: ${line0}`);
|
|
73
|
-
});
|
|
74
|
-
it('renders assistant message with markdown', () => {
|
|
75
|
-
const state = makeState({
|
|
76
|
-
messages: [
|
|
77
|
-
{ role: 'user', content: 'hi', uuid: 'u1', timestamp: Date.now() },
|
|
78
|
-
{ role: 'assistant', content: '# Hello\n\nWorld', uuid: 'a1', timestamp: Date.now() },
|
|
79
|
-
],
|
|
80
|
-
});
|
|
81
|
-
const grid = new CellGrid(80, 24);
|
|
82
|
-
rasterize(state, grid);
|
|
83
|
-
// Find the heading
|
|
84
|
-
let found = false;
|
|
85
|
-
for (let r = 0; r < grid.height; r++) {
|
|
86
|
-
const line = gridText(grid, r);
|
|
87
|
-
if (line.includes('# Hello')) {
|
|
88
|
-
found = true;
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
assert.ok(found, 'Should render markdown heading');
|
|
93
|
-
});
|
|
94
|
-
it('renders spinner when loading with no streaming text', () => {
|
|
95
|
-
const state = makeState({
|
|
96
|
-
loading: true,
|
|
97
|
-
thinkingStartedAt: Date.now(),
|
|
98
|
-
});
|
|
99
|
-
const grid = new CellGrid(80, 24);
|
|
100
|
-
rasterize(state, grid);
|
|
101
|
-
let found = false;
|
|
102
|
-
for (let r = 0; r < grid.height; r++) {
|
|
103
|
-
if (gridText(grid, r).includes('Thinking')) {
|
|
104
|
-
found = true;
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
assert.ok(found, 'Should show shimmer spinner');
|
|
109
|
-
});
|
|
110
|
-
it('renders streaming text', () => {
|
|
111
|
-
const state = makeState({
|
|
112
|
-
loading: true,
|
|
113
|
-
streamingText: 'partial response text',
|
|
114
|
-
});
|
|
115
|
-
const grid = new CellGrid(80, 24);
|
|
116
|
-
rasterize(state, grid);
|
|
117
|
-
let found = false;
|
|
118
|
-
for (let r = 0; r < grid.height; r++) {
|
|
119
|
-
if (gridText(grid, r).includes('partial response')) {
|
|
120
|
-
found = true;
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
assert.ok(found, 'Should render streaming text');
|
|
125
|
-
});
|
|
126
|
-
it('renders tool calls with status icons', () => {
|
|
127
|
-
const toolCalls = new Map();
|
|
128
|
-
toolCalls.set('tc1', { toolName: 'Read', status: 'done', args: '/path/to/file.ts', output: 'file content' });
|
|
129
|
-
toolCalls.set('tc2', { toolName: 'Bash', status: 'running', args: '$ npm test' });
|
|
130
|
-
const state = makeState({ toolCalls, loading: true, thinkingStartedAt: Date.now() });
|
|
131
|
-
const grid = new CellGrid(80, 24);
|
|
132
|
-
rasterize(state, grid);
|
|
133
|
-
let foundRead = false, foundBash = false;
|
|
134
|
-
for (let r = 0; r < grid.height; r++) {
|
|
135
|
-
const line = gridText(grid, r);
|
|
136
|
-
if (line.includes('Read') && line.includes('✓'))
|
|
137
|
-
foundRead = true;
|
|
138
|
-
if (line.includes('Bash') && line.includes('⠋'))
|
|
139
|
-
foundBash = true;
|
|
140
|
-
}
|
|
141
|
-
assert.ok(foundRead, 'Should show completed tool with ✓');
|
|
142
|
-
assert.ok(foundBash, 'Should show running tool with spinner');
|
|
143
|
-
});
|
|
144
|
-
it('renders permission prompt box', () => {
|
|
145
|
-
const state = makeState({
|
|
146
|
-
permissionBox: { toolName: 'Bash', description: '{"command":"rm -rf /"}', riskLevel: 'high', suggestion: '$ rm -rf /' },
|
|
147
|
-
});
|
|
148
|
-
const grid = new CellGrid(80, 24);
|
|
149
|
-
rasterize(state, grid);
|
|
150
|
-
let foundTool = false, foundYN = false;
|
|
151
|
-
for (let r = 0; r < grid.height; r++) {
|
|
152
|
-
const line = gridText(grid, r);
|
|
153
|
-
if (line.includes('Bash') && line.includes('high risk'))
|
|
154
|
-
foundTool = true;
|
|
155
|
-
if (line.includes('Yes') && line.includes('No'))
|
|
156
|
-
foundYN = true;
|
|
157
|
-
}
|
|
158
|
-
assert.ok(foundTool, 'Should show tool name and risk');
|
|
159
|
-
assert.ok(foundYN, 'Should show Y/N options');
|
|
160
|
-
});
|
|
161
|
-
it('renders status line', () => {
|
|
162
|
-
const state = makeState({
|
|
163
|
-
statusLine: 'gemma3:12b │ 1.2K↑ 500↓ │ $0.0100',
|
|
164
|
-
});
|
|
165
|
-
const grid = new CellGrid(80, 24);
|
|
166
|
-
rasterize(state, grid);
|
|
167
|
-
let found = false;
|
|
168
|
-
for (let r = 0; r < grid.height; r++) {
|
|
169
|
-
if (gridText(grid, r).includes('gemma3:12b')) {
|
|
170
|
-
found = true;
|
|
171
|
-
break;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
assert.ok(found, 'Should show status line with model info');
|
|
175
|
-
});
|
|
176
|
-
it('renders context warning', () => {
|
|
177
|
-
const state = makeState({
|
|
178
|
-
contextWarning: { text: '⚠ Context ~85% full — consider /compact', critical: false },
|
|
179
|
-
});
|
|
180
|
-
const grid = new CellGrid(80, 24);
|
|
181
|
-
rasterize(state, grid);
|
|
182
|
-
let found = false;
|
|
183
|
-
for (let r = 0; r < grid.height; r++) {
|
|
184
|
-
if (gridText(grid, r).includes('Context ~85%')) {
|
|
185
|
-
found = true;
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
assert.ok(found, 'Should show context warning');
|
|
190
|
-
});
|
|
191
|
-
it('renders error message', () => {
|
|
192
|
-
const state = makeState({
|
|
193
|
-
errorText: 'Connection refused',
|
|
194
|
-
});
|
|
195
|
-
const grid = new CellGrid(80, 24);
|
|
196
|
-
rasterize(state, grid);
|
|
197
|
-
let found = false;
|
|
198
|
-
for (let r = 0; r < grid.height; r++) {
|
|
199
|
-
if (gridText(grid, r).includes('Connection refused')) {
|
|
200
|
-
found = true;
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
assert.ok(found, 'Should show error text');
|
|
205
|
-
});
|
|
206
|
-
it('renders question prompt', () => {
|
|
207
|
-
const state = makeState({
|
|
208
|
-
questionPrompt: { question: 'What is your name?', options: ['Alice', 'Bob'], input: 'Al', cursor: 2 },
|
|
209
|
-
});
|
|
210
|
-
const grid = new CellGrid(80, 24);
|
|
211
|
-
const cursor = rasterize(state, grid);
|
|
212
|
-
let foundQ = false;
|
|
213
|
-
for (let r = 0; r < grid.height; r++) {
|
|
214
|
-
if (gridText(grid, r).includes('What is your name?')) {
|
|
215
|
-
foundQ = true;
|
|
216
|
-
break;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
assert.ok(foundQ, 'Should show question');
|
|
220
|
-
// Cursor should be positioned in the question input
|
|
221
|
-
assert.strictEqual(cursor.cursorCol, 5 + 2, 'Cursor should be at input position');
|
|
222
|
-
});
|
|
223
|
-
// ── Scroll indicator ──
|
|
224
|
-
it('shows scroll-up indicator when content overflows and auto-scrolled', () => {
|
|
225
|
-
const messages = Array.from({ length: 50 }, (_, i) => ({
|
|
226
|
-
role: 'user',
|
|
227
|
-
content: `Message line ${i}`,
|
|
228
|
-
uuid: `u${i}`,
|
|
229
|
-
timestamp: Date.now(),
|
|
230
|
-
}));
|
|
231
|
-
const state = makeState({ messages, manualScroll: 0 });
|
|
232
|
-
const grid = new CellGrid(80, 24);
|
|
233
|
-
rasterize(state, grid);
|
|
234
|
-
let found = false;
|
|
235
|
-
for (let r = 0; r < grid.height; r++) {
|
|
236
|
-
if (gridText(grid, r).includes('more above')) {
|
|
237
|
-
found = true;
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
assert.ok(found, 'Should show ↑ more above indicator');
|
|
242
|
-
});
|
|
243
|
-
it('shows scroll-down indicator when user scrolled up', () => {
|
|
244
|
-
const messages = Array.from({ length: 50 }, (_, i) => ({
|
|
245
|
-
role: 'user',
|
|
246
|
-
content: `Message line ${i}`,
|
|
247
|
-
uuid: `u${i}`,
|
|
248
|
-
timestamp: Date.now(),
|
|
249
|
-
}));
|
|
250
|
-
const state = makeState({ messages, manualScroll: 10 });
|
|
251
|
-
const grid = new CellGrid(80, 24);
|
|
252
|
-
rasterize(state, grid);
|
|
253
|
-
let found = false;
|
|
254
|
-
for (let r = 0; r < grid.height; r++) {
|
|
255
|
-
if (gridText(grid, r).includes('more below')) {
|
|
256
|
-
found = true;
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
assert.ok(found, 'Should show ↓ more below indicator');
|
|
261
|
-
});
|
|
262
|
-
it('no scroll indicator when content fits', () => {
|
|
263
|
-
const state = makeState({
|
|
264
|
-
messages: [{ role: 'user', content: 'short', uuid: 'u1', timestamp: Date.now() }],
|
|
265
|
-
});
|
|
266
|
-
const grid = new CellGrid(80, 24);
|
|
267
|
-
rasterize(state, grid);
|
|
268
|
-
let found = false;
|
|
269
|
-
for (let r = 0; r < grid.height; r++) {
|
|
270
|
-
const line = gridText(grid, r);
|
|
271
|
-
if (line.includes('more above') || line.includes('more below')) {
|
|
272
|
-
found = true;
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
assert.ok(!found, 'Should not show scroll indicator when content fits');
|
|
277
|
-
});
|
|
278
|
-
// ── Collapsible thinking ──
|
|
279
|
-
it('renders collapsed thinking when loading with thinkingText', () => {
|
|
280
|
-
const state = makeState({
|
|
281
|
-
loading: true,
|
|
282
|
-
thinkingText: 'Analyzing the codebase...\nLooking at files...\nPlanning approach...',
|
|
283
|
-
thinkingStartedAt: Date.now() - 5000,
|
|
284
|
-
thinkingExpanded: false,
|
|
285
|
-
});
|
|
286
|
-
const grid = new CellGrid(80, 24);
|
|
287
|
-
rasterize(state, grid);
|
|
288
|
-
let foundCollapsed = false;
|
|
289
|
-
for (let r = 0; r < grid.height; r++) {
|
|
290
|
-
if (gridText(grid, r).includes('∴ Thinking')) {
|
|
291
|
-
foundCollapsed = true;
|
|
292
|
-
break;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
assert.ok(foundCollapsed, 'Should show collapsed thinking summary');
|
|
296
|
-
});
|
|
297
|
-
it('renders expanded thinking with multiple lines', () => {
|
|
298
|
-
const state = makeState({
|
|
299
|
-
loading: true,
|
|
300
|
-
thinkingText: 'Line 1\nLine 2\nLine 3\nLine 4',
|
|
301
|
-
thinkingStartedAt: Date.now() - 3000,
|
|
302
|
-
thinkingExpanded: true,
|
|
303
|
-
});
|
|
304
|
-
const grid = new CellGrid(80, 24);
|
|
305
|
-
rasterize(state, grid);
|
|
306
|
-
let thinkingLines = 0;
|
|
307
|
-
for (let r = 0; r < grid.height; r++) {
|
|
308
|
-
if (gridText(grid, r).includes('💭'))
|
|
309
|
-
thinkingLines++;
|
|
310
|
-
}
|
|
311
|
-
assert.ok(thinkingLines >= 3, `Should show multiple thinking lines, got ${thinkingLines}`);
|
|
312
|
-
});
|
|
313
|
-
it('renders lastThinkingSummary after completion', () => {
|
|
314
|
-
const state = makeState({
|
|
315
|
-
loading: false,
|
|
316
|
-
lastThinkingSummary: '∴ Thought for 5s [Ctrl+O]',
|
|
317
|
-
});
|
|
318
|
-
const grid = new CellGrid(80, 24);
|
|
319
|
-
rasterize(state, grid);
|
|
320
|
-
let found = false;
|
|
321
|
-
for (let r = 0; r < grid.height; r++) {
|
|
322
|
-
if (gridText(grid, r).includes('Thought for 5s')) {
|
|
323
|
-
found = true;
|
|
324
|
-
break;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
assert.ok(found, 'Should show thinking summary after completion');
|
|
328
|
-
});
|
|
329
|
-
it('does not show thinking summary when null', () => {
|
|
330
|
-
const state = makeState({ loading: false, lastThinkingSummary: null });
|
|
331
|
-
const grid = new CellGrid(80, 24);
|
|
332
|
-
rasterize(state, grid);
|
|
333
|
-
let found = false;
|
|
334
|
-
for (let r = 0; r < grid.height; r++) {
|
|
335
|
-
if (gridText(grid, r).includes('Thought for')) {
|
|
336
|
-
found = true;
|
|
337
|
-
break;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
assert.ok(!found, 'Should not show thinking summary when null');
|
|
341
|
-
});
|
|
342
|
-
// ── Banner clamping ──
|
|
343
|
-
it('renders full banner on large terminal', () => {
|
|
344
|
-
const bannerLines = [' ___', ' / \\', '( )', 'OpenHarness v1.0.0', ' ~/project (main)'];
|
|
345
|
-
const state = makeState({ bannerLines });
|
|
346
|
-
const grid = new CellGrid(80, 40); // tall terminal
|
|
347
|
-
rasterize(state, grid);
|
|
348
|
-
let found = false;
|
|
349
|
-
for (let r = 0; r < grid.height; r++) {
|
|
350
|
-
if (gridText(grid, r).includes('___')) {
|
|
351
|
-
found = true;
|
|
352
|
-
break;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
assert.ok(found, 'Should show ASCII art on large terminal');
|
|
356
|
-
});
|
|
357
|
-
it('renders compact banner on small terminal', () => {
|
|
358
|
-
// Art lines are indices 0-2, info lines are 3-4. Compact should only show last 2.
|
|
359
|
-
const bannerLines = ['ART_LINE_1', 'ART_LINE_2', 'ART_LINE_3', 'OpenHarness v1.0.0', ' ~/project (main)'];
|
|
360
|
-
const state = makeState({ bannerLines });
|
|
361
|
-
const grid = new CellGrid(80, 35); // h >= 30 so banner shows, h < 40 so compact mode
|
|
362
|
-
rasterize(state, grid);
|
|
363
|
-
let foundArt = false;
|
|
364
|
-
let foundVersion = false;
|
|
365
|
-
for (let r = 0; r < grid.height; r++) {
|
|
366
|
-
const line = gridText(grid, r);
|
|
367
|
-
if (line.includes('ART_LINE'))
|
|
368
|
-
foundArt = true;
|
|
369
|
-
if (line.includes('OpenHarness'))
|
|
370
|
-
foundVersion = true;
|
|
371
|
-
}
|
|
372
|
-
assert.ok(!foundArt, 'Should NOT show ASCII art on small terminal');
|
|
373
|
-
assert.ok(foundVersion, 'Should still show version info on small terminal');
|
|
374
|
-
});
|
|
375
|
-
// ── Scrollbar ──
|
|
376
|
-
it('renders scrollbar when content overflows', () => {
|
|
377
|
-
const messages = Array.from({ length: 50 }, (_, i) => ({
|
|
378
|
-
role: 'user',
|
|
379
|
-
content: `Message ${i}`,
|
|
380
|
-
uuid: `u${i}`,
|
|
381
|
-
timestamp: Date.now(),
|
|
382
|
-
}));
|
|
383
|
-
const state = makeState({ messages });
|
|
384
|
-
const grid = new CellGrid(80, 24);
|
|
385
|
-
rasterize(state, grid);
|
|
386
|
-
// Check rightmost column for scrollbar characters
|
|
387
|
-
let foundThumb = false;
|
|
388
|
-
let foundTrack = false;
|
|
389
|
-
for (let r = 0; r < 20; r++) {
|
|
390
|
-
const char = grid.cells[r][79].char;
|
|
391
|
-
if (char === '█')
|
|
392
|
-
foundThumb = true;
|
|
393
|
-
if (char === '░')
|
|
394
|
-
foundTrack = true;
|
|
395
|
-
}
|
|
396
|
-
assert.ok(foundThumb, 'Should render scrollbar thumb █');
|
|
397
|
-
assert.ok(foundTrack, 'Should render scrollbar track ░');
|
|
398
|
-
});
|
|
399
|
-
it('no scrollbar when content fits', () => {
|
|
400
|
-
const state = makeState({
|
|
401
|
-
messages: [{ role: 'user', content: 'short', uuid: 'u1', timestamp: Date.now() }],
|
|
402
|
-
});
|
|
403
|
-
const grid = new CellGrid(80, 24);
|
|
404
|
-
rasterize(state, grid);
|
|
405
|
-
let foundScrollbar = false;
|
|
406
|
-
for (let r = 0; r < 20; r++) {
|
|
407
|
-
const char = grid.cells[r][79].char;
|
|
408
|
-
if (char === '█' || char === '░')
|
|
409
|
-
foundScrollbar = true;
|
|
410
|
-
}
|
|
411
|
-
assert.ok(!foundScrollbar, 'Should not render scrollbar when content fits');
|
|
412
|
-
});
|
|
413
|
-
it('hides banner completely on very small terminal', () => {
|
|
414
|
-
const bannerLines = [' ___', 'OpenHarness v1.0.0', ' ~/project'];
|
|
415
|
-
const state = makeState({ bannerLines });
|
|
416
|
-
const grid = new CellGrid(80, 10); // very small
|
|
417
|
-
rasterize(state, grid);
|
|
418
|
-
let found = false;
|
|
419
|
-
for (let r = 0; r < grid.height; r++) {
|
|
420
|
-
if (gridText(grid, r).includes('OpenHarness')) {
|
|
421
|
-
found = true;
|
|
422
|
-
break;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
// With a 10-row terminal, msgAreaHeight may be < 8, so banner should be hidden
|
|
426
|
-
// (depends on footer height, but this tests the principle)
|
|
427
|
-
});
|
|
428
|
-
// ── Autocomplete with descriptions ──
|
|
429
|
-
it('renders autocomplete with descriptions', () => {
|
|
430
|
-
const state = makeState({
|
|
431
|
-
autocomplete: ['help', 'history'],
|
|
432
|
-
autocompleteDescriptions: ['Show available commands', 'List recent sessions'],
|
|
433
|
-
autocompleteIndex: 0,
|
|
434
|
-
});
|
|
435
|
-
const grid = new CellGrid(80, 24);
|
|
436
|
-
rasterize(state, grid);
|
|
437
|
-
let foundDesc = false;
|
|
438
|
-
for (let r = 0; r < grid.height; r++) {
|
|
439
|
-
if (gridText(grid, r).includes('Show available commands')) {
|
|
440
|
-
foundDesc = true;
|
|
441
|
-
break;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
assert.ok(foundDesc, 'Should show command description in autocomplete');
|
|
445
|
-
});
|
|
446
|
-
// ── Tool result summary ──
|
|
447
|
-
it('renders tool result summary for completed tools', () => {
|
|
448
|
-
const toolCalls = new Map();
|
|
449
|
-
toolCalls.set('tc1', {
|
|
450
|
-
toolName: 'Read',
|
|
451
|
-
status: 'done',
|
|
452
|
-
args: '/src/main.ts',
|
|
453
|
-
output: 'line1\nline2\nline3',
|
|
454
|
-
resultSummary: '3 lines',
|
|
455
|
-
startedAt: Date.now() - 2000,
|
|
456
|
-
});
|
|
457
|
-
const state = makeState({ toolCalls });
|
|
458
|
-
const grid = new CellGrid(80, 24);
|
|
459
|
-
rasterize(state, grid);
|
|
460
|
-
let found = false;
|
|
461
|
-
for (let r = 0; r < grid.height; r++) {
|
|
462
|
-
if (gridText(grid, r).includes('3 lines')) {
|
|
463
|
-
found = true;
|
|
464
|
-
break;
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
assert.ok(found, 'Should show result summary for completed tool');
|
|
468
|
-
});
|
|
469
|
-
// ── Agent mode UI ──
|
|
470
|
-
it('renders agent tool call with distinct icon and description', () => {
|
|
471
|
-
const toolCalls = new Map();
|
|
472
|
-
toolCalls.set('agent1', {
|
|
473
|
-
toolName: 'Agent',
|
|
474
|
-
status: 'running',
|
|
475
|
-
args: 'Explore codebase',
|
|
476
|
-
isAgent: true,
|
|
477
|
-
agentDescription: 'Search for authentication patterns across the project',
|
|
478
|
-
startedAt: Date.now(),
|
|
479
|
-
});
|
|
480
|
-
const state = makeState({ toolCalls, loading: true });
|
|
481
|
-
const grid = new CellGrid(80, 24);
|
|
482
|
-
rasterize(state, grid);
|
|
483
|
-
let foundIcon = false;
|
|
484
|
-
let foundDesc = false;
|
|
485
|
-
for (let r = 0; r < grid.height; r++) {
|
|
486
|
-
const line = gridText(grid, r);
|
|
487
|
-
if (line.includes('⊕') && line.includes('Agent'))
|
|
488
|
-
foundIcon = true;
|
|
489
|
-
if (line.includes('authentication patterns'))
|
|
490
|
-
foundDesc = true;
|
|
491
|
-
}
|
|
492
|
-
assert.ok(foundIcon, 'Should show agent icon ⊕');
|
|
493
|
-
assert.ok(foundDesc, 'Should show agent description');
|
|
494
|
-
});
|
|
495
|
-
it('renders completed agent with ◈ icon', () => {
|
|
496
|
-
const toolCalls = new Map();
|
|
497
|
-
toolCalls.set('agent1', {
|
|
498
|
-
toolName: 'Agent',
|
|
499
|
-
status: 'done',
|
|
500
|
-
isAgent: true,
|
|
501
|
-
output: 'Found 3 patterns',
|
|
502
|
-
});
|
|
503
|
-
const state = makeState({ toolCalls });
|
|
504
|
-
const grid = new CellGrid(80, 24);
|
|
505
|
-
rasterize(state, grid);
|
|
506
|
-
let found = false;
|
|
507
|
-
for (let r = 0; r < grid.height; r++) {
|
|
508
|
-
if (gridText(grid, r).includes('◈')) {
|
|
509
|
-
found = true;
|
|
510
|
-
break;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
assert.ok(found, 'Should show completed agent icon ◈');
|
|
514
|
-
});
|
|
515
|
-
// ── Multi-line input ──
|
|
516
|
-
it('renders multi-line input with continuation indent', () => {
|
|
517
|
-
const state = makeState({ inputText: 'line 1\nline 2\nline 3', inputCursor: 19 });
|
|
518
|
-
const grid = new CellGrid(80, 24);
|
|
519
|
-
const cursor = rasterize(state, grid);
|
|
520
|
-
// First line has prompt, continuation lines have indent
|
|
521
|
-
let foundLine2 = false;
|
|
522
|
-
for (let r = 0; r < grid.height; r++) {
|
|
523
|
-
const line = gridText(grid, r);
|
|
524
|
-
if (line.includes('line 2') && !line.includes('❯')) {
|
|
525
|
-
foundLine2 = true;
|
|
526
|
-
break;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
assert.ok(foundLine2, 'Should render continuation lines');
|
|
530
|
-
// Cursor should be on line 3
|
|
531
|
-
assert.ok(cursor.cursorRow > 0, 'Cursor should be past first row');
|
|
532
|
-
});
|
|
533
|
-
it('positions cursor correctly in multi-line input', () => {
|
|
534
|
-
// Cursor at start of second line: "abc\n" → 4 chars, cursor at 4
|
|
535
|
-
const state = makeState({ inputText: 'abc\ndef', inputCursor: 4 });
|
|
536
|
-
const grid = new CellGrid(80, 24);
|
|
537
|
-
const cursor = rasterize(state, grid);
|
|
538
|
-
// Cursor should be on second line, col = promptWidth (2 for default mode)
|
|
539
|
-
assert.strictEqual(cursor.cursorCol, 2, 'Cursor col should be at prompt width');
|
|
540
|
-
});
|
|
541
|
-
it('positions cursor correctly in multi-line input with vim mode', () => {
|
|
542
|
-
// With vim insert mode, prompt is "[I] ❯ " = 6 chars
|
|
543
|
-
const state = makeState({ inputText: 'abc\ndef', inputCursor: 4, vimMode: 'insert' });
|
|
544
|
-
const grid = new CellGrid(80, 24);
|
|
545
|
-
const cursor = rasterize(state, grid);
|
|
546
|
-
// Cursor should be at promptWidth = 6 (vim indicator + prompt)
|
|
547
|
-
assert.strictEqual(cursor.cursorCol, 6, 'Cursor col should match vim prompt width');
|
|
548
|
-
});
|
|
549
|
-
it('scrollback navigation changes visible content', () => {
|
|
550
|
-
const messages = Array.from({ length: 50 }, (_, i) => ({
|
|
551
|
-
role: 'user',
|
|
552
|
-
content: `Message ${i}`,
|
|
553
|
-
uuid: `u${i}`,
|
|
554
|
-
timestamp: Date.now(),
|
|
555
|
-
}));
|
|
556
|
-
const grid1 = new CellGrid(80, 24);
|
|
557
|
-
const state1 = makeState({ messages, manualScroll: 0 });
|
|
558
|
-
rasterize(state1, grid1);
|
|
559
|
-
const grid2 = new CellGrid(80, 24);
|
|
560
|
-
const state2 = makeState({ messages, manualScroll: 20 });
|
|
561
|
-
rasterize(state2, grid2);
|
|
562
|
-
// The two grids should show different content
|
|
563
|
-
const line1 = gridText(grid1, 0);
|
|
564
|
-
const line2 = gridText(grid2, 0);
|
|
565
|
-
assert.notStrictEqual(line1, line2, 'Scrolled view should show different content');
|
|
566
|
-
});
|
|
567
|
-
});
|
|
568
|
-
// ── rasterizeLive tests (the active production renderer) ──
|
|
569
|
-
describe('rasterizeLive: live area renderer', () => {
|
|
570
|
-
it('renders input prompt', () => {
|
|
571
|
-
const state = makeState();
|
|
572
|
-
const grid = new CellGrid(80, 10);
|
|
573
|
-
const cursor = rasterizeLive(state, grid);
|
|
574
|
-
let found = false;
|
|
575
|
-
for (let r = 0; r < grid.height; r++) {
|
|
576
|
-
if (gridText(grid, r).includes('❯')) {
|
|
577
|
-
found = true;
|
|
578
|
-
break;
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
assert.ok(found, 'Should show input prompt');
|
|
582
|
-
});
|
|
583
|
-
it('renders spinner when loading', () => {
|
|
584
|
-
const state = makeState({ loading: true, thinkingStartedAt: Date.now() });
|
|
585
|
-
const grid = new CellGrid(80, 10);
|
|
586
|
-
rasterizeLive(state, grid);
|
|
587
|
-
let found = false;
|
|
588
|
-
for (let r = 0; r < grid.height; r++) {
|
|
589
|
-
if (gridText(grid, r).includes('Thinking')) {
|
|
590
|
-
found = true;
|
|
591
|
-
break;
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
assert.ok(found, 'Should show spinner');
|
|
595
|
-
});
|
|
596
|
-
it('renders streaming text', () => {
|
|
597
|
-
const state = makeState({ loading: true, streamingText: 'streaming response' });
|
|
598
|
-
const grid = new CellGrid(80, 15);
|
|
599
|
-
rasterizeLive(state, grid);
|
|
600
|
-
let found = false;
|
|
601
|
-
for (let r = 0; r < grid.height; r++) {
|
|
602
|
-
if (gridText(grid, r).includes('streaming response')) {
|
|
603
|
-
found = true;
|
|
604
|
-
break;
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
assert.ok(found, 'Should show streaming text');
|
|
608
|
-
});
|
|
609
|
-
it('renders error text', () => {
|
|
610
|
-
const state = makeState({ errorText: 'Connection failed' });
|
|
611
|
-
const grid = new CellGrid(80, 10);
|
|
612
|
-
rasterizeLive(state, grid);
|
|
613
|
-
let found = false;
|
|
614
|
-
for (let r = 0; r < grid.height; r++) {
|
|
615
|
-
if (gridText(grid, r).includes('Connection failed')) {
|
|
616
|
-
found = true;
|
|
617
|
-
break;
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
assert.ok(found, 'Should show error');
|
|
621
|
-
});
|
|
622
|
-
it('renders tool calls', () => {
|
|
623
|
-
const toolCalls = new Map();
|
|
624
|
-
toolCalls.set('tc1', { toolName: 'Read', status: 'done', args: '/path/to/file.ts' });
|
|
625
|
-
const state = makeState({ toolCalls });
|
|
626
|
-
const grid = new CellGrid(80, 10);
|
|
627
|
-
rasterizeLive(state, grid);
|
|
628
|
-
let found = false;
|
|
629
|
-
for (let r = 0; r < grid.height; r++) {
|
|
630
|
-
if (gridText(grid, r).includes('Read') && gridText(grid, r).includes('✓')) {
|
|
631
|
-
found = true;
|
|
632
|
-
break;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
assert.ok(found, 'Should show completed tool');
|
|
636
|
-
});
|
|
637
|
-
it('renders permission prompt with Y/N', () => {
|
|
638
|
-
const state = makeState({
|
|
639
|
-
permissionBox: { toolName: 'Bash', description: 'rm -rf', riskLevel: 'high', suggestion: null },
|
|
640
|
-
});
|
|
641
|
-
const grid = new CellGrid(80, 12);
|
|
642
|
-
rasterizeLive(state, grid);
|
|
643
|
-
let foundTool = false, foundYN = false;
|
|
644
|
-
for (let r = 0; r < grid.height; r++) {
|
|
645
|
-
const line = gridText(grid, r);
|
|
646
|
-
if (line.includes('Bash') && line.includes('high'))
|
|
647
|
-
foundTool = true;
|
|
648
|
-
if (line.includes('Yes') && line.includes('No'))
|
|
649
|
-
foundYN = true;
|
|
650
|
-
}
|
|
651
|
-
assert.ok(foundTool, 'Should show tool name and risk');
|
|
652
|
-
assert.ok(foundYN, 'Should show Y/N options');
|
|
653
|
-
});
|
|
654
|
-
it('renders question prompt with correct cursor', () => {
|
|
655
|
-
const state = makeState({
|
|
656
|
-
questionPrompt: { question: 'Pick one', options: ['A', 'B'], input: 'A', cursor: 1 },
|
|
657
|
-
});
|
|
658
|
-
const grid = new CellGrid(80, 15);
|
|
659
|
-
const cursor = rasterizeLive(state, grid);
|
|
660
|
-
assert.strictEqual(cursor.cursorCol, 3 + 1, 'Cursor should be at col 3 + cursor offset');
|
|
661
|
-
});
|
|
662
|
-
it('renders status line', () => {
|
|
663
|
-
const state = makeState({ statusLine: 'llama3 │ 1K↑ 500↓' });
|
|
664
|
-
const grid = new CellGrid(80, 10);
|
|
665
|
-
rasterizeLive(state, grid);
|
|
666
|
-
let found = false;
|
|
667
|
-
for (let r = 0; r < grid.height; r++) {
|
|
668
|
-
if (gridText(grid, r).includes('llama3')) {
|
|
669
|
-
found = true;
|
|
670
|
-
break;
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
assert.ok(found, 'Should show status line');
|
|
674
|
-
});
|
|
675
|
-
it('renders context warning', () => {
|
|
676
|
-
const state = makeState({ contextWarning: { text: '⚠ Context 85% full', critical: false } });
|
|
677
|
-
const grid = new CellGrid(80, 10);
|
|
678
|
-
rasterizeLive(state, grid);
|
|
679
|
-
let found = false;
|
|
680
|
-
for (let r = 0; r < grid.height; r++) {
|
|
681
|
-
if (gridText(grid, r).includes('Context 85%')) {
|
|
682
|
-
found = true;
|
|
683
|
-
break;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
assert.ok(found, 'Should show context warning');
|
|
687
|
-
});
|
|
688
|
-
it('renders collapsed thinking summary', () => {
|
|
689
|
-
const state = makeState({ lastThinkingSummary: '∴ Thought for 3s [Ctrl+O]' });
|
|
690
|
-
const grid = new CellGrid(80, 10);
|
|
691
|
-
rasterizeLive(state, grid);
|
|
692
|
-
let found = false;
|
|
693
|
-
for (let r = 0; r < grid.height; r++) {
|
|
694
|
-
if (gridText(grid, r).includes('Thought for 3s')) {
|
|
695
|
-
found = true;
|
|
696
|
-
break;
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
assert.ok(found, 'Should show thinking summary');
|
|
700
|
-
});
|
|
701
|
-
});
|
|
702
|
-
//# sourceMappingURL=e2e.test.js.map
|