s-app-scoder-agent 0.9.10 → 0.9.15

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.
@@ -1,4 +1,5 @@
1
1
  import { parseMarkdown } from "./markdown/parse.js";
2
+ import { MAX_GRAPH_ROWS, renderFlowchart } from "./markdown/graph.js";
2
3
  import { measure } from "./text-width.js";
3
4
  const EST_WIDTH = 80;
4
5
  /** Ước lượng số dòng wrap của một đoạn text ở width cho trước. */
@@ -46,10 +47,15 @@ export function estimateMarkdownRows(text, width = EST_WIDTH) {
46
47
  case "quote":
47
48
  rows += wrapEstimate(block.text, Math.max(8, width - 2));
48
49
  break;
49
- case "mermaid":
50
- // summary box: ~4 header lines + ≤6 nodes + ≤8 edges + hint + 2 border
51
- rows += Math.min(block.lines.length, 12) + 6;
50
+ case "mermaid": {
51
+ // Drawn graph: header + raster + notes + hint. Summary fallback:
52
+ // ~4 header lines + ≤6 nodes + ≤8 edges + hint + 2 border.
53
+ const graph = renderFlowchart(block.lines, Math.max(24, width), MAX_GRAPH_ROWS);
54
+ rows += graph
55
+ ? graph.height + 2 + Math.min(graph.notes.length, 4) + 2
56
+ : Math.min(block.lines.length, 12) + 6;
52
57
  break;
58
+ }
53
59
  case "chart":
54
60
  rows += 2 + 40 + 1; // ContentBox max: borders + ≤40 data rows
55
61
  break;
package/dist/tui/state.js CHANGED
@@ -30,6 +30,7 @@ export function initialState() {
30
30
  verification: null,
31
31
  subagents: [],
32
32
  plan: null,
33
+ warmup: null,
33
34
  };
34
35
  }
35
36
  const MAX_ITEMS = 400;
@@ -126,6 +127,7 @@ export function applyEvent(state, ev) {
126
127
  }
127
128
  // Plan của task trước không được lọt sang task mới.
128
129
  state.plan = null;
130
+ state.warmup = null;
129
131
  break;
130
132
  }
131
133
  case "llm_reasoning": {
@@ -291,6 +293,8 @@ export function applyEvent(state, ev) {
291
293
  state.mcpServers = { ...state.mcpServers, [ev.server]: ev.state };
292
294
  break;
293
295
  }
296
+ if (state.warmup?.active)
297
+ break;
294
298
  appendItem(state, { kind: "notice", text: ev.line, level: ev.line.includes("unavailable") ? "warn" : "info" });
295
299
  break;
296
300
  }
@@ -361,6 +365,15 @@ export function applyEvent(state, ev) {
361
365
  state.items = state.items.map((it) => it.kind === "assistant" && it.streaming ? { ...it, streaming: false } : it);
362
366
  break;
363
367
  }
368
+ case "warmup": {
369
+ if (ev.active) {
370
+ state.warmup = { active: true, stage: ev.stage, percent: Math.max(0, Math.min(100, ev.percent)), message: ev.message ?? null };
371
+ }
372
+ else {
373
+ state.warmup = null;
374
+ }
375
+ break;
376
+ }
364
377
  case "error": {
365
378
  appendItem(state, { kind: "notice", text: ev.message, level: "error" });
366
379
  break;
@@ -8,7 +8,7 @@ import { readdirSync } from "node:fs";
8
8
  import { join, relative } from "node:path";
9
9
  import fuzzysort from "fuzzysort";
10
10
  const SKIP = new Set(["node_modules", ".git", "dist", "build", ".next", "__pycache__", ".venv"]);
11
- let cache = null;
11
+ const cache = new Map();
12
12
  /**
13
13
  * File index for `workdir` (cached, TTL 5s; invalidateFileIndex on tool writes).
14
14
  * `force` (P1-2) bỏ qua cache — dùng cho fingerprint, nơi một file mới được tạo
@@ -16,8 +16,9 @@ let cache = null;
16
16
  * sẽ được tái sử dụng sai.
17
17
  */
18
18
  export function fileIndex(workdir, force = false) {
19
- if (!force && cache && Date.now() - cache.built < 5_000)
20
- return cache.files;
19
+ const hit = cache.get(workdir);
20
+ if (!force && hit && Date.now() - hit.built < 5_000)
21
+ return hit.files;
21
22
  const files = [];
22
23
  // Fast path: ripgrep --files (gitignore-aware). Bare-name globs match at any
23
24
  // depth; `!**/x/**` does NOT match absolute paths (I-07 lesson).
@@ -36,12 +37,12 @@ export function fileIndex(workdir, force = false) {
36
37
  if (files.length === 0)
37
38
  walkFiles(workdir, "", files, 0);
38
39
  files.sort();
39
- cache = { files, built: Date.now() };
40
+ cache.set(workdir, { files, built: Date.now() });
40
41
  return files;
41
42
  }
42
43
  /** Cache invalidate — call after write/edit tool_result (scope: whole index). */
43
44
  export function invalidateFileIndex() {
44
- cache = null;
45
+ cache.clear();
45
46
  }
46
47
  function walkFiles(root, prefix, out, depth) {
47
48
  if (depth > 6)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "s-app-scoder-agent",
3
- "version": "0.9.10",
3
+ "version": "0.9.15",
4
4
  "description": "Autonomous coding agent CLI — writes, edits, and builds code autonomously until the project compiles without errors.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",