miii-agent 0.1.30 โ†’ 0.1.31

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.
Files changed (3) hide show
  1. package/README.md +58 -11
  2. package/dist/cli.js +89 -23
  3. package/package.json +10 -3
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
- <h1 align="center">miii</h1>
1
+ <h1 align="center">miii โ€” Local AI Coding Agent for Your Terminal</h1>
2
2
 
3
3
  <p align="center">
4
- <strong>Cursor / Claude Code, but local.</strong><br>
5
- An offline AI pair-programmer in your terminal, powered by Ollama.<br>
6
- Private by default. Free forever.
4
+ <strong>An open-source, offline alternative to Claude Code, Cursor, and GitHub Copilot.</strong><br>
5
+ A private AI pair-programmer in your terminal, powered by Ollama and any local LLM.<br>
6
+ Private by default. Free forever. Works offline.
7
7
  </p>
8
8
 
9
9
  <p align="center">
@@ -15,26 +15,41 @@
15
15
  </p>
16
16
 
17
17
  <p align="center">
18
- <img src="demo3.gif" alt="miii demo">
18
+ <img src="demo3.gif" alt="miii local AI coding agent terminal demo powered by Ollama">
19
+ </p>
20
+
21
+ <p align="center">
22
+ ๐Ÿ”’ <strong>100% local</strong> โ€” your code never leaves your machine &nbsp;ยท&nbsp;
23
+ ๐Ÿ’ธ <strong>Free</strong> โ€” no API keys, no per-token billing &nbsp;ยท&nbsp;
24
+ โšก <strong>Offline</strong> โ€” runs on your own GPU
19
25
  </p>
20
26
 
21
27
  ---
22
28
 
23
- ## What is this?
29
+ ## What is miii? โ€” a local AI coding agent
24
30
 
