@adhdev/daemon-core 0.9.82-rc.541 → 0.9.82-rc.543
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/commands/router.d.ts +15 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +52 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +48 -9
- package/dist/index.mjs.map +1 -1
- package/dist/status/builders.d.ts +43 -0
- package/package.json +3 -3
- package/src/commands/router.ts +25 -1
- package/src/index.ts +1 -1
- package/src/providers/sdk/v1/builders/cli/detect-status.ts +19 -6
- package/src/status/builders.ts +37 -7
|
@@ -11,6 +11,49 @@ import type { DaemonCdpManager } from '../cdp/manager.js';
|
|
|
11
11
|
import type { GitCompactSummary } from '../git/git-types.js';
|
|
12
12
|
import type { SessionEntry } from '../shared-types.js';
|
|
13
13
|
import type { ProviderState } from '../providers/provider-instance.js';
|
|
14
|
+
/**
|
|
15
|
+
* A coordinator-spawned worker session that mesh policy launched hidden. This is
|
|
16
|
+
* the daemon-side equivalent of the web `shouldAutoHideMeshConversation` predicate:
|
|
17
|
+
* these sessions should default to muted+hidden in the user dashboard (the user
|
|
18
|
+
* interacts through the ONE coordinator session, not each worker), while the
|
|
19
|
+
* coordinator↔worker mesh data/completion path (mesh-event-forwarding) is
|
|
20
|
+
* unaffected.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isCoordinatorSpawnedHiddenWorker(settings: Record<string, any> | undefined): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* A session is surface-hidden (collapsed from the user's inbox/notifications) when
|
|
25
|
+
* mesh policy spawned it hidden, OR when a coordinator-spawned worker defaults
|
|
26
|
+
* hidden, OR when the user manually hid it (userHidden). userHidden === false is an
|
|
27
|
+
* explicit un-hide that overrides the policy/worker default until daemon restart.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveSurfaceHidden(settings: Record<string, any> | undefined): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* A session is muted (attention side-effects suppressed, but still shown in the
|
|
32
|
+
* list) when the user muted it, OR a coordinator-spawned worker defaults muted.
|
|
33
|
+
* userMuted === false is an explicit un-mute overriding the worker default.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolveMuted(settings: Record<string, any> | undefined): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Pure resolver for a mesh-spawned worker session's dashboard hide+mute state,
|
|
38
|
+
* shared by the standalone/local `buildSessionEntries` path (via the wrappers
|
|
39
|
+
* above, which read the values off a full settings object) AND the cloud daemon's
|
|
40
|
+
* synthetic remote-mesh-session mirror path in daemon-cloud
|
|
41
|
+
* (`appendMeshOwnedSessionsToSnapshot`), which has no full ProviderState — only
|
|
42
|
+
* the mesh attribution fields. Keeping both paths on this ONE helper guarantees a
|
|
43
|
+
* remote worker surfaced on the cloud dashboard hides+mutes identically to a local
|
|
44
|
+
* worker on standalone. A valid `userHidden`/`userMuted` boolean is an explicit
|
|
45
|
+
* per-session override and wins over the policy/worker default.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveSpawnedSessionHideMute(input: {
|
|
48
|
+
launchedByCoordinator?: unknown;
|
|
49
|
+
meshNodeFor?: unknown;
|
|
50
|
+
spawnedSessionVisibility?: unknown;
|
|
51
|
+
userHidden?: unknown;
|
|
52
|
+
userMuted?: unknown;
|
|
53
|
+
}): {
|
|
54
|
+
surfaceHidden: boolean;
|
|
55
|
+
muted: boolean;
|
|
56
|
+
};
|
|
14
57
|
export type SessionEntryProfile = 'full' | 'live' | 'metadata';
|
|
15
58
|
export interface SessionEntryBuildOptions {
|
|
16
59
|
profile?: SessionEntryProfile;
|
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.543",
|
|
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",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"author": "vilmire",
|
|
48
48
|
"license": "AGPL-3.0-or-later",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@adhdev/mesh-shared": "0.9.82-rc.
|
|
51
|
-
"@adhdev/session-host-core": "0.9.82-rc.
|
|
50
|
+
"@adhdev/mesh-shared": "0.9.82-rc.543",
|
|
51
|
+
"@adhdev/session-host-core": "0.9.82-rc.543",
|
|
52
52
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
53
53
|
"ajv": "^8.20.0",
|
|
54
54
|
"ajv-formats": "^3.0.1",
|
package/src/commands/router.ts
CHANGED
|
@@ -34,7 +34,7 @@ import { buildMeshHostRequiredFailure, resolveMeshHostStatus } from '../mesh/mes
|
|
|
34
34
|
import { analyzeMeshRefineNodeChangeArea, orderMeshRefineBatchNodes } from '../mesh/mesh-refine-batch.js';
|
|
35
35
|
import type { WorktreeBootstrapState } from '../mesh/worktree-bootstrap-config.js';
|
|
36
36
|
import { getMeshQueueRevision } from '../mesh/mesh-work-queue.js';
|
|
37
|
-
import type { RepoMeshSessionCleanupMode } from '../repo-mesh-types.js';
|
|
37
|
+
import type { RepoMeshSessionCleanupMode, RepoMeshSpawnedSessionVisibility } from '../repo-mesh-types.js';
|
|
38
38
|
import { DEFAULT_MESH_POLICY, magiAutoLaunchedSessionCleanupDecision } from '../repo-mesh-types.js';
|
|
39
39
|
import { resolve as pathResolve } from 'path';
|
|
40
40
|
import * as fs from 'fs';
|
|
@@ -362,6 +362,30 @@ export class DaemonCommandRouter {
|
|
|
362
362
|
return nodes;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
/**
|
|
366
|
+
* Same flattened node list as getCachedInlineMeshNodes(), but each node is
|
|
367
|
+
* paired with the `spawnedSessionVisibility` from its OWNING mesh's policy.
|
|
368
|
+
* The flat node list loses the mesh→node association, yet the cloud daemon's
|
|
369
|
+
* synthetic mesh-session mirror needs the mesh-level visibility policy to
|
|
370
|
+
* decide whether a coordinator-spawned worker session should be hidden+muted
|
|
371
|
+
* on the dashboard (the cached inline-mesh session entry carries no settings
|
|
372
|
+
* of its own). Falls back to DEFAULT_MESH_POLICY.spawnedSessionVisibility when
|
|
373
|
+
* the mesh policy is absent, matching the worker-launch stamp.
|
|
374
|
+
*/
|
|
375
|
+
public getCachedInlineMeshNodesWithVisibility(): Array<{ node: any; spawnedSessionVisibility: RepoMeshSpawnedSessionVisibility }> {
|
|
376
|
+
const out: Array<{ node: any; spawnedSessionVisibility: RepoMeshSpawnedSessionVisibility }> = [];
|
|
377
|
+
for (const mesh of this.inlineMeshCache.values()) {
|
|
378
|
+
const spawnedSessionVisibility: RepoMeshSpawnedSessionVisibility =
|
|
379
|
+
mesh?.policy?.spawnedSessionVisibility === 'visible' ? 'visible' : 'hidden';
|
|
380
|
+
if (Array.isArray(mesh?.nodes)) {
|
|
381
|
+
for (const node of mesh.nodes) {
|
|
382
|
+
out.push({ node, spawnedSessionVisibility });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
return out;
|
|
387
|
+
}
|
|
388
|
+
|
|
365
389
|
// ─── Remote mesh-session owner resolution ───────────────────────────
|
|
366
390
|
// Implementation lives in ./router-mesh-session-owner.ts (behavior-preserving
|
|
367
391
|
// code move). resolveRemoteMeshSessionOwnerDaemonId stays public (the [Z]
|
package/src/index.ts
CHANGED
|
@@ -384,7 +384,7 @@ export type {
|
|
|
384
384
|
|
|
385
385
|
// ── Status ──
|
|
386
386
|
export { DaemonStatusReporter } from './status/reporter.js';
|
|
387
|
-
export { buildSessionEntries, findCdpManager, hasCdpManager, isCdpConnected } from './status/builders.js';
|
|
387
|
+
export { buildSessionEntries, findCdpManager, hasCdpManager, isCdpConnected, isCoordinatorSpawnedHiddenWorker, resolveSurfaceHidden, resolveMuted, resolveSpawnedSessionHideMute } from './status/builders.js';
|
|
388
388
|
export { buildStatusSnapshot, buildMachineInfo, buildAvailableProviders, getLastDisplayMessage } from './status/snapshot.js';
|
|
389
389
|
export { getDaemonBuildInfo } from './build-info.js';
|
|
390
390
|
export type { DaemonBuildInfo } from './build-info.js';
|
|
@@ -301,11 +301,19 @@ function modalSupersededBySettledPrompt(
|
|
|
301
301
|
if (settled.footers.length > 0 && !settled.footers.every((f) => f.test(belowText))) return false;
|
|
302
302
|
// Require a real separator between the leftover box and the composer: a
|
|
303
303
|
// non-blank line that is neither a modal cue NOR part of the settled-prompt
|
|
304
|
-
// match itself
|
|
305
|
-
//
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
//
|
|
304
|
+
// match itself (its bare-prompt line OR one of its declared footer lines).
|
|
305
|
+
// That separator is the CLI's welcome banner / follow-up hint a stale box
|
|
306
|
+
// shows above the repainted composer. A live modal's selection cursor sits
|
|
307
|
+
// flush against its buttons with no such prose between them (and neither the
|
|
308
|
+
// cursor line nor the composer's own footer — e.g. claude's "? for shortcuts"
|
|
309
|
+
// — is a separator), so an active modal is never misread as stale.
|
|
310
|
+
//
|
|
311
|
+
// Footer exclusion is load-bearing: without it, a live approval modal whose
|
|
312
|
+
// frame also carries the settled composer's footer (question + buttons +
|
|
313
|
+
// "? for shortcuts" + "❯") gets misread as a stale box — the footer line
|
|
314
|
+
// counts as fake "separator prose" — and waiting_approval flips to idle, so
|
|
315
|
+
// the modal is missed and the worker wedges. The footer belongs to the
|
|
316
|
+
// composer, not to any leftover box.
|
|
309
317
|
const question = compile(modalSpec.questionPattern, modalSpec.questionFlags ?? 'i');
|
|
310
318
|
const variants = (modalSpec.questionVariants ?? []).map((v) => compile(v.regex, v.flags ?? 'i'));
|
|
311
319
|
const buttonFlags = modalSpec.buttonFlags && modalSpec.buttonFlags.includes('m')
|
|
@@ -324,7 +332,12 @@ function modalSupersededBySettledPrompt(
|
|
|
324
332
|
const settledPromptLineRe = compile(settledSpec.regex, (settledSpec.flags ?? 'm').includes('m') ? (settledSpec.flags ?? 'm') : `${settledSpec.flags ?? ''}m`);
|
|
325
333
|
const isSettledLine = (line: string): boolean => {
|
|
326
334
|
settledPromptLineRe.lastIndex = 0;
|
|
327
|
-
|
|
335
|
+
if (settledPromptLineRe.test(line)) return true;
|
|
336
|
+
// The composer's own declared footer (e.g. claude's "? for shortcuts") is
|
|
337
|
+
// part of the settled prompt block, not separator prose. Excluding it keeps
|
|
338
|
+
// a live approval modal that also renders the composer footer from being
|
|
339
|
+
// misread as a stale box.
|
|
340
|
+
return settled.footers.some((f) => f.test(line));
|
|
328
341
|
};
|
|
329
342
|
return below.some((line) => line.trim() !== '' && !isModalCueLine(line) && !isSettledLine(line));
|
|
330
343
|
}
|
package/src/status/builders.ts
CHANGED
|
@@ -42,7 +42,7 @@ import { TEXT_ONLY_MESSAGE_INPUT_SUPPORT } from '../providers/provider-input-sup
|
|
|
42
42
|
* coordinator↔worker mesh data/completion path (mesh-event-forwarding) is
|
|
43
43
|
* unaffected.
|
|
44
44
|
*/
|
|
45
|
-
function isCoordinatorSpawnedHiddenWorker(settings: Record<string, any> | undefined): boolean {
|
|
45
|
+
export function isCoordinatorSpawnedHiddenWorker(settings: Record<string, any> | undefined): boolean {
|
|
46
46
|
if (!settings) return false;
|
|
47
47
|
return settings.launchedByCoordinator === true
|
|
48
48
|
&& typeof settings.meshNodeFor === 'string'
|
|
@@ -56,7 +56,7 @@ function isCoordinatorSpawnedHiddenWorker(settings: Record<string, any> | undefi
|
|
|
56
56
|
* hidden, OR when the user manually hid it (userHidden). userHidden === false is an
|
|
57
57
|
* explicit un-hide that overrides the policy/worker default until daemon restart.
|
|
58
58
|
*/
|
|
59
|
-
function resolveSurfaceHidden(settings: Record<string, any> | undefined): boolean {
|
|
59
|
+
export function resolveSurfaceHidden(settings: Record<string, any> | undefined): boolean {
|
|
60
60
|
if (!settings) return false;
|
|
61
61
|
if (settings.userHidden === true) return true;
|
|
62
62
|
if (settings.userHidden === false) return false;
|
|
@@ -68,13 +68,37 @@ function resolveSurfaceHidden(settings: Record<string, any> | undefined): boolea
|
|
|
68
68
|
* list) when the user muted it, OR a coordinator-spawned worker defaults muted.
|
|
69
69
|
* userMuted === false is an explicit un-mute overriding the worker default.
|
|
70
70
|
*/
|
|
71
|
-
function resolveMuted(settings: Record<string, any> | undefined): boolean {
|
|
71
|
+
export function resolveMuted(settings: Record<string, any> | undefined): boolean {
|
|
72
72
|
if (!settings) return false;
|
|
73
73
|
if (settings.userMuted === true) return true;
|
|
74
74
|
if (settings.userMuted === false) return false;
|
|
75
75
|
return isCoordinatorSpawnedHiddenWorker(settings);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Pure resolver for a mesh-spawned worker session's dashboard hide+mute state,
|
|
80
|
+
* shared by the standalone/local `buildSessionEntries` path (via the wrappers
|
|
81
|
+
* above, which read the values off a full settings object) AND the cloud daemon's
|
|
82
|
+
* synthetic remote-mesh-session mirror path in daemon-cloud
|
|
83
|
+
* (`appendMeshOwnedSessionsToSnapshot`), which has no full ProviderState — only
|
|
84
|
+
* the mesh attribution fields. Keeping both paths on this ONE helper guarantees a
|
|
85
|
+
* remote worker surfaced on the cloud dashboard hides+mutes identically to a local
|
|
86
|
+
* worker on standalone. A valid `userHidden`/`userMuted` boolean is an explicit
|
|
87
|
+
* per-session override and wins over the policy/worker default.
|
|
88
|
+
*/
|
|
89
|
+
export function resolveSpawnedSessionHideMute(input: {
|
|
90
|
+
launchedByCoordinator?: unknown;
|
|
91
|
+
meshNodeFor?: unknown;
|
|
92
|
+
spawnedSessionVisibility?: unknown;
|
|
93
|
+
userHidden?: unknown;
|
|
94
|
+
userMuted?: unknown;
|
|
95
|
+
}): { surfaceHidden: boolean; muted: boolean } {
|
|
96
|
+
return {
|
|
97
|
+
surfaceHidden: resolveSurfaceHidden(input as Record<string, any>),
|
|
98
|
+
muted: resolveMuted(input as Record<string, any>),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
78
102
|
export type SessionEntryProfile = 'full' | 'live' | 'metadata';
|
|
79
103
|
|
|
80
104
|
export interface SessionEntryBuildOptions {
|
|
@@ -383,8 +407,12 @@ function buildCliSession(state: CliProviderState, options: SessionEntryBuildOpti
|
|
|
383
407
|
settings: state.settings,
|
|
384
408
|
...(coordinator && { coordinator }),
|
|
385
409
|
...(meshQueueStats && { meshQueueStats }),
|
|
386
|
-
|
|
387
|
-
|
|
410
|
+
// Emit these booleans explicitly (including false) so an un-hide/un-mute clears a
|
|
411
|
+
// previously-true value downstream. Consumers merge with `?? existing` and copy only
|
|
412
|
+
// `!== undefined` fields, so an absent field on false never overwrote a prior true —
|
|
413
|
+
// the toggle-off direction silently stuck. See session-entry-merge.ts.
|
|
414
|
+
surfaceHidden: resolveSurfaceHidden(state.settings),
|
|
415
|
+
muted: resolveMuted(state.settings),
|
|
388
416
|
};
|
|
389
417
|
}
|
|
390
418
|
|
|
@@ -426,8 +454,10 @@ function buildAcpSession(state: AcpProviderState, options: SessionEntryBuildOpti
|
|
|
426
454
|
settings: state.settings,
|
|
427
455
|
...(coordinator && { coordinator }),
|
|
428
456
|
...(meshQueueStats && { meshQueueStats }),
|
|
429
|
-
|
|
430
|
-
|
|
457
|
+
// Emit explicitly (including false) so un-hide/un-mute clears a prior true downstream —
|
|
458
|
+
// see buildCliSession above and session-entry-merge.ts.
|
|
459
|
+
surfaceHidden: resolveSurfaceHidden(state.settings),
|
|
460
|
+
muted: resolveMuted(state.settings),
|
|
431
461
|
};
|
|
432
462
|
}
|
|
433
463
|
|