@adhdev/daemon-core 0.9.76-rc.5 → 0.9.76-rc.50

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.
Files changed (46) hide show
  1. package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -1
  2. package/dist/cli-adapters/provider-cli-runtime.d.ts +1 -0
  3. package/dist/commands/cli-manager.d.ts +17 -4
  4. package/dist/commands/mesh-coordinator.d.ts +2 -0
  5. package/dist/commands/router.d.ts +11 -0
  6. package/dist/config/mesh-config.d.ts +3 -0
  7. package/dist/git/git-types.d.ts +1 -1
  8. package/dist/git/git-worktree.d.ts +64 -0
  9. package/dist/git/index.d.ts +2 -0
  10. package/dist/index.js +1382 -430
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +1409 -461
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/mesh/coordinator-prompt.d.ts +1 -0
  15. package/dist/mesh/mesh-events.d.ts +9 -0
  16. package/dist/providers/chat-message-normalization.d.ts +11 -0
  17. package/dist/providers/cli-provider-instance.d.ts +3 -0
  18. package/dist/providers/provider-instance-manager.d.ts +1 -0
  19. package/dist/providers/provider-instance.d.ts +2 -0
  20. package/dist/repo-mesh-types.d.ts +13 -0
  21. package/dist/shared-types.d.ts +4 -0
  22. package/package.json +4 -5
  23. package/src/cli-adapters/provider-cli-adapter.ts +28 -7
  24. package/src/cli-adapters/provider-cli-runtime.ts +3 -2
  25. package/src/commands/chat-commands.ts +94 -8
  26. package/src/commands/cli-manager.ts +78 -5
  27. package/src/commands/handler.ts +13 -4
  28. package/src/commands/mesh-coordinator.ts +149 -6
  29. package/src/commands/router.d.ts +1 -0
  30. package/src/commands/router.ts +554 -34
  31. package/src/config/mesh-config.ts +23 -2
  32. package/src/git/git-commands.ts +5 -1
  33. package/src/git/git-types.ts +1 -0
  34. package/src/git/git-worktree.ts +214 -0
  35. package/src/git/index.ts +14 -0
  36. package/src/mesh/coordinator-prompt.ts +25 -10
  37. package/src/mesh/mesh-events.ts +109 -43
  38. package/src/providers/chat-message-normalization.ts +54 -0
  39. package/src/providers/cli-provider-instance.d.ts +2 -0
  40. package/src/providers/cli-provider-instance.ts +55 -7
  41. package/src/providers/provider-instance-manager.ts +20 -1
  42. package/src/providers/provider-instance.ts +2 -0
  43. package/src/repo-mesh-types.ts +15 -0
  44. package/src/shared-types.ts +4 -0
  45. package/src/status/builders.ts +17 -12
  46. package/src/status/reporter.ts +6 -0
@@ -1,6 +1,8 @@
1
- import { existsSync, realpathSync } from 'node:fs'
1
+ import { execFileSync } from 'node:child_process'
2
+ import { existsSync, readdirSync, realpathSync } from 'node:fs'
2
3
  import { createRequire } from 'node:module'
3
- import { dirname, join, resolve } from 'node:path'
4
+ import * as os from 'node:os'
5
+ import { dirname, isAbsolute, join, resolve } from 'node:path'
4
6
  import type { ProviderModule, MeshCoordinatorMcpConfigFormat } from '../providers/contracts.js'
5
7
 