25
31
  miii lives in your terminal and codes alongside you โ€” reading files, writing features, running tests, fixing bugs. The twist: it runs on **your** hardware, powered by [Ollama](https://ollama.com) (or any local OpenAI-compatible server like [llama.cpp](https://github.com/ggml-org/llama.cpp) / [LM Studio](https://lmstudio.ai)).
26
32
 
27
- Your code never leaves your disk. There's nothing to log in to. Pull a model, type `miii`, go.
33
+ Your code never leaves your disk. There's nothing to log in to. Pull a model, type `miii`, go. It's the open-source, offline answer to cloud coding assistants like Claude Code, Cursor, and GitHub Copilot.
28
34
 
29
- ## Try it in 30 seconds
35
+ ## Install (macOS, Linux, Windows)
30
36
 
31
37
  **macOS / Linux:**
32
38
 
33
39
  ```bash
34
40
  ollama pull qwen2.5-coder:14b # any coding model works
41
+ ```
42
+
43
+ **Which model should I use?**
44
+ - **Low VRAM (8GB):** `qwen2.5-coder:7b` (Fast, capable)
45
+ - **Mid VRAM (16-24GB):** `qwen2.5-coder:14b` (Sweet spot)
46
+ - **High VRAM (48GB+):** `qwen2.5-coder:32b` (Powerhouse)
47
+
48
+ ```bash
35
49
  curl -fsSL https://raw.githubusercontent.com/maruakshay/miii-cli/main/install.sh | sh
36
50
  miii
37
51
  ```
52
+ *(The installer downloads the pre-compiled binary and adds it to your local path)*
38
53
 
39
54
  **Windows (PowerShell):**
40
55
 
@@ -77,7 +92,7 @@ miii --version # what you're running
77
92
  Opt out of background updates by adding `"autoUpdate": false` to `~/.miii/config.json`,
78
93
  or re-run the install script (`curl โ€ฆ | sh`) any time to update by hand.
79
94
 
80
- ## Why local-first?
95
+ ## Why local-first? Private, free, offline
81
96
 
82
97
  Most "AI coding tools" are just wrappers around a cloud API โ€” slow, metered, and they ship your private codebase to someone else's server.
83
98
 
@@ -89,13 +104,16 @@ Most "AI coding tools" are just wrappers around a cloud API โ€” slow, metered, a
89
104
  | Offline | No | Yes |
90
105
  | Latency | Network + queue | Your GPU only |
91
106
 
92
- It doesn't just chat, either โ€” it decomposes the problem, calls tools, and checks its own work before claiming victory.
107
+ It doesn't just chat, either โ€” it follows a **Plan $\rightarrow$ Act $\rightarrow$ Observe** loop:
108
+ 1. **Plan**: Decomposes the problem into a sequence of concrete steps.
109
+ 2. **Act**: Calls the necessary tools to gather context or modify code.
110
+ 3. **Observe**: Verifies the result and adjusts the plan until the goal is met.
93
111
 
94
112
  ## Five letters, five ideas
95
113
 
96
114
  **s**mall ยท **s**imple ยท **s**mart ยท **s**trategic ยท **s**emantic โ€” a tiny codebase you can read in an afternoon, no config ceremony, plans before it acts, and operates on the *meaning* of your code, not blind text matching.
97
115
 
98
- ## A few things that make it fun
116
+ ## Features
99
117
 
100
118
  - **๐Ÿงช `miii doctor`** โ€” not every local model can drive an agent. Doctor runs your models through real engineering tasks and tells you which ones actually deliver.
101
119
  ```bash
@@ -189,6 +207,15 @@ The model pages through the middle with ranged `read_file` reads. Spill files ar
189
207
  <details>
190
208
  <summary><strong>Development</strong></summary>
191
209
 
210
+ **Project Architecture:**
211
+ ```text
212
+ src/
213
+ โ”œโ”€โ”€ agent/ # The core reasoning loop
214
+ โ”œโ”€โ”€ tools/ # Implementation of read/write/bash
215
+ โ”œโ”€โ”€ terminal/ # UI and input handling
216
+ โ””โ”€โ”€ config/ # Settings and provider logic
217
+ ```
218
+
192
219
  ```bash
193
220
  git clone https://github.com/maruakshay/miii-cli.git
194
221
  cd miii-cli
@@ -211,6 +238,26 @@ npm run build && npm link # restore later with: npm install -g miii-agent
211
238
 
212
239
  ---
213
240
 
241
+ ## FAQ
242
+
243
+ **Does miii work without internet?**
244
+ Yes. Once you've pulled a model with Ollama, miii runs fully offline. No network calls, no account, no cloud.
245
+
246
+ **Is my code sent anywhere?**
247
+ No. Every file read, edit, and model inference happens on your machine. Your codebase never leaves your disk.
248
+
249
+ **Which model is best for coding?**
250
+ Depends on VRAM: `qwen2.5-coder:7b` (8GB), `qwen2.5-coder:14b` (16โ€“24GB, the sweet spot), `qwen2.5-coder:32b` (48GB+). Run `miii doctor` to grade your installed models on real engineering tasks.
251
+
252
+ **How is miii different from Claude Code, Cursor, or GitHub Copilot?**
253
+ Claude Code, Cursor, and Copilot are cloud services โ€” metered, account-gated, and they ship your code to a third-party server. miii is open-source, free, and runs entirely on your hardware. Same terminal-agent workflow as Claude Code, but on your own local model.
254
+
255
+ **How is it different from Continue.dev?**
256
+ Continue.dev is an IDE extension. miii is a standalone terminal agent โ€” no editor required โ€” with a Plan โ†’ Act โ†’ Observe loop, permission-gated tools, and lossless output spill built in.
257
+
258
+ **Do I need a GPU?**
259
+ No, but it helps. Smaller models run on CPU; a GPU makes larger models fast enough for real work.
260
+
214
261
  ## Status
215
262
 
216
263
  **MVP.** Core agent loop is stable; actively refining tool execution, streaming, and the permission model. PRs welcome โ€” fork it, break it, improve it.
package/dist/cli.js CHANGED
@@ -1445,6 +1445,7 @@ Ask in a numbered list. One round of questions per turn. Then wait.
1445
1445
  - After a tool result, move directly to the next tool call or the final answer. Do not restate what the previous tool did.
1446
1446
  - Every tool call MUST carry a complete, valid arguments object: all required fields present, correct types, valid JSON. Never emit a call with empty, partial, or placeholder arguments.
1447
1447
  - WRONG (leaks as text, nothing runs): writing \`call:some_tool{"foo":"bar"}\` or a fenced JSON block in your reply. RIGHT: emit it as a native function call with a full arguments object.
1448
+ - Batch independent tool calls in a SINGLE turn \u2014 parallel, not serial. If two reads, greps, or searches do not depend on each other's output, emit them together. Only serialize when a later call needs an earlier result.
1448
1449
 
1449
1450
  # Tools
1450
1451
  You have access to the following tools. Call them via the function-calling interface.
@@ -1454,14 +1455,33 @@ ${toolLines}
1454
1455
  - When you need to act on the filesystem or run a command, emit a tool call.
1455
1456
  - After each tool result, decide: more tool calls, or a final plain-text answer.
1456
1457
  - Stop emitting tool calls when GOAL is met. Reply with a concise plain-text final message confirming CRITERION is satisfied.
1458
+ - After the work is done, always close by asking the user what they want to do next \u2014 a brief, specific prompt (offer the most likely follow-ups when obvious). One line, no filler.
1457
1459
 
1458
1460
  # Rules
1459
1461
  - Always read a file before updating it. Never edit, overwrite, or create-over a file you have not read first this turn.
1460
1462
  - Prefer editing existing files over creating new ones.
1463
+ - To change an existing file, use edit_file with a small, targeted old_str/new_str diff \u2014 never rewrite the whole file with write_file. Reserve write_file for brand-new files or small ones. A full-file write_file on a large file risks getting cut off at the output token limit mid-write; a targeted edit_file stays small and avoids that.
1464
+ - When a new file's content is large, create it with write_file for the first portion, then append the rest with successive edit_file calls. Keep every write small.
1461
1465
  - For edit_file, make old_str unique by including surrounding context, or set replace_all to change every occurrence.
1462
1466
  - Never invent file paths. Read, glob, or grep before editing.
1463
1467
  - No empty filler or robotic boilerplate. A brief, genuine warm touch (see Tone and voice) is welcome; hollow pleasantries and reflexive apologies are not.
1464
1468
 
1469
+ # Scope discipline
1470
+ - Do ONLY what the user asked. No unrequested refactors, renames, reformatting, or "while I'm here" edits.
1471
+ - If you spot an unrelated issue worth fixing, mention it in your final message \u2014 do not fix it unprompted.
1472
+ - Touch the fewest files needed. A one-line request gets a one-line change, not a redesign.
1473
+
1474
+ # Secrets and safety
1475
+ - Never print, log, or echo secrets, API keys, tokens, passwords, or \`.env\` values. Redact them if you must reference one.
1476
+ - Never write credentials into source, commits, or output. If a secret is needed, read it from the environment or config.
1477
+ - Do not exfiltrate file contents to external services without the user asking.
1478
+
1479
+ # Git and commits
1480
+ - Do NOT commit, push, or create branches/PRs unless the user explicitly asks.
1481
+ - When asked to commit: never commit on the main branch \u2014 branch first. Stage only files relevant to the change; never blanket \`git add -A\` without checking what it sweeps in.
1482
+ - Write a concise commit message stating what changed and why. Do not add credentials or generated noise.
1483
+ - Never force-push, rebase shared history, or run destructive git commands without explicit confirmation.
1484
+
1465
1485
  # Context discipline
1466
1486
  - read_file returns line numbers and accepts offset/limit. For large files, grep or glob to the relevant region first, then read only that range with offset/limit. Do not read a whole large file when you need a few functions \u2014 it wastes the context window.
1467
1487
  - Reference code by the line numbers read_file returns.
@@ -2298,7 +2318,7 @@ var InputBar = memo(function InputBar2({ input, caret, disabled, processingLabel
2298
2318
  const [frame, setFrame] = useState(0);
2299
2319
  useEffect(() => {
2300
2320
  if (!disabled) return;
2301
- const t = setInterval(() => setFrame((f) => (f + 1) % SPIN.length), 150);
2321
+ const t = setInterval(() => setFrame((f) => (f + 1) % SPIN.length), 200);
2302
2322
  return () => clearInterval(t);
2303
2323
  }, [disabled]);
2304
2324
  return /* @__PURE__ */ jsx2(
@@ -3347,14 +3367,26 @@ function clipTail(rendered, max) {
3347
3367
  if (lines.length <= max) return { text: rendered, clipped: 0 };
3348
3368
  return { text: lines.slice(-max).join("\n"), clipped: lines.length - max };
3349
3369
  }
3370
+ var ANSI_RE = /\x1b\[[0-9;]*m/g;
3371
+ function stripAnsi(s) {
3372
+ return s.replace(ANSI_RE, "");
3373
+ }
3374
+ function visualHeight(text, width) {
3375
+ const w = Math.max(1, width);
3376
+ let rows = 0;
3377
+ for (const line of text.split("\n")) {
3378
+ rows += Math.max(1, Math.ceil(stripAnsi(line).length / w));
3379
+ }
3380
+ return rows;
3381
+ }
3350
3382
  function clipTailVisual(content, maxRows, width) {
3351
3383
  const w = Math.max(1, width);
3352
3384
  const lines = content.split("\n");
3353
- const visualRows = (line) => Math.max(1, Math.ceil(line.length / w));
3385
+ const visualRows2 = (line) => Math.max(1, Math.ceil(stripAnsi(line).length / w));
3354
3386
  let rows = 0;
3355
3387
  let start = lines.length;
3356
3388
  for (let i = lines.length - 1; i >= 0; i--) {
3357
- const h = visualRows(lines[i]);
3389
+ const h = visualRows2(lines[i]);
3358
3390
  if (rows + h > maxRows && start < lines.length) break;
3359
3391
  rows += h;
3360
3392
  start = i;
@@ -3367,9 +3399,20 @@ function liveFrameRows() {
3367
3399
  return Math.max(6, rows - 8);
3368
3400
  }
3369
3401
  var COLLAPSED_LINES = 3;
3402
+ function visualRows(text, width, cap) {
3403
+ const w = Math.max(1, width);
3404
+ let rows = 0;
3405
+ const lines = text.split("\n");
3406
+ for (const line of lines) {
3407
+ rows += Math.max(1, Math.ceil(line.length / w));
3408
+ if (rows >= cap) return cap;
3409
+ }
3410
+ return rows;
3411
+ }
3370
3412
  function estimateToolRows(use, result) {
3371
3413
  const input = use.input ?? {};
3372
3414
  const noErr = !result?.is_error;
3415
+ const w = contentWidth();
3373
3416
  if (use.name === "write_file" && noErr) {
3374
3417
  const total = countLines(String(input.content ?? ""));
3375
3418
  const shown = Math.min(total, COLLAPSED_LINES);
@@ -3385,10 +3428,10 @@ function estimateToolRows(use, result) {
3385
3428
  const lines = (result.content ?? "").split("\n");
3386
3429
  const multi = (use.name === "run_bash" || use.name === "grep" || use.name === "glob" || result.is_error) && lines.length > 1;
3387
3430
  if (multi) {
3388
- const shown = Math.min(lines.length, COLLAPSED_LINES);
3389
- rows += 1 + shown + (lines.length > shown ? 1 : 0);
3431
+ const shownLines = lines.slice(0, COLLAPSED_LINES).join("\n");
3432
+ rows += 1 + visualRows(shownLines, w, COLLAPSED_LINES * 4) + (lines.length > COLLAPSED_LINES ? 1 : 0);
3390
3433
  } else {
3391
- rows += 1;
3434
+ rows += visualRows(lines[0] ?? "", w, 4);
3392
3435
  }
3393
3436
  }
3394
3437
  return rows;
@@ -3422,7 +3465,7 @@ function ThinkingBlock({ content }) {
3422
3465
  const [frame, setFrame] = useState2(0);
3423
3466
  const visible = useThinkingVisible();
3424
3467
  useEffect2(() => {
3425
- const t = setInterval(() => setFrame((f) => (f + 1) % FRAMES.length), 80);
3468
+ const t = setInterval(() => setFrame((f) => (f + 1) % FRAMES.length), 100);
3426
3469
  return () => clearInterval(t);
3427
3470
  }, []);
3428
3471
  const label = "thinking";
@@ -3801,7 +3844,8 @@ function ChatView({
3801
3844
  permissionCursor = 0,
3802
3845
  activeToolUses,
3803
3846
  activeToolResults,
3804
- header
3847
+ header,
3848
+ logEpoch = 0
3805
3849
  }) {
3806
3850
  const empty = messages.length === 0 && !streaming && !thinking && !pendingPermission && !error;
3807
3851
  const log = [];
@@ -3816,8 +3860,12 @@ function ChatView({
3816
3860
  let streamNode = null;
3817
3861
  let streamRows = 0;
3818
3862
  if (streaming && streamingContent) {
3819
- const { text, clipped } = clipTail(renderMarkdownStreaming(streamingContent), liveBudget);
3820
- streamRows = text.split("\n").length + (clipped > 0 ? 1 : 0);
3863
+ const raw = clipTail(streamingContent, liveBudget);
3864
+ const width = contentWidth();
3865
+ const rendered = clipTailVisual(renderMarkdownStreaming(raw.text), liveBudget, width);
3866
+ const text = rendered.text;
3867
+ const clipped = raw.clipped + rendered.clipped;
3868
+ streamRows = visualHeight(text, width) + (clipped > 0 ? 1 : 0);
3821
3869
  streamNode = /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
3822
3870
  clipped > 0 && /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: `\u2191 ${clipped} more line${clipped === 1 ? "" : "s"} above \u2014 streaming\u2026` }),
3823
3871
  /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
@@ -3847,7 +3895,7 @@ function ChatView({
3847
3895
  ] });
3848
3896
  }
3849
3897
  return /* @__PURE__ */ jsxs12(Fragment2, { children: [
3850
- /* @__PURE__ */ jsx12(Static, { items: log, children: (item) => item.key === "header" ? /* @__PURE__ */ jsx12(Box12, { children: item.node }, item.key) : /* @__PURE__ */ jsx12(Box12, { marginLeft: 1, children: item.node }, item.key) }),
3898
+ /* @__PURE__ */ jsx12(Static, { items: log, children: (item) => item.key === "header" ? /* @__PURE__ */ jsx12(Box12, { children: item.node }, item.key) : /* @__PURE__ */ jsx12(Box12, { marginLeft: 1, children: item.node }, item.key) }, logEpoch),
3851
3899
  /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginLeft: 1, marginBottom: 1, children: [
3852
3900
  empty && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
3853
3901
  /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: EMPTY_STATE_TITLE }),
@@ -4015,8 +4063,8 @@ function useAgentRunner(model, activeCtx) {
4015
4063
  case "turn-end": {
4016
4064
  flushStream(true);
4017
4065
  flushThink(true);
4018
- setStreaming(false);
4019
4066
  if (ev.stop_reason === "tool_use") {
4067
+ setStreaming(false);
4020
4068
  flushTurn(null);
4021
4069
  setThinking(true);
4022
4070
  thinkingAcc = "";
@@ -4288,6 +4336,7 @@ function useKeyboard(opts) {
4288
4336
  sessions,
4289
4337
  setSessions,
4290
4338
  setNotice,
4339
+ setLogEpoch,
4291
4340
  switchProvider
4292
4341
  } = opts;
4293
4342
  const {
@@ -4321,6 +4370,7 @@ function useKeyboard(opts) {
4321
4370
  setError(null);
4322
4371
  setNotice(null);
4323
4372
  clearPasteStore();
4373
+ setLogEpoch((n) => n + 1);
4324
4374
  }
4325
4375
  const effort = cfg.effort ?? "medium";
4326
4376
  useInput((char, key) => {
@@ -4779,6 +4829,7 @@ function App() {
4779
4829
  sessionIdRef.current = sessionId;
4780
4830
  const [sessions, setSessions] = useState5([]);
4781
4831
  const [notice, setNotice] = useState5(null);
4832
+ const [logEpoch, setLogEpoch] = useState5(0);
4782
4833
  const [input, setInput] = useState5("");
4783
4834
  const [caret, setCaret] = useState5(0);
4784
4835
  const [paletteCursor, setPaletteCursor] = useState5(0);
@@ -4899,6 +4950,7 @@ function App() {
4899
4950
  sessions,
4900
4951
  setSessions,
4901
4952
  setNotice,
4953
+ setLogEpoch,
4902
4954
  switchProvider
4903
4955
  });
4904
4956
  const effort = cfg.effort ?? "medium";
@@ -4910,7 +4962,7 @@ function App() {
4910
4962
  return Math.round(used / activeCtx * 100);
4911
4963
  })();
4912
4964
  return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", paddingX: 1, children: [
4913
- state !== "ready" && /* @__PURE__ */ jsx13(WelcomeBlock, { model: cfg.model, activeCtx, effort, cwd, error: agent.error, updateAvailable, updateStatus }),
4965
+ state !== "ready" && state !== "sessions" && state !== "models" && /* @__PURE__ */ jsx13(WelcomeBlock, { model: cfg.model, activeCtx, effort, cwd, error: agent.error, updateAvailable, updateStatus }),
4914
4966
  state === "loading" && !agent.error && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: `connecting to ${provName}\u2026` }) }),
4915
4967
  agent.error && state !== "ready" && /* @__PURE__ */ jsx13(
4916
4968
  ChatView,
@@ -4922,7 +4974,7 @@ function App() {
4922
4974
  error: agent.error
4923
4975
  }
4924
4976
  ),
4925
- (state === "select-model" || state === "models") && /* @__PURE__ */ jsx13(
4977
+ state === "select-model" && /* @__PURE__ */ jsx13(
4926
4978
  ModelsView,
4927
4979
  {
4928
4980
  models: filteredModels,
@@ -4933,7 +4985,7 @@ function App() {
4933
4985
  providerType: provEntry.type,
4934
4986
  effort,
4935
4987
  query: pickerQuery,
4936
- requireSelection: state === "select-model"
4988
+ requireSelection: true
4937
4989
  }
4938
4990
  ),
4939
4991
  state === "providers" && /* @__PURE__ */ jsx13(
@@ -4945,8 +4997,7 @@ function App() {
4945
4997
  query: pickerQuery
4946
4998
  }
4947
4999
  ),
4948
- state === "sessions" && /* @__PURE__ */ jsx13(SessionsView, { sessions, cursor }),
4949
- state === "ready" && /* @__PURE__ */ jsxs13(Fragment3, { children: [
5000
+ (state === "ready" || state === "sessions" || state === "models") && /* @__PURE__ */ jsxs13(Fragment3, { children: [
4950
5001
  notice && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "green", children: `\u2713 ${notice}` }) }),
4951
5002
  /* @__PURE__ */ jsx13(
4952
5003
  ChatView,
@@ -4961,18 +5012,33 @@ function App() {
4961
5012
  permissionCursor: agent.permissionCursor,
4962
5013
  activeToolUses: agent.activeToolUses,
4963
5014
  activeToolResults: agent.activeToolResults,
4964
- header: /* @__PURE__ */ jsx13(WelcomeBlock, { model: cfg.model, activeCtx, effort, cwd })
5015
+ header: /* @__PURE__ */ jsx13(WelcomeBlock, { model: cfg.model, activeCtx, effort, cwd }),
5016
+ logEpoch
4965
5017
  }
4966
5018
  ),
4967
- input.startsWith("/") && /* @__PURE__ */ jsx13(CommandPalette, { filter: input, cursor: paletteCursor }),
4968
- contextWarning !== null && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: `\u26A0 context ${contextWarning}% full \u2014 run /clear and start fresh` }) }),
4969
- !input.startsWith("/") && (() => {
5019
+ state === "ready" && input.startsWith("/") && /* @__PURE__ */ jsx13(CommandPalette, { filter: input, cursor: paletteCursor }),
5020
+ state === "ready" && contextWarning !== null && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: "yellow", children: `\u26A0 context ${contextWarning}% full \u2014 run /clear and start fresh` }) }),
5021
+ state === "ready" && !input.startsWith("/") && (() => {
4970
5022
  const m = parseMention(input);
4971
5023
  if (!m) return null;
4972
5024
  return /* @__PURE__ */ jsx13(FilePicker, { matches: searchFiles(process.cwd(), m.query), cursor: filePickerCursor });
4973
5025
  })(),
4974
- /* @__PURE__ */ jsx13(InputBar, { input, caret, disabled: agent.busy, processingLabel: agent.processingLabel }),
4975
- !agent.busy && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: providerDown ? "provider unavailable \u2014 /provider to switch \xB7 /models to pick a model" : "type / to see commands" }) }),
5026
+ state === "ready" && /* @__PURE__ */ jsx13(InputBar, { input, caret, disabled: agent.busy, processingLabel: agent.processingLabel }),
5027
+ state === "sessions" && /* @__PURE__ */ jsx13(SessionsView, { sessions, cursor }),
5028
+ state === "models" && /* @__PURE__ */ jsx13(
5029
+ ModelsView,
5030
+ {
5031
+ models: filteredModels,
5032
+ cursor,
5033
+ model: cfg.model,
5034
+ host: provEntry.baseUrl,
5035
+ provider: provName,
5036
+ providerType: provEntry.type,
5037
+ effort,
5038
+ query: pickerQuery
5039
+ }
5040
+ ),
5041
+ state === "ready" && !agent.busy && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { dimColor: true, children: providerDown ? "provider unavailable \u2014 /provider to switch \xB7 /models to pick a model" : "type / to see commands" }) }),
4976
5042
  updateAvailable && /* @__PURE__ */ jsx13(Box13, { marginLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: updateStatus === "failed" ? "red" : updateStatus === "installed" ? "green" : "yellow", children: updateBannerText(updateAvailable, updateStatus) }) })
4977
5043
  ] })
4978
5044
  ] });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "miii-agent",
3
- "version": "0.1.30",
4
- "description": "Cursor / Claude Code, but local. An offline AI pair-programmer in your terminal, powered by Ollama. Private by default, free forever.",
3
+ "version": "0.1.31",
4
+ "description": "Local AI coding agent for your terminal โ€” an open-source, offline alternative to Claude Code, Cursor, and GitHub Copilot, powered by Ollama. Private by default, free forever.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "miii": "dist/cli.js"
@@ -52,7 +52,14 @@
52
52
  "pair-programming",
53
53
  "code-generation",
54
54
  "llama-cpp",
55
- "lm-studio"
55
+ "lm-studio",
56
+ "copilot",
57
+ "copilot-alternative",
58
+ "cursor-alternative",
59
+ "claude-code",
60
+ "claude-code-alternative",
61
+ "developer-tools",
62
+ "qwen"
56
63
  ],
57
64
  "license": "MIT",
58
65
  "dependencies": {