@adhdev/daemon-standalone 0.9.82-rc.180 → 0.9.82-rc.182

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/index.js CHANGED
@@ -36456,6 +36456,21 @@ Follow these recovery rules:
36456
36456
  };
36457
36457
  }
36458
36458
  });
36459
+ var logger_exports = {};
36460
+ __export2(logger_exports, {
36461
+ LOG: () => LOG2,
36462
+ LOG_DIR_PATH: () => LOG_DIR_PATH,
36463
+ LOG_PATH: () => LOG_PATH,
36464
+ daemonLog: () => daemonLog,
36465
+ getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
36466
+ getDaemonLogDir: () => getDaemonLogDir,
36467
+ getLogBufferSize: () => getLogBufferSize,
36468
+ getLogLevel: () => getLogLevel,
36469
+ getLogPath: () => getLogPath,
36470
+ getRecentLogs: () => getRecentLogs,
36471
+ installGlobalInterceptor: () => installGlobalInterceptor,
36472
+ setLogLevel: () => setLogLevel
36473
+ });
36459
36474
  function setLogLevel(level) {
36460
36475
  currentLevel = level;
36461
36476
  daemonLog("Logger", `Log level set to: ${level}`, "info");
@@ -36527,6 +36542,9 @@ Follow these recovery rules:
36527
36542
  const filtered = ringBuffer.filter((e) => LEVEL_NUM[e.level] >= minNum);
36528
36543
  return filtered.slice(-count);
36529
36544
  }
36545
+ function getLogBufferSize() {
36546
+ return ringBuffer.length;
36547
+ }
36530
36548
  function ts() {
36531
36549
  return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
36532
36550
  }
@@ -36606,6 +36624,9 @@ Follow these recovery rules:
36606
36624
  writeToFile(`Log file: ${currentLogFile}`);
36607
36625
  writeToFile(`Log level: ${currentLevel}`);
36608
36626
  }
36627
+ function getLogPath() {
36628
+ return currentLogFile;
36629
+ }
36609
36630
  var fs4;
36610
36631
  var path9;
36611
36632
  var os32;
@@ -36626,6 +36647,7 @@ Follow these recovery rules:
36626
36647
  var LOG2;
36627
36648
  var interceptorInstalled;
36628
36649
  var LOG_PATH;
36650
+ var LOG_DIR_PATH;
36629
36651
  var init_logger = __esm2({
36630
36652
  "src/logging/logger.ts"() {
36631
36653
  "use strict";
@@ -36686,6 +36708,7 @@ Follow these recovery rules:
36686
36708
  };
36687
36709
  interceptorInstalled = false;
36688
36710
  LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
36711
+ LOG_DIR_PATH = LOG_DIR;
36689
36712
  }
36690
36713
  });
36691
36714
  var mesh_coordinator_exports = {};
@@ -40142,18 +40165,6 @@ Next step: ${nextStep}`;
40142
40165
  } catch {
40143
40166
  }
40144
40167
  if (!meshIdFromDirectDispatch) return;
40145
- } else {
40146
- const workspaceMesh = getCachedMeshByWorkspace(workspace);
40147
- const workspaceMeshId = readNonEmptyString2(workspaceMesh?.id);
40148
- if (workspaceMeshId) {
40149
- try {
40150
- const activeDispatches = getActiveDirectDispatches(workspaceMeshId);
40151
- if (activeDispatches.some((d) => d.sessionId === instanceId) || hasUnterminalDirectDispatchLedgerEntry(workspaceMeshId, instanceId)) {
40152
- meshIdFromDirectDispatch = workspaceMeshId;
40153
- }
40154
- } catch {
40155
- }
40156
- }
40157
40168
  }
40158
40169
  const meshIdFromRuntime = readNonEmptyString2(settings.meshNodeFor) || meshIdFromDirectDispatch;
40159
40170
  const isMeshDelegate = Boolean(meshIdFromRuntime || settings.launchedByCoordinator);
@@ -48084,6 +48095,7 @@ ${lastSnapshot}`;
48084
48095
  }
48085
48096
  });
48086
48097
  }
