@adhdev/daemon-core 0.9.77-rc.9 → 0.9.78

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 (50) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +3 -0
  2. package/dist/cli-adapters/provider-cli-adapter.d.ts +2 -0
  3. package/dist/commands/mesh-coordinator.d.ts +10 -0
  4. package/dist/commands/router.d.ts +4 -1
  5. package/dist/config/mesh-config.d.ts +1 -0
  6. package/dist/git/git-worktree.d.ts +15 -2
  7. package/dist/index.d.ts +11 -6
  8. package/dist/index.js +2117 -300
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.mjs +2102 -300
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/mesh/mesh-events.d.ts +14 -7
  13. package/dist/mesh/mesh-ledger-reconciliation.d.ts +55 -0
  14. package/dist/mesh/mesh-ledger.d.ts +84 -4
  15. package/dist/mesh/mesh-sync.d.ts +4 -12
  16. package/dist/mesh/mesh-visualization.d.ts +70 -0
  17. package/dist/mesh/mesh-work-queue.d.ts +58 -1
  18. package/dist/mesh/p2p-relay-failure.d.ts +35 -0
  19. package/dist/providers/chat-message-normalization.d.ts +1 -0
  20. package/dist/providers/cli-provider-instance.d.ts +6 -0
  21. package/dist/repo-mesh-types.d.ts +2 -0
  22. package/dist/shared-types.d.ts +38 -0
  23. package/package.json +1 -1
  24. package/src/boot/daemon-lifecycle.ts +5 -0
  25. package/src/cli-adapters/provider-cli-adapter.ts +30 -5
  26. package/src/commands/cli-manager.ts +0 -4
  27. package/src/commands/mesh-coordinator.ts +55 -7
  28. package/src/commands/router.ts +964 -26
  29. package/src/commands/stream-commands.ts +8 -1
  30. package/src/config/config.ts +2 -1
  31. package/src/config/mesh-config.ts +2 -0
  32. package/src/config/workspaces.ts +1 -1
  33. package/src/git/git-worktree.ts +56 -4
  34. package/src/index.d.ts +3 -0
  35. package/src/index.ts +30 -6
  36. package/src/mesh/coordinator-prompt.ts +21 -10
  37. package/src/mesh/mesh-events.ts +532 -22
  38. package/src/mesh/mesh-ledger-reconciliation.ts +115 -0
  39. package/src/mesh/mesh-ledger.ts +209 -8
  40. package/src/mesh/mesh-sync.ts +4 -34
  41. package/src/mesh/mesh-visualization.ts +341 -0
  42. package/src/mesh/mesh-work-queue.ts +183 -17
  43. package/src/mesh/p2p-relay-failure.ts +152 -0
  44. package/src/providers/acp-provider-instance.ts +2 -1
  45. package/src/providers/chat-message-normalization.ts +33 -1
  46. package/src/providers/cli-provider-instance.ts +155 -31
  47. package/src/providers/extension-provider-instance.ts +2 -1
  48. package/src/providers/ide-provider-instance.ts +2 -2
  49. package/src/repo-mesh-types.ts +2 -0
  50. package/src/shared-types.ts +38 -0
