@adhdev/daemon-core 0.9.77-rc.10 → 0.9.77-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adhdev/daemon-core",
3
- "version": "0.9.77-rc.10",
3
+ "version": "0.9.77-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",
@@ -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
@@ -152,6 +161,24 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
152
161
  if (!instructions || !template?.trim()) {
153
162
  return { kind: 'unsupported', reason: 'Provider manual MCP setup is missing instructions or template' }
154
163
  }
164
+ const renderedTemplate = renderMeshCoordinatorTemplate(template, {
165
+ meshId,
166
+ workspace,
167
+ serverName,
168
+ adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND,
169
+ })
170
+ // Detect if the template is a runnable CLI command (single line, no YAML/JSON structure).
171
+ // If so, use cli_command kind so the daemon can execute it automatically.
172
+ const isCliCommand = !renderedTemplate.trim().includes('\n') && !renderedTemplate.trim().startsWith('{')
173
+ if (isCliCommand) {
174
+ return {
175
+ kind: 'cli_command',
176
+ serverName,
177
+ command: renderedTemplate.trim(),
178
+ requiresRestart: mcpConfig.requiresRestart === true,
179
+ instructions: instructions,
180
+ }
181
+ }
155
182
  return {
156
183
  kind: 'manual',
157
184
  serverName,
@@ -159,12 +186,7 @@ export function resolveMeshCoordinatorSetup(options: ResolveMeshCoordinatorSetup
159
186
  configPathCommand: mcpConfig.configPathCommand,
160
187
  requiresRestart: mcpConfig.requiresRestart === true,
161
188
  instructions,
162
- template: renderMeshCoordinatorTemplate(template, {
163
- meshId,
164
- workspace,
165
- serverName,
166
- adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND,
167
- }),
189
+ template: renderedTemplate,
168
190
  }
169
191
  }
170
192
 
@@ -1711,6 +1711,105 @@ export class DaemonCommandRouter {
1711
1711
  };
1712
1712
  }
1713
1713
 
