@adhdev/daemon-core 0.9.82-rc.337 → 0.9.82-rc.339

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.
@@ -987,4 +987,13 @@ export interface ProviderControlDef {
987
987
  order?: number;
988
988
  /** Hide this control when condition not met */
989
989
  hidden?: boolean;
990
+ /**
991
+ * FSM state ids in which this control should be visible (mirrors the spec's
992
+ * `control_bar[].visible_when_state`). When omitted the control is always
993
+ * visible. The daemon enforces this on click (FsmDriver.handleClickControl),
994
+ * so the web bar must mirror the same gating to avoid showing a button that
995
+ * the daemon would silently drop. Uses raw FSM state ids (e.g. 'idle',
996
+ * 'busy'), not the derived dashboard status.
997
+ */
998
+ visibleWhenState?: string[];
990
999
  }
@@ -529,6 +529,13 @@ export interface ProviderControlSchema {
529
529
  order?: number;
530
530
  /** Hide this control even if it would otherwise render */
531
531
  hidden?: boolean;
532
+ /**
533
+ * FSM state ids in which this control should be visible. When omitted the
534
+ * control is always visible. Mirrors the daemon's click-time enforcement so
535
+ * the bar hides controls the daemon would silently drop. Uses raw FSM state
536
+ * ids (e.g. 'idle', 'busy'), not the derived dashboard status.
537
+ */
538
+ visibleWhenState?: string[];
532
539
  }
533
540
  /** Machine hardware/OS info (reported by daemon, displayed by web) */
