@adhdev/daemon-core 0.9.82-rc.186 → 0.9.82-rc.188
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/boot/daemon-lifecycle.d.ts +1 -0
- package/dist/commands/cli-manager.d.ts +2 -1
- package/dist/commands/mesh-coordinator.d.ts +13 -0
- package/dist/commands/router.d.ts +5 -1
- package/dist/config/chat-history.d.ts +1 -0
- package/dist/git/git-commands.d.ts +2 -0
- package/dist/git/git-types.d.ts +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15461 -14552
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14411 -13502
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/beads-db.d.ts +1 -0
- package/dist/mesh/mesh-events.d.ts +46 -1
- package/dist/mesh/mesh-work-queue.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +4 -0
- package/dist/providers/contracts.d.ts +32 -1
- package/dist/providers/native-history/dispatcher.d.ts +2 -0
- package/dist/providers/sdk/v1/types/common/index.d.ts +35 -1
- package/dist/providers/spec/cli-adapter.d.ts +1 -0
- package/dist/providers/spec/driver.d.ts +6 -1
- package/dist/providers/spec/native-history-executor.d.ts +2 -0
- package/dist/providers/spec/schema.gen.d.ts +22 -0
- package/dist/providers/spec/types.d.ts +10 -0
- package/dist/repo-mesh-types.d.ts +6 -0
- package/package.json +1 -1
- package/src/boot/daemon-lifecycle.ts +2 -0
- package/src/commands/chat-commands.ts +206 -18
- package/src/commands/cli-manager.ts +56 -14
- package/src/commands/mesh-coordinator.ts +110 -5
- package/src/commands/router.ts +146 -21
- package/src/config/chat-history.ts +4 -0
- package/src/git/git-commands.ts +20 -2
- package/src/git/git-status.ts +35 -6
- package/src/git/git-types.ts +2 -0
- package/src/index.ts +2 -2
- package/src/mesh/beads-db.ts +4 -0
- package/src/mesh/mesh-events.ts +264 -4
- package/src/mesh/mesh-work-queue.ts +4 -0
- package/src/providers/cli-provider-instance.ts +122 -13
- package/src/providers/contracts.d.ts +55 -0
- package/src/providers/contracts.ts +36 -1
- package/src/providers/native-history/dispatcher.ts +126 -17
- package/src/providers/provider-loader.ts +4 -7
- package/src/providers/provider-schema.ts +56 -1
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +46 -0
- package/src/providers/sdk/v1/types/common/index.ts +19 -0
- package/src/providers/spec/cli-adapter.ts +32 -5
- package/src/providers/spec/driver.ts +68 -1
- package/src/providers/spec/evaluator.ts +11 -1
- package/src/providers/spec/native-history-executor.ts +93 -27
- package/src/providers/spec/schema.gen.ts +12 -1
- package/src/providers/spec/schema.json +21 -1
- package/src/providers/spec/types.ts +10 -0
- package/src/repo-mesh-types.ts +6 -0
|
@@ -58,6 +58,7 @@ export interface NativeHistoryMessage {
|
|
|
58
58
|
content: string;
|
|
59
59
|
receivedAt: number;
|
|
60
60
|
kind?: string;
|
|
61
|
+
workspace?: string;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
export interface NativeHistoryResult {
|
|
@@ -66,6 +67,7 @@ export interface NativeHistoryResult {
|
|
|
66
67
|
sourcePath: string;
|
|
67
68
|
sourceMtimeMs: number;
|
|
68
69
|
nativeHistoryCoverage?: 'full' | 'partial' | 'best-effort';
|
|
70
|
+
workspace?: string;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
const UUID_RE = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
|
|
@@ -87,6 +89,7 @@ function executeJsonl(src: NativeHistoryJsonlSource, input: NativeHistoryInput):
|
|
|
87
89
|
|
|
88
90
|
const windowMs = typeof src.recent_window_ms === 'number' ? src.recent_window_ms : 5 * 60_000;
|
|
89
91
|
const filePat = src.file_pattern ? globToRegex(src.file_pattern) : /.*\.jsonl$/;
|
|
92
|
+
const requestedSessionId = readRequestedSessionId(input);
|
|
90
93
|
|
|
91
94
|
// path can be:
|
|
92
95
|
// - a concrete file → used as-is
|
|
@@ -112,7 +115,8 @@ function executeJsonl(src: NativeHistoryJsonlSource, input: NativeHistoryInput):
|
|
|
112
115
|
const workspaceHint = typeof input.workspace === 'string' && input.workspace.trim() ? input.workspace.trim() : '';
|
|
113
116
|
let sourcePath: string | null = null;
|
|
114
117
|
if (resolved.includes('*')) {
|
|
115
|
-
sourcePath =
|
|
118
|
+
sourcePath = pickExactSessionFileAcrossGlob(resolved, filePat, requestedSessionId)
|
|
119
|
+
|| pickSessionBoundFileAcrossGlob(resolved, filePat, windowMs, sessionFloor, workspaceHint)
|
|
116
120
|
|| newestRecentFileAcrossGlob(resolved, filePat, windowMs, sessionFloor);
|
|
117
121
|
} else {
|
|
118
122
|
let stat: fs.Stats | null = null;
|
|
@@ -120,18 +124,18 @@ function executeJsonl(src: NativeHistoryJsonlSource, input: NativeHistoryInput):
|
|
|
120
124
|
if (stat && stat.isFile()) {
|
|
121
125
|
sourcePath = resolved;
|
|
122
126
|
} else if (stat && stat.isDirectory()) {
|
|
123
|
-
sourcePath =
|
|
124
|
-
||
|
|
127
|
+
sourcePath = pickExactSessionFile(resolved, filePat, requestedSessionId)
|
|
128
|
+
|| (requestedSessionId ? null : pickSessionBoundFile(resolved, filePat, windowMs, sessionFloor, workspaceHint))
|
|
129
|
+
|| (requestedSessionId ? null : newestRecentFile(resolved, filePat, windowMs, sessionFloor));
|
|
125
130
|
}
|
|
126
131
|
// Date-templated directories (e.g. ~/.codex/sessions/{yyyy}/{mm}/{dd})
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
// or doesn't exist yet, walk the last 3 UTC days at the same depth
|
|
131
|
-
// and pick the newest matching rollout across all of them.
|
|
132
|
+
// can drift from the provider's chosen calendar day because CLIs
|
|
133
|
+
// disagree on local-vs-UTC date buckets. Search nearby date dirs
|
|
134
|
+
// before falling back to non-exact matching.
|
|
132
135
|
if (!sourcePath && hasDateTemplateSegment(src.path)) {
|
|
133
|
-
sourcePath =
|
|
134
|
-
||
|
|
136
|
+
sourcePath = pickExactSessionFileAcrossDateWindow(src.path, input, filePat, requestedSessionId)
|
|
137
|
+
|| (requestedSessionId ? null : pickSessionBoundFileAcrossDateWindow(src.path, input, filePat, windowMs, sessionFloor, workspaceHint))
|
|
138
|
+
|| (requestedSessionId ? null : newestRecentFileAcrossDateWindow(src.path, input, filePat, windowMs, sessionFloor));
|
|
135
139
|
}
|
|
136
140
|
}
|
|
137
141
|
if (!sourcePath) return null;
|
|
@@ -139,6 +143,7 @@ function executeJsonl(src: NativeHistoryJsonlSource, input: NativeHistoryInput):
|
|
|
139
143
|
const mtime = safeMtimeMs(sourcePath);
|
|
140
144
|
const lines = readJsonlLines(sourcePath);
|
|
141
145
|
if (lines.length === 0) return null;
|
|
146
|
+
const transcriptWorkspace = readSessionMetaWorkspace(lines);
|
|
142
147
|
|
|
143
148
|
// session id: filename uuid or extracted from first record
|
|
144
149
|
let providerSessionId: string | undefined;
|
|
@@ -150,7 +155,7 @@ function executeJsonl(src: NativeHistoryJsonlSource, input: NativeHistoryInput):
|
|
|
150
155
|
if (m) providerSessionId = m[1];
|
|
151
156
|
}
|
|
152
157
|
|
|
153
|
-
const requested =
|
|
158
|
+
const requested = requestedSessionId || '';
|
|
154
159
|
if (requested && providerSessionId && providerSessionId !== requested) return null;
|
|
155
160
|
|
|
156
161
|
const filter = src.message_filter ? compileWhere(src.message_filter.where) : null;
|
|
@@ -159,7 +164,10 @@ function executeJsonl(src: NativeHistoryJsonlSource, input: NativeHistoryInput):
|
|
|
159
164
|
const rec = lines[i];
|
|
160
165
|
if (filter && !filter(rec)) continue;
|
|
161
166
|
const msg = projectMessage(rec, src.message_map, i, lines.length, mtime);
|
|
162
|
-
if (msg)
|
|
167
|
+
if (msg) {
|
|
168
|
+
if (transcriptWorkspace) msg.workspace = transcriptWorkspace;
|
|
169
|
+
messages.push(msg);
|
|
170
|
+
}
|
|
163
171
|
}
|
|
164
172
|
if (messages.length === 0) return null;
|
|
165
173
|
|
|
@@ -169,9 +177,19 @@ function executeJsonl(src: NativeHistoryJsonlSource, input: NativeHistoryInput):
|
|
|
169
177
|
sourcePath,
|
|
170
178
|
sourceMtimeMs: mtime,
|
|
171
179
|
nativeHistoryCoverage: 'full',
|
|
180
|
+
workspace: transcriptWorkspace,
|
|
172
181
|
};
|
|
173
182
|
}
|
|
174
183
|
|
|
184
|
+
function readSessionMetaWorkspace(lines: any[]): string | undefined {
|
|
185
|
+
for (const record of lines.slice(0, 5)) {
|
|
186
|
+
if (String(record?.type ?? '') !== 'session_meta') continue;
|
|
187
|
+
const cwd = typeof record?.payload?.cwd === 'string' ? record.payload.cwd.trim() : '';
|
|
188
|
+
if (cwd) return cwd;
|
|
189
|
+
}
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
|
|
175
193
|
function readJsonlLines(p: string): any[] {
|
|
176
194
|
let text: string;
|
|
177
195
|
try { text = fs.readFileSync(p, 'utf8'); } catch { return []; }
|
|
@@ -292,9 +310,9 @@ function expandPath(template: string, input: NativeHistoryInput): string | null
|
|
|
292
310
|
cwd: workspaceResolved,
|
|
293
311
|
cwd_dashed: workspaceResolved.replace(/\//g, '-'),
|
|
294
312
|
session_id: input.providerSessionId || input.sessionId || input.historySessionId || '',
|
|
295
|
-
yyyy: String(now.
|
|
296
|
-
mm: String(now.
|
|
297
|
-
dd: String(now.
|
|
313
|
+
yyyy: String(now.getFullYear()),
|
|
314
|
+
mm: String(now.getMonth() + 1).padStart(2, '0'),
|
|
315
|
+
dd: String(now.getDate()).padStart(2, '0'),
|
|
298
316
|
};
|
|
299
317
|
// Replace {var}. If a referenced variable is empty (e.g. session_id
|
|
300
318
|
// before the agent has allocated one), return null so the caller
|
|
@@ -393,12 +411,10 @@ function hasDateTemplateSegment(template: string): boolean {
|
|
|
393
411
|
}
|
|
394
412
|
|
|
395
413
|
/**
|
|
396
|
-
* Walk
|
|
414
|
+
* Walk nearby local calendar days of a date-templated path (e.g.
|
|
397
415
|
* `~/.codex/sessions/{yyyy}/{mm}/{dd}`) and return the newest matching
|
|
398
|
-
* file across all of them.
|
|
399
|
-
*
|
|
400
|
-
* date rolls over, so today's expanded dir alone misses the live
|
|
401
|
-
* transcript.
|
|
416
|
+
* file across all of them. Providers differ on local-vs-UTC date buckets,
|
|
417
|
+
* so today's expanded dir alone can miss a live transcript.
|
|
402
418
|
*/
|
|
403
419
|
function newestRecentFileAcrossDateWindow(
|
|
404
420
|
template: string,
|
|
@@ -409,8 +425,8 @@ function newestRecentFileAcrossDateWindow(
|
|
|
409
425
|
): string | null {
|
|
410
426
|
const cutoff = Math.max(Date.now() - windowMs, sessionFloorMs);
|
|
411
427
|
let best: { p: string; mtime: number } | null = null;
|
|
412
|
-
for (
|
|
413
|
-
const dayMs = Date.now()
|
|
428
|
+
for (const dayOffset of [0, -1, 1, -2, 2]) {
|
|
429
|
+
const dayMs = Date.now() + dayOffset * 24 * 60 * 60 * 1000;
|
|
414
430
|
const dayInput: NativeHistoryInput = { ...input, sessionStartedAtMs: sessionFloorMs };
|
|
415
431
|
const resolved = expandPathForDate(template, dayInput, new Date(dayMs));
|
|
416
432
|
if (!resolved) continue;
|
|
@@ -448,9 +464,9 @@ function expandPathForDate(template: string, input: NativeHistoryInput, day: Dat
|
|
|
448
464
|
cwd: workspaceResolved,
|
|
449
465
|
cwd_dashed: workspaceResolved.replace(/\//g, '-'),
|
|
450
466
|
session_id: input.providerSessionId || input.sessionId || input.historySessionId || '',
|
|
451
|
-
yyyy: String(day.
|
|
452
|
-
mm: String(day.
|
|
453
|
-
dd: String(day.
|
|
467
|
+
yyyy: String(day.getFullYear()),
|
|
468
|
+
mm: String(day.getMonth() + 1).padStart(2, '0'),
|
|
469
|
+
dd: String(day.getDate()).padStart(2, '0'),
|
|
454
470
|
};
|
|
455
471
|
let missing = false;
|
|
456
472
|
out = out.replace(/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/g, (_m, name) => {
|
|
@@ -481,6 +497,56 @@ function safeMtimeMs(p: string): number {
|
|
|
481
497
|
try { return Math.floor(fs.statSync(p).mtimeMs); } catch { return 0; }
|
|
482
498
|
}
|
|
483
499
|
|
|
500
|
+
function readRequestedSessionId(input: NativeHistoryInput): string {
|
|
501
|
+
const raw = input.providerSessionId || input.sessionId || input.historySessionId || '';
|
|
502
|
+
const value = typeof raw === 'string' ? raw.trim() : '';
|
|
503
|
+
return UUID_RE.test(value) ? value : '';
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function filenameUuid(filePath: string): string {
|
|
507
|
+
const match = path.basename(filePath).match(UUID_RE);
|
|
508
|
+
return match?.[1] || '';
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function pickExactSessionFile(dir: string, pattern: RegExp, requestedSessionId: string): string | null {
|
|
512
|
+
if (!requestedSessionId) return null;
|
|
513
|
+
const files = listMatchingFiles(dir, pattern)
|
|
514
|
+
.filter(p => filenameUuid(p).toLowerCase() === requestedSessionId.toLowerCase())
|
|
515
|
+
.sort((a, b) => safeMtimeMs(b) - safeMtimeMs(a));
|
|
516
|
+
return files[0] || null;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function pickExactSessionFileAcrossGlob(template: string, pattern: RegExp, requestedSessionId: string): string | null {
|
|
520
|
+
if (!requestedSessionId) return null;
|
|
521
|
+
const dirs = expandDirGlob(template);
|
|
522
|
+
const matches: string[] = [];
|
|
523
|
+
for (const d of dirs) {
|
|
524
|
+
const found = pickExactSessionFile(d, pattern, requestedSessionId);
|
|
525
|
+
if (found) matches.push(found);
|
|
526
|
+
}
|
|
527
|
+
matches.sort((a, b) => safeMtimeMs(b) - safeMtimeMs(a));
|
|
528
|
+
return matches[0] || null;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function pickExactSessionFileAcrossDateWindow(
|
|
532
|
+
template: string,
|
|
533
|
+
input: NativeHistoryInput,
|
|
534
|
+
pattern: RegExp,
|
|
535
|
+
requestedSessionId: string,
|
|
536
|
+
): string | null {
|
|
537
|
+
if (!requestedSessionId) return null;
|
|
538
|
+
const matches: string[] = [];
|
|
539
|
+
for (const dayOffset of [0, -1, 1, -2, 2]) {
|
|
540
|
+
const dayMs = Date.now() + dayOffset * 24 * 60 * 60 * 1000;
|
|
541
|
+
const resolved = expandPathForDate(template, input, new Date(dayMs));
|
|
542
|
+
if (!resolved) continue;
|
|
543
|
+
const found = pickExactSessionFile(resolved, pattern, requestedSessionId);
|
|
544
|
+
if (found) matches.push(found);
|
|
545
|
+
}
|
|
546
|
+
matches.sort((a, b) => safeMtimeMs(b) - safeMtimeMs(a));
|
|
547
|
+
return matches[0] || null;
|
|
548
|
+
}
|
|
549
|
+
|
|
484
550
|
// ────────────────────────────────────────────────────────────────────────────
|
|
485
551
|
// Per-session rollout binding
|
|
486
552
|
//
|
|
@@ -624,8 +690,8 @@ function pickSessionBoundFileAcrossDateWindow(
|
|
|
624
690
|
if (!sessionFloorMs || !workspaceHint) return null;
|
|
625
691
|
const cutoff = Math.max(Date.now() - windowMs, sessionFloorMs - SPAWN_BIND_GRACE_MS);
|
|
626
692
|
const files: string[] = [];
|
|
627
|
-
for (
|
|
628
|
-
const dayMs = sessionFloorMs
|
|
693
|
+
for (const dayOffset of [0, -1, 1, -2, 2]) {
|
|
694
|
+
const dayMs = sessionFloorMs + dayOffset * 24 * 60 * 60 * 1000;
|
|
629
695
|
const dayInput: NativeHistoryInput = { ...input, sessionStartedAtMs: sessionFloorMs };
|
|
630
696
|
const resolved = expandPathForDate(template, dayInput, new Date(dayMs));
|
|
631
697
|
if (!resolved) continue;
|
|
@@ -130,7 +130,18 @@ export const SCHEMA = {
|
|
|
130
130
|
"additionalProperties": false,
|
|
131
131
|
"properties": {
|
|
132
132
|
"busy_hold_ms": { "type": "integer", "minimum": 0 },
|
|
133
|
-
"startup_grace_ms": { "type": "integer", "minimum": 0 }
|
|
133
|
+
"startup_grace_ms": { "type": "integer", "minimum": 0 },
|
|
134
|
+
"completion_idle_after": {
|
|
135
|
+
"type": "object",
|
|
136
|
+
"additionalProperties": false,
|
|
137
|
+
"required": ["regex", "hold_ms"],
|
|
138
|
+
"properties": {
|
|
139
|
+
"section": { "type": "string", "minLength": 1 },
|
|
140
|
+
"regex": { "type": "string", "minLength": 1 },
|
|
141
|
+
"flags": { "type": "string" },
|
|
142
|
+
"hold_ms": { "type": "integer", "minimum": 0 }
|
|
143
|
+
}
|
|
144
|
+
}
|
|
134
145
|
}
|
|
135
146
|
}
|
|
136
147
|
},
|
|
@@ -59,7 +59,27 @@
|
|
|
59
59
|
"default": [],
|
|
60
60
|
"items": { "$ref": "#/definitions/delegateTrigger" }
|
|
61
61
|
},
|
|
62
|
-
"native_history": { "$ref": "#/definitions/nativeHistory" }
|
|
62
|
+
"native_history": { "$ref": "#/definitions/nativeHistory" },
|
|
63
|
+
"cli_version_range": { "type": "string", "minLength": 1 },
|
|
64
|
+
"debounce": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"additionalProperties": false,
|
|
67
|
+
"properties": {
|
|
68
|
+
"busy_hold_ms": { "type": "integer", "minimum": 0 },
|
|
69
|
+
"startup_grace_ms": { "type": "integer", "minimum": 0 },
|
|
70
|
+
"completion_idle_after": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"additionalProperties": false,
|
|
73
|
+
"required": ["regex", "hold_ms"],
|
|
74
|
+
"properties": {
|
|
75
|
+
"section": { "type": "string", "minLength": 1 },
|
|
76
|
+
"regex": { "type": "string", "minLength": 1 },
|
|
77
|
+
"flags": { "type": "string" },
|
|
78
|
+
"hold_ms": { "type": "integer", "minimum": 0 }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
63
83
|
},
|
|
64
84
|
"definitions": {
|
|
65
85
|
"size": {
|
|
@@ -227,5 +227,15 @@ export interface CliSpec {
|
|
|
227
227
|
* once the window passes and an idle state has actually been
|
|
228
228
|
* observed. */
|
|
229
229
|
startup_grace_ms?: number;
|
|
230
|
+
/** Treat a provider-specific completion marker as idle after it has
|
|
231
|
+
* remained visible for hold_ms. This handles TUIs that leave their
|
|
232
|
+
* last spinner glyph next to a completed timer, causing the normal
|
|
233
|
+
* busy regex to keep matching after the turn is done. */
|
|
234
|
+
completion_idle_after?: {
|
|
235
|
+
section?: string;
|
|
236
|
+
regex: string;
|
|
237
|
+
flags?: string;
|
|
238
|
+
hold_ms: number;
|
|
239
|
+
};
|
|
230
240
|
};
|
|
231
241
|
}
|
package/src/repo-mesh-types.ts
CHANGED
|
@@ -359,11 +359,17 @@ export interface RepoMeshSessionStatus {
|
|
|
359
359
|
sessionId: string;
|
|
360
360
|
providerType?: string;
|
|
361
361
|
state?: string;
|
|
362
|
+
chatStatus?: string;
|
|
362
363
|
lifecycle?: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted';
|
|
363
364
|
surfaceKind?: 'live_runtime' | 'recovery_snapshot' | 'inactive_record';
|
|
364
365
|
recoveryState?: string | null;
|
|
365
366
|
workspace?: string | null;
|
|
366
367
|
title?: string | null;
|
|
368
|
+
role?: string | null;
|
|
369
|
+
isSelfCoordinator?: boolean;
|
|
370
|
+
statusNote?: string | null;
|
|
371
|
+
createdAt?: string | null;
|
|
372
|
+
startedAt?: string | null;
|
|
367
373
|
lastActivityAt?: string | null;
|
|
368
374
|
isCached?: boolean;
|
|
369
375
|
}
|