@adhdev/daemon-core 0.9.82-rc.314 → 0.9.82-rc.315
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 +77 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +77 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/providers/spec/native-history-executor.ts +104 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/daemon-core",
|
|
3
|
-
"version": "0.9.82-rc.
|
|
3
|
+
"version": "0.9.82-rc.315",
|
|
4
4
|
"description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"author": "vilmire",
|
|
47
47
|
"license": "AGPL-3.0-or-later",
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@adhdev/mesh-shared": "0.9.82-rc.
|
|
49
|
+
"@adhdev/mesh-shared": "0.9.82-rc.315",
|
|
50
50
|
"@adhdev/session-host-core": "*",
|
|
51
51
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
52
52
|
"ajv": "^8.20.0",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
import * as fs from 'node:fs';
|
|
22
22
|
import * as os from 'node:os';
|
|
23
23
|
import * as path from 'node:path';
|
|
24
|
+
import { LOG } from '../../logging/logger.js';
|
|
24
25
|
import type {
|
|
25
26
|
NativeHistoryConfig,
|
|
26
27
|
NativeHistoryJsonlSource,
|
|
@@ -138,8 +139,48 @@ function executeJsonl(src: NativeHistoryJsonlSource, input: NativeHistoryInput):
|
|
|
138
139
|
|| (requestedSessionId ? null : pickSessionBoundFileAcrossDateWindow(src.path, input, filePat, windowMs, sessionFloor, workspaceHint))
|
|
139
140
|
|| (requestedSessionId ? null : newestRecentFileAcrossDateWindow(src.path, input, filePat, windowMs, sessionFloor));
|
|
140
141
|
}
|
|
142
|
+
// Raw-workspace slug candidate: `resolved` derives its {cwd*} slug from
|
|
143
|
+
// fs.realpathSync(workspace). On Windows realpath normalizes the path
|
|
144
|
+
// (drive-letter case D:↔d:, \\?\ long-path prefix, junction expansion)
|
|
145
|
+
// so the slug can diverge from the one the CLI actually wrote — and the
|
|
146
|
+
// concrete path above then misses with ENOENT. Retry with the slug built
|
|
147
|
+
// from the RAW workspace string before falling back to a scan; it's the
|
|
148
|
+
// cheap fix when realpath divergence is the only problem.
|
|
149
|
+
if (!sourcePath && !hasDateTemplateSegment(src.path)) {
|
|
150
|
+
const resolvedRaw = expandPath(src.path, input, { skipWorkspaceRealpath: true });
|
|
151
|
+
if (resolvedRaw && resolvedRaw !== resolved) {
|
|
152
|
+
try {
|
|
153
|
+
const rawStat = fs.statSync(resolvedRaw);
|
|
154
|
+
if (rawStat.isFile()) sourcePath = resolvedRaw;
|
|
155
|
+
else if (rawStat.isDirectory()) {
|
|
156
|
+
sourcePath = pickExactSessionFile(resolvedRaw, filePat, requestedSessionId)
|
|
157
|
+
|| (requestedSessionId ? null : newestRecentFile(resolvedRaw, filePat, windowMs, sessionFloor));
|
|
158
|
+
}
|
|
159
|
+
} catch { /* raw slug also missed — fall through to scan */ }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Last-resort scan: the slug-derived directory missed entirely (the
|
|
163
|
+
// dominant Windows failure: realpath/raw slug both diverge from the CLI's
|
|
164
|
+
// on-disk project dir → 0 messages, no PTY fallback for native-source
|
|
165
|
+
// providers). When we have an exact session id, walk the projects root
|
|
166
|
+
// for `<sessionId>.jsonl` regardless of which project subdir holds it.
|
|
167
|
+
// The session id is a UUID, so basename matching is unambiguous; mirrors
|
|
168
|
+
// the standalone reader's scan (claude-cli-transcript.ts resolveTranscriptPath).
|
|
169
|
+
if (!sourcePath && requestedSessionId) {
|
|
170
|
+
sourcePath = scanProjectsRootForSessionFile(src.path, input, requestedSessionId);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (!sourcePath) {
|
|
174
|
+
// Was silent before — a slug miss produced 0 messages with no trace, so
|
|
175
|
+
// a live read_chat returning empty was indistinguishable from "no file"
|
|
176
|
+
// vs "wrong path". Log the attempted concrete path + both slug variants
|
|
177
|
+
// so the failure mode is greppable in daemon logs.
|
|
178
|
+
const wsRaw = typeof input.workspace === 'string' ? input.workspace : '';
|
|
179
|
+
let wsReal = wsRaw;
|
|
180
|
+
try { if (wsRaw) wsReal = fs.realpathSync(wsRaw); } catch { /* keep raw */ }
|
|
181
|
+
LOG.debug('NativeHistory', `jsonl unresolved: tried=${JSON.stringify(resolved)} sessionId=${requestedSessionId || '(none)'} wsRaw=${JSON.stringify(wsRaw)} wsReal=${JSON.stringify(wsReal)} rawSlug=${JSON.stringify(claudeProjectDirName(wsRaw))} realSlug=${JSON.stringify(claudeProjectDirName(wsReal))} (concrete miss + raw-slug retry + projects scan all failed)`);
|
|
182
|
+
return null;
|
|
141
183
|
}
|
|
142
|
-
if (!sourcePath) return null;
|
|
143
184
|
|
|
144
185
|
const mtime = safeMtimeMs(sourcePath);
|
|
145
186
|
const lines = readJsonlLines(sourcePath);
|
|
@@ -278,7 +319,7 @@ function executeSqlite(src: NativeHistorySqliteSource, input: NativeHistoryInput
|
|
|
278
319
|
// Path expansion + globbing
|
|
279
320
|
// ────────────────────────────────────────────────────────────────────────────
|
|
280
321
|
|
|
281
|
-
function expandPath(template: string, input: NativeHistoryInput): string | null {
|
|
322
|
+
function expandPath(template: string, input: NativeHistoryInput, opts?: { skipWorkspaceRealpath?: boolean }): string | null {
|
|
282
323
|
if (!template) return null;
|
|
283
324
|
let out = template;
|
|
284
325
|
if (out.startsWith('~/') || out === '~') {
|
|
@@ -301,7 +342,11 @@ function expandPath(template: string, input: NativeHistoryInput): string | null
|
|
|
301
342
|
// `-`. Realpath also handles aliases such as /tmp -> /private/tmp.
|
|
302
343
|
const workspaceRaw = input.workspace ?? '';
|
|
303
344
|
let workspaceResolved = workspaceRaw;
|
|
304
|
-
|
|
345
|
+
// The caller may request the RAW slug (skip realpath) to recover from
|
|
346
|
+
// Windows realpath normalization diverging the {cwd*} slug from the dir
|
|
347
|
+
// the CLI actually created. Default keeps realpath (handles /tmp ->
|
|
348
|
+
// /private/tmp aliasing that the CLI itself resolves on macOS).
|
|
349
|
+
if (workspaceRaw && !opts?.skipWorkspaceRealpath) {
|
|
305
350
|
try { workspaceResolved = fs.realpathSync(workspaceRaw); }
|
|
306
351
|
catch { /* path may not exist yet — keep the raw value */ }
|
|
307
352
|
}
|
|
@@ -333,6 +378,62 @@ function claudeProjectDirName(workspace: string): string {
|
|
|
333
378
|
return workspace.replace(/[^A-Za-z0-9_-]/g, '-');
|
|
334
379
|
}
|
|
335
380
|
|
|
381
|
+
/**
|
|
382
|
+
* Last-resort lookup for a transcript by its exact session id, ignoring the
|
|
383
|
+
* per-cwd slug entirely. The slug-derived directory above can miss completely
|
|
384
|
+
* when the CLI's on-disk project dir disagrees with the slug we reconstruct
|
|
385
|
+
* (notably on Windows, where fs.realpathSync normalizes drive-letter case and
|
|
386
|
+
* adds a \\?\ prefix). Since the session id is a UUID, scanning the projects
|
|
387
|
+
* root for `<sessionId>.jsonl` is unambiguous.
|
|
388
|
+
*
|
|
389
|
+
* Derives the scan base from the template's segments up to (but excluding) the
|
|
390
|
+
* first one that references a per-session variable ({cwd*} or {session_id}) —
|
|
391
|
+
* e.g. `~/.claude/projects/{cwd_claude_project}/{session_id}.jsonl` → scan
|
|
392
|
+
* `~/.claude/projects`. Returns the matching file path, or null.
|
|
393
|
+
*/
|
|
394
|
+
function scanProjectsRootForSessionFile(template: string, input: NativeHistoryInput, requestedSessionId: string): string | null {
|
|
395
|
+
if (!requestedSessionId) return null;
|
|
396
|
+
// Resolve the leading static portion of the template (everything before the
|
|
397
|
+
// first {var} segment) into a concrete base directory.
|
|
398
|
+
let head = template;
|
|
399
|
+
if (head.startsWith('~/') || head === '~') head = path.join(os.homedir(), head.slice(2));
|
|
400
|
+
const segs = head.split('/');
|
|
401
|
+
const baseParts: string[] = [];
|
|
402
|
+
for (const seg of segs) {
|
|
403
|
+
if (/[{}*?]/.test(seg)) break;
|
|
404
|
+
baseParts.push(seg);
|
|
405
|
+
}
|
|
406
|
+
const base = baseParts.join('/');
|
|
407
|
+
if (!base) return null;
|
|
408
|
+
let baseStat: fs.Stats | null = null;
|
|
409
|
+
try { baseStat = fs.statSync(base); } catch { return null; }
|
|
410
|
+
if (!baseStat.isDirectory()) return null;
|
|
411
|
+
|
|
412
|
+
const needle = `${requestedSessionId.toLowerCase()}.jsonl`;
|
|
413
|
+
// Bounded walk: project layouts are <root>/<projectDir>/<uuid>.jsonl, so a
|
|
414
|
+
// shallow scan (root + one level of subdirs) suffices and avoids walking an
|
|
415
|
+
// unbounded tree. Check the root itself first, then each immediate subdir.
|
|
416
|
+
const dirsToScan: string[] = [base];
|
|
417
|
+
try {
|
|
418
|
+
for (const entry of fs.readdirSync(base, { withFileTypes: true })) {
|
|
419
|
+
if (entry.isDirectory()) dirsToScan.push(path.join(base, entry.name));
|
|
420
|
+
}
|
|
421
|
+
} catch { /* readdir failed — fall back to scanning base only */ }
|
|
422
|
+
|
|
423
|
+
for (const dir of dirsToScan) {
|
|
424
|
+
let entries: fs.Dirent[];
|
|
425
|
+
try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { continue; }
|
|
426
|
+
for (const entry of entries) {
|
|
427
|
+
if (!entry.isFile()) continue;
|
|
428
|
+
if (entry.name.toLowerCase() !== needle) continue;
|
|
429
|
+
const found = path.join(dir, entry.name);
|
|
430
|
+
LOG.debug('NativeHistory', `jsonl scan-fallback hit: sessionId=${requestedSessionId} resolved via projects-root scan → ${JSON.stringify(found)} (slug-derived path missed; likely realpath/slug divergence)`);
|
|
431
|
+
return found;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
|
|
336
437
|
function globToRegex(pattern: string): RegExp {
|
|
337
438
|
// Minimal glob: `*` → `[^/]*`, `?` → `[^/]`, `.` → `\.`. Anchored.
|
|
338
439
|
const re = pattern
|