codetyper-cli 0.4.2 → 0.4.3

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/README.md CHANGED
@@ -90,9 +90,11 @@ Full-screen terminal interface with real-time streaming responses.
90
90
  ![CodeTyper Status View](assets/CodetyperView.png)
91
91
 
92
92
  **Key bindings:**
93
+
93
94
  - `Enter` - Send message
94
95
  - `Shift+Enter` - New line
95
- - `/` - Open command menu
96
+ - `@` - Open file picker (works anywhere in input)
97
+ - `/` - Open command menu (works anywhere in input)
96
98
  - `Ctrl+M` - Toggle interaction mode
97
99
  - `Ctrl+T` - Toggle todo panel
98
100
  - `Shift+Up/Down` - Scroll log panel
@@ -103,6 +105,7 @@ Full-screen terminal interface with real-time streaming responses.
103
105
  Optional vim-style keyboard navigation for power users. Enable in settings.
104
106
 
105
107
  **Normal Mode:**
108
+
106
109
  - `j/k` - Scroll down/up
107
110
  - `gg/G` - Jump to top/bottom
108
111
  - `Ctrl+d/u` - Half page scroll
@@ -111,6 +114,7 @@ Optional vim-style keyboard navigation for power users. Enable in settings.
111
114
  - `:` - Command mode (`:q` quit, `:w` save)
112
115
 
113
116
  **Configuration:**
117
+
114
118
  ```json
115
119
  {
116
120
  "vim": {
@@ -128,26 +132,26 @@ Press `/` to access all commands organized by category.
128
132
 
129
133
  **Available Commands:**
130
134
 
131
- | Category | Command | Description |
132
- |----------|---------|-------------|
133
- | General | `/help` | Show available commands |
134
- | General | `/clear` | Clear conversation history |
135
- | General | `/exit` | Exit the chat |
136
- | Session | `/save` | Save current session |
137
- | Session | `/context` | Show context information |
138
- | Session | `/usage` | Show token usage statistics |
139
- | Session | `/remember` | Save a learning about the project |
140
- | Session | `/learnings` | Show saved learnings |
141
- | Settings | `/model` | Select AI model |
142
- | Settings | `/agent` | Select agent |
143
- | Settings | `/mode` | Switch interaction mode |
144
- | Settings | `/provider` | Switch LLM provider |
145
- | Settings | `/status` | Show provider status |
146
- | Settings | `/theme` | Change color theme |
147
- | Settings | `/mcp` | Manage MCP servers |
148
- | Account | `/whoami` | Show logged in account |
149
- | Account | `/login` | Authenticate with provider |
150
- | Account | `/logout` | Sign out from provider |
135
+ | Category | Command | Description |
136
+ | -------- | ------------ | --------------------------------- |
137
+ | General | `/help` | Show available commands |
138
+ | General | `/clear` | Clear conversation history |
139
+ | General | `/exit` | Exit the chat |
140
+ | Session | `/save` | Save current session |
141
+ | Session | `/context` | Show context information |
142
+ | Session | `/usage` | Show token usage statistics |
143
+ | Session | `/remember` | Save a learning about the project |
144
+ | Session | `/learnings` | Show saved learnings |
145
+ | Settings | `/model` | Select AI model |
146
+ | Settings | `/agent` | Select agent |
147
+ | Settings | `/mode` | Switch interaction mode |
148
+ | Settings | `/provider` | Switch LLM provider |
149
+ | Settings | `/status` | Show provider status |
150
+ | Settings | `/theme` | Change color theme |
151
+ | Settings | `/mcp` | Manage MCP servers |
152
+ | Account | `/whoami` | Show logged in account |
153
+ | Account | `/login` | Authenticate with provider |
154
+ | Account | `/logout` | Sign out from provider |
151
155
 
152
156
  ### Agent Mode with Diff View
153
157
 
@@ -156,6 +160,7 @@ When CodeTyper modifies files, you see a clear diff view of changes.
156
160
  ![Agent Mode with Diffs](assets/CodetyperAgentMode.png)
157
161
 
158
162
  **Interaction Modes:**
163
+
159
164
  - **Agent** - Full access, can modify files
160
165
  - **Ask** - Read-only, answers questions
161
166
  - **Code Review** - Review PRs and diffs
@@ -167,6 +172,7 @@ Granular control over what CodeTyper can do. Every file operation requires appro
167
172
  ![Permission Modal](assets/CodetyperPermissionView.png)
168
173
 
169
174
  **Permission Scopes:**
175
+
170
176
  - `[y]` Yes, this once
171
177
  - `[s]` Yes, for this session
172
178
  - `[a]` Always allow for this project
@@ -180,6 +186,7 @@ Access to multiple AI models through GitHub Copilot.
180
186
  ![Model Selection](assets/CodetyperCopilotModels.png)
181
187
 
182
188
  **Available Models:**
189
+
183
190
  - GPT-5, GPT-5-mini (Unlimited)
184
191
  - GPT-5.2-codex, GPT-5.1-codex
185
192
  - Grok-code-fast-1
@@ -187,19 +194,19 @@ Access to multiple AI models through GitHub Copilot.
187
194
 
188
195
  ### Theme System
189
196
 
190
- 14+ built-in themes to customize your experience.
197
+ 15+ built-in themes to customize your experience.
191
198
 
192
199
  ![Theme Selection](assets/CodetyperThemes.png)
193
200
 
194
201
  **Available Themes:**
195
- default, dracula, nord, tokyo-night, gruvbox, monokai, catppuccin, one-dark, solarized-dark, github-dark, rose-pine, kanagawa, ayu-dark, cargdev-cyberpunk
202
+ default, dracula, nord, tokyo-night, gruvbox, monokai, catppuccin, one-dark, solarized-dark, github-dark, rose-pine, kanagawa, ayu-dark, cargdev-cyberpunk, pink-purple
196
203
 
197
204
  ## Providers
198
205
 
199
- | Provider | Models | Auth Method | Use Case |
200
- |----------|--------|-------------|----------|
201
- | **GitHub Copilot** | GPT-5, Claude, Gemini | OAuth (device flow) | Cloud-based, high quality |
202
- | **Ollama** | Llama, DeepSeek, Qwen, etc. | Local server | Private, offline, zero-cost |
206
+ | Provider | Models | Auth Method | Use Case |
207
+ | ------------------ | --------------------------- | ------------------- | --------------------------- |
208
+ | **GitHub Copilot** | GPT-5, Claude, Gemini | OAuth (device flow) | Cloud-based, high quality |
209
+ | **Ollama** | Llama, DeepSeek, Qwen, etc. | Local server | Private, offline, zero-cost |
203
210
 
204
211
  ### Cascade Mode
205
212
 
@@ -244,6 +251,7 @@ Settings are stored in `~/.config/codetyper/config.json`:
244
251
  ### Project Context
245
252
 
246
253
  CodeTyper reads project-specific context from:
254
+
247
255
  - `.github/` - GitHub workflows and templates
248
256
  - `.codetyper/` - Project-specific rules and learnings
249
257
  - `rules.md` - Custom instructions for the AI
@@ -274,18 +282,18 @@ codetyper --print "Explain this codebase"
274
282
 
275
283
  CodeTyper has access to these built-in tools:
276
284
 
277
- | Tool | Description |
278
- |------|-------------|
279
- | `bash` | Execute shell commands |
280
- | `read` | Read file contents |
281
- | `write` | Create or overwrite files |
282
- | `edit` | Find and replace in files |
283
- | `glob` | Find files by pattern |
284
- | `grep` | Search file contents |
285
- | `lsp` | Language Server Protocol operations |
286
- | `web_search` | Search the web |
287
- | `todo-read` | Read current todo list |
288
- | `todo-write` | Update todo list |
285
+ | Tool | Description |
286
+ | ------------ | ----------------------------------- |
287
+ | `bash` | Execute shell commands |
288
+ | `read` | Read file contents |
289
+ | `write` | Create or overwrite files |
290
+ | `edit` | Find and replace in files |
291
+ | `glob` | Find files by pattern |
292
+ | `grep` | Search file contents |
293
+ | `lsp` | Language Server Protocol operations |
294
+ | `web_search` | Search the web |
295
+ | `todo-read` | Read current todo list |
296
+ | `todo-write` | Update todo list |
289
297
 
290
298
  ### MCP Integration
291
299
 
@@ -311,6 +319,7 @@ Connect external MCP (Model Context Protocol) servers for extended capabilities:
311
319
  ```