@@ -225,6 +225,7 @@ export class ProviderCliAdapter implements CliAdapter {
225
225
  currentTurnScope: TurnParseScope | null;
226
226
  recentOutputBuffer: string;
227
227
  accumulatedBuffer: string;
228
+ accumulatedRawBufferKey: string;
228
229
  screenText: string;
229
230
  currentStatus: CliSessionStatus['status'];
230
231
  activeModal: { message: string; buttons: string[] } | null;
@@ -299,14 +300,23 @@ export class ProviderCliAdapter implements CliAdapter {
299
300
  this.lastScreenSnapshotReadAt = Number.NEGATIVE_INFINITY;
300
301
  }
301
302
 
303
+ private getAccumulatedRawBufferCacheKey(): string {
304
+ return this.accumulatedRawBuffer
305
+ .replace(/\x1B\][^\x07]*(?:\x07|\x1B\\)/g, '')
306
+ .replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, '')
307
+ .replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, '');
308
+ }
309
+
302
310
  private getFreshParsedStatusCache(): any | null {
303
311
  const cached = this.parsedStatusCache;
312
+ const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
304
313
  if (
305
314
  cached
306
315
  && cached.responseBuffer === this.responseBuffer
307
316
  && cached.currentTurnScope === this.currentTurnScope
308
317
  && cached.recentOutputBuffer === this.recentOutputBuffer
309
318
  && cached.accumulatedBuffer === this.accumulatedBuffer
319
+ && cached.accumulatedRawBufferKey === accumulatedRawBufferKey
310
320
  && cached.screenText === this.lastScreenText
311
321
  && cached.currentStatus === this.currentStatus
312
322
  && cached.activeModal === this.activeModal
@@ -450,6 +460,7 @@ export class ProviderCliAdapter implements CliAdapter {
450
460
 
451
461
  // Scripts are required — loaded by ProviderLoader via compatibility array
452
462
  this.cliScripts = provider.scripts || {};
463
+ this.scriptState = typeof this.cliScripts.createState === 'function' ? (this.cliScripts.createState() ?? null) : null;
453
464
  const scriptNames = listCliScriptNames(this.cliScripts);
454
465
  if (scriptNames.length > 0) {
455
466
  LOG.info('CLI', `[${this.cliType}] CLI scripts: [${scriptNames.join(', ')}]`);
@@ -481,7 +492,7 @@ export class ProviderCliAdapter implements CliAdapter {
481
492
  this.parseErrorMessage = null;
482
493
  // Initialize per-session state: createState() is called once here and on script reload.
483
494
  // The returned object lives until the PTY exits (scriptState = null on exit).
484
- this.scriptState = typeof scripts.createState === 'function' ? scripts.createState() : null;
495
+ this.scriptState = typeof scripts.createState === 'function' ? (scripts.createState() ?? null) : null;
485
496
  const scriptNames = listCliScriptNames(scripts);
486
497
  LOG.info('CLI', `[${this.cliType}] CLI scripts injected: [${scriptNames.join(', ')}]`);
487
498
  }
@@ -1456,6 +1467,14 @@ export class ProviderCliAdapter implements CliAdapter {
1456
1467
 
1457
1468
  // ─── Script Execution ──────────────────────────
1458
1469
 
1470
+ private invokeCliScript<T>(script: Function, input: any): T {
1471
+ const hasStateFactory = typeof this.cliScripts?.createState === 'function';
1472
+ const expectsStateArgument = hasStateFactory || this.scriptState !== null || script.length >= 2;
1473
+ return expectsStateArgument
1474
+ ? script(this.scriptState, input)
1475
+ : script(input);
1476
+ }
1477
+
1459
1478
  private runParseSession(): ParsedSession | null {
1460
1479
  if (typeof this.cliScripts?.parseSession !== 'function') {
1461
1480
  this.parseErrorMessage = `${this.cliType} parseSession unavailable`;
@@ -1476,7 +1495,10 @@ export class ProviderCliAdapter implements CliAdapter {
1476
1495
  scope: this.currentTurnScope,
1477
1496
  runtimeSettings: this.runtimeSettings,
1478
1497
  });
1479
- const session = this.cliScripts.parseSession(this.scriptState, { ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
1498
+ const session = this.invokeCliScript<ParsedSession | null>(
1499
+ this.cliScripts.parseSession,
1500
+ { ...input, tail, tailScreen: buildCliScreenSnapshot(tail) },
1501
+ );
1480
1502
  this.parseErrorMessage = null;
1481
1503
  return session && typeof session === 'object' ? session : null;
1482
1504
  } catch (e: any) {
@@ -1491,7 +1513,7 @@ export class ProviderCliAdapter implements CliAdapter {
1491
1513
  if (!this.cliScripts?.detectStatus) return null;
1492
1514
  try {
1493
1515
  const screenText = this.terminalScreen.getText();
1494
- const status = this.cliScripts.detectStatus(this.scriptState, {
1516
+ const status = this.invokeCliScript<string | null>(this.cliScripts.detectStatus, {
1495
1517
  tail: text.slice(-500),
1496
1518
  screenText,
1497
1519
  rawBuffer: this.accumulatedRawBuffer,
@@ -1511,7 +1533,7 @@ export class ProviderCliAdapter implements CliAdapter {
1511
1533
  try {
1512
1534
  const screenText = this.terminalScreen.getText();
1513
1535
  const buffer = screenText || this.accumulatedBuffer;
1514
- return this.cliScripts.parseApproval(this.scriptState, {
1536
+ return this.invokeCliScript<{ message: string; buttons: string[] } | null>(this.cliScripts.parseApproval, {
1515
1537
  buffer,
1516
1538
  screenText,
1517
1539
  rawBuffer: this.accumulatedRawBuffer,
@@ -1576,12 +1598,14 @@ export class ProviderCliAdapter implements CliAdapter {
1576
1598
  const screenText = this.readTerminalScreenText();
1577
1599
  const parseScreenText = this.getParseScreenText(screenText);
1578
1600
  const cached = this.parsedStatusCache;
1601
+ const accumulatedRawBufferKey = this.getAccumulatedRawBufferCacheKey();
1579
1602
  if (
1580
1603
  cached
1581
1604
  && cached.responseBuffer === this.responseBuffer
1582
1605
  && cached.currentTurnScope === this.currentTurnScope
1583
1606
  && cached.recentOutputBuffer === this.recentOutputBuffer
1584
1607
  && cached.accumulatedBuffer === this.accumulatedBuffer
1608
+ && cached.accumulatedRawBufferKey === accumulatedRawBufferKey
1585
1609
  && cached.screenText === parseScreenText
1586
1610
  && cached.currentStatus === this.currentStatus
1587
1611
  && cached.activeModal === this.activeModal
@@ -1621,6 +1645,7 @@ export class ProviderCliAdapter implements CliAdapter {
1621
1645
  currentTurnScope: this.currentTurnScope,
1622
1646
  recentOutputBuffer: this.recentOutputBuffer,
1623
1647
  accumulatedBuffer: this.accumulatedBuffer,
1648
+ accumulatedRawBufferKey,
1624
1649
  screenText: parseScreenText,
1625
1650
  currentStatus: this.currentStatus,
1626
1651
  activeModal: this.activeModal,
@@ -1646,7 +1671,7 @@ export class ProviderCliAdapter implements CliAdapter {
1646
1671
  scope: this.currentTurnScope,
1647
1672
  runtimeSettings: this.runtimeSettings,
1648
1673
  });
1649
- return await Promise.resolve(fn(this.scriptState, {
1674
+ return await Promise.resolve(this.invokeCliScript(fn, {
1650
1675
  ...input,
1651
1676
  args: args && typeof args === 'object' ? { ...args } : {},
1652
1677
  }));
@@ -177,10 +177,6 @@ export function buildCoordinatorDelegatedCliLaunchOptions(
177
177
  const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
178
178
  const env: Record<string, string> = { ...(input.env || {}), ...COORDINATOR_DELEGATED_ENV_UNSETS };
179
179
 
180
- if (cliType === 'hermes-cli' && !hasCliArg(cliArgs, '--ignore-user-config')) {
181
- cliArgs.unshift('--ignore-user-config');
182
- }
183
-
184
180
  if (cliType === 'claude-cli' && !hasCliArg(cliArgs, '--mcp-config')) {
185
181
  cliArgs.unshift('--mcp-config', ensureEmptyDelegatedMcpConfig(input.workspace));
186
182
  }
@@ -28,6 +28,15 @@ export type MeshCoordinatorSetup =
28
28
  instructions: string
29
29
  template: string
30
30
  }
31
+ | {
32
+ /** Provider registers MCP via its own CLI command (e.g. `codex mcp add` / `gemini mcp add`). */
33
+ kind: 'cli_command'
34
+ serverName: string
35
+ /** The rendered shell command to execute before launching the coordinator session. */
36
+ command: string
37
+ requiresRestart: boolean
38
+ instructions: string
39
+ }
31
40
  | {
32
41
  kind: 'unsupported'
33
42
  reason: string
@@ -41,6 +50,8 @@ export interface ResolveMeshCoordinatorSetupOptions {
41
50
  adhdevMcpCommand?: string
42
51
  adhdevMcpEntryPath?: string
43
52
  nodeExecutable?: string
53
+ adhdevMcpTransport?: 'local' | 'ipc'
54
+ adhdevMcpPort?: number
44
55
  }
45
56
 
46
57
  const DEFAULT_SERVER_NAME = 'adhdev-mesh'
@@ -58,6 +69,8 @@ function resolveHermesMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetupO
58
69
  meshId: options.meshId,
59
70
  nodeExecutable: options.nodeExecutable,
60
71
  adhdevMcpEntryPath: options.adhdevMcpEntryPath,
72
+ adhdevMcpTransport: options.adhdevMcpTransport,
73
+ adhdevMcpPort: options.adhdevMcpPort,
61
74
  })
62
75
  if (!mcpServer) {
63
76
  return {
@@ -130,6 +143,8 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
130
143
  meshId,
131
144
  nodeExecutable: options.nodeExecutable,
132
145
  adhdevMcpEntryPath: options.adhdevMcpEntryPath,
146
+ adhdevMcpTransport: options.adhdevMcpTransport,
147
+ adhdevMcpPort: options.adhdevMcpPort,
133
148
  })
134
149
  if (!mcpServer) {
135
150
  return {
@@ -152,6 +167,24 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
152
167
  if (!instructions || !template?.trim()) {
153
168
  return { kind: 'unsupported', reason: 'Provider manual MCP setup is missing instructions or template' }
154
169
  }
170
+ const renderedTemplate = renderMeshCoordinatorTemplate(template, {
171
+ meshId,
172
+ workspace,
173
+ serverName,
174
+ adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND,
175
+ })
176
+ // Detect if the template is a runnable CLI command (single line, no YAML/JSON structure).
177
+ // If so, use cli_command kind so the daemon can execute it automatically.
178
+ const isCliCommand = !renderedTemplate.trim().includes('\n') && !renderedTemplate.trim().startsWith('{')
179
+ if (isCliCommand) {
180
+ return {
181
+ kind: 'cli_command',
182
+ serverName,
183
+ command: renderedTemplate.trim(),
184
+ requiresRestart: mcpConfig.requiresRestart === true,
185
+ instructions: instructions,
186
+ }
187
+ }
155
188
  return {
156
189
  kind: 'manual',
157
190
  serverName,
@@ -159,12 +192,7 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
159
192
  configPathCommand: mcpConfig.configPathCommand,
160
193
  requiresRestart: mcpConfig.requiresRestart === true,
161
194
  instructions,
162
- template: renderMeshCoordinatorTemplate(template, {
163
- meshId,
164
- workspace,
165
- serverName,
166
- adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND,
167
- }),
195
+ template: renderedTemplate,
168
196
  }
169
197
  }
170
198
 
@@ -196,17 +224,37 @@ function resolveAdhdevMcpServerLaunch(options: {
196
224
  meshId: string
197
225
  nodeExecutable?: string
198
226
  adhdevMcpEntryPath?: string
227
+ adhdevMcpTransport?: 'local' | 'ipc'
228
+ adhdevMcpPort?: number
199
229
  }): MeshCoordinatorMcpServerLaunch | null {
200
230
  const entryPath = resolveAdhdevMcpEntryPath(options.adhdevMcpEntryPath)
201
231
  if (!entryPath) return null
202
232
  const nodeExecutable = resolveMcpNodeExecutable(options.nodeExecutable)
203
233
  if (!nodeExecutable) return null
234
+ const transport = resolveMcpTransport(options.adhdevMcpTransport)
235
+ const args = [entryPath, '--mode', transport, '--repo-mesh', options.meshId]
236
+ const port = resolveMcpPort(options.adhdevMcpPort)
237
+ if (port !== undefined) args.push('--port', String(port))
204
238
  return {
205
239
  command: nodeExecutable,
206
- args: [entryPath, '--mode', 'ipc', '--repo-mesh', options.meshId],
240
+ args,
207
241
  }
208
242
  }
209
243
 
244
+ function resolveMcpTransport(explicitTransport?: 'local' | 'ipc'): 'local' | 'ipc' {
245
+ if (explicitTransport === 'local' || explicitTransport === 'ipc') return explicitTransport
246
+ const envTransport = process.env.ADHDEV_COORDINATOR_MCP_TRANSPORT?.trim()
247
+ return envTransport === 'local' ? 'local' : 'ipc'
248
+ }
249
+
250
+ function resolveMcpPort(explicitPort?: number): number | undefined {
251
+ if (typeof explicitPort === 'number' && Number.isInteger(explicitPort) && explicitPort > 0) return explicitPort
252
+ const raw = process.env.ADHDEV_COORDINATOR_MCP_PORT?.trim()
253
+ if (!raw) return undefined
254
+ const parsed = Number(raw)
255
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined
256
+ }
257
+
210
258
  function resolveMcpNodeExecutable(explicitExecutable?: string): string | null {
211
259
  const explicit = explicitExecutable?.trim()
212
260
  if (explicit) return explicit