@adhdev/daemon-core 0.9.73 → 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.
- package/dist/cli-adapters/provider-cli-adapter.d.ts +1 -0
- package/dist/commands/router.d.ts +4 -0
- package/dist/config/config.d.ts +3 -0
- package/dist/index.js +56 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +56 -18
- package/dist/index.mjs.map +1 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +17 -4
- package/src/commands/mesh-coordinator.ts +5 -0
- package/src/commands/router.ts +52 -16
- package/src/config/config.ts +6 -0
package/package.json
CHANGED
|
@@ -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:
|
|
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 ===
|
|
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])
|
package/src/commands/router.ts
CHANGED
|
@@ -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 ───
|
|
@@ -194,6 +213,10 @@ function summarizeSessionHostPruneResult(result: unknown): Record<string, unknow
|
|
|
194
213
|
|
|
195
214
|
export class DaemonCommandRouter {
|
|
196
215
|
private deps: CommandRouterDeps;
|
|
216
|
+
/** In-memory cache for cloud-originating meshes passed via inlineMesh.
|
|
217
|
+
* Allows the MCP server to query mesh data via get_mesh even when
|
|
218
|
+
* the mesh doesn't exist in the local meshes.json file. */
|
|
219
|
+
private inlineMeshCache = new Map<string, any>();
|
|
197
220
|
|
|
198
221
|
constructor(deps: CommandRouterDeps) {
|
|
199
222
|
this.deps = deps;
|
|
@@ -863,10 +886,12 @@ export class DaemonCommandRouter {
|
|
|
863
886
|
|| process.argv[1]?.includes('daemon-standalone');
|
|
864
887
|
const pkgName = isStandalone ? '@adhdev/daemon-standalone' : 'adhdev';
|
|
865
888
|
const npmSurface = resolveCurrentGlobalInstallSurface({ packageName: pkgName });
|
|
889
|
+
const channel = resolveUpgradeChannel(args);
|
|
890
|
+
const npmTag = CHANNEL_NPM_TAG[channel];
|
|
866
891
|
|
|
867
|
-
// Check
|
|
868
|
-
const latest = String(execNpmCommandSync(['view', pkgName
|
|
869
|
-
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}`);
|
|
870
895
|
let currentInstalled: string | null = null;
|
|
871
896
|
try {
|
|
872
897
|
const currentJson = String(execNpmCommandSync(['ls', '-g', pkgName, '--depth=0', '--json'], {
|
|
@@ -884,8 +909,8 @@ export class DaemonCommandRouter {
|
|
|
884
909
|
? this.deps.statusVersion.trim().replace(/^v/, '')
|
|
885
910
|
: null;
|
|
886
911
|
if (currentInstalled === latest && runningVersion === latest) {
|
|
887
|
-
LOG.info('Upgrade', `Already on
|
|
888
|
-
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 };
|
|
889
914
|
}
|
|
890
915
|
if (currentInstalled === latest && runningVersion && runningVersion !== latest) {
|
|
891
916
|
LOG.info('Upgrade', `Installed package is v${latest}, but running daemon is v${runningVersion}; scheduling restart`);
|
|
@@ -899,7 +924,7 @@ export class DaemonCommandRouter {
|
|
|
899
924
|
cwd: process.cwd(),
|
|
900
925
|
sessionHostAppName: process.env.ADHDEV_SESSION_HOST_NAME || 'adhdev',
|
|
901
926
|
});
|
|
902
|
-
LOG.info('Upgrade', `Scheduled detached upgrade to v${latest}`);
|
|
927
|
+
LOG.info('Upgrade', `Scheduled detached ${channel} upgrade to v${latest}`);
|
|
903
928
|
|
|
904
929
|
// Exit after the command response has been sent so the helper can replace the package cleanly.
|
|
905
930
|
setTimeout(() => {
|
|
@@ -907,7 +932,7 @@ export class DaemonCommandRouter {
|
|
|
907
932
|
process.exit(0);
|
|
908
933
|
}, 3000);
|
|
909
934
|
|
|
910
|
-
return { success: true, upgraded: true, version: latest, restarting: true };
|
|
935
|
+
return { success: true, upgraded: true, version: latest, restarting: true, channel, npmTag };
|
|
911
936
|
} catch (e: any) {
|
|
912
937
|
LOG.error('Upgrade', `Failed: ${e.message}`);
|
|
913
938
|
return { success: false, error: e.message };
|
|
@@ -937,11 +962,12 @@ export class DaemonCommandRouter {
|
|
|
937
962
|
try {
|
|
938
963
|
const { getMesh } = await import('../config/mesh-config.js');
|
|
939
964
|
const mesh = getMesh(meshId);
|
|
940
|
-
if (
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
}
|
|
965
|
+
if (mesh) return { success: true, mesh };
|
|
966
|
+
} catch { /* fall through to inline cache */ }
|
|
967
|
+
// Fallback: check in-memory cache for cloud-originating meshes
|
|
968
|
+
const cached = this.inlineMeshCache.get(meshId);
|
|
969
|
+
if (cached) return { success: true, mesh: cached };
|
|
970
|
+
return { success: false, error: 'Mesh not found' };
|
|
945
971
|
}
|
|
946
972
|
|
|
947
973
|
case 'create_mesh': {
|
|
@@ -1012,6 +1038,8 @@ export class DaemonCommandRouter {
|
|
|
1012
1038
|
let mesh: any;
|
|
1013
1039
|
if (args?.inlineMesh && typeof args.inlineMesh === 'object') {
|
|
1014
1040
|
mesh = args.inlineMesh;
|
|
1041
|
+
// Cache cloud mesh so the MCP server can retrieve it via get_mesh
|
|
1042
|
+
this.inlineMeshCache.set(meshId, mesh);
|
|
1015
1043
|
} else {
|
|
1016
1044
|
const { getMesh } = await import('../config/mesh-config.js');
|
|
1017
1045
|
mesh = getMesh(meshId);
|
|
@@ -1094,14 +1122,22 @@ export class DaemonCommandRouter {
|
|
|
1094
1122
|
}
|
|
1095
1123
|
|
|
1096
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
|
+
}
|
|
1097
1136
|
const mcpConfig = {
|
|
1098
1137
|
...existingMcpConfig,
|
|
1099
1138
|
mcpServers: {
|
|
1100
1139
|
...(existingMcpConfig.mcpServers || {}),
|
|
1101
|
-
[coordinatorSetup.serverName]:
|
|
1102
|
-
command: coordinatorSetup.mcpServer.command,
|
|
1103
|
-
args: coordinatorSetup.mcpServer.args,
|
|
1104
|
-
},
|
|
1140
|
+
[coordinatorSetup.serverName]: mcpServerEntry,
|
|
1105
1141
|
},
|
|
1106
1142
|
};
|
|
1107
1143
|
writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), 'utf-8');
|
package/src/config/config.ts
CHANGED
|
@@ -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
|
}
|