token-goat 2.9.26 → 2.9.29
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/README.md +30 -88
- package/SECURITY.md +14 -0
- package/dist/{token-goat-chunk-OZRSREKR.mjs → token-goat-chunk-2AWQ2R5X.mjs} +2 -2
- package/dist/{token-goat-chunk-BH4ZVRB2.mjs → token-goat-chunk-2NNUA2LR.mjs} +4 -4
- package/dist/token-goat-chunk-2WOUYWLM.mjs +955 -0
- package/dist/{token-goat-chunk-IKZLSRII.mjs → token-goat-chunk-435UQTKD.mjs} +5 -3
- package/dist/{token-goat-chunk-62IHOU6L.mjs → token-goat-chunk-44BM7DDQ.mjs} +5 -3
- package/dist/token-goat-chunk-52NSDWYY.mjs +96 -0
- package/dist/{token-goat-chunk-CXBOFPF4.mjs → token-goat-chunk-67BNIKKO.mjs} +32 -18
- package/dist/{token-goat-chunk-XBESNWEX.mjs → token-goat-chunk-6AK46ZT7.mjs} +2 -3
- package/dist/{token-goat-chunk-7SXPJOSZ.mjs → token-goat-chunk-7CPMDFGB.mjs} +166 -40
- package/dist/token-goat-chunk-ASLWOQ3I.mjs +14 -0
- package/dist/{token-goat-chunk-MWID3YOY.mjs → token-goat-chunk-BGYOZ6DO.mjs} +6 -4
- package/dist/{token-goat-chunk-PAV6NNY7.mjs → token-goat-chunk-C5YPNZKQ.mjs} +22 -8
- package/dist/{token-goat-chunk-D2X7XN5M.mjs → token-goat-chunk-CIQ2FTY3.mjs} +23 -242
- package/dist/token-goat-chunk-D4ETHJD6.mjs +246 -0
- package/dist/{token-goat-chunk-7Y6GWTII.mjs → token-goat-chunk-DNRPXHYH.mjs} +25 -17
- package/dist/{token-goat-chunk-L43RKNHA.mjs → token-goat-chunk-DNSPXQXQ.mjs} +2 -2
- package/dist/token-goat-chunk-DPNLUJWB.mjs +220 -0
- package/dist/token-goat-chunk-E4ZOJIZK.mjs +1382 -0
- package/dist/token-goat-chunk-E5TK5DNO.mjs +718 -0
- package/dist/{token-goat-chunk-VVROQBQJ.mjs → token-goat-chunk-EUSDXRXU.mjs} +62 -12
- package/dist/{token-goat-chunk-POOI26O6.mjs → token-goat-chunk-FTP4U4QA.mjs} +12 -8
- package/dist/token-goat-chunk-G23DWHV4.mjs +142 -0
- package/dist/{token-goat-chunk-MDV5VWF4.mjs → token-goat-chunk-G7IWXCFF.mjs} +223 -15
- package/dist/{token-goat-chunk-C2PG4K5D.mjs → token-goat-chunk-GLXRTTLE.mjs} +7 -5
- package/dist/{token-goat-chunk-M6CVNHTW.mjs → token-goat-chunk-H5J3C56Q.mjs} +95 -573
- package/dist/{token-goat-chunk-BAWKGODL.mjs → token-goat-chunk-HNFZZHFW.mjs} +2 -2
- package/dist/{token-goat-chunk-TG5ZPD6B.mjs → token-goat-chunk-HUYUHODZ.mjs} +1036 -759
- package/dist/token-goat-chunk-IVE6U7KV.mjs +53 -0
- package/dist/{token-goat-chunk-ZZT6PVB3.mjs → token-goat-chunk-IVWI2OCK.mjs} +72 -45
- package/dist/{token-goat-chunk-GMOUBOX4.mjs → token-goat-chunk-JTKCQMQA.mjs} +37 -5
- package/dist/{token-goat-chunk-H2CPLEMP.mjs → token-goat-chunk-KOPIR3KZ.mjs} +46 -23
- package/dist/token-goat-chunk-L7H3U27L.mjs +35 -0
- package/dist/{token-goat-chunk-FLEYOCAS.mjs → token-goat-chunk-LZNBQTDK.mjs} +6 -4
- package/dist/token-goat-chunk-MELOKFDJ.mjs +199 -0
- package/dist/{token-goat-chunk-RH27ZSPF.mjs → token-goat-chunk-NMBWLRHW.mjs} +164 -50
- package/dist/{token-goat-chunk-43JFN26X.mjs → token-goat-chunk-O6I2XU4P.mjs} +27 -967
- package/dist/{token-goat-chunk-G6EYO5CD.mjs → token-goat-chunk-ONXH6NZ5.mjs} +2 -87
- package/dist/token-goat-chunk-ORNFMIER.mjs +295 -0
- package/dist/{token-goat-chunk-LHUP4DXZ.mjs → token-goat-chunk-PGTH2U4C.mjs} +1 -1
- package/dist/{token-goat-chunk-5BQ7W7D7.mjs → token-goat-chunk-PKRWMHVP.mjs} +76 -59
- package/dist/{token-goat-chunk-DA43OE7L.mjs → token-goat-chunk-PQ53BSCF.mjs} +1 -1
- package/dist/{token-goat-chunk-STYRLQIW.mjs → token-goat-chunk-PYSUADX4.mjs} +2 -2
- package/dist/{token-goat-chunk-JALB3KWJ.mjs → token-goat-chunk-QO3LXVVR.mjs} +4247 -5005
- package/dist/{token-goat-chunk-L45IWWMC.mjs → token-goat-chunk-RLP6J7WR.mjs} +6 -6
- package/dist/token-goat-chunk-RQGGMPCR.mjs +205 -0
- package/dist/{token-goat-chunk-MBDJR6HU.mjs → token-goat-chunk-RTMVLHWX.mjs} +3708 -4003
- package/dist/{token-goat-chunk-E3K3BTEQ.mjs → token-goat-chunk-S4VSXURL.mjs} +8 -6
- package/dist/{token-goat-chunk-LKSXAMJB.mjs → token-goat-chunk-SE6E4BKJ.mjs} +1 -1
- package/dist/token-goat-chunk-TCQANXYC.mjs +351 -0
- package/dist/token-goat-chunk-TDUT2CL6.mjs +564 -0
- package/dist/{token-goat-chunk-LRIZ7K3F.mjs → token-goat-chunk-TGOXNAHW.mjs} +54 -111
- package/dist/{token-goat-chunk-WNBSCSAI.mjs → token-goat-chunk-UA5BKWWQ.mjs} +1 -1
- package/dist/{token-goat-chunk-RIB6XY2V.mjs → token-goat-chunk-UXSXQQIY.mjs} +1 -1
- package/dist/{token-goat-chunk-7EPYB34H.mjs → token-goat-chunk-VMFWNHGR.mjs} +84 -73
- package/dist/token-goat-chunk-VQ6F6T7X.mjs +36 -0
- package/dist/{token-goat-chunk-5M3NRJD2.mjs → token-goat-chunk-VZQEWRVH.mjs} +6 -4
- package/dist/{token-goat-chunk-OSUFN2FV.mjs → token-goat-chunk-XB5KKOCG.mjs} +5 -25
- package/dist/{token-goat-chunk-6E2IDLHF.mjs → token-goat-chunk-XYWPOSCN.mjs} +57 -615
- package/dist/{token-goat-chunk-CQHY4SL7.mjs → token-goat-chunk-YAGLESS3.mjs} +8 -5
- package/dist/token-goat-chunk-YKSRAWUU.mjs +33 -0
- package/dist/{token-goat-chunk-F2ARFHLJ.mjs → token-goat-chunk-YOOVFPTP.mjs} +2 -2
- package/dist/{token-goat-chunk-EEIDFMEM.mjs → token-goat-chunk-YZAAZU2S.mjs} +12 -3
- package/dist/token-goat-chunk-Z6KBMOBI.mjs +53 -0
- package/dist/{token-goat-chunk-4GEDH2WU.mjs → token-goat-chunk-ZER6EAXZ.mjs} +81 -70
- package/dist/token-goat-hook-client.cjs +475 -0
- package/dist/token-goat-hook-client.mjs +26 -0
- package/dist/token-goat-hook.mjs +31 -21
- package/dist/token-goat.core.mjs +9 -39
- package/docs/C4_RUNTIME_ARCHITECTURE.md +2 -2
- package/docs/cli.md +35 -23
- package/docs/install.md +18 -14
- package/package.json +1 -1
- package/dist/token-goat-chunk-ADMR3QVF.mjs +0 -41
- package/dist/token-goat-chunk-E6B2UFDF.mjs +0 -30
- package/dist/token-goat-chunk-GKZ2US5B.mjs +0 -187
- package/dist/token-goat-chunk-MZTO4FXH.mjs +0 -26
|
@@ -1,516 +1,74 @@
|
|
|
1
1
|
import { createRequire as __cjsRequire } from 'node:module';
|
|
2
2
|
const require = __cjsRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
GENERIC_SERVED_OUTPUT_KEY,
|
|
5
|
+
MAX_GENERIC_SERVED_OUTPUTS,
|
|
6
|
+
MAX_OUTSTANDING_AGENT_SPAWNS,
|
|
7
|
+
MAX_RANGES_PER_FILE,
|
|
8
|
+
MAX_SEEN_IMAGE_HASHES,
|
|
9
|
+
MAX_SERVED_OUTPUTS_PER_FILE,
|
|
10
|
+
consumedCurlDownloadKeys,
|
|
11
|
+
consumedFileLineRangeKeys,
|
|
12
|
+
consumedFileServedOutputKeys,
|
|
13
|
+
consumedOutstandingAgentSpawnKeys,
|
|
14
|
+
consumedPendingLargeFileHintKeys,
|
|
15
|
+
curlDownloadsAtLoad,
|
|
16
|
+
exportSessionState,
|
|
17
|
+
filesFullReadCountAtLoad,
|
|
18
|
+
filesReadCountAtLoad,
|
|
19
|
+
importSessionState,
|
|
20
|
+
migrateCurlDownloadKey,
|
|
21
|
+
migrateWebFetchKey,
|
|
22
|
+
outstandingAgentSpawnKey,
|
|
23
|
+
outstandingAgentSpawnsAtLoad,
|
|
24
|
+
pendingLargeFileHintsAtLoad
|
|
25
|
+
} from "./token-goat-chunk-TDUT2CL6.mjs";
|
|
3
26
|
import {
|
|
4
27
|
claudeConfigDir,
|
|
5
28
|
readTranscriptTail
|
|
6
|
-
} from "./token-goat-chunk-
|
|
29
|
+
} from "./token-goat-chunk-ONXH6NZ5.mjs";
|
|
7
30
|
import {
|
|
8
31
|
DEFAULT_MAX_AGE_MS,
|
|
9
|
-
DEFAULT_MAX_COUNT
|
|
32
|
+
DEFAULT_MAX_COUNT
|
|
33
|
+
} from "./token-goat-chunk-D4ETHJD6.mjs";
|
|
34
|
+
import {
|
|
10
35
|
recordStat,
|
|
11
36
|
redactSecrets
|
|
12
|
-
} from "./token-goat-chunk-
|
|
37
|
+
} from "./token-goat-chunk-CIQ2FTY3.mjs";
|
|
13
38
|
import {
|
|
14
39
|
detectHarness,
|
|
15
40
|
isAutoTriggerMultiplierExplicit,
|
|
16
41
|
loadConfig,
|
|
17
42
|
shortFingerprint
|
|
18
|
-
} from "./token-goat-chunk-
|
|
43
|
+
} from "./token-goat-chunk-TGOXNAHW.mjs";
|
|
19
44
|
import {
|
|
20
45
|
registerReset
|
|
21
|
-
} from "./token-goat-chunk-
|
|
46
|
+
} from "./token-goat-chunk-YZAAZU2S.mjs";
|
|
22
47
|
import {
|
|
23
48
|
LOCK_WAIT_MS_HARDENED,
|
|
24
49
|
atomicWriteText,
|
|
25
|
-
dataDir,
|
|
26
50
|
ensureDirSync,
|
|
27
|
-
foldPath,
|
|
28
51
|
isCodeFenceDelimiter,
|
|
29
52
|
normalizePathForwardSlash,
|
|
30
53
|
sanitizeIdForFilename,
|
|
31
54
|
stripLower,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
} from "./token-goat-chunk-
|
|
55
|
+
withFileLock,
|
|
56
|
+
withRetryOnLock
|
|
57
|
+
} from "./token-goat-chunk-XYWPOSCN.mjs";
|
|
58
|
+
import {
|
|
59
|
+
foldPath
|
|
60
|
+
} from "./token-goat-chunk-TCQANXYC.mjs";
|
|
35
61
|
import {
|
|
36
62
|
normalizePath
|
|
37
63
|
} from "./token-goat-chunk-NMTKNYGF.mjs";
|
|
64
|
+
import {
|
|
65
|
+
dataDir,
|
|
66
|
+
tokenGoatHome
|
|
67
|
+
} from "./token-goat-chunk-MELOKFDJ.mjs";
|
|
38
68
|
import {
|
|
39
69
|
init_define_import_meta_env
|
|
40
70
|
} from "./token-goat-chunk-A37V4PBF.mjs";
|
|
41
71
|
|
|
42
|
-
// src/session.ts
|
|
43
|
-
init_define_import_meta_env();
|
|
44
|
-
import { randomBytes, randomUUID } from "node:crypto";
|
|
45
|
-
import * as fs from "node:fs";
|
|
46
|
-
var _files = /* @__PURE__ */ new Map();
|
|
47
|
-
var _filesAtLoad = /* @__PURE__ */ new Map();
|
|
48
|
-
var _filesFullReadCountAtLoad = /* @__PURE__ */ new Map();
|
|
49
|
-
var _hintsShown = /* @__PURE__ */ new Set();
|
|
50
|
-
var _scheduledPromptCounts = /* @__PURE__ */ new Map();
|
|
51
|
-
var _webFetches = /* @__PURE__ */ new Map();
|
|
52
|
-
var _bashOutputs = /* @__PURE__ */ new Map();
|
|
53
|
-
var _grepQueries = /* @__PURE__ */ new Map();
|
|
54
|
-
var _globQueries = /* @__PURE__ */ new Map();
|
|
55
|
-
var _lastTabContext = null;
|
|
56
|
-
var _seenImageHashes = [];
|
|
57
|
-
var _outstandingAgentSpawns = [];
|
|
58
|
-
var _outstandingAgentSpawnsAtLoad = [];
|
|
59
|
-
var _bashReruns = /* @__PURE__ */ new Set();
|
|
60
|
-
var _curlDownloads = /* @__PURE__ */ new Map();
|
|
61
|
-
var _curlDownloadsAtLoad = /* @__PURE__ */ new Map();
|
|
62
|
-
var _fileLineRanges = /* @__PURE__ */ new Map();
|
|
63
|
-
var _fileServedOutputs = /* @__PURE__ */ new Map();
|
|
64
|
-
var _fileLineRangesAtLoad = /* @__PURE__ */ new Map();
|
|
65
|
-
var _fileServedOutputsAtLoad = /* @__PURE__ */ new Map();
|
|
66
|
-
var _compactedAt = 0;
|
|
67
|
-
var _cliReads = /* @__PURE__ */ new Set();
|
|
68
|
-
var _pendingLargeFileHints = /* @__PURE__ */ new Map();
|
|
69
|
-
var _pendingLargeFileHintsAtLoad = /* @__PURE__ */ new Map();
|
|
70
|
-
var _sessionId = null;
|
|
71
|
-
var _transcriptPath = null;
|
|
72
|
-
function fileSize(absPath) {
|
|
73
|
-
try {
|
|
74
|
-
return fs.statSync(absPath).size;
|
|
75
|
-
} catch {
|
|
76
|
-
return 0;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
function resolveFilesKey(normalized) {
|
|
80
|
-
if (_files.has(normalized)) return normalized;
|
|
81
|
-
const folded = foldPath(normalized);
|
|
82
|
-
if (folded === normalized) return normalized;
|
|
83
|
-
for (const existingKey of _files.keys()) {
|
|
84
|
-
if (foldPath(existingKey) === folded) return existingKey;
|
|
85
|
-
}
|
|
86
|
-
return normalized;
|
|
87
|
-
}
|
|
88
|
-
function recordFileRead(filePath, isFullRead = true) {
|
|
89
|
-
const normalized = normalizePath(filePath);
|
|
90
|
-
const key = resolveFilesKey(normalized);
|
|
91
|
-
const now = Date.now();
|
|
92
|
-
const size = fileSize(normalized);
|
|
93
|
-
const prev = _files.get(key);
|
|
94
|
-
if (prev === void 0) {
|
|
95
|
-
_files.set(key, {
|
|
96
|
-
path: key,
|
|
97
|
-
readCount: 1,
|
|
98
|
-
lastReadAt: now,
|
|
99
|
-
wasEdited: false,
|
|
100
|
-
sizeBytes: size,
|
|
101
|
-
...isFullRead ? { lastFullReadAt: now, fullReadCount: 1 } : {}
|
|
102
|
-
});
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
_files.set(key, {
|
|
106
|
-
...prev,
|
|
107
|
-
readCount: prev.readCount + 1,
|
|
108
|
-
lastReadAt: now,
|
|
109
|
-
sizeBytes: size,
|
|
110
|
-
...isFullRead ? { lastFullReadAt: now, fullReadCount: (prev.fullReadCount ?? 0) + 1 } : {}
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
var MAX_SYMBOLS_PER_FILE = 25;
|
|
114
|
-
function recordSymbolRead(filePath, symbol) {
|
|
115
|
-
const normalized = normalizePath(filePath);
|
|
116
|
-
const key = resolveFilesKey(normalized);
|
|
117
|
-
const prev = _files.get(key);
|
|
118
|
-
if (prev === void 0) {
|
|
119
|
-
_files.set(key, {
|
|
120
|
-
path: key,
|
|
121
|
-
readCount: 0,
|
|
122
|
-
lastReadAt: Date.now(),
|
|
123
|
-
wasEdited: false,
|
|
124
|
-
sizeBytes: fileSize(normalized),
|
|
125
|
-
symbols_read: [symbol]
|
|
126
|
-
});
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
const existing = prev.symbols_read ?? [];
|
|
130
|
-
if (existing.includes(symbol)) return;
|
|
131
|
-
const symbols_read = [...existing, symbol].slice(-MAX_SYMBOLS_PER_FILE);
|
|
132
|
-
_files.set(key, { ...prev, symbols_read });
|
|
133
|
-
}
|
|
134
|
-
function filesReadCountAtLoad() {
|
|
135
|
-
return _filesAtLoad;
|
|
136
|
-
}
|
|
137
|
-
function filesFullReadCountAtLoad() {
|
|
138
|
-
return _filesFullReadCountAtLoad;
|
|
139
|
-
}
|
|
140
|
-
function recordFileEdit(filePath) {
|
|
141
|
-
const normalized = normalizePath(filePath);
|
|
142
|
-
const key = resolveFilesKey(normalized);
|
|
143
|
-
_fileLineRanges.delete(foldPath(normalized));
|
|
144
|
-
const prev = _files.get(key);
|
|
145
|
-
if (prev === void 0) {
|
|
146
|
-
_files.set(key, {
|
|
147
|
-
path: key,
|
|
148
|
-
readCount: 0,
|
|
149
|
-
lastReadAt: 0,
|
|
150
|
-
wasEdited: true,
|
|
151
|
-
sizeBytes: fileSize(normalized)
|
|
152
|
-
});
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
_files.set(key, { ...prev, wasEdited: true });
|
|
156
|
-
}
|
|
157
|
-
function getSessionFiles() {
|
|
158
|
-
return _files;
|
|
159
|
-
}
|
|
160
|
-
function wasFileReadThisSession(filePath) {
|
|
161
|
-
const entry = _files.get(resolveFilesKey(normalizePath(filePath)));
|
|
162
|
-
return entry !== void 0 && entry.readCount > 0 && entry.lastReadAt >= _compactedAt;
|
|
163
|
-
}
|
|
164
|
-
function wasFileFullyReadThisSession(filePath) {
|
|
165
|
-
const entry = _files.get(resolveFilesKey(normalizePath(filePath)));
|
|
166
|
-
return entry !== void 0 && entry.lastFullReadAt !== void 0 && entry.lastFullReadAt >= _compactedAt;
|
|
167
|
-
}
|
|
168
|
-
function getCompactedAt() {
|
|
169
|
-
return _compactedAt;
|
|
170
|
-
}
|
|
171
|
-
function markCompacted(now = Date.now()) {
|
|
172
|
-
if (now <= _compactedAt) return;
|
|
173
|
-
_compactedAt = now;
|
|
174
|
-
_fileLineRanges = /* @__PURE__ */ new Map();
|
|
175
|
-
_fileServedOutputs = /* @__PURE__ */ new Map();
|
|
176
|
-
}
|
|
177
|
-
function getSessionFileEntry(filePath) {
|
|
178
|
-
return _files.get(resolveFilesKey(normalizePath(filePath)));
|
|
179
|
-
}
|
|
180
|
-
function wasHintShown(hintKey) {
|
|
181
|
-
return _hintsShown.has(hintKey);
|
|
182
|
-
}
|
|
183
|
-
function markHintShown(hintKey) {
|
|
184
|
-
_hintsShown.add(hintKey);
|
|
185
|
-
}
|
|
186
|
-
function recordScheduledPrompt(sessionId) {
|
|
187
|
-
const count = (_scheduledPromptCounts.get(sessionId) ?? 0) + 1;
|
|
188
|
-
_scheduledPromptCounts.set(sessionId, count);
|
|
189
|
-
return count;
|
|
190
|
-
}
|
|
191
|
-
function wasCliReadThisSession(cliReadKey) {
|
|
192
|
-
return _cliReads.has(cliReadKey);
|
|
193
|
-
}
|
|
194
|
-
function recordCliRead(cliReadKey) {
|
|
195
|
-
_cliReads.add(cliReadKey);
|
|
196
|
-
}
|
|
197
|
-
function recordLargeFileHintPending(filePath, sizeBytes) {
|
|
198
|
-
_pendingLargeFileHints.set(foldPath(normalizePath(filePath)), sizeBytes);
|
|
199
|
-
}
|
|
200
|
-
function takePendingLargeFileHint(filePath) {
|
|
201
|
-
const key = foldPath(normalizePath(filePath));
|
|
202
|
-
const size = _pendingLargeFileHints.get(key);
|
|
203
|
-
if (size === void 0) return null;
|
|
204
|
-
_pendingLargeFileHints.delete(key);
|
|
205
|
-
return size;
|
|
206
|
-
}
|
|
207
|
-
function consumedPendingLargeFileHintKeys() {
|
|
208
|
-
const consumed = [];
|
|
209
|
-
for (const key of _pendingLargeFileHintsAtLoad.keys()) {
|
|
210
|
-
if (!_pendingLargeFileHints.has(key)) consumed.push(key);
|
|
211
|
-
}
|
|
212
|
-
return consumed;
|
|
213
|
-
}
|
|
214
|
-
function pendingLargeFileHintsAtLoad() {
|
|
215
|
-
return _pendingLargeFileHintsAtLoad;
|
|
216
|
-
}
|
|
217
|
-
var WEB_FETCH_KEY_SEP = "\0";
|
|
218
|
-
function webFetchKey(url, prompt) {
|
|
219
|
-
const digest = shortFingerprint(`${url}${WEB_FETCH_KEY_SEP}${prompt}`);
|
|
220
|
-
return [redactSecrets(url).text, redactSecrets(prompt).text, digest].join(WEB_FETCH_KEY_SEP);
|
|
221
|
-
}
|
|
222
|
-
function recordWebFetch(url, prompt, cacheId) {
|
|
223
|
-
_webFetches.set(webFetchKey(url, prompt), cacheId);
|
|
224
|
-
}
|
|
225
|
-
function migrateCurlDownloadKey(key) {
|
|
226
|
-
if (/^[0-9a-f]{16}$/.test(key)) return key;
|
|
227
|
-
return curlDownloadKey(key);
|
|
228
|
-
}
|
|
229
|
-
function migrateWebFetchKey(key) {
|
|
230
|
-
const parts = key.split(WEB_FETCH_KEY_SEP);
|
|
231
|
-
if (parts.length !== 2) return key;
|
|
232
|
-
return webFetchKey(parts[0] ?? "", parts[1] ?? "");
|
|
233
|
-
}
|
|
234
|
-
function getSessionWebFetches() {
|
|
235
|
-
return _webFetches;
|
|
236
|
-
}
|
|
237
|
-
function recordBashOutput(commandHash, outputId, _sizeBytes) {
|
|
238
|
-
_bashOutputs.set(commandHash, outputId);
|
|
239
|
-
}
|
|
240
|
-
function getSessionBashOutputs() {
|
|
241
|
-
return Array.from(_bashOutputs.entries());
|
|
242
|
-
}
|
|
243
|
-
function recordBashRerun(commandHash) {
|
|
244
|
-
_bashReruns.add(commandHash);
|
|
245
|
-
}
|
|
246
|
-
function getSessionBashReruns() {
|
|
247
|
-
return Array.from(_bashReruns);
|
|
248
|
-
}
|
|
249
|
-
function getBashOutputId(commandHash) {
|
|
250
|
-
return _bashOutputs.get(commandHash) ?? null;
|
|
251
|
-
}
|
|
252
|
-
function recordGrepQuery(signature, matchCount) {
|
|
253
|
-
_grepQueries.set(signature, matchCount);
|
|
254
|
-
}
|
|
255
|
-
function getGrepMatchCount(signature) {
|
|
256
|
-
return _grepQueries.get(signature) ?? null;
|
|
257
|
-
}
|
|
258
|
-
function recordGlobQuery(signature, matchCount) {
|
|
259
|
-
_globQueries.set(signature, matchCount);
|
|
260
|
-
}
|
|
261
|
-
function getGlobMatchCount(signature) {
|
|
262
|
-
return _globQueries.get(signature) ?? null;
|
|
263
|
-
}
|
|
264
|
-
function setLastTabContext(text) {
|
|
265
|
-
_lastTabContext = shortFingerprint(text);
|
|
266
|
-
}
|
|
267
|
-
function lastTabContextMatches(text) {
|
|
268
|
-
return _lastTabContext !== null && _lastTabContext === shortFingerprint(text);
|
|
269
|
-
}
|
|
270
|
-
var MAX_SEEN_IMAGE_HASHES = 16;
|
|
271
|
-
function hasSeenImage(hash) {
|
|
272
|
-
return _seenImageHashes.includes(hash);
|
|
273
|
-
}
|
|
274
|
-
function recordSeenImage(hash) {
|
|
275
|
-
const at = _seenImageHashes.indexOf(hash);
|
|
276
|
-
if (at !== -1) _seenImageHashes.splice(at, 1);
|
|
277
|
-
_seenImageHashes.push(hash);
|
|
278
|
-
if (_seenImageHashes.length > MAX_SEEN_IMAGE_HASHES) {
|
|
279
|
-
_seenImageHashes.splice(0, _seenImageHashes.length - MAX_SEEN_IMAGE_HASHES);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
var MAX_OUTSTANDING_AGENT_SPAWNS = 30;
|
|
283
|
-
function recordOutstandingAgentSpawn(prompt) {
|
|
284
|
-
_outstandingAgentSpawns.push({ prompt: redactSecrets(prompt).text, ts: Date.now() });
|
|
285
|
-
if (_outstandingAgentSpawns.length > MAX_OUTSTANDING_AGENT_SPAWNS) {
|
|
286
|
-
_outstandingAgentSpawns.splice(0, _outstandingAgentSpawns.length - MAX_OUTSTANDING_AGENT_SPAWNS);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
function getOutstandingAgentSpawns() {
|
|
290
|
-
return _outstandingAgentSpawns;
|
|
291
|
-
}
|
|
292
|
-
function removeOutstandingAgentSpawn(finishedPrompt) {
|
|
293
|
-
const idx = _outstandingAgentSpawns.findIndex((e) => finishedPrompt.startsWith(e.prompt));
|
|
294
|
-
if (idx !== -1) _outstandingAgentSpawns.splice(idx, 1);
|
|
295
|
-
}
|
|
296
|
-
function outstandingAgentSpawnKey(prompt, ts) {
|
|
297
|
-
return `${prompt} ${ts}`;
|
|
298
|
-
}
|
|
299
|
-
function outstandingAgentSpawnsAtLoad() {
|
|
300
|
-
return _outstandingAgentSpawnsAtLoad;
|
|
301
|
-
}
|
|
302
|
-
function consumedOutstandingAgentSpawnKeys() {
|
|
303
|
-
const currentKeys = new Set(_outstandingAgentSpawns.map((e) => outstandingAgentSpawnKey(e.prompt, e.ts)));
|
|
304
|
-
const consumed = [];
|
|
305
|
-
for (const e of _outstandingAgentSpawnsAtLoad) {
|
|
306
|
-
const key = outstandingAgentSpawnKey(e.prompt, e.ts);
|
|
307
|
-
if (!currentKeys.has(key)) consumed.push(key);
|
|
308
|
-
}
|
|
309
|
-
return consumed;
|
|
310
|
-
}
|
|
311
|
-
function curlDownloadKey(url) {
|
|
312
|
-
return shortFingerprint(url);
|
|
313
|
-
}
|
|
314
|
-
function recordCurlDownload(url, savedPath) {
|
|
315
|
-
_curlDownloads.set(curlDownloadKey(url), savedPath);
|
|
316
|
-
}
|
|
317
|
-
function getCurlDownloadPath(url) {
|
|
318
|
-
return _curlDownloads.get(curlDownloadKey(url)) ?? null;
|
|
319
|
-
}
|
|
320
|
-
function clearCurlDownload(url) {
|
|
321
|
-
_curlDownloads.delete(curlDownloadKey(url));
|
|
322
|
-
}
|
|
323
|
-
function curlDownloadsAtLoad() {
|
|
324
|
-
return _curlDownloadsAtLoad;
|
|
325
|
-
}
|
|
326
|
-
function consumedCurlDownloadKeys() {
|
|
327
|
-
const consumed = [];
|
|
328
|
-
for (const url of _curlDownloadsAtLoad.keys()) {
|
|
329
|
-
if (!_curlDownloads.has(url)) consumed.push(url);
|
|
330
|
-
}
|
|
331
|
-
return consumed;
|
|
332
|
-
}
|
|
333
|
-
function consumedFileLineRangeKeys() {
|
|
334
|
-
const consumed = [];
|
|
335
|
-
for (const key of _fileLineRangesAtLoad.keys()) {
|
|
336
|
-
if (!_fileLineRanges.has(key)) consumed.push(key);
|
|
337
|
-
}
|
|
338
|
-
return consumed;
|
|
339
|
-
}
|
|
340
|
-
function consumedFileServedOutputKeys() {
|
|
341
|
-
const consumed = [];
|
|
342
|
-
for (const key of _fileServedOutputsAtLoad.keys()) {
|
|
343
|
-
if (!_fileServedOutputs.has(key)) consumed.push(key);
|
|
344
|
-
}
|
|
345
|
-
return consumed;
|
|
346
|
-
}
|
|
347
|
-
var MAX_RANGES_PER_FILE = 64;
|
|
348
|
-
function statIdentity(absPath) {
|
|
349
|
-
try {
|
|
350
|
-
const st = fs.statSync(absPath);
|
|
351
|
-
return { size: st.size, mtimeMs: st.mtimeMs };
|
|
352
|
-
} catch {
|
|
353
|
-
return void 0;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
function recordFileLineRange(filePath, start, end) {
|
|
357
|
-
const normalized = normalizePath(filePath);
|
|
358
|
-
const key = foldPath(normalized);
|
|
359
|
-
const ranges = _fileLineRanges.get(key) ?? [];
|
|
360
|
-
if (!ranges.some(([s, e]) => s === start && e === end)) {
|
|
361
|
-
ranges.push([start, end]);
|
|
362
|
-
if (ranges.length > MAX_RANGES_PER_FILE) ranges.splice(0, ranges.length - MAX_RANGES_PER_FILE);
|
|
363
|
-
_fileLineRanges.set(key, ranges);
|
|
364
|
-
}
|
|
365
|
-
const entryKey = resolveFilesKey(normalized);
|
|
366
|
-
const entry = _files.get(entryKey);
|
|
367
|
-
const identity = statIdentity(normalized);
|
|
368
|
-
if (entry && identity) _files.set(entryKey, { ...entry, rangeFileIdentity: identity });
|
|
369
|
-
}
|
|
370
|
-
function getFileLineRanges(filePath) {
|
|
371
|
-
return _fileLineRanges.get(foldPath(normalizePath(filePath))) ?? [];
|
|
372
|
-
}
|
|
373
|
-
function resetFileLineRanges(filePath) {
|
|
374
|
-
_fileLineRanges.delete(foldPath(normalizePath(filePath)));
|
|
375
|
-
}
|
|
376
|
-
var MAX_SERVED_OUTPUTS_PER_FILE = 8;
|
|
377
|
-
var GENERIC_SERVED_OUTPUT_KEY = "\0<bash-generic-served>";
|
|
378
|
-
var GENERIC_SERVED_OUTPUT_FOLDED_KEY = foldPath(normalizePath(GENERIC_SERVED_OUTPUT_KEY));
|
|
379
|
-
var MAX_GENERIC_SERVED_OUTPUTS = 32;
|
|
380
|
-
function recordFileServedOutput(filePath, outputId) {
|
|
381
|
-
const key = foldPath(normalizePath(filePath));
|
|
382
|
-
const cap = key === GENERIC_SERVED_OUTPUT_FOLDED_KEY ? MAX_GENERIC_SERVED_OUTPUTS : MAX_SERVED_OUTPUTS_PER_FILE;
|
|
383
|
-
const ids = (_fileServedOutputs.get(key) ?? []).filter((id) => id !== outputId);
|
|
384
|
-
ids.push(outputId);
|
|
385
|
-
if (ids.length > cap) ids.splice(0, ids.length - cap);
|
|
386
|
-
_fileServedOutputs.set(key, ids);
|
|
387
|
-
}
|
|
388
|
-
function getFileServedOutputs(filePath) {
|
|
389
|
-
return _fileServedOutputs.get(foldPath(normalizePath(filePath))) ?? [];
|
|
390
|
-
}
|
|
391
|
-
function markFileTruncated(filePath, isFullRead = true) {
|
|
392
|
-
const normalized = normalizePath(filePath);
|
|
393
|
-
const key = resolveFilesKey(normalized);
|
|
394
|
-
const prev = _files.get(key);
|
|
395
|
-
const now = Date.now();
|
|
396
|
-
if (prev === void 0) {
|
|
397
|
-
_files.set(key, {
|
|
398
|
-
path: key,
|
|
399
|
-
readCount: 1,
|
|
400
|
-
lastReadAt: now,
|
|
401
|
-
wasEdited: false,
|
|
402
|
-
sizeBytes: fileSize(normalized),
|
|
403
|
-
wasTruncated: true,
|
|
404
|
-
...isFullRead ? { lastFullReadAt: now, fullReadCount: 1 } : {}
|
|
405
|
-
});
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
_files.set(key, { ...prev, wasTruncated: true });
|
|
409
|
-
}
|
|
410
|
-
function wasFileTruncatedThisSession(filePath) {
|
|
411
|
-
const entry = _files.get(resolveFilesKey(normalizePath(filePath)));
|
|
412
|
-
return entry?.wasTruncated === true;
|
|
413
|
-
}
|
|
414
|
-
function generateSessionId() {
|
|
415
|
-
try {
|
|
416
|
-
return randomUUID();
|
|
417
|
-
} catch {
|
|
418
|
-
return randomBytes(16).toString("hex");
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
function getSessionId() {
|
|
422
|
-
if (_sessionId !== null) return _sessionId;
|
|
423
|
-
const fromEnv = process.env["CLAUDE_CODE_SESSION_ID"];
|
|
424
|
-
_sessionId = fromEnv !== void 0 && fromEnv !== "" ? fromEnv : generateSessionId();
|
|
425
|
-
return _sessionId;
|
|
426
|
-
}
|
|
427
|
-
function setTranscriptPath(path4, sessionId) {
|
|
428
|
-
if (path4 === "") return;
|
|
429
|
-
_transcriptPath = { path: path4, sessionId };
|
|
430
|
-
}
|
|
431
|
-
function getTranscriptPath() {
|
|
432
|
-
if (_transcriptPath === null) return void 0;
|
|
433
|
-
return _transcriptPath.sessionId === getSessionId() ? _transcriptPath.path : void 0;
|
|
434
|
-
}
|
|
435
|
-
function exportSessionState() {
|
|
436
|
-
return {
|
|
437
|
-
files: Array.from(_files.values()),
|
|
438
|
-
hintsShown: Array.from(_hintsShown),
|
|
439
|
-
..._scheduledPromptCounts.size > 0 ? { scheduledPromptCounts: Array.from(_scheduledPromptCounts.entries()) } : {},
|
|
440
|
-
webFetches: Array.from(_webFetches.entries()),
|
|
441
|
-
bashOutputs: Array.from(_bashOutputs.entries()),
|
|
442
|
-
bashReruns: Array.from(_bashReruns),
|
|
443
|
-
curlDownloads: Array.from(_curlDownloads.entries()),
|
|
444
|
-
fileLineRanges: Array.from(_fileLineRanges.entries()),
|
|
445
|
-
..._fileServedOutputs.size > 0 ? { fileServedOutputs: Array.from(_fileServedOutputs.entries()) } : {},
|
|
446
|
-
cliReads: Array.from(_cliReads),
|
|
447
|
-
pendingLargeFileHints: Array.from(_pendingLargeFileHints.entries()),
|
|
448
|
-
grepQueries: Array.from(_grepQueries.entries()),
|
|
449
|
-
globQueries: Array.from(_globQueries.entries()),
|
|
450
|
-
outstandingAgentSpawns: _outstandingAgentSpawns.map((e) => [e.prompt, e.ts]),
|
|
451
|
-
..._lastTabContext !== null ? { lastTabContextDigest: _lastTabContext } : {},
|
|
452
|
-
..._seenImageHashes.length > 0 ? { seenImageHashes: [..._seenImageHashes] } : {},
|
|
453
|
-
..._compactedAt > 0 ? { compactedAt: _compactedAt } : {}
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
function importSessionState(s) {
|
|
457
|
-
_files = /* @__PURE__ */ new Map();
|
|
458
|
-
for (const e of s.files) {
|
|
459
|
-
if (e && typeof e.path === "string") _files.set(e.path, e);
|
|
460
|
-
}
|
|
461
|
-
_filesAtLoad = new Map(Array.from(_files, ([key, e]) => [key, e.readCount]));
|
|
462
|
-
_filesFullReadCountAtLoad = new Map(Array.from(_files, ([key, e]) => [key, e.fullReadCount ?? 0]));
|
|
463
|
-
_hintsShown = new Set(s.hintsShown);
|
|
464
|
-
_scheduledPromptCounts = new Map(s.scheduledPromptCounts ?? []);
|
|
465
|
-
_webFetches = new Map(s.webFetches);
|
|
466
|
-
_bashOutputs = new Map(s.bashOutputs);
|
|
467
|
-
_bashReruns = new Set(s.bashReruns ?? []);
|
|
468
|
-
_curlDownloads = new Map(s.curlDownloads);
|
|
469
|
-
_curlDownloadsAtLoad = new Map(_curlDownloads);
|
|
470
|
-
_fileLineRanges = new Map(s.fileLineRanges ?? []);
|
|
471
|
-
_fileLineRangesAtLoad = new Map(_fileLineRanges);
|
|
472
|
-
_fileServedOutputs = new Map(s.fileServedOutputs ?? []);
|
|
473
|
-
_fileServedOutputsAtLoad = new Map(_fileServedOutputs);
|
|
474
|
-
_cliReads = new Set(s.cliReads ?? []);
|
|
475
|
-
_pendingLargeFileHints = new Map(s.pendingLargeFileHints ?? []);
|
|
476
|
-
_pendingLargeFileHintsAtLoad = new Map(_pendingLargeFileHints);
|
|
477
|
-
_grepQueries = new Map(s.grepQueries ?? []);
|
|
478
|
-
_globQueries = new Map(s.globQueries ?? []);
|
|
479
|
-
_outstandingAgentSpawns = (s.outstandingAgentSpawns ?? []).map(([prompt, ts]) => ({ prompt, ts }));
|
|
480
|
-
_outstandingAgentSpawnsAtLoad = [..._outstandingAgentSpawns];
|
|
481
|
-
_lastTabContext = s.lastTabContextDigest ?? null;
|
|
482
|
-
_seenImageHashes = [...s.seenImageHashes ?? []];
|
|
483
|
-
_compactedAt = s.compactedAt ?? 0;
|
|
484
|
-
}
|
|
485
|
-
registerReset(() => {
|
|
486
|
-
_files = /* @__PURE__ */ new Map();
|
|
487
|
-
_filesAtLoad = /* @__PURE__ */ new Map();
|
|
488
|
-
_filesFullReadCountAtLoad = /* @__PURE__ */ new Map();
|
|
489
|
-
_hintsShown = /* @__PURE__ */ new Set();
|
|
490
|
-
_scheduledPromptCounts = /* @__PURE__ */ new Map();
|
|
491
|
-
_webFetches = /* @__PURE__ */ new Map();
|
|
492
|
-
_bashOutputs = /* @__PURE__ */ new Map();
|
|
493
|
-
_bashReruns = /* @__PURE__ */ new Set();
|
|
494
|
-
_curlDownloads = /* @__PURE__ */ new Map();
|
|
495
|
-
_curlDownloadsAtLoad = /* @__PURE__ */ new Map();
|
|
496
|
-
_fileLineRanges = /* @__PURE__ */ new Map();
|
|
497
|
-
_fileLineRangesAtLoad = /* @__PURE__ */ new Map();
|
|
498
|
-
_fileServedOutputs = /* @__PURE__ */ new Map();
|
|
499
|
-
_fileServedOutputsAtLoad = /* @__PURE__ */ new Map();
|
|
500
|
-
_cliReads = /* @__PURE__ */ new Set();
|
|
501
|
-
_pendingLargeFileHints = /* @__PURE__ */ new Map();
|
|
502
|
-
_pendingLargeFileHintsAtLoad = /* @__PURE__ */ new Map();
|
|
503
|
-
_grepQueries = /* @__PURE__ */ new Map();
|
|
504
|
-
_globQueries = /* @__PURE__ */ new Map();
|
|
505
|
-
_outstandingAgentSpawns = [];
|
|
506
|
-
_outstandingAgentSpawnsAtLoad = [];
|
|
507
|
-
_lastTabContext = null;
|
|
508
|
-
_seenImageHashes = [];
|
|
509
|
-
_compactedAt = 0;
|
|
510
|
-
_sessionId = null;
|
|
511
|
-
_transcriptPath = null;
|
|
512
|
-
});
|
|
513
|
-
|
|
514
72
|
// src/sessions_dir.ts
|
|
515
73
|
init_define_import_meta_env();
|
|
516
74
|
import * as path from "node:path";
|
|
@@ -522,7 +80,7 @@ function sessionsDir() {
|
|
|
522
80
|
// src/session_store.ts
|
|
523
81
|
init_define_import_meta_env();
|
|
524
82
|
import { createHash } from "node:crypto";
|
|
525
|
-
import * as
|
|
83
|
+
import * as fs from "node:fs";
|
|
526
84
|
import * as path2 from "node:path";
|
|
527
85
|
var MAX_FILES = 500;
|
|
528
86
|
var AGENT_SALT_MARKER = sanitizeIdForFilename(":agent:");
|
|
@@ -547,6 +105,7 @@ function sessionSidecarPath(sessionId, suffix) {
|
|
|
547
105
|
const safe = sessionFileStem(sessionId);
|
|
548
106
|
if (!safe) return null;
|
|
549
107
|
if (suffix.includes("/") || suffix.includes("\\") || suffix.includes("..")) return null;
|
|
108
|
+
if (suffix !== ".json" && suffix.endsWith(".json")) return null;
|
|
550
109
|
const dir = sessionsDir();
|
|
551
110
|
const candidate = path2.join(dir, `${safe}${suffix}`);
|
|
552
111
|
try {
|
|
@@ -738,14 +297,14 @@ function mergeLineRanges(disk, mem) {
|
|
|
738
297
|
}
|
|
739
298
|
return Array.from(byPath.entries());
|
|
740
299
|
}
|
|
741
|
-
var
|
|
300
|
+
var GENERIC_SERVED_OUTPUT_FOLDED_KEY = foldPath(normalizePath(GENERIC_SERVED_OUTPUT_KEY));
|
|
742
301
|
function mergeServedOutputs(disk, mem) {
|
|
743
302
|
const byPath = /* @__PURE__ */ new Map();
|
|
744
303
|
for (const [filePath, ids] of disk) byPath.set(filePath, [...ids]);
|
|
745
304
|
for (const [filePath, ids] of mem) {
|
|
746
305
|
const prev = byPath.get(filePath) ?? [];
|
|
747
306
|
const merged = [...prev.filter((id) => !ids.includes(id)), ...ids];
|
|
748
|
-
const cap = filePath ===
|
|
307
|
+
const cap = filePath === GENERIC_SERVED_OUTPUT_FOLDED_KEY ? MAX_GENERIC_SERVED_OUTPUTS : MAX_SERVED_OUTPUTS_PER_FILE;
|
|
749
308
|
if (merged.length > cap) merged.splice(0, merged.length - cap);
|
|
750
309
|
byPath.set(filePath, merged);
|
|
751
310
|
}
|
|
@@ -838,8 +397,23 @@ function capFiles(s, max) {
|
|
|
838
397
|
}
|
|
839
398
|
function readDiskState(p) {
|
|
840
399
|
try {
|
|
841
|
-
|
|
842
|
-
|
|
400
|
+
return readDiskStateForMerge(p);
|
|
401
|
+
} catch {
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function readDiskStateForMerge(p) {
|
|
406
|
+
let text = "";
|
|
407
|
+
try {
|
|
408
|
+
withRetryOnLock(() => {
|
|
409
|
+
text = fs.readFileSync(p, "utf8");
|
|
410
|
+
});
|
|
411
|
+
} catch (err) {
|
|
412
|
+
if (err.code === "ENOENT") return null;
|
|
413
|
+
throw err;
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
return coerce(JSON.parse(text));
|
|
843
417
|
} catch {
|
|
844
418
|
return null;
|
|
845
419
|
}
|
|
@@ -856,8 +430,8 @@ function listSiblingSessionStates(sessionId) {
|
|
|
856
430
|
const dir = sessionsDir();
|
|
857
431
|
const out = [];
|
|
858
432
|
try {
|
|
859
|
-
if (!
|
|
860
|
-
for (const file of
|
|
433
|
+
if (!fs.existsSync(dir)) return out;
|
|
434
|
+
for (const file of fs.readdirSync(dir)) {
|
|
861
435
|
if (!file.endsWith(".json") || !file.startsWith(prefix)) continue;
|
|
862
436
|
const state = readDiskState(path2.join(dir, file));
|
|
863
437
|
if (state !== null) out.push(state);
|
|
@@ -867,22 +441,20 @@ function listSiblingSessionStates(sessionId) {
|
|
|
867
441
|
}
|
|
868
442
|
return out;
|
|
869
443
|
}
|
|
444
|
+
var EMPTY_SESSION = { files: [], hintsShown: [], webFetches: [], bashOutputs: [], curlDownloads: [] };
|
|
870
445
|
function loadSessionState(sessionId) {
|
|
871
446
|
const p = sessionPath(sessionId);
|
|
872
|
-
|
|
873
|
-
const disk = readDiskState(p);
|
|
874
|
-
if (disk === null) return;
|
|
875
|
-
importSessionState(disk);
|
|
447
|
+
importSessionState((p ? readDiskState(p) : null) ?? EMPTY_SESSION);
|
|
876
448
|
}
|
|
877
449
|
function saveSessionState(sessionId) {
|
|
878
450
|
const p = sessionPath(sessionId);
|
|
879
451
|
if (!p) return;
|
|
880
452
|
try {
|
|
881
453
|
const dir = path2.dirname(p);
|
|
882
|
-
if (!
|
|
454
|
+
if (!fs.existsSync(dir)) ensureDirSync(dir);
|
|
883
455
|
const mem = exportSessionState();
|
|
884
456
|
const writeMerged = () => {
|
|
885
|
-
const disk =
|
|
457
|
+
const disk = readDiskStateForMerge(p);
|
|
886
458
|
const merged = capFiles(disk ? mergeSessionState(disk, mem) : mem, MAX_FILES);
|
|
887
459
|
if (merged.created_ts === void 0) merged.created_ts = Date.now() / 1e3;
|
|
888
460
|
let json;
|
|
@@ -901,9 +473,9 @@ function saveSessionState(sessionId) {
|
|
|
901
473
|
|
|
902
474
|
// src/skill_cache.ts
|
|
903
475
|
init_define_import_meta_env();
|
|
904
|
-
import * as
|
|
476
|
+
import * as fs2 from "fs/promises";
|
|
905
477
|
import { resolve } from "path";
|
|
906
|
-
import { readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync2, statSync
|
|
478
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync2, statSync, unlinkSync } from "node:fs";
|
|
907
479
|
var COMPACT_END_MARKER = "<!-- COMPACT_END -->";
|
|
908
480
|
var SKILLS_OUTPUT_SUBDIR = "skills";
|
|
909
481
|
var _skillOutputsDirOverride = null;
|
|
@@ -1068,14 +640,14 @@ function extractChecklistSection(body) {
|
|
|
1068
640
|
async function listOutputs() {
|
|
1069
641
|
try {
|
|
1070
642
|
const dir = skillOutputsDir();
|
|
1071
|
-
const entries = await
|
|
643
|
+
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
1072
644
|
const metas = [];
|
|
1073
645
|
for (const entry of entries) {
|
|
1074
646
|
if (!entry.isFile() || !entry.name.endsWith(".meta")) {
|
|
1075
647
|
continue;
|
|
1076
648
|
}
|
|
1077
649
|
try {
|
|
1078
|
-
const content = await
|
|
650
|
+
const content = await fs2.readFile(resolve(dir, entry.name), "utf-8");
|
|
1079
651
|
const meta = JSON.parse(content);
|
|
1080
652
|
metas.push(meta);
|
|
1081
653
|
} catch {
|
|
@@ -1126,7 +698,7 @@ async function findCrossSessionEntry(skillName, contentSha) {
|
|
|
1126
698
|
const dir = skillOutputsDir();
|
|
1127
699
|
const bodyPath = resolve(dir, `${meta.outputId}.txt`);
|
|
1128
700
|
try {
|
|
1129
|
-
const bodyExists = await
|
|
701
|
+
const bodyExists = await fs2.access(bodyPath).then(() => true).catch(() => false);
|
|
1130
702
|
if (bodyExists) {
|
|
1131
703
|
return meta;
|
|
1132
704
|
}
|
|
@@ -1262,7 +834,7 @@ async function readSkillHits(skillName) {
|
|
|
1262
834
|
if (!name) return { count: 0, lastTs: 0 };
|
|
1263
835
|
const dir = skillOutputsDir();
|
|
1264
836
|
const hitsFile = resolve(dir, `${sanitizeSkillId(name)}.hits`);
|
|
1265
|
-
const content = await
|
|
837
|
+
const content = await fs2.readFile(hitsFile, "utf-8").catch(() => null);
|
|
1266
838
|
if (content) {
|
|
1267
839
|
const parsed = JSON.parse(content);
|
|
1268
840
|
return parsed;
|
|
@@ -1290,14 +862,14 @@ function runExclusiveInProcess(key, fn) {
|
|
|
1290
862
|
async function acquireSkillHitLock(lockPath) {
|
|
1291
863
|
for (let attempt = 0; attempt < SKILL_HIT_LOCK_MAX_ATTEMPTS; attempt++) {
|
|
1292
864
|
try {
|
|
1293
|
-
await
|
|
865
|
+
await fs2.mkdir(lockPath);
|
|
1294
866
|
return true;
|
|
1295
867
|
} catch (err) {
|
|
1296
868
|
if (err.code !== "EEXIST") return false;
|
|
1297
869
|
try {
|
|
1298
|
-
const st = await
|
|
870
|
+
const st = await fs2.stat(lockPath);
|
|
1299
871
|
if (Date.now() - st.mtimeMs > SKILL_HIT_LOCK_STALE_MS) {
|
|
1300
|
-
await
|
|
872
|
+
await fs2.rmdir(lockPath).catch(() => {
|
|
1301
873
|
});
|
|
1302
874
|
continue;
|
|
1303
875
|
}
|
|
@@ -1326,7 +898,7 @@ async function incrementSkillHit(skillName) {
|
|
|
1326
898
|
hits.lastTs = Date.now();
|
|
1327
899
|
await atomicWriteText(hitsFile, JSON.stringify(hits, null, 2));
|
|
1328
900
|
} finally {
|
|
1329
|
-
await
|
|
901
|
+
await fs2.rmdir(lockPath).catch(() => {
|
|
1330
902
|
});
|
|
1331
903
|
}
|
|
1332
904
|
});
|
|
@@ -1362,14 +934,14 @@ async function listSkills(sessionId) {
|
|
|
1362
934
|
let compactLen = 0;
|
|
1363
935
|
let compactText = "";
|
|
1364
936
|
try {
|
|
1365
|
-
const stat2 = await
|
|
937
|
+
const stat2 = await fs2.stat(resolve(dir, compactFileId));
|
|
1366
938
|
compactLen = stat2.size;
|
|
1367
|
-
compactText = await
|
|
939
|
+
compactText = await fs2.readFile(resolve(dir, compactFileId), "utf-8").catch(() => "");
|
|
1368
940
|
} catch {
|
|
1369
941
|
compactLen = 0;
|
|
1370
942
|
}
|
|
1371
943
|
const hasMarker = extractCompactFromMarker(
|
|
1372
|
-
await
|
|
944
|
+
await fs2.readFile(resolve(dir, `${meta.outputId}.txt`), "utf-8").catch(() => "")
|
|
1373
945
|
) !== null;
|
|
1374
946
|
const compactStale = isCompactStale(compactText, meta.skillName, meta.contentSha);
|
|
1375
947
|
const { count: hitCount } = await readSkillHits(meta.skillName);
|
|
@@ -1408,7 +980,7 @@ async function resolvePluginSkillPath(pluginName, skillSlug) {
|
|
|
1408
980
|
const manifestPath = _pluginsManifestPathOverride ?? resolve(claudeConfigDir(), "plugins", "installed_plugins.json");
|
|
1409
981
|
let raw;
|
|
1410
982
|
try {
|
|
1411
|
-
raw = await
|
|
983
|
+
raw = await fs2.readFile(manifestPath, "utf8");
|
|
1412
984
|
} catch {
|
|
1413
985
|
return null;
|
|
1414
986
|
}
|
|
@@ -1430,7 +1002,7 @@ async function resolvePluginSkillPath(pluginName, skillSlug) {
|
|
|
1430
1002
|
if (typeof installPath !== "string" || installPath === "") continue;
|
|
1431
1003
|
const diskPath = resolve(installPath, "skills", skillSlug, "SKILL.md");
|
|
1432
1004
|
try {
|
|
1433
|
-
await
|
|
1005
|
+
await fs2.access(diskPath);
|
|
1434
1006
|
return diskPath;
|
|
1435
1007
|
} catch {
|
|
1436
1008
|
continue;
|
|
@@ -1449,7 +1021,7 @@ async function installedSkillPath(skillName) {
|
|
|
1449
1021
|
}
|
|
1450
1022
|
const diskPath = resolve(skillsSourceDir(), name, "SKILL.md");
|
|
1451
1023
|
try {
|
|
1452
|
-
await
|
|
1024
|
+
await fs2.access(diskPath);
|
|
1453
1025
|
return diskPath;
|
|
1454
1026
|
} catch {
|
|
1455
1027
|
return null;
|
|
@@ -1471,7 +1043,7 @@ function pruneSkillOutputs(maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_
|
|
|
1471
1043
|
ts = parsed.ts;
|
|
1472
1044
|
} catch {
|
|
1473
1045
|
try {
|
|
1474
|
-
ts =
|
|
1046
|
+
ts = statSync(resolve(dir, file)).mtimeMs;
|
|
1475
1047
|
} catch {
|
|
1476
1048
|
continue;
|
|
1477
1049
|
}
|
|
@@ -1509,7 +1081,7 @@ function pruneSkillOutputs(maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_
|
|
|
1509
1081
|
|
|
1510
1082
|
// src/compact.ts
|
|
1511
1083
|
init_define_import_meta_env();
|
|
1512
|
-
import * as
|
|
1084
|
+
import * as fs3 from "node:fs";
|
|
1513
1085
|
import * as path3 from "node:path";
|
|
1514
1086
|
var CONTEXT_AUTOCOMPACT_TOKENS = 66e4;
|
|
1515
1087
|
var CATALOG_TOKENS = 10800;
|
|
@@ -1747,10 +1319,10 @@ function isNoisePath(inputPath) {
|
|
|
1747
1319
|
function findLatestSessionId() {
|
|
1748
1320
|
try {
|
|
1749
1321
|
const sessionsDir2 = path3.join(tokenGoatHome(), "sessions");
|
|
1750
|
-
if (!
|
|
1322
|
+
if (!fs3.existsSync(sessionsDir2)) {
|
|
1751
1323
|
return null;
|
|
1752
1324
|
}
|
|
1753
|
-
const files =
|
|
1325
|
+
const files = fs3.readdirSync(sessionsDir2);
|
|
1754
1326
|
const jsonFiles = files.filter((f) => f.endsWith(".json") && !f.includes(AGENT_SALT_MARKER));
|
|
1755
1327
|
if (jsonFiles.length === 0) {
|
|
1756
1328
|
return null;
|
|
@@ -1760,9 +1332,9 @@ function findLatestSessionId() {
|
|
|
1760
1332
|
return null;
|
|
1761
1333
|
}
|
|
1762
1334
|
let latestFile = firstFile;
|
|
1763
|
-
let latestMtime =
|
|
1335
|
+
let latestMtime = fs3.statSync(path3.join(sessionsDir2, firstFile)).mtimeMs;
|
|
1764
1336
|
for (const file of jsonFiles) {
|
|
1765
|
-
const mtime =
|
|
1337
|
+
const mtime = fs3.statSync(path3.join(sessionsDir2, file)).mtimeMs;
|
|
1766
1338
|
if (mtime > latestMtime) {
|
|
1767
1339
|
latestFile = file;
|
|
1768
1340
|
latestMtime = mtime;
|
|
@@ -1785,7 +1357,7 @@ function writeSessionManifest(projectHash, sessionId, manifestJson) {
|
|
|
1785
1357
|
const safeSessionId = sessionFileStem(sessionId);
|
|
1786
1358
|
if (!safeSessionId) return;
|
|
1787
1359
|
const sessionsDir2 = path3.join(dataDir(), "projects", projectHash, "sessions");
|
|
1788
|
-
if (!
|
|
1360
|
+
if (!fs3.existsSync(sessionsDir2)) {
|
|
1789
1361
|
ensureDirSync(sessionsDir2);
|
|
1790
1362
|
}
|
|
1791
1363
|
const dest = path3.join(sessionsDir2, `${safeSessionId}.json`);
|
|
@@ -1793,28 +1365,28 @@ function writeSessionManifest(projectHash, sessionId, manifestJson) {
|
|
|
1793
1365
|
}
|
|
1794
1366
|
function readAllSessionManifests(projectHash, maxAgeSecs = 3600) {
|
|
1795
1367
|
const sessionsDir2 = path3.join(dataDir(), "projects", projectHash, "sessions");
|
|
1796
|
-
if (!
|
|
1368
|
+
if (!fs3.existsSync(sessionsDir2)) {
|
|
1797
1369
|
return [];
|
|
1798
1370
|
}
|
|
1799
1371
|
const now = Date.now() / 1e3;
|
|
1800
1372
|
const results = [];
|
|
1801
1373
|
try {
|
|
1802
|
-
const files =
|
|
1374
|
+
const files = fs3.readdirSync(sessionsDir2);
|
|
1803
1375
|
for (const file of files) {
|
|
1804
1376
|
if (!file.endsWith(".json")) {
|
|
1805
1377
|
continue;
|
|
1806
1378
|
}
|
|
1807
1379
|
try {
|
|
1808
1380
|
const fullPath = path3.join(sessionsDir2, file);
|
|
1809
|
-
const stat2 =
|
|
1381
|
+
const stat2 = fs3.statSync(fullPath);
|
|
1810
1382
|
if (now - stat2.mtimeMs / 1e3 > maxAgeSecs) {
|
|
1811
1383
|
try {
|
|
1812
|
-
|
|
1384
|
+
fs3.unlinkSync(fullPath);
|
|
1813
1385
|
} catch {
|
|
1814
1386
|
}
|
|
1815
1387
|
continue;
|
|
1816
1388
|
}
|
|
1817
|
-
const text =
|
|
1389
|
+
const text = fs3.readFileSync(fullPath, "utf8");
|
|
1818
1390
|
const data = JSON.parse(text);
|
|
1819
1391
|
if (typeof data === "object" && data !== null && "files" in data) {
|
|
1820
1392
|
results.push(data);
|
|
@@ -1901,56 +1473,6 @@ function computeAdaptiveBudget(cache, ageSecs = 0, opts) {
|
|
|
1901
1473
|
}
|
|
1902
1474
|
|
|
1903
1475
|
export {
|
|
1904
|
-
recordFileRead,
|
|
1905
|
-
recordSymbolRead,
|
|
1906
|
-
recordFileEdit,
|
|
1907
|
-
getSessionFiles,
|
|
1908
|
-
wasFileReadThisSession,
|
|
1909
|
-
wasFileFullyReadThisSession,
|
|
1910
|
-
getCompactedAt,
|
|
1911
|
-
markCompacted,
|
|
1912
|
-
getSessionFileEntry,
|
|
1913
|
-
wasHintShown,
|
|
1914
|
-
markHintShown,
|
|
1915
|
-
recordScheduledPrompt,
|
|
1916
|
-
wasCliReadThisSession,
|
|
1917
|
-
recordCliRead,
|
|
1918
|
-
recordLargeFileHintPending,
|
|
1919
|
-
takePendingLargeFileHint,
|
|
1920
|
-
WEB_FETCH_KEY_SEP,
|
|
1921
|
-
recordWebFetch,
|
|
1922
|
-
getSessionWebFetches,
|
|
1923
|
-
recordBashOutput,
|
|
1924
|
-
getSessionBashOutputs,
|
|
1925
|
-
recordBashRerun,
|
|
1926
|
-
getSessionBashReruns,
|
|
1927
|
-
getBashOutputId,
|
|
1928
|
-
recordGrepQuery,
|
|
1929
|
-
getGrepMatchCount,
|
|
1930
|
-
recordGlobQuery,
|
|
1931
|
-
getGlobMatchCount,
|
|
1932
|
-
setLastTabContext,
|
|
1933
|
-
lastTabContextMatches,
|
|
1934
|
-
hasSeenImage,
|
|
1935
|
-
recordSeenImage,
|
|
1936
|
-
recordOutstandingAgentSpawn,
|
|
1937
|
-
getOutstandingAgentSpawns,
|
|
1938
|
-
removeOutstandingAgentSpawn,
|
|
1939
|
-
recordCurlDownload,
|
|
1940
|
-
getCurlDownloadPath,
|
|
1941
|
-
clearCurlDownload,
|
|
1942
|
-
recordFileLineRange,
|
|
1943
|
-
getFileLineRanges,
|
|
1944
|
-
resetFileLineRanges,
|
|
1945
|
-
GENERIC_SERVED_OUTPUT_KEY,
|
|
1946
|
-
recordFileServedOutput,
|
|
1947
|
-
getFileServedOutputs,
|
|
1948
|
-
markFileTruncated,
|
|
1949
|
-
wasFileTruncatedThisSession,
|
|
1950
|
-
getSessionId,
|
|
1951
|
-
setTranscriptPath,
|
|
1952
|
-
getTranscriptPath,
|
|
1953
|
-
exportSessionState,
|
|
1954
1476
|
SESSIONS_SUBDIR,
|
|
1955
1477
|
sessionsDir,
|
|
1956
1478
|
AGENT_SALT_MARKER,
|