48098
+ var CLAUDE_TUI_OPTION_PATTERN = /^\s*(?:[❯›>]\s*)?(\d+)\.\s+(.+?)\s*$/;
48087
48099
  function claudeTuiQuestionHeaders(screenText) {
48088
48100
  const navLine = screenText.split(/\r?\n/).find((line) => line.includes("\u2714 Submit") && /[☐☒]/.test(line));
48089
48101
  if (!navLine) return [];
@@ -48095,6 +48107,88 @@ ${lastSnapshot}`;
48095
48107
  }
48096
48108
  return headers;
48097
48109
  }
48110
+ function isClaudeTuiSelectFooter(text) {
48111
+ return /Enter to select/i.test(text) && /Esc to cancel/i.test(text);
48112
+ }
48113
+ function readClaudeHeaderLine(lines, beforeIndex) {
48114
+ for (let i = beforeIndex; i >= 0; i -= 1) {
48115
+ const candidate = lines[i].trim();
48116
+ if (!candidate) continue;
48117
+ const match = candidate.match(/^[☐☒]\s+(.+?)\s*$/);
48118
+ if (match?.[1]) return readString(match[1]);
48119
+ if (/^─+$/.test(candidate)) break;
48120
+ }
48121
+ return void 0;
48122
+ }
48123
+ function readClaudeOptionDescription(lines, optionLineIndex) {
48124
+ const nextLine = lines[optionLineIndex + 1];
48125
+ const next = nextLine?.trim();
48126
+ if (!next || CLAUDE_TUI_OPTION_PATTERN.test(nextLine) || /^─+$/.test(next) || /^Enter to select\b/i.test(next) || /^[☐☒]\s+/.test(next)) {
48127
+ return void 0;
48128
+ }
48129
+ return next;
48130
+ }
48131
+ function parseClaudeHeaderlessInteractiveTuiQuestion(page, index) {
48132
+ if (!isClaudeTuiSelectFooter(page.screenText)) return null;
48133
+ if (!/Type something\.?|Chat about this/i.test(page.screenText)) return null;
48134
+ const lines = page.screenText.split(/\r?\n/);
48135
+ let footerIndex = -1;
48136
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
48137
+ if (/Enter to select/i.test(lines[i])) {
48138
+ footerIndex = i;
48139
+ break;
48140
+ }
48141
+ }
48142
+ if (footerIndex < 0) return null;
48143
+ let optionBlockEnd = footerIndex - 1;
48144
+ for (let i = footerIndex - 1; i >= 0; i -= 1) {
48145
+ if (/^─+$/.test(lines[i].trim())) {
48146
+ optionBlockEnd = i - 1;
48147
+ break;
48148
+ }
48149
+ }
48150
+ const optionLineIndexes = [];
48151
+ for (let i = optionBlockEnd; i >= 0; i -= 1) {
48152
+ const line = lines[i];
48153
+ if (CLAUDE_TUI_OPTION_PATTERN.test(line)) {
48154
+ optionLineIndexes.push(i);
48155
+ continue;
48156
+ }
48157
+ if (optionLineIndexes.length > 0 && (!line.trim() || /^─+$/.test(line.trim()))) break;
48158
+ }
48159
+ optionLineIndexes.reverse();
48160
+ if (optionLineIndexes.length === 0) return null;
48161
+ const firstOptionIndex = optionLineIndexes[0];
48162
+ let question = "";
48163
+ for (let i = firstOptionIndex - 1; i >= 0; i -= 1) {
48164
+ const candidate = lines[i].trim();
48165
+ if (!candidate || /^─+$/.test(candidate) || /^[☐☒]\s+/.test(candidate)) continue;
48166
+ question = candidate;
48167
+ break;
48168
+ }
48169
+ if (!question) return null;
48170
+ const options = [];
48171
+ let allowFreeform = false;
48172
+ for (const optionLineIndex of optionLineIndexes) {
48173
+ const match = lines[optionLineIndex].match(CLAUDE_TUI_OPTION_PATTERN);
48174
+ if (!match) continue;
48175
+ const label = match[2].trim();
48176
+ if (/^Chat about this$/i.test(label)) continue;
48177
+ if (/^Type something\.?$/i.test(label)) allowFreeform = true;
48178
+ const description = readClaudeOptionDescription(lines, optionLineIndex);
48179
+ options.push({ label, ...description ? { description } : {} });
48180
+ }
48181
+ if (options.length === 0) return null;
48182
+ const header = readString(page.header) || readClaudeHeaderLine(lines, firstOptionIndex - 1);
48183
+ return {
48184
+ questionId: `q${index + 1}`,
48185
+ question,
48186
+ ...header ? { header } : {},
48187
+ multiSelect: /Space to select|toggle selections/i.test(page.screenText),
48188
+ options,
48189
+ ...allowFreeform ? { allowFreeform: true } : {}
48190
+ };
48191
+ }
48098
48192
  function parseClaudeInteractiveTuiQuestion(page, index) {
48099
48193
  const lines = page.screenText.split(/\r?\n/);
48100
48194
  let navIndex = -1;
@@ -48104,7 +48198,8 @@ ${lastSnapshot}`;
48104
48198
  break;
48105
48199
  }
