lonny-agent 0.2.4 → 0.2.7
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/.github/workflows/ci.yml +21 -0
- package/AGENTS.md +106 -0
- package/CHANGELOG.md +24 -0
- package/README.md +326 -326
- package/dist/agent/__tests__/session-restore.test.d.ts +2 -0
- package/dist/agent/__tests__/session-restore.test.d.ts.map +1 -0
- package/dist/agent/__tests__/session-restore.test.js +260 -0
- package/dist/agent/__tests__/session-restore.test.js.map +1 -0
- package/dist/agent/commands.d.ts +26 -0
- package/dist/agent/commands.d.ts.map +1 -0
- package/dist/agent/commands.js +253 -0
- package/dist/agent/commands.js.map +1 -0
- package/dist/agent/compaction.js +8 -1
- package/dist/agent/compaction.js.map +1 -1
- package/dist/agent/index.d.ts +2 -1
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +2 -2
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/llm.d.ts +4 -0
- package/dist/agent/llm.d.ts.map +1 -1
- package/dist/agent/memory.d.ts +12 -0
- package/dist/agent/memory.d.ts.map +1 -0
- package/dist/agent/memory.js +51 -0
- package/dist/agent/memory.js.map +1 -0
- package/dist/agent/prompt-builder.d.ts +6 -1
- package/dist/agent/prompt-builder.d.ts.map +1 -1
- package/dist/agent/prompt-builder.js +100 -33
- package/dist/agent/prompt-builder.js.map +1 -1
- package/dist/agent/providers/google.d.ts.map +1 -1
- package/dist/agent/providers/google.js.map +1 -1
- package/dist/agent/providers/openai.d.ts +1 -0
- package/dist/agent/providers/openai.d.ts.map +1 -1
- package/dist/agent/providers/openai.js +59 -6
- package/dist/agent/providers/openai.js.map +1 -1
- package/dist/agent/session-chat.d.ts +3 -0
- package/dist/agent/session-chat.d.ts.map +1 -0
- package/dist/agent/session-chat.js +384 -0
- package/dist/agent/session-chat.js.map +1 -0
- package/dist/agent/session-display.d.ts +29 -0
- package/dist/agent/session-display.d.ts.map +1 -0
- package/dist/agent/session-display.js +179 -0
- package/dist/agent/session-display.js.map +1 -0
- package/dist/agent/session-persistence.d.ts +55 -0
- package/dist/agent/session-persistence.d.ts.map +1 -0
- package/dist/agent/session-persistence.js +101 -0
- package/dist/agent/session-persistence.js.map +1 -0
- package/dist/agent/session-utils.d.ts +5 -0
- package/dist/agent/session-utils.d.ts.map +1 -0
- package/dist/agent/session-utils.js +51 -0
- package/dist/agent/session-utils.js.map +1 -0
- package/dist/agent/session.d.ts +19 -17
- package/dist/agent/session.d.ts.map +1 -1
- package/dist/agent/session.js +234 -578
- package/dist/agent/session.js.map +1 -1
- package/dist/cli/index.d.ts +4 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +67 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +2 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +7 -1
- package/dist/config/index.js.map +1 -1
- package/dist/index.js +24 -3
- package/dist/index.js.map +1 -1
- package/dist/tools/__tests__/bash.test.js +169 -2
- package/dist/tools/__tests__/bash.test.js.map +1 -1
- package/dist/tools/__tests__/edit.test.js +1091 -340
- package/dist/tools/__tests__/edit.test.js.map +1 -1
- package/dist/tools/__tests__/fetch.test.js +1 -1
- package/dist/tools/__tests__/fetch.test.js.map +1 -1
- package/dist/tools/__tests__/glob.test.js +1 -1
- package/dist/tools/__tests__/glob.test.js.map +1 -1
- package/dist/tools/__tests__/grep.test.js +33 -1
- package/dist/tools/__tests__/grep.test.js.map +1 -1
- package/dist/tools/__tests__/ls.test.js +1 -1
- package/dist/tools/__tests__/ls.test.js.map +1 -1
- package/dist/tools/__tests__/read.test.js +1 -1
- package/dist/tools/__tests__/read.test.js.map +1 -1
- package/dist/tools/__tests__/registry.test.js +313 -0
- package/dist/tools/__tests__/registry.test.js.map +1 -1
- package/dist/tools/__tests__/sed.test.d.ts +2 -0
- package/dist/tools/__tests__/sed.test.d.ts.map +1 -0
- package/dist/tools/__tests__/sed.test.js +228 -0
- package/dist/tools/__tests__/sed.test.js.map +1 -0
- package/dist/tools/__tests__/write_plan.test.js +1 -1
- package/dist/tools/__tests__/write_plan.test.js.map +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +711 -18
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/codebase/ast/__tests__/ast-edit-demo.d.ts +2 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-demo.d.ts.map +1 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-demo.js +7 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-demo.js.map +1 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-final.d.ts +6 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-final.d.ts.map +1 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-final.js +11 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-final.js.map +1 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-test.d.ts +2 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-test.d.ts.map +1 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-test.js +9 -0
- package/dist/tools/codebase/ast/__tests__/ast-edit-test.js.map +1 -0
- package/dist/tools/codebase/ast/__tests__/integration.test.d.ts +2 -0
- package/dist/tools/codebase/ast/__tests__/integration.test.d.ts.map +1 -0
- package/dist/tools/codebase/ast/__tests__/integration.test.js +415 -0
- package/dist/tools/codebase/ast/__tests__/integration.test.js.map +1 -0
- package/dist/tools/codebase/ast/__tests__/tree-sitter.test.d.ts +2 -0
- package/dist/tools/codebase/ast/__tests__/tree-sitter.test.d.ts.map +1 -0
- package/dist/tools/codebase/ast/__tests__/tree-sitter.test.js +414 -0
- package/dist/tools/codebase/ast/__tests__/tree-sitter.test.js.map +1 -0
- package/dist/tools/codebase/ast/adapter.d.ts +23 -0
- package/dist/tools/codebase/ast/adapter.d.ts.map +1 -0
- package/dist/tools/codebase/ast/adapter.js +11 -0
- package/dist/tools/codebase/ast/adapter.js.map +1 -0
- package/dist/tools/codebase/ast/tools.d.ts +3 -0
- package/dist/tools/codebase/ast/tools.d.ts.map +1 -0
- package/dist/tools/codebase/ast/tools.js +286 -0
- package/dist/tools/codebase/ast/tools.js.map +1 -0
- package/dist/tools/codebase/ast/tree-sitter-adapter.d.ts +3 -0
- package/dist/tools/codebase/ast/tree-sitter-adapter.d.ts.map +1 -0
- package/dist/tools/codebase/ast/tree-sitter-adapter.js +412 -0
- package/dist/tools/codebase/ast/tree-sitter-adapter.js.map +1 -0
- package/dist/tools/codebase/ast/tree-sitter-converters.d.ts +4 -0
- package/dist/tools/codebase/ast/tree-sitter-converters.d.ts.map +1 -0
- package/dist/tools/codebase/ast/tree-sitter-converters.js +447 -0
- package/dist/tools/codebase/ast/tree-sitter-converters.js.map +1 -0
- package/dist/tools/codebase/ast/types.d.ts +103 -0
- package/dist/tools/codebase/ast/types.d.ts.map +1 -0
- package/dist/tools/codebase/ast/types.js +2 -0
- package/dist/tools/codebase/ast/types.js.map +1 -0
- package/dist/tools/codebase/ast/wasm/tree-sitter-python.wasm +0 -0
- package/dist/tools/codebase/ast/wasm/tree-sitter-tsx.wasm +0 -0
- package/dist/tools/codebase/ast/wasm/tree-sitter-typescript.wasm +0 -0
- package/dist/tools/codebase/ast/wasm/tree-sitter.wasm +0 -0
- package/dist/tools/codebase/ast/wasm/web-tree-sitter.wasm +0 -0
- package/dist/tools/codebase/find.d.ts +3 -0
- package/dist/tools/codebase/find.d.ts.map +1 -0
- package/dist/tools/codebase/find.js +61 -0
- package/dist/tools/codebase/find.js.map +1 -0
- package/dist/tools/codebase/glob.d.ts +3 -0
- package/dist/tools/codebase/glob.d.ts.map +1 -0
- package/dist/tools/codebase/glob.js +37 -0
- package/dist/tools/codebase/glob.js.map +1 -0
- package/dist/tools/codebase/grep.d.ts +3 -0
- package/dist/tools/codebase/grep.d.ts.map +1 -0
- package/dist/tools/codebase/grep.js +169 -0
- package/dist/tools/codebase/grep.js.map +1 -0
- package/dist/tools/codebase/ls.d.ts +3 -0
- package/dist/tools/codebase/ls.d.ts.map +1 -0
- package/dist/tools/codebase/ls.js +39 -0
- package/dist/tools/codebase/ls.js.map +1 -0
- package/dist/tools/codebase/read.d.ts +10 -0
- package/dist/tools/codebase/read.d.ts.map +1 -0
- package/dist/tools/codebase/read.js +81 -0
- package/dist/tools/codebase/read.js.map +1 -0
- package/dist/tools/delete_memory.d.ts +3 -0
- package/dist/tools/delete_memory.d.ts.map +1 -0
- package/dist/tools/delete_memory.js +46 -0
- package/dist/tools/delete_memory.js.map +1 -0
- package/dist/tools/edit/diff-compute.d.ts +4 -0
- package/dist/tools/edit/diff-compute.d.ts.map +1 -0
- package/dist/tools/edit/diff-compute.js +18 -0
- package/dist/tools/edit/diff-compute.js.map +1 -0
- package/dist/tools/edit/diff-render.d.ts +18 -0
- package/dist/tools/edit/diff-render.d.ts.map +1 -0
- package/dist/tools/edit/diff-render.js +128 -0
- package/dist/tools/edit/diff-render.js.map +1 -0
- package/dist/tools/edit/edit.d.ts +4 -0
- package/dist/tools/edit/edit.d.ts.map +1 -0
- package/dist/tools/edit/edit.js +440 -0
- package/dist/tools/edit/edit.js.map +1 -0
- package/dist/tools/edit/matcher.d.ts +24 -0
- package/dist/tools/edit/matcher.d.ts.map +1 -0
- package/dist/tools/edit/matcher.js +66 -0
- package/dist/tools/edit/matcher.js.map +1 -0
- package/dist/tools/edit/parser.d.ts +10 -0
- package/dist/tools/edit/parser.d.ts.map +1 -0
- package/dist/tools/edit/parser.js +120 -0
- package/dist/tools/edit/parser.js.map +1 -0
- package/dist/tools/edit/types.d.ts +16 -0
- package/dist/tools/edit/types.d.ts.map +1 -0
- package/dist/tools/edit/types.js +2 -0
- package/dist/tools/edit/types.js.map +1 -0
- package/dist/tools/edit/write_plan.d.ts +5 -0
- package/dist/tools/edit/write_plan.d.ts.map +1 -0
- package/dist/tools/edit/write_plan.js +98 -0
- package/dist/tools/edit/write_plan.js.map +1 -0
- package/dist/tools/edit.d.ts +50 -9
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +394 -159
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/execute/bash/constants.d.ts +24 -0
- package/dist/tools/execute/bash/constants.d.ts.map +1 -0
- package/dist/tools/execute/bash/constants.js +88 -0
- package/dist/tools/execute/bash/constants.js.map +1 -0
- package/dist/tools/execute/bash/errors.d.ts +39 -0
- package/dist/tools/execute/bash/errors.d.ts.map +1 -0
- package/dist/tools/execute/bash/errors.js +249 -0
- package/dist/tools/execute/bash/errors.js.map +1 -0
- package/dist/tools/execute/bash/execution.d.ts +18 -0
- package/dist/tools/execute/bash/execution.d.ts.map +1 -0
- package/dist/tools/execute/bash/execution.js +207 -0
- package/dist/tools/execute/bash/execution.js.map +1 -0
- package/dist/tools/execute/bash/index.d.ts +3 -0
- package/dist/tools/execute/bash/index.d.ts.map +1 -0
- package/dist/tools/execute/bash/index.js +117 -0
- package/dist/tools/execute/bash/index.js.map +1 -0
- package/dist/tools/execute/bash/platform.d.ts +6 -0
- package/dist/tools/execute/bash/platform.d.ts.map +1 -0
- package/dist/tools/execute/bash/platform.js +64 -0
- package/dist/tools/execute/bash/platform.js.map +1 -0
- package/dist/tools/execute/bash/security.d.ts +12 -0
- package/dist/tools/execute/bash/security.d.ts.map +1 -0
- package/dist/tools/execute/bash/security.js +26 -0
- package/dist/tools/execute/bash/security.js.map +1 -0
- package/dist/tools/execute/bash/validation.d.ts +16 -0
- package/dist/tools/execute/bash/validation.d.ts.map +1 -0
- package/dist/tools/execute/bash/validation.js +57 -0
- package/dist/tools/execute/bash/validation.js.map +1 -0
- package/dist/tools/execute/bash.d.ts +3 -0
- package/dist/tools/execute/bash.d.ts.map +1 -0
- package/dist/tools/execute/bash.js +728 -0
- package/dist/tools/execute/bash.js.map +1 -0
- package/dist/tools/execute/git.d.ts +3 -0
- package/dist/tools/execute/git.d.ts.map +1 -0
- package/dist/tools/execute/git.js +183 -0
- package/dist/tools/execute/git.js.map +1 -0
- package/dist/tools/execute/task_complete.d.ts +7 -0
- package/dist/tools/execute/task_complete.d.ts.map +1 -0
- package/dist/tools/execute/task_complete.js +38 -0
- package/dist/tools/execute/task_complete.js.map +1 -0
- package/dist/tools/fetch.d.ts.map +1 -1
- package/dist/tools/fetch.js +2 -0
- package/dist/tools/fetch.js.map +1 -1
- package/dist/tools/find.d.ts.map +1 -1
- package/dist/tools/find.js +2 -0
- package/dist/tools/find.js.map +1 -1
- package/dist/tools/git.d.ts.map +1 -1
- package/dist/tools/git.js +2 -0
- package/dist/tools/git.js.map +1 -1
- package/dist/tools/glob.d.ts.map +1 -1
- package/dist/tools/glob.js +2 -0
- package/dist/tools/glob.js.map +1 -1
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +56 -30
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/install/clawhub.d.ts +26 -0
- package/dist/tools/install/clawhub.d.ts.map +1 -0
- package/dist/tools/install/clawhub.js +182 -0
- package/dist/tools/install/clawhub.js.map +1 -0
- package/dist/tools/install/constants.d.ts +5 -0
- package/dist/tools/install/constants.d.ts.map +1 -0
- package/dist/tools/install/constants.js +5 -0
- package/dist/tools/install/constants.js.map +1 -0
- package/dist/tools/install/install_skill.d.ts +3 -0
- package/dist/tools/install/install_skill.d.ts.map +1 -0
- package/dist/tools/install/install_skill.js +132 -0
- package/dist/tools/install/install_skill.js.map +1 -0
- package/dist/tools/install/npm.d.ts +8 -0
- package/dist/tools/install/npm.d.ts.map +1 -0
- package/dist/tools/install/npm.js +52 -0
- package/dist/tools/install/npm.js.map +1 -0
- package/dist/tools/install/skill-content.d.ts +9 -0
- package/dist/tools/install/skill-content.d.ts.map +1 -0
- package/dist/tools/install/skill-content.js +89 -0
- package/dist/tools/install/skill-content.js.map +1 -0
- package/dist/tools/install_skill.d.ts.map +1 -1
- package/dist/tools/install_skill.js +2 -0
- package/dist/tools/install_skill.js.map +1 -1
- package/dist/tools/list_memory.d.ts +3 -0
- package/dist/tools/list_memory.d.ts.map +1 -0
- package/dist/tools/list_memory.js +55 -0
- package/dist/tools/list_memory.js.map +1 -0
- package/dist/tools/ls.d.ts.map +1 -1
- package/dist/tools/ls.js +2 -0
- package/dist/tools/ls.js.map +1 -1
- package/dist/tools/memory/delete_memory.d.ts +3 -0
- package/dist/tools/memory/delete_memory.d.ts.map +1 -0
- package/dist/tools/memory/delete_memory.js +46 -0
- package/dist/tools/memory/delete_memory.js.map +1 -0
- package/dist/tools/memory/list_memory.d.ts +3 -0
- package/dist/tools/memory/list_memory.d.ts.map +1 -0
- package/dist/tools/memory/list_memory.js +55 -0
- package/dist/tools/memory/list_memory.js.map +1 -0
- package/dist/tools/memory/save_memory.d.ts +3 -0
- package/dist/tools/memory/save_memory.d.ts.map +1 -0
- package/dist/tools/memory/save_memory.js +45 -0
- package/dist/tools/memory/save_memory.js.map +1 -0
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +2 -0
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/registry.d.ts +7 -8
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +114 -46
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/save_memory.d.ts +3 -0
- package/dist/tools/save_memory.d.ts.map +1 -0
- package/dist/tools/save_memory.js +45 -0
- package/dist/tools/save_memory.js.map +1 -0
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +2 -0
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/sed.d.ts +4 -0
- package/dist/tools/sed.d.ts.map +1 -0
- package/dist/tools/sed.js +121 -0
- package/dist/tools/sed.js.map +1 -0
- package/dist/tools/tree.d.ts +12 -0
- package/dist/tools/tree.d.ts.map +1 -0
- package/dist/tools/tree.js +87 -0
- package/dist/tools/tree.js.map +1 -0
- package/dist/tools/types.d.ts +12 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/web/fetch.d.ts +3 -0
- package/dist/tools/web/fetch.d.ts.map +1 -0
- package/dist/tools/web/fetch.js +49 -0
- package/dist/tools/web/fetch.js.map +1 -0
- package/dist/tools/web/search.d.ts +3 -0
- package/dist/tools/web/search.d.ts.map +1 -0
- package/dist/tools/web/search.js +134 -0
- package/dist/tools/web/search.js.map +1 -0
- package/dist/tools/write_plan.d.ts.map +1 -1
- package/dist/tools/write_plan.js +2 -0
- package/dist/tools/write_plan.js.map +1 -1
- package/dist/tui/commands.d.ts +4 -0
- package/dist/tui/commands.d.ts.map +1 -0
- package/dist/tui/commands.js +118 -0
- package/dist/tui/commands.js.map +1 -0
- package/dist/tui/components/colors.d.ts +36 -0
- package/dist/tui/components/colors.d.ts.map +1 -0
- package/dist/tui/components/colors.js +48 -0
- package/dist/tui/components/colors.js.map +1 -0
- package/dist/tui/components/header-bar.d.ts +26 -0
- package/dist/tui/components/header-bar.d.ts.map +1 -0
- package/dist/tui/components/header-bar.js +78 -0
- package/dist/tui/components/header-bar.js.map +1 -0
- package/dist/tui/components/index.d.ts +9 -0
- package/dist/tui/components/index.d.ts.map +1 -0
- package/dist/tui/components/index.js +9 -0
- package/dist/tui/components/index.js.map +1 -0
- package/dist/tui/components/landing-screen.d.ts +12 -0
- package/dist/tui/components/landing-screen.d.ts.map +1 -0
- package/dist/tui/components/landing-screen.js +53 -0
- package/dist/tui/components/landing-screen.js.map +1 -0
- package/dist/tui/components/pixel-logo.d.ts +5 -0
- package/dist/tui/components/pixel-logo.d.ts.map +1 -0
- package/dist/tui/components/pixel-logo.js +27 -0
- package/dist/tui/components/pixel-logo.js.map +1 -0
- package/dist/tui/components/plan-utils.d.ts +11 -0
- package/dist/tui/components/plan-utils.d.ts.map +1 -0
- package/dist/tui/components/plan-utils.js +62 -0
- package/dist/tui/components/plan-utils.js.map +1 -0
- package/dist/tui/components/plans-list.d.ts +18 -0
- package/dist/tui/components/plans-list.d.ts.map +1 -0
- package/dist/tui/components/plans-list.js +46 -0
- package/dist/tui/components/plans-list.js.map +1 -0
- package/dist/tui/components/rich-footer.d.ts +29 -0
- package/dist/tui/components/rich-footer.d.ts.map +1 -0
- package/dist/tui/components/rich-footer.js +124 -0
- package/dist/tui/components/rich-footer.js.map +1 -0
- package/dist/tui/components/todo-panel.d.ts +14 -0
- package/dist/tui/components/todo-panel.d.ts.map +1 -0
- package/dist/tui/components/todo-panel.js +83 -0
- package/dist/tui/components/todo-panel.js.map +1 -0
- package/dist/tui/components.d.ts.map +1 -1
- package/dist/tui/components.js +14 -7
- package/dist/tui/components.js.map +1 -1
- package/dist/tui/index.d.ts +2 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +99 -505
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/overlays.d.ts +28 -0
- package/dist/tui/overlays.d.ts.map +1 -0
- package/dist/tui/overlays.js +154 -0
- package/dist/tui/overlays.js.map +1 -0
- package/dist/tui/themes.d.ts +5 -0
- package/dist/tui/themes.d.ts.map +1 -0
- package/dist/tui/themes.js +38 -0
- package/dist/tui/themes.js.map +1 -0
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +62 -101
- package/dist/web/index.js.map +1 -1
- package/dist/web/public/app.js +5 -855
- package/dist/web/public/confirm.js +70 -0
- package/dist/web/public/index.html +121 -120
- package/dist/web/public/input.js +107 -0
- package/dist/web/public/messages.js +411 -0
- package/dist/web/public/sidebar.js +82 -0
- package/dist/web/public/state.js +72 -0
- package/dist/web/public/style.css +247 -70
- package/dist/web/public/utils.js +37 -0
- package/dist/web/public/websocket.js +267 -0
- package/dist/web/public/ws.js +19 -0
- package/dist/web/session-bridge.d.ts.map +1 -1
- package/dist/web/session-bridge.js +85 -10
- package/dist/web/session-bridge.js.map +1 -1
- package/docs/ast-tools.md +117 -0
- package/package.json +11 -5
- package/scripts/check-line-count.mjs +53 -0
- package/scripts/copy-ast-wasm.mjs +32 -0
- package/scripts/copy-native.mjs +24 -0
- package/scripts/copy-web.mjs +15 -0
- package/src/agent/__tests__/session-restore.test.ts +284 -0
- package/src/agent/commands.ts +274 -0
- package/src/agent/compaction.ts +9 -2
- package/src/agent/index.ts +7 -2
- package/src/agent/llm.ts +4 -0
- package/src/agent/memory.ts +60 -0
- package/src/agent/prompt-builder.ts +111 -33
- package/src/agent/providers/google.ts +0 -1
- package/src/agent/providers/openai.ts +79 -8
- package/src/agent/session-chat.ts +480 -0
- package/src/agent/session-display.ts +195 -0
- package/src/agent/session-persistence.ts +146 -0
- package/src/agent/session-utils.ts +54 -0
- package/src/agent/session.ts +269 -670
- package/src/cli/index.ts +73 -4
- package/src/config/index.ts +14 -7
- package/src/index.ts +30 -3
- package/src/tools/__tests__/bash.test.ts +188 -2
- package/src/tools/__tests__/edit.test.ts +1216 -356
- package/src/tools/__tests__/fetch.test.ts +1 -1
- package/src/tools/__tests__/glob.test.ts +1 -1
- package/src/tools/__tests__/grep.test.ts +36 -1
- package/src/tools/__tests__/ls.test.ts +1 -1
- package/src/tools/__tests__/read.test.ts +1 -1
- package/src/tools/__tests__/registry.test.ts +332 -0
- package/src/tools/__tests__/write_plan.test.ts +1 -1
- package/src/tools/codebase/ast/__tests__/integration.test.ts +452 -0
- package/src/tools/codebase/ast/__tests__/tree-sitter.test.ts +466 -0
- package/src/tools/codebase/ast/adapter.ts +44 -0
- package/src/tools/codebase/ast/tools.ts +322 -0
- package/src/tools/codebase/ast/tree-sitter-adapter.ts +468 -0
- package/src/tools/codebase/ast/tree-sitter-converters.ts +480 -0
- package/src/tools/codebase/ast/types.ts +102 -0
- package/src/tools/codebase/ast/wasm/tree-sitter-python.wasm +0 -0
- package/src/tools/codebase/ast/wasm/tree-sitter-tsx.wasm +0 -0
- package/src/tools/codebase/ast/wasm/tree-sitter-typescript.wasm +0 -0
- package/src/tools/codebase/ast/wasm/tree-sitter.wasm +0 -0
- package/src/tools/codebase/ast/wasm/web-tree-sitter.wasm +0 -0
- package/src/tools/{find.ts → codebase/find.ts} +4 -2
- package/src/tools/{glob.ts → codebase/glob.ts} +4 -2
- package/src/tools/{grep.ts → codebase/grep.ts} +61 -32
- package/src/tools/{ls.ts → codebase/ls.ts} +4 -2
- package/src/tools/{read.ts → codebase/read.ts} +5 -3
- package/src/tools/edit/diff-compute.ts +21 -0
- package/src/tools/edit/diff-render.ts +145 -0
- package/src/tools/edit/edit.ts +468 -0
- package/src/tools/edit/matcher.ts +70 -0
- package/src/tools/edit/parser.ts +131 -0
- package/src/tools/edit/types.ts +19 -0
- package/src/tools/{write_plan.ts → edit/write_plan.ts} +4 -2
- package/src/tools/execute/bash/constants.ts +93 -0
- package/src/tools/execute/bash/errors.ts +304 -0
- package/src/tools/execute/bash/execution.ts +211 -0
- package/src/tools/execute/bash/index.ts +131 -0
- package/src/tools/execute/bash/platform.ts +65 -0
- package/src/tools/execute/bash/security.ts +28 -0
- package/src/tools/execute/bash/validation.ts +78 -0
- package/src/tools/execute/git.ts +209 -0
- package/src/tools/execute/task_complete.ts +40 -0
- package/src/tools/install/clawhub.ts +222 -0
- package/src/tools/install/constants.ts +4 -0
- package/src/tools/install/install_skill.ts +150 -0
- package/src/tools/install/npm.ts +60 -0
- package/src/tools/install/skill-content.ts +108 -0
- package/src/tools/memory/delete_memory.ts +46 -0
- package/src/tools/memory/list_memory.ts +53 -0
- package/src/tools/memory/save_memory.ts +45 -0
- package/src/tools/registry.ts +121 -50
- package/src/tools/tree.ts +103 -0
- package/src/tools/types.ts +13 -0
- package/src/tools/{fetch.ts → web/fetch.ts} +4 -2
- package/src/tools/{search.ts → web/search.ts} +4 -2
- package/src/tui/commands.ts +135 -0
- package/src/tui/components/colors.ts +52 -0
- package/src/tui/components/header-bar.ts +88 -0
- package/src/tui/components/index.ts +8 -0
- package/src/tui/components/landing-screen.ts +67 -0
- package/src/tui/components/pixel-logo.ts +33 -0
- package/src/tui/components/plan-utils.ts +69 -0
- package/src/tui/components/plans-list.ts +55 -0
- package/src/tui/components/rich-footer.ts +146 -0
- package/src/tui/components/todo-panel.ts +95 -0
- package/src/tui/index.ts +110 -561
- package/src/tui/overlays.ts +203 -0
- package/src/tui/themes.ts +41 -0
- package/src/web/index.ts +66 -107
- package/src/web/public/app.js +5 -855
- package/src/web/public/confirm.js +70 -0
- package/src/web/public/index.html +121 -120
- package/src/web/public/input.js +107 -0
- package/src/web/public/messages.js +411 -0
- package/src/web/public/sidebar.js +82 -0
- package/src/web/public/state.js +72 -0
- package/src/web/public/style.css +247 -70
- package/src/web/public/utils.js +37 -0
- package/src/web/public/websocket.js +267 -0
- package/src/web/public/ws.js +19 -0
- package/src/web/session-bridge.ts +90 -12
- package/.claude/settings.local.json +0 -14
- package/.kilo/plans/1780064105789-mighty-pixel.md +0 -171
- package/.kilo/plans/1780293725888-quick-wizard.md +0 -62
- package/.lonny/plan-web-cwd-status.md +0 -38
- package/AGENT.md +0 -99
- package/src/tools/bash.ts +0 -39
- package/src/tools/edit.ts +0 -554
- package/src/tools/exec.ts +0 -348
- package/src/tools/git.ts +0 -76
- package/src/tools/install_skill.ts +0 -539
- package/src/tui/components.ts +0 -635
package/src/tui/components.ts
DELETED
|
@@ -1,635 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs'
|
|
2
|
-
import * as path from 'node:path'
|
|
3
|
-
import type { Component, SelectItem, SelectListTheme } from '../pi-tui/index.js'
|
|
4
|
-
import { SelectList } from '../pi-tui/index.js'
|
|
5
|
-
import { PLAN_DIR } from '../tools/write_plan.js'
|
|
6
|
-
import { visibleLen } from './utils.js'
|
|
7
|
-
|
|
8
|
-
// ── ANSI Color Helpers ───────────────────────────────────────────────────────
|
|
9
|
-
|
|
10
|
-
// Re-applies background after every full reset (\x1b[0m) so that foreground
|
|
11
|
-
// color resets don't "punch through" the background.
|
|
12
|
-
function safeBg(text: string, bg: string): string {
|
|
13
|
-
return `\x1b[${bg}m${text.replace(/\x1b\[0m/g, `\x1b[0m\x1b[${bg}m`)}\x1b[0m`
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export const colors = {
|
|
17
|
-
bgDark: (text: string) => safeBg(text, '48;2;30;30;30'),
|
|
18
|
-
bgDim: (text: string) => safeBg(text, '48;2;25;25;25'),
|
|
19
|
-
headerBg: (text: string) => safeBg(text, '48;2;170;170;170'),
|
|
20
|
-
separator: (text: string) => `\x1b[38;2;60;60;60m${text}\x1b[0m`,
|
|
21
|
-
statusBg: (text: string) => safeBg(text, '48;2;25;25;35'),
|
|
22
|
-
running: (text: string) => `\x1b[38;2;0;255;100m${text}\x1b[0m`,
|
|
23
|
-
idle: (text: string) => `\x1b[38;2;150;150;150m${text}\x1b[0m`,
|
|
24
|
-
doneTodo: (text: string) => `\x1b[38;2;100;200;100m${text}\x1b[0m`,
|
|
25
|
-
todo: (text: string) => `\x1b[38;2;150;150;150m${text}\x1b[0m`,
|
|
26
|
-
accent: (text: string) => `\x1b[38;2;0;170;255m${text}\x1b[0m`,
|
|
27
|
-
dim: (text: string) => `\x1b[38;2;90;90;90m${text}\x1b[0m`,
|
|
28
|
-
userLabel: (text: string) => `\x1b[38;2;255;200;50m${text}\x1b[0m`,
|
|
29
|
-
assistantLabel: (text: string) => `\x1b[38;2;0;255;150m${text}\x1b[0m`,
|
|
30
|
-
error: (text: string) => `\x1b[38;2;255;80;80m${text}\x1b[0m`,
|
|
31
|
-
success: (text: string) => `\x1b[38;2;0;200;100m${text}\x1b[0m`,
|
|
32
|
-
inputPrompt: (text: string) => `\x1b[38;2;0;170;255m${text}\x1b[0m`,
|
|
33
|
-
warn: (text: string) => `\x1b[38;2;255;200;50m${text}\x1b[0m`,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ── App Version (read from package.json) ─────────────────────────────────
|
|
37
|
-
|
|
38
|
-
const APP_VERSION: string = (() => {
|
|
39
|
-
try {
|
|
40
|
-
const pkgPath = new URL('../../package.json', import.meta.url)
|
|
41
|
-
const raw = fs.readFileSync(pkgPath, 'utf-8')
|
|
42
|
-
return JSON.parse(raw).version || '0.1.0'
|
|
43
|
-
} catch {
|
|
44
|
-
return '0.1.0'
|
|
45
|
-
}
|
|
46
|
-
})()
|
|
47
|
-
|
|
48
|
-
// ── Pixel font for "lonnycode" logo (5 rows — 5 cols per char) ──────────
|
|
49
|
-
|
|
50
|
-
const PIXEL_FONT: Record<string, string[]> = {
|
|
51
|
-
L: ['█ ', '█ ', '█ ', '█ ', '█████'],
|
|
52
|
-
O: [' ███ ', '█ █', '█ █', '█ █', ' ███ '],
|
|
53
|
-
N: ['█ █', '██ █', '█ █ █', '█ ██', '█ █'],
|
|
54
|
-
Y: ['█ █', ' █ █ ', ' █ ', ' █ ', ' █ '],
|
|
55
|
-
C: [' ███ ', '█ ', '█ ', '█ ', ' ███ '],
|
|
56
|
-
D: ['███ ', '█ █ ', '█ █', '█ █ ', '███ '],
|
|
57
|
-
E: ['█████', '█ ', '███ ', '█ ', '█████'],
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const LONNY_CHARS = ['L', 'O', 'N', 'N', 'Y']
|
|
61
|
-
const CODE_CHARS = ['C', 'O', 'D', 'E']
|
|
62
|
-
|
|
63
|
-
const PIXEL_LOGO_WIDTH = 54 // 5 cols — 9 chars + 8 gaps + 2 gap between words
|
|
64
|
-
|
|
65
|
-
function renderPixelLogo(): string[] {
|
|
66
|
-
const midGray = '\x1b[38;2;160;160;160m'
|
|
67
|
-
const brightWhite = '\x1b[38;2;255;255;255m'
|
|
68
|
-
const reset = '\x1b[0m'
|
|
69
|
-
const lines: string[] = []
|
|
70
|
-
for (let row = 0; row < 5; row++) {
|
|
71
|
-
const lonnyPart = LONNY_CHARS.map(ch => PIXEL_FONT[ch][row]).join(' ')
|
|
72
|
-
const codePart = CODE_CHARS.map(ch => PIXEL_FONT[ch][row]).join(' ')
|
|
73
|
-
lines.push(`${midGray + lonnyPart} ${brightWhite}${codePart}${reset}`)
|
|
74
|
-
}
|
|
75
|
-
return lines
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ── Landing input colors ────────────────────────────────────────────────
|
|
79
|
-
|
|
80
|
-
export const landingColors = {
|
|
81
|
-
inputBg: '\x1b[48;2;35;35;35m',
|
|
82
|
-
inputBorder: '\x1b[38;2;60;60;60m',
|
|
83
|
-
cyanBar: '\x1b[38;2;0;200;255m',
|
|
84
|
-
placeholderDim: '\x1b[38;2;130;130;130m',
|
|
85
|
-
placeholderQuote: '\x1b[38;2;160;160;160m',
|
|
86
|
-
inputText: '\x1b[38;2;220;220;220m',
|
|
87
|
-
statusBg: '\x1b[48;2;18;18;18m',
|
|
88
|
-
statusText: '\x1b[38;2;110;110;110m',
|
|
89
|
-
statusAccent: '\x1b[38;2;0;170;255m',
|
|
90
|
-
reset: '\x1b[0m',
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// ── Helpers ──────────────────────────────────────────────────────────────
|
|
94
|
-
|
|
95
|
-
export interface PlanEntry {
|
|
96
|
-
name: string
|
|
97
|
-
description: string
|
|
98
|
-
fullPath: string
|
|
99
|
-
mtime: number
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function listPlans(cwd: string): PlanEntry[] {
|
|
103
|
-
const planDir = path.resolve(cwd, PLAN_DIR)
|
|
104
|
-
try {
|
|
105
|
-
const files = fs.readdirSync(planDir)
|
|
106
|
-
return files
|
|
107
|
-
.filter(f => f.endsWith('.md'))
|
|
108
|
-
.map(f => {
|
|
109
|
-
const fullPath = path.join(planDir, f)
|
|
110
|
-
let mtime = 0
|
|
111
|
-
try {
|
|
112
|
-
mtime = fs.statSync(fullPath).mtimeMs
|
|
113
|
-
} catch {
|
|
114
|
-
/* ignore */
|
|
115
|
-
}
|
|
116
|
-
return {
|
|
117
|
-
name: f.replace(/\.md$/, ''),
|
|
118
|
-
description: f,
|
|
119
|
-
fullPath,
|
|
120
|
-
mtime,
|
|
121
|
-
}
|
|
122
|
-
})
|
|
123
|
-
.sort((a, b) => b.mtime - a.mtime)
|
|
124
|
-
} catch {
|
|
125
|
-
return []
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export function loadTodos(filePath: string): string {
|
|
130
|
-
try {
|
|
131
|
-
const content = fs.readFileSync(filePath, 'utf-8')
|
|
132
|
-
const lines = content.split('\n')
|
|
133
|
-
const todos: string[] = []
|
|
134
|
-
let inTodo = false
|
|
135
|
-
for (const line of lines) {
|
|
136
|
-
if (line.startsWith('## Todo List')) {
|
|
137
|
-
inTodo = true
|
|
138
|
-
continue
|
|
139
|
-
}
|
|
140
|
-
if (inTodo && line.startsWith('## ')) break
|
|
141
|
-
if (inTodo) {
|
|
142
|
-
const m = line.trim().match(/^- \[([ x])\]\s+(.+)/)
|
|
143
|
-
if (m) {
|
|
144
|
-
const done = m[1] === 'x'
|
|
145
|
-
const check = done ? '\u2705' : '\u2B1C'
|
|
146
|
-
todos.push(`${check} ${done ? colors.doneTodo(m[2]) : colors.todo(m[2])}`)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
return todos.length > 0 ? todos.join('\n') : '(no todo items)'
|
|
151
|
-
} catch {
|
|
152
|
-
return '(no plan selected)'
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export function plansToItems(plans: PlanEntry[]): SelectItem[] {
|
|
157
|
-
return plans.map(p => ({
|
|
158
|
-
value: p.name,
|
|
159
|
-
label: p.name,
|
|
160
|
-
description: p.mtime
|
|
161
|
-
? `${new Date(p.mtime).toLocaleDateString()} ${new Date(p.mtime).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`
|
|
162
|
-
: '',
|
|
163
|
-
}))
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// ── Rich Footer helpers ────────────────────────────────────────────────────
|
|
167
|
-
|
|
168
|
-
function formatTokens(n: number): string {
|
|
169
|
-
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`
|
|
170
|
-
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`
|
|
171
|
-
return String(n)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// ── OpenCode-style Header ────────────────────────────────────────────────
|
|
175
|
-
|
|
176
|
-
export class HeaderBar implements Component {
|
|
177
|
-
private mode: string
|
|
178
|
-
private model: string
|
|
179
|
-
private provider: string
|
|
180
|
-
private agentStatus: 'running' | 'idle'
|
|
181
|
-
private planCount: number
|
|
182
|
-
private planName: string
|
|
183
|
-
private totalInputTokens: number = 0
|
|
184
|
-
private totalOutputTokens: number = 0
|
|
185
|
-
private totalApiCalls: number = 0
|
|
186
|
-
private projectName: string = ''
|
|
187
|
-
|
|
188
|
-
constructor(model: string, provider: string) {
|
|
189
|
-
this.model = model
|
|
190
|
-
this.provider = provider
|
|
191
|
-
this.mode = 'code'
|
|
192
|
-
this.agentStatus = 'idle'
|
|
193
|
-
this.planCount = 0
|
|
194
|
-
this.planName = ''
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
setMode(m: string): void {
|
|
198
|
-
this.mode = m
|
|
199
|
-
}
|
|
200
|
-
setAgentStatus(s: 'running' | 'idle'): void {
|
|
201
|
-
this.agentStatus = s
|
|
202
|
-
}
|
|
203
|
-
setPlanCount(n: number): void {
|
|
204
|
-
this.planCount = n
|
|
205
|
-
}
|
|
206
|
-
setPlanName(n: string): void {
|
|
207
|
-
this.planName = n
|
|
208
|
-
}
|
|
209
|
-
setTokenUsage(inputTokens: number, outputTokens: number, apiCalls: number): void {
|
|
210
|
-
this.totalInputTokens = inputTokens
|
|
211
|
-
this.totalOutputTokens = outputTokens
|
|
212
|
-
this.totalApiCalls = apiCalls
|
|
213
|
-
}
|
|
214
|
-
setProjectName(name: string): void {
|
|
215
|
-
this.projectName = name
|
|
216
|
-
}
|
|
217
|
-
invalidate(): void {}
|
|
218
|
-
handleInput?(_data: string): void {}
|
|
219
|
-
|
|
220
|
-
render(width: number): string[] {
|
|
221
|
-
const appName = colors.accent('\u2588 lonny')
|
|
222
|
-
const statusDot =
|
|
223
|
-
this.agentStatus === 'running' ? colors.running('\u25CF') : colors.dim('\u25CB')
|
|
224
|
-
const statusLabel =
|
|
225
|
-
this.agentStatus === 'running' ? colors.running('running') : colors.dim('idle')
|
|
226
|
-
const modeLabel = this.mode === 'ask' ? colors.success(this.mode) : colors.warn(this.mode)
|
|
227
|
-
const modelInfo = colors.dim(`${this.provider}/${this.model}`)
|
|
228
|
-
|
|
229
|
-
let rightPart = `${statusDot} ${statusLabel} ${modeLabel} ${modelInfo}`
|
|
230
|
-
|
|
231
|
-
// Show token usage if there are any
|
|
232
|
-
const totalTokens = this.totalInputTokens + this.totalOutputTokens
|
|
233
|
-
if (totalTokens > 0) {
|
|
234
|
-
const tokenStr = `\u25B4${this.totalInputTokens} \u25BE${this.totalOutputTokens} ${totalTokens}`
|
|
235
|
-
const callsStr = `${this.totalApiCalls} calls`
|
|
236
|
-
const projectTag = this.projectName ? `${this.projectName} ` : ''
|
|
237
|
-
rightPart += ` ${colors.dim('|')} ${colors.dim(`${projectTag}${tokenStr} ${callsStr}`)}`
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (this.planCount > 0) {
|
|
241
|
-
rightPart += ` ${colors.dim('|')} ${colors.accent(`${this.planCount} plan${this.planCount > 1 ? 's' : ''}`)}`
|
|
242
|
-
if (this.planName) rightPart += ` ${colors.dim(this.planName)}`
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const line = ` ${appName} ${colors.dim('·')} ${rightPart}`
|
|
246
|
-
return [colors.headerBg(line), colors.dim('\u2500'.repeat(width))]
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// ── Rich Footer (cwd | mode | tokens | model | version + command hints) ────
|
|
251
|
-
|
|
252
|
-
export class RichFooter implements Component {
|
|
253
|
-
private cwd: string
|
|
254
|
-
private mode: string = 'code'
|
|
255
|
-
private model: string = ''
|
|
256
|
-
private provider: string = ''
|
|
257
|
-
private totalInputTokens: number = 0
|
|
258
|
-
private totalOutputTokens: number = 0
|
|
259
|
-
private totalApiCalls: number = 0
|
|
260
|
-
private balance: string = ''
|
|
261
|
-
private webBalance: string = ''
|
|
262
|
-
private visible = true
|
|
263
|
-
private phase: 'landing' | 'chat' = 'landing'
|
|
264
|
-
private agentStatus: 'running' | 'idle' = 'idle'
|
|
265
|
-
|
|
266
|
-
constructor(cwd: string, model: string, provider: string) {
|
|
267
|
-
this.cwd = cwd
|
|
268
|
-
this.model = model
|
|
269
|
-
this.provider = provider
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
setMode(m: string): void {
|
|
273
|
-
this.mode = m
|
|
274
|
-
}
|
|
275
|
-
setModel(model: string, provider: string): void {
|
|
276
|
-
this.model = model
|
|
277
|
-
this.provider = provider
|
|
278
|
-
}
|
|
279
|
-
setTokenUsage(inputTokens: number, outputTokens: number, apiCalls: number): void {
|
|
280
|
-
this.totalInputTokens = inputTokens
|
|
281
|
-
this.totalOutputTokens = outputTokens
|
|
282
|
-
this.totalApiCalls = apiCalls
|
|
283
|
-
}
|
|
284
|
-
setVisible(v: boolean): void {
|
|
285
|
-
this.visible = v
|
|
286
|
-
}
|
|
287
|
-
setPhase(p: 'landing' | 'chat'): void {
|
|
288
|
-
this.phase = p
|
|
289
|
-
}
|
|
290
|
-
setBalance(b: string): void {
|
|
291
|
-
this.balance = b
|
|
292
|
-
}
|
|
293
|
-
setWebBalance(wb: string): void {
|
|
294
|
-
this.webBalance = wb
|
|
295
|
-
}
|
|
296
|
-
setAgentStatus(s: 'running' | 'idle'): void {
|
|
297
|
-
this.agentStatus = s
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
invalidate(): void {}
|
|
301
|
-
handleInput?(_data: string): void {}
|
|
302
|
-
|
|
303
|
-
private visibleLen(s: string): number {
|
|
304
|
-
return visibleLen(s)
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
render(width: number): string[] {
|
|
308
|
-
if (!this.visible || width < 40) return []
|
|
309
|
-
|
|
310
|
-
const { statusBg, statusText, statusAccent, reset } = landingColors
|
|
311
|
-
|
|
312
|
-
// Left: working directory
|
|
313
|
-
const dir = this.cwd.length > 30 ? `...${this.cwd.slice(-27)}` : this.cwd
|
|
314
|
-
const leftPart = `${statusAccent}\u25A0${reset}${statusBg}${statusText} ${dir}${reset}`
|
|
315
|
-
|
|
316
|
-
if (this.phase === 'landing') {
|
|
317
|
-
// Minimal: cwd | ready | version
|
|
318
|
-
const centerPart = `${statusBg + statusText} ready ${reset}`
|
|
319
|
-
const rightPart = `${statusBg + statusText}v${APP_VERSION} ${reset}`
|
|
320
|
-
const line = leftPart + centerPart + rightPart
|
|
321
|
-
const visLen = this.visibleLen(line)
|
|
322
|
-
const padded = visLen < width ? line + statusBg + ' '.repeat(width - visLen) + reset : line
|
|
323
|
-
return [padded]
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// ── Chat phase: build segments ────────────────────────────────────────
|
|
327
|
-
const segments: string[] = []
|
|
328
|
-
|
|
329
|
-
// Status dot
|
|
330
|
-
const statusDot =
|
|
331
|
-
this.agentStatus === 'running'
|
|
332
|
-
? `\x1b[38;2;0;255;100m\u25CF\x1b[0m`
|
|
333
|
-
: `\x1b[38;2;150;150;150m\u25CB\x1b[0m`
|
|
334
|
-
const statusLabel =
|
|
335
|
-
this.agentStatus === 'running'
|
|
336
|
-
? `\x1b[38;2;0;255;100mrunning\x1b[0m`
|
|
337
|
-
: `\x1b[38;2;150;150;150midle\x1b[0m`
|
|
338
|
-
segments.push(`${statusDot} ${statusLabel}`)
|
|
339
|
-
|
|
340
|
-
// Mode tag
|
|
341
|
-
const modeTag =
|
|
342
|
-
this.mode === 'plan'
|
|
343
|
-
? `\x1b[38;2;255;200;50m${this.mode}\x1b[0m`
|
|
344
|
-
: this.mode === 'ask'
|
|
345
|
-
? `\x1b[38;2;0;200;100m${this.mode}\x1b[0m`
|
|
346
|
-
: `\x1b[38;2;0;200;255m${this.mode}\x1b[0m`
|
|
347
|
-
segments.push(modeTag)
|
|
348
|
-
|
|
349
|
-
// Model/provider
|
|
350
|
-
if (this.model) {
|
|
351
|
-
segments.push(`\x1b[38;2;110;110;110m${this.provider}/${this.model}\x1b[0m`)
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Token usage
|
|
355
|
-
const totalTokens = this.totalInputTokens + this.totalOutputTokens
|
|
356
|
-
if (totalTokens > 0) {
|
|
357
|
-
const tokenStr = `\u25B4${formatTokens(this.totalInputTokens)} \u25BE${formatTokens(this.totalOutputTokens)} ${formatTokens(totalTokens)}`
|
|
358
|
-
segments.push(`\x1b[38;2;110;110;110m${tokenStr}\x1b[0m`)
|
|
359
|
-
segments.push(`\x1b[38;2;110;110;110m${this.totalApiCalls}c\x1b[0m`)
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// Balance (DeepSeek official API only)
|
|
363
|
-
if (this.webBalance) {
|
|
364
|
-
// Show the web-style breakdown if available
|
|
365
|
-
segments.push(`\x1b[38;2;255;200;50m\u4F59\u989D\x1b[0m\uFF1A${this.webBalance}`)
|
|
366
|
-
} else if (this.balance) {
|
|
367
|
-
segments.push(`\x1b[38;2;255;200;50m\u4F59\u989D\x1b[0m\uFF1A${this.balance}`)
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// Build center part from segments
|
|
371
|
-
const separator = `${statusBg} \x1b[38;2;60;60;60m\u2502\x1b[0m ${reset}`
|
|
372
|
-
const centerContent = `${statusBg + statusText} ${segments.join(separator)} ${reset}`
|
|
373
|
-
|
|
374
|
-
// Right: version
|
|
375
|
-
const rightPart = `${statusBg + statusText}v${APP_VERSION} ${reset}`
|
|
376
|
-
|
|
377
|
-
const line = leftPart + centerContent + rightPart
|
|
378
|
-
|
|
379
|
-
// If there's extra space, append command hints
|
|
380
|
-
const lineLen = line.length - 2 * statusBg.length - reset.length // approximate
|
|
381
|
-
let result = line
|
|
382
|
-
if (lineLen < width - 40) {
|
|
383
|
-
const hints = [
|
|
384
|
-
'\x1b[38;2;110;110;110m/mode\x1b[0m',
|
|
385
|
-
'\x1b[38;2;110;110;110m/plans\x1b[0m',
|
|
386
|
-
'\x1b[38;2;110;110;110m/help\x1b[0m',
|
|
387
|
-
'\x1b[38;2;110;110;110m?\x1b[0m',
|
|
388
|
-
].join(' \x1b[38;2;60;60;60m\u00b7\x1b[0m ')
|
|
389
|
-
const hintStr = `${statusBg + statusText} ${hints} ${reset}`
|
|
390
|
-
// Only append if it fits
|
|
391
|
-
const fullLine = line + hintStr
|
|
392
|
-
// Calculate approximate visible length (strip ANSI)
|
|
393
|
-
const approxLen = fullLine.replace(/\x1b\[[0-9;]*m/g, '').length
|
|
394
|
-
if (approxLen <= width) {
|
|
395
|
-
result = fullLine
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
const visLen = this.visibleLen(result)
|
|
400
|
-
const padded = visLen < width ? result + statusBg + ' '.repeat(width - visLen) + reset : result
|
|
401
|
-
|
|
402
|
-
return [padded]
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// ── LandingScreen (pixel logo + welcome) ──────────────────────────────
|
|
407
|
-
|
|
408
|
-
export class LandingScreen implements Component {
|
|
409
|
-
onSubmit?: (value: string) => void
|
|
410
|
-
private model: string
|
|
411
|
-
private provider: string
|
|
412
|
-
|
|
413
|
-
constructor(model: string, provider: string) {
|
|
414
|
-
this.model = model
|
|
415
|
-
this.provider = provider
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
invalidate(): void {}
|
|
419
|
-
|
|
420
|
-
handleInput(data: string): void {
|
|
421
|
-
// Any key transitions to chat
|
|
422
|
-
if (data && this.onSubmit) {
|
|
423
|
-
this.onSubmit(data)
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
private visibleLen(s: string): number {
|
|
428
|
-
return visibleLen(s)
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
render(width: number): string[] {
|
|
432
|
-
const lines: string[] = []
|
|
433
|
-
const center = (text: string, totalWidth: number): string => {
|
|
434
|
-
const textWidth = this.visibleLen(text)
|
|
435
|
-
const pad = Math.max(0, Math.floor((totalWidth - textWidth) / 2))
|
|
436
|
-
return ' '.repeat(pad) + text
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
// ── Pixel logo ─────────────────────────────────────────────────────
|
|
440
|
-
const logoLines = renderPixelLogo()
|
|
441
|
-
const logoPad = Math.max(0, Math.floor((width - PIXEL_LOGO_WIDTH) / 2))
|
|
442
|
-
const padStr = ' '.repeat(logoPad)
|
|
443
|
-
|
|
444
|
-
for (const line of logoLines) {
|
|
445
|
-
lines.push(padStr + line)
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// ── Decorative divider ────────────────────────────────────────────
|
|
449
|
-
const divider = colors.dim('\u2500'.repeat(Math.min(36, width - 4)))
|
|
450
|
-
lines.push(center(divider, width))
|
|
451
|
-
|
|
452
|
-
// ── Prompt text ───────────────────────────────────────────────────
|
|
453
|
-
lines.push('')
|
|
454
|
-
const prompt =
|
|
455
|
-
colors.dim('Type a message and press ') + colors.accent('Enter') + colors.dim(' to start')
|
|
456
|
-
lines.push(center(prompt, width))
|
|
457
|
-
lines.push('')
|
|
458
|
-
|
|
459
|
-
// ── Quick command hints ───────────────────────────────────────────
|
|
460
|
-
const cmds = [
|
|
461
|
-
colors.inputPrompt('/mode'),
|
|
462
|
-
colors.inputPrompt('/model'),
|
|
463
|
-
colors.inputPrompt('/plans'),
|
|
464
|
-
colors.inputPrompt('/help'),
|
|
465
|
-
].join(colors.dim(' \u00B7 '))
|
|
466
|
-
lines.push(center(colors.dim('Commands: ') + cmds, width))
|
|
467
|
-
|
|
468
|
-
// ── Model & version info ──────────────────────────────────────────
|
|
469
|
-
const modelInfo = colors.dim(`${this.provider}/${this.model}`)
|
|
470
|
-
const versionInfo = colors.dim(`v${APP_VERSION}`)
|
|
471
|
-
lines.push(center(modelInfo + colors.separator(' \u2502 ') + versionInfo, width))
|
|
472
|
-
|
|
473
|
-
return lines
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// ── PlansList wrapper (SelectList has no setItems) ───────────────────────
|
|
478
|
-
|
|
479
|
-
export class PlansList implements Component {
|
|
480
|
-
private selectList: SelectList
|
|
481
|
-
private allItems: SelectItem[]
|
|
482
|
-
private maxVisible: number
|
|
483
|
-
private theme: SelectListTheme
|
|
484
|
-
onSelectionChange?: (item: SelectItem) => void
|
|
485
|
-
|
|
486
|
-
constructor(items: SelectItem[], maxVisible: number, theme: SelectListTheme) {
|
|
487
|
-
this.allItems = items
|
|
488
|
-
this.selectList = new SelectList(items, maxVisible, theme)
|
|
489
|
-
this.maxVisible = maxVisible
|
|
490
|
-
this.theme = theme
|
|
491
|
-
this.selectList.onSelectionChange = item => {
|
|
492
|
-
if (this.onSelectionChange) this.onSelectionChange(item)
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
setFilter(filter: string): void {
|
|
497
|
-
this.selectList.setFilter(filter)
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
clearFilter(): void {
|
|
501
|
-
this.selectList.setFilter('')
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
refresh(items: SelectItem[]): void {
|
|
505
|
-
this.allItems = items
|
|
506
|
-
const cb = this.onSelectionChange
|
|
507
|
-
this.selectList = new SelectList(items, this.maxVisible, this.theme)
|
|
508
|
-
this.selectList.onSelectionChange = cb
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
getSelectedItem(): SelectItem | null {
|
|
512
|
-
return this.selectList.getSelectedItem()
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
setSelectedIndex(index: number): void {
|
|
516
|
-
this.selectList.setSelectedIndex(index)
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
invalidate(): void {
|
|
520
|
-
this.selectList.invalidate()
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
render(width: number): string[] {
|
|
524
|
-
return this.selectList.render(width)
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
handleInput(data: string): void {
|
|
528
|
-
this.selectList.handleInput(data)
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// ── Persistent Todo Side Panel ───────────────────────────────────────
|
|
533
|
-
|
|
534
|
-
export class TodoPanel implements Component {
|
|
535
|
-
private cwd: string
|
|
536
|
-
private todos: { text: string; done: boolean }[] = []
|
|
537
|
-
private planName: string = ''
|
|
538
|
-
private dirty: boolean = true
|
|
539
|
-
|
|
540
|
-
constructor(cwd: string) {
|
|
541
|
-
this.cwd = cwd
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
refresh(): void {
|
|
545
|
-
this.dirty = true
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
invalidate(): void {
|
|
549
|
-
this.dirty = true
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
private load(): void {
|
|
553
|
-
this.dirty = false
|
|
554
|
-
const plans = listPlans(this.cwd)
|
|
555
|
-
if (plans.length === 0) {
|
|
556
|
-
this.todos = []
|
|
557
|
-
this.planName = ''
|
|
558
|
-
return
|
|
559
|
-
}
|
|
560
|
-
const plan = plans[0]
|
|
561
|
-
this.planName = plan.name
|
|
562
|
-
this.todos = []
|
|
563
|
-
try {
|
|
564
|
-
const content = fs.readFileSync(plan.fullPath, 'utf-8')
|
|
565
|
-
const lines = content.split('\n')
|
|
566
|
-
let inTodo = false
|
|
567
|
-
for (const line of lines) {
|
|
568
|
-
if (line.startsWith('## Todo List')) {
|
|
569
|
-
inTodo = true
|
|
570
|
-
continue
|
|
571
|
-
}
|
|
572
|
-
if (inTodo && line.startsWith('## ')) break
|
|
573
|
-
if (inTodo) {
|
|
574
|
-
const m = line.trim().match(/^- \[([ x])\]\s+(.+)/)
|
|
575
|
-
if (m) {
|
|
576
|
-
this.todos.push({ text: m[2], done: m[1] === 'x' })
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
} catch {
|
|
581
|
-
// ignore file read errors
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
private visibleLen(s: string): number {
|
|
586
|
-
return visibleLen(s)
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
render(width: number): string[] {
|
|
590
|
-
if (this.dirty) this.load()
|
|
591
|
-
|
|
592
|
-
const lines: string[] = []
|
|
593
|
-
|
|
594
|
-
// ── Header ──
|
|
595
|
-
const headerText = ` ${colors.accent('\u25B6')} TODO`
|
|
596
|
-
const headerPadding = Math.max(0, width - this.visibleLen(headerText))
|
|
597
|
-
lines.push(colors.bgDark(headerText + ' '.repeat(headerPadding)))
|
|
598
|
-
|
|
599
|
-
// ── Divider ──
|
|
600
|
-
lines.push(colors.separator('\u2500'.repeat(width)))
|
|
601
|
-
|
|
602
|
-
if (!this.planName) {
|
|
603
|
-
lines.push(colors.dim(' (no plan)'))
|
|
604
|
-
return lines
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
if (this.todos.length === 0) {
|
|
608
|
-
lines.push(colors.dim(' (no todos)'))
|
|
609
|
-
return lines
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// ── Todo items ──
|
|
613
|
-
const contentWidth = width - 3 // leave room for icon + space
|
|
614
|
-
for (const todo of this.todos) {
|
|
615
|
-
const icon = todo.done ? '\u2705' : '\u2B1C'
|
|
616
|
-
const textStyle = todo.done ? colors.doneTodo : colors.todo
|
|
617
|
-
const text = todo.text
|
|
618
|
-
// Truncate text if too long (account for visible width)
|
|
619
|
-
const maxTextLen = contentWidth - 1 // 1 for space after icon
|
|
620
|
-
let truncated = text
|
|
621
|
-
let textVisLen = this.visibleLen(textStyle(text))
|
|
622
|
-
if (textVisLen > maxTextLen) {
|
|
623
|
-
// Simple truncation: cut raw text and add ellipsis
|
|
624
|
-
truncated = `${text.slice(0, maxTextLen - 1)}\u2026`
|
|
625
|
-
textVisLen = maxTextLen
|
|
626
|
-
}
|
|
627
|
-
const line = ` ${icon} ${textStyle(truncated)}`
|
|
628
|
-
const visLen = this.visibleLen(line)
|
|
629
|
-
const padding = Math.max(0, width - visLen)
|
|
630
|
-
lines.push(line + ' '.repeat(padding))
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
return lines
|
|
634
|
-
}
|
|
635
|
-
}
|