ahp-inspector 1.4.1 → 1.4.3
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/dist/index.js +303 -211
- package/package.json +1 -1
- package/ui-dist/assets/{index-CkWXlGE4.css → index-DTLBo7X9.css} +1 -1
- package/ui-dist/assets/index-dyClOfJ7.js +81 -0
- package/ui-dist/assets/index-dyClOfJ7.js.map +1 -0
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/index-DHunX_bW.js +0 -81
- package/ui-dist/assets/index-DHunX_bW.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2,48 +2,156 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { existsSync as existsSync2, readFileSync, statSync as statSync3 } from "fs";
|
|
5
|
-
import { dirname as
|
|
5
|
+
import { dirname as dirname5, join as join7, resolve as resolvePath } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
8
8
|
// ../host-node/src/discovery.ts
|
|
9
9
|
import { createHash } from "crypto";
|
|
10
|
-
import { readdir, stat } from "fs/promises";
|
|
11
10
|
import { homedir } from "os";
|
|
12
|
-
import { basename, join, sep } from "path";
|
|
11
|
+
import { basename as basename2, dirname as dirname2, isAbsolute, join as join2, relative, sep } from "path";
|
|
12
|
+
|
|
13
|
+
// ../host-node/src/bounded-log-discovery.ts
|
|
14
|
+
import { opendir, stat } from "fs/promises";
|
|
15
|
+
import { basename, dirname, join } from "path";
|
|
16
|
+
async function scanConfiguredRoots(options) {
|
|
17
|
+
const now = options.now ?? Date.now;
|
|
18
|
+
const maxDepthBelowLaunch = options.maxDepthBelowLaunch ?? 3;
|
|
19
|
+
const rootResults = [];
|
|
20
|
+
for (const [rootIndex, root] of options.roots.entries()) {
|
|
21
|
+
const state = {
|
|
22
|
+
stats: 0,
|
|
23
|
+
immediateEntries: 0,
|
|
24
|
+
truncated: false,
|
|
25
|
+
startedAt: now(),
|
|
26
|
+
files: []
|
|
27
|
+
};
|
|
28
|
+
const launchEntries = [];
|
|
29
|
+
let rootDirectory;
|
|
30
|
+
try {
|
|
31
|
+
rootDirectory = await opendir(root.dir);
|
|
32
|
+
while (true) {
|
|
33
|
+
if (rootScanOverBudget(state, options, now, true)) break;
|
|
34
|
+
const entry = await rootDirectory.read();
|
|
35
|
+
if (!entry) break;
|
|
36
|
+
state.immediateEntries++;
|
|
37
|
+
const absPath = join(root.dir, entry.name);
|
|
38
|
+
const entryStat = await boundedStat(absPath, state, options, now);
|
|
39
|
+
if (!entryStat) continue;
|
|
40
|
+
if (entryStat.isDirectory()) {
|
|
41
|
+
launchEntries.push({ absPath, mtimeMs: entryStat.mtimeMs });
|
|
42
|
+
} else if (entryStat.isFile() && options.matchesFilename(entry.name)) {
|
|
43
|
+
state.files.push(toScannedFile(absPath, root.dir, entryStat.mtimeMs, entryStat.size));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
} finally {
|
|
48
|
+
await rootDirectory?.close().catch(() => {
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
launchEntries.sort((left, right) => right.mtimeMs - left.mtimeMs);
|
|
52
|
+
if (launchEntries.length > options.topLaunchDirs) state.truncated = true;
|
|
53
|
+
for (const launch of launchEntries.slice(0, options.topLaunchDirs)) {
|
|
54
|
+
if (rootScanOverBudget(state, options, now, false)) break;
|
|
55
|
+
await walkLaunchDirectory(launch.absPath, launch.absPath, maxDepthBelowLaunch, state, options, now);
|
|
56
|
+
}
|
|
57
|
+
rootResults.push({
|
|
58
|
+
rootIndex,
|
|
59
|
+
files: state.files,
|
|
60
|
+
truncated: state.truncated,
|
|
61
|
+
statsAttempted: state.stats,
|
|
62
|
+
immediateEntriesExamined: state.immediateEntries
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return { roots: rootResults, truncated: rootResults.some((root) => root.truncated) };
|
|
66
|
+
}
|
|
67
|
+
async function walkLaunchDirectory(absDir, launchDir, depthLeft, state, options, now) {
|
|
68
|
+
if (depthLeft < 0 || rootScanOverBudget(state, options, now, false)) return;
|
|
69
|
+
let directory;
|
|
70
|
+
try {
|
|
71
|
+
directory = await opendir(absDir);
|
|
72
|
+
while (true) {
|
|
73
|
+
if (rootScanOverBudget(state, options, now, false)) return;
|
|
74
|
+
const entry = await directory.read();
|
|
75
|
+
if (!entry) return;
|
|
76
|
+
const absPath = join(absDir, entry.name);
|
|
77
|
+
const entryStat = await boundedStat(absPath, state, options, now);
|
|
78
|
+
if (!entryStat) continue;
|
|
79
|
+
if (entryStat.isDirectory()) {
|
|
80
|
+
if (depthLeft === 0) {
|
|
81
|
+
state.truncated = true;
|
|
82
|
+
} else {
|
|
83
|
+
await walkLaunchDirectory(absPath, launchDir, depthLeft - 1, state, options, now);
|
|
84
|
+
}
|
|
85
|
+
} else if (entryStat.isFile() && options.matchesFilename(entry.name)) {
|
|
86
|
+
state.files.push(toScannedFile(absPath, launchDir, entryStat.mtimeMs, entryStat.size));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
} finally {
|
|
91
|
+
await directory?.close().catch(() => {
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function boundedStat(absPath, state, options, now) {
|
|
96
|
+
if (rootScanOverBudget(state, options, now, false)) return void 0;
|
|
97
|
+
state.stats++;
|
|
98
|
+
try {
|
|
99
|
+
return await stat(absPath);
|
|
100
|
+
} catch {
|
|
101
|
+
return void 0;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function rootScanOverBudget(state, options, now, includeImmediateEntries) {
|
|
105
|
+
const overBudget = state.stats >= options.maxStats || now() - state.startedAt >= options.timeBudgetMs || includeImmediateEntries && state.immediateEntries >= options.maxImmediateEntries;
|
|
106
|
+
if (overBudget) state.truncated = true;
|
|
107
|
+
return overBudget;
|
|
108
|
+
}
|
|
109
|
+
function toScannedFile(absPath, launchDir, mtimeMs, sizeBytes) {
|
|
110
|
+
return {
|
|
111
|
+
absPath,
|
|
112
|
+
name: basename(absPath),
|
|
113
|
+
parentDir: dirname(absPath),
|
|
114
|
+
launchDir,
|
|
115
|
+
mtimeMs,
|
|
116
|
+
sizeBytes
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ../host-node/src/discovery.ts
|
|
13
121
|
var DEFAULT_TIME_BUDGET_MS = 1500;
|
|
14
122
|
var DEFAULT_MAX_STATS = 5e3;
|
|
123
|
+
var DEFAULT_MAX_IMMEDIATE_ENTRIES = 5e3;
|
|
15
124
|
var DEFAULT_TOP_LAUNCH_DIRS = 10;
|
|
16
|
-
var MAX_LAUNCH_LIST = 50;
|
|
17
125
|
var MAX_RESULTS = 200;
|
|
18
126
|
var MAX_DEPTH_BELOW_LAUNCH = 3;
|
|
19
127
|
function defaultRoots() {
|
|
20
128
|
const home = homedir();
|
|
21
129
|
const platform = process.platform;
|
|
22
130
|
const ossDevRoots = [
|
|
23
|
-
{ origin: "vscode-oss-dev", dir:
|
|
24
|
-
{ origin: "vscode-oss-dev", dir:
|
|
131
|
+
{ origin: "vscode-oss-dev", dir: join2(home, ".vscode-oss-dev", "logs") },
|
|
132
|
+
{ origin: "vscode-oss-dev", dir: join2(home, ".vscode-oss-agents-dev", "logs") }
|
|
25
133
|
];
|
|
26
134
|
if (platform === "darwin") {
|
|
27
135
|
return [
|
|
28
|
-
{ origin: "vscode", dir:
|
|
136
|
+
{ origin: "vscode", dir: join2(home, "Library", "Application Support", "Code", "logs") },
|
|
29
137
|
{
|
|
30
138
|
origin: "vscode-insiders",
|
|
31
|
-
dir:
|
|
139
|
+
dir: join2(home, "Library", "Application Support", "Code - Insiders", "logs")
|
|
32
140
|
},
|
|
33
141
|
...ossDevRoots
|
|
34
142
|
];
|
|
35
143
|
}
|
|
36
144
|
if (platform === "win32") {
|
|
37
|
-
const appData = process.env.APPDATA ??
|
|
145
|
+
const appData = process.env.APPDATA ?? join2(home, "AppData", "Roaming");
|
|
38
146
|
return [
|
|
39
|
-
{ origin: "vscode", dir:
|
|
40
|
-
{ origin: "vscode-insiders", dir:
|
|
147
|
+
{ origin: "vscode", dir: join2(appData, "Code", "logs") },
|
|
148
|
+
{ origin: "vscode-insiders", dir: join2(appData, "Code - Insiders", "logs") },
|
|
41
149
|
...ossDevRoots
|
|
42
150
|
];
|
|
43
151
|
}
|
|
44
152
|
return [
|
|
45
|
-
{ origin: "vscode", dir:
|
|
46
|
-
{ origin: "vscode-insiders", dir:
|
|
153
|
+
{ origin: "vscode", dir: join2(home, ".config", "Code", "logs") },
|
|
154
|
+
{ origin: "vscode-insiders", dir: join2(home, ".config", "Code - Insiders", "logs") },
|
|
47
155
|
...ossDevRoots
|
|
48
156
|
];
|
|
49
157
|
}
|
|
@@ -70,132 +178,97 @@ function makeId(absPath) {
|
|
|
70
178
|
return createHash("sha256").update(absPath).digest("hex").slice(0, 32);
|
|
71
179
|
}
|
|
72
180
|
function makeContextLabel(absPath, launchDir) {
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return tail.join(" / ");
|
|
181
|
+
const relativeParent = relative(launchDir, dirname2(absPath));
|
|
182
|
+
if (relativeParent === "" || relativeParent === ".") return "";
|
|
183
|
+
if (isAbsolute(relativeParent) || relativeParent === ".." || relativeParent.startsWith(`..${sep}`)) return "";
|
|
184
|
+
return [basename2(launchDir), ...relativeParent.split(sep).filter(Boolean)].join(" / ");
|
|
78
185
|
}
|
|
79
186
|
var idToPath = /* @__PURE__ */ new Map();
|
|
187
|
+
var discoveryGeneration = 0;
|
|
80
188
|
function resolveCandidateId(id) {
|
|
81
189
|
return idToPath.get(id) ?? null;
|
|
82
190
|
}
|
|
83
191
|
async function discoverVsCodeLogs(opts = {}) {
|
|
84
192
|
const roots = opts.roots ?? defaultRoots();
|
|
85
|
-
const
|
|
86
|
-
const maxStats = opts.maxStats ?? DEFAULT_MAX_STATS;
|
|
87
|
-
const topLaunch = opts.topLaunchDirs ?? DEFAULT_TOP_LAUNCH_DIRS;
|
|
88
|
-
const now = opts.now ?? Date.now;
|
|
89
|
-
const startedAt = now();
|
|
90
|
-
let stats = 0;
|
|
91
|
-
let truncated = false;
|
|
92
|
-
const collected = [];
|
|
193
|
+
const generation = ++discoveryGeneration;
|
|
93
194
|
idToPath.clear();
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
for (const
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (tickAndCheck()) {
|
|
158
|
-
truncated = true;
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const abs = join(absDir, name);
|
|
162
|
-
let st;
|
|
163
|
-
try {
|
|
164
|
-
st = await stat(abs);
|
|
165
|
-
} catch {
|
|
166
|
-
continue;
|
|
167
|
-
}
|
|
168
|
-
if (st.isDirectory()) {
|
|
169
|
-
await walkBounded(abs, launchDir, depthLeft - 1, origin, sink, tickAndCheck);
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
if (!st.isFile()) continue;
|
|
173
|
-
const ok = FILENAME_RE_AHP_JSONL.test(name) || FILENAME_RE_AHP_NAMED_JSONL.test(name);
|
|
174
|
-
if (!ok) continue;
|
|
175
|
-
const sc = score(name, st.mtimeMs, st.size, absDir);
|
|
176
|
-
const id = makeId(abs);
|
|
177
|
-
idToPath.set(id, abs);
|
|
178
|
-
const confidence = tier(sc);
|
|
179
|
-
sink.push({
|
|
180
|
-
id,
|
|
181
|
-
label: basename(abs),
|
|
182
|
-
mtimeMs: st.mtimeMs,
|
|
183
|
-
sizeBytes: st.size,
|
|
184
|
-
origin,
|
|
185
|
-
confidence,
|
|
186
|
-
contextLabel: makeContextLabel(abs, launchDir)
|
|
187
|
-
});
|
|
188
|
-
if (sink.length >= MAX_RESULTS * 4) {
|
|
189
|
-
truncated = true;
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
195
|
+
const scan = await scanConfiguredRoots({
|
|
196
|
+
roots,
|
|
197
|
+
matchesFilename: matchesAhpFilename,
|
|
198
|
+
timeBudgetMs: opts.timeBudgetMs ?? DEFAULT_TIME_BUDGET_MS,
|
|
199
|
+
maxStats: opts.maxStats ?? DEFAULT_MAX_STATS,
|
|
200
|
+
maxImmediateEntries: opts.maxImmediateEntries ?? DEFAULT_MAX_IMMEDIATE_ENTRIES,
|
|
201
|
+
topLaunchDirs: opts.topLaunchDirs ?? DEFAULT_TOP_LAUNCH_DIRS,
|
|
202
|
+
maxDepthBelowLaunch: MAX_DEPTH_BELOW_LAUNCH,
|
|
203
|
+
now: opts.now ?? Date.now
|
|
204
|
+
});
|
|
205
|
+
const populatedRoots = scan.roots.map((scannedRoot) => {
|
|
206
|
+
const root = roots[scannedRoot.rootIndex];
|
|
207
|
+
if (!root) return [];
|
|
208
|
+
return scannedRoot.files.map((file) => toPickerCandidate(file, root.origin)).sort(comparePickerCandidates);
|
|
209
|
+
}).filter((candidates) => candidates.length > 0);
|
|
210
|
+
const effectiveResultCap = Math.max(MAX_RESULTS, populatedRoots.length);
|
|
211
|
+
const retained = [];
|
|
212
|
+
const retainedPaths = /* @__PURE__ */ new Set();
|
|
213
|
+
for (const candidates of populatedRoots) {
|
|
214
|
+
const candidate = candidates[0];
|
|
215
|
+
if (!candidate || retainedPaths.has(candidate.absPath)) continue;
|
|
216
|
+
retained.push(candidate);
|
|
217
|
+
retainedPaths.add(candidate.absPath);
|
|
218
|
+
}
|
|
219
|
+
const remainingCapacity = effectiveResultCap - retained.length;
|
|
220
|
+
const extraQuota = populatedRoots.length > 0 ? Math.floor(remainingCapacity / populatedRoots.length) : 0;
|
|
221
|
+
for (const candidates of populatedRoots) {
|
|
222
|
+
for (const candidate of candidates.slice(1, 1 + extraQuota)) {
|
|
223
|
+
if (retainedPaths.has(candidate.absPath)) continue;
|
|
224
|
+
retained.push(candidate);
|
|
225
|
+
retainedPaths.add(candidate.absPath);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const fillCandidates = populatedRoots.flat().filter((candidate) => !retainedPaths.has(candidate.absPath)).sort(comparePickerCandidates);
|
|
229
|
+
for (const candidate of fillCandidates) {
|
|
230
|
+
if (retained.length >= effectiveResultCap) break;
|
|
231
|
+
if (retainedPaths.has(candidate.absPath)) continue;
|
|
232
|
+
retained.push(candidate);
|
|
233
|
+
retainedPaths.add(candidate.absPath);
|
|
234
|
+
}
|
|
235
|
+
retained.sort(comparePickerCandidates);
|
|
236
|
+
if (generation === discoveryGeneration) {
|
|
237
|
+
idToPath.clear();
|
|
238
|
+
for (const candidate of retained) idToPath.set(candidate.safe.id, candidate.absPath);
|
|
239
|
+
}
|
|
240
|
+
const totalCandidateCount = new Set(populatedRoots.flat().map((candidate) => candidate.absPath)).size;
|
|
241
|
+
return {
|
|
242
|
+
candidates: retained.map((candidate) => candidate.safe),
|
|
243
|
+
truncated: scan.truncated || retained.length < totalCandidateCount
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function toPickerCandidate(file, origin) {
|
|
247
|
+
const confidence = tier(score(file.name, file.mtimeMs, file.sizeBytes, file.parentDir));
|
|
248
|
+
return {
|
|
249
|
+
absPath: file.absPath,
|
|
250
|
+
safe: {
|
|
251
|
+
id: makeId(file.absPath),
|
|
252
|
+
label: file.name,
|
|
253
|
+
mtimeMs: file.mtimeMs,
|
|
254
|
+
sizeBytes: file.sizeBytes,
|
|
255
|
+
origin,
|
|
256
|
+
confidence,
|
|
257
|
+
contextLabel: makeContextLabel(file.absPath, file.launchDir)
|
|
192
258
|
}
|
|
193
|
-
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function comparePickerCandidates(left, right) {
|
|
262
|
+
const order = { high: 0, medium: 1, low: 2 };
|
|
263
|
+
const confidenceDifference = order[left.safe.confidence] - order[right.safe.confidence];
|
|
264
|
+
return confidenceDifference || right.safe.mtimeMs - left.safe.mtimeMs;
|
|
265
|
+
}
|
|
266
|
+
function matchesAhpFilename(name) {
|
|
267
|
+
return FILENAME_RE_AHP_JSONL.test(name) || FILENAME_RE_AHP_NAMED_JSONL.test(name);
|
|
194
268
|
}
|
|
195
269
|
|
|
196
270
|
// ../host-node/src/find-latest-ahp-log.ts
|
|
197
|
-
import { open as fsOpen
|
|
198
|
-
import { join as join2 } from "path";
|
|
271
|
+
import { open as fsOpen } from "fs/promises";
|
|
199
272
|
|
|
200
273
|
// ../parser/src/jsonl.ts
|
|
201
274
|
var MAX_BUF_BYTES = 16 * 1024 * 1024;
|
|
@@ -391,6 +464,13 @@ function objectChild(parent, key) {
|
|
|
391
464
|
return typeof child === "object" && child !== null ? child : null;
|
|
392
465
|
}
|
|
393
466
|
function candidateObjects(p) {
|
|
467
|
+
if (Array.isArray(p)) {
|
|
468
|
+
const items = [];
|
|
469
|
+
for (const item of p) {
|
|
470
|
+
if (typeof item === "object" && item !== null) items.push(item);
|
|
471
|
+
}
|
|
472
|
+
return items;
|
|
473
|
+
}
|
|
394
474
|
const out = [p];
|
|
395
475
|
const action = objectChild(p, "action");
|
|
396
476
|
if (action) out.push(action);
|
|
@@ -405,7 +485,25 @@ function sessionFromObject(p) {
|
|
|
405
485
|
const uri = session.uri;
|
|
406
486
|
if (typeof uri === "string") return uri;
|
|
407
487
|
}
|
|
408
|
-
|
|
488
|
+
const sessionId = asString(p.sessionId);
|
|
489
|
+
if (sessionId) return sessionId;
|
|
490
|
+
const channel = asString(p.channel);
|
|
491
|
+
if (channel) return channel;
|
|
492
|
+
const terminal = asString(p.terminal);
|
|
493
|
+
if (terminal) return terminal;
|
|
494
|
+
const resource = asString(p.resource);
|
|
495
|
+
if (resource) return resource;
|
|
496
|
+
const external = asString(p.external);
|
|
497
|
+
if (external) return external;
|
|
498
|
+
const scheme = asString(p.scheme);
|
|
499
|
+
const path = asString(p.path);
|
|
500
|
+
if (scheme && path) return `${scheme}:${path}`;
|
|
501
|
+
const summary = p.summary;
|
|
502
|
+
if (typeof summary === "object" && summary !== null) {
|
|
503
|
+
const summaryResource = asString(summary.resource);
|
|
504
|
+
if (summaryResource) return summaryResource;
|
|
505
|
+
}
|
|
506
|
+
return null;
|
|
409
507
|
}
|
|
410
508
|
function turnFromObject(p) {
|
|
411
509
|
const fromTop = asString(p.turnId);
|
|
@@ -550,55 +648,29 @@ function extractWireMeta(raw2) {
|
|
|
550
648
|
// ../host-node/src/find-latest-ahp-log.ts
|
|
551
649
|
var DEFAULT_TIME_BUDGET_MS2 = 1500;
|
|
552
650
|
var DEFAULT_MAX_STATS2 = 5e3;
|
|
553
|
-
var
|
|
554
|
-
var
|
|
651
|
+
var DEFAULT_MAX_IMMEDIATE_ENTRIES2 = 5e3;
|
|
652
|
+
var DEFAULT_TOP_LAUNCH_DIRS2 = 10;
|
|
653
|
+
var MAX_DEPTH_BELOW_LAUNCH2 = 4;
|
|
555
654
|
var PROBE_READ_BYTES = 64 * 1024;
|
|
556
655
|
async function findLatestAhpLog(opts = {}) {
|
|
557
656
|
const roots = opts.rootsOverride ?? defaultRoots();
|
|
558
|
-
const
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
for (const c of ranked) {
|
|
571
|
-
if (await probeAhpShape(c.absPath)) return c.absPath;
|
|
657
|
+
const scan = await scanConfiguredRoots({
|
|
658
|
+
roots,
|
|
659
|
+
matchesFilename: matchesAhpFilename2,
|
|
660
|
+
timeBudgetMs: DEFAULT_TIME_BUDGET_MS2,
|
|
661
|
+
maxStats: DEFAULT_MAX_STATS2,
|
|
662
|
+
maxImmediateEntries: DEFAULT_MAX_IMMEDIATE_ENTRIES2,
|
|
663
|
+
topLaunchDirs: DEFAULT_TOP_LAUNCH_DIRS2,
|
|
664
|
+
maxDepthBelowLaunch: MAX_DEPTH_BELOW_LAUNCH2
|
|
665
|
+
});
|
|
666
|
+
const ranked = scan.roots.flatMap((root) => root.files).filter((candidate) => candidate.sizeBytes > 0).sort((left, right) => right.mtimeMs - left.mtimeMs);
|
|
667
|
+
for (const candidate of ranked) {
|
|
668
|
+
if (await probeAhpShape(candidate.absPath)) return candidate.absPath;
|
|
572
669
|
}
|
|
573
670
|
return null;
|
|
574
671
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
let names;
|
|
578
|
-
try {
|
|
579
|
-
names = await readdir2(absDir);
|
|
580
|
-
} catch {
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
for (const name of names) {
|
|
584
|
-
if (tickAndCheck()) return;
|
|
585
|
-
const abs = join2(absDir, name);
|
|
586
|
-
let st;
|
|
587
|
-
try {
|
|
588
|
-
st = await stat2(abs);
|
|
589
|
-
} catch {
|
|
590
|
-
continue;
|
|
591
|
-
}
|
|
592
|
-
if (st.isDirectory()) {
|
|
593
|
-
await walk(abs, depthLeft - 1, sink, tickAndCheck);
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
596
|
-
if (!st.isFile()) continue;
|
|
597
|
-
if (!(FILENAME_RE_AHP_JSONL.test(name) || FILENAME_RE_AHP_NAMED_JSONL.test(name))) {
|
|
598
|
-
continue;
|
|
599
|
-
}
|
|
600
|
-
sink.push({ absPath: abs, mtimeMs: st.mtimeMs, sizeBytes: st.size });
|
|
601
|
-
}
|
|
672
|
+
function matchesAhpFilename2(name) {
|
|
673
|
+
return FILENAME_RE_AHP_JSONL.test(name) || FILENAME_RE_AHP_NAMED_JSONL.test(name);
|
|
602
674
|
}
|
|
603
675
|
async function probeAhpShape(absPath) {
|
|
604
676
|
let fh;
|
|
@@ -637,7 +709,7 @@ async function probeAhpShape(absPath) {
|
|
|
637
709
|
|
|
638
710
|
// ../host-node/src/host-adapter.ts
|
|
639
711
|
import { accessSync, constants, statSync } from "fs";
|
|
640
|
-
import { basename as
|
|
712
|
+
import { basename as basename5, resolve as pathResolve } from "path";
|
|
641
713
|
|
|
642
714
|
// ../host-node/src/tail-reader.ts
|
|
643
715
|
import { createReadStream } from "fs";
|
|
@@ -646,11 +718,11 @@ import { stat as fsStat } from "fs/promises";
|
|
|
646
718
|
// ../../node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/index.js
|
|
647
719
|
import { EventEmitter } from "events";
|
|
648
720
|
import { stat as statcb, Stats } from "fs";
|
|
649
|
-
import { readdir as
|
|
721
|
+
import { readdir as readdir2, stat as stat4 } from "fs/promises";
|
|
650
722
|
import * as sp2 from "path";
|
|
651
723
|
|
|
652
724
|
// ../../node_modules/.pnpm/readdirp@5.0.0/node_modules/readdirp/index.js
|
|
653
|
-
import { lstat, readdir
|
|
725
|
+
import { lstat, readdir, realpath, stat as stat2 } from "fs/promises";
|
|
654
726
|
import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "path";
|
|
655
727
|
import { Readable } from "stream";
|
|
656
728
|
var EntryTypes = {
|
|
@@ -731,7 +803,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
731
803
|
const { root, type } = opts;
|
|
732
804
|
this._fileFilter = normalizeFilter(opts.fileFilter);
|
|
733
805
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
734
|
-
const statMethod = opts.lstat ? lstat :
|
|
806
|
+
const statMethod = opts.lstat ? lstat : stat2;
|
|
735
807
|
if (wantBigintFsStats) {
|
|
736
808
|
this._stat = (path) => statMethod(path, { bigint: true });
|
|
737
809
|
} else {
|
|
@@ -802,7 +874,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
802
874
|
async _exploreDir(path, depth) {
|
|
803
875
|
let files;
|
|
804
876
|
try {
|
|
805
|
-
files = await
|
|
877
|
+
files = await readdir(path, this._rdOptions);
|
|
806
878
|
} catch (error) {
|
|
807
879
|
this._onError(error);
|
|
808
880
|
}
|
|
@@ -810,10 +882,10 @@ var ReaddirpStream = class extends Readable {
|
|
|
810
882
|
}
|
|
811
883
|
async _formatEntry(dirent, path) {
|
|
812
884
|
let entry;
|
|
813
|
-
const
|
|
885
|
+
const basename7 = this._isDirent ? dirent.name : dirent;
|
|
814
886
|
try {
|
|
815
|
-
const fullPath = presolve(pjoin(path,
|
|
816
|
-
entry = { path: prelative(this._root, fullPath), fullPath, basename:
|
|
887
|
+
const fullPath = presolve(pjoin(path, basename7));
|
|
888
|
+
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename7 };
|
|
817
889
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
818
890
|
} catch (err) {
|
|
819
891
|
this._onError(err);
|
|
@@ -884,7 +956,7 @@ function readdirp(root, options = {}) {
|
|
|
884
956
|
|
|
885
957
|
// ../../node_modules/.pnpm/chokidar@5.0.0/node_modules/chokidar/handler.js
|
|
886
958
|
import { watch as fs_watch, unwatchFile, watchFile } from "fs";
|
|
887
|
-
import { realpath as fsrealpath, lstat as lstat2, open, stat as
|
|
959
|
+
import { realpath as fsrealpath, lstat as lstat2, open, stat as stat3 } from "fs/promises";
|
|
888
960
|
import { type as osType } from "os";
|
|
889
961
|
import * as sp from "path";
|
|
890
962
|
var STR_DATA = "data";
|
|
@@ -911,7 +983,7 @@ var EVENTS = {
|
|
|
911
983
|
};
|
|
912
984
|
var EV = EVENTS;
|
|
913
985
|
var THROTTLE_MODE_WATCH = "watch";
|
|
914
|
-
var statMethods = { lstat: lstat2, stat:
|
|
986
|
+
var statMethods = { lstat: lstat2, stat: stat3 };
|
|
915
987
|
var KEY_LISTENERS = "listeners";
|
|
916
988
|
var KEY_ERR = "errHandlers";
|
|
917
989
|
var KEY_RAW = "rawEmitters";
|
|
@@ -1354,9 +1426,9 @@ var NodeFsHandler = class {
|
|
|
1354
1426
|
_watchWithNodeFs(path, listener) {
|
|
1355
1427
|
const opts = this.fsw.options;
|
|
1356
1428
|
const directory = sp.dirname(path);
|
|
1357
|
-
const
|
|
1429
|
+
const basename7 = sp.basename(path);
|
|
1358
1430
|
const parent = this.fsw._getWatchedDir(directory);
|
|
1359
|
-
parent.add(
|
|
1431
|
+
parent.add(basename7);
|
|
1360
1432
|
const absolutePath = sp.resolve(path);
|
|
1361
1433
|
const options = {
|
|
1362
1434
|
persistent: opts.persistent
|
|
@@ -1366,7 +1438,7 @@ var NodeFsHandler = class {
|
|
|
1366
1438
|
let closer;
|
|
1367
1439
|
if (opts.usePolling) {
|
|
1368
1440
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
1369
|
-
options.interval = enableBin && isBinaryPath(
|
|
1441
|
+
options.interval = enableBin && isBinaryPath(basename7) ? opts.binaryInterval : opts.interval;
|
|
1370
1442
|
closer = setFsWatchFileListener(path, absolutePath, options, {
|
|
1371
1443
|
listener,
|
|
1372
1444
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -1388,18 +1460,18 @@ var NodeFsHandler = class {
|
|
|
1388
1460
|
if (this.fsw.closed) {
|
|
1389
1461
|
return;
|
|
1390
1462
|
}
|
|
1391
|
-
const
|
|
1392
|
-
const
|
|
1393
|
-
const parent = this.fsw._getWatchedDir(
|
|
1463
|
+
const dirname6 = sp.dirname(file);
|
|
1464
|
+
const basename7 = sp.basename(file);
|
|
1465
|
+
const parent = this.fsw._getWatchedDir(dirname6);
|
|
1394
1466
|
let prevStats = stats;
|
|
1395
|
-
if (parent.has(
|
|
1467
|
+
if (parent.has(basename7))
|
|
1396
1468
|
return;
|
|
1397
1469
|
const listener = async (path, newStats) => {
|
|
1398
1470
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
1399
1471
|
return;
|
|
1400
1472
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
1401
1473
|
try {
|
|
1402
|
-
const newStats2 = await
|
|
1474
|
+
const newStats2 = await stat3(file);
|
|
1403
1475
|
if (this.fsw.closed)
|
|
1404
1476
|
return;
|
|
1405
1477
|
const at = newStats2.atimeMs;
|
|
@@ -1417,9 +1489,9 @@ var NodeFsHandler = class {
|
|
|
1417
1489
|
prevStats = newStats2;
|
|
1418
1490
|
}
|
|
1419
1491
|
} catch (error) {
|
|
1420
|
-
this.fsw._remove(
|
|
1492
|
+
this.fsw._remove(dirname6, basename7);
|
|
1421
1493
|
}
|
|
1422
|
-
} else if (parent.has(
|
|
1494
|
+
} else if (parent.has(basename7)) {
|
|
1423
1495
|
const at = newStats.atimeMs;
|
|
1424
1496
|
const mt = newStats.mtimeMs;
|
|
1425
1497
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -1667,11 +1739,11 @@ function createPattern(matcher) {
|
|
|
1667
1739
|
if (matcher.path === string)
|
|
1668
1740
|
return true;
|
|
1669
1741
|
if (matcher.recursive) {
|
|
1670
|
-
const
|
|
1671
|
-
if (!
|
|
1742
|
+
const relative4 = sp2.relative(matcher.path, string);
|
|
1743
|
+
if (!relative4) {
|
|
1672
1744
|
return false;
|
|
1673
1745
|
}
|
|
1674
|
-
return !
|
|
1746
|
+
return !relative4.startsWith("..") && !sp2.isAbsolute(relative4);
|
|
1675
1747
|
}
|
|
1676
1748
|
return false;
|
|
1677
1749
|
};
|
|
@@ -1773,7 +1845,7 @@ var DirEntry = class {
|
|
|
1773
1845
|
return;
|
|
1774
1846
|
const dir = this.path;
|
|
1775
1847
|
try {
|
|
1776
|
-
await
|
|
1848
|
+
await readdir2(dir);
|
|
1777
1849
|
} catch (err) {
|
|
1778
1850
|
if (this._removeWatcher) {
|
|
1779
1851
|
this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
|
|
@@ -2123,7 +2195,7 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2123
2195
|
const fullPath = opts.cwd ? sp2.join(opts.cwd, path) : path;
|
|
2124
2196
|
let stats2;
|
|
2125
2197
|
try {
|
|
2126
|
-
stats2 = await
|
|
2198
|
+
stats2 = await stat4(fullPath);
|
|
2127
2199
|
} catch (err) {
|
|
2128
2200
|
}
|
|
2129
2201
|
if (!stats2 || this.closed)
|
|
@@ -2250,8 +2322,8 @@ var FSWatcher = class extends EventEmitter {
|
|
|
2250
2322
|
}
|
|
2251
2323
|
return this._userIgnored(path, stats);
|
|
2252
2324
|
}
|
|
2253
|
-
_isntIgnored(path,
|
|
2254
|
-
return !this._isIgnored(path,
|
|
2325
|
+
_isntIgnored(path, stat5) {
|
|
2326
|
+
return !this._isIgnored(path, stat5);
|
|
2255
2327
|
}
|
|
2256
2328
|
/**
|
|
2257
2329
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
@@ -2549,21 +2621,21 @@ var NodeHostAdapter = class {
|
|
|
2549
2621
|
}
|
|
2550
2622
|
async openLog(path) {
|
|
2551
2623
|
const resolved = pathResolve(process.cwd(), path);
|
|
2552
|
-
let
|
|
2624
|
+
let stat5;
|
|
2553
2625
|
try {
|
|
2554
|
-
|
|
2626
|
+
stat5 = statSync(resolved);
|
|
2555
2627
|
} catch {
|
|
2556
|
-
throw new Error(`openLog: cannot stat '${
|
|
2628
|
+
throw new Error(`openLog: cannot stat '${basename5(resolved)}'`);
|
|
2557
2629
|
}
|
|
2558
|
-
if (!
|
|
2559
|
-
throw new Error(`openLog: '${
|
|
2630
|
+
if (!stat5.isFile()) {
|
|
2631
|
+
throw new Error(`openLog: '${basename5(resolved)}' is not a regular file`);
|
|
2560
2632
|
}
|
|
2561
2633
|
try {
|
|
2562
2634
|
accessSync(resolved, constants.R_OK);
|
|
2563
2635
|
} catch {
|
|
2564
|
-
throw new Error(`openLog: '${
|
|
2636
|
+
throw new Error(`openLog: '${basename5(resolved)}' is not readable`);
|
|
2565
2637
|
}
|
|
2566
|
-
return { id: resolved, path: resolved, size:
|
|
2638
|
+
return { id: resolved, path: resolved, size: stat5.size };
|
|
2567
2639
|
}
|
|
2568
2640
|
watchLog(handle, sinkOrChunk) {
|
|
2569
2641
|
const node = handle;
|
|
@@ -2589,7 +2661,7 @@ var NodeHostAdapter = class {
|
|
|
2589
2661
|
|
|
2590
2662
|
// ../server/src/app-state.ts
|
|
2591
2663
|
import { Buffer as Buffer2 } from "buffer";
|
|
2592
|
-
import { basename as
|
|
2664
|
+
import { basename as basename6 } from "path";
|
|
2593
2665
|
|
|
2594
2666
|
// ../core/src/correlator.ts
|
|
2595
2667
|
var Correlator = class {
|
|
@@ -4606,6 +4678,8 @@ function formatTs(ms) {
|
|
|
4606
4678
|
)}`;
|
|
4607
4679
|
}
|
|
4608
4680
|
function formatSessionShort(sessionId) {
|
|
4681
|
+
const watched = formatResourceWatchChannel(sessionId);
|
|
4682
|
+
if (watched) return watched;
|
|
4609
4683
|
const parts = sessionId.split(/[/:]+/).filter(Boolean);
|
|
4610
4684
|
let label = parts.at(-1) ?? sessionId;
|
|
4611
4685
|
label = label.replace(/^session[-_:]?/i, "");
|
|
@@ -4616,6 +4690,24 @@ function formatSessionShort(sessionId) {
|
|
|
4616
4690
|
if (label.length <= 18) return label;
|
|
4617
4691
|
return `${label.slice(0, 17)}\u2026`;
|
|
4618
4692
|
}
|
|
4693
|
+
function formatResourceWatchChannel(sessionId) {
|
|
4694
|
+
const match2 = sessionId.match(/^ahp-resource-watch:\/\/[^/]*\/(.+)$/u);
|
|
4695
|
+
if (!match2) return null;
|
|
4696
|
+
const encoded = match2[1];
|
|
4697
|
+
if (!encoded) return null;
|
|
4698
|
+
try {
|
|
4699
|
+
const normalized = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
4700
|
+
const json = atob(normalized);
|
|
4701
|
+
const parsed = JSON.parse(json);
|
|
4702
|
+
const root = parsed.root ?? parsed.uri ?? parsed.resource;
|
|
4703
|
+
if (typeof root !== "string") return null;
|
|
4704
|
+
const tail = root.split(/[/\\]/u).filter(Boolean).at(-1) ?? root;
|
|
4705
|
+
const name = decodeURIComponent(tail);
|
|
4706
|
+
return `watch:${name.length <= 24 ? name : `${name.slice(0, 23)}\u2026`}`;
|
|
4707
|
+
} catch {
|
|
4708
|
+
return null;
|
|
4709
|
+
}
|
|
4710
|
+
}
|
|
4619
4711
|
function payloadPreviewOf(raw2) {
|
|
4620
4712
|
if (raw2 === void 0 || raw2 === null) return "";
|
|
4621
4713
|
let src = raw2;
|
|
@@ -4828,7 +4920,7 @@ async function createAppState(opts) {
|
|
|
4828
4920
|
const handlePath = handle.path ?? handle.id;
|
|
4829
4921
|
const initialMtimeMs = opts.initialMtimeMs ?? Date.now();
|
|
4830
4922
|
const meta = {
|
|
4831
|
-
filename:
|
|
4923
|
+
filename: basename6(handlePath),
|
|
4832
4924
|
sizeBytes: handle.size ?? 0,
|
|
4833
4925
|
startedAt: Date.now(),
|
|
4834
4926
|
logKey: opts.logKey ?? computeLogKey(handlePath, initialMtimeMs)
|
|
@@ -8830,7 +8922,7 @@ function classifyDirection(raw2) {
|
|
|
8830
8922
|
|
|
8831
8923
|
// src/index.ts
|
|
8832
8924
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
8833
|
-
var __dirname2 =
|
|
8925
|
+
var __dirname2 = dirname5(__filename2);
|
|
8834
8926
|
function loadVersion() {
|
|
8835
8927
|
const candidates = [join7(__dirname2, "..", "package.json"), join7(__dirname2, "package.json")];
|
|
8836
8928
|
for (const p of candidates) {
|
|
@@ -8902,9 +8994,9 @@ var program = new Command().name("ahp-inspector").version(VERSION).argument(
|
|
|
8902
8994
|
let absPath;
|
|
8903
8995
|
if (file) {
|
|
8904
8996
|
absPath = resolvePath(file);
|
|
8905
|
-
let
|
|
8997
|
+
let stat5;
|
|
8906
8998
|
try {
|
|
8907
|
-
|
|
8999
|
+
stat5 = statSync3(absPath);
|
|
8908
9000
|
} catch (err) {
|
|
8909
9001
|
const e = err;
|
|
8910
9002
|
if (e.code === "ENOENT") {
|
|
@@ -8914,7 +9006,7 @@ Usage: ahp-inspector [path-to-log.jsonl]`);
|
|
|
8914
9006
|
fail(`Error: cannot read ${absPath}: ${e.message}
|
|
8915
9007
|
Check file permissions.`);
|
|
8916
9008
|
}
|
|
8917
|
-
if (!
|
|
9009
|
+
if (!stat5.isFile()) {
|
|
8918
9010
|
fail(`Error: log file not found: ${absPath}
|
|
8919
9011
|
Usage: ahp-inspector [path-to-log.jsonl]`);
|
|
8920
9012
|
}
|