@adhdev/daemon-core 0.9.76-rc.11 → 0.9.76-rc.12
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 +2 -1
- package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
- package/dist/commands/cli-manager.d.ts +6 -4
- package/dist/index.js +91 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +92 -46
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +1 -0
- package/package.json +3 -1
- package/src/cli-adapters/provider-cli-adapter.ts +2 -0
- package/src/cli-adapters/provider-cli-runtime.ts +3 -2
- package/src/commands/cli-manager.ts +13 -3
- package/src/commands/mesh-coordinator.ts +11 -2
- package/src/commands/router.ts +54 -13
- package/src/providers/cli-provider-instance.ts +2 -1
|
@@ -67,6 +67,7 @@ export declare class CliProviderInstance implements ProviderInstance {
|
|
|
67
67
|
constructor(provider: ProviderModule, workingDir: string, cliArgs?: string[], instanceId?: string, transportFactory?: PtyTransportFactory, options?: {
|
|
68
68
|
providerSessionId?: string;
|
|
69
69
|
launchMode?: 'new' | 'resume' | 'manual';
|
|
70
|
+
extraEnv?: Record<string, string>;
|
|
70
71
|
onProviderSessionResolved?: (info: {
|
|
71
72
|
instanceId: string;
|
|
72
73
|
providerType: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/daemon-core",
|
|
3
|
-
"version": "0.9.76-rc.
|
|
3
|
+
"version": "0.9.76-rc.12",
|
|
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",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"chalk": "^5.3.0",
|
|
53
53
|
"chokidar": "^5.0.0",
|
|
54
54
|
"conf": "^13.0.0",
|
|
55
|
+
"js-yaml": "^4.1.1",
|
|
55
56
|
"node-pty": "^1.2.0-beta.12",
|
|
56
57
|
"ws": "^8.19.0"
|
|
57
58
|
},
|
|
@@ -62,6 +63,7 @@
|
|
|
62
63
|
"@adhdev/ghostty-vt-node": "*"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
66
|
+
"@types/js-yaml": "^4.0.9",
|
|
65
67
|
"@types/node": "^22.0.0",
|
|
66
68
|
"@types/ws": "^8.18.1",
|
|
67
69
|
"tsup": "^8.2.0",
|
|
@@ -422,6 +422,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
422
422
|
provider: CliProviderModule,
|
|
423
423
|
workingDir: string,
|
|
424
424
|
private extraArgs: string[] = [],
|
|
425
|
+
private extraEnv: Record<string, string> = {},
|
|
425
426
|
transportFactory: PtyTransportFactory = new NodePtyTransportFactory(),
|
|
426
427
|
) {
|
|
427
428
|
this.provider = provider;
|
|
@@ -523,6 +524,7 @@ export class ProviderCliAdapter implements CliAdapter {
|
|
|
523
524
|
runtimeSettings: this.runtimeSettings,
|
|
524
525
|
workingDir: this.workingDir,
|
|
525
526
|
extraArgs: this.extraArgs,
|
|
527
|
+
extraEnv: this.extraEnv,
|
|
526
528
|
});
|
|
527
529
|
|
|
528
530
|
LOG.info('CLI', `[${this.cliType}] Spawning in ${this.workingDir}`);
|
|
@@ -27,8 +27,9 @@ export function resolveCliSpawnPlan(options: {
|
|
|
27
27
|
runtimeSettings: Record<string, any>;
|
|
28
28
|
workingDir: string;
|
|
29
29
|
extraArgs: string[];
|
|
30
|
+
extraEnv?: Record<string, string>;
|
|
30
31
|
}): CliSpawnPlan {
|
|
31
|
-
const { provider, runtimeSettings, workingDir, extraArgs } = options;
|
|
32
|
+
const { provider, runtimeSettings, workingDir, extraArgs, extraEnv } = options;
|
|
32
33
|
const { spawn: spawnConfig } = provider;
|
|
33
34
|
const configuredCommand = typeof runtimeSettings.executablePath === 'string' && runtimeSettings.executablePath.trim()
|
|
34
35
|
? runtimeSettings.executablePath.trim()
|
|
@@ -65,7 +66,7 @@ export function resolveCliSpawnPlan(options: {
|
|
|
65
66
|
shellArgs = allArgs;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
const env = buildCliSpawnEnv(process.env, spawnConfig.env);
|
|
69
|
+
const env = buildCliSpawnEnv(process.env, { ...(spawnConfig.env || {}), ...(extraEnv || {}) });
|
|
69
70
|
// Some CLI agents, notably Hermes, route their tools through TERMINAL_CWD
|
|
70
71
|
// rather than process.cwd(). Keep the generic ADHDev launch workspace as
|
|
71
72
|
// the single source of truth so PTY cwd and tool cwd cannot diverge.
|
|
@@ -132,6 +132,12 @@ type CliAdapterWithExtraArgs = CliAdapter & {
|
|
|
132
132
|
extraArgs?: string[];
|
|
133
133
|
};
|
|
134
134
|
|
|
135
|
+
type CliStartOptions = {
|
|
136
|
+
resumeSessionId?: string;
|
|
137
|
+
settingsOverride?: Record<string, any>;
|
|
138
|
+
extraEnv?: Record<string, string>;
|
|
139
|
+
};
|
|
140
|
+
|
|
135
141
|
function isUuid(value: string): boolean {
|
|
136
142
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value);
|
|
137
143
|
}
|
|
@@ -365,6 +371,7 @@ export class DaemonCliManager {
|
|
|
365
371
|
runtimeId: string,
|
|
366
372
|
providerSessionId?: string,
|
|
367
373
|
attachExisting = false,
|
|
374
|
+
extraEnv?: Record<string, string>,
|
|
368
375
|
): CliAdapter {
|
|
369
376
|
// cliType normalize (Resolve alias)
|
|
370
377
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
@@ -382,7 +389,7 @@ export class DaemonCliManager {
|
|
|
382
389
|
providerSessionId,
|
|
383
390
|
attachExisting,
|
|
384
391
|
);
|
|
385
|
-
return new ProviderCliAdapter(resolvedProvider as CliProviderModule, workingDir, cliArgs, transportFactory);
|
|
392
|
+
return new ProviderCliAdapter(resolvedProvider as CliProviderModule, workingDir, cliArgs, extraEnv || {}, transportFactory);
|
|
386
393
|
}
|
|
387
394
|
|
|
388
395
|
throw new Error(`No CLI provider found for '${cliType}'. Create a provider.js in providers/cli/${cliType}/`);
|
|
@@ -425,6 +432,7 @@ export class DaemonCliManager {
|
|
|
425
432
|
options?: {
|
|
426
433
|
providerSessionId?: string;
|
|
427
434
|
launchMode?: CliLaunchMode;
|
|
435
|
+
extraEnv?: Record<string, string>;
|
|
428
436
|
onProviderSessionResolved?: (info: {
|
|
429
437
|
instanceId: string;
|
|
430
438
|
providerType: string;
|
|
@@ -480,7 +488,7 @@ export class DaemonCliManager {
|
|
|
480
488
|
workingDir: string,
|
|
481
489
|
cliArgs?: string[],
|
|
482
490
|
initialModel?: string,
|
|
483
|
-
options?:
|
|
491
|
+
options?: CliStartOptions,
|
|
484
492
|
): Promise<{ runtimeSessionId: string; providerSessionId?: string }> {
|
|
485
493
|
const trimmed = (workingDir || '').trim();
|
|
486
494
|
if (!trimmed) throw new Error('working directory required');
|
|
@@ -629,6 +637,7 @@ export class DaemonCliManager {
|
|
|
629
637
|
{
|
|
630
638
|
providerSessionId: sessionBinding.providerSessionId,
|
|
631
639
|
launchMode: sessionBinding.launchMode,
|
|
640
|
+
extraEnv: options?.extraEnv,
|
|
632
641
|
onProviderSessionResolved: ({ providerSessionId, providerName, providerType, workspace }) => {
|
|
633
642
|
this.persistRecentActivity({
|
|
634
643
|
kind: 'cli',
|
|
@@ -651,6 +660,7 @@ export class DaemonCliManager {
|
|
|
651
660
|
key,
|
|
652
661
|
sessionBinding.providerSessionId,
|
|
653
662
|
false,
|
|
663
|
+
options?.extraEnv,
|
|
654
664
|
);
|
|
655
665
|
try {
|
|
656
666
|
await adapter.spawn();
|
|
@@ -904,7 +914,7 @@ export class DaemonCliManager {
|
|
|
904
914
|
dir,
|
|
905
915
|
args?.cliArgs,
|
|
906
916
|
args?.initialModel,
|
|
907
|
-
{ resumeSessionId: args?.resumeSessionId, settingsOverride: args?.settings },
|
|
917
|
+
{ resumeSessionId: args?.resumeSessionId, settingsOverride: args?.settings, extraEnv: args?.env },
|
|
908
918
|
);
|
|
909
919
|
|
|
910
920
|
return {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, realpathSync } from 'node:fs'
|
|
2
2
|
import { createRequire } from 'node:module'
|
|
3
|
-
import
|
|
3
|
+
import * as os from 'node:os'
|
|
4
|
+
import { dirname, isAbsolute, join, resolve } from 'node:path'
|
|
4
5
|
import type { ProviderModule, MeshCoordinatorMcpConfigFormat } from '../providers/contracts.js'
|
|
5
6
|
|
|
6
7
|
export interface MeshCoordinatorMcpServerLaunch {
|
|
@@ -80,7 +81,7 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
|
|
|
80
81
|
return {
|
|
81
82
|
kind: 'auto_import',
|
|
82
83
|
serverName,
|
|
83
|
-
configPath:
|
|
84
|
+
configPath: resolveMcpConfigPath(path, workspace),
|
|
84
85
|
configFormat: mcpConfig.format,
|
|
85
86
|
mcpServer,
|
|
86
87
|
}
|
|
@@ -118,6 +119,14 @@ function renderMeshCoordinatorTemplate(template: string, values: Record<string,
|
|
|
118
119
|
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key: string) => values[key] || '')
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
function resolveMcpConfigPath(configPath: string, workspace: string): string {
|
|
123
|
+
const trimmed = configPath.trim()
|
|
124
|
+
if (trimmed === '~') return os.homedir()
|
|
125
|
+
if (trimmed.startsWith('~/')) return join(os.homedir(), trimmed.slice(2))
|
|
126
|
+
if (isAbsolute(trimmed)) return trimmed
|
|
127
|
+
return join(workspace, trimmed)
|
|
128
|
+
}
|
|
129
|
+
|
|
121
130
|
function resolveAdhdevMcpServerLaunch(options: {
|
|
122
131
|
meshId: string
|
|
123
132
|
nodeExecutable?: string
|
package/src/commands/router.ts
CHANGED
|
@@ -30,6 +30,7 @@ import { SessionRegistry } from '../sessions/registry.js';
|
|
|
30
30
|
import { LOG } from '../logging/logger.js';
|
|
31
31
|
import { logCommand } from '../logging/command-log.js';
|
|
32
32
|
import type { CommandLogEntry } from '../logging/command-log.js';
|
|
33
|
+
import * as yaml from 'js-yaml';
|
|
33
34
|
import { getRecentLogs, LOG_PATH } from '../logging/logger.js';
|
|
34
35
|
import { createInteractionId, getRecentDebugTrace, recordDebugTrace } from '../logging/debug-trace.js';
|
|
35
36
|
import { getSessionHostSurfaceKind, partitionSessionHostRecords } from '../session-host/runtime-surface.js';
|
|
@@ -63,6 +64,28 @@ function resolveUpgradeChannel(args: any): ReleaseChannel {
|
|
|
63
64
|
}
|
|
64
65
|
import * as fs from 'fs';
|
|
65
66
|
|
|
67
|
+
type MeshCoordinatorConfigFormat = 'claude_mcp_json' | 'hermes_config_yaml';
|
|
68
|
+
|
|
69
|
+
function loadYamlModule(): { load: (input: string) => any; dump: (input: any, options?: Record<string, any>) => string } {
|
|
70
|
+
return yaml as { load: (input: string) => any; dump: (input: any, options?: Record<string, any>) => string };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getMcpServersKey(format: MeshCoordinatorConfigFormat): 'mcpServers' | 'mcp_servers' {
|
|
74
|
+
return format === 'hermes_config_yaml' ? 'mcp_servers' : 'mcpServers';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function parseMeshCoordinatorMcpConfig(text: string, format: MeshCoordinatorConfigFormat): Record<string, any> {
|
|
78
|
+
if (!text.trim()) return {};
|
|
79
|
+
if (format === 'claude_mcp_json') return JSON.parse(text);
|
|
80
|
+
const parsed = loadYamlModule().load(text);
|
|
81
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function serializeMeshCoordinatorMcpConfig(config: Record<string, any>, format: MeshCoordinatorConfigFormat): string {
|
|
85
|
+
if (format === 'claude_mcp_json') return JSON.stringify(config, null, 2);
|
|
86
|
+
return loadYamlModule().dump(config, { noRefs: true, lineWidth: 120 });
|
|
87
|
+
}
|
|
88
|
+
|
|
66
89
|
// ─── Types ───
|
|
67
90
|
|
|
68
91
|
export interface SessionHostControlPlane {
|
|
@@ -1231,7 +1254,8 @@ export class DaemonCommandRouter {
|
|
|
1231
1254
|
};
|
|
1232
1255
|
}
|
|
1233
1256
|
|
|
1234
|
-
|
|
1257
|
+
const configFormat = coordinatorSetup.configFormat as MeshCoordinatorConfigFormat;
|
|
1258
|
+
if (configFormat !== 'claude_mcp_json' && configFormat !== 'hermes_config_yaml') {
|
|
1235
1259
|
return {
|
|
1236
1260
|
success: false,
|
|
1237
1261
|
code: 'mesh_coordinator_unsupported',
|
|
@@ -1261,18 +1285,27 @@ export class DaemonCommandRouter {
|
|
|
1261
1285
|
};
|
|
1262
1286
|
}
|
|
1263
1287
|
|
|
1264
|
-
// 1. Write provider-declared MCP config
|
|
1265
|
-
const { existsSync, readFileSync, writeFileSync, copyFileSync } = await import('fs');
|
|
1288
|
+
// 1. Write provider-declared MCP config for CLIs that auto-import it.
|
|
1289
|
+
const { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync } = await import('fs');
|
|
1290
|
+
const { dirname } = await import('path');
|
|
1266
1291
|
const mcpConfigPath = coordinatorSetup.configPath;
|
|
1292
|
+
mkdirSync(dirname(mcpConfigPath), { recursive: true });
|
|
1267
1293
|
|
|
1268
1294
|
// Backup existing MCP config if present.
|
|
1269
1295
|
const hadExistingMcpConfig = existsSync(mcpConfigPath);
|
|
1270
|
-
let existingMcpConfig: any = {};
|
|
1296
|
+
let existingMcpConfig: Record<string, any> = {};
|
|
1271
1297
|
if (hadExistingMcpConfig) {
|
|
1272
1298
|
try {
|
|
1273
|
-
existingMcpConfig =
|
|
1299
|
+
existingMcpConfig = parseMeshCoordinatorMcpConfig(readFileSync(mcpConfigPath, 'utf-8'), configFormat);
|
|
1274
1300
|
copyFileSync(mcpConfigPath, mcpConfigPath + '.backup');
|
|
1275
|
-
} catch
|
|
1301
|
+
} catch (error: any) {
|
|
1302
|
+
LOG.error('MeshCoordinator', `Failed to parse existing MCP config ${mcpConfigPath}: ${error?.message || error}`);
|
|
1303
|
+
return {
|
|
1304
|
+
success: false,
|
|
1305
|
+
code: 'mesh_coordinator_config_parse_failed',
|
|
1306
|
+
error: `Failed to parse existing MCP config at ${mcpConfigPath}`,
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1276
1309
|
}
|
|
1277
1310
|
|
|
1278
1311
|
// Merge ADHDev mesh server into existing config.
|
|
@@ -1288,31 +1321,39 @@ export class DaemonCommandRouter {
|
|
|
1288
1321
|
ADHDEV_MCP_TRANSPORT: 'ipc',
|
|
1289
1322
|
};
|
|
1290
1323
|
}
|
|
1324
|
+
const mcpServersKey = getMcpServersKey(configFormat);
|
|
1325
|
+
const existingServers = existingMcpConfig[mcpServersKey];
|
|
1291
1326
|
const mcpConfig = {
|
|
1292
1327
|
...existingMcpConfig,
|
|
1293
|
-
|
|
1294
|
-
...(
|
|
1328
|
+
[mcpServersKey]: {
|
|
1329
|
+
...(existingServers && typeof existingServers === 'object' && !Array.isArray(existingServers) ? existingServers : {}),
|
|
1295
1330
|
[coordinatorSetup.serverName]: mcpServerEntry,
|
|
1296
1331
|
},
|
|
1297
1332
|
};
|
|
1298
|
-
writeFileSync(mcpConfigPath,
|
|
1333
|
+
writeFileSync(mcpConfigPath, serializeMeshCoordinatorMcpConfig(mcpConfig, configFormat), 'utf-8');
|
|
1299
1334
|
LOG.info('MeshCoordinator', `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
1300
1335
|
|
|
1301
1336
|
const cliArgs: string[] = [];
|
|
1337
|
+
const launchEnv: Record<string, string> = {};
|
|
1302
1338
|
if (systemPrompt) {
|
|
1303
|
-
|
|
1339
|
+
if (configFormat === 'hermes_config_yaml') {
|
|
1340
|
+
launchEnv.HERMES_EPHEMERAL_SYSTEM_PROMPT = systemPrompt;
|
|
1341
|
+
} else {
|
|
1342
|
+
cliArgs.push('--append-system-prompt', systemPrompt);
|
|
1343
|
+
}
|
|
1304
1344
|
}
|
|
1305
1345
|
if (cliType === 'claude-cli') {
|
|
1306
1346
|
cliArgs.push('--mcp-config', coordinatorSetup.configPath);
|
|
1307
1347
|
}
|
|
1308
1348
|
|
|
1309
|
-
// 3. Launch CLI session via existing cliManager
|
|
1310
|
-
//
|
|
1311
|
-
// CLI
|
|
1349
|
+
// 3. Launch CLI session via existing cliManager.
|
|
1350
|
+
// Provider-specific prompt injection remains fail-closed: Claude gets
|
|
1351
|
+
// explicit CLI args, while Hermes reads HERMES_EPHEMERAL_SYSTEM_PROMPT.
|
|
1312
1352
|
const launchResult: any = await this.deps.cliManager.handleCliCommand('launch_cli', {
|
|
1313
1353
|
cliType,
|
|
1314
1354
|
dir: workspace,
|
|
1315
1355
|
cliArgs: cliArgs.length > 0 ? cliArgs : undefined,
|
|
1356
|
+
env: Object.keys(launchEnv).length > 0 ? launchEnv : undefined,
|
|
1316
1357
|
settings: {
|
|
1317
1358
|
meshCoordinatorFor: meshId
|
|
1318
1359
|
}
|
|
@@ -214,6 +214,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
214
214
|
options?: {
|
|
215
215
|
providerSessionId?: string;
|
|
216
216
|
launchMode?: 'new' | 'resume' | 'manual';
|
|
217
|
+
extraEnv?: Record<string, string>;
|
|
217
218
|
onProviderSessionResolved?: (info: {
|
|
218
219
|
instanceId: string;
|
|
219
220
|
providerType: string;
|
|
@@ -230,7 +231,7 @@ export class CliProviderInstance implements ProviderInstance {
|
|
|
230
231
|
this.providerSessionId = options?.providerSessionId;
|
|
231
232
|
this.launchMode = options?.launchMode || 'new';
|
|
232
233
|
this.onProviderSessionResolved = options?.onProviderSessionResolved;
|
|
233
|
-
this.adapter = new ProviderCliAdapter(provider as CliProviderModule, workingDir, cliArgs, transportFactory);
|
|
234
|
+
this.adapter = new ProviderCliAdapter(provider as CliProviderModule, workingDir, cliArgs, options?.extraEnv || {}, transportFactory);
|
|
234
235
|
this.monitor = new StatusMonitor();
|
|
235
236
|
this.historyWriter = new ChatHistoryWriter();
|
|
236
237
|
}
|