312
320
 
313
321
  **MCP Browser Features:**
322
+
314
323
  - Search by name, description, or tags
315
324
  - Filter by category (database, web, AI, etc.)
316
325
  - View server details and required environment variables
@@ -324,6 +333,7 @@ Connect external MCP (Model Context Protocol) servers for extended capabilities:
324
333
  Lifecycle hooks for intercepting tool execution and session events.
325
334
 
326
335
  **Hook Events:**
336
+
327
337
  - `PreToolUse` - Validate/modify before tool execution
328
338
  - `PostToolUse` - Side effects after tool execution
329
339
  - `SessionStart` - At session initialization
@@ -332,16 +342,22 @@ Lifecycle hooks for intercepting tool execution and session events.
332
342
  - `Stop` - When execution stops
333
343
 
334
344
  **Configuration** (`.codetyper/hooks.json`):
345
+
335
346
  ```json
336
347
  {
337
348
  "hooks": [
338
- { "event": "PreToolUse", "script": ".codetyper/hooks/validate.sh", "timeout": 5000 },
349
+ {
350
+ "event": "PreToolUse",
351
+ "script": ".codetyper/hooks/validate.sh",
352
+ "timeout": 5000
353
+ },
339
354
  { "event": "PostToolUse", "script": ".codetyper/hooks/notify.sh" }
340
355
  ]
341
356
  }
342
357
  ```
343
358
 
344
359
  **Exit Codes:**
360
+
345
361
  - `0` - Allow (optionally output `{"updatedInput": {...}}` to modify args)
346
362
  - `1` - Warn but continue
347
363
  - `2` - Block execution
@@ -351,6 +367,7 @@ Lifecycle hooks for intercepting tool execution and session events.
351
367
  Extend CodeTyper with custom tools, commands, and hooks.
352
368
 
353
369
  **Plugin Structure:**
370
+
354
371
  ```
355
372
  .codetyper/plugins/{name}/
356
373
  ├── plugin.json # Manifest
@@ -363,6 +380,7 @@ Extend CodeTyper with custom tools, commands, and hooks.
363
380
  ```
364
381
 
365
382
  **Manifest** (`plugin.json`):
383
+
366
384
  ```json
367
385
  {
368
386
  "name": "my-plugin",
@@ -373,13 +391,18 @@ Extend CodeTyper with custom tools, commands, and hooks.
373
391
  ```
374
392
 
375
393
  **Custom Tool Definition:**
394
+
376
395
  ```typescript
377
396
  import { z } from "zod";
378
397
  export default {
379
398
  name: "custom_tool",
380
399
  description: "Does something",
381
400
  parameters: z.object({ input: z.string() }),
382
- execute: async (args, ctx) => ({ success: true, title: "Done", output: "..." }),
401
+ execute: async (args, ctx) => ({
402
+ success: true,
403
+ title: "Done",
404
+ output: "...",
405
+ }),
383
406
  };
384
407
  ```
385
408
 
@@ -404,12 +427,12 @@ Sessions are stored in `.codetyper/sessions/` with automatic commit message sugg
404
427
 
405
428
  The next major release focuses on production-ready autonomous agent execution:
406
429
 
