miii-agent 0.1.16 → 0.1.17

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/LICENSE +21 -0
  2. package/dist/cli.js +57 -21
  3. package/package.json +22 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 maruakshay
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/dist/cli.js CHANGED
@@ -2119,7 +2119,7 @@ function messageText(m) {
2119
2119
  function firstUserText(messages) {
2120
2120
  const first = messages.find((m) => m.role === "user");
2121
2121
  if (!first) return "untitled";
2122
- return messageText(first).trim().slice(0, 80) || "untitled";
2122
+ return flattenForTitle(messageText(first)).slice(0, 80) || "untitled";
2123
2123
  }
2124
2124
  function readMeta(id) {
2125
2125
  try {
@@ -2151,6 +2151,10 @@ function persistSession(id, messages, title) {
2151
2151
  }
2152
2152
  writeFileSync2(sessionPath(id), lines.join("\n") + "\n", "utf-8");
2153
2153
  }
2154
+ function setSessionTitle(id, title) {
2155
+ if (!readMeta(id)) return;
2156
+ persistSession(id, loadSession(id), title);
2157
+ }
2154
2158
  function listSessions() {
2155
2159
  if (!existsSync2(SESSION_DIR)) return [];
2156
2160
  const metas = [];
@@ -2213,12 +2217,35 @@ function toDisplayMessages(history) {
2213
2217
  }
2214
2218
  return out;
2215
2219
  }
2216
- async function summarizeMessage(model, text) {
2217
- const fallback = text.trim().slice(0, 80) || "untitled";
2218
- const prompt = `Summarize this user request as a short title, 3-6 words, no punctuation. Reply with the title only.
2220
+ function flattenForTitle(text) {
2221
+ return text.replace(/<[^>]*>/g, " ").replace(/[`*_#>|]/g, " ").replace(/https?:\/\/\S+/g, " ").replace(/\s+/g, " ").trim();
2222
+ }
2223
+ function looksLikeJunkTitle(title) {
2224
+ return !title || /[<>]/.test(title) || title.length > 80;
2225
+ }
2226
+ async function summarizeConversation(model, messages) {
2227
+ const parts = [];
2228
+ let sawUser = false;
2229
+ let sawAssistant = false;
2230
+ for (const m of messages) {
2231
+ if (m.role === "system") continue;
2232
+ const t = flattenForTitle(messageText(m));
2233
+ if (!t) continue;
2234
+ if (m.role === "user" && !sawUser) {
2235
+ parts.push(`User: ${t}`);
2236
+ sawUser = true;
2237
+ } else if (m.role === "assistant" && !sawAssistant) {
2238
+ parts.push(`Assistant: ${t}`);
2239
+ sawAssistant = true;
2240
+ }
2241
+ if (sawUser && sawAssistant) break;
2242
+ }
2243
+ const convo = parts.join("\n").slice(0, 2e3);
2244
+ const fallback = (parts[0]?.replace(/^User: /, "") ?? "").slice(0, 80) || "untitled";
2245
+ const prompt = `Summarize this conversation as a short title, 3-6 words, no punctuation. Reply with the title only.
2219
2246
 
2220
- Request:
2221
- ${text.slice(0, 2e3)}`;
2247
+ Conversation:
2248
+ ${convo}`;
2222
2249
  try {
2223
2250
  let out = "";
2224
2251
  for await (const chunk of chat3(
@@ -2229,7 +2256,8 @@ ${text.slice(0, 2e3)}`;
2229
2256
  )) {
2230
2257
  if (chunk.content) out += chunk.content;
2231
2258
  }
2232
- return out.trim().split("\n").filter(Boolean)[0]?.trim() || fallback;
2259
+ const title = out.trim().split("\n").filter(Boolean)[0]?.trim() ?? "";
2260
+ return looksLikeJunkTitle(title) ? fallback : title;
2233
2261
  } catch {
2234
2262
  return fallback;
2235
2263
  }
