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.
- package/.scoderrc.example.json +2 -0
- package/README.md +1 -1
- package/dist/agent/interaction.js +15 -8
- package/dist/agent/prompt-context.js +5 -0
- package/dist/agent.js +232 -3
- package/dist/cli/repl.js +6 -0
- package/dist/config/config.js +23 -6
- package/dist/context/prompt.js +10 -4
- package/dist/llm/llm.js +3 -1
- package/dist/llm/provider-anthropic.js +5 -3
- package/dist/llm/retry.js +4 -0
- package/dist/mcp/manager.js +2 -2
- package/dist/security/permissions.js +32 -12
- package/dist/tools/read-file.js +4 -2
- package/dist/tools/run-command.js +42 -24
- package/dist/tools/search.js +7 -0
- package/dist/tui/app.js +16 -3
- package/dist/tui/charset.js +26 -0
- package/dist/tui/chrome.js +9 -6
- package/dist/tui/hooks/use-keybinds.js +24 -1
- package/dist/tui/hooks/use-scroll.js +12 -3
- package/dist/tui/markdown/diagram.js +85 -6
- package/dist/tui/markdown/graph.js +1021 -0
- package/dist/tui/selectors.js +9 -3
- package/dist/tui/state.js +13 -0
- package/dist/workspace/file-index.js +6 -5
- package/package.json +1 -1
package/dist/tui/selectors.js
CHANGED
|
@@ -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
|
-
//
|
|
51
|
-
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
|
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
|
|
45
|
+
cache.clear();
|
|
45
46
|
}
|
|
46
47
|
function walkFiles(root, prefix, out, depth) {
|
|
47
48
|
if (depth > 6)
|
package/package.json
CHANGED