@adhdev/daemon-core 0.9.77-rc.2 → 0.9.77-rc.20

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.
@@ -77,6 +77,8 @@ export declare class ProviderCliAdapter implements CliAdapter {
77
77
  private resizeSuppressUntil;
78
78
  private statusHistory;
79
79
  private cliScripts;
80
+ /** Per-session opaque state object created by cliScripts.createState(), reset on stop. */
81
+ private scriptState;
80
82
  private runtimeSettings;
81
83
  /** Full accumulated rendered PTY transcript for parser/readback use */
82
84
  private accumulatedBuffer;
@@ -63,17 +63,27 @@ export interface ParsedSession {
63
63
  coverage?: 'full' | 'tail' | 'current-turn';
64
64
  }
65
65
  export interface CliScripts {
66
- parseSession?: (input: CliScriptInput & {
66
+ /**
67
+ * Optional state factory. Called once per CLI session start (or script reload).
68
+ * The returned object is passed as the first argument to detectStatus, parseApproval,
69
+ * and parseSession on every invocation, allowing scripts to maintain per-session state
70
+ * (e.g. last-seen status, approval fingerprints, stability counters).
71
+ *
72
+ * Scripts that don't define createState() receive null as the state argument,
73
+ * making this change fully backward compatible.
74
+ */
75
+ createState?: () => unknown;
76
+ parseSession?: (state: unknown, input: CliScriptInput & {
67
77
  tail?: string;
68
78
  tailScreen?: CliScreenSnapshot;
69
79
  }) => ParsedSession | null;
70
- detectStatus?: (input: CliStatusInput) => string | null;
71
- parseApproval?: (input: CliApprovalInput) => {
80
+ detectStatus?: (state: unknown, input: CliStatusInput) => string | null;
81
+ parseApproval?: (state: unknown, input: CliApprovalInput) => {
72
82
  message: string;
73
83
  buttons: string[];
74
84
  } | null;
75
85
  resolveAction?: (data: any) => string;
76
- [name: string]: ((input: any) => any) | undefined;
86
+ [name: string]: ((state: unknown, input: any) => any) | ((data: any) => any) | (() => unknown) | undefined;
77
87
  }
78
88
  export interface CliScreenLine {
79
89
  index: number;
@@ -17,6 +17,14 @@ export type MeshCoordinatorSetup = {
17
17
  requiresRestart: boolean;
18
18
  instructions: string;
19
19
  template: string;
20
+ } | {
21
+ /** Provider registers MCP via its own CLI command (e.g. `codex mcp add` / `gemini mcp add`). */
22
+ kind: 'cli_command';
23
+ serverName: string;
24
+ /** The rendered shell command to execute before launching the coordinator session. */
25
+ command: string;
26
+ requiresRestart: boolean;
27
+ instructions: string;
20
28
  } | {
21
29
  kind: 'unsupported';
22
30
  reason: string;
package/dist/index.js CHANGED
@@ -1323,7 +1323,7 @@ function tryAssignQueueTask(components, meshId, nodeId, sessionId, providerType)
1323
1323
  targetSessionId: sessionId,
1324
1324
  cliType: providerType,
1325
1325
  action: "send_chat",
1326
- input: task.message
1326
+ message: task.message
1327
1327
  }).catch((e) => {
1328
1328
  LOG.error("MeshQueue", `Failed to dispatch task to node ${nodeId}: ${e?.message}`);
1329
1329
  });
@@ -1405,6 +1405,15 @@ function injectMeshSystemMessage(components, args) {
1405
1405
  }, 500);
1406
1406
  }
1407
1407
  }
1408
+ } else if (args.event === "agent:ready") {
1409
+ const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
1410
+ const nodeId = readNonEmptyString(args.metadataEvent.nodeId) || readNonEmptyString(args.metadataEvent.meshNodeId);
1411
+ const providerType = readNonEmptyString(args.metadataEvent.providerType);
1412
+ if (sessionId && nodeId && providerType) {
1413
+ setTimeout(() => {
1414
+ tryAssignQueueTask(components, args.meshId, nodeId, sessionId, providerType);
1415
+ }, 500);
1416
+ }
1408
1417
  } else if (args.event === "agent:stopped") {
1409
1418
  const sessionId = readNonEmptyString(args.metadataEvent.targetSessionId);
1410
1419
  if (sessionId) {
@@ -1584,6 +1593,7 @@ var init_mesh_events = __esm({
1584
1593
  "agent:generating_completed",
1585
1594
  "agent:waiting_approval",
1586
1595
  "agent:stopped",
1596
+ "agent:ready",
1587
1597
  "monitor:long_generating"
1588
1598
  ]);
1589
1599
  EVENT_TO_LEDGER_KIND = {
@@ -2699,6 +2709,8 @@ var init_provider_cli_adapter = __esm({
2699
2709
  statusHistory = [];
2700
2710
  // ─── CLI Scripts (script-based parsing) ───
2701
2711
  cliScripts;
2712
+ /** Per-session opaque state object created by cliScripts.createState(), reset on stop. */
2713
+ scriptState = null;
2702
2714
  runtimeSettings = {};
2703
2715
  /** Full accumulated rendered PTY transcript for parser/readback use */
2704
2716
  accumulatedBuffer = "";
@@ -2880,6 +2892,7 @@ ${lastSnapshot}`;
2880
2892
  this.cliScripts = scripts;
2881
2893
  this.parsedStatusCache = null;
2882
2894
  this.parseErrorMessage = null;
2895
+ this.scriptState = typeof scripts.createState === "function" ? scripts.createState() : null;
2883
2896
  const scriptNames = listCliScriptNames(scripts);
2884
2897
  LOG.info("CLI", `[${this.cliType}] CLI scripts injected: [${scriptNames.join(", ")}]`);
2885
2898
  }
@@ -2997,6 +3010,7 @@ ${lastSnapshot}`;
2997
3010
  this.ready = false;
2998
3011
  this.startupParseGate = false;
2999
3012
  this.spawnAt = 0;
3013
+ this.scriptState = null;
3000
3014
  this.onStatusChange?.();
3001
3015
  });
3002
3016
  this.spawnAt = Date.now();
@@ -3770,7 +3784,7 @@ ${lastSnapshot}`;
3770
3784
  scope: this.currentTurnScope,
3771
3785
  runtimeSettings: this.runtimeSettings
3772
3786
  });
3773
- const session = this.cliScripts.parseSession({ ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
3787
+ const session = this.cliScripts.parseSession(this.scriptState, { ...input, tail, tailScreen: buildCliScreenSnapshot(tail) });
3774
3788
  this.parseErrorMessage = null;
3775
3789
  return session && typeof session === "object" ? session : null;
3776
3790
  } catch (e) {
@@ -3784,7 +3798,7 @@ ${lastSnapshot}`;
3784
3798
  if (!this.cliScripts?.detectStatus) return null;
3785
3799
  try {
3786
3800
  const screenText = this.terminalScreen.getText();
3787
- const status = this.cliScripts.detectStatus({
3801
+ const status = this.cliScripts.detectStatus(this.scriptState, {
3788
3802
  tail: text.slice(-500),
3789
3803
  screenText,
3790
3804
  rawBuffer: this.accumulatedRawBuffer,
@@ -3803,7 +3817,7 @@ ${lastSnapshot}`;
3803
3817
  try {
3804
3818
  const screenText = this.terminalScreen.getText();
3805
3819
  const buffer = screenText || this.accumulatedBuffer;
3806
- return this.cliScripts.parseApproval({
3820
+ return this.cliScripts.parseApproval(this.scriptState, {
3807
3821
  buffer,
3808
3822
  screenText,
3809
3823
  rawBuffer: this.accumulatedRawBuffer,
@@ -3911,7 +3925,7 @@ ${lastSnapshot}`;
3911
3925
  scope: this.currentTurnScope,
3912
3926
  runtimeSettings: this.runtimeSettings
3913
3927
  });
3914
- return await Promise.resolve(fn({
3928
+ return await Promise.resolve(fn(this.scriptState, {
3915
3929
  ...input,
3916
3930
  args: args && typeof args === "object" ? { ...args } : {}
3917
3931
  }));
@@ -15205,11 +15219,13 @@ async function handleOpenPanel(h, args) {
15205
15219
  async function handlePtyInput(h, args) {
15206
15220
  const { cliType, data, targetSessionId } = args || {};
15207
15221
  if (!data) return { success: false, error: "data required" };
15222
+ const cleanData = typeof data === "string" ? data.replace(/\x1b\[[?>][0-9;]*c/g, "") : data;
15223
+ if (!cleanData) return { success: true };
15208
15224
  const adapter = h.getCliAdapter(targetSessionId || cliType);
15209
15225
  if (!adapter || typeof adapter.writeRaw !== "function") {
15210
15226
  return { success: false, error: `CLI adapter not found: ${targetSessionId || cliType || "unknown"}` };
15211
15227
  }
15212
- await adapter.writeRaw(data);
15228
+ await adapter.writeRaw(cleanData);
15213
15229
  return { success: true };
15214
15230
  }
15215
15231
  function handlePtyResize(_h, args) {
@@ -16839,6 +16855,8 @@ var CliProviderInstance = class {
16839
16855
  this.completedDebounceTimer = null;
16840
16856
  }, 3e3);
16841
16857
  }
16858
+ } else if (newStatus === "idle" && this.lastStatus === "starting") {
16859
+ this.pushEvent({ event: "agent:ready", chatTitle, timestamp: now });
16842
16860
  } else if (newStatus === "stopped") {
16843
16861
  if (this.generatingDebounceTimer) {
16844
16862
  clearTimeout(this.generatingDebounceTimer);
@@ -18582,9 +18600,6 @@ function buildCoordinatorDelegatedCliLaunchOptions(input) {
18582
18600
  const cliType = String(input.cliType || "").trim();
18583
18601
  const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
18584
18602
  const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
18585
- if (cliType === "hermes-cli" && !hasCliArg(cliArgs, "--ignore-user-config")) {
18586
- cliArgs.unshift("--ignore-user-config");
18587
- }
18588
18603
  if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
18589
18604
  cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
18590
18605
  }
@@ -21919,6 +21934,22 @@ function resolveMeshCoordinatorSetup(options) {
21919
21934
  if (!instructions || !template?.trim()) {
21920
21935
  return { kind: "unsupported", reason: "Provider manual MCP setup is missing instructions or template" };
21921
21936
  }
21937
+ const renderedTemplate = renderMeshCoordinatorTemplate(template, {
21938
+ meshId,
21939
+ workspace,
21940
+ serverName,
21941
+ adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND
21942
+ });
21943
+ const isCliCommand = !renderedTemplate.trim().includes("\n") && !renderedTemplate.trim().startsWith("{");
21944
+ if (isCliCommand) {
21945
+ return {
21946
+ kind: "cli_command",
21947
+ serverName,
21948
+ command: renderedTemplate.trim(),
21949
+ requiresRestart: mcpConfig.requiresRestart === true,
21950
+ instructions
21951
+ };
21952
+ }
21922
21953
  return {
21923
21954
  kind: "manual",
21924
21955
  serverName,
@@ -21926,12 +21957,7 @@ function resolveMeshCoordinatorSetup(options) {
21926
21957
  configPathCommand: mcpConfig.configPathCommand,
21927
21958
  requiresRestart: mcpConfig.requiresRestart === true,
21928
21959
  instructions,
21929
- template: renderMeshCoordinatorTemplate(template, {
21930
- meshId,
21931
- workspace,
21932
- serverName,
21933
- adhdevMcpCommand: options.adhdevMcpCommand || DEFAULT_ADHDEV_MCP_COMMAND
21934
- })
21960
+ template: renderedTemplate
21935
21961
  };
21936
21962
  }
21937
21963
  return {
@@ -24113,6 +24139,93 @@ var DaemonCommandRouter = class {
24113
24139
  meshCoordinatorSetup: coordinatorSetup
24114
24140
  };
24115
24141
  }
24142
+ if (coordinatorSetup.kind === "cli_command") {
24143
+ let cliCmdSystemPrompt = "";
24144
+ try {
24145
+ cliCmdSystemPrompt = buildCoordinatorSystemPrompt2({ mesh, coordinatorCliType: cliType });
24146
+ } catch (error) {
24147
+ const message = error?.message || String(error);
24148
+ LOG.error("MeshCoordinator", `Failed to build coordinator prompt: ${message}`);
24149
+ return {
24150
+ success: false,
24151
+ code: "mesh_coordinator_prompt_failed",
24152
+ error: `Failed to build Repo Mesh coordinator prompt: ${message}`,
24153
+ meshId,
24154
+ cliType,
24155
+ workspace
24156
+ };
24157
+ }
24158
+ try {
24159
+ const { execFileSync: execCmdSync } = await import("child_process");
24160
+ const cmdParts = coordinatorSetup.command.trim().split(/\s+/);
24161
+ const [regCmd, ...regArgs] = cmdParts;
24162
+ LOG.info("MeshCoordinator", `Running MCP registration: ${coordinatorSetup.command}`);
24163
+ execCmdSync(regCmd, regArgs, { stdio: "pipe", timeout: 15e3 });
24164
+ } catch (error) {
24165
+ LOG.warn("MeshCoordinator", `MCP registration command failed (may be pre-registered): ${error?.message || error}`);
24166
+ }
24167
+ const cliCmdArgs = [];
24168
+ const cliCmdEnv = {};
24169
+ if (cliCmdSystemPrompt) {
24170
+ if (cliType === "codex-cli") {
24171
+ cliCmdArgs.push("-c", `developer_instructions=${JSON.stringify(cliCmdSystemPrompt)}`);
24172
+ } else if (cliType === "gemini-cli") {
24173
+ try {
24174
+ const { writeFileSync: wfs, existsSync: efs, readFileSync: rfs } = await import("fs");
24175
+ const geminiMdPath = `${workspace}/GEMINI.md`;
24176
+ const marker = "<!-- adhdev-mesh-coordinator-prompt -->";
24177
+ const markerEnd = "<!-- /adhdev-mesh-coordinator-prompt -->";
24178
+ const block = `${marker}
24179
+ ${cliCmdSystemPrompt}
24180
+ ${markerEnd}`;
24181
+ if (efs(geminiMdPath)) {
24182
+ const existing = rfs(geminiMdPath, "utf-8");
24183
+ const replaced = existing.replace(
24184
+ new RegExp(`${marker}[\\s\\S]*?${markerEnd}`, "g"),
24185
+ block
24186
+ );
24187
+ wfs(geminiMdPath, replaced.includes(marker) ? replaced : `${existing}
24188
+
24189
+ ${block}`);
24190
+ } else {
24191
+ wfs(geminiMdPath, block);
24192
+ }
24193
+ LOG.info("MeshCoordinator", `Wrote coordinator prompt to ${workspace}/GEMINI.md`);
24194
+ } catch (e) {
24195
+ LOG.warn("MeshCoordinator", `Could not write GEMINI.md: ${e?.message || e}`);
24196
+ }
24197
+ }
24198
+ }
24199
+ const cliCmdLaunch = await this.deps.cliManager.handleCliCommand("launch_cli", {
24200
+ cliType,
24201
+ dir: workspace,
24202
+ cliArgs: cliCmdArgs.length > 0 ? cliCmdArgs : void 0,
24203
+ env: Object.keys(cliCmdEnv).length > 0 ? cliCmdEnv : void 0,
24204
+ settings: { meshCoordinatorFor: meshId }
24205
+ });
24206
+ if (!cliCmdLaunch?.success) {
24207
+ return { success: false, error: cliCmdLaunch?.error || "Failed to launch CLI session" };
24208
+ }
24209
+ LOG.info("MeshCoordinator", `Launched ${cliType} coordinator (cli_command) for mesh ${meshId}`);
24210
+ try {
24211
+ const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
24212
+ appendLedgerEntry2(meshId, {
24213
+ kind: "coordinator_started",
24214
+ sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
24215
+ providerType: cliType,
24216
+ payload: { workspace }
24217
+ });
24218
+ } catch {
24219
+ }
24220
+ return {
24221
+ success: true,
24222
+ meshId,
24223
+ cliType,
24224
+ workspace,
24225
+ sessionId: cliCmdLaunch.sessionId || cliCmdLaunch.id,
24226
+ mcpRegistered: true
24227
+ };
24228
+ }
24116
24229
  const configFormat = coordinatorSetup.configFormat;
24117
24230
  if (configFormat !== "claude_mcp_json" && configFormat !== "hermes_config_yaml") {
24118
24231
  return {