@adhdev/daemon-core 0.9.82-rc.7 → 0.9.82-rc.70
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 +2 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -0
- package/dist/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/dist/commands/router.d.ts +24 -0
- package/dist/config/mesh-config.d.ts +66 -1
- package/dist/git/git-commands.d.ts +1 -0
- package/dist/git/git-status.d.ts +5 -0
- package/dist/git/git-types.d.ts +10 -0
- package/dist/index.d.ts +13 -6
- package/dist/index.js +4619 -1143
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4582 -1128
- package/dist/index.mjs.map +1 -1
- package/dist/installer.d.ts +1 -4
- package/dist/launch.d.ts +1 -1
- package/dist/logging/async-batch-writer.d.ts +10 -0
- package/dist/mesh/beads-db.d.ts +18 -0
- package/dist/mesh/mesh-active-work.d.ts +48 -0
- package/dist/mesh/mesh-events.d.ts +28 -5
- package/dist/mesh/mesh-fast-forward.d.ts +39 -0
- package/dist/mesh/mesh-host-ownership.d.ts +9 -0
- package/dist/mesh/mesh-ledger.d.ts +38 -1
- package/dist/mesh/mesh-work-queue.d.ts +27 -5
- package/dist/mesh/refine-config.d.ts +119 -0
- package/dist/providers/chat-message-normalization.d.ts +1 -0
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/dist/repo-mesh-types.d.ts +160 -0
- package/dist/status/reporter.d.ts +2 -0
- package/package.json +3 -1
- package/src/boot/daemon-lifecycle.ts +4 -0
- package/src/cli-adapters/provider-cli-adapter.ts +91 -3
- package/src/cli-adapters/provider-cli-parse.d.ts +1 -0
- package/src/cli-adapters/provider-cli-parse.ts +4 -0
- package/src/cli-adapters/provider-cli-runtime.ts +3 -1
- package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.ts +20 -10
- package/src/commands/handler.ts +8 -1
- package/src/commands/mesh-coordinator.ts +13 -143
- package/src/commands/router.ts +2452 -409
- package/src/config/chat-history.ts +9 -7
- package/src/config/mesh-config.ts +244 -1
- package/src/daemon/dev-cli-debug.ts +10 -1
- package/src/detection/ide-detector.ts +26 -16
- package/src/git/git-commands.ts +3 -3
- package/src/git/git-status.ts +97 -6
- package/src/git/git-summary.ts +3 -0
- package/src/git/git-types.ts +11 -0
- package/src/index.ts +39 -5
- package/src/installer.d.ts +1 -1
- package/src/installer.ts +8 -6
- package/src/launch.d.ts +1 -1
- package/src/launch.ts +37 -28
- package/src/logging/async-batch-writer.ts +55 -0
- package/src/logging/logger.ts +2 -1
- package/src/mesh/beads-db.ts +176 -0
- package/src/mesh/coordinator-prompt.ts +4 -2
- package/src/mesh/mesh-active-work.ts +205 -0
- package/src/mesh/mesh-events.ts +291 -38
- package/src/mesh/mesh-fast-forward.ts +430 -0
- package/src/mesh/mesh-host-ownership.ts +73 -0
- package/src/mesh/mesh-ledger.ts +138 -1
- package/src/mesh/mesh-work-queue.ts +199 -137
- package/src/mesh/refine-config.ts +306 -0
- package/src/providers/chat-message-normalization.ts +3 -1
- package/src/providers/cli-provider-instance.ts +66 -1
- package/src/providers/ide-provider-instance.ts +17 -3
- package/src/providers/provider-loader.ts +10 -4
- package/src/providers/version-archive.ts +38 -20
- package/src/repo-mesh-types.ts +174 -0
- package/src/status/reporter.ts +15 -0
- package/src/system/host-memory.ts +29 -12
package/src/repo-mesh-types.ts
CHANGED
|
@@ -23,11 +23,42 @@ export interface RepoMesh {
|
|
|
23
23
|
defaultBranch?: string;
|
|
24
24
|
policy: RepoMeshPolicy;
|
|
25
25
|
coordinator: RepoMeshCoordinatorConfig;
|
|
26
|
+
meshHost?: RepoMeshHostMetadata;
|
|
26
27
|
projectContext: ProjectContextSnapshot;
|
|
27
28
|
nodes: RepoMeshNode[];
|
|
28
29
|
status: 'active' | 'archived' | 'deleted';
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
export type RepoMeshDaemonRole = 'host' | 'member';
|
|
33
|
+
|
|
34
|
+
export interface RepoMeshHostPairingMetadata {
|
|
35
|
+
status: 'not_configured' | 'pairing' | 'paired' | 'rejected' | 'revoked';
|
|
36
|
+
tokenId?: string;
|
|
37
|
+
joinedAt?: string;
|
|
38
|
+
lastPairedAt?: string;
|
|
39
|
+
lastRejectedAt?: string;
|
|
40
|
+
expiresAt?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface RepoMeshHostMetadata {
|
|
44
|
+
/** Local daemon role for this mesh. Missing metadata defaults to host for standalone compatibility. */
|
|
45
|
+
role: RepoMeshDaemonRole;
|
|
46
|
+
/** Daemon that owns mesh truth/status/git/queue/session/ledger/coordinator ownership. */
|
|
47
|
+
hostDaemonId?: string;
|
|
48
|
+
/** Mesh node that represents the host daemon, when known. */
|
|
49
|
+
hostNodeId?: string;
|
|
50
|
+
/** Future standalone manual pairing endpoint entered by member daemons. */
|
|
51
|
+
hostAddress?: string;
|
|
52
|
+
/** Redacted pairing state only; raw join tokens must not be persisted here. */
|
|
53
|
+
pairing?: RepoMeshHostPairingMetadata;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface RepoMeshHostStatus extends RepoMeshHostMetadata {
|
|
57
|
+
canOwnCoordinator: boolean;
|
|
58
|
+
canOwnQueue: boolean;
|
|
59
|
+
defaulted: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
31
62
|
export interface RepoMeshNode {
|
|
32
63
|
id: string;
|
|
33
64
|
daemonId: string;
|
|
@@ -42,6 +73,7 @@ export interface RepoMeshNode {
|
|
|
42
73
|
effectiveCapabilities: RepoMeshNodeCapabilities;
|
|
43
74
|
policy: RepoMeshNodePolicy;
|
|
44
75
|
health: RepoMeshNodeHealth;
|
|
76
|
+
role?: RepoMeshDaemonRole;
|
|
45
77
|
status: 'enabled' | 'disabled' | 'removed';
|
|
46
78
|
}
|
|
47
79
|
|
|
@@ -229,6 +261,7 @@ export interface LocalMeshEntry {
|
|
|
229
261
|
defaultBranch?: string;
|
|
230
262
|
policy: RepoMeshPolicy;
|
|
231
263
|
coordinator: RepoMeshCoordinatorConfig;
|
|
264
|
+
meshHost?: RepoMeshHostMetadata;
|
|
232
265
|
nodes: LocalMeshNodeEntry[];
|
|
233
266
|
createdAt: string;
|
|
234
267
|
updatedAt: string;
|
|
@@ -251,6 +284,7 @@ export interface LocalMeshNodeEntry {
|
|
|
251
284
|
clonedFromNodeId?: string;
|
|
252
285
|
/** Optional associated/external repos configured as node metadata. */
|
|
253
286
|
relatedRepos?: RepoMeshRelatedRepo[];
|
|
287
|
+
role?: RepoMeshDaemonRole;
|
|
254
288
|
}
|
|
255
289
|
|
|
256
290
|
// ─── Mesh Status (runtime, not persisted) ───────
|
|
@@ -259,17 +293,157 @@ export interface RepoMeshStatus {
|
|
|
259
293
|
meshId: string;
|
|
260
294
|
meshName: string;
|
|
261
295
|
repoIdentity: string;
|
|
296
|
+
defaultBranch?: string;
|
|
262
297
|
refreshedAt: string;
|
|
298
|
+
meshHost?: RepoMeshHostStatus;
|
|
263
299
|
nodes: RepoMeshNodeStatus[];
|
|
300
|
+
queue?: RepoMeshQueueStatus;
|
|
301
|
+
ledger?: RepoMeshLedgerStatus;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export interface RepoMeshSessionStatus {
|
|
305
|
+
sessionId: string;
|
|
306
|
+
providerType?: string;
|
|
307
|
+
state?: string;
|
|
308
|
+
lifecycle?: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'interrupted';
|
|
309
|
+
surfaceKind?: 'live_runtime' | 'recovery_snapshot' | 'inactive_record';
|
|
310
|
+
recoveryState?: string | null;
|
|
311
|
+
workspace?: string | null;
|
|
312
|
+
title?: string | null;
|
|
313
|
+
lastActivityAt?: string | null;
|
|
314
|
+
isCached?: boolean;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export type RepoMeshPeerConnectionState = 'self' | 'connected' | 'connecting' | 'disconnected' | 'failed' | 'closed' | 'unknown';
|
|
318
|
+
export type RepoMeshPeerConnectionTransport = 'local' | 'direct' | 'relay' | 'unknown';
|
|
319
|
+
|
|
320
|
+
export interface RepoMeshPeerConnectionStatus {
|
|
321
|
+
perspective: 'selected_coordinator';
|
|
322
|
+
source: 'mesh_peer_status' | 'not_reported';
|
|
323
|
+
state: RepoMeshPeerConnectionState;
|
|
324
|
+
transport: RepoMeshPeerConnectionTransport;
|
|
325
|
+
reported: boolean;
|
|
326
|
+
reason?: string;
|
|
327
|
+
lastStateChangeAt?: string;
|
|
328
|
+
lastConnectedAt?: string;
|
|
329
|
+
lastCommandAt?: string;
|
|
264
330
|
}
|
|
265
331
|
|
|
266
332
|
export interface RepoMeshNodeStatus {
|
|
267
333
|
nodeId: string;
|
|
268
334
|
machineLabel: string;
|
|
269
335
|
workspace: string;
|
|
336
|
+
repoRoot?: string;
|
|
337
|
+
daemonId?: string;
|
|
338
|
+
machineId?: string;
|
|
339
|
+
role?: RepoMeshDaemonRole;
|
|
340
|
+
machineStatus?: string;
|
|
341
|
+
isLocalWorktree?: boolean;
|
|
342
|
+
worktreeBranch?: string;
|
|
270
343
|
health: RepoMeshNodeHealth;
|
|
271
344
|
git?: GitRepoStatus;
|
|
345
|
+
/**
|
|
346
|
+
* True when the selected coordinator has evidence that a peer git probe is still
|
|
347
|
+
* in flight or just timed out during initial mesh handshake, so callers should
|
|
348
|
+
* treat missing git data as pending instead of authoritative absence.
|
|
349
|
+
*/
|
|
350
|
+
gitProbePending?: boolean;
|
|
272
351
|
providers: string[];
|
|
273
352
|
activeSessions: string[];
|
|
353
|
+
activeSessionDetails?: RepoMeshSessionStatus[];
|
|
354
|
+
providerPriority?: string[];
|
|
355
|
+
launchReady?: boolean;
|
|
356
|
+
lastSeenAt?: string;
|
|
357
|
+
updatedAt?: string;
|
|
358
|
+
connection?: RepoMeshPeerConnectionStatus;
|
|
274
359
|
error?: string;
|
|
275
360
|
}
|
|
361
|
+
|
|
362
|
+
export type RepoMeshQueueTaskStatus = 'pending' | 'assigned' | 'completed' | 'failed' | 'cancelled';
|
|
363
|
+
|
|
364
|
+
export interface RepoMeshQueueTask {
|
|
365
|
+
id: string;
|
|
366
|
+
meshId: string;
|
|
367
|
+
message: string;
|
|
368
|
+
status: RepoMeshQueueTaskStatus;
|
|
369
|
+
targetNodeId?: string;
|
|
370
|
+
targetSessionId?: string;
|
|
371
|
+
assignedNodeId?: string;
|
|
372
|
+
assignedSessionId?: string;
|
|
373
|
+
cancelReason?: string;
|
|
374
|
+
cancelledAt?: string;
|
|
375
|
+
requeueReason?: string;
|
|
376
|
+
requeuedAt?: string;
|
|
377
|
+
requeueCount?: number;
|
|
378
|
+
autoLaunch?: {
|
|
379
|
+
status: 'skipped' | 'started' | 'failed' | 'completed';
|
|
380
|
+
reason?: string;
|
|
381
|
+
nodeId?: string;
|
|
382
|
+
providerType?: string;
|
|
383
|
+
sessionId?: string;
|
|
384
|
+
updatedAt: string;
|
|
385
|
+
};
|
|
386
|
+
dispatchTimestamp?: string;
|
|
387
|
+
createdAt: string;
|
|
388
|
+
updatedAt: string;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export interface RepoMeshQueueSummary {
|
|
392
|
+
total: number;
|
|
393
|
+
active: number;
|
|
394
|
+
historical: number;
|
|
395
|
+
pending: number;
|
|
396
|
+
assigned: number;
|
|
397
|
+
completed: number;
|
|
398
|
+
failed: number;
|
|
399
|
+
cancelled: number;
|
|
400
|
+
activeCounts: {
|
|
401
|
+
pending: number;
|
|
402
|
+
assigned: number;
|
|
403
|
+
};
|
|
404
|
+
historicalCounts: {
|
|
405
|
+
completed: number;
|
|
406
|
+
failed: number;
|
|
407
|
+
cancelled: number;
|
|
408
|
+
};
|
|
409
|
+
activeAssignments: Array<{
|
|
410
|
+
id: string;
|
|
411
|
+
nodeId?: string;
|
|
412
|
+
sessionId?: string;
|
|
413
|
+
message: string;
|
|
414
|
+
}>;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export interface RepoMeshQueueStatus {
|
|
418
|
+
tasks: RepoMeshQueueTask[];
|
|
419
|
+
summary: RepoMeshQueueSummary;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export interface RepoMeshLedgerEntryStatus {
|
|
423
|
+
id: string;
|
|
424
|
+
meshId: string;
|
|
425
|
+
timestamp: string;
|
|
426
|
+
kind: string;
|
|
427
|
+
nodeId?: string;
|
|
428
|
+
sessionId?: string;
|
|
429
|
+
providerType?: string;
|
|
430
|
+
payload: Record<string, unknown>;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export interface RepoMeshLedgerSummaryStatus {
|
|
434
|
+
meshId: string;
|
|
435
|
+
totalEntries: number;
|
|
436
|
+
taskDispatched: number;
|
|
437
|
+
taskCompleted: number;
|
|
438
|
+
taskFailed: number;
|
|
439
|
+
taskStalled: number;
|
|
440
|
+
sessionLaunched: number;
|
|
441
|
+
checkpointCreated: number;
|
|
442
|
+
lastActivityAt: string | null;
|
|
443
|
+
recentFailures: number;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export interface RepoMeshLedgerStatus {
|
|
447
|
+
entries: RepoMeshLedgerEntryStatus[];
|
|
448
|
+
summary: RepoMeshLedgerSummaryStatus;
|
|
449
|
+
}
|
package/src/status/reporter.ts
CHANGED
|
@@ -51,6 +51,8 @@ export class DaemonStatusReporter {
|
|
|
51
51
|
private lastStatusSentAt = 0;
|
|
52
52
|
private statusPendingThrottle = false;
|
|
53
53
|
private lastP2PStatusHash = '';
|
|
54
|
+
private lastP2PStatusSentAt: number = 0;
|
|
55
|
+
private p2pDebounceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
54
56
|
private lastServerStatusHash = '';
|
|
55
57
|
private lastStatusSummary = '';
|
|
56
58
|
|
|
@@ -355,7 +357,20 @@ export class DaemonStatusReporter {
|
|
|
355
357
|
: { ...hashTarget, sessions };
|
|
356
358
|
const h = this.simpleHash(JSON.stringify(hashPayload));
|
|
357
359
|
if (h !== this.lastP2PStatusHash) {
|
|
360
|
+
const now = Date.now();
|
|
361
|
+
// Rate limit: max 1 per 500ms
|
|
362
|
+
if (this.lastP2PStatusSentAt && now - this.lastP2PStatusSentAt < 500) {
|
|
363
|
+
if (!this.p2pDebounceTimer) {
|
|
364
|
+
this.p2pDebounceTimer = setTimeout(() => {
|
|
365
|
+
this.p2pDebounceTimer = null;
|
|
366
|
+
this.sendUnifiedStatusReport({ reason: 'p2p_debounce' });
|
|
367
|
+
}, 500);
|
|
368
|
+
}
|
|
369
|
+
return false; // Dropped for now, but will trigger later
|
|
370
|
+
}
|
|
371
|
+
|
|
358
372
|
this.lastP2PStatusHash = h;
|
|
373
|
+
this.lastP2PStatusSentAt = now;
|
|
359
374
|
this.deps.p2p?.sendStatus(payload);
|
|
360
375
|
return true;
|
|
361
376
|
}
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import * as os from 'os';
|
|
14
|
-
import {
|
|
14
|
+
import { exec } from 'child_process';
|
|
15
|
+
import { promisify } from 'util';
|
|
16
|
+
|
|
17
|
+
const execAsync = promisify(exec);
|
|
15
18
|
|
|
16
19
|
export interface HostMemorySnapshot {
|
|
17
20
|
totalMem: number;
|
|
@@ -21,19 +24,22 @@ export interface HostMemorySnapshot {
|
|
|
21
24
|
availableMem: number;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
let cachedDarwinAvail: number | null = null;
|
|
28
|
+
let darwinMemoryInterval: NodeJS.Timeout | null = null;
|
|
29
|
+
|
|
30
|
+
async function updateDarwinMemoryCache() {
|
|
31
|
+
if (os.platform() !== 'darwin') return;
|
|
26
32
|
try {
|
|
27
|
-
const
|
|
33
|
+
const { stdout } = await execAsync('vm_stat', {
|
|
28
34
|
encoding: 'utf-8',
|
|
29
35
|
timeout: 4000,
|
|
30
36
|
maxBuffer: 256 * 1024,
|
|
31
37
|
});
|
|
32
|
-
const pageSizeMatch =
|
|
38
|
+
const pageSizeMatch = stdout.match(/page size of (\d+)\s*bytes/i);
|
|
33
39
|
const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : 4096;
|
|
34
40
|
|
|
35
41
|
const counts: Record<string, number> = {};
|
|
36
|
-
for (const line of
|
|
42
|
+
for (const line of stdout.split('\n')) {
|
|
37
43
|
const m = line.match(/^\s*Pages\s+([^:]+):\s+([\d,]+)\s*\.?/);
|
|
38
44
|
if (!m) continue;
|
|
39
45
|
const key = m[1].trim().toLowerCase().replace(/\s+/g, '_');
|
|
@@ -49,17 +55,28 @@ function parseDarwinAvailableBytes(totalMem: number): number | null {
|
|
|
49
55
|
|
|
50
56
|
const availPages = free + inactive + speculative + purgeable + fileBacked;
|
|
51
57
|
const bytes = availPages * pageSize;
|
|
52
|
-
|
|
53
|
-
return Math.min(bytes, totalMem);
|
|
58
|
+
cachedDarwinAvail = Number.isFinite(bytes) && bytes >= 0 ? Math.min(bytes, os.totalmem()) : null;
|
|
54
59
|
} catch {
|
|
55
|
-
|
|
60
|
+
// silently fallback
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
export function getHostMemorySnapshot(): HostMemorySnapshot {
|
|
65
|
+
if (os.platform() === 'darwin' && !darwinMemoryInterval) {
|
|
66
|
+
updateDarwinMemoryCache();
|
|
67
|
+
darwinMemoryInterval = setInterval(updateDarwinMemoryCache, 3000);
|
|
68
|
+
darwinMemoryInterval.unref();
|
|
69
|
+
}
|
|
70
|
+
|
|
60
71
|
const totalMem = os.totalmem();
|
|
61
72
|
const freeMem = os.freemem();
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
const availableMem = os.platform() === 'darwin'
|
|
74
|
+
? (cachedDarwinAvail ?? freeMem)
|
|
75
|
+
: freeMem;
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
totalMem,
|
|
79
|
+
freeMem,
|
|
80
|
+
availableMem,
|
|
81
|
+
};
|
|
65
82
|
}
|