@adhdev/daemon-core 0.9.67 → 0.9.69
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/mesh-coordinator.d.ts +25 -0
- package/dist/index.js +673 -337
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +673 -336
- package/dist/index.mjs.map +1 -1
- package/dist/providers/contracts.d.ts +34 -0
- package/dist/shared-types.d.ts +3 -1
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/commands/mesh-coordinator.ts +97 -0
- package/src/commands/router.ts +196 -0
- package/src/providers/contracts.ts +37 -0
- package/src/providers/provider-schema.ts +67 -0
- package/src/shared-types.ts +3 -1
- package/src/status/snapshot.ts +2 -0
|
@@ -260,6 +260,31 @@ export interface CdpTargetFilter {
|
|
|
260
260
|
titleExcludes?: string;
|
|
261
261
|
}
|
|
262
262
|
export type ProviderVersionCommand = string | Partial<Record<string, string>>;
|
|
263
|
+
export type MeshCoordinatorMcpConfigMode = 'auto_import' | 'manual' | 'none';
|
|
264
|
+
export type MeshCoordinatorMcpConfigFormat = 'claude_mcp_json' | 'hermes_config_yaml';
|
|
265
|
+
export interface ProviderMeshCoordinatorConfig {
|
|
266
|
+
/** Whether ADHDev may select this provider for Repo Mesh coordinator sessions. */
|
|
267
|
+
supported: boolean;
|
|
268
|
+
/** Human-readable reason shown when unsupported or blocked. */
|
|
269
|
+
reason?: string;
|
|
270
|
+
/** How ADHDev mesh MCP tools become visible to the launched CLI. */
|
|
271
|
+
mcpConfig?: {
|
|
272
|
+
mode: MeshCoordinatorMcpConfigMode;
|
|
273
|
+
format?: MeshCoordinatorMcpConfigFormat;
|
|
274
|
+
/** Provider-relative/project-relative config path for auto-import modes, e.g. '.mcp.json'. */
|
|
275
|
+
path?: string;
|
|
276
|
+
/** MCP server name to materialize or display. Defaults to 'adhdev-mesh'. */
|
|
277
|
+
serverName?: string;
|
|
278
|
+
/** Manual setup target path/help command, e.g. 'hermes config path'. */
|
|
279
|
+
configPathCommand?: string;
|
|
280
|
+
/** Whether users need a fresh CLI session after config changes. */
|
|
281
|
+
requiresRestart?: boolean;
|
|
282
|
+
/** User-facing setup explanation for manual modes. */
|
|
283
|
+
instructions?: string;
|
|
284
|
+
/** Copyable setup template. Supports {{meshId}}, {{adhdevMcpCommand}}, {{workspace}}, {{serverName}}. */
|
|
285
|
+
template?: string;
|
|
286
|
+
};
|
|
287
|
+
}
|
|
263
288
|
export interface ProviderCompatibilityEntry {
|
|
264
289
|
ideVersion: string;
|
|
265
290
|
scriptDir: string;
|
|
@@ -271,6 +296,10 @@ export interface ProviderModule {
|
|
|
271
296
|
name: string;
|
|
272
297
|
/** Category: determines execution method */
|
|
273
298
|
category: ProviderCategory;
|
|
299
|
+
/** When provider-owned, daemon treats provider parser output as canonical transcript authority. */
|
|
300
|
+
transcriptAuthority?: 'provider' | 'daemon';
|
|
301
|
+
/** Full context lets provider-owned parsers canonicalize retained history instead of daemon prefix stitching. */
|
|
302
|
+
transcriptContext?: 'full' | 'tail';
|
|
274
303
|
/** Alias list — allows users to invoke by alternate names (e.g. ['claude', 'claude-code']) */
|
|
275
304
|
aliases?: string[];
|
|
276
305
|
/** CDP ports [primary, secondary] (IDE category only) */
|
|
@@ -448,6 +477,11 @@ export interface ProviderModule {
|
|
|
448
477
|
spawnArgBuilder?: (config: Record<string, string>) => string[];
|
|
449
478
|
/** ACP agent auth methods (multiple supported — in priority order) */
|
|
450
479
|
auth?: AcpAuthMethod[];
|
|
480
|
+
/**
|
|
481
|
+
* Repo Mesh coordinator capability and MCP ingestion behavior.
|
|
482
|
+
* Providers must declare this rather than relying on daemon hardcoded CLI quirks.
|
|
483
|
+
*/
|
|
484
|
+
meshCoordinator?: ProviderMeshCoordinatorConfig;
|
|
451
485
|
contractVersion?: number;
|
|
452
486
|
capabilities?: {
|
|
453
487
|
input?: {
|
package/dist/shared-types.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export type { ProviderState, ProviderStatus, ActiveChatData, IdeProviderState, C
|
|
|
12
12
|
export type { ProviderErrorReason } from './providers/provider-instance.js';
|
|
13
13
|
import type { ActiveChatData as _ActiveChatData, ProviderErrorReason as _ProviderErrorReason } from './providers/provider-instance.js';
|
|
14
14
|
import type { WorkspaceEntry } from './config/workspaces.js';
|
|
15
|
-
import type { ProviderResumeCapability } from './providers/contracts.js';
|
|
15
|
+
import type { ProviderMeshCoordinatorConfig, ProviderResumeCapability } from './providers/contracts.js';
|
|
16
16
|
import type { GitCompactSummary, GitWorkspaceUpdate, WorkspaceGitSubscriptionParams } from './git/git-types.js';
|
|
17
17
|
export type { GitCommandName, GitCompactSummary, GitDiffSummary, GitFailureReason, GitFileChange, GitFileChangeStatus, GitRepoIdentity, GitRepoStatus, GitSnapshot, GitSnapshotCompareSummary, GitSnapshotReason, GitWorkspaceUpdate, WorkspaceGitSubscriptionParams, } from './git/git-types.js';
|
|
18
18
|
export interface SessionActiveChatData extends Omit<_ActiveChatData, 'messages'> {
|
|
@@ -343,6 +343,8 @@ export interface AvailableProviderInfo {
|
|
|
343
343
|
lastDetection?: MachineProviderCheckResult;
|
|
344
344
|
/** Last end-to-end ADHDev verification result, when available. */
|
|
345
345
|
lastVerification?: MachineProviderCheckResult;
|
|
346
|
+
/** Provider-declared Repo Mesh coordinator/MCP behavior. */
|
|
347
|
+
meshCoordinator?: ProviderMeshCoordinatorConfig;
|
|
346
348
|
}
|
|
347
349
|
export interface MachineProviderCheckResult {
|
|
348
350
|
ok: boolean;
|
package/package.json
CHANGED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { join } from 'path'
|
|
2
|
+
import type { ProviderModule, MeshCoordinatorMcpConfigFormat } from '../providers/contracts.js'
|
|
3
|
+
|
|
4
|
+
export type MeshCoordinatorSetup =
|
|
5
|
+
| {
|
|
6
|
+
kind: 'auto_import'
|
|
7
|
+
serverName: string
|
|
8
|
+
configPath: string
|
|
9
|
+
configFormat?: MeshCoordinatorMcpConfigFormat
|
|
10
|
+
}
|
|
11
|
+
| {
|
|
12
|
+
kind: 'manual'
|
|
13
|
+
serverName: string
|
|
14
|
+
configFormat?: MeshCoordinatorMcpConfigFormat
|
|
15
|
+
configPathCommand?: string
|
|
16
|
+
requiresRestart: boolean
|
|
17
|
+
instructions: string
|
|
18
|
+
template: string
|
|
19
|
+
}
|
|
20
|
+
| {
|
|
21
|
+
kind: 'unsupported'
|
|
22
|
+
reason: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ResolveMeshCoordinatorSetupOptions {
|
|
26
|
+
provider?: ProviderModule | null
|
|
27
|
+
meshId: string
|
|
28
|
+
workspace: string
|
|
29
|
+
adhdevMcpCommand?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const DEFAULT_SERVER_NAME = 'adhdev-mesh'
|
|
33
|
+
const DEFAULT_ADHDEV_MCP_COMMAND = 'adhdev-mcp'
|
|
34
|
+
|
|
35
|
+
export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetupOptions): MeshCoordinatorSetup {
|
|
36
|
+
const { provider, meshId, workspace } = options
|
|
37
|
+
const config = provider?.meshCoordinator
|
|
38
|
+
if (!config?.supported) {
|
|
39
|
+
return {
|
|
40
|
+
kind: 'unsupported',
|
|
41
|
+
reason: config?.reason || 'Provider does not declare Repo Mesh coordinator support',
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const mcpConfig = config.mcpConfig
|
|
46
|
+
if (!mcpConfig || mcpConfig.mode === 'none') {
|
|
47
|
+
return {
|
|
48
|
+
kind: 'unsupported',
|
|
49
|
+
reason: config.reason || 'Provider does not declare a usable Repo Mesh MCP configuration mode',
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const serverName = mcpConfig.serverName?.trim() || DEFAULT_SERVER_NAME
|
|
54
|
+
if (mcpConfig.mode === 'auto_import') {
|
|
55
|
+
const path = mcpConfig.path?.trim()
|
|
56
|
+
if (!path) {
|
|
57
|
+
return { kind: 'unsupported', reason: 'Provider auto-import MCP config is missing a config path' }
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
kind: 'auto_import',
|
|
61
|
+
serverName,
|
|
62
|
+
configPath: join(workspace, path),
|
|
63
|
+
configFormat: mcpConfig.format,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (mcpConfig.mode === 'manual') {
|
|
68
|
+
const instructions = mcpConfig.instructions?.trim()
|
|
69
|
+
const template = mcpConfig.template
|
|
70
|
+
if (!instructions || !template?.trim()) {
|
|
71
|
+
return { kind: 'unsupported', reason: 'Provider manual MCP setup is missing instructions or template' }
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
kind: 'manual',
|
|
75
|
+
serverName,
|
|
76
|
+
configFormat: mcpConfig.format,
|
|
77
|
+
configPathCommand: mcpConfig.configPathCommand,
|
|
78
|
+
requiresRestart: mcpConfig.requiresRestart === true,
|
|
79
|
+
instructions,
|
|
80
|
+
template: renderMeshCoordinatorTemplate(template, {
|
|
81
|
+
meshId,
|
|
82
|
+
workspace,
|
|
83
|
+
serverName,
|
|
84
|
+
adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND,
|
|
85
|
+
}),
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
kind: 'unsupported',
|
|
91
|
+
reason: `Unsupported Repo Mesh MCP configuration mode: ${String(mcpConfig.mode)}`,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function renderMeshCoordinatorTemplate(template: string, values: Record<string, string>): string {
|
|
96
|
+
return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key: string) => values[key] || '')
|
|
97
|
+
}
|
package/src/commands/router.ts
CHANGED
|
@@ -33,6 +33,7 @@ import type { CommandLogEntry } from '../logging/command-log.js';
|
|
|
33
33
|
import { getRecentLogs, LOG_PATH } from '../logging/logger.js';
|
|
34
34
|
import { createInteractionId, getRecentDebugTrace, recordDebugTrace } from '../logging/debug-trace.js';
|
|
35
35
|
import { getSessionHostSurfaceKind, partitionSessionHostRecords } from '../session-host/runtime-surface.js';
|
|
36
|
+
import { resolveMeshCoordinatorSetup } from './mesh-coordinator.js';
|
|
36
37
|
import { buildSessionEntries } from '../status/builders.js';
|
|
37
38
|
import { buildMachineInfo, buildStatusSnapshot } from '../status/snapshot.js';
|
|
38
39
|
import { getSessionCompletionMarker } from '../status/snapshot.js';
|
|
@@ -920,6 +921,201 @@ export class DaemonCommandRouter {
|
|
|
920
921
|
return { success: true };
|
|
921
922
|
}
|
|
922
923
|
|
|
924
|
+
// ─── Mesh CRUD (local meshes.json) ───
|
|
925
|
+
case 'list_meshes': {
|
|
926
|
+
try {
|
|
927
|
+
const { listMeshes } = await import('../config/mesh-config.js');
|
|
928
|
+
return { success: true, meshes: listMeshes() };
|
|
929
|
+
} catch (e: any) {
|
|
930
|
+
return { success: false, error: e.message };
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
case 'get_mesh': {
|
|
935
|
+
const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
|
|
936
|
+
if (!meshId) return { success: false, error: 'meshId required' };
|
|
937
|
+
try {
|
|
938
|
+
const { getMesh } = await import('../config/mesh-config.js');
|
|
939
|
+
const mesh = getMesh(meshId);
|
|
940
|
+
if (!mesh) return { success: false, error: 'Mesh not found' };
|
|
941
|
+
return { success: true, mesh };
|
|
942
|
+
} catch (e: any) {
|
|
943
|
+
return { success: false, error: e.message };
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
case 'create_mesh': {
|
|
948
|
+
const name = typeof args?.name === 'string' ? args.name.trim() : '';
|
|
949
|
+
const repoIdentity = typeof args?.repoIdentity === 'string' ? args.repoIdentity.trim() : '';
|
|
950
|
+
const repoRemoteUrl = typeof args?.repoRemoteUrl === 'string' ? args.repoRemoteUrl.trim() : undefined;
|
|
951
|
+
const defaultBranch = typeof args?.defaultBranch === 'string' ? args.defaultBranch.trim() : undefined;
|
|
952
|
+
if (!name) return { success: false, error: 'name required' };
|
|
953
|
+
try {
|
|
954
|
+
const { createMesh } = await import('../config/mesh-config.js');
|
|
955
|
+
const mesh = createMesh({ name, repoIdentity, repoRemoteUrl, defaultBranch });
|
|
956
|
+
return { success: true, mesh };
|
|
957
|
+
} catch (e: any) {
|
|
958
|
+
return { success: false, error: e.message };
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
case 'delete_mesh': {
|
|
963
|
+
const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
|
|
964
|
+
if (!meshId) return { success: false, error: 'meshId required' };
|
|
965
|
+
try {
|
|
966
|
+
const { deleteMesh } = await import('../config/mesh-config.js');
|
|
967
|
+
const deleted = deleteMesh(meshId);
|
|
968
|
+
return { success: true, deleted };
|
|
969
|
+
} catch (e: any) {
|
|
970
|
+
return { success: false, error: e.message };
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
case 'add_mesh_node': {
|
|
975
|
+
const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
|
|
976
|
+
const workspace = typeof args?.workspace === 'string' ? args.workspace.trim() : '';
|
|
977
|
+
if (!meshId) return { success: false, error: 'meshId required' };
|
|
978
|
+
if (!workspace) return { success: false, error: 'workspace required' };
|
|
979
|
+
try {
|
|
980
|
+
const { addNode } = await import('../config/mesh-config.js');
|
|
981
|
+
const node = addNode(meshId, { workspace });
|
|
982
|
+
if (!node) return { success: false, error: 'Mesh not found' };
|
|
983
|
+
return { success: true, node };
|
|
984
|
+
} catch (e: any) {
|
|
985
|
+
return { success: false, error: e.message };
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
case 'remove_mesh_node': {
|
|
990
|
+
const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
|
|
991
|
+
const nodeId = typeof args?.nodeId === 'string' ? args.nodeId.trim() : '';
|
|
992
|
+
if (!meshId || !nodeId) return { success: false, error: 'meshId and nodeId required' };
|
|
993
|
+
try {
|
|
994
|
+
const { removeNode } = await import('../config/mesh-config.js');
|
|
995
|
+
const removed = removeNode(meshId, nodeId);
|
|
996
|
+
return { success: true, removed };
|
|
997
|
+
} catch (e: any) {
|
|
998
|
+
return { success: false, error: e.message };
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// ─── Mesh Coordinator Launch ───
|
|
1003
|
+
case 'launch_mesh_coordinator': {
|
|
1004
|
+
const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
|
|
1005
|
+
const cliType = typeof args?.cliType === 'string' ? args.cliType.trim() : 'claude-cli';
|
|
1006
|
+
if (!meshId) return { success: false, error: 'meshId required' };
|
|
1007
|
+
|
|
1008
|
+
try {
|
|
1009
|
+
const { getMesh } = await import('../config/mesh-config.js');
|
|
1010
|
+
const { buildCoordinatorSystemPrompt } = await import('../mesh/coordinator-prompt.js');
|
|
1011
|
+
const mesh = getMesh(meshId);
|
|
1012
|
+
if (!mesh) return { success: false, error: 'Mesh not found' };
|
|
1013
|
+
if (mesh.nodes.length === 0) return { success: false, error: 'No nodes in mesh' };
|
|
1014
|
+
|
|
1015
|
+
const workspace = mesh.nodes[0].workspace;
|
|
1016
|
+
const providerMeta = this.deps.providerLoader.resolve?.(cliType) || this.deps.providerLoader.getMeta(cliType);
|
|
1017
|
+
const coordinatorSetup = resolveMeshCoordinatorSetup({
|
|
1018
|
+
provider: providerMeta,
|
|
1019
|
+
meshId,
|
|
1020
|
+
workspace,
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
if (coordinatorSetup.kind === 'unsupported') {
|
|
1024
|
+
return {
|
|
1025
|
+
success: false,
|
|
1026
|
+
code: 'mesh_coordinator_unsupported',
|
|
1027
|
+
error: coordinatorSetup.reason,
|
|
1028
|
+
meshId,
|
|
1029
|
+
cliType,
|
|
1030
|
+
workspace,
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
if (coordinatorSetup.kind === 'manual') {
|
|
1035
|
+
return {
|
|
1036
|
+
success: false,
|
|
1037
|
+
code: 'mesh_coordinator_manual_mcp_setup_required',
|
|
1038
|
+
error: coordinatorSetup.instructions,
|
|
1039
|
+
meshId,
|
|
1040
|
+
cliType,
|
|
1041
|
+
workspace,
|
|
1042
|
+
meshCoordinatorSetup: coordinatorSetup,
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
if (coordinatorSetup.configFormat !== 'claude_mcp_json') {
|
|
1047
|
+
return {
|
|
1048
|
+
success: false,
|
|
1049
|
+
code: 'mesh_coordinator_unsupported',
|
|
1050
|
+
error: `Unsupported auto-import MCP config format: ${String(coordinatorSetup.configFormat)}`,
|
|
1051
|
+
meshId,
|
|
1052
|
+
cliType,
|
|
1053
|
+
workspace,
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// 1. Write provider-declared MCP config to workspace for CLIs that auto-import it.
|
|
1058
|
+
const { existsSync, readFileSync, writeFileSync, copyFileSync } = await import('fs');
|
|
1059
|
+
const mcpConfigPath = coordinatorSetup.configPath;
|
|
1060
|
+
|
|
1061
|
+
// Backup existing MCP config if present.
|
|
1062
|
+
const hadExistingMcpConfig = existsSync(mcpConfigPath);
|
|
1063
|
+
let existingMcpConfig: any = {};
|
|
1064
|
+
if (hadExistingMcpConfig) {
|
|
1065
|
+
try {
|
|
1066
|
+
existingMcpConfig = JSON.parse(readFileSync(mcpConfigPath, 'utf-8'));
|
|
1067
|
+
copyFileSync(mcpConfigPath, mcpConfigPath + '.backup');
|
|
1068
|
+
} catch { /* empty */ }
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// Merge ADHDev mesh server into existing config.
|
|
1072
|
+
const mcpConfig = {
|
|
1073
|
+
...existingMcpConfig,
|
|
1074
|
+
mcpServers: {
|
|
1075
|
+
...(existingMcpConfig.mcpServers || {}),
|
|
1076
|
+
[coordinatorSetup.serverName]: {
|
|
1077
|
+
command: 'adhdev-mcp',
|
|
1078
|
+
args: ['--repo-mesh', meshId],
|
|
1079
|
+
},
|
|
1080
|
+
},
|
|
1081
|
+
};
|
|
1082
|
+
writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2), 'utf-8');
|
|
1083
|
+
LOG.info('MeshCoordinator', `Wrote ${mcpConfigPath} with ${coordinatorSetup.serverName} server`);
|
|
1084
|
+
|
|
1085
|
+
// 2. Build coordinator system prompt
|
|
1086
|
+
let systemPrompt = '';
|
|
1087
|
+
try {
|
|
1088
|
+
systemPrompt = buildCoordinatorSystemPrompt({ mesh });
|
|
1089
|
+
} catch {
|
|
1090
|
+
systemPrompt = `You are a Repo Mesh Coordinator for "${mesh.name}". Use the adhdev-mesh MCP tools (mesh_status, mesh_list_nodes, mesh_send_task, mesh_read_chat, mesh_launch_session, etc.) to orchestrate work across ${mesh.nodes.length} node(s).`;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// 3. Launch CLI session via existing cliManager
|
|
1094
|
+
const launchResult: any = await this.deps.cliManager.handleCliCommand('launch_cli', {
|
|
1095
|
+
cliType,
|
|
1096
|
+
dir: workspace,
|
|
1097
|
+
initialPrompt: systemPrompt,
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
if (!launchResult?.success) {
|
|
1101
|
+
return { success: false, error: launchResult?.error || 'Failed to launch CLI session' };
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
LOG.info('MeshCoordinator', `Launched ${cliType} coordinator for mesh ${meshId} in ${workspace}`);
|
|
1105
|
+
return {
|
|
1106
|
+
success: true,
|
|
1107
|
+
meshId,
|
|
1108
|
+
cliType,
|
|
1109
|
+
workspace,
|
|
1110
|
+
sessionId: launchResult.sessionId || launchResult.id,
|
|
1111
|
+
mcpConfigWritten: true,
|
|
1112
|
+
};
|
|
1113
|
+
} catch (e: any) {
|
|
1114
|
+
LOG.error('MeshCoordinator', `Failed: ${e.message}`);
|
|
1115
|
+
return { success: false, error: e.message };
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
|
|
923
1119
|
default:
|
|
924
1120
|
break;
|
|
925
1121
|
}
|
|
@@ -345,6 +345,33 @@ export interface CdpTargetFilter {
|
|
|
345
345
|
|
|
346
346
|
export type ProviderVersionCommand = string | Partial<Record<string, string>>;
|
|
347
347
|
|
|
348
|
+
export type MeshCoordinatorMcpConfigMode = 'auto_import' | 'manual' | 'none';
|
|
349
|
+
export type MeshCoordinatorMcpConfigFormat = 'claude_mcp_json' | 'hermes_config_yaml';
|
|
350
|
+
|
|
351
|
+
export interface ProviderMeshCoordinatorConfig {
|
|
352
|
+
/** Whether ADHDev may select this provider for Repo Mesh coordinator sessions. */
|
|
353
|
+
supported: boolean;
|
|
354
|
+
/** Human-readable reason shown when unsupported or blocked. */
|
|
355
|
+
reason?: string;
|
|
356
|
+
/** How ADHDev mesh MCP tools become visible to the launched CLI. */
|
|
357
|
+
mcpConfig?: {
|
|
358
|
+
mode: MeshCoordinatorMcpConfigMode;
|
|
359
|
+
format?: MeshCoordinatorMcpConfigFormat;
|
|
360
|
+
/** Provider-relative/project-relative config path for auto-import modes, e.g. '.mcp.json'. */
|
|
361
|
+
path?: string;
|
|
362
|
+
/** MCP server name to materialize or display. Defaults to 'adhdev-mesh'. */
|
|
363
|
+
serverName?: string;
|
|
364
|
+
/** Manual setup target path/help command, e.g. 'hermes config path'. */
|
|
365
|
+
configPathCommand?: string;
|
|
366
|
+
/** Whether users need a fresh CLI session after config changes. */
|
|
367
|
+
requiresRestart?: boolean;
|
|
368
|
+
/** User-facing setup explanation for manual modes. */
|
|
369
|
+
instructions?: string;
|
|
370
|
+
/** Copyable setup template. Supports {{meshId}}, {{adhdevMcpCommand}}, {{workspace}}, {{serverName}}. */
|
|
371
|
+
template?: string;
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
348
375
|
export interface ProviderCompatibilityEntry {
|
|
349
376
|
ideVersion: string;
|
|
350
377
|
scriptDir: string;
|
|
@@ -357,6 +384,10 @@ export interface ProviderModule {
|
|
|
357
384
|
name: string;
|
|
358
385
|
/** Category: determines execution method */
|
|
359
386
|
category: ProviderCategory;
|
|
387
|
+
/** When provider-owned, daemon treats provider parser output as canonical transcript authority. */
|
|
388
|
+
transcriptAuthority?: 'provider' | 'daemon';
|
|
389
|
+
/** Full context lets provider-owned parsers canonicalize retained history instead of daemon prefix stitching. */
|
|
390
|
+
transcriptContext?: 'full' | 'tail';
|
|
360
391
|
/** Alias list — allows users to invoke by alternate names (e.g. ['claude', 'claude-code']) */
|
|
361
392
|
aliases?: string[];
|
|
362
393
|
|
|
@@ -555,6 +586,12 @@ export interface ProviderModule {
|
|
|
555
586
|
/** ACP agent auth methods (multiple supported — in priority order) */
|
|
556
587
|
auth?: AcpAuthMethod[];
|
|
557
588
|
|
|
589
|
+
/**
|
|
590
|
+
* Repo Mesh coordinator capability and MCP ingestion behavior.
|
|
591
|
+
* Providers must declare this rather than relying on daemon hardcoded CLI quirks.
|
|
592
|
+
*/
|
|
593
|
+
meshCoordinator?: ProviderMeshCoordinatorConfig;
|
|
594
|
+
|
|
558
595
|
// ─── Contract version / capability declaration ───
|
|
559
596
|
contractVersion?: number;
|
|
560
597
|
capabilities?: {
|
|
@@ -7,6 +7,8 @@ const KNOWN_PROVIDER_FIELDS = new Set<string>([
|
|
|
7
7
|
'type',
|
|
8
8
|
'name',
|
|
9
9
|
'category',
|
|
10
|
+
'transcriptAuthority',
|
|
11
|
+
'transcriptContext',
|
|
10
12
|
'aliases',
|
|
11
13
|
'cdpPorts',
|
|
12
14
|
'targetFilter',
|
|
@@ -51,6 +53,7 @@ const KNOWN_PROVIDER_FIELDS = new Set<string>([
|
|
|
51
53
|
'staticConfigOptions',
|
|
52
54
|
'spawnArgBuilder',
|
|
53
55
|
'auth',
|
|
56
|
+
'meshCoordinator',
|
|
54
57
|
'contractVersion',
|
|
55
58
|
'capabilities',
|
|
56
59
|
'providerVersion',
|
|
@@ -125,6 +128,7 @@ export function validateProviderDefinition(raw: unknown): ProviderValidationResu
|
|
|
125
128
|
|
|
126
129
|
validateCapabilities(provider as unknown as ProviderModule, controls, errors)
|
|
127
130
|
validateCanonicalHistory(provider.canonicalHistory, errors)
|
|
131
|
+
validateMeshCoordinator(provider.meshCoordinator, errors)
|
|
128
132
|
|
|
129
133
|
for (const control of controls) {
|
|
130
134
|
validateControl(control as ProviderControlDef, errors)
|
|
@@ -233,6 +237,69 @@ function validateCanonicalHistory(raw: unknown, errors: string[]): void {
|
|
|
233
237
|
}
|
|
234
238
|
}
|
|
235
239
|
|
|
240
|
+
function validateMeshCoordinator(raw: unknown, errors: string[]): void {
|
|
241
|
+
if (raw === undefined) return
|
|
242
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
243
|
+
errors.push('meshCoordinator must be an object')
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const meshCoordinator = raw as Record<string, unknown>
|
|
248
|
+
if (typeof meshCoordinator.supported !== 'boolean') {
|
|
249
|
+
errors.push('meshCoordinator.supported must be boolean')
|
|
250
|
+
}
|
|
251
|
+
if (meshCoordinator.reason !== undefined && (typeof meshCoordinator.reason !== 'string' || !meshCoordinator.reason.trim())) {
|
|
252
|
+
errors.push('meshCoordinator.reason must be a non-empty string when provided')
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const mcpConfig = meshCoordinator.mcpConfig
|
|
256
|
+
if (mcpConfig === undefined) return
|
|
257
|
+
if (!mcpConfig || typeof mcpConfig !== 'object' || Array.isArray(mcpConfig)) {
|
|
258
|
+
errors.push('meshCoordinator.mcpConfig must be an object')
|
|
259
|
+
return
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const config = mcpConfig as Record<string, unknown>
|
|
263
|
+
const mode = config.mode
|
|
264
|
+
if (!['auto_import', 'manual', 'none'].includes(String(mode))) {
|
|
265
|
+
errors.push('meshCoordinator.mcpConfig.mode must be one of: auto_import, manual, none')
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const format = config.format
|
|
269
|
+
if (format !== undefined && !['claude_mcp_json', 'hermes_config_yaml'].includes(String(format))) {
|
|
270
|
+
errors.push('meshCoordinator.mcpConfig.format must be one of: claude_mcp_json, hermes_config_yaml')
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
for (const key of ['path', 'serverName', 'configPathCommand', 'instructions', 'template']) {
|
|
274
|
+
const value = config[key]
|
|
275
|
+
if (value !== undefined && (typeof value !== 'string' || !value.trim())) {
|
|
276
|
+
errors.push(`meshCoordinator.mcpConfig.${key} must be a non-empty string when provided`)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (config.requiresRestart !== undefined && typeof config.requiresRestart !== 'boolean') {
|
|
281
|
+
errors.push('meshCoordinator.mcpConfig.requiresRestart must be boolean when provided')
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (mode === 'auto_import') {
|
|
285
|
+
if (format === undefined) {
|
|
286
|
+
errors.push('meshCoordinator.mcpConfig.format is required for auto_import MCP setup')
|
|
287
|
+
}
|
|
288
|
+
if (typeof config.path !== 'string' || !config.path.trim()) {
|
|
289
|
+
errors.push('meshCoordinator.mcpConfig.path is required for auto_import MCP setup')
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (mode === 'manual') {
|
|
294
|
+
if (typeof config.instructions !== 'string' || !config.instructions.trim()) {
|
|
295
|
+
errors.push('meshCoordinator.mcpConfig.instructions is required for manual MCP setup')
|
|
296
|
+
}
|
|
297
|
+
if (typeof config.template !== 'string' || !config.template.trim()) {
|
|
298
|
+
errors.push('meshCoordinator.mcpConfig.template is required for manual MCP setup')
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
236
303
|
function validateControl(control: ProviderControlDef, errors: string[]): void {
|
|
237
304
|
if (!control || typeof control !== 'object') {
|
|
238
305
|
errors.push('controls: each control must be an object')
|
package/src/shared-types.ts
CHANGED
|
@@ -43,7 +43,7 @@ export type { ProviderErrorReason } from './providers/provider-instance.js';
|
|
|
43
43
|
// Local import for use in Managed*Entry types below
|
|
44
44
|
import type { ActiveChatData as _ActiveChatData, ProviderErrorReason as _ProviderErrorReason } from './providers/provider-instance.js';
|
|
45
45
|
import type { WorkspaceEntry } from './config/workspaces.js';
|
|
46
|
-
import type { ProviderResumeCapability } from './providers/contracts.js';
|
|
46
|
+
import type { ProviderMeshCoordinatorConfig, ProviderResumeCapability } from './providers/contracts.js';
|
|
47
47
|
import type {
|
|
48
48
|
GitCompactSummary,
|
|
49
49
|
GitDiffSummary,
|
|
@@ -447,6 +447,8 @@ export interface AvailableProviderInfo {
|
|
|
447
447
|
lastDetection?: MachineProviderCheckResult;
|
|
448
448
|
/** Last end-to-end ADHDev verification result, when available. */
|
|
449
449
|
lastVerification?: MachineProviderCheckResult;
|
|
450
|
+
/** Provider-declared Repo Mesh coordinator/MCP behavior. */
|
|
451
|
+
meshCoordinator?: ProviderMeshCoordinatorConfig;
|
|
450
452
|
}
|
|
451
453
|
|
|
452
454
|
export interface MachineProviderCheckResult {
|
package/src/status/snapshot.ts
CHANGED
|
@@ -144,6 +144,7 @@ function buildAvailableProviders(
|
|
|
144
144
|
machineStatus?: 'disabled' | 'enabled_unchecked' | 'not_detected' | 'detected';
|
|
145
145
|
lastDetection?: AvailableProviderInfo['lastDetection'];
|
|
146
146
|
lastVerification?: AvailableProviderInfo['lastVerification'];
|
|
147
|
+
meshCoordinator?: AvailableProviderInfo['meshCoordinator'];
|
|
147
148
|
}> = providerLoader.getAvailableProviderInfos?.() || providerLoader.getAll();
|
|
148
149
|
return providers.map((provider) => ({
|
|
149
150
|
type: provider.type,
|
|
@@ -157,6 +158,7 @@ function buildAvailableProviders(
|
|
|
157
158
|
...(provider.machineStatus !== undefined ? { machineStatus: provider.machineStatus } : {}),
|
|
158
159
|
...(provider.lastDetection !== undefined ? { lastDetection: provider.lastDetection } : {}),
|
|
159
160
|
...(provider.lastVerification !== undefined ? { lastVerification: provider.lastVerification } : {}),
|
|
161
|
+
...(provider.meshCoordinator !== undefined ? { meshCoordinator: provider.meshCoordinator } : {}),
|
|
160
162
|
}));
|
|
161
163
|
}
|
|
162
164
|
|