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 +21 -0
- package/README.md +200 -0
- package/dist/localcode.js +212 -0
- package/package.json +39 -0
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
|
+

|
|
7
|
+

|
|
8
|
+

|
|
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(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/ /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
|
+
}
|