1714
+ // ─── CLI-command MCP registration (Codex, Gemini CLI) ───────────
1715
+ if (coordinatorSetup.kind === 'cli_command') {
1716
+ // Build coordinator prompt first — fail closed on errors.
1717
+ let cliCmdSystemPrompt = '';
1718
+ try {
1719
+ cliCmdSystemPrompt = buildCoordinatorSystemPrompt({ mesh, coordinatorCliType: cliType });
1720
+ } catch (error: any) {
1721
+ const message = error?.message || String(error);
1722
+ LOG.error('MeshCoordinator', `Failed to build coordinator prompt: ${message}`);
1723
+ return {
1724
+ success: false,
1725
+ code: 'mesh_coordinator_prompt_failed',
1726
+ error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
1727
+ meshId, cliType, workspace,
1728
+ };
1729
+ }
1730
+
1731
+ // Run the provider's MCP registration command.
1732
+ try {
1733
+ const { execFileSync: execCmdSync } = await import('node:child_process');
1734
+ const cmdParts = coordinatorSetup.command.trim().split(/\s+/);
1735
+ const [regCmd, ...regArgs] = cmdParts;
1736
+ LOG.info('MeshCoordinator', `Running MCP registration: ${coordinatorSetup.command}`);
1737
+ execCmdSync(regCmd, regArgs, { stdio: 'pipe', timeout: 15_000 });
1738
+ } catch (error: any) {
1739
+ // Non-fatal — server may already be registered (providers return exit 1 on duplicate).
1740
+ LOG.warn('MeshCoordinator', `MCP registration command failed (may be pre-registered): ${error?.message || error}`);
1741
+ }
1742
+
1743
+ // Inject system prompt using provider-native methods.
1744
+ // Codex: -c 'instructions="..."' CLI config override
1745
+ // Gemini: write GEMINI.md to workspace (auto-loaded as context)
1746
+ const cliCmdArgs: string[] = [];
1747
+ const cliCmdEnv: Record<string, string> = {};
1748
+ if (cliCmdSystemPrompt) {
1749
+ if (cliType === 'codex-cli') {
1750
+ // Codex reads `developer_instructions` from config.toml as system instructions.
1751
+ // The -c flag overrides a config key for this session only.
1752
+ cliCmdArgs.push('-c', `developer_instructions=${JSON.stringify(cliCmdSystemPrompt)}`);
1753
+ } else if (cliType === 'gemini-cli') {
1754
+ // Gemini CLI auto-loads GEMINI.md from CWD as project context.
1755
+ // Write a temporary GEMINI.md to the workspace before launch.
1756
+ try {
1757
+ const { writeFileSync: wfs, existsSync: efs, readFileSync: rfs } = await import('node:fs');
1758
+ const geminiMdPath = `${workspace}/GEMINI.md`;
1759
+ const marker = '<!-- adhdev-mesh-coordinator-prompt -->';
1760
+ const markerEnd = '<!-- /adhdev-mesh-coordinator-prompt -->';
1761
+ const block = `${marker}\n${cliCmdSystemPrompt}\n${markerEnd}`;
1762
+ if (efs(geminiMdPath)) {
1763
+ const existing = rfs(geminiMdPath, 'utf-8');
1764
+ // Replace existing block or append
1765
+ const replaced = existing.replace(
1766
+ new RegExp(`${marker}[\\s\\S]*?${markerEnd}`, 'g'),
1767
+ block,
1768
+ );
1769
+ wfs(geminiMdPath, replaced.includes(marker) ? replaced : `${existing}\n\n${block}`);
1770
+ } else {
1771
+ wfs(geminiMdPath, block);
1772
+ }
1773
+ LOG.info('MeshCoordinator', `Wrote coordinator prompt to ${workspace}/GEMINI.md`);
1774
+ } catch (e: any) {
1775
+ LOG.warn('MeshCoordinator', `Could not write GEMINI.md: ${e?.message || e}`);
1776
+ }
1777
+ }
1778
+ }
1779
+
1780
+ const cliCmdLaunch: any = await this.deps.cliManager.handleCliCommand('launch_cli', {
1781
+ cliType,
1782
+ dir: workspace,
1783
+ cliArgs: cliCmdArgs.length > 0 ? cliCmdArgs : undefined,
1784
+ env: Object.keys(cliCmdEnv).length > 0 ? cliCmdEnv : undefined,
1785
+ settings: { meshCoordinatorFor: meshId },
1786
+ });
1787
+
1788
+ if (!cliCmdLaunch?.success) {
1789
+ return { success: false, error: cliCmdLaunch?.error || 'Failed to launch CLI session' };
1790
+ }
1791
+
1792
+ LOG.info('MeshCoordinator', `Launched ${cliType} coordinator (cli_command) for mesh ${meshId}`);
1793
+ try {
1794
+ const { appendLedgerEntry } = await import('../mesh/mesh-ledger.js');
1795
+ appendLedgerEntry(meshId, {
1796
+ kind: 'coordinator_started',
1797
+ sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
1798
+ providerType: cliType,
1799
+ payload: { workspace },
1800
+ });
1801
+ } catch { /* best-effort */ }
1802
+
1803
+ return {
1804
+ success: true,
1805
+ meshId,
1806
+ cliType,
1807
+ workspace,
1808
+ sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
1809
+ mcpRegistered: true,
1810
+ };
1811
+ }
1812
+
1714
1813
  const configFormat = coordinatorSetup.configFormat as MeshCoordinatorConfigFormat;
1715
1814
  if (configFormat !== 'claude_mcp_json' && configFormat !== 'hermes_config_yaml') {
1716
1815
  return {
@@ -113,11 +113,18 @@ export async function handleOpenPanel(h: CommandHelpers, args: any): Promise<Com
113
113
  export async function handlePtyInput(h: CommandHelpers, args: any): Promise<CommandResult> {
114
114
  const { cliType, data, targetSessionId } = args || {};
115
115
  if (!data) return { success: false, error: 'data required' };
116
+
117
+ // Filter out VT100/VT420 Device Attributes responses (e.g. \x1b[?1;2c)
118
+ // These are echoed by xterm.js in the dashboard in response to \x1b[c queries
119
+ // and pollute the CLI input buffer.
120
+ const cleanData = typeof data === 'string' ? data.replace(/\x1b\[\?[0-9;]*c/g, '') : data;
121
+ if (!cleanData) return { success: true };
122
+
116
123
  const adapter = h.getCliAdapter(targetSessionId || cliType);
117
124
  if (!adapter || typeof adapter.writeRaw !== 'function') {
118
125
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || 'unknown'}` };
119
126
  }
120
- await adapter.writeRaw(data);
127
+ await adapter.writeRaw(cleanData);
121
128
  return { success: true };
122
129
  }
123
130
 
@@ -76,7 +76,7 @@ export function tryAssignQueueTask(
76
76
  targetSessionId: sessionId,
77
77
  cliType: providerType,
78
78
  action: 'send_chat',
79
- input: task.message,
79
+ message: task.message,
80
80
  }).catch((e: any) => {
81
81
  LOG.error('MeshQueue', `Failed to dispatch task to node ${nodeId}: ${e?.message}`);
82
82
  });