@@ -2495,7 +2523,7 @@ function FileEditBlock({
2495
2523
  Text9,
2496
2524
  {
2497
2525
  wrap: "truncate",
2498
- backgroundColor: ln.sign === "+" ? "#13351f" : ln.sign === "-" ? "#3b1414" : void 0,
2526
+ backgroundColor: ln.sign === "-" ? "#3b1414" : ln.sign === "+" && label !== "Write" ? "#13351f" : void 0,
2499
2527
  dimColor: ln.sign === " ",
2500
2528
  children: [
2501
2529
  `${ln.sign} `,
@@ -3018,6 +3046,7 @@ function useKeyboard(opts) {
3018
3046
  setFilePickerCursor,
3019
3047
  sessionId,
3020
3048
  setSessionId,
3049
+ onResumeSession,
3021
3050
  sessions,
3022
3051
  setSessions,
3023
3052
  setNotice,
@@ -3190,6 +3219,7 @@ function useKeyboard(opts) {
3190
3219
  setActiveToolResults([]);
3191
3220
  setError(null);
3192
3221
  setSessionId(meta.id);
3222
+ onResumeSession(meta.id);
3193
3223
  setNotice(`resumed \xB7 ${meta.title}`);
3194
3224
  setState("ready");
3195
3225
  }
@@ -3288,17 +3318,6 @@ function useKeyboard(opts) {
3288
3318
  } else if (trimmed) {
3289
3319
  setNotice(null);
3290
3320
  const message = expandPastes(trimmed);
3291
- if (!agentHistory.length && cfg.model) {
3292
- const id = sessionId;
3293
- const model = cfg.model;
3294
- void (async () => {
3295
- try {
3296
- const title = await summarizeMessage(model, message);
3297
- persistSession(id, [{ role: "user", content: message }], title);
3298
- } catch {
3299
- }
3300
- })();
3301
- }
3302
3321
  sendMessage(message);
3303
3322
  }
3304
3323
  clearPasteStore();
@@ -3393,9 +3412,25 @@ function App() {
3393
3412
  if (v) setUpdateAvailable(v);
3394
3413
  });
3395
3414
  }, []);
3415
+ const titledSessions = useRef2(/* @__PURE__ */ new Set());
3396
3416
  useEffect4(() => {
3397
- if (agent.agentHistory.length) persistSession(sessionId, agent.agentHistory);
3398
- }, [agent.agentHistory, sessionId]);
3417
+ const history = agent.agentHistory;
3418
+ if (!history.length) return;
3419
+ persistSession(sessionId, history);
3420
+ if (!titledSessions.current.has(sessionId) && cfg.model && history.some((m) => m.role === "assistant")) {
3421
+ titledSessions.current.add(sessionId);
3422
+ const id = sessionId;
3423
+ const model = cfg.model;
3424
+ const snapshot = history;
3425
+ void (async () => {
3426
+ try {
3427
+ const title = await summarizeConversation(model, snapshot);
3428
+ setSessionTitle(id, title);
3429
+ } catch {
3430
+ }
3431
+ })();
3432
+ }
3433
+ }, [agent.agentHistory, sessionId, cfg.model]);
3399
3434
  const loadGen = useRef2(0);
3400
3435
  const loadModels = (afterProvider = false) => {
3401
3436
  const gen = ++loadGen.current;
@@ -3466,6 +3501,7 @@ function App() {
3466
3501
  setFilePickerCursor,
3467
3502
  sessionId,
3468
3503
  setSessionId,
3504
+ onResumeSession: (id) => titledSessions.current.add(id),
3469
3505
  sessions,
3470
3506
  setSessions,
3471
3507
  setNotice,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miii-agent",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "Terminal AI coding agent powered by Ollama",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,8 @@
8
8
  },
9
9
  "files": [
10
10
  "dist",
11
- "README.md"
11
+ "README.md",
12
+ "LICENSE"
12
13
  ],
13
14
  "engines": {
14
15
  "node": ">=18"
@@ -28,13 +29,30 @@
28
29
  "type": "git",
29
30
  "url": "git+https://github.com/maruakshay/miii-cli.git"
30
31
  },
32
+ "homepage": "https://github.com/maruakshay/miii-cli#readme",
33
+ "bugs": {
34
+ "url": "https://github.com/maruakshay/miii-cli/issues"
35
+ },
31
36
  "keywords": [
32
37
  "cli",
33
38
  "ai",
39
+ "ai-agent",
40
+ "coding-agent",
41
+ "ai-coding-assistant",
34
42
  "ollama",
35
- "agent",
43
+ "llm",
44
+ "local-llm",
45
+ "local-first",
46
+ "offline",
47
+ "privacy",
48
+ "terminal",
49
+ "tui",
36
50
  "ink",
37
- "tui"
51
+ "agent",
52
+ "pair-programming",
53
+ "code-generation",
54
+ "llama-cpp",
55
+ "lm-studio"
38
56
  ],
39
57
  "license": "MIT",
40
58
  "dependencies": {