48106
48200
  }
48107
- if (navIndex < 0 || !page.screenText.includes("Enter to select")) return null;
48201
+ if (navIndex < 0) return parseClaudeHeaderlessInteractiveTuiQuestion(page, index);
48202
+ if (!page.screenText.includes("Enter to select")) return null;
48108
48203
  let question = "";
48109
48204
  let questionLineIndex = -1;
48110
48205
  for (let i = navIndex + 1; i < lines.length; i += 1) {
@@ -48118,9 +48213,8 @@ ${lastSnapshot}`;
48118
48213
  if (!question) return null;
48119
48214
  const options = [];
48120
48215
  let allowFreeform = false;
48121
- const optionPattern = /^\s*(?:[❯›>]\s*)?(\d+)\.\s+(.+?)\s*$/;
48122
48216
  for (let i = questionLineIndex + 1; i < lines.length; i += 1) {
48123
- const match = lines[i].match(optionPattern);
48217
+ const match = lines[i].match(CLAUDE_TUI_OPTION_PATTERN);
48124
48218
  if (!match) continue;
48125
48219
  const label = match[2].trim();
48126
48220
  if (/^Type something\.?$/i.test(label)) {
@@ -48130,7 +48224,7 @@ ${lastSnapshot}`;
48130
48224
  if (/^Chat about this$/i.test(label)) continue;
48131
48225
  let description;
48132
48226
  const nextLine = lines[i + 1]?.trim();
48133
- if (nextLine && !optionPattern.test(lines[i + 1]) && !/^─+$/.test(nextLine) && !/^Enter to select\b/.test(nextLine)) {
48227
+ if (nextLine && !CLAUDE_TUI_OPTION_PATTERN.test(lines[i + 1]) && !/^─+$/.test(nextLine) && !/^Enter to select\b/.test(nextLine)) {
48134
48228
  description = nextLine;
48135
48229
  }
48136
48230
  options.push({ label, ...description ? { description } : {} });
@@ -62850,7 +62944,11 @@ ${formatManifestValidationIssues2(validation.issues)}`,
62850
62944
  maybeRefreshNativeHistory() {
62851
62945
  }
62852
62946
  getScriptParsedStatus() {
62853
- return this.getStatus();
62947
+ const status = this.getStatus();
62948
+ return {
62949
+ ...status,
62950
+ messages: this.readClaudeScreenAssistantMessages()
62951
+ };
62854
62952
  }
62855
62953
  getPartialResponse() {
62856
62954
  return this.partialResponse;
@@ -63077,11 +63175,58 @@ ${formatManifestValidationIssues2(validation.issues)}`,
63077
63175
  }
63078
63176
  }
63079
63177
  }
