@adhdev/daemon-core 0.9.74 → 0.9.75

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/session-host-core",
3
- "version": "0.9.74",
3
+ "version": "0.9.75",
4
4
  "description": "ADHDev local session host core \u2014 session registry, protocol, buffers",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.74",
3
+ "version": "0.9.75",
4
4
  "description": "ADHDev daemon core \u2014 CDP, IDE detection, providers, command execution",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -262,6 +262,17 @@ export class ProviderCliAdapter implements CliAdapter {
262
262
  return screenText;
263
263
  }
264
264
 
265
+ private getParseScreenText(screenText: string): string {
266
+ const currentSnapshot = normalizeScreenSnapshot(screenText);
267
+ const lastSnapshot = this.lastScreenSnapshot;
268
+ if (!lastSnapshot || lastSnapshot === currentSnapshot) return screenText;
269
+ // Terminal screen reads can miss a just-rendered completed Hermes box while
270
+ // the normalized snapshot captured during output still has it. Feed both
271
+ // views to provider parsers so flattened snapshot-only final bubbles do
272
+ // not disappear from read_chat/chat_tail.
273
+ return `${screenText}\n${lastSnapshot}`;
274
+ }
275
+
265
276
  private shouldReadTerminalScreenSnapshot(now: number): boolean {
266
277
  if (!this.lastScreenText) return true;
267
278
  return (now - this.lastScreenSnapshotReadAt) >= ProviderCliAdapter.SCREEN_SNAPSHOT_MIN_INTERVAL_MS;
@@ -1424,12 +1435,13 @@ export class ProviderCliAdapter implements CliAdapter {
1424
1435
  }
1425
1436
  try {
1426
1437
  const screenText = this.terminalScreen.getText();
1438
+ const parseScreenText = this.getParseScreenText(screenText);
1427
1439
  const tail = this.recentOutputBuffer.slice(-500);
1428
1440
  const input = buildCliParseInput({
1429
1441
  accumulatedBuffer: this.accumulatedBuffer,
1430
1442
  accumulatedRawBuffer: this.accumulatedRawBuffer,
1431
1443
  recentOutputBuffer: this.recentOutputBuffer,
1432
- terminalScreenText: screenText,
1444
+ terminalScreenText: parseScreenText,
1433
1445
  baseMessages: [],
1434
1446
  partialResponse: this.responseBuffer,
1435
1447
  isWaitingForResponse: this.isWaitingForResponse,
@@ -1534,6 +1546,7 @@ export class ProviderCliAdapter implements CliAdapter {
1534
1546
  */
1535
1547
  getScriptParsedStatus(): any {
1536
1548
  const screenText = this.readTerminalScreenText();
1549
+ const parseScreenText = this.getParseScreenText(screenText);
1537
1550
  const cached = this.parsedStatusCache;
1538
1551
  if (
1539
1552
  cached
@@ -1541,7 +1554,7 @@ export class ProviderCliAdapter implements CliAdapter {
1541
1554
  && cached.currentTurnScope === this.currentTurnScope
1542
1555
  && cached.recentOutputBuffer === this.recentOutputBuffer
1543
1556
  && cached.accumulatedBuffer === this.accumulatedBuffer
1544
- && cached.screenText === screenText
1557
+ && cached.screenText === parseScreenText
1545
1558
  && cached.currentStatus === this.currentStatus
1546
1559
  && cached.activeModal === this.activeModal
1547
1560
  && cached.cliName === this.cliName
@@ -1580,7 +1593,7 @@ export class ProviderCliAdapter implements CliAdapter {
1580
1593
  currentTurnScope: this.currentTurnScope,
1581
1594
  recentOutputBuffer: this.recentOutputBuffer,
1582
1595
  accumulatedBuffer: this.accumulatedBuffer,
1583
- screenText,
1596
+ screenText: parseScreenText,
1584
1597
  currentStatus: this.currentStatus,
1585
1598
  activeModal: this.activeModal,
1586
1599
  cliName: this.cliName,
@@ -1598,7 +1611,7 @@ export class ProviderCliAdapter implements CliAdapter {
1598
1611
  accumulatedBuffer: this.accumulatedBuffer,
1599
1612
  accumulatedRawBuffer: this.accumulatedRawBuffer,
1600
1613
  recentOutputBuffer: this.recentOutputBuffer,
1601
- terminalScreenText: this.terminalScreen.getText(),
1614
+ terminalScreenText: this.getParseScreenText(this.terminalScreen.getText()),
1602
1615
  baseMessages: [],
1603
1616
  partialResponse: this.responseBuffer,
1604
1617
  isWaitingForResponse: this.isWaitingForResponse,
@@ -149,6 +149,11 @@ function resolveAdhdevMcpEntryPath(explicitPath?: string): string | null {
149
149
  addCandidate(resolve(dir, '../vendor/mcp-server/index.js'))
150
150
  addCandidate(resolve(dir, '../../vendor/mcp-server/index.js'))
151
151
  addCandidate(resolve(dir, '../../../vendor/mcp-server/index.js'))
152
+ // Source checkout/dev mode does not vendor the MCP server into daemon-standalone.
153
+ // Resolve the sibling workspace build directly so Repo Mesh auto-import still
154
+ // writes an absolute Node entrypoint instead of falling back to a PATH bin shim.
155
+ addCandidate(resolve(dir, '../../mcp-server/dist/index.js'))
156
+ addCandidate(resolve(dir, '../../../mcp-server/dist/index.js'))
152
157
  }
153
158
 
154
159
  addPackagedCandidates(process.argv[1])
@@ -38,6 +38,25 @@ import { buildSessionEntries } from '../status/builders.js';
38
38
  import { buildMachineInfo, buildStatusSnapshot } from '../status/snapshot.js';
39
39
  import { getSessionCompletionMarker } from '../status/snapshot.js';
40
40
  import { execNpmCommandSync, resolveCurrentGlobalInstallSurface, spawnDetachedDaemonUpgradeHelper } from './upgrade-helper.js';
41
+
42
+ type ReleaseChannel = 'stable' | 'preview';
43
+ const CHANNEL_NPM_TAG: Record<ReleaseChannel, 'latest' | 'next'> = { stable: 'latest', preview: 'next' };
44
+
45
+ function normalizeReleaseChannel(value: unknown): ReleaseChannel | null {
46
+ if (typeof value !== 'string') return null;
47
+ const normalized = value.trim().toLowerCase();
48
+ if (normalized === 'stable' || normalized === 'latest') return 'stable';
49
+ if (normalized === 'preview' || normalized === 'next') return 'preview';
50
+ return null;
51
+ }
52
+
53
+ function resolveUpgradeChannel(args: any): ReleaseChannel {
54
+ return normalizeReleaseChannel(args?.channel)
55
+ || normalizeReleaseChannel(args?.updatePolicy?.channel)
56
+ || normalizeReleaseChannel(args?.npmTag)
57
+ || normalizeReleaseChannel(loadConfig().updateChannel)
58
+ || 'stable';
59
+ }
41
60
  import * as fs from 'fs';
42
61
 
43
62
  // ─── Types ───
@@ -867,10 +886,12 @@ export class DaemonCommandRouter {
867
886
  || process.argv[1]?.includes('daemon-standalone');
868
887
  const pkgName = isStandalone ? '@adhdev/daemon-standalone' : 'adhdev';
869
888
  const npmSurface = resolveCurrentGlobalInstallSurface({ packageName: pkgName });
889
+ const channel = resolveUpgradeChannel(args);
890
+ const npmTag = CHANNEL_NPM_TAG[channel];
870
891
 
871
- // Check latest version
872
- const latest = String(execNpmCommandSync(['view', pkgName, 'version'], { encoding: 'utf-8', timeout: 10000 }, npmSurface)).trim();
873
- LOG.info('Upgrade', `Latest ${pkgName}: v${latest}`);
892
+ // Check channel-pinned dist-tag and resolve it to a concrete install version.
893
+ const latest = String(execNpmCommandSync(['view', `${pkgName}@${npmTag}`, 'version'], { encoding: 'utf-8', timeout: 10000 }, npmSurface)).trim();
894
+ LOG.info('Upgrade', `Latest ${pkgName}@${npmTag}: v${latest}`);
874
895
  let currentInstalled: string | null = null;
875
896
  try {
876
897
  const currentJson = String(execNpmCommandSync(['ls', '-g', pkgName, '--depth=0', '--json'], {
@@ -888,8 +909,8 @@ export class DaemonCommandRouter {
888
909
  ? this.deps.statusVersion.trim().replace(/^v/, '')
889
910
  : null;
890
911
  if (currentInstalled === latest && runningVersion === latest) {
891
- LOG.info('Upgrade', `Already on latest version v${latest}; skipping install`);
892
- return { success: true, upgraded: false, alreadyLatest: true, version: latest };
912
+ LOG.info('Upgrade', `Already on ${channel} channel version v${latest}; skipping install`);
913
+ return { success: true, upgraded: false, alreadyLatest: true, version: latest, channel, npmTag };
893
914
  }
894
915
  if (currentInstalled === latest && runningVersion && runningVersion !== latest) {
895
916
  LOG.info('Upgrade', `Installed package is v${latest}, but running daemon is v${runningVersion}; scheduling restart`);
@@ -903,7 +924,7 @@ export class DaemonCommandRouter {
903
924
  cwd: process.cwd(),
904
925
  sessionHostAppName: process.env.ADHDEV_SESSION_HOST_NAME || 'adhdev',
905
926
  });
906
- LOG.info('Upgrade', `Scheduled detached upgrade to v${latest}`);
927
+ LOG.info('Upgrade', `Scheduled detached ${channel} upgrade to v${latest}`);
907
928
 
908
929
  // Exit after the command response has been sent so the helper can replace the package cleanly.
909
930
  setTimeout(() => {
@@ -911,7 +932,7 @@ export class DaemonCommandRouter {
911
932
  process.exit(0);
912
933
  }, 3000);
913
934
 
914
- return { success: true, upgraded: true, version: latest, restarting: true };
935
+ return { success: true, upgraded: true, version: latest, restarting: true, channel, npmTag };
915
936
  } catch (e: any) {
916
937
  LOG.error('Upgrade', `Failed: ${e.message}`);
917
938
  return { success: false, error: e.message };
@@ -1101,14 +1122,22 @@ export class DaemonCommandRouter {
1101
1122
  }
1102
1123
 
1103
1124
  // Merge ADHDev mesh server into existing config.
1125
+ // Pass full mesh data as env var so the MCP server can bootstrap
1126
+ // without depending on meshes.json or a running daemon.
1127
+ const mcpServerEntry: Record<string, any> = {
1128
+ command: coordinatorSetup.mcpServer.command,
1129
+ args: coordinatorSetup.mcpServer.args,
1130
+ };
1131
+ if (args?.inlineMesh) {
1132
+ mcpServerEntry.env = {
1133
+ ADHDEV_INLINE_MESH: JSON.stringify(mesh),
1134
+ };
1135
+ }
1104
1136
  const mcpConfig = {
1105
1137
  ...existingMcpConfig,
1106
1138
  mcpServers: {
1107
1139
  ...(existingMcpConfig.mcpServers || {}),
1108
- [coordinatorSetup.serverName]: {
1109
- command: coordinatorSetup.mcpServer.command,
1110
- args: coordinatorSetup.mcpServer.args,
1111
- },
1140
+ [coordinatorSetup.serverName]: mcpServerEntry,
1112
1141
  },
1113
1142
  };
1114
1143
  writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), 'utf-8');
@@ -15,6 +15,7 @@ export type { SavedProviderSessionEntry } from './saved-sessions.js';
15
15
  export type { DaemonState } from './state-store.js';
16
16
 
17
17
  export type ProviderSourceMode = 'normal' | 'no-upstream';
18
+ export type ReleaseChannel = 'stable' | 'preview';
18
19
 
19
20
  export function resolveProviderSourceMode(
20
21
  providerSourceMode: unknown,
@@ -122,6 +123,9 @@ export interface ADHDevConfig {
122
123
  // Optional explicit provider override root (for example a local adhdev-providers checkout)
123
124
  providerDir?: string;
124
125
 
126
+ /** Preferred daemon update channel. Defaults to stable/latest. */
127
+ updateChannel?: ReleaseChannel;
128
+
125
129
  /**
126
130
  * Browser terminal sizing behavior for dashboard CLI panes.
127
131
  * Default `measured` keeps terminal size daemon-authoritative.
@@ -151,6 +155,7 @@ const DEFAULT_CONFIG: ADHDevConfig = {
151
155
  machineProviders: {},
152
156
  ideSettings: {},
153
157
  providerSourceMode: 'normal',
158
+ updateChannel: 'stable',
154
159
  terminalSizingMode: 'measured',
155
160
  };
156
161
 
@@ -228,6 +233,7 @@ function normalizeConfig(raw: unknown): ADHDevConfig & { activeWorkspaceId?: str
228
233
  ideSettings: isPlainObject(parsed.ideSettings) ? parsed.ideSettings : {},
229
234
  providerSourceMode: resolveProviderSourceMode(parsed.providerSourceMode, parsed.disableUpstream),
230
235
  providerDir: asOptionalString(parsed.providerDir),
236
+ updateChannel: parsed.updateChannel === 'preview' ? 'preview' : 'stable',
231
237
  terminalSizingMode: parsed.terminalSizingMode === 'fit' ? 'fit' : 'measured',
232
238
  };
233
239
  }