534
541
  export interface MachineInfo {
@@ -65,6 +65,31 @@ export interface RecentReadDebugSnapshot {
65
65
  }
66
66
  export declare function shouldEmitRecentReadDebugLog(cache: Map<string, string>, snapshot: RecentReadDebugSnapshot): boolean;
67
67
  export declare function buildMachineInfo(profile?: 'full' | 'live' | 'metadata'): MachineInfo;
68
+ /**
69
+ * Resolve the last user-visible (non-system) message for a session as a preview.
70
+ *
71
+ * Exported so the cloud coordinator can derive a preview for a LOCAL mesh-owned
72
+ * worktree session directly from the real provider instance it hosts. A REMOTE
73
+ * worker session has no local instance (its preview rides the completion event's
74
+ * finalSummary — see resolveMeshSurfacedSessionPreview), but a LOCAL coordinator
75
+ * IS the worker, so its hosted instance's transcript holds the assistant reply and
76
+ * this is the source of truth for that case.
77
+ */
78
+ export declare function getLastDisplayMessage(session: {
79
+ activeChat?: {
80
+ messages?: Array<{
81
+ role?: string;
82
+ content?: unknown;
83
+ receivedAt?: number | string;
84
+ timestamp?: number | string;
85
+ }> | null;
86
+ } | null;
87
+ }): {
88
+ role: string;
89
+ preview: string;
90
+ receivedAt: number;
91
+ hash: string;
92
+ } | null;
68
93
  export { getSessionCurrentNotificationId, applySessionNotificationOverlay } from '../config/recent-activity.js';
69
94
  export declare function getSessionCompletionMarker(session: {
70
95
  activeChat?: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.82-rc.337",
3
+ "version": "0.9.82-rc.339",
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.337",
49
+ "@adhdev/mesh-shared": "0.9.82-rc.339",
50
50
  "@adhdev/session-host-core": "*",
51
51
  "@agentclientprotocol/sdk": "^0.16.1",
52
52
  "ajv": "^8.20.0",
package/src/index.ts CHANGED
@@ -320,7 +320,7 @@ export type {
320
320
  // ── Status ──
321
321
  export { DaemonStatusReporter } from './status/reporter.js';
322
322
  export { buildSessionEntries, findCdpManager, hasCdpManager, isCdpConnected } from './status/builders.js';
323
- export { buildStatusSnapshot, buildMachineInfo } from './status/snapshot.js';
323
+ export { buildStatusSnapshot, buildMachineInfo, getLastDisplayMessage } from './status/snapshot.js';
324
324
  export { getDaemonBuildInfo } from './build-info.js';
325
325
  export type { DaemonBuildInfo } from './build-info.js';
326
326
  export { normalizeManagedStatus, isManagedStatusWorking, isManagedStatusWaiting, normalizeActiveChatData } from './status/normalize.js';
@@ -1425,8 +1425,15 @@ export class CliProviderInstance implements ProviderInstance {
1425
1425
  chatTitle: pending.chatTitle,
1426
1426
  duration: pending.duration,
1427
1427
  timestamp: pending.timestamp,
1428
+ // When finalization is forced past the timeout on a `parsed_status:` block
1429
+ // (the parser never confirmed a final assistant turn) we previously rode an
1430
+ // empty `finalSummary` unconditionally. That empty value propagates to the
1431
+ // mesh coordinator's mirror preview (meshSessionLastMessagePreview), leaving a
1432
+ // delegated session's inbox preview blank — or, for a LOCAL worktree session,
1433
+ // stuck on the dispatched user task. If the parser DID surface assistant text,
1434
+ // prefer it; only fall back to '' when no assistant summary can be derived.
1428
1435
  finalSummary: blockReason.startsWith('parsed_status:')
1429
- ? ''
1436
+ ? (this.completionFinalSummary(this.adapter?.getScriptParsedStatus()?.messages) ?? '')
1430
1437
  : this.completionFinalSummary(this.adapter?.getScriptParsedStatus()?.messages),
1431
1438
  completionDiagnostic,
1432
1439
  });
@@ -1156,4 +1156,13 @@ export interface ProviderControlDef {
1156
1156
  order?: number;
1157
1157
  /** Hide this control when condition not met */
1158
1158
  hidden?: boolean;
1159
+ /**
1160
+ * FSM state ids in which this control should be visible (mirrors the spec's
1161
+ * `control_bar[].visible_when_state`). When omitted the control is always
1162
+ * visible. The daemon enforces this on click (FsmDriver.handleClickControl),
1163
+ * so the web bar must mirror the same gating to avoid showing a button that
1164
+ * the daemon would silently drop. Uses raw FSM state ids (e.g. 'idle',
1165
+ * 'busy'), not the derived dashboard status.
1166
+ */
1167
+ visibleWhenState?: string[];
1159
1168
  }
@@ -124,6 +124,12 @@ function synthesizeControlsFromControlBar(specControls: any[]): ProviderControlD
124
124
  const actionType = ctl?.action?.type;
125
125
  if (!id || !actionType) return;
126
126
  const label = typeof ctl?.label === 'string' && ctl.label.trim() ? ctl.label : id;
127
+ // Preserve the spec's state gating so the web bar can mirror the daemon's
128
+ // FsmDriver.handleClickControl enforcement (otherwise the button renders in
129
+ // states where the daemon would silently drop the click).
130
+ const visibleWhenState = Array.isArray(ctl?.visible_when_state)
131
+ ? ctl.visible_when_state.filter((s: unknown): s is string => typeof s === 'string')
132
+ : undefined;
127
133
  if (actionType === 'open_picker') {
128
134
  out.push({
129
135
  id,
@@ -135,6 +141,7 @@ function synthesizeControlsFromControlBar(specControls: any[]): ProviderControlD
135
141
  setScript: id,
136
142
  readFrom: id,
137
143
  order: index,
144
+ ...(visibleWhenState && visibleWhenState.length > 0 ? { visibleWhenState } : {}),
138
145
  });
139
146
  } else if (actionType === 'send_keys') {
140
147
  out.push({
@@ -145,6 +152,7 @@ function synthesizeControlsFromControlBar(specControls: any[]): ProviderControlD
145
152
  invokeScript: id,
146
153
  resultDisplay: 'none',
147
154
  order: index,
155
+ ...(visibleWhenState && visibleWhenState.length > 0 ? { visibleWhenState } : {}),
148
156
  });
149
157
  }
150
158
  // attach_image intentionally skipped — see fn doc.
@@ -635,6 +635,13 @@ export interface ProviderControlSchema {
635
635
  order?: number;
636
636
  /** Hide this control even if it would otherwise render */
637
637
  hidden?: boolean;
638
+ /**
639
+ * FSM state ids in which this control should be visible. When omitted the
640
+ * control is always visible. Mirrors the daemon's click-time enforcement so
641
+ * the bar hides controls the daemon would silently drop. Uses raw FSM state
642
+ * ids (e.g. 'idle', 'busy'), not the derived dashboard status.
643
+ */
644
+ visibleWhenState?: string[];
638
645
  }
639
646
 
640
647
  // ─── Common Sub-Types (used across StatusReportPayload, BaseDaemonData, etc.) ──
@@ -283,7 +283,17 @@ function simplePreviewHash(value: string): string {
283
283
  return h.toString(16);
284
284
  }
285
285
 
286
- function getLastDisplayMessage(session: {
286
+ /**
287
+ * Resolve the last user-visible (non-system) message for a session as a preview.
288
+ *
289
+ * Exported so the cloud coordinator can derive a preview for a LOCAL mesh-owned
290
+ * worktree session directly from the real provider instance it hosts. A REMOTE
291
+ * worker session has no local instance (its preview rides the completion event's
292
+ * finalSummary — see resolveMeshSurfacedSessionPreview), but a LOCAL coordinator
293
+ * IS the worker, so its hosted instance's transcript holds the assistant reply and
294
+ * this is the source of truth for that case.
295
+ */
296
+ export function getLastDisplayMessage(session: {
287
297
  activeChat?: {
288
298
  messages?: Array<{
289
299
  role?: string;