407
- | Feature | Issue | Status |
408
- |---------|-------|--------|
409
- | Plan Approval Gate | [#111](https://github.com/CarGDev/codetyper.cli/issues/111) | Planned |
410
- | Diff Preview Before Write | [#112](https://github.com/CarGDev/codetyper.cli/issues/112) | Planned |
411
- | Execution Control (Pause/Resume/Abort) | [#113](https://github.com/CarGDev/codetyper.cli/issues/113) | Planned |
412
- | Consistent Model Behavior | [#114](https://github.com/CarGDev/codetyper.cli/issues/114) | Planned |
430
+ | Feature | Issue | Status |
431
+ | --------------------------------------- | ----------------------------------------------------------- | ------- |
432
+ | Plan Approval Gate | [#111](https://github.com/CarGDev/codetyper.cli/issues/111) | Planned |
433
+ | Diff Preview Before Write | [#112](https://github.com/CarGDev/codetyper.cli/issues/112) | Planned |
434
+ | Execution Control (Pause/Resume/Abort) | [#113](https://github.com/CarGDev/codetyper.cli/issues/113) | Planned |
435
+ | Consistent Model Behavior | [#114](https://github.com/CarGDev/codetyper.cli/issues/114) | Planned |
413
436
  | Quality Gates (TypeScript, Lint, Tests) | [#115](https://github.com/CarGDev/codetyper.cli/issues/115) | Planned |
414
437
 
415
438
  ### Known Issues
@@ -439,11 +462,14 @@ bun test
439
462
  bun run lint
440
463
  ```
441
464
 
442
- ## Recent Changes (v0.3.0)
465
+ ## Recent Changes (v0.4.2)
443
466
 
444
- - **System Prompt Builder**: New modular prompt system with modes, tiers, and providers
445
- - **Module Restructure**: Consistent internal organization with improved imports
446
- - **Solid.js TUI**: Fully migrated to Solid.js + OpenTUI (removed legacy React/Ink)
467
+ - **Pink Purple Theme**: New built-in color theme
468
+ - **Image Paste Fix**: Fixed race condition where pasted images were silently dropped
469
+ - **@ and / Anywhere**: File picker and command menu now work at any cursor position
470
+ - **Plan Approval Gate**: User confirmation before agent executes plans
471
+ - **Execution Control**: Pause, resume, and abort agent execution
472
+ - **Text Clipboard Copy/Read**: Cross-platform clipboard operations with mouse selection
447
473
 
448
474
  See [CHANGELOG](docs/CHANGELOG.md) for complete version history.
449
475
 
package/dist/index.js CHANGED
@@ -36986,9 +36986,18 @@ var init_source4 = __esm(() => {
36986
36986
  });
36987
36987
 
36988
36988
  // src/constants/copilot.ts
36989
- var COPILOT_PROVIDER_NAME = "copilot", COPILOT_DISPLAY_NAME = "GitHub Copilot", COPILOT_AUTH_URL = "https://api.github.com/copilot_internal/v2/token", COPILOT_MODELS_URL = "https://api.githubcopilot.com/models", GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98", GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code", GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token", COPILOT_MODELS_CACHE_TTL, COPILOT_MAX_RETRIES = 3, COPILOT_INITIAL_RETRY_DELAY = 1000, COPILOT_DEFAULT_MODEL = "gpt-5-mini", COPILOT_UNLIMITED_MODEL = "gpt-4o", MODEL_COST_MULTIPLIERS, UNLIMITED_MODELS, MODEL_CONTEXT_SIZES, DEFAULT_CONTEXT_SIZE, getModelContextSize = (modelId) => MODEL_CONTEXT_SIZES[modelId] ?? DEFAULT_CONTEXT_SIZE, COPILOT_FALLBACK_MODELS;
36989
+ var COPILOT_PROVIDER_NAME = "copilot", COPILOT_DISPLAY_NAME = "GitHub Copilot", COPILOT_AUTH_URL = "https://api.github.com/copilot_internal/v2/token", COPILOT_MODELS_URL = "https://api.githubcopilot.com/models", GITHUB_CLIENT_ID = "Iv1.b507a08c87ecfe98", GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code", GITHUB_ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token", COPILOT_MODELS_CACHE_TTL, COPILOT_MAX_RETRIES = 3, COPILOT_INITIAL_RETRY_DELAY = 1000, COPILOT_STREAM_TIMEOUT = 120000, COPILOT_CONNECTION_RETRY_DELAY = 2000, CONNECTION_ERROR_PATTERNS, COPILOT_DEFAULT_MODEL = "gpt-5-mini", COPILOT_UNLIMITED_MODEL = "gpt-4o", MODEL_COST_MULTIPLIERS, UNLIMITED_MODELS, MODEL_CONTEXT_SIZES, DEFAULT_CONTEXT_SIZE, getModelContextSize = (modelId) => MODEL_CONTEXT_SIZES[modelId] ?? DEFAULT_CONTEXT_SIZE, COPILOT_FALLBACK_MODELS;
36990
36990
  var init_copilot = __esm(() => {
36991
36991
  COPILOT_MODELS_CACHE_TTL = 5 * 60 * 1000;
36992
+ CONNECTION_ERROR_PATTERNS = [
36993
+ /socket.*closed/i,
36994
+ /ECONNRESET/i,
36995
+ /ECONNREFUSED/i,
36996
+ /ETIMEDOUT/i,
36997
+ /network.*error/i,
36998
+ /fetch.*failed/i,
36999
+ /aborted/i
37000
+ ];
36992
37001
  MODEL_COST_MULTIPLIERS = {
36993
37002
  "gpt-4o": 0,
36994
37003
  "gpt-4o-mini": 0,
@@ -37321,7 +37330,10 @@ var init_models = __esm(() => {
37321
37330
  });
37322
37331
 
37323
37332
  // src/providers/copilot/utils.ts
37324
- var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)), isRateLimitError = (error2) => {
37333
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)), isConnectionError = (error2) => {
37334
+ const message = error2 instanceof Error ? error2.message : String(error2);
37335
+ return CONNECTION_ERROR_PATTERNS.some((pattern) => pattern.test(message));
37336
+ }, isRateLimitError = (error2) => {
37325
37337
  if (error2 && typeof error2 === "object" && "response" in error2) {
37326
37338
  const response2 = error2.response;
37327
37339
  return response2?.statusCode === 429;
@@ -66811,40 +66823,53 @@ var formatMessages = (messages) => messages.map((msg) => {
66811
66823
  }
66812
66824
  } catch {}
66813
66825
  return false;
66814
- }, executeStream = (endpoint, token, body, onChunk) => new Promise((resolve3, reject) => {
66815
- const stream2 = source_default2.stream.post(endpoint, {
66816
- headers: buildHeaders(token),
66817
- json: body
66826
+ }, executeStream = async (endpoint, token, body, onChunk) => {
66827
+ const response2 = await fetch(endpoint, {
66828
+ method: "POST",
66829
+ headers: {
66830
+ ...buildHeaders(token),
66831
+ Accept: "text/event-stream"
66832
+ },
66833
+ body: JSON.stringify(body),
66834
+ signal: AbortSignal.timeout(COPILOT_STREAM_TIMEOUT)
66818
66835
  });
66836
+ if (!response2.ok) {
66837
+ throw new Error(`Copilot API error: ${response2.status} ${response2.statusText}`);
66838
+ }
66839
+ if (!response2.body) {
66840
+ throw new Error("No response body from Copilot stream");
66841
+ }
66842
+ const reader = response2.body.getReader();
66843
+ const decoder3 = new TextDecoder;
66819
66844
  let buffer = "";
66820
66845
  let doneReceived = false;
66821
- stream2.on("data", (data) => {
66822
- buffer += data.toString();
66823
- const lines = buffer.split(`
66846
+ try {
66847
+ while (true) {
66848
+ const { done, value } = await reader.read();
66849
+ if (done)
66850
+ break;
66851
+ buffer += decoder3.decode(value, { stream: true });
66852
+ const lines = buffer.split(`
66824
66853
  `);
66825
- buffer = lines.pop() ?? "";
66826
- for (const line of lines) {
66827
- if (processStreamLine(line, onChunk)) {
66828
- doneReceived = true;
66829
- return;
66854
+ buffer = lines.pop() ?? "";
66855
+ for (const line of lines) {
66856
+ if (processStreamLine(line, onChunk)) {
66857
+ doneReceived = true;
66858
+ return;
66859
+ }
66830
66860
  }
66831
66861
  }
66832
- });
66833
- stream2.on("error", (error2) => {
66834
- onChunk({ type: "error", error: error2.message });
66835
- reject(error2);
66836
- });
66837
- stream2.on("end", () => {
66838
- if (buffer.trim()) {
66839
- processStreamLine(buffer, onChunk);
66840
- }
66841
- if (!doneReceived) {
66842
- addDebugLog("api", "Stream ended without [DONE] message, sending done chunk");
66843
- onChunk({ type: "done" });
66844
- }
66845
- resolve3();
66846
- });
66847
- }), chatStream = async (messages, options2, onChunk) => {
66862
+ } finally {
66863
+ reader.releaseLock();
66864
+ }
66865
+ if (buffer.trim()) {
66866
+ processStreamLine(buffer, onChunk);
66867
+ }
66868
+ if (!doneReceived) {
66869
+ addDebugLog("api", "Stream ended without [DONE] message, sending done chunk");
66870
+ onChunk({ type: "done" });
66871
+ }
66872
+ }, chatStream = async (messages, options2, onChunk) => {
66848
66873
  addDebugLog("api", `Copilot stream request: ${messages.length} messages`);
66849
66874
  const token = await refreshToken();
66850
66875
  const endpoint = getEndpoint(token);
@@ -66874,6 +66899,12 @@ var formatMessages = (messages) => messages.map((msg) => {
66874
66899
  switchedToUnlimited = true;
66875
66900
  continue;
66876
66901
  }
66902
+ if (isConnectionError(error2) && attempt < COPILOT_MAX_RETRIES - 1) {
66903
+ const delay2 = COPILOT_CONNECTION_RETRY_DELAY * Math.pow(2, attempt);
66904
+ addDebugLog("api", `Connection error, retrying in ${delay2}ms (attempt ${attempt + 1})`);
66905
+ await sleep(delay2);
66906
+ continue;
66907
+ }
66877
66908
  if (isRateLimitError(error2) && attempt < COPILOT_MAX_RETRIES - 1) {
66878
66909
  const delay2 = getRetryDelay(error2, attempt);
66879
66910
  await sleep(delay2);
@@ -67247,57 +67278,61 @@ var parseStreamLine = (line, onChunk) => {
67247
67278
  onChunk({ type: "done" });
67248
67279
  }
67249
67280
  } catch {}
67250
- }, processStreamData = (data, buffer, onChunk) => {
67251
- const combined = buffer + data.toString();
67252
- const lines = combined.split(`
67253
- `);
67254
- const remaining = lines.pop() || "";
67255
- for (const line of lines) {
67256
- parseStreamLine(line, onChunk);
67257
- }
67258
- return remaining;
67259
67281
  }, ollamaChatStream = async (messages, options2, onChunk) => {
67260
67282
  const baseUrl = getOllamaBaseUrl();
67261
67283
  const body = buildChatRequest(messages, options2, true);
67262
67284
  addDebugLog("api", `Ollama stream request: ${messages.length} msgs, model=${body.model}`);
67263
- const stream2 = source_default2.stream.post(`${baseUrl}${OLLAMA_ENDPOINTS.CHAT}`, {
67264
- json: body,
67265
- timeout: { request: OLLAMA_TIMEOUTS.CHAT }
67285
+ const response2 = await fetch(`${baseUrl}${OLLAMA_ENDPOINTS.CHAT}`, {
67286
+ method: "POST",
67287
+ headers: { "Content-Type": "application/json" },
67288
+ body: JSON.stringify(body),
67289
+ signal: AbortSignal.timeout(OLLAMA_TIMEOUTS.CHAT)
67266
67290
  });
67291
+ if (!response2.ok) {
67292
+ throw new Error(`Ollama API error: ${response2.status} ${response2.statusText}`);
67293
+ }
67294
+ if (!response2.body) {
67295
+ throw new Error("No response body from Ollama stream");
67296
+ }
67297
+ const reader = response2.body.getReader();
67298
+ const decoder3 = new TextDecoder;
67267
67299
  let buffer = "";
67268
67300
  let doneReceived = false;
67269
- stream2.on("data", (data) => {
67270
- buffer = processStreamData(data, buffer, (chunk2) => {
67271
- if (chunk2.type === "done") {
67272
- doneReceived = true;
67273
- }
67274
- onChunk(chunk2);
67275
- });
67276
- });
67277
- stream2.on("error", (error2) => {
67278
- onChunk({ type: "error", error: error2.message });
67279
- });
67280
- return new Promise((resolve3, reject) => {
67281
- stream2.on("end", () => {
67282
- if (buffer.trim()) {
67283
- parseStreamLine(buffer, (chunk2) => {
67301
+ try {
67302
+ while (true) {
67303
+ const { done, value } = await reader.read();
67304
+ if (done)
67305
+ break;
67306
+ buffer += decoder3.decode(value, { stream: true });
67307
+ const lines = buffer.split(`
67308
+ `);
67309
+ buffer = lines.pop() ?? "";
67310
+ for (const line of lines) {
67311
+ parseStreamLine(line, (chunk2) => {
67284
67312
  if (chunk2.type === "done") {
67285
67313
  doneReceived = true;
67286
67314
  }
67287
67315
  onChunk(chunk2);
67288
67316
  });
67289
67317
  }
67290
- if (!doneReceived) {
67291
- addDebugLog("api", "Ollama stream ended without done, sending done chunk");
67292
- onChunk({ type: "done" });
67318
+ }
67319
+ } finally {
67320
+ reader.releaseLock();
67321
+ }
67322
+ if (buffer.trim()) {
67323
+ parseStreamLine(buffer, (chunk2) => {
67324
+ if (chunk2.type === "done") {
67325
+ doneReceived = true;
67293
67326
  }
67294
- resolve3();
67327
+ onChunk(chunk2);
67295
67328
  });
67296
- stream2.on("error", reject);
67297
- });
67329
+ }
67330
+ if (!doneReceived) {
67331
+ addDebugLog("api", "Ollama stream ended without done, sending done chunk");
67332
+ onChunk({ type: "done" });
67333
+ }
67298
67334
  };
67299
67335
  var init_stream2 = __esm(async () => {
67300
- init_source4();
67301
67336
  init_ollama();
67302
67337
  init_state2();
67303
67338
  init_chat2();
@@ -92500,56 +92535,58 @@ var activePlans, planListeners, COMPLEXITY_KEYWORDS, analyzeTask = (taskDescript
92500
92535
  return activePlans.get(planId);
92501
92536
  }, getActivePlans = () => {
92502
92537
  return Array.from(activePlans.values()).filter((p) => p.status !== "completed" && p.status !== "failed" && p.status !== "rejected");
92503
- }, formatPlanForDisplay = (plan) => {
92538
+ }, RISK_ICONS, formatPlanForDisplay = (plan) => {
92504
92539
  const lines = [];
92505
- lines.push(`# Implementation Plan: ${plan.title}`);
92540
+ lines.push(`Plan to implement`);
92541
+ lines.push("");
92542
+ lines.push(plan.title);
92506
92543
  lines.push("");
92507
- lines.push(`## Summary`);
92508
92544
  lines.push(plan.summary);
92509
92545
  lines.push("");
92510
92546
  if (plan.context.filesAnalyzed.length > 0) {
92511
- lines.push(`## Files Analyzed`);
92512
- plan.context.filesAnalyzed.forEach((f) => lines.push(`- ${f}`));
92547
+ lines.push("Files Analyzed");
92548
+ plan.context.filesAnalyzed.forEach((f) => lines.push(` ${f}`));
92513
92549
  lines.push("");
92514
92550
  }
92515
92551
  if (plan.context.currentArchitecture) {
92516
- lines.push(`## Current Architecture`);
92517
- lines.push(plan.context.currentArchitecture);
92552
+ lines.push("Current Architecture");
92553
+ lines.push(` ${plan.context.currentArchitecture}`);
92554
+ lines.push("");
92555
+ }
92556
+ if (plan.steps.length > 0) {
92557
+ lines.push("Implementation Steps");
92558
+ plan.steps.forEach((step, i2) => {
92559
+ const icon = RISK_ICONS[step.riskLevel] ?? " ";
92560
+ lines.push(` ${i2 + 1}. [${icon}] ${step.title}`);
92561
+ lines.push(` ${step.description}`);
92562
+ if (step.filesAffected.length > 0) {
92563
+ lines.push(` Files: ${step.filesAffected.join(", ")}`);
92564
+ }
92565
+ });
92518
92566
  lines.push("");
92519
92567
  }
92520
- lines.push(`## Implementation Steps`);
92521
- plan.steps.forEach((step, i2) => {
92522
- const riskIcon = step.riskLevel === "high" ? "⚠️" : step.riskLevel === "medium" ? "⚡" : "✓";
92523
- lines.push(`${i2 + 1}. ${riskIcon} **${step.title}**`);
92524
- lines.push(` ${step.description}`);
92525
- if (step.filesAffected.length > 0) {
92526
- lines.push(` Files: ${step.filesAffected.join(", ")}`);
92527
- }
92528
- });
92529
- lines.push("");
92530
92568
  if (plan.risks.length > 0) {
92531
- lines.push(`## Risks`);
92569
+ lines.push("Risks");
92532
92570
  plan.risks.forEach((risk) => {
92533
- lines.push(`- **${risk.impact.toUpperCase()}**: ${risk.description}`);
92534
- lines.push(` Mitigation: ${risk.mitigation}`);
92571
+ lines.push(` [${risk.impact.toUpperCase()}] ${risk.description}`);
92572
+ lines.push(` Mitigation: ${risk.mitigation}`);
92535
92573
  });
92536
92574
  lines.push("");
92537
92575
  }
92538
- lines.push(`## Testing Strategy`);
92539
- lines.push(plan.testingStrategy || "TBD");
92540
- lines.push("");
92541
- lines.push(`## Rollback Plan`);
92542
- lines.push(plan.rollbackPlan || "TBD");
92543
- lines.push("");
92544
- lines.push(`## Estimated Changes`);
92545
- lines.push(`- Files to create: ${plan.estimatedChanges.filesCreated}`);
92546
- lines.push(`- Files to modify: ${plan.estimatedChanges.filesModified}`);
92547
- lines.push(`- Files to delete: ${plan.estimatedChanges.filesDeleted}`);
92548
- lines.push("");
92549
- lines.push("---");
92550
- lines.push("**Awaiting approval to proceed with implementation.**");
92551
- lines.push("Reply with 'proceed', 'approve', or 'go ahead' to start execution.");
92552
- lines.push("Reply with 'stop', 'cancel', or provide feedback to modify the plan.");
92576
+ if (plan.testingStrategy) {
92577
+ lines.push("Testing Strategy");
92578
+ lines.push(` ${plan.testingStrategy}`);
92579
+ lines.push("");
92580
+ }
92581
+ if (plan.rollbackPlan) {
92582
+ lines.push("Rollback Plan");
92583
+ lines.push(` ${plan.rollbackPlan}`);
92584
+ lines.push("");
92585
+ }
92586
+ lines.push("Estimated Changes");
92587
+ lines.push(` Files to create: ${plan.estimatedChanges.filesCreated}`);
92588
+ lines.push(` Files to modify: ${plan.estimatedChanges.filesModified}`);
92589
+ lines.push(` Files to delete: ${plan.estimatedChanges.filesDeleted}`);
92553
92590
  return lines.join(`
92554
92591
  `);
92555
92592
  }, isApprovalMessage = (message) => {
@@ -92607,6 +92644,11 @@ var init_plan_service = __esm(() => {
92607
92644
  "module"
92608
92645
  ]
92609
92646
  };
92647
+ RISK_ICONS = {
92648
+ high: "!",
92649
+ medium: "~",
92650
+ low: " "
92651
+ };
92610
92652
  });
92611
92653
 
92612
92654
  // src/tools/plan-approval/execute.ts
@@ -93906,14 +93948,14 @@ var serviceState, callOllamaEmbed = async (texts, model) => {
93906
93948
  }
93907
93949
  } catch (error49) {
93908
93950
  const message = error49 instanceof Error ? error49.message : String(error49);
93909
- const isConnectionError = message.includes("ECONNREFUSED") || message.includes("connect");
93951
+ const isConnectionError2 = message.includes("ECONNREFUSED") || message.includes("connect");
93910
93952
  serviceState = {
93911
93953
  initialized: true,
93912
93954
  model: null,
93913
93955
  available: false,
93914
93956
  error: {
93915
- code: isConnectionError ? "OLLAMA_NOT_RUNNING" : "EMBEDDING_FAILED",
93916
- message: isConnectionError ? "Ollama is not running. Start it with: ollama serve" : `Embedding service error: ${message}`
93957
+ code: isConnectionError2 ? "OLLAMA_NOT_RUNNING" : "EMBEDDING_FAILED",
93958
+ message: isConnectionError2 ? "Ollama is not running. Start it with: ollama serve" : `Embedding service error: ${message}`
93917
93959
  }
93918
93960
  };
93919
93961
  }
@@ -104147,6 +104189,9 @@ var initializeChatService = async (options2) => {
104147
104189
  initializeBrain().catch(() => {});
104148
104190
  return { state: state4, session };
104149
104191
  };
104192
+ // src/services/chat-tui/message-handler.ts
104193
+ init_dist_node();
104194
+
104150
104195
  // src/services/agent-stream.ts
104151
104196
  init_dist_node();
104152
104197
  init_tools3();
@@ -107321,6 +107366,46 @@ ${commentsContext}` : ""}`;
107321
107366
  callbacks.onLog("system", formatted);
107322
107367
  }
107323
107368
  }
107369
+ const newPendingPlans = getActivePlans().filter((p) => p.status === "pending");
107370
+ if (newPendingPlans.length > 0) {
107371
+ const plan = newPendingPlans[0];
107372
+ const planContent = formatPlanForDisplay(plan);
107373
+ addDebugLog("state", `Showing plan approval modal: ${plan.id}`);
107374
+ await new Promise((resolve4) => {
107375
+ appStore.setMode("plan_approval");
107376
+ appStore.setPlanApprovalPrompt({
107377
+ id: v4_default(),
107378
+ planTitle: plan.title,
107379
+ planSummary: plan.summary,
107380
+ planContent,
107381
+ resolve: (response2) => {
107382
+ appStore.setPlanApprovalPrompt(null);
107383
+ if (response2.approved) {
107384
+ approvePlan(plan.id, response2.editMode);
107385
+ startPlanExecution(plan.id);
107386
+ addDebugLog("state", `Plan ${plan.id} approved via modal`);
107387
+ appStore.addLog({
107388
+ type: "system",
107389
+ content: `Plan "${plan.title}" approved. Proceeding with implementation.`
107390
+ });
107391
+ state4.messages.push({
107392
+ role: "user",
107393
+ content: `The user approved the plan. Proceed with the implementation of plan "${plan.title}".`
107394
+ });
107395
+ } else {
107396
+ rejectPlan(plan.id, response2.feedback ?? "User cancelled");
107397
+ addDebugLog("state", `Plan ${plan.id} rejected via modal`);
107398
+ appStore.addLog({
107399
+ type: "system",
107400
+ content: `Plan "${plan.title}" cancelled.`
107401
+ });
107402
+ }
107403
+ appStore.setMode("idle");
107404
+ resolve4();
107405
+ }
107406
+ });
107407
+ });
107408
+ }
107324
107409
  } catch (error49) {
107325
107410
  appStore.cancelStreaming();
107326
107411
  appStore.stopThinking();
@@ -113297,92 +113382,106 @@ function PlanApprovalModal(props) {
113297
113382
  }
113298
113383
  });
113299
113384
  return (() => {
113300
- var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text");
113301
- insertNode(_el$, _el$2);
113385
+ var _el$ = createElement("box"), _el$8 = createElement("box"), _el$9 = createElement("text");
113386
+ insertNode(_el$, _el$8);
113302
113387
  setProp(_el$, "flexDirection", "column");
113303
113388
  setProp(_el$, "border", ["top", "bottom", "left", "right"]);
113304
113389
  setProp(_el$, "paddingLeft", 2);
113305
113390
  setProp(_el$, "paddingRight", 2);
113306
113391
  setProp(_el$, "paddingTop", 1);
113307
113392
  setProp(_el$, "paddingBottom", 1);
113308
- insertNode(_el$2, _el$3);
113309
- setProp(_el$2, "marginBottom", 1);
113310
- insertNode(_el$3, createTextNode(`CodeTyper has written up a plan and is ready to execute. Would you like to proceed?`));
113311
113393
  insert(_el$, createComponent2(Show, {
113312
113394
  get when() {
113313
- return props.prompt.planTitle;
113395
+ return props.prompt.planContent;
113314
113396
  },
113315
113397
  get children() {
113316
- var _el$5 = createElement("box"), _el$6 = createElement("text");
113317
- insertNode(_el$5, _el$6);
113318
- setProp(_el$5, "marginBottom", 1);
113319
- insert(_el$6, () => props.prompt.planTitle);
113398
+ var _el$2 = createElement("box"), _el$3 = createElement("text");
113399
+ insertNode(_el$2, _el$3);
113400
+ setProp(_el$2, "marginBottom", 1);
113401
+ setProp(_el$2, "flexDirection", "column");
113402
+ insert(_el$3, () => props.prompt.planContent);
113403
+ effect((_$p) => setProp(_el$3, "fg", theme.colors.text, _$p));
113404
+ return _el$2;
113405
+ }
113406
+ }), _el$8);
113407
+ insert(_el$, createComponent2(Show, {
113408
+ get when() {
113409
+ return memo2(() => !!!props.prompt.planContent)() && props.prompt.planTitle;
113410
+ },
113411
+ get children() {
113412
+ var _el$4 = createElement("box"), _el$5 = createElement("text");
113413
+ insertNode(_el$4, _el$5);
113414
+ setProp(_el$4, "marginBottom", 1);
113415
+ insert(_el$5, () => props.prompt.planTitle);
113320
113416
  effect((_p$) => {
113321
113417
  var _v$ = theme.colors.text, _v$2 = TextAttributes.BOLD;
113322
- _v$ !== _p$.e && (_p$.e = setProp(_el$6, "fg", _v$, _p$.e));
113323
- _v$2 !== _p$.t && (_p$.t = setProp(_el$6, "attributes", _v$2, _p$.t));
113418
+ _v$ !== _p$.e && (_p$.e = setProp(_el$5, "fg", _v$, _p$.e));
113419
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$5, "attributes", _v$2, _p$.t));
113324
113420
  return _p$;
113325
113421
  }, {
113326
113422
  e: undefined,
113327
113423
  t: undefined
113328
113424
  });
113329
- return _el$5;
113425
+ return _el$4;
113330
113426
  }
113331
- }), null);
113427
+ }), _el$8);
113332
113428
  insert(_el$, createComponent2(Show, {
113333
113429
  get when() {
113334
- return props.prompt.planSummary;
113430
+ return memo2(() => !!!props.prompt.planContent)() && props.prompt.planSummary;
113335
113431
  },
113336
113432
  get children() {
113337
- var _el$7 = createElement("box"), _el$8 = createElement("text");
113338
- insertNode(_el$7, _el$8);
113339
- setProp(_el$7, "marginBottom", 1);
113340
- insert(_el$8, () => props.prompt.planSummary);
113341
- effect((_$p) => setProp(_el$8, "fg", theme.colors.textDim, _$p));
113342
- return _el$7;
113433
+ var _el$6 = createElement("box"), _el$7 = createElement("text");
113434
+ insertNode(_el$6, _el$7);
113435
+ setProp(_el$6, "marginBottom", 1);
113436
+ insert(_el$7, () => props.prompt.planSummary);
113437
+ effect((_$p) => setProp(_el$7, "fg", theme.colors.textDim, _$p));
113438
+ return _el$6;
113343
113439
  }
113344
- }), null);
113440
+ }), _el$8);
113441
+ insertNode(_el$8, _el$9);
113442
+ setProp(_el$8, "marginBottom", 1);
113443
+ insertNode(_el$9, createTextNode(`Would you like to proceed with this plan?`));
113345
113444
  insert(_el$, createComponent2(Show, {
113346
113445
  get when() {
113347
113446
  return !feedbackMode();
113348
113447
  },
113349
113448
  get children() {
113350
- var _el$9 = createElement("box");
113351
- setProp(_el$9, "flexDirection", "column");
113352
- setProp(_el$9, "marginTop", 1);
113353
- insert(_el$9, createComponent2(For, {
113449
+ var _el$1 = createElement("box");
113450
+ setProp(_el$1, "flexDirection", "column");
113451
+ setProp(_el$1, "marginTop", 1);
113452
+ insert(_el$1, createComponent2(For, {
113354
113453
  each: PLAN_APPROVAL_OPTIONS,
113355
113454
  children: (option, index) => {
113356
113455
  const isSelected = () => index() === selectedIndex();
113357
113456
  return (() => {
113358
- var _el$23 = createElement("box"), _el$24 = createElement("text"), _el$25 = createElement("text"), _el$26 = createTextNode(`. `), _el$27 = createElement("text");
113359
- insertNode(_el$23, _el$24);
113360
- insertNode(_el$23, _el$25);
113361
- insertNode(_el$23, _el$27);
113362
- setProp(_el$23, "flexDirection", "row");
113363
- insert(_el$24, () => isSelected() ? "> " : " ");
113457
+ var _el$25 = createElement("box"), _el$26 = createElement("text"), _el$27 = createElement("text"), _el$28 = createTextNode(`. `), _el$29 = createElement("text");
113364
113458
  insertNode(_el$25, _el$26);
113365
- insert(_el$25, () => option.key, _el$26);
113366
- insert(_el$27, () => option.label);
113367
- insert(_el$23, createComponent2(Show, {
113459
+ insertNode(_el$25, _el$27);
113460
+ insertNode(_el$25, _el$29);
113461
+ setProp(_el$25, "flexDirection", "row");
113462
+ insert(_el$26, () => isSelected() ? "> " : " ");
113463
+ insertNode(_el$27, _el$28);
113464
+ insert(_el$27, () => option.key, _el$28);
113465
+ insert(_el$29, () => option.label);
113466
+ insert(_el$25, createComponent2(Show, {
113368
113467
  get when() {
113369
113468
  return option.shortcut;
113370
113469
  },
113371
113470
  get children() {
113372
- var _el$28 = createElement("text"), _el$29 = createTextNode(` (`), _el$31 = createTextNode(`)`);
113373
- insertNode(_el$28, _el$29);
113374
- insertNode(_el$28, _el$31);
113375
- insert(_el$28, () => option.shortcut, _el$31);
113376
- effect((_$p) => setProp(_el$28, "fg", theme.colors.textMuted, _$p));
113377
- return _el$28;
113471
+ var _el$30 = createElement("text"), _el$31 = createTextNode(` (`), _el$33 = createTextNode(`)`);
113472
+ insertNode(_el$30, _el$31);
113473
+ insertNode(_el$30, _el$33);
113474
+ insert(_el$30, () => option.shortcut, _el$33);
113475
+ effect((_$p) => setProp(_el$30, "fg", theme.colors.textMuted, _$p));
113476
+ return _el$30;
113378
113477
  }
113379
113478
  }), null);
113380
113479
  effect((_p$) => {
113381
113480
  var _v$10 = isSelected() ? theme.colors.primary : theme.colors.textDim, _v$11 = isSelected() ? TextAttributes.BOLD : TextAttributes.NONE, _v$12 = theme.colors.textDim, _v$13 = isSelected() ? theme.colors.text : theme.colors.textDim;
113382
- _v$10 !== _p$.e && (_p$.e = setProp(_el$24, "fg", _v$10, _p$.e));
113383
- _v$11 !== _p$.t && (_p$.t = setProp(_el$24, "attributes", _v$11, _p$.t));
113384
- _v$12 !== _p$.a && (_p$.a = setProp(_el$25, "fg", _v$12, _p$.a));
113385
- _v$13 !== _p$.o && (_p$.o = setProp(_el$27, "fg", _v$13, _p$.o));
113481
+ _v$10 !== _p$.e && (_p$.e = setProp(_el$26, "fg", _v$10, _p$.e));
113482
+ _v$11 !== _p$.t && (_p$.t = setProp(_el$26, "attributes", _v$11, _p$.t));
113483
+ _v$12 !== _p$.a && (_p$.a = setProp(_el$27, "fg", _v$12, _p$.a));
113484
+ _v$13 !== _p$.o && (_p$.o = setProp(_el$29, "fg", _v$13, _p$.o));
113386
113485
  return _p$;
113387
113486
  }, {
113388
113487
  e: undefined,
@@ -113390,11 +113489,11 @@ function PlanApprovalModal(props) {
113390
113489
  a: undefined,
113391
113490
  o: undefined
113392
113491
  });
113393
- return _el$23;
113492
+ return _el$25;
113394
113493
  })();
113395
113494
  }
113396
113495
  }));
113397
- return _el$9;
113496
+ return _el$1;
113398
113497
  }
113399
113498
  }), null);
113400
113499
  insert(_el$, createComponent2(Show, {
@@ -113402,28 +113501,28 @@ function PlanApprovalModal(props) {
113402
113501
  return feedbackMode();
113403
113502
  },
113404
113503
  get children() {
113405
- var _el$0 = createElement("box"), _el$1 = createElement("text"), _el$11 = createElement("box"), _el$12 = createElement("text"), _el$13 = createElement("text"), _el$15 = createElement("text");
113406
- insertNode(_el$0, _el$1);
113407
- insertNode(_el$0, _el$11);
113408
- insertNode(_el$0, _el$15);
113409
- setProp(_el$0, "flexDirection", "column");
113410
- setProp(_el$0, "marginTop", 1);
113411
- insertNode(_el$1, createTextNode(`Tell CodeTyper what to change:`));
113412
- insertNode(_el$11, _el$12);
113413
- setProp(_el$11, "border", ["left"]);
113414
- setProp(_el$11, "paddingLeft", 1);
113415
- setProp(_el$11, "marginTop", 1);
113416
- insertNode(_el$12, _el$13);
113417
- insert(_el$12, () => feedbackText() || " ", _el$13);
113418
- insertNode(_el$13, createTextNode(`_`));
113419
- insertNode(_el$15, createTextNode(`Enter to submit | Esc to cancel`));
113504
+ var _el$10 = createElement("box"), _el$11 = createElement("text"), _el$13 = createElement("box"), _el$14 = createElement("text"), _el$15 = createElement("text"), _el$17 = createElement("text");
113505
+ insertNode(_el$10, _el$11);
113506
+ insertNode(_el$10, _el$13);
113507
+ insertNode(_el$10, _el$17);
113508
+ setProp(_el$10, "flexDirection", "column");
113509
+ setProp(_el$10, "marginTop", 1);
113510
+ insertNode(_el$11, createTextNode(`Tell CodeTyper what to change:`));
113511
+ insertNode(_el$13, _el$14);
113512
+ setProp(_el$13, "border", ["left"]);
113513
+ setProp(_el$13, "paddingLeft", 1);
113514
+ setProp(_el$13, "marginTop", 1);
113515
+ insertNode(_el$14, _el$15);
113516
+ insert(_el$14, () => feedbackText() || " ", _el$15);
113517
+ insertNode(_el$15, createTextNode(`_`));
113518
+ insertNode(_el$17, createTextNode(`Enter to submit | Esc to cancel`));
113420
113519
  effect((_p$) => {
113421
113520
  var _v$3 = theme.colors.text, _v$4 = theme.colors.borderFocus, _v$5 = theme.colors.text, _v$6 = theme.colors.bgCursor, _v$7 = theme.colors.textDim;
113422
- _v$3 !== _p$.e && (_p$.e = setProp(_el$1, "fg", _v$3, _p$.e));
113423
- _v$4 !== _p$.t && (_p$.t = setProp(_el$11, "borderColor", _v$4, _p$.t));
113424
- _v$5 !== _p$.a && (_p$.a = setProp(_el$12, "fg", _v$5, _p$.a));
113425
- _v$6 !== _p$.o && (_p$.o = setProp(_el$13, "fg", _v$6, _p$.o));
113426
- _v$7 !== _p$.i && (_p$.i = setProp(_el$15, "fg", _v$7, _p$.i));
113521
+ _v$3 !== _p$.e && (_p$.e = setProp(_el$11, "fg", _v$3, _p$.e));
113522
+ _v$4 !== _p$.t && (_p$.t = setProp(_el$13, "borderColor", _v$4, _p$.t));
113523
+ _v$5 !== _p$.a && (_p$.a = setProp(_el$14, "fg", _v$5, _p$.a));
113524
+ _v$6 !== _p$.o && (_p$.o = setProp(_el$15, "fg", _v$6, _p$.o));
113525
+ _v$7 !== _p$.i && (_p$.i = setProp(_el$17, "fg", _v$7, _p$.i));
113427
113526
  return _p$;
113428
113527
  }, {
113429
113528
  e: undefined,
@@ -113432,7 +113531,7 @@ function PlanApprovalModal(props) {
113432
113531
  o: undefined,
113433
113532
  i: undefined
113434
113533
  });
113435
- return _el$0;
113534
+ return _el$10;
113436
113535
  }
113437
113536
  }), null);
113438
113537
  insert(_el$, createComponent2(Show, {
@@ -113440,42 +113539,42 @@ function PlanApprovalModal(props) {
113440
113539
  return !feedbackMode();
113441
113540
  },
113442
113541
  get children() {
113443
- var _el$17 = createElement("box");
113444
- setProp(_el$17, "marginTop", 1);
113445
- setProp(_el$17, "flexDirection", "row");
113446
- insert(_el$17, createComponent2(Show, {
113542
+ var _el$19 = createElement("box");
113543
+ setProp(_el$19, "marginTop", 1);
113544
+ setProp(_el$19, "flexDirection", "row");
113545
+ insert(_el$19, createComponent2(Show, {
113447
113546
  get when() {
113448
113547
  return props.prompt.planFilePath;
113449
113548
  },
113450
113549
  get children() {
113451
- var _el$18 = createElement("text"), _el$19 = createTextNode(` - `);
113452
- insertNode(_el$18, _el$19);
113453
- insert(_el$18, PLAN_APPROVAL_FOOTER_TEXT, _el$19);
113454
- insert(_el$18, () => props.prompt.planFilePath, null);
113455
- effect((_$p) => setProp(_el$18, "fg", theme.colors.textDim, _$p));
113456
- return _el$18;
113550
+ var _el$20 = createElement("text"), _el$21 = createTextNode(` - `);
113551
+ insertNode(_el$20, _el$21);
113552
+ insert(_el$20, PLAN_APPROVAL_FOOTER_TEXT, _el$21);
113553
+ insert(_el$20, () => props.prompt.planFilePath, null);
113554
+ effect((_$p) => setProp(_el$20, "fg", theme.colors.textDim, _$p));
113555
+ return _el$20;
113457
113556
  }
113458
113557
  }), null);
113459
- insert(_el$17, createComponent2(Show, {
113558
+ insert(_el$19, createComponent2(Show, {
113460
113559
  get when() {
113461
113560
  return !props.prompt.planFilePath;
113462
113561
  },
113463
113562
  get children() {
113464
- var _el$20 = createElement("text"), _el$21 = createTextNode(`↑↓ options | Enter select | 1-4 shortcut | Esc cancel`);
113465
- insertNode(_el$20, _el$21);
113466
- effect((_$p) => setProp(_el$20, "fg", theme.colors.textDim, _$p));
113467
- return _el$20;
113563
+ var _el$22 = createElement("text"), _el$23 = createTextNode(`↑↓ options | Enter select | 1-4 shortcut | Esc cancel`);
113564
+ insertNode(_el$22, _el$23);
113565
+ effect((_$p) => setProp(_el$22, "fg", theme.colors.textDim, _$p));
113566
+ return _el$22;
113468
113567
  }
113469
113568
  }), null);
113470
- return _el$17;
113569
+ return _el$19;
113471
113570
  }
113472
113571
  }), null);
113473
113572
  effect((_p$) => {
113474
113573
  var _v$8 = theme.colors.borderModal, _v$9 = theme.colors.background, _v$0 = theme.colors.primary, _v$1 = TextAttributes.BOLD;
113475
113574
  _v$8 !== _p$.e && (_p$.e = setProp(_el$, "borderColor", _v$8, _p$.e));
113476
113575
  _v$9 !== _p$.t && (_p$.t = setProp(_el$, "backgroundColor", _v$9, _p$.t));
113477
- _v$0 !== _p$.a && (_p$.a = setProp(_el$3, "fg", _v$0, _p$.a));
113478
- _v$1 !== _p$.o && (_p$.o = setProp(_el$3, "attributes", _v$1, _p$.o));
113576
+ _v$0 !== _p$.a && (_p$.a = setProp(_el$9, "fg", _v$0, _p$.a));
113577
+ _v$1 !== _p$.o && (_p$.o = setProp(_el$9, "attributes", _v$1, _p$.o));
113479
113578
  return _p$;
113480
113579
  }, {
113481
113580
  e: undefined,
@@ -115680,6 +115779,10 @@ function AppContent(props) {
115680
115779
  props.onPermissionResponse(allowed, scope);
115681
115780
  };
115682
115781
  const handlePlanApprovalResponse = (response2) => {
115782
+ const prompt2 = app.planApprovalPrompt();
115783
+ if (prompt2?.resolve) {
115784
+ prompt2.resolve(response2);
115785
+ }
115683
115786
  props.onPlanApprovalResponse(response2);
115684
115787
  };
115685
115788
  const handleLearningResponse = (save, scope, editedContent) => {
@@ -117123,4 +117226,4 @@ ${plan.steps.map((s) => `${s.id}. ${s.description}`).join(`
117123
117226
  });
117124
117227
  program2.parse(process.argv);
117125
117228
 
117126
- //# debugId=916DA4C2FBA06B5A64756E2164756E21
117229
+ //# debugId=07E4A86E6DD680D764756E2164756E21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codetyper-cli",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "CodeTyper AI Agent - Standalone CLI for autonomous code generation",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -10,9 +10,6 @@
10
10
  "scripts": {
11
11
  "dev": "bun src/index.ts",
12
12
  "dev:nobump": "bun scripts/build.ts && npm link",
13
- "dev:watch": "bun scripts/dev-watch.ts",
14
- "dev:debug": "bun --inspect=localhost:6499/debug src/index.ts",
15
- "dev:debug-brk": "bun --inspect-brk=localhost:6499/debug src/index.ts",
16
13
  "build": "bun scripts/build.ts",
17
14
  "sync-version": "bun scripts/sync-version.ts",
18
15
  "start": "bun src/index.ts",
@@ -20,7 +17,8 @@
20
17
  "lint": "bun eslint src/**/*.ts",
21
18
  "format": "npx prettier --write \"src/**/*.ts\"",
22
19
  "prettier": "npx prettier --write \"src/**/*.ts\" \"src/**/*.tsx\" \"scripts/**/*.ts\"",
23
- "typecheck": "bun tsc --noEmit"
20
+ "typecheck": "bun tsc --noEmit",
21
+ "version": "bun scripts/sync-version.ts && git add src/version.json"
24
22
  },
25
23
  "keywords": [
26
24
  "ai",
@@ -78,13 +76,13 @@
78
76
  },
79
77
  "devDependencies": {
80
78
  "@eslint/eslintrc": "^3.3.3",
81
- "@eslint/js": "^9.39.2",
79
+ "@eslint/js": "^10.0.1",
82
80
  "@types/inquirer": "^9.0.7",
83
81
  "@types/node": "^25.0.10",
84
82
  "@types/uuid": "^10.0.0",
85
83
  "@typescript-eslint/eslint-plugin": "^8.53.1",
86
84
  "@typescript-eslint/parser": "^8.53.1",
87
- "eslint": "^9.39.2",
85
+ "eslint": "^10.0.0",
88
86
  "eslint-config-standard": "^17.1.0",
89
87
  "eslint-config-standard-with-typescript": "^43.0.1",
90
88
  "eslint-plugin-import": "^2.32.0",
package/src/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.4.2"
2
+ "version": "0.4.3"
3
3
  }