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/cli/index.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { resetGlobalEventBus } from '../agent/event-bus.js'
|
|
2
|
+
import { Session } from '../agent/session.js'
|
|
1
3
|
import { type Config, loadConfig } from '../config/index.js'
|
|
4
|
+
import { resetTokenUsage } from '../config/tokens.js'
|
|
2
5
|
import { runInit } from './init.js'
|
|
3
6
|
|
|
4
7
|
export interface CliOptions {
|
|
@@ -7,6 +10,10 @@ export interface CliOptions {
|
|
|
7
10
|
web?: boolean
|
|
8
11
|
port?: number
|
|
9
12
|
init?: boolean
|
|
13
|
+
continueSession?: boolean
|
|
14
|
+
sessionId?: string
|
|
15
|
+
listSessions?: boolean
|
|
16
|
+
deleteSession?: string
|
|
10
17
|
}
|
|
11
18
|
|
|
12
19
|
export async function parseArgs(argv: string[]): Promise<CliOptions> {
|
|
@@ -18,11 +25,69 @@ export async function parseArgs(argv: string[]): Promise<CliOptions> {
|
|
|
18
25
|
return { init: true } as CliOptions
|
|
19
26
|
}
|
|
20
27
|
|
|
28
|
+
// Check for new command — clear all saved sessions, then continue fresh
|
|
29
|
+
if (args[0] === 'new') {
|
|
30
|
+
const config = loadConfig()
|
|
31
|
+
Session.clearSavedSession(config.cwd)
|
|
32
|
+
resetTokenUsage(config.cwd)
|
|
33
|
+
resetGlobalEventBus()
|
|
34
|
+
args.splice(0, 1) // Remove 'new', remaining args become normal arguments
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ── Session subcommands ──
|
|
38
|
+
if (args[0] === 'session') {
|
|
39
|
+
const sub = args[1]
|
|
40
|
+
if (sub === 'list') {
|
|
41
|
+
const sessions = Session.listSessions()
|
|
42
|
+
if (sessions.length === 0) {
|
|
43
|
+
console.log('No saved sessions found.')
|
|
44
|
+
} else {
|
|
45
|
+
console.log(`\n Saved Sessions (${sessions.length}):`)
|
|
46
|
+
console.log(' ' + '-'.repeat(80))
|
|
47
|
+
console.log(
|
|
48
|
+
' ID Title Mode Messages Tokens Updated',
|
|
49
|
+
)
|
|
50
|
+
console.log(' ' + '-'.repeat(80))
|
|
51
|
+
for (const s of sessions) {
|
|
52
|
+
const id = s.id.padEnd(9)
|
|
53
|
+
const title = (s.title || '(untitled)').slice(0, 42).padEnd(43)
|
|
54
|
+
const mode = s.mode.padEnd(7)
|
|
55
|
+
const msgs = String(s.messageCount).padEnd(9)
|
|
56
|
+
const tokens = String(s.totalInputTokens + s.totalOutputTokens).padEnd(9)
|
|
57
|
+
const date = s.updatedAt.slice(0, 10)
|
|
58
|
+
console.log(` ${id} ${title} ${mode} ${msgs} ${tokens} ${date}`)
|
|
59
|
+
}
|
|
60
|
+
console.log()
|
|
61
|
+
}
|
|
62
|
+
process.exit(0)
|
|
63
|
+
}
|
|
64
|
+
if (sub === 'delete') {
|
|
65
|
+
const id = args[2]
|
|
66
|
+
if (!id) {
|
|
67
|
+
console.error('Usage: lonny session delete <id>')
|
|
68
|
+
process.exit(1)
|
|
69
|
+
}
|
|
70
|
+
const deleted = Session.deleteSession(id)
|
|
71
|
+
if (deleted) {
|
|
72
|
+
console.log(`Deleted session: ${id}`)
|
|
73
|
+
} else {
|
|
74
|
+
console.error(`Session not found: ${id}`)
|
|
75
|
+
process.exit(1)
|
|
76
|
+
}
|
|
77
|
+
process.exit(0)
|
|
78
|
+
}
|
|
79
|
+
// If just "session" with no subcommand, show usage
|
|
80
|
+
console.log('Usage: lonny session list|delete <id>')
|
|
81
|
+
process.exit(0)
|
|
82
|
+
}
|
|
83
|
+
|
|
21
84
|
let prompt: string | undefined
|
|
22
85
|
let autoApprove: boolean | undefined
|
|
23
|
-
let mode: 'code' | 'plan' | 'ask' | undefined
|
|
86
|
+
let mode: 'code' | 'plan' | 'ask' | 'loop' | undefined
|
|
24
87
|
let web = false
|
|
25
88
|
let port: number | undefined
|
|
89
|
+
let continueSession = false
|
|
90
|
+
let sessionId: string | undefined
|
|
26
91
|
|
|
27
92
|
for (let i = 0; i < args.length; i++) {
|
|
28
93
|
const arg = args[i]
|
|
@@ -31,19 +96,23 @@ export async function parseArgs(argv: string[]): Promise<CliOptions> {
|
|
|
31
96
|
} else if (arg === '--auto-approve') {
|
|
32
97
|
autoApprove = true
|
|
33
98
|
} else if (arg === '--mode') {
|
|
34
|
-
mode = args[++i] as 'code' | 'plan' | 'ask'
|
|
99
|
+
mode = args[++i] as 'code' | 'plan' | 'ask' | 'loop'
|
|
35
100
|
} else if (arg === '--web') {
|
|
36
101
|
web = true
|
|
37
102
|
} else if (arg === '--port') {
|
|
38
103
|
port = parseInt(args[++i], 10)
|
|
104
|
+
} else if (arg === '--continue' || arg === '-c') {
|
|
105
|
+
continueSession = true
|
|
106
|
+
} else if (arg === '--session' || arg === '-s') {
|
|
107
|
+
sessionId = args[++i]
|
|
39
108
|
}
|
|
40
109
|
}
|
|
41
110
|
|
|
42
|
-
if (!prompt && args.length > 0 && !args[0].startsWith('-')) {
|
|
111
|
+
if (!prompt && args.length > 0 && !args[0].startsWith('-') && args[0] !== 'session') {
|
|
43
112
|
prompt = args[0]
|
|
44
113
|
}
|
|
45
114
|
|
|
46
115
|
const config = loadConfig({ autoApprove, mode })
|
|
47
116
|
|
|
48
|
-
return { config, prompt, web, port }
|
|
117
|
+
return { config, prompt, web, port, continueSession, sessionId }
|
|
49
118
|
}
|
package/src/config/index.ts
CHANGED
|
@@ -5,7 +5,7 @@ import * as path from 'node:path'
|
|
|
5
5
|
export interface Config {
|
|
6
6
|
apiKey: string
|
|
7
7
|
baseUrl?: string
|
|
8
|
-
mode: 'code' | 'plan' | 'ask'
|
|
8
|
+
mode: 'code' | 'plan' | 'ask' | 'loop'
|
|
9
9
|
provider: 'openai' | 'anthropic' | 'google' | 'ollama'
|
|
10
10
|
model: string
|
|
11
11
|
contextWindow: number
|
|
@@ -288,6 +288,12 @@ function loadJsonConfig(): JsonConfig {
|
|
|
288
288
|
}
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
+
function saveJsonConfig(config: JsonConfig): void {
|
|
292
|
+
const configPath = path.join(os.homedir(), '.lonny', 'config.json')
|
|
293
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8')
|
|
294
|
+
cachedJsonConfig = config
|
|
295
|
+
}
|
|
296
|
+
|
|
291
297
|
/** Check if the model is a DeepSeek model (supports enable_cache). */
|
|
292
298
|
function isDeepSeekModel(model: string, baseUrl?: string): boolean {
|
|
293
299
|
if (/deepseek/i.test(model)) return true
|
|
@@ -296,7 +302,7 @@ function isDeepSeekModel(model: string, baseUrl?: string): boolean {
|
|
|
296
302
|
}
|
|
297
303
|
|
|
298
304
|
export function loadConfig(options?: {
|
|
299
|
-
mode?: 'code' | 'plan' | 'ask'
|
|
305
|
+
mode?: 'code' | 'plan' | 'ask' | 'loop'
|
|
300
306
|
autoApprove?: boolean
|
|
301
307
|
cwd?: string
|
|
302
308
|
}): Config {
|
|
@@ -304,6 +310,11 @@ export function loadConfig(options?: {
|
|
|
304
310
|
|
|
305
311
|
const model = jsonConfig.model || 'deepseek-v4-flash'
|
|
306
312
|
const baseUrl = process.env.LONNY_BASE_URL || jsonConfig.baseUrl || undefined
|
|
313
|
+
const provider = (process.env.LONNY_PROVIDER || jsonConfig.provider || 'openai') as
|
|
314
|
+
| 'openai'
|
|
315
|
+
| 'anthropic'
|
|
316
|
+
| 'google'
|
|
317
|
+
| 'ollama'
|
|
307
318
|
|
|
308
319
|
// Auto-enable cache for DeepSeek models unless explicitly disabled
|
|
309
320
|
const enableCache = jsonConfig.enableCache ?? (isDeepSeekModel(model, baseUrl) || undefined)
|
|
@@ -314,11 +325,7 @@ export function loadConfig(options?: {
|
|
|
314
325
|
return {
|
|
315
326
|
apiKey: jsonConfig.apiKey || '',
|
|
316
327
|
baseUrl,
|
|
317
|
-
provider
|
|
318
|
-
| 'openai'
|
|
319
|
-
| 'anthropic'
|
|
320
|
-
| 'google'
|
|
321
|
-
| 'ollama',
|
|
328
|
+
provider,
|
|
322
329
|
mode: options?.mode || 'code',
|
|
323
330
|
model,
|
|
324
331
|
contextWindow,
|
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { execSync } from 'node:child_process'
|
|
3
3
|
import * as os from 'node:os'
|
|
4
4
|
import { runAgent } from './agent/index.js'
|
|
5
|
+
import { Session } from './agent/session.js'
|
|
5
6
|
import { parseArgs } from './cli/index.js'
|
|
6
7
|
import { fmtErr } from './tools/errors.js'
|
|
7
8
|
import { startTui } from './tui/index.js'
|
|
@@ -27,7 +28,9 @@ function tryEnableUtf8(): void {
|
|
|
27
28
|
|
|
28
29
|
async function main() {
|
|
29
30
|
tryEnableUtf8()
|
|
30
|
-
const { config, prompt, web, port, init } = await parseArgs(
|
|
31
|
+
const { config, prompt, web, port, init, continueSession, sessionId } = await parseArgs(
|
|
32
|
+
process.argv,
|
|
33
|
+
)
|
|
31
34
|
|
|
32
35
|
// init command exits after completion
|
|
33
36
|
if (init) {
|
|
@@ -41,12 +44,36 @@ async function main() {
|
|
|
41
44
|
process.exit(1)
|
|
42
45
|
}
|
|
43
46
|
|
|
47
|
+
let loadedSession: Session | null = null
|
|
48
|
+
|
|
49
|
+
// Handle --continue and --session flags
|
|
50
|
+
if (continueSession || sessionId) {
|
|
51
|
+
if (sessionId) {
|
|
52
|
+
loadedSession = await Session.loadById(sessionId, config)
|
|
53
|
+
if (loadedSession) {
|
|
54
|
+
console.log(
|
|
55
|
+
`${BLD}Resuming session:${RS} ${loadedSession.sessionTitle || loadedSession.sessionId}`,
|
|
56
|
+
)
|
|
57
|
+
} else {
|
|
58
|
+
console.error(`${RE}Error:${RS} Session not found: ${sessionId}`)
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
loadedSession = await Session.load(config)
|
|
63
|
+
if (loadedSession) {
|
|
64
|
+
console.log(
|
|
65
|
+
`${BLD}Continuing last session:${RS} ${loadedSession.sessionTitle || loadedSession.sessionId}`,
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
44
71
|
if (web) {
|
|
45
72
|
await startWebUi(config, port || 15090)
|
|
46
73
|
} else if (prompt) {
|
|
47
|
-
await runAgent(prompt, config)
|
|
74
|
+
await runAgent(prompt, config, loadedSession ?? undefined)
|
|
48
75
|
} else {
|
|
49
|
-
await startTui(config)
|
|
76
|
+
await startTui(config, loadedSession ?? undefined)
|
|
50
77
|
}
|
|
51
78
|
}
|
|
52
79
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import * as fs from 'node:fs'
|
|
2
|
+
import * as os from 'node:os'
|
|
3
|
+
import * as path from 'node:path'
|
|
1
4
|
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { bashTool } from '../bash.js'
|
|
5
|
+
import { bashTool } from '../execute/bash/index.js'
|
|
6
|
+
|
|
7
|
+
function makeTempDir(): string {
|
|
8
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'lonny-test-'))
|
|
9
|
+
}
|
|
3
10
|
|
|
4
11
|
describe('bash tool', () => {
|
|
5
12
|
it('executes a command successfully', async () => {
|
|
@@ -17,7 +24,7 @@ describe('bash tool', () => {
|
|
|
17
24
|
it('returns error for invalid command', async () => {
|
|
18
25
|
const result = await bashTool.execute({ command: 'some_nonexistent_command_xyz' })
|
|
19
26
|
expect(result.success).toBe(false)
|
|
20
|
-
expect(result.error).toContain('Command
|
|
27
|
+
expect(result.error).toContain('Command exited with code 1')
|
|
21
28
|
})
|
|
22
29
|
|
|
23
30
|
it('accepts custom timeout', async () => {
|
|
@@ -25,4 +32,183 @@ describe('bash tool', () => {
|
|
|
25
32
|
expect(result.success).toBe(true)
|
|
26
33
|
expect(result.output).toContain('timed')
|
|
27
34
|
})
|
|
35
|
+
|
|
36
|
+
it('includes description in output when provided', async () => {
|
|
37
|
+
const result = await bashTool.execute({
|
|
38
|
+
command: 'echo hello',
|
|
39
|
+
description: 'testing description',
|
|
40
|
+
})
|
|
41
|
+
expect(result.success).toBe(true)
|
|
42
|
+
expect(result.output).toContain('[bash]')
|
|
43
|
+
expect(result.output).toContain('testing description')
|
|
44
|
+
expect(result.output).toContain('hello')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('runs command in specified cwd', async () => {
|
|
48
|
+
const tmpDir = makeTempDir()
|
|
49
|
+
try {
|
|
50
|
+
// Create a marker file so we can verify cwd
|
|
51
|
+
const result = await bashTool.execute({ command: 'pwd', cwd: tmpDir })
|
|
52
|
+
expect(result.success).toBe(true)
|
|
53
|
+
// On Windows, PowerShell's Get-Location returns the path
|
|
54
|
+
// We just need to check the command executed without error
|
|
55
|
+
if (os.platform() === 'win32') {
|
|
56
|
+
// PowerShell: use Get-Location instead of pwd
|
|
57
|
+
const result2 = await bashTool.execute({
|
|
58
|
+
command: `Get-Location | Select-Object -ExpandProperty Path`,
|
|
59
|
+
cwd: tmpDir,
|
|
60
|
+
})
|
|
61
|
+
expect(result2.success).toBe(true)
|
|
62
|
+
const normalizedOutput = result2.output.replace(/\\/g, '/')
|
|
63
|
+
const normalizedTmp = tmpDir.replace(/\\/g, '/')
|
|
64
|
+
expect(normalizedOutput).toContain(normalizedTmp)
|
|
65
|
+
} else {
|
|
66
|
+
expect(result.output).toContain(tmpDir)
|
|
67
|
+
}
|
|
68
|
+
} finally {
|
|
69
|
+
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('handles stderr output separately', async () => {
|
|
74
|
+
// PowerShell: write to stderr using Write-Error
|
|
75
|
+
const result = await bashTool.execute({
|
|
76
|
+
command: 'Write-Error "test error" 2>&1 | Out-Null; Write-Output "stdout ok"',
|
|
77
|
+
})
|
|
78
|
+
// 2>&1 redirects stderr to stdout in PowerShell, so it should succeed
|
|
79
|
+
expect(result.success).toBe(true)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('shows (no output) for empty output', async () => {
|
|
83
|
+
// A command that produces no output
|
|
84
|
+
const result = await bashTool.execute({ command: 'Write-Output ""' })
|
|
85
|
+
expect(result.success).toBe(true)
|
|
86
|
+
expect(result.output).toContain('(no output)')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('truncates very large output', async () => {
|
|
90
|
+
// Generate a very large output to trigger truncation
|
|
91
|
+
const result = await bashTool.execute({ command: '1..5000 | ForEach-Object { "Line $_" }' })
|
|
92
|
+
expect(result.success).toBe(true)
|
|
93
|
+
// Check if truncation warning is present (output > 10k chars)
|
|
94
|
+
if (result.output.length > 10000) {
|
|
95
|
+
expect(result.output).toContain('truncated at')
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it('rejects whitespace-only command', async () => {
|
|
100
|
+
const result = await bashTool.execute({ command: ' ' })
|
|
101
|
+
expect(result.success).toBe(false)
|
|
102
|
+
expect(result.error).toContain('whitespace')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('rejects non-string command type', async () => {
|
|
106
|
+
const result = await bashTool.execute({ command: 123 })
|
|
107
|
+
expect(result.success).toBe(false)
|
|
108
|
+
expect(result.error).toContain('must be a string')
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('rejects non-existent cwd', async () => {
|
|
112
|
+
const result = await bashTool.execute({
|
|
113
|
+
command: 'echo test',
|
|
114
|
+
cwd: 'C:\\NonExistent_Directory_XYZ_123',
|
|
115
|
+
})
|
|
116
|
+
expect(result.success).toBe(false)
|
|
117
|
+
expect(result.error).toContain('does not exist')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('blocks destructive rm -rf / command', async () => {
|
|
121
|
+
const result = await bashTool.execute({ command: 'rm -rf /' })
|
|
122
|
+
expect(result.success).toBe(false)
|
|
123
|
+
expect(result.error).toContain('Destructive')
|
|
124
|
+
expect(result.error).toContain('destroy')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('blocks destructive format command', async () => {
|
|
128
|
+
const result = await bashTool.execute({ command: 'format D: /Q' })
|
|
129
|
+
expect(result.success).toBe(false)
|
|
130
|
+
expect(result.error).toContain('Destructive')
|
|
131
|
+
expect(result.error).toContain('destroy')
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('clamps timeout to valid range', async () => {
|
|
135
|
+
// Very large timeout should be clamped, not cause error
|
|
136
|
+
const result = await bashTool.execute({ command: 'echo ok', timeout: 999999999 })
|
|
137
|
+
expect(result.success).toBe(true)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('rejects filename-like command (no space before flag)', async () => {
|
|
141
|
+
// This test verifies that the tool handles edge case input gracefully
|
|
142
|
+
const result = await bashTool.execute({ command: '--version' })
|
|
143
|
+
// Should fail with exit code 1, not crash
|
|
144
|
+
expect(result.success).toBe(false)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('blocks Remove-Item -Recurse -Force command', async () => {
|
|
148
|
+
const result = await bashTool.execute({ command: 'Remove-Item C:\\Windows -Recurse -Force' })
|
|
149
|
+
expect(result.success).toBe(false)
|
|
150
|
+
expect(result.error).toContain('Destructive')
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('blocks diskpart clean-all command', async () => {
|
|
154
|
+
const result = await bashTool.execute({ command: 'diskpart clean-all' })
|
|
155
|
+
expect(result.success).toBe(false)
|
|
156
|
+
expect(result.error).toContain('Destructive')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('blocks reg delete command', async () => {
|
|
160
|
+
const result = await bashTool.execute({ command: 'reg delete HKLM\\Software' })
|
|
161
|
+
expect(result.success).toBe(false)
|
|
162
|
+
expect(result.error).toContain('Destructive')
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('rejects cwd with path traversal', async () => {
|
|
166
|
+
const result = await bashTool.execute({
|
|
167
|
+
command: 'echo test',
|
|
168
|
+
cwd: 'C:\\Users\\..\\Windows',
|
|
169
|
+
})
|
|
170
|
+
expect(result.success).toBe(false)
|
|
171
|
+
expect(result.error).toContain('path traversal')
|
|
172
|
+
expect(result.error).toContain('..')
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('rejects cwd with path traversal using forward slashes', async () => {
|
|
176
|
+
const result = await bashTool.execute({
|
|
177
|
+
command: 'echo test',
|
|
178
|
+
cwd: '/Users/../etc',
|
|
179
|
+
})
|
|
180
|
+
expect(result.success).toBe(false)
|
|
181
|
+
expect(result.error).toContain('path traversal')
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it('redacts sensitive data from output', async () => {
|
|
185
|
+
// Test redaction of API key pattern in output
|
|
186
|
+
const result = await bashTool.execute({
|
|
187
|
+
command: "Write-Output 'api_key=sk-abc123def456ghi789jkl012mno345pqr678stu'",
|
|
188
|
+
})
|
|
189
|
+
expect(result.success).toBe(true)
|
|
190
|
+
// The API key should be redacted
|
|
191
|
+
expect(result.output).not.toContain('sk-abc123def456ghi789jkl012mno345pqr678stu')
|
|
192
|
+
expect(result.output).toContain('[REDACTED]')
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('redacts sensitive data from stderr', async () => {
|
|
196
|
+
const result = await bashTool.execute({
|
|
197
|
+
command: "Write-Error 'The token ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx is invalid'",
|
|
198
|
+
})
|
|
199
|
+
// Should not crash; the redacted marker should appear in the output/error
|
|
200
|
+
if (!result.success && result.error) {
|
|
201
|
+
// The token may be split across lines in PowerShell error formatting,
|
|
202
|
+
// but [REDACTED] should appear at least once
|
|
203
|
+
expect(result.error).toContain('[REDACTED]')
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
it('shows platform-specific tip for grep on Windows', async () => {
|
|
208
|
+
if (os.platform() === 'win32') {
|
|
209
|
+
const result = await bashTool.execute({ command: 'grep "pattern" file.txt' })
|
|
210
|
+
expect(result.success).toBe(false)
|
|
211
|
+
expect(result.error).toContain('findstr')
|
|
212
|
+
}
|
|
213
|
+
})
|
|
28
214
|
})
|