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
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Component } from '../../pi-tui/index.js'
|
|
2
|
+
import { colors } from './colors.js'
|
|
3
|
+
|
|
4
|
+
function formatTokens(n: number): string {
|
|
5
|
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`
|
|
6
|
+
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`
|
|
7
|
+
return String(n)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export { formatTokens }
|
|
11
|
+
|
|
12
|
+
export class HeaderBar implements Component {
|
|
13
|
+
private mode: string
|
|
14
|
+
private model: string
|
|
15
|
+
private provider: string
|
|
16
|
+
private agentStatus: 'running' | 'idle'
|
|
17
|
+
private planCount: number
|
|
18
|
+
private planName: string
|
|
19
|
+
private totalInputTokens: number = 0
|
|
20
|
+
private totalOutputTokens: number = 0
|
|
21
|
+
private totalApiCalls: number = 0
|
|
22
|
+
private projectName: string = ''
|
|
23
|
+
|
|
24
|
+
constructor(model: string, provider: string) {
|
|
25
|
+
this.model = model
|
|
26
|
+
this.provider = provider
|
|
27
|
+
this.mode = 'code'
|
|
28
|
+
this.agentStatus = 'idle'
|
|
29
|
+
this.planCount = 0
|
|
30
|
+
this.planName = ''
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
setMode(m: string): void {
|
|
34
|
+
this.mode = m
|
|
35
|
+
}
|
|
36
|
+
setAgentStatus(s: 'running' | 'idle'): void {
|
|
37
|
+
this.agentStatus = s
|
|
38
|
+
}
|
|
39
|
+
setPlanCount(n: number): void {
|
|
40
|
+
this.planCount = n
|
|
41
|
+
}
|
|
42
|
+
setPlanName(n: string): void {
|
|
43
|
+
this.planName = n
|
|
44
|
+
}
|
|
45
|
+
setTokenUsage(inputTokens: number, outputTokens: number, apiCalls: number): void {
|
|
46
|
+
this.totalInputTokens = inputTokens
|
|
47
|
+
this.totalOutputTokens = outputTokens
|
|
48
|
+
this.totalApiCalls = apiCalls
|
|
49
|
+
}
|
|
50
|
+
setProjectName(name: string): void {
|
|
51
|
+
this.projectName = name
|
|
52
|
+
}
|
|
53
|
+
invalidate(): void {}
|
|
54
|
+
handleInput?(_data: string): void {}
|
|
55
|
+
|
|
56
|
+
render(width: number): string[] {
|
|
57
|
+
const appName = colors.accent('\u2588 lonny')
|
|
58
|
+
const statusDot =
|
|
59
|
+
this.agentStatus === 'running' ? colors.running('\u25CF') : colors.dim('\u25CB')
|
|
60
|
+
const statusLabel =
|
|
61
|
+
this.agentStatus === 'running' ? colors.running('running') : colors.dim('idle')
|
|
62
|
+
const modeLabel =
|
|
63
|
+
this.mode === 'ask'
|
|
64
|
+
? colors.success(this.mode)
|
|
65
|
+
: this.mode === 'loop'
|
|
66
|
+
? colors.accent(this.mode)
|
|
67
|
+
: colors.warn(this.mode)
|
|
68
|
+
const modelInfo = colors.dim(`${this.provider}/${this.model}`)
|
|
69
|
+
|
|
70
|
+
let rightPart = `${statusDot} ${statusLabel} ${modeLabel} ${modelInfo}`
|
|
71
|
+
|
|
72
|
+
const totalTokens = this.totalInputTokens + this.totalOutputTokens
|
|
73
|
+
if (totalTokens > 0) {
|
|
74
|
+
const tokenStr = `\u25B4${this.totalInputTokens} \u25BE${this.totalOutputTokens} ${totalTokens}`
|
|
75
|
+
const callsStr = `${this.totalApiCalls} calls`
|
|
76
|
+
const projectTag = this.projectName ? `${this.projectName} ` : ''
|
|
77
|
+
rightPart += ` ${colors.dim('|')} ${colors.dim(`${projectTag}${tokenStr} ${callsStr}`)}`
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (this.planCount > 0) {
|
|
81
|
+
rightPart += ` ${colors.dim('|')} ${colors.accent(`${this.planCount} plan${this.planCount > 1 ? 's' : ''}`)}`
|
|
82
|
+
if (this.planName) rightPart += ` ${colors.dim(this.planName)}`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const line = ` ${appName} ${colors.dim('·')} ${rightPart}`
|
|
86
|
+
return [colors.headerBg(line), colors.dim('\u2500'.repeat(width))]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { APP_VERSION, colors, landingColors, safeBg } from './colors.js'
|
|
2
|
+
export { formatTokens, HeaderBar } from './header-bar.js'
|
|
3
|
+
export { LandingScreen } from './landing-screen.js'
|
|
4
|
+
export { PIXEL_LOGO_WIDTH, renderPixelLogo } from './pixel-logo.js'
|
|
5
|
+
export { listPlans, loadTodos, PlanEntry, plansToItems } from './plan-utils.js'
|
|
6
|
+
export { PlansList } from './plans-list.js'
|
|
7
|
+
export { RichFooter } from './rich-footer.js'
|
|
8
|
+
export { TodoPanel } from './todo-panel.js'
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Component } from '../../pi-tui/index.js'
|
|
2
|
+
import { visibleLen } from '../utils.js'
|
|
3
|
+
import { APP_VERSION, colors } from './colors.js'
|
|
4
|
+
import { PIXEL_LOGO_WIDTH, renderPixelLogo } from './pixel-logo.js'
|
|
5
|
+
|
|
6
|
+
export class LandingScreen implements Component {
|
|
7
|
+
onSubmit?: (value: string) => void
|
|
8
|
+
private model: string
|
|
9
|
+
private provider: string
|
|
10
|
+
|
|
11
|
+
constructor(model: string, provider: string) {
|
|
12
|
+
this.model = model
|
|
13
|
+
this.provider = provider
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
invalidate(): void {}
|
|
17
|
+
|
|
18
|
+
handleInput(data: string): void {
|
|
19
|
+
if (data && this.onSubmit) {
|
|
20
|
+
this.onSubmit(data)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private visibleLen(s: string): number {
|
|
25
|
+
return visibleLen(s)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
render(width: number): string[] {
|
|
29
|
+
const lines: string[] = []
|
|
30
|
+
const center = (text: string, totalWidth: number): string => {
|
|
31
|
+
const textWidth = this.visibleLen(text)
|
|
32
|
+
const pad = Math.max(0, Math.floor((totalWidth - textWidth) / 2))
|
|
33
|
+
return ' '.repeat(pad) + text
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const logoLines = renderPixelLogo()
|
|
37
|
+
const logoPad = Math.max(0, Math.floor((width - PIXEL_LOGO_WIDTH) / 2))
|
|
38
|
+
const padStr = ' '.repeat(logoPad)
|
|
39
|
+
|
|
40
|
+
for (const line of logoLines) {
|
|
41
|
+
lines.push(padStr + line)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const divider = colors.dim('\u2500'.repeat(Math.min(36, width - 4)))
|
|
45
|
+
lines.push(center(divider, width))
|
|
46
|
+
|
|
47
|
+
lines.push('')
|
|
48
|
+
const prompt =
|
|
49
|
+
colors.dim('Type a message and press ') + colors.accent('Enter') + colors.dim(' to start')
|
|
50
|
+
lines.push(center(prompt, width))
|
|
51
|
+
lines.push('')
|
|
52
|
+
|
|
53
|
+
const cmds = [
|
|
54
|
+
colors.inputPrompt('/mode'),
|
|
55
|
+
colors.inputPrompt('/model'),
|
|
56
|
+
colors.inputPrompt('/plans'),
|
|
57
|
+
colors.inputPrompt('/help'),
|
|
58
|
+
].join(colors.dim(' \u00B7 '))
|
|
59
|
+
lines.push(center(colors.dim('Commands: ') + cmds, width))
|
|
60
|
+
|
|
61
|
+
const modelInfo = colors.dim(`${this.provider}/${this.model}`)
|
|
62
|
+
const versionInfo = colors.dim(`v${APP_VERSION}`)
|
|
63
|
+
lines.push(center(modelInfo + colors.separator(' \u2502 ') + versionInfo, width))
|
|
64
|
+
|
|
65
|
+
return lines
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { colors } from './colors.js'
|
|
2
|
+
|
|
3
|
+
const PIXEL_FONT: Record<string, string[]> = {
|
|
4
|
+
L: ['█ ', '█ ', '█ ', '█ ', '█████'],
|
|
5
|
+
O: [' ███ ', '█ █', '█ █', '█ █', ' ███ '],
|
|
6
|
+
N: ['█ █', '██ █', '█ █ █', '█ ██', '█ █'],
|
|
7
|
+
Y: ['█ █', ' █ █ ', ' █ ', ' █ ', ' █ '],
|
|
8
|
+
C: [' ███ ', '█ ', '█ ', '█ ', ' ███ '],
|
|
9
|
+
D: ['███ ', '█ █ ', '█ █', '█ █ ', '███ '],
|
|
10
|
+
E: ['█████', '█ ', '███ ', '█ ', '█████'],
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const LONNY_CHARS = ['L', 'O', 'N', 'N', 'Y']
|
|
14
|
+
const CODE_CHARS = ['C', 'O', 'D', 'E']
|
|
15
|
+
|
|
16
|
+
const PIXEL_LOGO_WIDTH = 54
|
|
17
|
+
|
|
18
|
+
export { PIXEL_LOGO_WIDTH }
|
|
19
|
+
|
|
20
|
+
function renderPixelLogo(): string[] {
|
|
21
|
+
const midGray = '\x1b[38;2;160;160;160m'
|
|
22
|
+
const brightWhite = '\x1b[38;2;255;255;255m'
|
|
23
|
+
const reset = '\x1b[0m'
|
|
24
|
+
const lines: string[] = []
|
|
25
|
+
for (let row = 0; row < 5; row++) {
|
|
26
|
+
const lonnyPart = LONNY_CHARS.map(ch => PIXEL_FONT[ch][row]).join(' ')
|
|
27
|
+
const codePart = CODE_CHARS.map(ch => PIXEL_FONT[ch][row]).join(' ')
|
|
28
|
+
lines.push(`${midGray + lonnyPart} ${brightWhite}${codePart}${reset}`)
|
|
29
|
+
}
|
|
30
|
+
return lines
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { renderPixelLogo }
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import * as path from 'node:path'
|
|
3
|
+
import type { SelectItem } from '../../pi-tui/index.js'
|
|
4
|
+
import { PLAN_DIR } from '../../tools/edit/write_plan.js'
|
|
5
|
+
import { colors } from './colors.js'
|
|
6
|
+
|
|
7
|
+
export interface PlanEntry {
|
|
8
|
+
name: string
|
|
9
|
+
description: string
|
|
10
|
+
fullPath: string
|
|
11
|
+
mtime: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function listPlans(cwd: string): PlanEntry[] {
|
|
15
|
+
const planDir = path.resolve(cwd, PLAN_DIR)
|
|
16
|
+
try {
|
|
17
|
+
const files = fs.readdirSync(planDir)
|
|
18
|
+
return files
|
|
19
|
+
.filter(f => f.endsWith('.md'))
|
|
20
|
+
.map(f => {
|
|
21
|
+
const fullPath = path.join(planDir, f)
|
|
22
|
+
let mtime = 0
|
|
23
|
+
try {
|
|
24
|
+
mtime = fs.statSync(fullPath).mtimeMs
|
|
25
|
+
} catch {
|
|
26
|
+
/* ignore */
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
name: f.replace(/\.md$/, ''),
|
|
30
|
+
description: f,
|
|
31
|
+
fullPath,
|
|
32
|
+
mtime,
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
.sort((a, b) => b.mtime - a.mtime)
|
|
36
|
+
} catch {
|
|
37
|
+
return []
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function loadTodos(filePath: string): string {
|
|
42
|
+
try {
|
|
43
|
+
const content = fs.readFileSync(filePath, 'utf-8')
|
|
44
|
+
const lines = content.split('\n')
|
|
45
|
+
const todos: string[] = []
|
|
46
|
+
for (const raw of lines) {
|
|
47
|
+
const line = raw.trim()
|
|
48
|
+
const m = line.match(/^- \[([ x])\]\s+(.+)/)
|
|
49
|
+
if (m) {
|
|
50
|
+
const done = m[1] === 'x'
|
|
51
|
+
const check = done ? '\u2705' : '\u2B1C'
|
|
52
|
+
todos.push(`${check} ${done ? colors.doneTodo(m[2]) : colors.todo(m[2])}`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return todos.length > 0 ? todos.join('\n') : '(no todo items)'
|
|
56
|
+
} catch {
|
|
57
|
+
return '(no plan selected)'
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function plansToItems(plans: PlanEntry[]): SelectItem[] {
|
|
62
|
+
return plans.map(p => ({
|
|
63
|
+
value: p.name,
|
|
64
|
+
label: p.name,
|
|
65
|
+
description: p.mtime
|
|
66
|
+
? `${new Date(p.mtime).toLocaleDateString()} ${new Date(p.mtime).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`
|
|
67
|
+
: '',
|
|
68
|
+
}))
|
|
69
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Component, SelectItem, SelectListTheme } from '../../pi-tui/index.js'
|
|
2
|
+
import { SelectList } from '../../pi-tui/index.js'
|
|
3
|
+
|
|
4
|
+
export class PlansList implements Component {
|
|
5
|
+
private selectList: SelectList
|
|
6
|
+
private allItems: SelectItem[]
|
|
7
|
+
private maxVisible: number
|
|
8
|
+
private theme: SelectListTheme
|
|
9
|
+
onSelectionChange?: (item: SelectItem) => void
|
|
10
|
+
|
|
11
|
+
constructor(items: SelectItem[], maxVisible: number, theme: SelectListTheme) {
|
|
12
|
+
this.allItems = items
|
|
13
|
+
this.selectList = new SelectList(items, maxVisible, theme)
|
|
14
|
+
this.maxVisible = maxVisible
|
|
15
|
+
this.theme = theme
|
|
16
|
+
this.selectList.onSelectionChange = item => {
|
|
17
|
+
if (this.onSelectionChange) this.onSelectionChange(item)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
setFilter(filter: string): void {
|
|
22
|
+
this.selectList.setFilter(filter)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
clearFilter(): void {
|
|
26
|
+
this.selectList.setFilter('')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
refresh(items: SelectItem[]): void {
|
|
30
|
+
this.allItems = items
|
|
31
|
+
const cb = this.onSelectionChange
|
|
32
|
+
this.selectList = new SelectList(items, this.maxVisible, this.theme)
|
|
33
|
+
this.selectList.onSelectionChange = cb
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
getSelectedItem(): SelectItem | null {
|
|
37
|
+
return this.selectList.getSelectedItem()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setSelectedIndex(index: number): void {
|
|
41
|
+
this.selectList.setSelectedIndex(index)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
invalidate(): void {
|
|
45
|
+
this.selectList.invalidate()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
render(width: number): string[] {
|
|
49
|
+
return this.selectList.render(width)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
handleInput(data: string): void {
|
|
53
|
+
this.selectList.handleInput(data)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { Component } from '../../pi-tui/index.js'
|
|
2
|
+
import { visibleLen } from '../utils.js'
|
|
3
|
+
import { APP_VERSION, colors, landingColors } from './colors.js'
|
|
4
|
+
import { formatTokens } from './header-bar.js'
|
|
5
|
+
|
|
6
|
+
export class RichFooter implements Component {
|
|
7
|
+
private cwd: string
|
|
8
|
+
private mode: string = 'code'
|
|
9
|
+
private model: string = ''
|
|
10
|
+
private provider: string = ''
|
|
11
|
+
private totalInputTokens: number = 0
|
|
12
|
+
private totalOutputTokens: number = 0
|
|
13
|
+
private totalApiCalls: number = 0
|
|
14
|
+
private balance: string = ''
|
|
15
|
+
private webBalance: string = ''
|
|
16
|
+
private visible = true
|
|
17
|
+
private phase: 'landing' | 'chat' = 'landing'
|
|
18
|
+
private agentStatus: 'running' | 'idle' = 'idle'
|
|
19
|
+
|
|
20
|
+
constructor(cwd: string, model: string, provider: string) {
|
|
21
|
+
this.cwd = cwd
|
|
22
|
+
this.model = model
|
|
23
|
+
this.provider = provider
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
setMode(m: string): void {
|
|
27
|
+
this.mode = m
|
|
28
|
+
}
|
|
29
|
+
setModel(model: string, provider: string): void {
|
|
30
|
+
this.model = model
|
|
31
|
+
this.provider = provider
|
|
32
|
+
}
|
|
33
|
+
setTokenUsage(inputTokens: number, outputTokens: number, apiCalls: number): void {
|
|
34
|
+
this.totalInputTokens = inputTokens
|
|
35
|
+
this.totalOutputTokens = outputTokens
|
|
36
|
+
this.totalApiCalls = apiCalls
|
|
37
|
+
}
|
|
38
|
+
setVisible(v: boolean): void {
|
|
39
|
+
this.visible = v
|
|
40
|
+
}
|
|
41
|
+
setPhase(p: 'landing' | 'chat'): void {
|
|
42
|
+
this.phase = p
|
|
43
|
+
}
|
|
44
|
+
setBalance(b: string): void {
|
|
45
|
+
this.balance = b
|
|
46
|
+
}
|
|
47
|
+
setWebBalance(wb: string): void {
|
|
48
|
+
this.webBalance = wb
|
|
49
|
+
}
|
|
50
|
+
setAgentStatus(s: 'running' | 'idle'): void {
|
|
51
|
+
this.agentStatus = s
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
invalidate(): void {}
|
|
55
|
+
handleInput?(_data: string): void {}
|
|
56
|
+
|
|
57
|
+
private visibleLen(s: string): number {
|
|
58
|
+
return visibleLen(s)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
render(width: number): string[] {
|
|
62
|
+
if (!this.visible || width < 40) return []
|
|
63
|
+
|
|
64
|
+
const { statusBg, statusText, statusAccent, reset } = landingColors
|
|
65
|
+
|
|
66
|
+
const dir = this.cwd.length > 30 ? `...${this.cwd.slice(-27)}` : this.cwd
|
|
67
|
+
const leftPart = `${statusAccent}\u25A0${reset}${statusBg}${statusText} ${dir}${reset}`
|
|
68
|
+
|
|
69
|
+
if (this.phase === 'landing') {
|
|
70
|
+
const centerPart = `${statusBg + statusText} ready ${reset}`
|
|
71
|
+
const rightPart = `${statusBg + statusText}v${APP_VERSION} ${reset}`
|
|
72
|
+
const line = leftPart + centerPart + rightPart
|
|
73
|
+
const visLen = this.visibleLen(line)
|
|
74
|
+
const padded = visLen < width ? line + statusBg + ' '.repeat(width - visLen) + reset : line
|
|
75
|
+
return [padded]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const segments: string[] = []
|
|
79
|
+
|
|
80
|
+
const statusDot =
|
|
81
|
+
this.agentStatus === 'running'
|
|
82
|
+
? `\x1b[38;2;0;255;100m\u25CF\x1b[0m`
|
|
83
|
+
: `\x1b[38;2;150;150;150m\u25CB\x1b[0m`
|
|
84
|
+
const statusLabel =
|
|
85
|
+
this.agentStatus === 'running'
|
|
86
|
+
? `\x1b[38;2;0;255;100mrunning\x1b[0m`
|
|
87
|
+
: `\x1b[38;2;150;150;150midle\x1b[0m`
|
|
88
|
+
segments.push(`${statusDot} ${statusLabel}`)
|
|
89
|
+
|
|
90
|
+
const modeTag =
|
|
91
|
+
this.mode === 'plan'
|
|
92
|
+
? `\x1b[38;2;255;200;50m${this.mode}\x1b[0m`
|
|
93
|
+
: this.mode === 'ask'
|
|
94
|
+
? `\x1b[38;2;0;200;100m${this.mode}\x1b[0m`
|
|
95
|
+
: this.mode === 'loop'
|
|
96
|
+
? `\x1b[38;2;200;100;255m${this.mode}\x1b[0m`
|
|
97
|
+
: `\x1b[38;2;0;200;255m${this.mode}\x1b[0m`
|
|
98
|
+
segments.push(modeTag)
|
|
99
|
+
|
|
100
|
+
if (this.model) {
|
|
101
|
+
segments.push(`\x1b[38;2;110;110;110m${this.provider}/${this.model}\x1b[0m`)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const totalTokens = this.totalInputTokens + this.totalOutputTokens
|
|
105
|
+
if (totalTokens > 0) {
|
|
106
|
+
const tokenStr = `\u25B4${formatTokens(this.totalInputTokens)} \u25BE${formatTokens(this.totalOutputTokens)} ${formatTokens(totalTokens)}`
|
|
107
|
+
segments.push(`\x1b[38;2;110;110;110m${tokenStr}\x1b[0m`)
|
|
108
|
+
segments.push(`\x1b[38;2;110;110;110m${this.totalApiCalls}c\x1b[0m`)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (this.webBalance) {
|
|
112
|
+
segments.push(`\x1b[38;2;255;200;50m\u4F59\u989D\x1b[0m\uFF1A${this.webBalance}`)
|
|
113
|
+
} else if (this.balance) {
|
|
114
|
+
segments.push(`\x1b[38;2;255;200;50m\u4F59\u989D\x1b[0m\uFF1A${this.balance}`)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const separator = `${statusBg} \x1b[38;2;60;60;60m\u2502\x1b[0m ${reset}`
|
|
118
|
+
const centerContent = `${statusBg + statusText} ${segments.join(separator)} ${reset}`
|
|
119
|
+
|
|
120
|
+
const rightPart = `${statusBg + statusText}v${APP_VERSION} ${reset}`
|
|
121
|
+
|
|
122
|
+
const line = leftPart + centerContent + rightPart
|
|
123
|
+
|
|
124
|
+
const lineLen = line.length - 2 * statusBg.length - reset.length
|
|
125
|
+
let result = line
|
|
126
|
+
if (lineLen < width - 40) {
|
|
127
|
+
const hints = [
|
|
128
|
+
'\x1b[38;2;110;110;110m/mode\x1b[0m',
|
|
129
|
+
'\x1b[38;2;110;110;110m/plans\x1b[0m',
|
|
130
|
+
'\x1b[38;2;110;110;110m/help\x1b[0m',
|
|
131
|
+
'\x1b[38;2;110;110;110m?\x1b[0m',
|
|
132
|
+
].join(' \x1b[38;2;60;60;60m\u00b7\x1b[0m ')
|
|
133
|
+
const hintStr = `${statusBg + statusText} ${hints} ${reset}`
|
|
134
|
+
const fullLine = line + hintStr
|
|
135
|
+
const approxLen = fullLine.replace(/\x1b\[[0-9;]*m/g, '').length
|
|
136
|
+
if (approxLen <= width) {
|
|
137
|
+
result = fullLine
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const visLen = this.visibleLen(result)
|
|
142
|
+
const padded = visLen < width ? result + statusBg + ' '.repeat(width - visLen) + reset : result
|
|
143
|
+
|
|
144
|
+
return [padded]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import type { Component } from '../../pi-tui/index.js'
|
|
3
|
+
import { visibleLen } from '../utils.js'
|
|
4
|
+
import { colors } from './colors.js'
|
|
5
|
+
import { listPlans, type PlanEntry } from './plan-utils.js'
|
|
6
|
+
|
|
7
|
+
export class TodoPanel implements Component {
|
|
8
|
+
private cwd: string
|
|
9
|
+
private todos: { text: string; done: boolean }[] = []
|
|
10
|
+
private planName: string = ''
|
|
11
|
+
private dirty: boolean = true
|
|
12
|
+
|
|
13
|
+
constructor(cwd: string) {
|
|
14
|
+
this.cwd = cwd
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
refresh(): void {
|
|
18
|
+
this.dirty = true
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
invalidate(): void {
|
|
22
|
+
this.dirty = true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private load(): void {
|
|
26
|
+
this.dirty = false
|
|
27
|
+
const plans = listPlans(this.cwd)
|
|
28
|
+
if (plans.length === 0) {
|
|
29
|
+
this.todos = []
|
|
30
|
+
this.planName = ''
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
const plan = plans[0]
|
|
34
|
+
this.planName = plan.name
|
|
35
|
+
this.todos = []
|
|
36
|
+
try {
|
|
37
|
+
const content = fs.readFileSync(plan.fullPath, 'utf-8')
|
|
38
|
+
const lines = content.split('\n')
|
|
39
|
+
for (const line of lines) {
|
|
40
|
+
const m = line.trim().match(/^- \[([ x])\]\s+(.+)/)
|
|
41
|
+
if (m) {
|
|
42
|
+
this.todos.push({ text: m[2], done: m[1] === 'x' })
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
// ignore file read errors
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private visibleLen(s: string): number {
|
|
51
|
+
return visibleLen(s)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
render(width: number): string[] {
|
|
55
|
+
if (this.dirty) this.load()
|
|
56
|
+
|
|
57
|
+
const lines: string[] = []
|
|
58
|
+
|
|
59
|
+
const headerText = ` ${colors.accent('\u25B6')} TODO`
|
|
60
|
+
const headerPadding = Math.max(0, width - this.visibleLen(headerText))
|
|
61
|
+
lines.push(colors.bgDark(headerText + ' '.repeat(headerPadding)))
|
|
62
|
+
|
|
63
|
+
lines.push(colors.separator('\u2500'.repeat(width)))
|
|
64
|
+
|
|
65
|
+
if (!this.planName) {
|
|
66
|
+
lines.push(colors.dim(' (no plan)'))
|
|
67
|
+
return lines
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (this.todos.length === 0) {
|
|
71
|
+
lines.push(colors.dim(' (no todos)'))
|
|
72
|
+
return lines
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const contentWidth = width - 3
|
|
76
|
+
for (const todo of this.todos) {
|
|
77
|
+
const icon = todo.done ? '\u2705' : '\u2B1C'
|
|
78
|
+
const textStyle = todo.done ? colors.doneTodo : colors.todo
|
|
79
|
+
const text = todo.text
|
|
80
|
+
const maxTextLen = contentWidth - 1
|
|
81
|
+
let truncated = text
|
|
82
|
+
let textVisLen = this.visibleLen(textStyle(text))
|
|
83
|
+
if (textVisLen > maxTextLen) {
|
|
84
|
+
truncated = `${text.slice(0, maxTextLen - 1)}\u2026`
|
|
85
|
+
textVisLen = maxTextLen
|
|
86
|
+
}
|
|
87
|
+
const line = ` ${icon} ${textStyle(truncated)}`
|
|
88
|
+
const visLen = this.visibleLen(line)
|
|
89
|
+
const padding = Math.max(0, width - visLen)
|
|
90
|
+
lines.push(line + ' '.repeat(padding))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return lines
|
|
94
|
+
}
|
|
95
|
+
}
|