@datename/fastcode-termux 0.1.6 → 0.1.8-beta.0
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/LICENSE +4 -0
- package/README.md +67 -16
- package/dist/agent/approval-json.d.ts +43 -0
- package/dist/agent/approval-json.js +69 -0
- package/dist/agent/approval-native.d.ts +3 -0
- package/dist/agent/approval-native.js +165 -0
- package/dist/agent/approval-store.d.ts +16 -0
- package/dist/agent/approval-store.js +21 -0
- package/dist/agent/approval.d.ts +83 -0
- package/dist/agent/approval.js +42 -0
- package/dist/agent/compaction.d.ts +41 -0
- package/dist/agent/compaction.js +270 -0
- package/dist/agent/context.d.ts +29 -0
- package/dist/agent/context.js +62 -0
- package/dist/agent/guards.d.ts +24 -16
- package/dist/agent/guards.js +1167 -18
- package/dist/agent/ignore.d.ts +11 -0
- package/dist/agent/ignore.js +129 -0
- package/dist/agent/policy/defaults.d.ts +16 -0
- package/dist/agent/policy/defaults.js +17 -0
- package/dist/agent/policy/egress.d.ts +32 -0
- package/dist/agent/policy/egress.js +280 -0
- package/dist/agent/process-tree.d.ts +22 -0
- package/dist/agent/process-tree.js +102 -0
- package/dist/agent/protocol-mode.d.ts +6 -0
- package/dist/agent/protocol-mode.js +51 -0
- package/dist/agent/protocol.d.ts +20 -1
- package/dist/agent/protocol.js +169 -39
- package/dist/agent/registry.d.ts +19 -0
- package/dist/agent/registry.js +247 -0
- package/dist/agent/runner.d.ts +127 -0
- package/dist/agent/runner.js +391 -0
- package/dist/agent/shell-ast.d.ts +11 -0
- package/dist/agent/shell-ast.js +204 -0
- package/dist/agent/shell-session.d.ts +51 -0
- package/dist/agent/shell-session.js +611 -0
- package/dist/agent/stream.d.ts +29 -0
- package/dist/agent/stream.js +103 -0
- package/dist/agent/tool-schemas.d.ts +2 -0
- package/dist/agent/tool-schemas.js +82 -0
- package/dist/agent/tools/append_file.d.ts +2 -0
- package/dist/agent/tools/append_file.js +28 -0
- package/dist/agent/tools/apply_patch.d.ts +10 -0
- package/dist/agent/tools/apply_patch.js +92 -0
- package/dist/agent/tools/copy_file.d.ts +2 -0
- package/dist/agent/tools/copy_file.js +53 -0
- package/dist/agent/tools/delete_file.d.ts +2 -0
- package/dist/agent/tools/delete_file.js +43 -0
- package/dist/agent/tools/grep.d.ts +2 -0
- package/dist/agent/tools/grep.js +54 -0
- package/dist/agent/tools/index.d.ts +2 -0
- package/dist/agent/tools/index.js +32 -0
- package/dist/agent/tools/list_files.d.ts +2 -0
- package/dist/agent/tools/list_files.js +17 -0
- package/dist/agent/tools/make_dir.d.ts +2 -0
- package/dist/agent/tools/make_dir.js +26 -0
- package/dist/agent/tools/move_path.d.ts +9 -0
- package/dist/agent/tools/move_path.js +73 -0
- package/dist/agent/tools/paths.d.ts +7 -0
- package/dist/agent/tools/paths.js +84 -0
- package/dist/agent/tools/pwd.d.ts +2 -0
- package/dist/agent/tools/pwd.js +10 -0
- package/dist/agent/tools/read_file.d.ts +2 -0
- package/dist/agent/tools/read_file.js +81 -0
- package/dist/agent/tools/read_many.d.ts +2 -0
- package/dist/agent/tools/read_many.js +43 -0
- package/dist/agent/tools/readers.d.ts +58 -0
- package/dist/agent/tools/readers.js +426 -0
- package/dist/agent/tools/replace_in_file.d.ts +2 -0
- package/dist/agent/tools/replace_in_file.js +63 -0
- package/dist/agent/tools/shell.d.ts +2 -0
- package/dist/agent/tools/shell.js +48 -0
- package/dist/agent/tools/stat_path.d.ts +2 -0
- package/dist/agent/tools/stat_path.js +31 -0
- package/dist/agent/tools/types.d.ts +65 -0
- package/dist/agent/tools/types.js +1 -0
- package/dist/agent/tools/validate.d.ts +19 -0
- package/dist/agent/tools/validate.js +92 -0
- package/dist/agent/tools/write_file.d.ts +2 -0
- package/dist/agent/tools/write_file.js +28 -0
- package/dist/agent/tools.d.ts +3 -1
- package/dist/agent/tools.js +2 -377
- package/dist/app.d.ts +2 -1
- package/dist/app.js +846 -173
- package/dist/cli-main.js +363 -0
- package/dist/cli.js +444 -333
- package/dist/commands/about.js +1 -1
- package/dist/commands/attach.d.ts +9 -0
- package/dist/commands/attach.js +15 -0
- package/dist/commands/bg.d.ts +7 -0
- package/dist/commands/bg.js +9 -0
- package/dist/commands/cancel.d.ts +10 -0
- package/dist/commands/cancel.js +10 -0
- package/dist/commands/clear.d.ts +1 -0
- package/dist/commands/clear.js +1 -1
- package/dist/commands/compact.d.ts +22 -0
- package/dist/commands/compact.js +34 -0
- package/dist/commands/context.d.ts +7 -0
- package/dist/commands/context.js +25 -0
- package/dist/commands/edit.d.ts +10 -0
- package/dist/commands/edit.js +36 -0
- package/dist/commands/effort.d.ts +25 -0
- package/dist/commands/effort.js +48 -0
- package/dist/commands/expand.d.ts +10 -0
- package/dist/commands/expand.js +8 -0
- package/dist/commands/index.js +24 -0
- package/dist/commands/jobs.d.ts +7 -0
- package/dist/commands/jobs.js +17 -0
- package/dist/commands/kill.d.ts +7 -0
- package/dist/commands/kill.js +13 -0
- package/dist/commands/login.d.ts +6 -4
- package/dist/commands/login.js +24 -22
- package/dist/commands/logout.js +8 -16
- package/dist/commands/model.d.ts +1 -0
- package/dist/commands/model.js +10 -22
- package/dist/commands/provider.d.ts +1 -2
- package/dist/commands/provider.js +4 -11
- package/dist/commands/skills.js +34 -4
- package/dist/commands/steer.d.ts +11 -0
- package/dist/commands/steer.js +13 -0
- package/dist/commands/threads.d.ts +9 -0
- package/dist/commands/threads.js +26 -0
- package/dist/commands/whoami.js +6 -5
- package/dist/config/store.d.ts +53 -12
- package/dist/config/store.js +163 -73
- package/dist/config/trust.d.ts +30 -8
- package/dist/config/trust.js +139 -14
- package/dist/headless.d.ts +7 -0
- package/dist/headless.js +213 -0
- package/dist/index.js +19 -3
- package/dist/lib/debug.d.ts +2 -0
- package/dist/lib/debug.js +22 -0
- package/dist/lib/diagnostics.d.ts +48 -4
- package/dist/lib/diagnostics.js +90 -8
- package/dist/lib/highlight-subset.d.ts +21 -0
- package/dist/lib/highlight-subset.js +88 -0
- package/dist/lib/http.d.ts +11 -1
- package/dist/lib/http.js +62 -4
- package/dist/lib/lifecycle.d.ts +5 -0
- package/dist/lib/lifecycle.js +62 -0
- package/dist/lib/markdown.js +22 -4
- package/dist/lib/model-meta.d.ts +19 -0
- package/dist/lib/model-meta.js +113 -0
- package/dist/lib/native-tools.d.ts +12 -0
- package/dist/lib/native-tools.js +21 -0
- package/dist/lib/net.d.ts +33 -0
- package/dist/lib/net.js +168 -0
- package/dist/patch/apply.d.ts +15 -0
- package/dist/patch/apply.js +172 -0
- package/dist/patch/parse.d.ts +29 -0
- package/dist/patch/parse.js +112 -0
- package/dist/patch/plan.d.ts +49 -0
- package/dist/patch/plan.js +273 -0
- package/dist/providers/anthropic.d.ts +1 -0
- package/dist/providers/anthropic.js +12 -0
- package/dist/providers/custom.d.ts +9 -0
- package/dist/providers/deepseek.d.ts +10 -0
- package/dist/providers/deepseek.js +3 -2
- package/dist/providers/google.d.ts +9 -0
- package/dist/providers/groq.d.ts +10 -0
- package/dist/providers/groq.js +2 -1
- package/dist/providers/index.d.ts +10 -201
- package/dist/providers/index.js +30 -0
- package/dist/providers/mistral.d.ts +10 -0
- package/dist/providers/mistral.js +2 -1
- package/dist/providers/moonshot.d.ts +10 -0
- package/dist/providers/moonshot.js +2 -1
- package/dist/providers/ollama.d.ts +9 -0
- package/dist/providers/openai.d.ts +10 -0
- package/dist/providers/openai.js +2 -1
- package/dist/providers/openaiCompatible.d.ts +33 -2
- package/dist/providers/openaiCompatible.js +78 -16
- package/dist/providers/openrouter.d.ts +10 -0
- package/dist/providers/openrouter.js +2 -1
- package/dist/providers/qwen.d.ts +10 -0
- package/dist/providers/qwen.js +2 -1
- package/dist/providers/spec.d.ts +12 -0
- package/dist/providers/spec.js +29 -0
- package/dist/providers/xai.d.ts +10 -0
- package/dist/providers/xai.js +2 -1
- package/dist/providers/zhipu.d.ts +10 -0
- package/dist/providers/zhipu.js +2 -1
- package/dist/session/log.d.ts +49 -14
- package/dist/session/log.js +236 -11
- package/dist/session/projection.d.ts +76 -0
- package/dist/session/projection.js +526 -0
- package/dist/skills/manager.d.ts +15 -0
- package/dist/skills/manager.js +135 -18
- package/dist/types.d.ts +75 -1
- package/dist/ui/Message.d.ts +1 -7
- package/dist/ui/Message.js +13 -2
- package/dist/ui/Picker.d.ts +8 -0
- package/dist/ui/Picker.js +24 -0
- package/dist/ui/Prompt.d.ts +1 -2
- package/dist/ui/Prompt.js +2 -2
- package/dist/ui/Spinner.js +11 -5
- package/dist/ui/StatusBar.d.ts +2 -1
- package/dist/ui/StatusBar.js +6 -5
- package/package.json +3 -2
- package/src/agent/approval-json.ts +103 -0
- package/src/agent/approval-native.ts +168 -0
- package/src/agent/approval-store.ts +38 -0
- package/src/agent/approval.ts +94 -0
- package/src/agent/compaction.ts +321 -0
- package/src/agent/context.ts +97 -0
- package/src/agent/guards.ts +1239 -19
- package/src/agent/ignore.ts +147 -0
- package/src/agent/policy/defaults.ts +34 -0
- package/src/agent/policy/egress.ts +335 -0
- package/src/agent/process-tree.ts +114 -0
- package/src/agent/protocol-mode.ts +59 -0
- package/src/agent/protocol.ts +191 -40
- package/src/agent/registry.ts +270 -0
- package/src/agent/runner.ts +486 -0
- package/src/agent/shell-ast.ts +227 -0
- package/src/agent/shell-session.ts +673 -0
- package/src/agent/stream.ts +143 -0
- package/src/agent/tool-schemas.ts +86 -0
- package/src/agent/tools/append_file.ts +30 -0
- package/src/agent/tools/apply_patch.ts +95 -0
- package/src/agent/tools/copy_file.ts +56 -0
- package/src/agent/tools/delete_file.ts +45 -0
- package/src/agent/tools/grep.ts +57 -0
- package/src/agent/tools/index.ts +34 -0
- package/src/agent/tools/list_files.ts +19 -0
- package/src/agent/tools/make_dir.ts +28 -0
- package/src/agent/tools/move_path.ts +83 -0
- package/src/agent/tools/paths.ts +92 -0
- package/src/agent/tools/pwd.ts +12 -0
- package/src/agent/tools/read_file.ts +84 -0
- package/src/agent/tools/read_many.ts +45 -0
- package/src/agent/tools/readers.ts +491 -0
- package/src/agent/tools/replace_in_file.ts +66 -0
- package/src/agent/tools/shell.ts +53 -0
- package/src/agent/tools/stat_path.ts +33 -0
- package/src/agent/tools/types.ts +84 -0
- package/src/agent/tools/validate.ts +104 -0
- package/src/agent/tools/write_file.ts +30 -0
- package/src/agent/tools.ts +3 -377
- package/src/app.ts +853 -170
- package/src/{cli.ts → cli-main.ts} +64 -9
- package/src/commands/about.ts +1 -1
- package/src/commands/attach.ts +16 -0
- package/src/commands/bg.ts +9 -0
- package/src/commands/cancel.ts +10 -0
- package/src/commands/clear.ts +1 -1
- package/src/commands/compact.ts +35 -0
- package/src/commands/context.ts +26 -0
- package/src/commands/edit.ts +37 -0
- package/src/commands/effort.ts +49 -0
- package/src/commands/expand.ts +8 -0
- package/src/commands/index.ts +24 -0
- package/src/commands/jobs.ts +18 -0
- package/src/commands/kill.ts +14 -0
- package/src/commands/login.ts +24 -22
- package/src/commands/logout.ts +8 -16
- package/src/commands/model.ts +10 -22
- package/src/commands/provider.ts +4 -11
- package/src/commands/skills.ts +34 -4
- package/src/commands/steer.ts +13 -0
- package/src/commands/threads.ts +28 -0
- package/src/commands/whoami.ts +6 -5
- package/src/config/store.ts +168 -77
- package/src/config/trust.ts +181 -22
- package/src/headless.ts +225 -0
- package/src/index.ts +19 -3
- package/src/lib/debug.ts +24 -0
- package/src/lib/diagnostics.ts +90 -8
- package/src/lib/highlight-subset.ts +93 -0
- package/src/lib/http.ts +66 -4
- package/src/lib/lifecycle.ts +69 -0
- package/src/lib/markdown.ts +22 -4
- package/src/lib/model-meta.ts +138 -0
- package/src/lib/native-tools.ts +32 -0
- package/src/lib/net.ts +204 -0
- package/src/patch/apply.ts +194 -0
- package/src/patch/parse.ts +131 -0
- package/src/patch/plan.ts +317 -0
- package/src/providers/anthropic.ts +13 -1
- package/src/providers/deepseek.ts +3 -2
- package/src/providers/groq.ts +2 -1
- package/src/providers/index.ts +32 -1
- package/src/providers/mistral.ts +2 -1
- package/src/providers/moonshot.ts +2 -1
- package/src/providers/openai.ts +2 -1
- package/src/providers/openaiCompatible.ts +104 -19
- package/src/providers/openrouter.ts +2 -1
- package/src/providers/qwen.ts +2 -1
- package/src/providers/spec.ts +42 -0
- package/src/providers/xai.ts +2 -1
- package/src/providers/zhipu.ts +2 -1
- package/src/session/log.ts +311 -29
- package/src/session/projection.ts +621 -0
- package/src/skills/manager.ts +140 -18
- package/src/types/highlight-shims.d.ts +14 -0
- package/src/types.ts +79 -2
- package/src/ui/Message.ts +13 -2
- package/src/ui/Picker.ts +24 -0
- package/src/ui/Prompt.ts +2 -2
- package/src/ui/Spinner.ts +11 -5
- package/src/ui/StatusBar.ts +6 -5
- package/tsconfig.json +1 -0
- /package/dist/{cli.d.ts → cli-main.d.ts} +0 -0
package/dist/session/log.js
CHANGED
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
*
|
|
9
9
|
* FASTCODE_SESSION_LOG=0 disable logging
|
|
10
10
|
* FASTCODE_SESSION_CACHE_MB=N sessions cache cap in MB (default 256)
|
|
11
|
+
* FASTCODE_FSYNC=0|1 force checkpoint fsync off/on
|
|
11
12
|
*/
|
|
12
|
-
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs";
|
|
13
|
+
import { appendFileSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readdirSync, readFileSync, readSync, rmSync, statSync, writeSync } from "node:fs";
|
|
13
14
|
import { join } from "node:path";
|
|
14
15
|
import { getPaths } from "../config/paths.js";
|
|
16
|
+
import { buildProjection, writeProjection } from "./projection.js";
|
|
15
17
|
const NL = String.fromCharCode(10);
|
|
16
18
|
export function sessionCacheLimitBytes() {
|
|
17
19
|
const mb = Number(process.env["FASTCODE_SESSION_CACHE_MB"]);
|
|
@@ -20,19 +22,93 @@ export function sessionCacheLimitBytes() {
|
|
|
20
22
|
export function loggingEnabled() {
|
|
21
23
|
return process.env["FASTCODE_SESSION_LOG"] !== "0";
|
|
22
24
|
}
|
|
25
|
+
export function projectionPath(file) {
|
|
26
|
+
return file.replace(/[.]jsonl$/, ".projection.json");
|
|
27
|
+
}
|
|
28
|
+
export function fsyncMode() {
|
|
29
|
+
const raw = (process.env["FASTCODE_FSYNC"] ?? "").trim().toLowerCase();
|
|
30
|
+
if (["1", "true", "yes", "on"].includes(raw))
|
|
31
|
+
return "on";
|
|
32
|
+
if (["0", "false", "no", "off"].includes(raw))
|
|
33
|
+
return "off";
|
|
34
|
+
return "auto";
|
|
35
|
+
}
|
|
36
|
+
function onSharedStorage(root) {
|
|
37
|
+
const normalized = root.replace(/\\/g, "/");
|
|
38
|
+
return normalized === "/sdcard"
|
|
39
|
+
|| normalized.startsWith("/sdcard/")
|
|
40
|
+
|| normalized === "/storage/emulated"
|
|
41
|
+
|| normalized.startsWith("/storage/emulated/");
|
|
42
|
+
}
|
|
43
|
+
export function fsyncEnabled(type = "checkpoint") {
|
|
44
|
+
if (type !== "checkpoint")
|
|
45
|
+
return false;
|
|
46
|
+
const mode = fsyncMode();
|
|
47
|
+
if (mode === "on")
|
|
48
|
+
return true;
|
|
49
|
+
if (mode === "off")
|
|
50
|
+
return false;
|
|
51
|
+
return onSharedStorage(getPaths().root);
|
|
52
|
+
}
|
|
53
|
+
function writeLine(file, line, type) {
|
|
54
|
+
if (!fsyncEnabled(type)) {
|
|
55
|
+
appendFileSync(file, line, "utf8");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const fd = openSync(file, "a");
|
|
59
|
+
try {
|
|
60
|
+
writeSync(fd, line);
|
|
61
|
+
fsyncSync(fd);
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
closeSync(fd);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function fsyncPath(file) {
|
|
68
|
+
if (!existsSync(file))
|
|
69
|
+
return;
|
|
70
|
+
try {
|
|
71
|
+
const fd = openSync(file, "r");
|
|
72
|
+
try {
|
|
73
|
+
fsyncSync(fd);
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
closeSync(fd);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// FUSE / read-only filesystems may reject fsync; the append is still
|
|
81
|
+
// best effort and the caller already caught close-level failures.
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function countLines(file) {
|
|
85
|
+
if (!existsSync(file))
|
|
86
|
+
return 0;
|
|
87
|
+
try {
|
|
88
|
+
return readFileSync(file, "utf8").split(NL).filter(Boolean).length;
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
23
94
|
function newId() {
|
|
24
95
|
return new Date().toISOString().replace(/[:.]/g, "-") + "-" + Math.random().toString(36).slice(2, 6);
|
|
25
96
|
}
|
|
26
97
|
function openLog(id, file, meta) {
|
|
27
98
|
let closed = false;
|
|
99
|
+
let seq = countLines(file);
|
|
28
100
|
const append = (entry) => {
|
|
29
101
|
if (closed || !loggingEnabled())
|
|
30
|
-
return;
|
|
102
|
+
return 0;
|
|
103
|
+
const next = seq + 1;
|
|
104
|
+
const line = JSON.stringify({ ts: Date.now(), seq: next, ...entry }) + NL;
|
|
31
105
|
try {
|
|
32
|
-
|
|
106
|
+
writeLine(file, line, String(entry.type ?? ""));
|
|
107
|
+
seq = next;
|
|
108
|
+
return next;
|
|
33
109
|
}
|
|
34
110
|
catch {
|
|
35
|
-
|
|
111
|
+
return 0;
|
|
36
112
|
}
|
|
37
113
|
};
|
|
38
114
|
append({ type: "session_start", id, cwd: process.cwd(), ...meta });
|
|
@@ -40,10 +116,28 @@ function openLog(id, file, meta) {
|
|
|
40
116
|
id,
|
|
41
117
|
file,
|
|
42
118
|
append,
|
|
43
|
-
|
|
44
|
-
|
|
119
|
+
count() {
|
|
120
|
+
return seq;
|
|
121
|
+
},
|
|
122
|
+
close(info = {}) {
|
|
123
|
+
append({
|
|
124
|
+
type: "session_end",
|
|
125
|
+
reason: info.reason ?? "close",
|
|
126
|
+
// Reserved extension point: future compaction can fill this
|
|
127
|
+
// slot without changing the session_end event shape.
|
|
128
|
+
compaction: {
|
|
129
|
+
source: info.compaction?.source ?? "none",
|
|
130
|
+
summaryRef: info.compaction?.summaryRef ?? null,
|
|
131
|
+
pending: info.compaction?.pending ?? false,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
45
134
|
closed = true;
|
|
46
135
|
try {
|
|
136
|
+
// Snapshot + manifest are written while the facts still exist;
|
|
137
|
+
// pruning later keeps this verified copy.
|
|
138
|
+
ensureProjection(file);
|
|
139
|
+
fsyncPath(file);
|
|
140
|
+
fsyncPath(projectionPath(file));
|
|
47
141
|
pruneSessions();
|
|
48
142
|
}
|
|
49
143
|
catch {
|
|
@@ -52,6 +146,21 @@ function openLog(id, file, meta) {
|
|
|
52
146
|
},
|
|
53
147
|
};
|
|
54
148
|
}
|
|
149
|
+
/** Summary files referenced by older compacted facts in this session. */
|
|
150
|
+
export function staleSummaryRefs(file) {
|
|
151
|
+
let facts;
|
|
152
|
+
try {
|
|
153
|
+
facts = readSession(file);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
const compacted = facts.filter((fact) => fact?.type === "compacted");
|
|
159
|
+
const latest = compacted.at(-1)?.summaryRef;
|
|
160
|
+
return Array.from(new Set(compacted
|
|
161
|
+
.map((fact) => fact.summaryRef)
|
|
162
|
+
.filter((ref) => typeof ref === "string" && ref.length > 0 && ref !== latest)));
|
|
163
|
+
}
|
|
55
164
|
export function createSessionLog(meta = {}) {
|
|
56
165
|
const { sessions } = getPaths();
|
|
57
166
|
mkdirSync(sessions, { recursive: true });
|
|
@@ -59,10 +168,10 @@ export function createSessionLog(meta = {}) {
|
|
|
59
168
|
const file = join(sessions, id + ".jsonl");
|
|
60
169
|
return openLog(id, file, meta);
|
|
61
170
|
}
|
|
62
|
-
export function openSessionLog(file) {
|
|
171
|
+
export function openSessionLog(file, meta = {}) {
|
|
63
172
|
const { sessions } = getPaths();
|
|
64
173
|
mkdirSync(sessions, { recursive: true });
|
|
65
|
-
return openLog(undefined, existsSync(file) ? file : join(sessions, file),
|
|
174
|
+
return openLog(undefined, existsSync(file) ? file : join(sessions, file), meta);
|
|
66
175
|
}
|
|
67
176
|
export function listSessions() {
|
|
68
177
|
const { sessions } = getPaths();
|
|
@@ -79,7 +188,8 @@ export function listSessions() {
|
|
|
79
188
|
const info = statSync(file);
|
|
80
189
|
bytes = info.size;
|
|
81
190
|
modified = info.mtime.toISOString();
|
|
82
|
-
messages = readFileSync(file, "utf8").split(NL).filter((line) => line.includes('"type":"
|
|
191
|
+
messages = readFileSync(file, "utf8").split(NL).filter((line) => line.includes('"type":"user"') ||
|
|
192
|
+
(line.includes('"type":"message"') && line.includes('"role":"user"'))).length;
|
|
83
193
|
}
|
|
84
194
|
catch {
|
|
85
195
|
// unreadable: report what we have
|
|
@@ -112,18 +222,133 @@ export function readSession(idOrFile) {
|
|
|
112
222
|
}
|
|
113
223
|
export function loadSessionMessages(idOrFile) {
|
|
114
224
|
return readSession(idOrFile)
|
|
115
|
-
.filter((entry) => entry.type === "message" && typeof entry.content === "string")
|
|
116
|
-
.map((entry) => ({
|
|
225
|
+
.filter((entry) => (entry.type === "message" || entry.type === "user" || entry.type === "assistant_raw") && typeof entry.content === "string")
|
|
226
|
+
.map((entry) => ({
|
|
227
|
+
role: entry.type === "assistant_raw" ? "assistant" : entry.role ?? "user",
|
|
228
|
+
content: entry.content,
|
|
229
|
+
}));
|
|
117
230
|
}
|
|
118
231
|
export function latestSessionFile() {
|
|
119
232
|
const all = listSessions();
|
|
120
233
|
return all.length > 0 ? all[0].file : undefined;
|
|
121
234
|
}
|
|
235
|
+
function summarize(id, file, entries) {
|
|
236
|
+
let cwd = "";
|
|
237
|
+
let providerId = "";
|
|
238
|
+
let model = "";
|
|
239
|
+
let turns = 0;
|
|
240
|
+
let activeFiles = [];
|
|
241
|
+
let messages = 0;
|
|
242
|
+
let lastTs = 0;
|
|
243
|
+
for (const entry of entries) {
|
|
244
|
+
if (typeof entry.ts === "number")
|
|
245
|
+
lastTs = entry.ts;
|
|
246
|
+
if (entry.type === "session_start") {
|
|
247
|
+
cwd = typeof entry.cwd === "string" ? entry.cwd : cwd;
|
|
248
|
+
providerId = typeof entry.providerId === "string" ? entry.providerId : providerId;
|
|
249
|
+
model = typeof entry.model === "string" ? entry.model : model;
|
|
250
|
+
}
|
|
251
|
+
else if (entry.type === "message") {
|
|
252
|
+
messages += 1;
|
|
253
|
+
}
|
|
254
|
+
else if (entry.type === "checkpoint") {
|
|
255
|
+
cwd = typeof entry.cwd === "string" ? entry.cwd : cwd;
|
|
256
|
+
providerId = typeof entry.providerId === "string" ? entry.providerId : providerId;
|
|
257
|
+
model = typeof entry.model === "string" ? entry.model : model;
|
|
258
|
+
if (typeof entry.turn === "number")
|
|
259
|
+
turns = entry.turn;
|
|
260
|
+
if (Array.isArray(entry.activeFiles))
|
|
261
|
+
activeFiles = entry.activeFiles;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return { id, file, cwd, providerId, model, turns, activeFiles, messages, lastTs };
|
|
265
|
+
}
|
|
266
|
+
function readLastEntry(file) {
|
|
267
|
+
let size = 0;
|
|
268
|
+
try {
|
|
269
|
+
size = statSync(file).size;
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
return undefined;
|
|
273
|
+
}
|
|
274
|
+
if (size === 0)
|
|
275
|
+
return undefined;
|
|
276
|
+
const length = Math.min(size, 64 * 1024);
|
|
277
|
+
const fd = openSync(file, "r");
|
|
278
|
+
try {
|
|
279
|
+
const buffer = Buffer.alloc(length);
|
|
280
|
+
readSync(fd, buffer, 0, length, size - length);
|
|
281
|
+
const lines = buffer.toString("utf8").trimEnd().split(NL);
|
|
282
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
283
|
+
if (!lines[i])
|
|
284
|
+
continue;
|
|
285
|
+
try {
|
|
286
|
+
return JSON.parse(lines[i]);
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return { type: "unparsable_tail" };
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
finally {
|
|
295
|
+
closeSync(fd);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
export function findUnclosedSessions() {
|
|
299
|
+
const { sessions } = getPaths();
|
|
300
|
+
if (!existsSync(sessions))
|
|
301
|
+
return [];
|
|
302
|
+
const files = readdirSync(sessions)
|
|
303
|
+
.filter((name) => name.endsWith(".jsonl"))
|
|
304
|
+
.map((name) => {
|
|
305
|
+
const file = join(sessions, name);
|
|
306
|
+
let modified = 0;
|
|
307
|
+
try {
|
|
308
|
+
modified = statSync(file).mtimeMs;
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
// unreadable
|
|
312
|
+
}
|
|
313
|
+
return { name, file, modified };
|
|
314
|
+
})
|
|
315
|
+
.sort((a, b) => b.modified - a.modified);
|
|
316
|
+
const out = [];
|
|
317
|
+
for (const entry of files) {
|
|
318
|
+
const last = readLastEntry(entry.file);
|
|
319
|
+
if (!last || last.type === "session_end")
|
|
320
|
+
continue;
|
|
321
|
+
let entries;
|
|
322
|
+
try {
|
|
323
|
+
entries = readSession(entry.file);
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
if (entries.length === 0 || !entries.some((item) => item.type === "session_start"))
|
|
329
|
+
continue;
|
|
330
|
+
out.push(summarize(entry.name.replace(/[.]jsonl$/, ""), entry.file, entries));
|
|
331
|
+
}
|
|
332
|
+
return out;
|
|
333
|
+
}
|
|
334
|
+
export function latestUnclosedSession() {
|
|
335
|
+
return findUnclosedSessions()[0];
|
|
336
|
+
}
|
|
337
|
+
function ensureProjection(file) {
|
|
338
|
+
// Always refresh from the facts that still exist: a projection written at
|
|
339
|
+
// an earlier checkpoint may be stale by the time we close or prune. If the
|
|
340
|
+
// JSONL is already gone, leave the verified projection untouched.
|
|
341
|
+
const entries = readSession(file);
|
|
342
|
+
if (entries.length === 0)
|
|
343
|
+
return;
|
|
344
|
+
writeProjection(file, buildProjection(entries), entries);
|
|
345
|
+
}
|
|
122
346
|
export function pruneSessions(limit = sessionCacheLimitBytes()) {
|
|
123
347
|
const all = listSessions();
|
|
124
348
|
let total = all.reduce((sum, entry) => sum + entry.bytes, 0);
|
|
125
349
|
for (let i = all.length - 1; i >= 0 && total > limit; i -= 1) {
|
|
126
350
|
try {
|
|
351
|
+
ensureProjection(all[i].file);
|
|
127
352
|
rmSync(all[i].file, { force: true });
|
|
128
353
|
total -= all[i].bytes;
|
|
129
354
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { ChatMessage } from "../types.js";
|
|
2
|
+
import { type ActiveFile } from "./log.js";
|
|
3
|
+
export interface SessionMeta {
|
|
4
|
+
cwd: string;
|
|
5
|
+
providerId: string;
|
|
6
|
+
model: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ProjectionFingerprint {
|
|
9
|
+
toolCatalogHash: string;
|
|
10
|
+
modelId: string;
|
|
11
|
+
cwdDigest: string;
|
|
12
|
+
compactionSource: "local" | "server" | "none";
|
|
13
|
+
}
|
|
14
|
+
export interface ProjectionManifest {
|
|
15
|
+
version: 1;
|
|
16
|
+
algorithm: "sha256";
|
|
17
|
+
savedAt: string;
|
|
18
|
+
/** Hash of the projection content (messages/meta/files). */
|
|
19
|
+
contentHash: string;
|
|
20
|
+
/** Hash of the source JSONL facts at save time, when available. */
|
|
21
|
+
sessionHash?: string;
|
|
22
|
+
/** Highest fact sequence covered by this projection. */
|
|
23
|
+
lastFactSeq?: number;
|
|
24
|
+
}
|
|
25
|
+
export interface Projection {
|
|
26
|
+
version: 1;
|
|
27
|
+
kind: "projection";
|
|
28
|
+
cwd: string;
|
|
29
|
+
providerId: string;
|
|
30
|
+
model: string;
|
|
31
|
+
fingerprint: ProjectionFingerprint;
|
|
32
|
+
messages: ChatMessage[];
|
|
33
|
+
activeFiles: ActiveFile[];
|
|
34
|
+
lastFactSeq: number;
|
|
35
|
+
/** Integrity data written at save/prune time; never re-derived from facts. */
|
|
36
|
+
manifest?: ProjectionManifest;
|
|
37
|
+
}
|
|
38
|
+
export type ProjectionReadStatus = "ok" | "legacy" | "hash_mismatch" | "corrupt" | "missing";
|
|
39
|
+
export interface ProjectionReadResult {
|
|
40
|
+
status: ProjectionReadStatus;
|
|
41
|
+
projection?: Projection;
|
|
42
|
+
expectedHash?: string;
|
|
43
|
+
actualHash?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ResumeState {
|
|
46
|
+
projection: Projection;
|
|
47
|
+
messages: ChatMessage[];
|
|
48
|
+
meta: SessionMeta;
|
|
49
|
+
warnings: string[];
|
|
50
|
+
rebuilt: boolean;
|
|
51
|
+
}
|
|
52
|
+
export declare function unpairedToolNotice(tool: string): string;
|
|
53
|
+
export declare function cwdDigest(cwd: string): string;
|
|
54
|
+
export declare function projectionFingerprint(meta: SessionMeta, compactionSource?: ProjectionFingerprint["compactionSource"]): ProjectionFingerprint;
|
|
55
|
+
export declare function sameFingerprint(a: ProjectionFingerprint | undefined, b: ProjectionFingerprint): boolean;
|
|
56
|
+
export declare function sessionMetaFromFacts(facts: any[]): SessionMeta;
|
|
57
|
+
export declare function sessionMetaFromFile(file: string): SessionMeta;
|
|
58
|
+
export declare function factsToMessages(facts: any[]): ChatMessage[];
|
|
59
|
+
export declare function compactionSourceFromFacts(facts: any[]): ProjectionFingerprint["compactionSource"];
|
|
60
|
+
export declare function projectionContentHash(projection: Projection): string;
|
|
61
|
+
export declare function factsContentHash(facts: any[]): string;
|
|
62
|
+
/**
|
|
63
|
+
* Keep native tool_call/tool_result pairs complete. Orphan tool messages left
|
|
64
|
+
* behind by projection truncation are dropped; missing results are synthesized
|
|
65
|
+
* with the existing "execution unknown" notice so a resumed model never waits
|
|
66
|
+
* for a result that cannot arrive.
|
|
67
|
+
*/
|
|
68
|
+
export declare function pairToolMessages(messages: ChatMessage[]): {
|
|
69
|
+
messages: ChatMessage[];
|
|
70
|
+
repaired: boolean;
|
|
71
|
+
};
|
|
72
|
+
export declare function buildProjection(facts: any[], metaOverride?: Partial<SessionMeta>): Projection;
|
|
73
|
+
export declare function readProjectionResult(file: string): ProjectionReadResult;
|
|
74
|
+
export declare function readProjection(file: string): Projection | undefined;
|
|
75
|
+
export declare function writeProjection(file: string, projection: Projection, facts?: any[]): void;
|
|
76
|
+
export declare function resumeSession(file: string, currentCwd?: string): ResumeState;
|