63178
+ readCurrentScreenSections(screenText) {
63179
+ try {
63180
+ const ev = evaluate(this.spec, screenText);
63181
+ return Object.fromEntries(ev.sections.map((section) => [section.id, section.text]));
63182
+ } catch {
63183
+ return {};
63184
+ }
63185
+ }
63186
+ readClaudeScreenAssistantMessages() {
63187
+ if (this.cliType !== "claude-cli") return [];
63188
+ let screenText = "";
63189
+ try {
63190
+ screenText = this.driver.snapshot();
63191
+ } catch {
63192
+ return [];
63193
+ }
63194
+ const sections = this.readCurrentScreenSections(screenText);
63195
+ const body = sections.body || screenText;
63196
+ const messages = [];
63197
+ const seen = /* @__PURE__ */ new Set();
63198
+ for (const line of body.split(/\r?\n/)) {
63199
+ const match = line.match(/^\s*⏺\s+(.+?)\s*$/);
63200
+ const content = match?.[1]?.trim();
63201
+ if (!content || seen.has(content)) continue;
63202
+ seen.add(content);
63203
+ messages.push({
63204
+ role: "assistant",
63205
+ kind: "standard",
63206
+ content,
63207
+ source: "assistant_text",
63208
+ userFacing: true,
63209
+ bubbleState: "final"
63210
+ });
63211
+ }
63212
+ return messages;
63213
+ }
63080
63214
  maybeCaptureClaudeTuiPrompt() {
63081
63215
  if (this.cliType !== "claude-cli" || this.activeInteractivePrompt || this.claudeTuiPromptCaptureInFlight) return;
63082
63216
  const screenText = this.driver.snapshot();
63083
63217
  const headers = this.readClaudeTuiHeaders(screenText);
63084
- if (headers.length === 0 || !screenText.includes("Enter to select")) return;
63218
+ if (!screenText.includes("Enter to select")) return;
63219
+ if (headers.length === 0) {
63220
+ const prompt = detectClaudeAskUserQuestionPromptFromTuiPages([{ screenText }], {
63221
+ promptId: `ask-user-${this.providerSessionId || "claude"}-${Date.now()}`,
63222
+ providerType: this.cliType
63223
+ });
63224
+ if (!prompt) return;
63225
+ this.activeInteractivePrompt = prompt;
63226
+ this.interactivePromptTransport = "tui";
63227
+ this.statusCallback?.();
63228
+ return;
63229
+ }
63085
63230
  this.claudeTuiPromptCaptureInFlight = true;
63086
63231
  void this.captureClaudeTuiPrompt(screenText, headers).finally(() => {
63087
63232
  this.claudeTuiPromptCaptureInFlight = false;
@@ -63165,6 +63310,11 @@ ${formatManifestValidationIssues2(validation.issues)}`,
63165
63310
  }
63166
63311
  var COMPLETED_FINALIZATION_RETRY_MS = 1e3;
63167
63312
  var COMPLETED_FINALIZATION_MAX_WAIT_MS = 3e4;
63313
+ var TERMINAL_MESH_EVENTS = /* @__PURE__ */ new Set([
63314
+ "agent:generating_completed",
63315
+ "agent:stopped",
63316
+ "agent:ready"
63317
+ ]);
63168
63318
  var IMAGE_MIME_EXTENSIONS = {
63169
63319
  "image/png": ".png",
63170
63320
  "image/jpeg": ".jpg",
@@ -63685,6 +63835,39 @@ ${formatManifestValidationIssues2(validation.issues)}`,
63685
63835
  longGeneratingThresholdSec: this.settings.longGeneratingThresholdSec || 180
63686
63836
  });
63687
63837
  }