6
8
  export interface MeshCoordinatorMcpServerLaunch {
@@ -32,6 +34,7 @@ export type MeshCoordinatorSetup =
32
34
 
33
35
  export interface ResolveMeshCoordinatorSetupOptions {
34
36
  provider?: ProviderModule | null
37
+ cliType?: string
35
38
  meshId: string
36
39
  workspace: string
37
40
  adhdevMcpCommand?: string
@@ -41,6 +44,58 @@ export interface ResolveMeshCoordinatorSetupOptions {
41
44
 
42
45
  const DEFAULT_SERVER_NAME = 'adhdev-mesh'
43
46
  const DEFAULT_ADHDEV_MCP_COMMAND = 'adhdev-mcp'
47
+ const HERMES_CLI_TYPE = 'hermes-cli'
48
+ const HERMES_MCP_CONFIG_PATH = '~/.hermes/config.yaml'
49
+
50
+ function isHermesProvider(provider: ProviderModule | null | undefined, cliType?: string): boolean {
51
+ const type = cliType?.trim() || provider?.type?.trim() || ''
52
+ return type === HERMES_CLI_TYPE
53
+ }
54
+
55
+ function resolveHermesMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetupOptions): MeshCoordinatorSetup {
56
+ const mcpServer = resolveAdhdevMcpServerLaunch({
57
+ meshId: options.meshId,
58
+ nodeExecutable: options.nodeExecutable,
59
+ adhdevMcpEntryPath: options.adhdevMcpEntryPath,
60
+ })
61
+ if (!mcpServer) {
62
+ return {
63
+ kind: 'unsupported',
64
+ reason: 'Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode',
65
+ }
66
+ }
67
+ const configPath = resolveMcpConfigPath(HERMES_MCP_CONFIG_PATH, options.workspace)
68
+ if (!configPath.trim()) {
69
+ return createHermesManualMeshCoordinatorSetup(options.meshId, options.workspace)
70
+ }
71
+ return {
72
+ kind: 'auto_import',
73
+ serverName: DEFAULT_SERVER_NAME,
74
+ configPath,
75
+ configFormat: 'hermes_config_yaml',
76
+ mcpServer,
77
+ }
78
+ }
79
+
80
+ export function createHermesManualMeshCoordinatorSetup(meshId: string, workspace: string): MeshCoordinatorSetup {
81
+ return {
82
+ kind: 'manual',
83
+ serverName: DEFAULT_SERVER_NAME,
84
+ configFormat: 'hermes_config_yaml',
85
+ configPathCommand: HERMES_MCP_CONFIG_PATH,
86
+ requiresRestart: true,
87
+ instructions: 'Hermes CLI does not auto-import repo-local .mcp.json. Add this MCP server to Hermes config under mcp_servers, then start a fresh Hermes session.',
88
+ template: renderMeshCoordinatorTemplate(
89
+ 'mcp_servers:\n {{serverName}}:\n command: {{adhdevMcpCommand}}\n args:\n - --repo-mesh\n - {{meshId}}\n enabled: true\n',
90
+ {
91
+ meshId,
92
+ workspace,
93
+ serverName: DEFAULT_SERVER_NAME,
94
+ adhdevMcpCommand: DEFAULT_ADHDEV_MCP_COMMAND,
95
+ },
96
+ ),
97
+ }
98
+ }
44
99
 
45
100
  export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetupOptions): MeshCoordinatorSetup {
46
101
  const { provider, meshId, workspace } = options
@@ -52,6 +107,10 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
52
107
  }
53
108
  }
54
109
 
110
+ if (isHermesProvider(provider, options.cliType)) {
111
+ return resolveHermesMeshCoordinatorSetup(options)
112
+ }
113
+
55
114
  const mcpConfig = config.mcpConfig
