localcode-agent 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LocalCode Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,200 @@
1
+ # ⚡ LocalCode
2
+
3
+ **An AI coding agent that runs entirely in your terminal no cloud account required.**
4
+ Point it at a local model (Ollama, LM Studio) or any OpenAI-compatible server and start building.
5
+
6
+ ![Node.js](https://img.shields.io/badge/Node.js-18%2B-green)
7
+ ![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20%7C%20Windows-blue)
8
+ ![License](https://img.shields.io/badge/license-MIT-brightgreen)
9
+
10
+ ---
11
+
12
+ ## What it does
13
+
14
+ LocalCode gives you an autonomous agent that can read your codebase, write and edit files, run shell commands, and commit to git all from a keyboard-driven terminal UI. You describe the task, the agent does the work, and asks for your confirmation before touching anything destructive.
15
+
16
+ ---
17
+
18
+ ## Requirements
19
+
20
+ - **Node.js 18+** [nodejs.org](https://nodejs.org)
21
+ - A running **local LLM server** Ollama or LM Studio (see below)
22
+
23
+ ---
24
+
25
+ ## Quick start
26
+
27
+ ### 1. Install a local model server
28
+
29
+ **Ollama** (recommended free, works on Linux / macOS / Windows)
30
+
31
+ ```bash
32
+ # Install from https://ollama.com, then run:
33
+ ollama serve
34
+ ollama pull deepseek-coder # or any model you prefer
35
+ ```
36
+
37
+ **LM Studio** download the desktop app from [lmstudio.ai](https://lmstudio.ai), load a model, and click **Start Local Server**.
38
+
39
+ ---
40
+
41
+ ### 2. Install LocalCode
42
+
43
+ ```bash
44
+ git clone https://github.com/lsheasel/LocalCode.git
45
+ cd LocalCode
46
+ npm install
47
+ npm run build
48
+ npm link # adds 'localcode' to your PATH
49
+ ```
50
+
51
+ > **Windows:** use PowerShell or Windows Terminal.
52
+ > **macOS / Linux:** any terminal works.
53
+
54
+ ---
55
+
56
+ ### 3. Run it
57
+
58
+ ```bash
59
+ localcode
60
+ ```
61
+
62
+ This opens the interactive TUI. Type a task and press `Enter`.
63
+
64
+ You can also pass a task directly on the command line:
65
+
66
+ ```bash
67
+ localcode fix the auth bug in src/auth.ts
68
+ localcode add unit tests for the user service
69
+ localcode explain the architecture of this project
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Connecting to a server
75
+
76
+ Type `/connect` and press `Enter` to open the connection popup:
77
+
78
+ 1. **Choose a provider** Ollama, LM Studio, or any OpenAI-compatible API
79
+ 2. **Enter the IP address** use `localhost` for a server on the same machine
80
+ 3. **Enter the port** `11434` for Ollama, `1234` for LM Studio
81
+
82
+ The connection is saved automatically to `~/.localcode/config.json`.
83
+
84
+ ---
85
+
86
+ ## Switching models
87
+
88
+ Type `/model` to open the model picker. LocalCode fetches all available models from your server. Use the arrow keys to navigate, `/` to search, and `Enter` to select.
89
+
90
+ ---
91
+
92
+ ## Keyboard shortcuts
93
+
94
+ | Key | Action |
95
+ |---|---|
96
+ | `Enter` | Send message / run task |
97
+ | `Tab` | Accept autocomplete suggestion |
98
+ | `↑ / ↓` | Browse command history |
99
+ | `PageUp / PageDown` | Scroll chat history |
100
+ | `Ctrl+C` | Stop the running agent |
101
+ | `Ctrl+L` | Clear the screen |
102
+ | `Esc` | Close popup / cancel input |
103
+
104
+ **Shell passthrough** prefix a command with `$` or `!` to run it directly without the agent:
105
+
106
+ ```
107
+ $ npm test
108
+ ! git log --oneline -10
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Slash commands
114
+
115
+ Type `/` to open the command picker. All commands are searchable.
116
+
117
+ | Command | What it does |
118
+ |---|---|
119
+ | `/connect` | Open the server connection popup |
120
+ | `/model` | Pick a model from the server (searchable popup) |
121
+ | `/models` | List all available models as plain text |
122
+ | `/doctor` | Check server connectivity and current config |
123
+ | `/config` | Show the current configuration |
124
+ | `/config provider ollama` | Switch to Ollama |
125
+ | `/config provider lmstudio` | Switch to LM Studio |
126
+ | `/config model <name>` | Set the active model by name |
127
+ | `/config url <url>` | Override the server base URL |
128
+ | `/config temperature <0–1>` | Adjust model temperature |
129
+ | `/clear` | Clear the chat |
130
+ | `/exit` | Quit |
131
+
132
+ ---
133
+
134
+ ## Configuration file
135
+
136
+ Settings live in `~/.localcode/config.json` and are created automatically on first run. You can also edit the file directly:
137
+
138
+ ```json
139
+ {
140
+ "llm": {
141
+ "provider": "ollama",
142
+ "model": "deepseek-coder:latest",
143
+ "baseURL": "http://localhost:11434",
144
+ "temperature": 0.1
145
+ }
146
+ }
147
+ ```
148
+
149
+ **Supported providers:** `ollama` · `lmstudio`
150
+
151
+ ---
152
+
153
+ ## What the agent can do
154
+
155
+ When you give it a task, the agent can:
156
+
157
+ - Read and search files in your project
158
+ - Write new files or edit existing ones (with a diff preview and confirmation before applying)
159
+ - Run shell commands git, npm, compilers, test runners, anything
160
+ - Create git commits
161
+
162
+ **Safety:** Dangerous operations (`rm -rf`, `sudo`, force-push, database drops) are blocked automatically. File writes and shell commands ask for confirmation before running.
163
+
164
+ ---
165
+
166
+ ## Troubleshooting
167
+
168
+ **"Ollama is not reachable"**
169
+ Make sure Ollama is running (`ollama serve`) and the URL matches. Run `/doctor` to check.
170
+
171
+ **"LM Studio is not reachable"**
172
+ Open LM Studio, load a model, and click **Start Local Server**. Default port is `1234`.
173
+
174
+ **"Model not found"**
175
+ Type `/models` to see what's loaded, then switch with `/model` or `/config model <name>`.
176
+
177
+ **The TUI looks broken / garbled**
178
+ LocalCode requires a terminal with 256-color and UTF-8 support.
179
+ Use **Windows Terminal** on Windows, or any modern terminal on macOS / Linux (iTerm2, Ghostty, Alacritty, etc.).
180
+
181
+ ---
182
+
183
+ ## Contributing
184
+
185
+ Contributions are welcome. To get started:
186
+
187
+ 1. Fork the repository and create a branch for your change
188
+ 2. Install dependencies: `npm install`
189
+ 3. Start watch mode: `npm run dev`
190
+ 4. Make your changes in `src/`
191
+ 5. Test with `node dist/localcode.js`
192
+ 6. Open a pull request with a clear description of what you changed and why
193
+
194
+ Please keep pull requests focused one feature or fix per PR. If you're planning something large, open an issue first to discuss the approach.
195
+
196
+ ---
197
+
198
+ ## License
199
+
200
+ [MIT](./LICENSE) free to use, modify, and distribute.
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+ import i,{useState,useRef,useEffect,useCallback}from'react';import {render,useApp,useInput,Box,Text}from'ink';import Z from'chalk';import Lt from'ink-text-input';import {readFile,mkdir,rm,copyFile,readdir,unlink,rename,writeFile,appendFile}from'fs/promises';import*as j from'fs';import {existsSync,readdirSync,statSync,cpSync}from'fs';import*as Pe from'path';import {join,resolve,basename,extname,dirname}from'path';import*as Ht from'os';import {exec,execSync}from'child_process';import {EventEmitter}from'events';import {promisify}from'util';import {createRequire}from'module';var Oo=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,o)=>(typeof require<"u"?require:e)[o]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});var St={llm:{provider:"ollama",model:"deepseek-coder:latest",baseURL:"http://localhost:11434",temperature:.1,maxTokens:8192},theme:"dark",fontSize:14,shell:process.platform==="win32"?"powershell.exe":process.platform==="darwin"?process.env.SHELL||"zsh":process.env.SHELL||"bash",workspaceDir:Ht.homedir(),security:{allowDangerousCommands:false,requireConfirmation:["rm -rf","sudo rm","shutdown","reboot","git push --force","git reset --hard","DROP TABLE","DROP DATABASE"]}},Xt=`You are LocalCode, an elite autonomous AI software engineering agent running inside a futuristic developer terminal. You analyze codebases, fix bugs, create features, run tests, and manage projects with surgical precision.
3
+
4
+ ## IMPORTANT: When NOT to use tools
5
+
6
+ For greetings, small talk, or simple questions ("hi", "hello", "what can you do", "how are you", etc.) \u2014 respond DIRECTLY as text without calling any tools. Immediately end with DONE: <your response>.
7
+
8
+ Example:
9
+ User: hi
10
+ You: DONE: Hey! I'm LocalCode, your AI coding agent. Tell me what to build, fix, or analyze and I'll get to work.
11
+
12
+ Only use tools when the task genuinely requires reading files, running commands, or inspecting the codebase.
13
+
14
+ ## Tool Calling
15
+
16
+ When you need to take an action, respond with ONLY a JSON object in this exact format:
17
+ {"tool": "TOOL_NAME", "arguments": {ARGUMENTS_OBJECT}}
18
+
19
+ ## Available Tools
20
+
21
+ ### Shell
22
+ - **run_shell**: Execute a shell command
23
+ {"tool": "run_shell", "arguments": {"command": "npm test"}}
24
+
25
+ ### File System
26
+ - **read_file**: Read file contents
27
+ {"tool": "read_file", "arguments": {"path": "src/auth.ts"}}
28
+
29
+ - **write_file**: Write/overwrite a file completely
30
+ {"tool": "write_file", "arguments": {"path": "src/auth.ts", "content": "..."}}
31
+
32
+ - **append_file**: Append content to a file (creates if missing)
33
+ {"tool": "append_file", "arguments": {"path": "log.txt", "content": "new line
34
+ "}}
35
+
36
+ - **edit_file**: Targeted search-and-replace inside a file
37
+ {"tool": "edit_file", "arguments": {"path": "src/auth.ts", "old": "old code", "new": "new code"}}
38
+
39
+ - **delete_file**: Delete a file or directory
40
+ {"tool": "delete_file", "arguments": {"path": "src/old.ts", "recursive": false}}
41
+
42
+ - **move_file**: Move or rename a file/directory
43
+ {"tool": "move_file", "arguments": {"from": "src/foo.ts", "to": "src/bar.ts"}}
44
+
45
+ - **copy_file**: Copy a file
46
+ {"tool": "copy_file", "arguments": {"from": "src/foo.ts", "to": "src/foo.backup.ts"}}
47
+
48
+ - **create_dir**: Create a directory (including parents)
49
+ {"tool": "create_dir", "arguments": {"path": "src/utils/helpers"}}
50
+
51
+ - **list_files**: List directory contents
52
+ {"tool": "list_files", "arguments": {"path": "src", "recursive": true}}
53
+
54
+ - **find_files**: Find files by name pattern (glob-style, * and ? supported)
55
+ {"tool": "find_files", "arguments": {"pattern": "*.test.ts", "path": "src"}}
56
+
57
+ - **search_files**: Search for a text pattern inside files
58
+ {"tool": "search_files", "arguments": {"pattern": "authMiddleware", "path": "src"}}
59
+
60
+ ### Git
61
+ - **git_status**: Working tree status
62
+ {"tool": "git_status", "arguments": {}}
63
+
64
+ - **git_diff**: Show changes (set staged: true for staged diff)
65
+ {"tool": "git_diff", "arguments": {"staged": false}}
66
+
67
+ - **git_log**: Recent commit history
68
+ {"tool": "git_log", "arguments": {"limit": 20}}
69
+
70
+ - **git_commit**: Stage all and commit
71
+ {"tool": "git_commit", "arguments": {"message": "fix: resolve auth session handling"}}
72
+
73
+ ### Network
74
+ - **web_fetch**: Fetch a URL and return its content as readable text (HTML is stripped)
75
+ {"tool": "web_fetch", "arguments": {"url": "https://example.com", "format": "text"}}
76
+ Use format "json" for JSON APIs.
77
+
78
+ - **http_request**: Make an HTTP request (GET/POST/PUT/DELETE/PATCH)
79
+ {"tool": "http_request", "arguments": {"method": "POST", "url": "http://localhost:3000/api/users", "headers": {"Authorization": "Bearer token"}, "body": {"name": "Alice"}}}
80
+
81
+ ### LSP / Diagnostics
82
+ - **lsp_check**: Run the project's language checker (tsc, cargo check, go vet, pyflakes, eslint) and return diagnostics
83
+ {"tool": "lsp_check", "arguments": {"path": "."}}
84
+ Optional: pass a specific file path instead of "." to check only that file.
85
+
86
+ ## Workflow
87
+
88
+ 1. EXPLORE: Understand the codebase structure before making changes
89
+ 2. ANALYZE: Read relevant files thoroughly
90
+ 3. ACT: Make precise, minimal changes
91
+ 4. VERIFY: Run tests to confirm fixes work
92
+ 5. REPORT: Summarize what was done
93
+
94
+ ## Rules
95
+
96
+ - Always explore before you change anything
97
+ - Make minimal, focused changes
98
+ - Use run_shell for directory/file system operations: mkdir, cp, mv, touch, rename, find, etc.
99
+ - Use write_file or edit_file when creating or modifying file contents
100
+ - Never run dangerous commands (rm -rf /, sudo rm, format, shutdown etc.)
101
+ - Run tests after changes when possible
102
+
103
+ ## Completion
104
+
105
+ When the task is fully complete, respond with exactly:
106
+ DONE: [Clear summary of all changes made and results]
107
+
108
+ The word DONE: must be at the very start of your final response.`;var Gt=`You are LocalCode in PLAN MODE. Your job is to think deeply and produce a clear, structured implementation plan \u2014 do NOT call any tools or execute anything.
109
+
110
+ Analyze the request and respond with a detailed plan in this format:
111
+
112
+ ## Goal
113
+ One sentence describing what needs to be achieved.
114
+
115
+ ## Steps
116
+ Numbered list of concrete implementation steps. For each step include:
117
+ - What file(s) to create or modify
118
+ - What exactly to change and why
119
+ - Any potential pitfalls or edge cases
120
+
121
+ ## Files affected
122
+ List of all files that will be changed.
123
+
124
+ ## Open questions
125
+ Any ambiguities or decisions that need user input before starting.
126
+
127
+ End with: DONE: <one-line summary of the plan>`,qt=30,Ve=[{cmd:"/plugin",description:"Manage plugins (list/install/remove/reload)"},{cmd:"/plugin install ",description:"Install plugin from path"},{cmd:"/plugin remove ",description:"Remove plugin by name"},{cmd:"/plugin reload",description:"Reload all plugins"},{cmd:"/connect",description:"Connect to server (popup)"},{cmd:"/model",description:"Select model (popup)"},{cmd:"/attach",description:"Attach file or image (@-picker)"},{cmd:"/compact",description:"Summarize & compress conversation"},{cmd:"/session",description:"List saved sessions"},{cmd:"/session save ",description:"Save session as <name>"},{cmd:"/session load ",description:"Load session <name>"},{cmd:"/session delete ",description:"Delete session <name>"},{cmd:"/config",description:"Show current configuration"},{cmd:"/config model ",description:"Switch model"},{cmd:"/config provider ollama",description:"Use Ollama (localhost:11434)"},{cmd:"/config provider lmstudio",description:"Use LM Studio (localhost:1234)"},{cmd:"/config url ",description:"Set base URL"},{cmd:"/help",description:"Show help"},{cmd:"/lsp",description:"Run diagnostics (tsc/cargo/pylint/eslint)"},{cmd:"/models",description:"List available models"},{cmd:"/doctor",description:"Check system status"},{cmd:"/clear",description:"Clear screen"},{cmd:"/exit",description:"Quit"}],lt=["fix auth bug","fix typescript errors","analyze architecture","explain this codebase","create REST API for users","add unit tests","optimize database queries","refactor api layer","scan for security issues","create nextjs dashboard","run tests","explain docker-compose.yml"];var jo=["\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 ","\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 ","\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 ","\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 ","\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557","\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],Uo=[" \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"," \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D"," \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 "," \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D "," \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557"," \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"],Jt=["Start inside a project folder so the agent has codebase context","Run shell commands directly: $ npm test or ! git status","LM Studio: /config provider lmstudio | Ollama: /config provider ollama","Try: fix auth bug \xB7 analyze architecture \xB7 add unit tests","Drag & drop a file into the terminal to attach it automatically","Type @filename to attach a file inline \u2014 e.g. @src/app.ts explain this","Use /model to browse and switch models from the running server","Tab autocompletes commands or toggles BUILD \u2194 PLAN mode","/compact summarizes long conversations to free up context window","/session save <name> to bookmark a conversation, /session load to resume","/doctor checks your LLM connection and shows current configuration","Plan before you build: tab to switch to PLAN mode, then describe the feature"];function Wo(r,e){if(r.length<2)return "";let o=e.find(s=>s!==r&&s.toLowerCase().startsWith(r.toLowerCase()));if(o)return o.slice(r.length);let t=Ve.find(s=>s.cmd.startsWith(r)&&s.cmd!==r);if(t)return t.cmd.slice(r.length);let n=lt.find(s=>s.startsWith(r)&&s!==r);return n?n.slice(r.length):""}var Vt=({config:r,history:e,onSubmit:o})=>{let[t,n]=useState(""),[s,l]=useState(-1),c=Jt[new Date().getDate()%Jt.length],a=Wo(t,e);useInput((y,x)=>{if(x.tab&&a){n(t+a);return}if(x.upArrow){let S=Math.min(s+1,e.length-1);l(S),e[S]&&n(e[S]);}if(x.downArrow){let S=Math.max(s-1,-1);l(S),n(S===-1?"":e[S]||"");}x.escape&&(n(""),l(-1));});let u=useCallback(y=>{n(y),l(-1);},[]),d=useCallback(y=>{y.trim()&&(l(-1),o(y.trim()),n(""));},[o]),p=Math.max(1,Math.floor((process.stdout.rows||24)/2)-10);return i.createElement(Box,{flexDirection:"column",alignItems:"center"},Array.from({length:p}).map((y,x)=>i.createElement(Text,{key:x}," ")),jo.map((y,x)=>i.createElement(Box,{key:x},i.createElement(Text,{color:"#d8d8d8"},y),i.createElement(Text,{color:"#3B82F6"},Uo[x]))),i.createElement(Text,null," "),i.createElement(Box,{flexDirection:"column",borderStyle:"single",borderColor:"#1E3A5F",minWidth:60},i.createElement(Box,{paddingX:1},i.createElement(Text,{color:"#3B82F6",bold:true},"> "),i.createElement(Lt,{value:t,onChange:u,onSubmit:d,placeholder:"ask anything \xB7 / for commands \xB7 @ to attach"}),a&&i.createElement(Text,{color:"#1F2937"},a)),i.createElement(Box,{paddingX:1,justifyContent:"space-between"},i.createElement(Box,null,i.createElement(Text,{color:"#4B5563"},"\u21B5 "),i.createElement(Text,{color:"#6B7280"},"send "),i.createElement(Text,{color:"#4B5563"},"tab "),i.createElement(Text,{color:"#6B7280"},a?"complete":"autocomplete")),i.createElement(Box,null,i.createElement(Text,{backgroundColor:"#1D4ED8",color:"#BFDBFE"}," BUILD "),i.createElement(Text,{color:"#374151"}," "),i.createElement(Text,{color:"#9CA3AF"},r.llm.model.length>20?r.llm.model.slice(0,20)+"\u2026":r.llm.model)))),i.createElement(Box,{paddingLeft:2,marginTop:1},i.createElement(Text,{color:"#4B5563"},"\u2191\u2193 "),i.createElement(Text,{color:"#6B7280"},"history "),i.createElement(Text,{color:"#4B5563"},"@ "),i.createElement(Text,{color:"#6B7280"},"attach "),i.createElement(Text,{color:"#4B5563"},"ctrl+c "),i.createElement(Text,{color:"#6B7280"},"quit")),i.createElement(Text,null," "),i.createElement(Box,{paddingLeft:2},i.createElement(Text,{color:"#F59E0B",bold:true},"\u25CF Tip "),i.createElement(Text,{color:"#4B5563"},c)))};var Kt=process.env.HOME||process.env.USERPROFILE||"";function Xo(r){try{return execSync("git rev-parse --abbrev-ref HEAD",{cwd:r,stdio:["ignore","pipe","ignore"],timeout:800}).toString().trim()}catch{return ""}}var Go={idle:"",running:"#1D4ED8",thinking:"#92400E",error:"#7F1D1D"},Zt={idle:"",running:"RUNNING",thinking:"THINKING",error:"ERROR"},wt=({config:r,cwd:e,agentStatus:o,tokenCount:t,mode:n="build"})=>{let s=useRef(""),l=useRef("");l.current!==e&&(l.current=e,s.current=Xo(e));let c=e.startsWith(Kt)?e.replace(Kt,"~"):e,a=s.current;return i.createElement(Box,{justifyContent:"space-between"},i.createElement(Box,null,i.createElement(Text,{bold:true,color:"#60A5FA"},"localcode "),i.createElement(Text,{color:"#374151"},"v0.1.0 "),i.createElement(Text,{color:"#6B7280"},c),a&&i.createElement(Text,{color:"#4B5563"}," (",a,")"),t>0&&i.createElement(Text,{color:"#374151"}," ~",t,"t")),i.createElement(Box,null,Zt[o]&&i.createElement(Text,{backgroundColor:Go[o],color:"#BFDBFE"}," ",Zt[o]," "),i.createElement(Text,{color:"#374151"}," tab "),i.createElement(Text,{backgroundColor:n==="plan"?"#166534":"#1D4ED8",color:n==="plan"?"#86EFAC":"#BFDBFE"}," ",n==="plan"?"PLAN MODE":"BUILD MODE"," ")))};var Rt=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],at=({label:r="Thinking"})=>{let[e,o]=useState(0);return useEffect(()=>{let t=setInterval(()=>o(n=>(n+1)%Rt.length),80);return ()=>clearInterval(t)},[]),i.createElement(Text,{color:"#3B82F6"},Rt[e]," ",r,"...")};var Ct=({filePath:r,oldLines:e,newLines:o,startLine:t,contextBefore:n,contextAfter:s})=>{let l=[],c=t-n.length;n.forEach((d,p)=>{let y=c+p;l.push({type:"context",content:d,left:y,right:y});});let a=t,u=t;return e.forEach(d=>l.push({type:"removed",content:d,left:a++,right:null})),o.forEach(d=>l.push({type:"added",content:d,left:null,right:u++})),s.forEach((d,p)=>l.push({type:"context",content:d,left:a+p,right:u+p})),i.createElement(Box,{flexDirection:"column",marginY:1,marginX:1},i.createElement(Box,{paddingX:2,paddingY:0},i.createElement(Text,{color:"#6B7280"},"Edit "),i.createElement(Text,{color:"#9CA3AF"},r)),i.createElement(Box,{flexDirection:"column",borderStyle:"single",borderColor:"#374151"},l.map((d,p)=>{let y=d.left!==null?String(d.left).padStart(4):" ",x=d.right!==null?String(d.right).padStart(4):" ";return d.type==="removed"?i.createElement(Box,{key:p},i.createElement(Text,{color:"#EF4444"}," ",y," "),i.createElement(Text,{color:"#374151"}," "),i.createElement(Text,{color:"#EF4444"}," - "),i.createElement(Text,{color:"#FCA5A5"},d.content)):d.type==="added"?i.createElement(Box,{key:p},i.createElement(Text,{color:"#374151"}," "),i.createElement(Text,{color:"#22C55E"}," ",x," "),i.createElement(Text,{color:"#22C55E"}," + "),i.createElement(Text,{color:"#86EFAC"},d.content)):i.createElement(Box,{key:p},i.createElement(Text,{color:"#4B5563"}," ",y," "),i.createElement(Text,{color:"#4B5563"}," ",x," "),i.createElement(Text,{color:"#374151"}," "),i.createElement(Text,{color:"#6B7280"},d.content))})))};var At=({text:r})=>{let e=[],o=r;for(;o;){let t=o.match(/^`([^`]*)`/);if(t){e.push({t:t[1],code:true}),o=o.slice(t[0].length);continue}let n=o.match(/^\*\*([^*]+)\*\*/);if(n){e.push({t:n[1],bold:true}),o=o.slice(n[0].length);continue}let s=o.match(/^\*([^*]+)\*/);if(s){e.push({t:s[1],italic:true}),o=o.slice(s[0].length);continue}let l=o.search(/`|\*\*|\*(?!\*)/);if(l===-1){e.push({t:o});break}if(l===0){e.push({t:o[0]}),o=o.slice(1);continue}e.push({t:o.slice(0,l)}),o=o.slice(l);}return i.createElement(i.Fragment,null,e.map((t,n)=>t.code?i.createElement(Text,{key:n,color:"#7DD3FC"},t.t):t.bold?i.createElement(Text,{key:n,bold:true,color:"#E5E7EB"},t.t):t.italic?i.createElement(Text,{key:n,color:"#D1D5DB",italic:true},t.t):i.createElement(Text,{key:n,color:"#D1D5DB"},t.t)))},Bt=({content:r})=>{let e=r.split(`
128
+ `),o=[],t=false,n="",s=[],l=c=>{o.push(i.createElement(Box,{key:c,flexDirection:"column"},n&&i.createElement(Box,null,i.createElement(Text,{color:"#1D4ED8"}," \u250C\u2500 "),i.createElement(Text,{color:"#60A5FA"},n)),s.map((a,u)=>i.createElement(Box,{key:u},i.createElement(Text,{color:"#374151"}," \u2502 "),i.createElement(Text,{color:"#7DD3FC",wrap:"wrap"},a||" "))),i.createElement(Text,{color:"#1D4ED8"}," \u2514","\u2500".repeat(Math.min(40,Math.max(8,...s.map(a=>a.length+1))))))),s=[],n="";};for(let c=0;c<e.length;c++){let a=e[c];if(a.startsWith("```")){t?(t=false,l(`c${c}`)):(t=true,n=a.slice(3).trim());continue}if(t){s.push(a);continue}if(a.startsWith("### "))o.push(i.createElement(Text,{key:c,bold:true,color:"#93C5FD",wrap:"wrap"},a.slice(4)));else if(a.startsWith("## "))o.push(i.createElement(Text,{key:c,bold:true,color:"#60A5FA",wrap:"wrap"},a.slice(3)));else if(a.startsWith("# "))o.push(i.createElement(Text,{key:c,bold:true,color:"#3B82F6",wrap:"wrap"},a.slice(2)));else if(/^[-*+] /.test(a))o.push(i.createElement(Box,{key:c},i.createElement(Text,{color:"#6B7280"}," \u2022 "),i.createElement(Box,{flexWrap:"wrap"},i.createElement(At,{text:a.slice(2)}))));else if(/^\d+\. /.test(a)){let u=a.match(/^(\d+)\. (.*)/);o.push(i.createElement(Box,{key:c},i.createElement(Text,{color:"#6B7280"}," ",u[1],". "),i.createElement(Box,{flexWrap:"wrap"},i.createElement(At,{text:u[2]}))));}else /^---+$/.test(a.trim())?o.push(i.createElement(Text,{key:c,color:"#374151"},"\u2500".repeat(48))):a.trim()?o.push(i.createElement(Box,{key:c,flexWrap:"wrap"},i.createElement(At,{text:a}))):o.push(i.createElement(Text,{key:c}," "));}return t&&s.length&&l("end"),i.createElement(Box,{flexDirection:"column"},o)};var eo=[{id:"ollama",label:"Ollama",defaultPort:"11434",urlSuffix:""},{id:"lmstudio",label:"LM Studio",defaultPort:"1234",urlSuffix:"/v1"}],to=({onConnect:r,onCancel:e})=>{let[o,t]=useState("provider"),[n,s]=useState(""),[l,c]=useState(0),[a,u]=useState(eo[0]),[d,p]=useState("localhost"),[y,x]=useState("11434"),S=eo.filter(T=>T.label.toLowerCase().includes(n.toLowerCase())||T.id.toLowerCase().includes(n.toLowerCase()));useInput((T,$)=>{if(o==="provider"){if($.upArrow){c(b=>Math.max(0,b-1));return}if($.downArrow){c(b=>Math.min(S.length-1,b+1));return}if($.escape){e();return}if($.return){let b=S[Math.min(l,S.length-1)];if(!b)return;u(b),p("localhost"),x(b.defaultPort),t("ip");return}}if(o==="ip"){if($.escape){t("provider");return}if($.return){t("port");return}}if(o==="port"){if($.escape){t("ip");return}if($.return){let b=a.id,J=`http://${d}:${y}${a.urlSuffix}`;r(b,J);return}}});let G=o==="provider"?"\u203A Choose provider":o==="ip"?`\u203A ${a.label} \u203A IP address`:`\u203A ${a.label} \u203A Port`;return i.createElement(Box,{flexDirection:"column",borderStyle:"round",borderColor:"#3B82F6",marginX:1},i.createElement(Box,{paddingX:2},i.createElement(Text,{color:"#3B82F6",bold:true}," Connect "),i.createElement(Text,{color:"#4B5563"},G)),o==="provider"&&i.createElement(i.Fragment,null,i.createElement(Box,{paddingX:2,borderStyle:"single",borderTop:true,borderColor:"#1E3A5F"},i.createElement(Text,{color:"#6B7280"},"/ "),i.createElement(Lt,{value:n,onChange:T=>{s(T),c(0);},placeholder:"Search provider ...",focus:true})),S.length===0?i.createElement(Box,{paddingX:4},i.createElement(Text,{color:"#6B7280"},"No provider found")):S.map((T,$)=>{let b=$===l;return i.createElement(Box,{key:T.id,paddingX:2},i.createElement(Text,{color:b?"#3B82F6":"#374151"},b?"\u25B6 ":" "),i.createElement(Text,{color:b?"#93C5FD":"#9CA3AF",bold:b},T.label),i.createElement(Text,{color:b?"#4B5563":"#2D3748"}," :",T.defaultPort))})),o==="ip"&&i.createElement(Box,{paddingX:2,paddingY:1,flexDirection:"column"},i.createElement(Text,{color:"#6B7280"},"IP address:"),i.createElement(Box,{marginTop:1,borderStyle:"single",borderColor:"#1E3A5F",paddingX:1},i.createElement(Lt,{value:d,onChange:p,focus:true}))),o==="port"&&i.createElement(Box,{paddingX:2,paddingY:1,flexDirection:"column"},i.createElement(Text,{color:"#6B7280"},"Port:"),i.createElement(Box,{marginTop:1,borderStyle:"single",borderColor:"#1E3A5F",paddingX:1},i.createElement(Lt,{value:y,onChange:x,focus:true}))),i.createElement(Box,{paddingX:2,borderStyle:"single",borderTop:true,borderColor:"#1E3A5F"},o==="provider"?i.createElement(i.Fragment,null,i.createElement(Text,{color:"#374151"},"\u2191\u2193 "),i.createElement(Text,{color:"#4B5563"},"select "),i.createElement(Text,{color:"#374151"},"enter "),i.createElement(Text,{color:"#4B5563"},"next "),i.createElement(Text,{color:"#374151"},"esc "),i.createElement(Text,{color:"#4B5563"},"close")):o==="ip"?i.createElement(i.Fragment,null,i.createElement(Text,{color:"#374151"},"enter "),i.createElement(Text,{color:"#4B5563"},"next "),i.createElement(Text,{color:"#374151"},"esc "),i.createElement(Text,{color:"#4B5563"},"back")):i.createElement(i.Fragment,null,i.createElement(Text,{color:"#22C55E"},"enter "),i.createElement(Text,{color:"#4B5563"},"connect "),i.createElement(Text,{color:"#374151"},"esc "),i.createElement(Text,{color:"#4B5563"},"back"))))};var ro=({models:r,loading:e,currentModel:o,onSelect:t,onCancel:n})=>{let[s,l]=useState(""),[c,a]=useState(0),u=r.filter(p=>p.toLowerCase().includes(s.toLowerCase()));useInput((p,y)=>{if(e){if(y.escape){n();return}return}if(y.upArrow){a(x=>Math.max(0,x-1));return}if(y.downArrow){a(x=>Math.min(u.length-1,x+1));return}if(y.escape){n();return}if(y.return){let x=u[Math.min(c,u.length-1)];x&&t(x);return}});let d=u.slice(0,8);return i.createElement(Box,{flexDirection:"column",borderStyle:"round",borderColor:"#6366F1",marginX:1},i.createElement(Box,{paddingX:2},i.createElement(Text,{color:"#6366F1",bold:true}," Model "),i.createElement(Text,{color:"#4B5563"},"\u203A Select a model "),i.createElement(Text,{color:"#374151"},"current: "),i.createElement(Text,{color:"#9CA3AF"},o)),i.createElement(Box,{paddingX:2,borderStyle:"single",borderTop:true,borderColor:"#312E81"},i.createElement(Text,{color:"#6B7280"},"/ "),i.createElement(Lt,{value:s,onChange:p=>{l(p),a(0);},placeholder:"Search model ...",focus:!e})),e?i.createElement(Box,{paddingX:4,paddingY:1},i.createElement(Text,{color:"#6B7280"},"Loading models from server ...")):d.length===0?i.createElement(Box,{paddingX:4,paddingY:1},i.createElement(Text,{color:"#6B7280"},r.length===0?"No models found \u2014 is the server reachable?":"No matches")):d.map((p,y)=>{let x=y===c;return i.createElement(Box,{key:p,paddingX:2},i.createElement(Text,{color:x?"#6366F1":"#374151"},x?"\u25B6 ":" "),p===o?i.createElement(Text,{color:x?"#A5B4FC":"#6366F1",bold:true},"\u2713 ",p):i.createElement(Text,{color:x?"#A5B4FC":"#9CA3AF"}," ",p))}),u.length>8&&i.createElement(Box,{paddingX:4},i.createElement(Text,{color:"#374151"},"\u2026 ",u.length-8," more (refine search)")),i.createElement(Box,{paddingX:2,borderStyle:"single",borderTop:true,borderColor:"#312E81"},i.createElement(Text,{color:"#374151"},"\u2191\u2193 "),i.createElement(Text,{color:"#4B5563"},"select "),i.createElement(Text,{color:"#374151"},"enter "),i.createElement(Text,{color:"#4B5563"},"apply "),i.createElement(Text,{color:"#374151"},"esc "),i.createElement(Text,{color:"#4B5563"},"close")))};var tr=new Set([".jpg",".jpeg",".png",".gif",".webp",".bmp",".svg"]),so=({files:r,onSelect:e,onCancel:o})=>{let[t,n]=useState(""),[s,l]=useState(0),c=r.filter(a=>a.toLowerCase().includes(t.toLowerCase())).slice(0,8);return useInput((a,u)=>{if(u.upArrow){l(d=>Math.max(0,d-1));return}if(u.downArrow){l(d=>Math.min(c.length-1,d+1));return}if(u.escape){o();return}if(u.return){let d=c[Math.min(s,c.length-1)];d&&e(d);return}}),i.createElement(Box,{flexDirection:"column",borderStyle:"round",borderColor:"#22C55E",marginX:1},i.createElement(Box,{paddingX:2},i.createElement(Text,{color:"#22C55E",bold:true}," @ Attach "),i.createElement(Text,{color:"#4B5563"},"\u203A Datei oder Bild ausw\xE4hlen")),i.createElement(Box,{paddingX:2,borderStyle:"single",borderTop:true,borderColor:"#15803D"},i.createElement(Text,{color:"#6B7280"},"/ "),i.createElement(Lt,{value:t,onChange:a=>{n(a),l(0);},placeholder:"Search file...",focus:true})),c.length===0?i.createElement(Box,{paddingX:4,paddingY:1},i.createElement(Text,{color:"#6B7280"},"No files found")):c.map((a,u)=>{let d=u===s,p=tr.has(extname(a).toLowerCase());return i.createElement(Box,{key:a,paddingX:2},i.createElement(Text,{color:d?"#22C55E":"#374151"},d?"\u25B6 ":" "),i.createElement(Text,{color:d?"#86EFAC":"#9CA3AF"},p?"[img] ":"[file] ",a))}),i.createElement(Box,{paddingX:2,borderStyle:"single",borderTop:true,borderColor:"#15803D"},i.createElement(Text,{color:"#374151"},"\u2191\u2193 "),i.createElement(Text,{color:"#4B5563"},"select "),i.createElement(Text,{color:"#374151"},"enter "),i.createElement(Text,{color:"#4B5563"},"attach "),i.createElement(Text,{color:"#374151"},"esc "),i.createElement(Text,{color:"#4B5563"},"close")))};var ct=class{async stream(e,o,t){let n=o.baseURL||"http://localhost:11434",s="",l=await fetch(`${n}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:o.model||"deepseek-coder",messages:e.map(u=>{let d={role:u.role,content:u.content};return u.images?.length&&(d.images=u.images),d}),stream:true,options:{temperature:o.temperature??.1,num_predict:o.maxTokens??8192}})});if(!l.ok){let u=await l.text();throw new Error(`Ollama error ${l.status}: ${u}`)}let c=l.body.getReader(),a=new TextDecoder;for(;;){let{done:u,value:d}=await c.read();if(u)break;let p=a.decode(d,{stream:true});for(let y of p.split(`
129
+ `).filter(x=>x.trim()))try{let x=JSON.parse(y),S=x.message?.content||"";if(S&&(t(S),s+=S),x.done)return s}catch{}}return s}async listModels(e="http://localhost:11434"){try{let o=await fetch(`${e}/api/tags`,{signal:AbortSignal.timeout(5e3)});return o.ok?((await o.json()).models||[]).map(n=>n.name):[]}catch{return []}}async checkHealth(e="http://localhost:11434"){try{return (await fetch(`${e}/api/tags`,{signal:AbortSignal.timeout(3e3)})).ok}catch{return false}}};var $t="http://localhost:1234/v1",ut=class{async stream(e,o,t){let n=(o.baseURL||$t).replace(/\/$/,""),s="",l=await fetch(`${n}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:o.model,messages:e.map(d=>d.images?.length?{role:d.role,content:[{type:"text",text:d.content},...d.images.map(p=>({type:"image_url",image_url:{url:`data:image/png;base64,${p}`}}))]}:{role:d.role,content:d.content}),stream:true,temperature:o.temperature??.1,max_tokens:o.maxTokens??8192})});if(!l.ok){let d=await l.text();throw new Error(`LM Studio error ${l.status}: ${d}`)}let c=l.body.getReader(),a=new TextDecoder,u="";for(;;){let{done:d,value:p}=await c.read();if(d)break;u+=a.decode(p,{stream:true});let y=u.split(`
130
+ `);u=y.pop()||"";for(let x of y){if(!x.startsWith("data: "))continue;let S=x.slice(6).trim();if(S==="[DONE]")return s;try{let T=JSON.parse(S).choices?.[0]?.delta?.content;T&&(t(T),s+=T);}catch{}}}return s}async checkHealth(e){try{let o=(e||$t).replace(/\/$/,"");return (await fetch(`${o}/models`,{signal:AbortSignal.timeout(2e3)})).ok}catch{return false}}async listModels(e){try{let o=(e||$t).replace(/\/$/,""),t=await fetch(`${o}/models`,{signal:AbortSignal.timeout(3e3)});return t.ok?((await t.json()).data??[]).map(s=>s.id):[]}catch{return []}}};var io=new ct,lo=new ut,oe=class{static async stream(e,o,t){switch(o.provider){case "ollama":return io.stream(e,o,t);case "lmstudio":return lo.stream(e,o,t);default:throw new Error(`Unknown provider: ${o.provider}. Use "ollama" or "lmstudio".`)}}static getOllamaProvider(){return io}static getLMStudioProvider(){return lo}};var Qe=promisify(exec);async function dt(r,e){let o=e?resolve(r,e):void 0;return existsSync(join(r,"tsconfig.json"))?sr(r,o):existsSync(join(r,"Cargo.toml"))?ir(r):existsSync(join(r,"go.mod"))?lr(r,o):existsSync(join(r,"pyproject.toml"))||existsSync(join(r,"setup.py"))||existsSync(join(r,"requirements.txt"))?ar(r,o):existsSync(join(r,".eslintrc.js"))||existsSync(join(r,".eslintrc.cjs"))||existsSync(join(r,".eslintrc.json"))||existsSync(join(r,".eslintrc.yml"))?cr(r,o):{diagnostics:[],tool:"none",error:"No supported project detected (tsconfig.json, Cargo.toml, go.mod, setup.py, .eslintrc)"}}async function sr(r,e){try{let o=e?`"${e}"`:"",{stdout:t}=await Qe(`npx --yes tsc --noEmit --pretty false ${o} 2>&1 || true`,{cwd:r,timeout:3e4});return {diagnostics:ur(t),tool:"tsc"}}catch(o){return {diagnostics:[],tool:"tsc",error:String(o)}}}async function ir(r){try{let{stdout:e,stderr:o}=await Qe("cargo check --message-format short 2>&1 || true",{cwd:r,timeout:6e4});return {diagnostics:dr(e+o),tool:"cargo check"}}catch(e){return {diagnostics:[],tool:"cargo check",error:String(e)}}}async function lr(r,e){try{let o=e?`"${e}"`:"./...",{stdout:t,stderr:n}=await Qe(`go vet ${o} 2>&1 || true`,{cwd:r,timeout:3e4});return {diagnostics:mr(t+n),tool:"go vet"}}catch(o){return {diagnostics:[],tool:"go vet",error:String(o)}}}async function ar(r,e){try{let o=e?`"${e}"`:".",{stdout:t,stderr:n}=await Qe(`python -m pyflakes ${o} 2>&1 || true`,{cwd:r,timeout:15e3});return {diagnostics:pr(t+n),tool:"pyflakes"}}catch(o){return {diagnostics:[],tool:"pyflakes",error:String(o)}}}async function cr(r,e){try{let o=e?`"${e}"`:".",{stdout:t}=await Qe(`npx --yes eslint --format json ${o} 2>/dev/null || true`,{cwd:r,timeout:2e4});return {diagnostics:fr(t),tool:"eslint"}}catch(o){return {diagnostics:[],tool:"eslint",error:String(o)}}}function ur(r){let e=[],o=/^(.+)\((\d+),(\d+)\):\s+(error|warning|info)\s+TS\d+:\s+(.+)$/gm,t;for(;(t=o.exec(r))!==null;)e.push({file:t[1].trim(),line:+t[2],col:+t[3],severity:t[4],message:t[5].trim()});return e}function dr(r){let e=[],o=/^(.+):(\d+):(\d+):\s+(error|warning|note)\[?[^\]]*\]?:\s+(.+)$/gm,t;for(;(t=o.exec(r))!==null;)e.push({file:t[1].trim(),line:+t[2],col:+t[3],severity:t[4]==="note"?"info":t[4],message:t[5].trim()});return e}function mr(r){let e=[],o=/^(.+):(\d+):(\d+):\s+(.+)$/gm,t;for(;(t=o.exec(r))!==null;)e.push({file:t[1].trim(),line:+t[2],col:+t[3],severity:"error",message:t[4].trim()});return e}function pr(r){let e=[],o=/^(.+):(\d+):(\d+):\s+(.+)$/gm,t;for(;(t=o.exec(r))!==null;)e.push({file:t[1].trim(),line:+t[2],col:+t[3],severity:"error",message:t[4].trim()});return e}function fr(r){let e=[];try{let o=JSON.parse(r);for(let t of o)for(let n of t.messages??[])e.push({file:t.filePath,line:n.line,col:n.column,severity:n.severity===2?"error":"warning",message:n.message,code:n.ruleId??void 0});}catch{}return e}var mt=createRequire(import.meta.url),ge=join(Ht.homedir(),".localcode","plugins"),he=class r{static _inst;_plugins=[];_errors=[];_loaded=false;static getInstance(){return r._inst||(r._inst=new r),r._inst}getPluginDir(){return ge}load(){if(this._loaded||(this._loaded=true,!existsSync(ge)))return;let e;try{e=readdirSync(ge);}catch{return}for(let o of e){let t=join(ge,o),n=null;try{if(statSync(t).isDirectory()){let s=join(t,"index.js"),l=join(t,"index.cjs");n=existsSync(s)?s:existsSync(l)?l:null;}else (o.endsWith(".js")||o.endsWith(".cjs"))&&(n=t);}catch{continue}if(n)try{let s=mt(n),l=s.default??s;l&&typeof l.name=="string"&&l.name?this._plugins.push(l):this._errors.push({file:n,error:'Missing or invalid "name" field'});}catch(s){this._errors.push({file:n,error:String(s)});}}}reload(){for(let e of Object.keys(mt.cache??{}))e.startsWith(ge)&&delete mt.cache[e];this._loaded=false,this._plugins=[],this._errors=[],this.load();}getAll(){return this._plugins}getErrors(){return this._errors}getCommands(){return this._plugins.flatMap(e=>e.commands??[])}getTools(){return this._plugins.flatMap(e=>e.tools??[])}getTool(e){return this.getTools().find(o=>o.name===e)}async install(e){let o=resolve(e);if(!existsSync(o))return {ok:false,error:`Not found: ${o}`};let t=statSync(o).isDirectory(),n=t?existsSync(join(o,"index.js"))?join(o,"index.js"):join(o,"index.cjs"):o;if(!existsSync(n))return {ok:false,error:"No index.js / index.cjs found in directory"};let s;try{let l=mt(n);s=l.default??l;}catch(l){return {ok:false,error:`Failed to load plugin: ${String(l)}`}}if(!s?.name)return {ok:false,error:'Plugin must export a "name" field'};try{await mkdir(ge,{recursive:!0});let l=join(ge,s.name);t?(existsSync(l)&&await rm(l,{recursive:!0,force:!0}),cpSync(o,l,{recursive:!0})):(await mkdir(l,{recursive:!0}),await copyFile(o,join(l,"index.js")));}catch(l){return {ok:false,error:`Copy failed: ${String(l)}`}}return this.reload(),{ok:true,name:s.name}}async remove(e){let o=join(ge,e),t=join(ge,`${e}.js`);if(existsSync(o))await rm(o,{recursive:true,force:true});else if(existsSync(t))await rm(t,{force:true});else return {ok:false,error:`Plugin "${e}" not found in ${ge}`};return this.reload(),{ok:true}}};var xo=promisify(exec);function Br(){return (process.platform==="win32"?["C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe","C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",`${process.env.LOCALAPPDATA}\\Google\\Chrome\\Application\\chrome.exe`,`${process.env.LOCALAPPDATA}\\Chromium\\Application\\chrome.exe`,"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",`${process.env.LOCALAPPDATA}\\Microsoft\\Edge\\Application\\msedge.exe`]:process.platform==="darwin"?["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/Applications/Chromium.app/Contents/MacOS/Chromium","/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"]:["/usr/bin/google-chrome","/usr/bin/chromium-browser","/usr/bin/chromium","/usr/bin/microsoft-edge"]).find(e=>existsSync(e))??null}async function yo(r,e){let{tool:o,arguments:t}=r;try{switch(o){case "run_shell":return De(String(t.command||""),String(t.cwd||e));case "read_file":return Lr(String(t.path||""),e);case "write_file":return $r(String(t.path||""),String(t.content||""),e);case "append_file":return Er(String(t.path||""),String(t.content||""),e);case "edit_file":return Pr(String(t.path||""),String(t.old||""),String(t.new||""),e);case "delete_file":return Mr(String(t.path||""),e,!!t.recursive);case "move_file":return Dr(String(t.from||""),String(t.to||""),e);case "copy_file":return Fr(String(t.from||""),String(t.to||""),e);case "create_dir":return Or(String(t.path||""),e);case "list_files":return kr(String(t.path||"."),e,!!t.recursive);case "find_files":return Ir(String(t.pattern||""),String(t.path||"."),e);case "search_files":return _r(String(t.pattern||""),String(t.path||"."),e);case "git_status":return De("git status",e);case "git_diff":return De(t.staged?"git diff --staged":"git diff",e);case "git_log":return De(`git log --oneline -${Number(t.limit)||20}`,e);case "git_commit":return De(`git add -A && git commit -m ${JSON.stringify(String(t.message||"chore: update"))}`,e);case "web_fetch":return Nr(String(t.url||""),String(t.format||"text"));case "http_request":return jr(String(t.method||"GET"),String(t.url||""),t.headers,t.body);case "lsp_check":return Ur(String(t.path||"."),e);default:{let n=he.getInstance().getTool(o);return n?n.handler(t,{cwd:e}):{success:!1,output:"",error:`Unknown tool: ${o}`}}}}catch(n){return {success:false,output:"",error:String(n)}}}async function De(r,e){try{let o=process.platform==="win32",{stdout:t,stderr:n}=await xo(r,{cwd:e,timeout:6e4,maxBuffer:1024*1024*10,shell:o?"cmd.exe":"/bin/sh"});return {success:!0,output:(t+(n?`
131
+ STDERR:
132
+ ${n}`:"")).trim()||"(no output)"}}catch(o){let t=o;return {success:false,output:t.stdout||"",error:t.stderr||t.message||String(o)}}}async function Lr(r,e){let o=resolve(e,r),s=(await readFile(o,"utf-8")).split(`
133
+ `).map((l,c)=>`${String(c+1).padStart(4)} \u2502 ${l}`).join(`
134
+ `);return {success:true,output:`// ${o}
135
+ ${s}`}}async function $r(r,e,o){let t=resolve(o,r),n=dirname(t);return existsSync(n)||await mkdir(n,{recursive:true}),await writeFile(t,e,"utf-8"),{success:true,output:`Written: ${t} (${e.length} chars, ${e.split(`
136
+ `).length} lines)`}}async function Pr(r,e,o,t){let n=resolve(t,r),s=await readFile(n,"utf-8");if(!s.includes(e))return {success:false,output:"",error:`Pattern not found in ${r}. Check for exact whitespace and line endings.`};let l=s.indexOf(e),c=s.slice(0,l).split(`
137
+ `).length,a=s.split(`
138
+ `),u=e.split(`
139
+ `),d=3,p=a.slice(Math.max(0,c-1-d),c-1),y=a.slice(c-1+u.length,c-1+u.length+d);return await writeFile(n,s.replace(e,o),"utf-8"),{success:true,output:`Edited: ${n}`,meta:{diffPath:r,diffOld:u,diffNew:o.split(`
140
+ `),diffStartLine:c,diffContextBefore:p,diffContextAfter:y}}}async function kr(r,e,o){let t=resolve(e,r),n=new Set(["node_modules","dist",".git","__pycache__","target",".next","build","AppData","appdata",".cache","cache","Cache","Temp","temp","tmp","OneDrive","OneDriveConsumer","Pictures","Videos","Music",".npm",".yarn",".pnpm-store","venv",".venv","env"]),s=4,l=300,c=0;async function a(d,p="",y=0){if(y>s||c>=l)return [];let x;try{x=await readdir(d,{withFileTypes:!0});}catch{return [`${p}(permission denied)`]}let S=[];for(let G of x){if(c>=l){S.push(`${p}\u2026 (limit reached)`);break}let T=G.isDirectory();if(n.has(G.name)){T&&S.push(`${p}${G.name}/ (skipped)`);continue}if(S.push(`${p}${G.name}${T?"/":""}`),c++,T&&o&&y<s){let $=await a(join(d,G.name),`${p} `,y+1);S.push(...$);}}return S}return {success:true,output:(await a(t)).join(`
141
+ `)||"(empty directory)"}}async function _r(r,e,o){let t=resolve(o,e);if(process.platform==="win32"){let c=`findstr /s /n /i /r "${r}" "${t}\\*.ts" "${t}\\*.tsx" "${t}\\*.js" "${t}\\*.jsx" "${t}\\*.py" "${t}\\*.go" "${t}\\*.json" "${t}\\*.md" 2>nul`;return De(c,o)}let l=`grep -rn ${["ts","tsx","js","jsx","py","go","rs","java","cs","cpp","c","h","json","yaml","yml","md"].map(c=>`--include="*.${c}"`).join(" ")} "${r}" "${t}" 2>/dev/null | head -60`;return De(l,o)}async function Er(r,e,o){let t=resolve(o,r),n=dirname(t);return existsSync(n)||await mkdir(n,{recursive:true}),await appendFile(t,e,"utf-8"),{success:true,output:`Appended ${e.length} chars to ${t}`}}async function Mr(r,e,o){let t=resolve(e,r);return await rm(t,{recursive:o,force:true}),{success:true,output:`Deleted: ${t}`}}async function Dr(r,e,o){let t=resolve(o,r),n=resolve(o,e),s=dirname(n);return existsSync(s)||await mkdir(s,{recursive:true}),await rename(t,n),{success:true,output:`Moved: ${t} \u2192 ${n}`}}async function Fr(r,e,o){let t=resolve(o,r),n=resolve(o,e),s=dirname(n);return existsSync(s)||await mkdir(s,{recursive:true}),await copyFile(t,n),{success:true,output:`Copied: ${t} \u2192 ${n}`}}async function Or(r,e){let o=resolve(e,r);return await mkdir(o,{recursive:true}),{success:true,output:`Created directory: ${o}`}}async function Ir(r,e,o){let t=resolve(o,e);process.platform==="win32";let s=new Set(["node_modules",".git","dist","__pycache__",".next","build","target"]),l=[],c=new RegExp("^"+r.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".")+"$","i");async function a(u){if(l.length>=200)return;let d;try{d=await readdir(u,{withFileTypes:!0});}catch{return}for(let p of d){if(s.has(p.name))continue;let y=join(u,p.name);p.isDirectory()?await a(y):c.test(p.name)&&l.push(y);}}return await a(t),{success:true,output:l.join(`
142
+ `)||"No files found."}}async function Nr(r,e){if(/^[A-Za-z]:[\\\/]/.test(r)||/^\/[^\s]/.test(r)||r.startsWith("file://"))return {success:false,output:"",error:`"${r}" is a local path. Use read_file to read local files.`};if(!r.startsWith("http://")&&!r.startsWith("https://"))return {success:false,output:"",error:"URL must start with http:// or https://"};let t=Br(),n=join(Ht.tmpdir(),`localcode_web_${Date.now()}.png`);if(t)try{let l=["--headless=new","--disable-gpu","--no-sandbox","--disable-dev-shm-usage",`--screenshot="${n}"`,"--window-size=1280,900","--hide-scrollbars",`"${r}"`].join(" ");await xo(`"${t}" ${l}`,{timeout:2e4});let a=(await readFile(n)).toString("base64");await unlink(n).catch(()=>{});let{text:u}=await po(r);return {success:!0,output:`[screenshot taken] ${r}
143
+
144
+ ${u.slice(0,8e3)}`,images:[a]}}catch{await unlink(n).catch(()=>{});}let{text:s}=await po(r);return {success:true,output:`[no browser found \u2014 text only] ${r}
145
+
146
+ ${s.slice(0,2e4)}`}}async function po(r){let e=await fetch(r,{headers:{"User-Agent":"Mozilla/5.0 (compatible; LocalCode/1.0)"},signal:AbortSignal.timeout(15e3)}),o=e.headers.get("content-type")||"";if(o.startsWith("image/")){let n=await e.arrayBuffer();return {text:`[image: ${r}]`,imageB64:Buffer.from(n).toString("base64")}}let t=await e.text();if(o.includes("application/json"))try{return {text:JSON.stringify(JSON.parse(t),null,2)}}catch{}return {text:t.replace(/<script[\s\S]*?<\/script>/gi,"").replace(/<style[\s\S]*?<\/style>/gi,"").replace(/<[^>]+>/g," ").replace(/&amp;/g,"&").replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&quot;/g,'"').replace(/&#39;/g,"'").replace(/&nbsp;/g," ").replace(/[ \t]{2,}/g," ").replace(/\n{3,}/g,`
147
+
148
+ `).trim()}}async function jr(r,e,o,t){if(!e.startsWith("http://")&&!e.startsWith("https://"))return {success:false,output:"",error:"URL must start with http:// or https://"};let n={method:r.toUpperCase(),headers:{"Content-Type":"application/json",...o},signal:AbortSignal.timeout(15e3)};t!==void 0&&r.toUpperCase()!=="GET"&&(n.body=typeof t=="string"?t:JSON.stringify(t));let s=await fetch(e,n),l=await s.text(),c;try{c=JSON.stringify(JSON.parse(l),null,2);}catch{c=l;}return {success:s.ok,output:`HTTP ${s.status} ${s.statusText}
149
+
150
+ ${c.slice(0,1e4)}`,error:s.ok?void 0:`HTTP ${s.status}`}}async function Ur(r,e){let o=r==="."?void 0:resolve(e,r),{diagnostics:t,tool:n,error:s}=await dt(e,o);if(s&&t.length===0)return {success:false,output:"",error:s};if(t.length===0)return {success:true,output:`\u2713 No issues found (${n})`};let l=t.filter(u=>u.severity==="error").length,c=t.filter(u=>u.severity==="warning").length,a=[`${n}: ${l} error${l!==1?"s":""}, ${c} warning${c!==1?"s":""}`,"",...t.slice(0,60).map(u=>`${u.file}:${u.line}:${u.col} ${u.severity} ${u.message}${u.code?` [${u.code}]`:""}`)];return t.length>60&&a.push(`\u2026 and ${t.length-60} more`),{success:l===0,output:a.join(`
151
+ `),error:l>0?`${l} error(s)`:void 0}}var Fe=Pe.join(Ht.homedir(),".localcode"),ft=Pe.join(Fe,"config.json"),Et=Pe.join(Fe,"history.json"),Ge=Pe.join(Fe,"sessions"),ke=class r{static instance;config;constructor(){this.config=this.load();}static getInstance(){return r.instance||(r.instance=new r),r.instance}load(){try{if(j.existsSync(Fe)||j.mkdirSync(Fe,{recursive:!0}),j.existsSync(ft)){let e=j.readFileSync(ft,"utf-8");return {...St,...JSON.parse(e)}}}catch{}return {...St}}get(){return this.config}set(e){this.config={...this.config,...e},this.save();}setLLM(e){this.config.llm={...this.config.llm,...e},this.save();}save(){try{j.existsSync(Fe)||j.mkdirSync(Fe,{recursive:!0}),j.writeFileSync(ft,JSON.stringify(this.config,null,2),"utf-8");}catch{}}getHistory(){try{if(j.existsSync(Et))return JSON.parse(j.readFileSync(Et,"utf-8"))}catch{}return []}addHistory(e){try{let o=this.getHistory(),t=[e,...o.filter(n=>n!==e)].slice(0,500);j.writeFileSync(Et,JSON.stringify(t),"utf-8");}catch{}}getConfigPath(){return ft}ensureSessions(){j.existsSync(Ge)||j.mkdirSync(Ge,{recursive:true});}listSessions(){try{return this.ensureSessions(),j.readdirSync(Ge).filter(e=>e.endsWith(".json")).map(e=>e.slice(0,-5)).sort()}catch{return []}}saveSession(e,o){try{this.ensureSessions();let t=Pe.join(Ge,`${e}.json`);j.writeFileSync(t,JSON.stringify(o,null,2),"utf-8");}catch{}}loadSession(e){try{let o=Pe.join(Ge,`${e}.json`);return j.existsSync(o)?JSON.parse(j.readFileSync(o,"utf-8")):null}catch{return null}}deleteSession(e){try{let o=Pe.join(Ge,`${e}.json`);j.existsSync(o)&&j.unlinkSync(o);}catch{}}};var Wr=[{pattern:/rm\s+-[rf]{1,3}\s+[/~]/i,reason:"Recursive deletion of system or home paths"},{pattern:/rm\s+--recursive.*--force/i,reason:"Force-recursive file deletion"},{pattern:/sudo\s+rm/i,reason:"Privileged file deletion via sudo"},{pattern:/:\(\)\s*\{.*\|.*\}/,reason:"Fork bomb \u2014 infinite process spawn"},{pattern:/\bshutdown\b/i,reason:"System shutdown command"},{pattern:/\breboot\b/i,reason:"System reboot command"},{pattern:/\bhalt\b/i,reason:"System halt command"},{pattern:/\bmkfs\b/i,reason:"Disk formatting command"},{pattern:/dd\s+if=.*of=\/dev/i,reason:"Direct disk write via dd"},{pattern:/git\s+push\s+.*--force/i,reason:"Force-push overwrites remote history"},{pattern:/git\s+reset\s+--hard\s+HEAD~\d+/i,reason:"Hard reset discards committed history"},{pattern:/DROP\s+(TABLE|DATABASE)/i,reason:"Destructive SQL operation (DROP)"},{pattern:/TRUNCATE\s+TABLE/i,reason:"Destructive SQL operation (TRUNCATE)"},{pattern:/rd\s+\/s\s+\/q/i,reason:"Recursive directory deletion (cmd.exe)"},{pattern:/rmdir\s+\/s/i,reason:"Recursive directory deletion (cmd.exe)"},{pattern:/del\s+.*\/[fFsS].*\/[qQ]/i,reason:"Force-delete all files (cmd.exe)"},{pattern:/format\s+[A-Za-z]:/i,reason:"Disk format command (Windows)"},{pattern:/Remove-Item\s+.*-Recurse\s+.*-Force/i,reason:"Force-recursive deletion (PowerShell)"},{pattern:/Remove-Item\s+.*-Force\s+.*-Recurse/i,reason:"Force-recursive deletion (PowerShell)"},{pattern:/Clear-Disk\b/i,reason:"Disk wipe command (PowerShell)"},{pattern:/Reset-ComputerMachinePassword\b/i,reason:"System credential reset (PowerShell)"}],Hr=[/git\s+push(?!\s+--dry-run)/i,/git\s+reset/i,/npm\s+publish/i,/docker\s+rm/i,/kubectl\s+delete/i,/terraform\s+destroy/i,/\bmkdir\b/i,/\btouch\b/i,/\bcp\b/i,/\bmv\b/i,/\brename\b/i,/\brm\b/i,/\brmdir\b/i],gt=class{static check(e){let o=e.trim();for(let{pattern:t,reason:n}of Wr)if(t.test(o))return {safe:false,reason:n};for(let t of Hr)if(t.test(o))return {safe:true,requiresConfirmation:true,reason:"This command may have irreversible effects"};return {safe:true}}};var zr=/^(hi|hey|hello|sup|yo|hallo|hej|ciao|howdy|how are you|what can you do|what are you|who are you|thanks|thank you|danke|ok|okay|cool|nice|great|good|yes|no|nope|yep|sure|help me|what\??)[\s!?.]*$/i,Yr=new Set(["read_file","list_files","find_files","search_files","git_status","git_diff","git_log","lsp_check"]),ht=class extends EventEmitter{aborted=false;confirmResolve=null;injectionQueue=[];abort(){this.aborted=true,this.confirmResolve?.(false),this.confirmResolve=null;}confirm(e){this.confirmResolve?.(e),this.confirmResolve=null;}inject(e){this.injectionQueue.push(e);}async run(e,o,t=[],n="build"){this.aborted=false;let s=ke.getInstance().get(),l=o||s.workspaceDir||Ht.homedir(),c=t.filter(T=>T.type==="file").map(T=>`<file path="${T.name}">
152
+ ${T.data}
153
+ </file>`).join(`
154
+ `),a=t.filter(T=>T.type==="image").map(T=>T.data),u=e,d=/https?:\/\/\S+/g,p=[...e.matchAll(d)];for(let T of p){let $=T[0].replace(/[.,;!?)]+$/,"");try{let b=await fetch($,{signal:AbortSignal.timeout(1e4)});if((b.headers.get("content-type")||"").startsWith("image/")){let Ae=await b.arrayBuffer();a.push(Buffer.from(Ae).toString("base64")),u=u.replace($,"[attached image]");}}catch{}}let y=c?`${c}
155
+
156
+ Task: ${u}
157
+
158
+ Working directory: ${l}`:`Task: ${u}
159
+
160
+ Working directory: ${l}`;if(zr.test(e.trim())&&!t.length){this.emit("thinking");let T="",$=[{role:"system",content:"You are LocalCode, a helpful AI coding agent. Reply concisely and directly. Do NOT call any tools. End your reply with DONE: <reply>."},{role:"user",content:e}];try{await oe.stream($,s.llm,b=>{this.emit("token",b),T+=b;});}catch(b){this.emit("error",Mt(b,s.llm)),this.emit("done",{response:""});return}this.emit("done",{response:T||"DONE: Hey! I'm LocalCode. Give me a coding task and I'll get to work."});return}if(n==="plan"){this.emit("thinking");let T="",$=[{role:"system",content:Gt},{role:"user",content:y,...a.length?{images:a}:{}}];try{await oe.stream($,s.llm,b=>{this.emit("token",b),T+=b;});}catch(b){this.emit("error",Mt(b,s.llm)),this.emit("done",{response:""});return}this.emit("done",{response:T});return}let x=he.getInstance().getTools(),S=x.length>0?`
161
+
162
+ ### Plugin Tools
163
+ `+x.map(T=>`- **${T.name}**: ${T.description}
164
+ {"tool": "${T.name}", "arguments": {}}`).join(`
165
+ `):"",G=[{role:"system",content:Xt+S},{role:"user",content:y,...a.length?{images:a}:{}}];this.emit("start",{instruction:e,cwd:l}),this.injectionQueue=[];for(let T=0;T<qt;T++){if(this.aborted){this.emit("done",{response:"Task aborted by user.",aborted:true});return}for(;this.injectionQueue.length>0;){let I=this.injectionQueue.shift();this.emit("injection",{message:I}),G.push({role:"user",content:`[User message during task]: ${I}`});}this.emit("thinking");let $="";try{await oe.stream(G,s.llm,I=>{this.emit("token",I),$+=I;});}catch(I){let le=Mt(I,s.llm);this.emit("error",le),this.emit("done",{response:""});return}G.push({role:"assistant",content:$});let b=Vr($);if(!b){let I=bo($);this.emit("done",{response:I});return}if(b.tool==="run_shell"){let I=String(b.arguments.command||""),le=gt.check(I);if(!le.safe){let ne={success:false,output:"",error:`Blocked: ${le.reason}`};this.emit("tool_call",{toolCall:b,blocked:true,reason:le.reason}),this.emit("tool_result",{toolCall:b,result:ne}),G.push({role:"user",content:`Command was blocked by security guard: ${le.reason}. Choose a safer approach.`});continue}}if(!Yr.has(b.tool)){let I;if(b.tool==="edit_file"){let xe=String(b.arguments.path||""),ye=String(b.arguments.old||""),Oe=String(b.arguments.new||"");try{let Ie=await readFile(resolve(l,xe),"utf-8");if(Ie.includes(ye)){let rt=Ie.indexOf(ye),_e=Ie.slice(0,rt).split(`
166
+ `).length,qe=Ie.split(`
167
+ `),Ee=ye.split(`
168
+ `),Me=3;I={filePath:xe,oldLines:Ee,newLines:Oe.split(`
169
+ `),startLine:_e,contextBefore:qe.slice(Math.max(0,_e-1-Me),_e-1),contextAfter:qe.slice(_e-1+Ee.length,_e-1+Ee.length+Me)};}}catch{}}let le=Jr(b);this.emit("confirm_required",{toolCall:b,reason:le,diffPreview:I});let{confirmed:ne,timedOut:Be}=await this.waitForConfirmation();if(!ne){let xe={success:false,output:"",error:Be?"Confirmation timed out":"Denied by user"};this.emit("tool_result",{toolCall:b,result:xe}),this.emit("done",{response:Be?"No response in 30 seconds \u2014 task stopped.":"Task stopped \u2014 action denied by user.",aborted:true});return}}this.emit("tool_call",{toolCall:b});let J=await yo(b,l);this.emit("tool_result",{toolCall:b,result:J});let Ae={role:"user",content:`Tool "${b.tool}" result:
170
+ ${J.success?J.output:`ERROR: ${J.error||"Unknown error"}`}`};if(G.push(Ae),$.includes("DONE:")){let I=bo($);if(I){this.emit("done",{response:I});return}}}this.emit("done",{response:"Reached maximum iteration limit."});}waitForConfirmation(){return new Promise(e=>{this.confirmResolve=o=>e({confirmed:o,timedOut:false}),setTimeout(()=>{this.confirmResolve&&(this.confirmResolve=null,e({confirmed:false,timedOut:true}));},3e4);})}};function Jr(r){let e=r.arguments;switch(r.tool){case "run_shell":return `Shell: ${String(e.command||"")}`;case "read_file":return `Read file: ${String(e.path||"")}`;case "write_file":return `Write file: ${String(e.path||"")}`;case "append_file":return `Append to file: ${String(e.path||"")}`;case "edit_file":return `Edit file: ${String(e.path||"")}`;case "delete_file":return `Delete: ${String(e.path||"")}`;case "move_file":return `Move: ${String(e.from||"")} \u2192 ${String(e.to||"")}`;case "copy_file":return `Copy: ${String(e.from||"")} \u2192 ${String(e.to||"")}`;case "create_dir":return `Create directory: ${String(e.path||"")}`;case "list_files":return `List files: ${String(e.path||".")}`;case "find_files":return `Find files: "${String(e.pattern||"")}" in ${String(e.path||".")}`;case "search_files":return `Search "${String(e.pattern||"")}" in ${String(e.path||".")}`;case "git_status":return "git status";case "git_diff":return "git diff";case "git_log":return `git log (last ${String(e.limit||20)})`;case "git_commit":return `git commit: ${String(e.message||"")}`;case "web_fetch":return `Fetch URL: ${String(e.url||"")}`;case "http_request":return `${String(e.method||"GET")} ${String(e.url||"")}`;case "lsp_check":return `LSP check: ${String(e.path||".")}`;default:return r.tool}}function bo(r){let e=r;e=e.replace(/```json[\s\S]*?```/gi,""),e=e.replace(/\{[\s\S]*?"tool"\s*:[\s\S]*?"arguments"\s*:[\s\S]*?\}/g,"");let o=e.match(/^([\s\S]+?)\s*DONE:\s*(?:<[^>]*>)?/i);if(o&&o[1].trim())return o[1].trim();let t=e.match(/DONE:\s*(?:<([^>]*)>|([\s\S]*))/);return t&&(e=(t[1]||t[2]||"").trim()),e.trim()}function Mt(r,e){let o=String(r),t=o.toLowerCase();return t.includes("fetch failed")||t.includes("econnrefused")||t.includes("econnreset")||t.includes("network")?e.provider==="ollama"?["Ollama is not reachable.",""," \u2022 Start Ollama: ollama serve"," \u2022 Pull model: ollama pull "+e.model," \u2022 URL: "+(e.baseURL||"http://localhost:11434"),""," Switch provider: /config provider lmstudio"].join(`
171
+ `):e.provider==="lmstudio"?["LM Studio is not reachable.",""," \u2022 Open LM Studio and start a Local Server"," \u2022 URL: "+(e.baseURL||"http://localhost:1234/v1"),""," Change URL: /config url http://localhost:1234/v1"].join(`
172
+ `):[`Connection failed (${e.provider}).`," Check URL: /config url <url>"].join(`
173
+ `):t.includes("model")&&(t.includes("not found")||t.includes("does not exist"))||t.includes("404")?[`Model "${e.model}" not found.`,""," \u2022 Switch model: /config model <name>"," \u2022 List models: /models"].join(`
174
+ `):o}function Vr(r){for(let e=0;e<r.length;e++){if(r[e]!=="{")continue;let o=0,t=false,n=false,s=e;for(;s<r.length;s++){let c=r[s];if(n){n=false;continue}if(c==="\\"&&t){n=true;continue}if(c==='"'){t=!t;continue}if(!t){if(c==="{")o++;else if(c==="}"&&(o--,o===0))break}}if(o!==0)continue;let l=r.slice(e,s+1);try{let c=JSON.parse(l);if(typeof c.tool=="string"&&c.arguments!==null&&typeof c.arguments=="object")return c}catch{}}return null}var xt=class extends EventEmitter{shell=null;_cwd;_alive=false;constructor(e,o){super(),this._cwd=e;let t=o||(process.platform==="win32"?"powershell.exe":process.platform==="darwin"?process.env.SHELL||"zsh":process.env.SHELL||"bash");try{let n=Oo("node-pty");this.shell=n.spawn(t,[],{name:"xterm-256color",cols:process.stdout.columns||80,rows:10,cwd:e,env:process.env}),this._alive=!0,this.shell.onData(s=>this.emit("data",s)),this.shell.onExit(({exitCode:s})=>{this._alive=!1,this.emit("exit",s);});}catch{}}write(e){this.shell?.write(e);}resize(e,o){try{this.shell?.resize(e,o);}catch{}}get cwd(){return this._cwd}isAlive(){return this._alive}kill(){try{this.shell?.kill();}catch{}this.shell=null,this._alive=false;}};var ln=new Set([".jpg",".jpeg",".png",".gif",".webp",".bmp",".svg"]),an=new Set(["node_modules",".git","dist","__pycache__",".next","build","target"]);async function yt(r,e){let o=resolve(e,r);if(!existsSync(o))return null;let t=basename(o),n=extname(o).toLowerCase();if(ln.has(n)){let l=await readFile(o),c=n===".png"?"image/png":n===".gif"?"image/gif":n===".webp"?"image/webp":"image/jpeg";return {path:o,name:t,type:"image",data:l.toString("base64"),mimeType:c}}let s=await readFile(o,"utf-8").catch(()=>null);return s===null?null:{path:o,name:t,type:"file",data:s}}async function cn(r,e=2){let o=[];async function t(n,s,l){if(l>e||o.length>300)return;let c;try{c=await readdir(n,{withFileTypes:!0});}catch{return}for(let a of c){if(an.has(a.name))continue;let u=s?`${s}/${a.name}`:a.name;a.isDirectory()?(o.push(u+"/"),await t(join(n,a.name),u,l+1)):o.push(u);}}return await t(r,"",0),o}var un=0,dn=()=>String(++un);function mn(r){let e=[],o=[],t=()=>{o.length>0&&(e.push({type:"agent",messages:o}),o=[]);};for(let n of r)n.type==="text"&&n.content.startsWith("> ")?(t(),e.push({type:"user",content:n.content.slice(2),timestamp:n.timestamp})):o.push(n);return t(),e}function Ot(r,e){return r.split(`
175
+ `).reduce((o,t)=>o+Math.max(1,Math.ceil((t.length||1)/Math.max(1,e))),0)}function pn(r,e){if(r.type==="user")return 4;let o=0;for(let t of r.messages)if(t.type==="error")o+=Ot(t.content,e);else if(t.type==="command")o+=t.content.split(`
176
+ `).length+(t.commandTitle?1:0)+2;else if(t.type==="text")o+=Ot(t.content,e);else if(t.type==="done"&&t.content)o+=Ot(t.content.replace(/^DONE:\s*/i,"").trim(),e);else if(t.type==="tool_result"&&t.toolCall?.tool==="edit_file"&&t.toolResult?.meta){let n=t.toolResult.meta;o+=(n.diffContextBefore?.length??0)+(n.diffOld?.length??0)+(n.diffNew?.length??0)+(n.diffContextAfter?.length??0)+4;}else o+=1;return Math.max(2,o+2)}function fn(r,e,o,t){let n=[],s=0,l=Math.max(0,r.length-t),c=r.length-l;for(let a=l-1;a>=0;a--){let u=pn(r[a],o);if(s+u>e)return n.length===0?(n.unshift(r[a]),{visible:n,hiddenAbove:a,hiddenBelow:c}):{visible:n,hiddenAbove:a+1,hiddenBelow:c};n.unshift(r[a]),s+=u;}return {visible:n,hiddenAbove:0,hiddenBelow:c}}function wo(r){return new Date(r).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}var gn=({content:r,timestamp:e})=>i.createElement(Box,{flexDirection:"column",marginBottom:1,marginX:1,borderStyle:"single",borderColor:"#1D4ED8"},i.createElement(Box,{paddingX:1},i.createElement(Text,{color:"#3B82F6",bold:true},"# "),i.createElement(Text,{color:"#E5E7EB",bold:true},r)),i.createElement(Box,{paddingX:1},i.createElement(Text,{color:"#374151"},wo(e)))),hn=({msg:r})=>{switch(r.type){case "text":return i.createElement(Bt,{content:r.content});case "command":{let e=r.content.split(`
177
+ `);return i.createElement(Box,{flexDirection:"column",marginBottom:1,paddingLeft:2},r.commandTitle&&i.createElement(Box,{marginBottom:0},i.createElement(Text,{color:"#6B7280"},"\u250C\u2500 "),i.createElement(Text,{color:"#9CA3AF",bold:true},r.commandTitle)),i.createElement(Box,{flexDirection:"column",borderStyle:"single",borderColor:"#374151",paddingX:1},e.map((o,t)=>{if(o.startsWith(" /")||o.startsWith(" $")||o.startsWith(" !")){let s=o.search(/\s{2,}/),l=s>0?o.slice(0,s):o,c=s>0?o.slice(s).trim():"";return i.createElement(Box,{key:t},i.createElement(Text,{color:"#3B82F6"},l),c?i.createElement(Text,{color:"#6B7280"}," ",c):null)}if(o.startsWith("**")&&o.endsWith("**"))return i.createElement(Text,{key:t,color:"#9CA3AF",bold:true},o.replace(/\*\*/g,""));if(o==="")return i.createElement(Text,{key:t}," ");if(/^\s{2}\S.*\s:\s/.test(o)){let s=o.indexOf(" : "),l=o.slice(0,s),c=o.slice(s+3);return i.createElement(Box,{key:t},i.createElement(Text,{color:"#6B7280"},l," "),i.createElement(Text,{color:"#374151"},": "),i.createElement(Text,{color:"#E5E7EB"},c))}return i.createElement(Text,{key:t,color:"#9CA3AF"},o)})))}case "tool_call":{if(!r.toolCall)return null;let e=r.toolCall.arguments,o=(()=>{switch(r.toolCall.tool){case "run_shell":return `$ ${String(e.command||"").slice(0,60)}`;case "read_file":return `Read ${e.path}`;case "write_file":return `Write ${e.path}`;case "append_file":return `Append ${e.path}`;case "edit_file":return null;case "delete_file":return `Delete ${e.path}`;case "move_file":return `Move ${e.from} \u2192 ${e.to}`;case "copy_file":return `Copy ${e.from} \u2192 ${e.to}`;case "create_dir":return `mkdir ${e.path}`;case "list_files":return `ls ${e.path||"."}`;case "find_files":return `find ${e.pattern}`;case "search_files":return `grep "${e.pattern}"`;case "git_status":return "git status";case "git_diff":return "git diff";case "git_log":return "git log";case "git_commit":return `git commit "${String(e.message||"").slice(0,40)}"`;case "web_fetch":return `fetch ${String(e.url||"").slice(0,55)}`;case "http_request":return `${e.method||"GET"} ${String(e.url||"").slice(0,50)}`;case "lsp_check":return `lsp check ${String(e.path||".")}`;default:return r.toolCall.tool}})();return o?i.createElement(Box,{paddingLeft:1},i.createElement(Text,{color:"#4B5563"}," "),i.createElement(Text,{color:"#6B7280"},o)):null}case "tool_result":{if(!r.toolCall||r.toolCall.tool==="edit_file")return null;if(!r.toolResult?.success)return i.createElement(Box,{paddingLeft:1},i.createElement(Text,{color:"#EF4444"}," \u2717 ",(r.toolResult?.error||"").slice(0,80)));let e=(r.toolResult.output||"").split(`
178
+ `).filter(Boolean),o=e.length>1?`${e.length} lines`:(e[0]||"").slice(0,50);return i.createElement(Box,{paddingLeft:1},i.createElement(Text,{color:"#374151"}," "),i.createElement(Text,{color:"#4B5563"},o))}case "error":return i.createElement(Text,{color:"#EF4444",wrap:"wrap"}," \u2717 ",r.content);case "done":{let e=r.content.replace(/```json[\s\S]*?```/gi,"").replace(/\{[\s\S]*?"tool"\s*:[\s\S]*?\}/g,"").replace(/\s*DONE:\s*<[^>]*>/gi,"").replace(/\s*DONE:\s*.*/gi,"").trim();return e?i.createElement(Bt,{content:e}):null}default:return null}},xn=({messages:r,model:e})=>{let o=[],t=[],n=()=>{t.length&&(o.push({type:"content",msgs:t}),t=[]);};for(let a of r)a.type==="tool_result"&&a.toolCall?.tool==="edit_file"&&a.toolResult?.meta?.diffPath?(n(),o.push({type:"diff",msg:a})):t.push(a);n();let l=r.find(a=>a.type==="done")?.timestamp??r[r.length-1]?.timestamp,c=r.some(a=>a.type==="text"&&a.content&&!a.content.startsWith("> ")||a.type==="error"||a.type==="done"&&a.content||a.type==="tool_result"&&a.toolCall?.tool==="edit_file");return i.createElement(Box,{flexDirection:"column",marginBottom:1},o.map((a,u)=>{if(a.type==="diff"){let p=a.msg.toolResult.meta;return i.createElement(Ct,{key:u,filePath:p.diffPath,oldLines:p.diffOld,newLines:p.diffNew,startLine:p.diffStartLine,contextBefore:p.diffContextBefore??[],contextAfter:p.diffContextAfter??[]})}let d=u===o.length-1;return i.createElement(Box,{key:u},i.createElement(Text,{color:"#3B82F6"}," \u2502 "),i.createElement(Box,{flexDirection:"column",flexGrow:1},a.msgs.map(p=>i.createElement(hn,{key:p.id,msg:p})),d&&c&&l&&i.createElement(Box,{marginTop:0},i.createElement(Text,{color:"#374151"},e),i.createElement(Text,{color:"#1D4ED8"}," "),i.createElement(Text,{color:"#374151"},"(",wo(l),")"))))}))};function yn(r){let e=r.indexOf("<think>");if(e===-1)return {thinking:"",response:r,stillThinking:false};let o=r.indexOf("</think>",e);return o===-1?{thinking:r.slice(e+7),response:"",stillThinking:true}:{thinking:r.slice(e+7,o),response:r.slice(o+8).trimStart(),stillThinking:false}}function Tn(r,e){if(r.length<2)return "";let o=e.find(s=>s!==r&&s.toLowerCase().startsWith(r.toLowerCase()));if(o)return o.slice(r.length);let t=Ve.find(s=>s.cmd.startsWith(r)&&s.cmd!==r);if(t)return t.cmd.slice(r.length);let n=lt.find(s=>s.startsWith(r)&&s!==r);return n?n.slice(r.length):""}var Co=({initialCommand:r,cwd:e})=>{let{exit:o}=useApp(),t=ke.getInstance(),[n,s]=useState([]),[l,c]=useState("idle"),[a,u]=useState(""),[d,p]=useState(0),[y,x]=useState(()=>t.getHistory()),[S,G]=useState(null),[T,$]=useState(""),[b,J]=useState(-1),[Ae,I]=useState(0),[le,ne]=useState(0),[Be,xe]=useState(false),[ye,Oe]=useState(false),[Ie,rt]=useState([]),[_e,qe]=useState(false),[Ee,Me]=useState(false),[Lo,$o]=useState([]),[ze,nt]=useState([]),[ae,Po]=useState("build"),[ko,st]=useState([]),de=useRef(null),Tt=useRef(null),[jt,_o]=useState(process.stdout.rows||24),[Ut,Eo]=useState(process.stdout.columns||80),Wt=useRef({agentStatus:l,isRunning:false,attachments:ze,mode:ae,pickerIdx:Ae,messages:n});Wt.current={agentStatus:l,isRunning:l==="thinking"||l==="running",attachments:ze,mode:ae,pickerIdx:Ae,messages:n};let Ye=n.length===0&&l==="idle"&&!S,Mo=[...Ve,...ko],Je=T.startsWith("/")&&l==="idle"&&!Ye&&!Be&&!ye?Mo.filter(h=>h.cmd.toLowerCase().startsWith(T.toLowerCase())).slice(0,7):[],it=Je.length>0,Ne=!Ye&&!it&&!Be&&!ye&&l==="idle"?Tn(T,y):"",je=l==="thinking"||l==="running";useEffect(()=>{let h=()=>{_o(process.stdout.rows||24),Eo(process.stdout.columns||80);};return process.stdout.on("resize",h),()=>{process.stdout.off("resize",h);}},[]),useEffect(()=>{let h=A=>{let z=A.toString().match(/\x1b\[<(\d+);\d+;\d+[Mm]/);if(!z)return;let R=parseInt(z[1]);R===64&&ne(ee=>ee+3),R===65&&ne(ee=>Math.max(0,ee-3));};return process.stdin.on("data",h),()=>{process.stdin.off("data",h);}},[]),useEffect(()=>{try{Tt.current=new xt(e,t.get().shell);}catch{}return ()=>{Tt.current?.kill();}},[]),useEffect(()=>{if(r){let h=setTimeout(()=>bt(r),150);return ()=>clearTimeout(h)}},[]),useEffect(()=>{let h=he.getInstance();h.load(),st(h.getCommands().map(A=>({cmd:A.cmd,description:A.description})));},[]);let g=useCallback(h=>{s(A=>[...A,{...h,id:dn(),timestamp:Date.now()}]),ne(0);},[]),Do=useCallback(h=>{let A=h.trim().replace(/^["']|["']$/g,""),B=/^[A-Za-z]:[\\\/].{2,}/.test(A),z=/^\/[^\s\/]+\/[^\s]*/.test(A);if(B||z){$(""),J(-1),I(0),yt(A,e).then(R=>{R?nt(ee=>[...ee,R]):$(h);});return}$(h),J(-1),I(0);},[e]),bt=useCallback(async h=>{let{agentStatus:A,isRunning:B,attachments:z,mode:R,messages:ee}=Wt.current,C=h.trim();if(C){if($(""),J(-1),I(0),C.startsWith("/config")||C.toLowerCase()==="/config"){let _=C.slice(7).trim(),[L,...D]=_.split(/\s+/),f=D.join(" ").trim();if(L)switch(L.toLowerCase()){case "model":if(!f){g({type:"error",content:"Usage: /config model <model-name>"});break}t.setLLM({model:f}),g({type:"done",content:`Model \u2192 ${f}`});break;case "provider":{if(!f||!["ollama","lmstudio"].includes(f.toLowerCase())){g({type:"error",content:`Available providers: ollama lmstudio
179
+ /config provider ollama
180
+ /config provider lmstudio`});break}let v=f==="lmstudio"?{provider:"lmstudio",baseURL:"http://localhost:1234/v1",model:t.get().llm.model}:{provider:"ollama",baseURL:"http://localhost:11434",model:t.get().llm.model};t.setLLM(v),g({type:"done",content:`Provider \u2192 ${f}
181
+ URL \u2192 ${v.baseURL}`});break}case "url":case "baseurl":case "base-url":if(!f){g({type:"error",content:"Usage: /config url <url>"});break}t.setLLM({baseURL:f}),g({type:"done",content:`Base URL \u2192 ${f}`});break;case "temperature":case "temp":if(!f){g({type:"error",content:"Usage: /config temperature <0.0\u20131.0>"});break}t.setLLM({temperature:parseFloat(f)}),g({type:"done",content:`Temperature \u2192 ${f}`});break;default:g({type:"error",content:"Unknown subcommand. Type /config for an overview."});}else {let v=t.get();g({type:"command",commandTitle:"config",content:[` config path : ${t.getConfigPath()}`,"",` provider : ${v.llm.provider}`,` model : ${v.llm.model}`,` url : ${v.llm.baseURL||"(default)"}`,` temperature : ${v.llm.temperature??.1}`,"","**Commands**"," /config provider ollama Use Ollama (localhost:11434)"," /config provider lmstudio Use LM Studio (localhost:1234)"," /config model <name> Switch model"," /config url <url> Override base URL"," /config temperature <val> Set temperature (0.0\u20131.0)"].join(`
182
+ `)});}t.addHistory(C),x(t.getHistory());return}if(C==="/exit"||C==="exit"||C==="quit"){o();return}if(C==="/clear"||C==="clear"){s([]);return}if(C==="/lsp"||C.startsWith("/lsp ")){let _=C.slice(4).trim()||".";c("thinking"),u("");let{diagnostics:L,tool:D,error:f}=await dt(e,_==="."?void 0:_);if(c("idle"),u(""),f&&L.length===0)g({type:"error",content:f});else if(L.length===0)g({type:"command",commandTitle:`lsp (${D})`,content:" \u2713 No issues found"});else {let v=L.filter(F=>F.severity==="error").length,k=L.filter(F=>F.severity==="warning").length,se=[` ${D}: ${v} error${v!==1?"s":""}, ${k} warning${k!==1?"s":""}`,"",...L.slice(0,40).map(F=>` ${F.file}:${F.line}:${F.col} ${F.severity} ${F.message}${F.code?` [${F.code}]`:""}`),...L.length>40?[` \u2026 and ${L.length-40} more`]:[]];g({type:"command",commandTitle:`lsp (${D})`,content:se.join(`
183
+ `)});}t.addHistory(C),x(t.getHistory());return}if(C==="/attach"){Me(true),(async()=>$o(await cn(e)))();return}if(C==="/compact"){if(ee.length===0){g({type:"error",content:"Nothing to compact."});return}c("thinking"),u("");let _=ee.map(f=>f.type==="text"&&f.content.startsWith("> ")?`User: ${f.content.slice(2)}`:f.type==="done"?`Assistant: ${f.content.replace(/^DONE:\s*/i,"").trim()}`:f.type==="tool_call"&&f.toolCall?` [${f.toolCall.tool}]`:null).filter(Boolean).join(`
184
+ `),L=[{role:"system",content:"You are a helpful assistant. Summarize the following conversation concisely in bullet points, preserving key decisions and results."},{role:"user",content:_}],D="";try{await oe.stream(L,t.get().llm,f=>{D+=f,u(D);});}catch{}u(""),c("idle"),s([]),g({type:"done",content:`[Compacted]
185
+ ${D}`});return}if(C.startsWith("/session")){let _=C.slice(8).trim(),[L,...D]=_.split(/\s+/),f=D.join(" ").trim()||L;if(!L||L==="list"){let v=t.listSessions();g({type:"command",commandTitle:"sessions",content:v.length?v.map(k=>` \u2022 ${k}`).join(`
186
+ `):" No sessions saved yet. Use /session save <name>"});}else if(L==="save"){if(!f||f==="save"){g({type:"error",content:"Usage: /session save <name>"});return}t.saveSession(f,ee),g({type:"done",content:`Session "${f}" saved (${ee.length} messages)`});}else if(L==="load"){if(!f||f==="load"){g({type:"error",content:"Usage: /session load <name>"});return}let v=t.loadSession(f);if(!v){g({type:"error",content:`Session "${f}" not found.`});return}s(v),g({type:"done",content:`Session "${f}" loaded (${v.length} messages)`});}else if(L==="delete"){if(!f||f==="delete"){g({type:"error",content:"Usage: /session delete <name>"});return}t.deleteSession(f),g({type:"done",content:`Session "${f}" deleted`});}else g({type:"error",content:"Usage: /session [list|save <name>|load <name>|delete <name>]"});t.addHistory(C),x(t.getHistory());return}if(C==="/connect"){$(""),xe(true);return}if(C==="/model"){$(""),Oe(true),qe(true),rt([]),(async()=>{let _=t.get(),D=_.llm.provider==="ollama"?await oe.getOllamaProvider().listModels(_.llm.baseURL):await oe.getLMStudioProvider().listModels(_.llm.baseURL);rt(D),qe(false);})();return}if(C==="/plugin"||C.startsWith("/plugin ")){let _=C.slice(7).trim(),[L,...D]=_.split(/\s+/),f=D.join(" ").trim(),v=he.getInstance();if(!L||L==="list"){let k=v.getAll(),se=v.getErrors(),F=[];if(k.length===0&&se.length===0)F.push(" No plugins installed."),F.push(` Plugin dir: ${v.getPluginDir()}`),F.push(""),F.push(" /plugin install <path> Install a plugin");else {for(let V of k){let be=(V.commands??[]).map(Ue=>Ue.cmd.trim()).join(", "),Q=(V.tools??[]).map(Ue=>Ue.name).join(", ");F.push(` \u2022 ${V.name} v${V.version}${V.description?" "+V.description:""}`),be&&F.push(` commands : ${be}`),Q&&F.push(` tools : ${Q}`);}for(let V of se)F.push(` \u2717 ${V.file}: ${V.error}`);}g({type:"command",commandTitle:"plugins",content:F.join(`
187
+ `)});}else if(L==="install"){if(!f){g({type:"error",content:"Usage: /plugin install <path>"}),t.addHistory(C),x(t.getHistory());return}c("thinking");let k=await v.install(f);c("idle"),k.ok?(st(v.getCommands().map(se=>({cmd:se.cmd,description:se.description}))),g({type:"done",content:`Plugin "${k.name}" installed successfully`})):g({type:"error",content:`Install failed: ${k.error}`});}else if(L==="remove"){if(!f){g({type:"error",content:"Usage: /plugin remove <name>"}),t.addHistory(C),x(t.getHistory());return}c("thinking");let k=await v.remove(f);c("idle"),k.ok?(st(v.getCommands().map(se=>({cmd:se.cmd,description:se.description}))),g({type:"done",content:`Plugin "${f}" removed`})):g({type:"error",content:k.error||"Remove failed"});}else L==="reload"?(v.reload(),st(v.getCommands().map(k=>({cmd:k.cmd,description:k.description}))),g({type:"done",content:`Plugins reloaded (${v.getAll().length} loaded)`})):g({type:"error",content:"Usage: /plugin [list | install <path> | remove <name> | reload]"});t.addHistory(C),x(t.getHistory());return}if(C.startsWith("/")){let _=he.getInstance().getCommands(),L=C.trim(),D=_.find(f=>{let v=f.cmd.trimEnd();return L===v||L.startsWith(v+" ")});if(D){let f=D.cmd.trimEnd(),v=L.slice(f.length).trim();c("thinking");try{let k=await D.handler(v,{cwd:e});c("idle"),k.type==="error"?g({type:"error",content:k.content}):k.type==="command"?g({type:"command",commandTitle:k.title,content:k.content}):g({type:"done",content:k.content});}catch(k){c("idle"),g({type:"error",content:`Plugin error: ${String(k)}`});}t.addHistory(C),x(t.getHistory());return}}switch(C.trim().toLowerCase()){case "exit":case "quit":o();return;case "clear":s([]);return;case "help":case "/help":g({type:"command",commandTitle:"help",content:["**Attachments**"," /attach Attach file or image (@-picker)"," @path/to/file Include file in message (type in input)","","**Session**"," /session List saved sessions"," /session save <name> Save conversation"," /session load <name> Load conversation"," /session delete <name> Delete session"," /compact Summarize & compress conversation","","**Connection**"," /connect Connect to server (popup)"," /model Select model (popup)","","**Configuration**"," /config Show current configuration"," /config provider ollama Use Ollama (localhost:11434)"," /config provider lmstudio Use LM Studio (localhost:1234)"," /config model <name> Switch model"," /config url <url> Set base URL"," /config temperature <val> Set temperature (0.0\u20131.0)","","**System**"," /lsp Run diagnostics (tsc/cargo/go vet/pyflakes/eslint)"," /models List available models"," /doctor Check connection & status"," /clear Clear screen"," /exit Quit","","**Keyboard shortcuts**"," ctrl+c Abort running agent / quit"," ctrl+l Clear chat history"," ctrl+k Clear input line"," \u2191 \u2193 Navigate history"," tab Autocomplete / toggle BUILD\u2194PLAN mode"," PageUp / PageDown Scroll chat","","**Shell**"," $ <cmd> or ! <cmd> e.g.: $ npm test","","**Plugins**"," /plugin List installed plugins"," /plugin install <path> Install plugin from directory or .js file"," /plugin remove <name> Uninstall a plugin"," /plugin reload Reload all plugins"].join(`
188
+ `)});break;case "doctor":{let _=t.get(),L=_.llm.provider==="ollama",D=L?await oe.getOllamaProvider().checkHealth(_.llm.baseURL):await oe.getLMStudioProvider().checkHealth(_.llm.baseURL),f=L?"Ollama":"LM Studio",v=L?"ollama serve":"LM Studio \u2192 start Local Server";g({type:"command",commandTitle:"doctor",content:[` Node.js : \u2713 ${process.version}`,` Platform : \u2713 ${process.platform}`,` ${f.padEnd(9)}: ${D?"\u2713 Reachable":`\u2717 Not reachable \u2014 ${v}`}`,` Provider : ${_.llm.provider}`,` Model : ${_.llm.model}`,` URL : ${_.llm.baseURL||"(default)"}`,` Config : ${t.getConfigPath()}`].join(`
189
+ `)});break}case "models":{let _=t.get(),L=_.llm.provider==="ollama",D=L?await oe.getOllamaProvider().listModels(_.llm.baseURL):await oe.getLMStudioProvider().listModels(_.llm.baseURL);g({type:"command",commandTitle:"models",content:D.length?D.map(v=>` \u2022 ${v}`).join(`
190
+ `):L?" No Ollama models found. Pull one with: ollama pull deepseek-coder":" No LM Studio models found. Open LM Studio and load a model."});break}default:{if(C.startsWith("$")||C.startsWith("!")){Tt.current?.write(C.slice(1).trim()+`
191
+ `);break}if(B&&de.current){de.current.inject(C),g({type:"text",content:`> [btw] ${C}`});break}let _=C.trim().replace(/^["']|["']$/g,"");if(/^[A-Za-z]:[\\\/].{2,}/.test(_)||/^\/[^\s]{2,}/.test(_)){let N=await yt(_,e);if(N){nt(Se=>[...Se,N]);return}}let D=/@([^\s]+)/g,f=[],v=C,k;for(;(k=D.exec(C))!==null;)f.push(yt(k[1],e)),v=v.replace(k[0],`[${k[1]}]`);let F=(await Promise.all(f)).filter(N=>N!==null),V=[...z,...F];c("thinking"),u(""),p(0);let be=V.length?` [${V.map(N=>N.name).join(", ")}]`:"";g({type:"text",content:`> ${v}${be}`}),nt([]);let Q=new ht;de.current=Q;let Ue=0;Q.on("thinking",()=>{c("thinking"),u("");}),Q.on("token",N=>{c("running"),u(Se=>Se+N),Ue+=N.length,p(Ue);}),Q.on("tool_call",({toolCall:N})=>{u(""),g({type:"tool_call",content:N.tool,toolCall:N});}),Q.on("tool_result",({toolCall:N,result:Se})=>{g({type:"tool_result",content:"",toolCall:N,toolResult:Se});}),Q.on("confirm_required",({toolCall:N,reason:Se,diffPreview:Fo})=>{G({toolCall:N,reason:Se,diffPreview:Fo});}),Q.on("injection",({message:N})=>{}),Q.on("error",N=>{c("error"),g({type:"error",content:N});}),Q.on("done",({response:N,aborted:Se})=>{u(""),c("idle"),G(null),de.current=null,Se?g({type:"error",content:"Stopped."}):N&&g({type:"done",content:N});}),Q.run(v,e,V,R).catch(N=>{c("error"),g({type:"error",content:String(N)}),de.current=null;});break}}t.addHistory(C),x(t.getHistory());}},[g,e,o]);useInput((h,A)=>{if(h.startsWith("\x1B[<")){let B=h.match(/\x1b\[<(\d+)/);if(B){let z=parseInt(B[1]);if(z===64){ne(R=>R+3);return}if(z===65){ne(R=>Math.max(0,R-3));return}}return}if(Be||ye||Ee){A.ctrl&&h==="c"&&(xe(false),Oe(false),Me(false));return}if(!Ye){if(A.pageUp){ne(B=>B+2);return}if(A.pageDown){ne(B=>Math.max(0,B-2));return}}if(!Ye&&l==="idle"){if(it){if(A.upArrow){I(B=>Math.max(0,B-1));return}if(A.downArrow){I(B=>Math.min(Je.length-1,B+1));return}if(A.tab){let B=Je[Ae];B&&($(B.cmd.endsWith(" ")?B.cmd:B.cmd.trim()),I(0));return}if(A.escape){$(""),I(0),J(-1);return}return}if(A.tab&&!Ne){Po(B=>B==="build"?"plan":"build");return}if(A.tab&&Ne){$(T+Ne);return}if(A.upArrow){if(T===""){ne(z=>z+3);return}let B=Math.min(b+1,y.length-1);J(B),y[B]&&$(y[B]);return}if(A.downArrow){if(T===""&&le>0){ne(z=>Math.max(0,z-3));return}let B=Math.max(b-1,-1);J(B),$(B===-1?"":y[B]||"");return}if(A.escape){$(""),J(-1);return}}if(A.ctrl&&h==="c"){de.current?(de.current.abort(),de.current=null,c("idle"),u(""),g({type:"error",content:"Aborted."})):o();return}if(A.ctrl&&h==="l"){s([]);return}if(A.ctrl&&h==="k"){$(""),J(-1);return}S&&(h==="y"||h==="Y"?(de.current?.confirm(true),G(null)):(h==="n"||h==="N"||A.escape)&&(de.current?.confirm(false),G(null)));});let Te=t.get();Te.llm.provider==="lmstudio"?"LM Studio":"Ollama";return i.createElement(Box,{flexDirection:"column",height:jt},Ye?i.createElement(i.Fragment,null,i.createElement(Box,{flexGrow:1,alignItems:"center",justifyContent:"center"},i.createElement(Vt,{config:Te,history:y,onSubmit:bt})),i.createElement(wt,{config:Te,cwd:e,agentStatus:l,tokenCount:d,mode:ae})):i.createElement(i.Fragment,null,i.createElement(Box,{flexGrow:1}),(()=>{let h=it?Je.length+3:0,A=a||je?2:0,B=ze.length>0?1:0,z=S?.diffPreview?S.diffPreview.contextBefore.length+S.diffPreview.oldLines.length+S.diffPreview.newLines.length+S.diffPreview.contextAfter.length+4:0,R=S?1+z:0,L=4+B+1+h+A+R+1,D=Math.max(2,jt-L),f=Math.max(20,Ut-8),v=mn(n),k=Math.min(le,Math.max(0,v.length-1)),{visible:se,hiddenAbove:F,hiddenBelow:V}=fn(v,D,f,k);return i.createElement(i.Fragment,null,F>0?i.createElement(Box,{paddingX:2},i.createElement(Text,{color:"#374151"},"\u2191 PageUp "),i.createElement(Text,{color:"#4B5563"},F," older messages")):i.createElement(Text,null," "),se.map((be,Q)=>be.type==="user"?i.createElement(gn,{key:Q,content:be.content,timestamp:be.timestamp}):i.createElement(xn,{key:Q,messages:be.messages,model:Te.llm.model})),V>0&&i.createElement(Box,{paddingX:2},i.createElement(Text,{color:"#374151"},"\u2193 PageDown "),i.createElement(Text,{color:"#4B5563"},V," newer messages")))})(),(a||je&&!a)&&(()=>{let{thinking:h,response:A,stillThinking:B}=yn(a),z=A.replace(/```json[\s\S]*?```/g,"").replace(/\{[\s\S]*?"tool"\s*:/g,""),R=h.trimEnd().split(`
192
+ `).filter(ee=>ee.trim()).slice(-3);return i.createElement(Box,{marginBottom:0,flexDirection:"column"},h&&i.createElement(Box,{flexDirection:"column"},i.createElement(Box,null,i.createElement(Text,{color:"#3B82F6"}," \u2502 "),i.createElement(Text,{color:"#6366F1",bold:true},"Reasoning"),B&&i.createElement(at,{label:""})),R.map((ee,C)=>i.createElement(Box,{key:C},i.createElement(Text,{color:"#3B82F6"}," \u2502 "),i.createElement(Text,{color:"#4B5563",italic:true},ee.slice(0,Ut-10))))),i.createElement(Box,null,i.createElement(Text,{color:"#3B82F6"}," \u2502 "),i.createElement(Box,{flexGrow:1},a?z?i.createElement(Box,null,i.createElement(Text,{color:"#D1D5DB",wrap:"wrap"},z),i.createElement(Text,{color:"#3B82F6"},"\u2588")):B?i.createElement(Box,null,i.createElement(Text,{color:"#6366F1"},"Thinking "),i.createElement(at,{label:""})):null:i.createElement(Box,null,i.createElement(Text,{color:"#6366F1"},"Thinking "),i.createElement(at,{label:""})))))})(),S&&i.createElement(Box,{flexDirection:"column",marginX:1,marginBottom:1,borderStyle:"single",borderColor:"#F59E0B"},S.diffPreview&&i.createElement(Ct,{filePath:S.diffPreview.filePath,oldLines:S.diffPreview.oldLines,newLines:S.diffPreview.newLines,startLine:S.diffPreview.startLine,contextBefore:S.diffPreview.contextBefore,contextAfter:S.diffPreview.contextAfter}),i.createElement(Box,{paddingX:2,paddingY:0},i.createElement(Text,{color:"#F59E0B"},"Allow "),i.createElement(Text,{color:"#D1D5DB"},S.reason),i.createElement(Text,{color:"#4B5563"}," "),i.createElement(Text,{color:"#22C55E"},"[y] yes"),i.createElement(Text,{color:"#4B5563"}," / "),i.createElement(Text,{color:"#EF4444"},"[n] no"))),Be&&i.createElement(to,{onConnect:(h,A)=>{t.setLLM({provider:h,baseURL:A}),xe(false),g({type:"done",content:`Connected \xB7 ${h} ${A}`});},onCancel:()=>xe(false)}),ye&&i.createElement(ro,{models:Ie,loading:_e,currentModel:Te.llm.model,onSelect:h=>{t.setLLM({model:h}),Oe(false),g({type:"done",content:`Model \u2192 ${h}`});},onCancel:()=>Oe(false)}),Ee&&i.createElement(so,{files:Lo,onSelect:async h=>{Me(false);let A=await yt(h,e);A&&nt(B=>[...B,A]);},onCancel:()=>Me(false)}),it&&i.createElement(Box,{flexDirection:"column",borderStyle:"round",borderColor:"#2D4A7A",marginX:1},Je.map((h,A)=>{let B=A===Ae;return i.createElement(Box,{key:h.cmd,paddingX:1},i.createElement(Text,{color:B?"#3B82F6":"#374151"},B?"\u25B6 ":" "),i.createElement(Text,{color:B?"#60A5FA":"#6B7280",bold:true},h.cmd.trimEnd()),i.createElement(Text,{color:B?"#4B5563":"#374151"}," ",h.description))})),i.createElement(Box,{flexDirection:"column",borderStyle:"single",borderColor:ae==="plan"?"#14532D":"#1E3A5F",marginX:1},ze.length>0&&i.createElement(Box,{paddingX:1,flexDirection:"row"},ze.map((h,A)=>i.createElement(Box,{key:A,marginRight:1},i.createElement(Text,{color:h.type==="image"?"#A78BFA":"#60A5FA"},"@",h.name)))),i.createElement(Box,{paddingX:1},i.createElement(Text,{color:je?"#F59E0B":ae==="plan"?"#22C55E":"#3B82F6",bold:true},"> "),i.createElement(Lt,{value:T,onChange:Do,onSubmit:bt,placeholder:je?"inject message to agent...":ae==="plan"?"describe what to plan...":"/ for commands \xB7 @ to attach files",focus:!S&&!Be&&!ye&&!Ee}),Ne&&!je&&i.createElement(Text,{color:"#1F2937"},Ne)),i.createElement(Box,{paddingX:1,justifyContent:"space-between"},i.createElement(Box,null,je?i.createElement(i.Fragment,null,i.createElement(Text,{color:"#F59E0B"},"ctrl+c "),i.createElement(Text,{color:"#6B7280"},"abort "),i.createElement(Text,{color:"#4B5563"},"\u21B5 "),i.createElement(Text,{color:"#6B7280"},"inject message")):i.createElement(i.Fragment,null,i.createElement(Text,{color:"#4B5563"},"\u21B5 "),i.createElement(Text,{color:"#6B7280"},"send "),i.createElement(Text,{color:"#4B5563"},"tab "),i.createElement(Text,{color:"#6B7280"},Ne?"complete":"switch mode"," "),i.createElement(Text,{color:"#4B5563"},"@ "),i.createElement(Text,{color:"#6B7280"},"attach"))),i.createElement(Box,null,i.createElement(Text,{backgroundColor:ae==="plan"?"#166534":"#1D4ED8",color:ae==="plan"?"#86EFAC":"#BFDBFE"}," ",ae==="plan"?"PLAN":"BUILD"," "),i.createElement(Text,{color:"#374151"}," "),i.createElement(Text,{color:"#9CA3AF"},Te.llm.model.length>24?Te.llm.model.slice(0,24)+"\u2026":Te.llm.model)))),i.createElement(wt,{config:Te,cwd:e,agentStatus:l,tokenCount:d,mode:ae})))};var tt=process.argv.slice(2),vn=process.cwd();(tt.includes("--help")||tt.includes("-h"))&&(process.stdout.write(`
193
+ ${Z.bold.blue("\u26A1 LocalCode")} ${Z.gray("v0.1.0")} ${Z.gray("\u2014 Futuristic AI Developer Terminal")}
194
+
195
+ ${Z.bold("Usage:")}
196
+ ${Z.blue("localcode")} Start interactive TUI
197
+ ${Z.blue("localcode")} <task> Run AI task directly
198
+ ${Z.blue("localcode")} --provider <p> Override LLM provider
199
+ ${Z.blue("localcode")} --model <m> Override model
200
+ ${Z.blue("localcode")} --help Show this help
201
+
202
+ ${Z.bold("Examples:")}
203
+ ${Z.gray("localcode")}
204
+ ${Z.gray("localcode fix auth bug")}
205
+ ${Z.gray("localcode --provider ollama --model llama3 fix typescript errors")}
206
+ ${Z.gray("localcode --provider openai --model gpt-4o create REST API")}
207
+
208
+ ${Z.bold("Providers:")} ollama \xB7 openai \xB7 claude \xB7 openrouter \xB7 lmstudio
209
+
210
+ ${Z.bold("Config:")} ~/.localcode/config.json
211
+ `),process.exit(0));(tt.includes("--version")||tt.includes("-v"))&&(process.stdout.write(`0.1.0
212
+ `),process.exit(0));var et=[...tt];function Ao(r){let e=et.indexOf(r);if(e===-1)return;let o=et[e+1];return et.splice(e,2),o}var It=Ao("--provider"),Nt=Ao("--model");(It||Nt)&&ke.getInstance().setLLM({...It&&{provider:It},...Nt&&{model:Nt}});var wn=et.length>0?et.join(" "):void 0,Bo=process.stdout.isTTY;function Cn(){Bo&&process.stdout.write("\x1B[?1049h\x1B[2J\x1B[3J\x1B[H\x1B[?1000h\x1B[?1006h");}function ot(){Bo&&process.stdout.write("\x1B[?1006l\x1B[?1000l\x1B[?1049l");}process.on("exit",ot);process.on("SIGINT",()=>{ot(),process.exit(0);});process.on("SIGTERM",()=>{ot(),process.exit(0);});process.on("uncaughtException",()=>{ot(),process.exit(1);});Cn();var{waitUntilExit:An}=render(i.createElement(Co,{initialCommand:wn,cwd:vn}),{exitOnCtrlC:false,patchConsole:true});An().then(()=>{ot(),process.exit(0);});
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "localcode-agent",
3
+ "version": "0.1.1",
4
+ "description": "Futuristic AI Developer Terminal & Autonomous Coding Agent",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=18.0.0"
9
+ },
10
+ "files": [
11
+ "dist/"
12
+ ],
13
+ "bin": {
14
+ "localcode": "dist/localcode.js",
15
+ "local": "dist/localcode.js"
16
+ },
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "dev": "tsup --watch",
20
+ "start": "node dist/localcode.js",
21
+ "link:dev": "npm run build && npm link",
22
+ "prepublishOnly": "npm run build",
23
+ "publish:npm": "npm publish"
24
+ },
25
+ "dependencies": {
26
+ "chalk": "^4.1.2",
27
+ "ink": "^4.4.1",
28
+ "ink-text-input": "^5.0.1",
29
+ "node-pty": "^1.0.0",
30
+ "react": "^18.2.0",
31
+ "strip-ansi": "^6.0.1"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^20.14.0",
35
+ "@types/react": "^18.2.0",
36
+ "tsup": "^8.0.0",
37
+ "typescript": "^5.4.5"
38
+ }
39
+ }