63838
+ /**
63839
+ * Stamp a direct-dispatch mesh assignment on this instance.
63840
+ * setupMeshEventForwarding reads settings.meshNodeFor + meshActiveTaskId to
63841
+ * route generating_completed back to the originating coordinator. Without
63842
+ * this stamp, mesh_send_task --direct targets a plain CLI session whose
63843
+ * completion events silently drop because the forwarder has nothing to
63844
+ * match against.
63845
+ */
63846
+ attachMeshAssignment(assignment) {
63847
+ if (!assignment?.meshId) return;
63848
+ this.settings = {
63849
+ ...this.settings,
63850
+ meshNodeFor: assignment.meshId,
63851
+ ...assignment.nodeId ? { meshNodeId: assignment.nodeId } : {},
63852
+ ...assignment.taskId ? { meshActiveTaskId: assignment.taskId } : {}
63853
+ };
63854
+ this.adapter.updateRuntimeSettings?.(this.settings);
63855
+ }
63856
+ /**
63857
+ * Clear a previously-attached mesh assignment after the task reaches a
63858
+ * terminal state. Leaving meshNodeFor pinned would route this session's
63859
+ * subsequent unrelated turns (e.g. ad-hoc dashboard chats) to the
63860
+ * coordinator as if they were task completions.
63861
+ */
63862
+ detachMeshAssignment() {
63863
+ if (!this.settings.meshNodeFor && !this.settings.meshActiveTaskId && !this.settings.meshNodeId) return;
63864
+ const { meshNodeFor, meshNodeId, meshActiveTaskId, ...rest } = this.settings;
63865
+ void meshNodeFor;
63866
+ void meshNodeId;
63867
+ void meshActiveTaskId;
63868
+ this.settings = rest;
63869
+ this.adapter.updateRuntimeSettings?.(this.settings);
63870
+ }
63688
63871
  onEvent(event, data) {
63689
63872
  if (event === "send_message") {
63690
63873
  const input = normalizeInputEnvelope(data);
@@ -64317,9 +64500,15 @@ ${formatManifestValidationIssues2(validation.issues)}`,
64317
64500
  };
64318
64501
  if (this.context?.emitProviderEvent) {
64319
64502
  this.context.emitProviderEvent(enrichedEvent);
64320
- return;
64503
+ } else {
64504
+ this.events.push(enrichedEvent);
64505
+ }
64506
+ if (TERMINAL_MESH_EVENTS.has(event.event) && this.settings.meshActiveTaskId) {
64507
+ try {
64508
+ this.detachMeshAssignment();
64509
+ } catch {
64510
+ }
64321
64511
  }
64322
- this.events.push(enrichedEvent);
64323
64512
  }
64324
64513
  flushEvents() {
64325
64514
  const events = [...this.events];
@@ -66966,6 +67155,18 @@ Run 'adhdev doctor' for detailed diagnostics.`
66966
67155
  } else if (currentStatus === "starting") {
66967
67156
  currentStatus = getEffectiveAgentSendStatus(adapter);
66968
67157
  }
67158
+ const meshContext = args?.meshContext;
67159
+ if (meshContext && typeof meshContext === "object" && typeof meshContext.meshId === "string" && meshContext.meshId) {
67160
+ const targetInstanceId = key;
67161
+ try {
67162
+ this.deps.getInstanceManager()?.attachMeshAssignmentToInstance(targetInstanceId, {
67163
+ meshId: meshContext.meshId,
67164
+ ...typeof meshContext.nodeId === "string" && meshContext.nodeId ? { nodeId: meshContext.nodeId } : {},
67165
+ ...typeof meshContext.taskId === "string" && meshContext.taskId ? { taskId: meshContext.taskId } : {}
67166
+ });
67167
+ } catch {
67168
+ }
67169
+ }
66969
67170
  const input = normalizeInputEnvelope(args?.input ? { input: args.input } : args);
66970
67171
  const provider = this.providerLoader.resolve(agentType) || this.providerLoader.getMeta(agentType);
66971
67172
  if (provider?.category === "acp") {
@@ -77308,6 +77509,36 @@ ${ptyResult.output.slice(-2e3)}`);
77308
77509
  }
77309
77510
  return updated;
77310
77511
  }
77512
+ /** Stamp a mesh assignment on a single instance (used by mesh_send_task
77513
+ * --direct so the worker's completion event has a coordinator routing
77514
+ * marker in state.settings). Returns true if the instance existed and
77515
+ * the stamp was applied. */
77516
+ attachMeshAssignmentToInstance(instanceId, assignment) {
77517
+ const inst = this.instances.get(instanceId);
77518
+ if (!inst || typeof inst.attachMeshAssignment !== "function") {
77519
+ try {
77520
+ const { LOG: LOG22 } = (init_logger(), __toCommonJS2(logger_exports));
77521
+ LOG22.warn?.("MeshDispatch", `attachMeshAssignment skipped: instance ${instanceId} ${inst ? "has no attach method" : "not found"}`);
77522
+ } catch {
77523
+ }
77524
+ return false;
77525
+ }
77526
+ inst.attachMeshAssignment(assignment);
77527
+ try {
77528
+ const { LOG: LOG22 } = (init_logger(), __toCommonJS2(logger_exports));
77529
+ LOG22.info?.("MeshDispatch", `stamped mesh assignment on ${instanceId}: mesh=${assignment.meshId} node=${assignment.nodeId || ""} task=${assignment.taskId || ""}`);
77530
+ } catch {
77531
+ }
77532
+ return true;
77533
+ }
77534
+ /** Clear a mesh assignment after the dispatched task reaches a terminal
77535
+ * state (generating_completed / stopped / failed). */
77536
+ detachMeshAssignmentFromInstance(instanceId) {
77537
+ const inst = this.instances.get(instanceId);
77538
+ if (!inst || typeof inst.detachMeshAssignment !== "function") return false;
77539
+ inst.detachMeshAssignment();
77540
+ return true;
77541
+ }
77311
77542
  refreshProviderDefinitions(resolveProvider) {
77312
77543
  let refreshed = 0;
77313
77544
  for (const instance of this.instances.values()) {