56
115
  if (!mcpConfig || mcpConfig.mode === 'none') {
57
116
  return {
@@ -74,13 +133,13 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
74
133
  if (!mcpServer) {
75
134
  return {
76
135
  kind: 'unsupported',
77
- reason: 'Could not resolve the ADHDev MCP server entrypoint without relying on a PATH bin shim',
136
+ reason: 'Could not resolve the ADHDev MCP server entrypoint and a Node runtime with WebSocket support for daemon IPC mode',
78
137
  }
79
138
  }
80
139
  return {
81
140
  kind: 'auto_import',
82
141
  serverName,
83
- configPath: join(workspace, path),
142
+ configPath: resolveMcpConfigPath(path, workspace),
84
143
  configFormat: mcpConfig.format,
85
144
  mcpServer,
86
145
  }
@@ -118,6 +177,14 @@ function renderMeshCoordinatorTemplate(template: string, values: Record<string,
118
177
  return template.replace(/\{\{\s*(meshId|workspace|serverName|adhdevMcpCommand)\s*\}\}/g, (_, key: string) => values[key] || '')
119
178
  }
120
179
 
180
+ function resolveMcpConfigPath(configPath: string, workspace: string): string {
181
+ const trimmed = configPath.trim()
182
+ if (trimmed === '~') return os.homedir()
183
+ if (trimmed.startsWith('~/')) return join(os.homedir(), trimmed.slice(2))
184
+ if (isAbsolute(trimmed)) return trimmed
185
+ return join(workspace, trimmed)
186
+ }
187
+
121
188
  function resolveAdhdevMcpServerLaunch(options: {
122
189
  meshId: string
123
190
  nodeExecutable?: string
@@ -125,9 +192,85 @@ function resolveAdhdevMcpServerLaunch(options: {
125
192
  }): MeshCoordinatorMcpServerLaunch | null {
126
193
  const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath)
127
194
  if (!entryPath) return null
195
+ const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable)
196
+ if (!nodeExecutable) return null
128
197
  return {
129
- command: options.nodeExecutable?.trim() || process.execPath,
130
- args: [entryPath, '--repo-mesh', options.meshId],
198
+ command: nodeExecutable,
199
+ args: [entryPath, '--mode', 'ipc', '--repo-mesh', options.meshId],
200
+ }
201
+ }
202
+
203
+ function resolveMcpNodeExecutable(explicitExecutable?: string): string | null {
204
+ const explicit = explicitExecutable?.trim()
205
+ if (explicit) return explicit
206
+
207
+ const candidates: string[] = []
208
+ const addCandidate = (candidate?: string | null) => {
209
+ const trimmed = candidate?.trim()
210
+ if (!trimmed) return
211
+ const normalized = normalizeExistingPath(trimmed) || trimmed
212
+ if (!candidates.includes(normalized)) candidates.push(normalized)
213
+ }
214
+
215
+ addCandidate(process.env.ADHDEV_MCP_NODE_EXECUTABLE)
216
+ addCandidate(process.env.ADHDEV_NODE_EXECUTABLE)
217
+ addCandidate(process.env.npm_node_execpath)
218
+ addNodeCandidatesFromPath(process.env.PATH, addCandidate)
219
+ addNodeCandidatesFromNvm(os.homedir(), addCandidate)
220
+ addCandidate('/opt/homebrew/bin/node')
221
+ addCandidate('/usr/local/bin/node')
222
+ addCandidate('/usr/bin/node')
223
+ addCandidate(process.execPath)
224
+
225
+ for (const candidate of candidates) {
226
+ if (nodeRuntimeSupportsWebSocket(candidate)) return candidate
227
+ }
228
+ return null
229
+ }
230
+
231
+ function addNodeCandidatesFromPath(pathValue: string | undefined, addCandidate: (candidate?: string | null) => void) {
232
+ for (const entry of (pathValue || '').split(':')) {
233
+ const dir = entry.trim()
234
+ if (!dir) continue
235
+ addCandidate(join(dir, 'node'))
236
+ }
237
+ }
238
+
239
+ function addNodeCandidatesFromNvm(homeDir: string, addCandidate: (candidate?: string | null) => void) {
240
+ const versionsDir = join(homeDir, '.nvm', 'versions', 'node')
241
+ try {
242
+ const versionDirs = readdirSync(versionsDir, { withFileTypes: true })
243
+ .filter((entry) => entry.isDirectory())
244
+ .map((entry) => entry.name)
245
+ .sort(compareNodeVersionNamesDescending)
246
+ for (const versionDir of versionDirs) {
247
+ addCandidate(join(versionsDir, versionDir, 'bin', 'node'))
248
+ }
249
+ } catch {
250
+ // nvm is optional; PATH and process.execPath candidates still cover normal installs.
251
+ }
252
+ }
253
+
254
+ function compareNodeVersionNamesDescending(a: string, b: string): number {
255
+ const parse = (value: string) => value.replace(/^v/, '').split('.').map((part) => Number.parseInt(part, 10) || 0)
256
+ const left = parse(a)
257
+ const right = parse(b)
258
+ for (let i = 0; i < Math.max(left.length, right.length); i++) {
259
+ const diff = (right[i] || 0) - (left[i] || 0)
260
+ if (diff !== 0) return diff
261
+ }
262
+ return b.localeCompare(a)
263
+ }
264
+
265
+ function nodeRuntimeSupportsWebSocket(nodeExecutable: string): boolean {
266
+ try {
267
+ execFileSync(nodeExecutable, ['-e', "process.exit(typeof WebSocket === 'function' ? 0 : 42)"], {
268
+ stdio: 'ignore',
269
+ timeout: 3000,
270
+ })
271
+ return true
272
+ } catch {
273
+ return false
131
274
  }
132
275
  }
133
276
 
@@ -21,6 +21,7 @@ export interface SessionHostControlPlane {
21
21
  }): Promise<any>;
22
22
  listSessions(): Promise<any[]>;
23
23
  stopSession(sessionId: string): Promise<any>;
24
+ deleteSession(sessionId: string, opts?: { force?: boolean }): Promise<any>;
24
25
  resumeSession(sessionId: string): Promise<any>;
25
26
  restartSession(sessionId: string): Promise<any>;
26
27
  sendSignal(sessionId: string, signal: string): Promise<any>;