@adhdev/daemon-core 0.9.82-rc.187 → 0.9.82-rc.188

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 (37) hide show
  1. package/dist/boot/daemon-lifecycle.d.ts +1 -0
  2. package/dist/commands/cli-manager.d.ts +2 -1
  3. package/dist/commands/router.d.ts +5 -1
  4. package/dist/git/git-commands.d.ts +2 -0
  5. package/dist/git/git-types.d.ts +2 -0
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +401 -33
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.mjs +400 -33
  10. package/dist/index.mjs.map +1 -1
  11. package/dist/providers/cli-provider-instance.d.ts +4 -0
  12. package/dist/providers/contracts.d.ts +31 -0
  13. package/dist/providers/sdk/v1/types/common/index.d.ts +35 -1
  14. package/dist/providers/spec/driver.d.ts +6 -1
  15. package/dist/providers/spec/schema.gen.d.ts +22 -0
  16. package/dist/providers/spec/types.d.ts +10 -0
  17. package/dist/repo-mesh-types.d.ts +6 -0
  18. package/package.json +1 -1
  19. package/src/boot/daemon-lifecycle.ts +2 -0
  20. package/src/commands/chat-commands.ts +26 -0
  21. package/src/commands/cli-manager.ts +52 -14
  22. package/src/commands/router.ts +35 -4
  23. package/src/git/git-commands.ts +20 -2
  24. package/src/git/git-status.ts +35 -6
  25. package/src/git/git-types.ts +2 -0
  26. package/src/index.ts +1 -1
  27. package/src/providers/cli-provider-instance.ts +110 -9
  28. package/src/providers/contracts.d.ts +55 -0
  29. package/src/providers/contracts.ts +35 -0
  30. package/src/providers/provider-schema.ts +56 -1
  31. package/src/providers/sdk/v1/schemas/cli/provider.schema.json +46 -0
  32. package/src/providers/sdk/v1/types/common/index.ts +19 -0
  33. package/src/providers/spec/driver.ts +68 -1
  34. package/src/providers/spec/schema.gen.ts +12 -1
  35. package/src/providers/spec/schema.json +21 -1
  36. package/src/providers/spec/types.ts +10 -0
  37. package/src/repo-mesh-types.ts +6 -0
package/dist/index.js CHANGED
@@ -275,6 +275,8 @@ async function getGitRepoStatus(workspace, options = {}) {
275
275
  if (includeSubmodules) {
276
276
  submodules = await getSubmoduleStatuses(repo, options);
277
277
  }
278
+ const submoduleDirty = (submodules || []).some((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error);
279
+ const dirty = parsed.staged + parsed.modified + parsed.untracked + parsed.deleted + parsed.renamed > 0 || parsed.conflictFiles.length > 0 || stashCount > 0 || submoduleDirty;
278
280
  return {
279
281
  workspace: repo.workspace,
280
282
  repoRoot: repo.repoRoot,
@@ -293,6 +295,7 @@ async function getGitRepoStatus(workspace, options = {}) {
293
295
  untracked: parsed.untracked,
294
296
  deleted: parsed.deleted,
295
297
  renamed: parsed.renamed,
298
+ dirty,
296
299
  hasConflicts: parsed.conflictFiles.length > 0,
297
300
  conflictFiles: parsed.conflictFiles,
298
301
  stashCount,
@@ -466,6 +469,7 @@ function emptyStatus(workspace, lastCheckedAt, error) {
466
469
  untracked: 0,
467
470
  deleted: 0,
468
471
  renamed: 0,
472
+ dirty: false,
469
473
  hasConflicts: false,
470
474
  conflictFiles: [],
471
475
  stashCount: 0,
@@ -478,17 +482,33 @@ async function getSubmoduleStatuses(repo, options) {
478
482
  if (!repo.repoRoot) return [];
479
483
  try {
480
484
  const result = await runGit(repo, ["submodule", "status", "--recursive"], options);
481
- return parseSubmoduleStatusOutput(result.stdout, repo.repoRoot, options.submoduleIgnorePaths);
485
+ const submodules = parseSubmoduleStatusOutput(result.stdout, repo.repoRoot, options.submoduleIgnorePaths);
486
+ await Promise.all(submodules.map((submodule) => enrichSubmoduleWorktreeStatus(repo, submodule, options)));
487
+ return submodules;
482
488
  } catch {
483
489
  return [];
484
490
  }
485
491
  }
492
+ async function enrichSubmoduleWorktreeStatus(repo, submodule, options) {
493
+ try {
494
+ const result = await runGit(repo, ["status", "--porcelain=v2", "--branch"], {
495
+ ...options,
496
+ cwd: submodule.repoPath
497
+ });
498
+ const parsed = parsePorcelainV2Status(result.stdout);
499
+ const dirty = parsed.staged + parsed.modified + parsed.untracked + parsed.deleted + parsed.renamed > 0 || parsed.conflictFiles.length > 0;
500
+ submodule.dirty = submodule.dirty || dirty;
501
+ } catch (error) {
502
+ submodule.dirty = true;
503
+ submodule.error = formatGitError(error);
504
+ }
505
+ }
486
506
  function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
487
507
  const submodules = [];
488
508
  const ignoreSet = new Set(ignorePaths || []);
489
509
  for (const line of output.split("\n")) {
490
510
  if (!line.trim()) continue;
491
- const match = line.match(/^([\-+\s])([0-9a-f]{40})\s+(\S+)(?:\s+\(([^)]+)\))?/);
511
+ const match = line.match(/^([\-+U\s])([0-9a-f]{40})\s+(\S+)(?:\s+\(([^)]+)\))?/);
492
512
  if (!match) continue;
493
513
  const prefix = match[1];
494
514
  const commit = match[2];
@@ -498,8 +518,8 @@ function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
498
518
  path: path40,
499
519
  commit,
500
520
  repoPath: repoRoot + "/" + path40,
501
- dirty: prefix === "+",
502
- outOfSync: prefix === "-",
521
+ dirty: prefix === "U",
522
+ outOfSync: prefix === "-" || prefix === "+",
503
523
  lastCheckedAt: Date.now()
504
524
  });
505
525
  }
@@ -6157,6 +6177,52 @@ var init_provider_schema = __esm({
6157
6177
  properties: { mode: { const: "env_var" }, name: { type: "string" } }
6158
6178
  }
6159
6179
  ]
6180
+ },
6181
+ delegatedWorkerIsolation: {
6182
+ description: "Provider-declared launch isolation for coordinator-spawned worker sessions. Keeps worker-only sessions from inheriting coordinator MCP/tools/config.",
6183
+ type: "object",
6184
+ additionalProperties: false,
6185
+ properties: {
6186
+ env: {
6187
+ type: "object",
6188
+ additionalProperties: false,
6189
+ properties: {
6190
+ unset: {
6191
+ type: "array",
6192
+ items: { type: "string", minLength: 1 }
6193
+ }
6194
+ }
6195
+ },
6196
+ args: {
6197
+ type: "array",
6198
+ items: {
6199
+ oneOf: [
6200
+ {
6201
+ type: "object",
6202
+ additionalProperties: false,
6203
+ required: ["mode", "flag"],
6204
+ properties: {
6205
+ mode: { const: "empty_mcp_config" },
6206
+ flag: { type: "string", minLength: 1 },
6207
+ strictFlag: { type: "string", minLength: 1 }
6208
+ }
6209
+ },
6210
+ {
6211
+ type: "object",
6212
+ additionalProperties: false,
6213
+ required: ["mode", "flag", "key", "value"],
6214
+ properties: {
6215
+ mode: { const: "config_override" },
6216
+ flag: { type: "string", minLength: 1 },
6217
+ key: { type: "string", minLength: 1 },
6218
+ value: { type: "string", minLength: 1 },
6219
+ dedupeKey: { type: "string", minLength: 1 }
6220
+ }
6221
+ }
6222
+ ]
6223
+ }
6224
+ }
6225
+ }
6160
6226
  }
6161
6227
  }
6162
6228
  },
@@ -11290,6 +11356,7 @@ __export(index_exports, {
11290
11356
  probeCdpPort: () => probeCdpPort,
11291
11357
  queuePendingMeshCoordinatorEvent: () => queuePendingMeshCoordinatorEvent,
11292
11358
  readAntigravityCliSession: () => readSession3,
11359
+ readCachedInlineMeshActiveSessionDetails: () => readCachedInlineMeshActiveSessionDetails,
11293
11360
  readChatHistory: () => readChatHistory,
11294
11361
  readClaudeCliSession: () => readSession,
11295
11362
  readCodexCliSession: () => readSession2,
@@ -12334,7 +12401,14 @@ async function handleGitCommand(command, args, services = defaultGitCommandServi
12334
12401
  switch (command) {
12335
12402
  case "git_status": {
12336
12403
  if (!services.getStatus) return serviceNotImplemented(command);
12337
- const status = await runService(() => services.getStatus({ workspace, refreshUpstream: optionalBoolean(args?.refreshUpstream) }));
12404
+ const submoduleIgnorePaths = Array.isArray(args?.submoduleIgnorePaths) ? args.submoduleIgnorePaths.filter((value) => typeof value === "string" && value.trim().length > 0) : void 0;
12405
+ const statusParams = { workspace };
12406
+ const refreshUpstream = optionalBoolean(args?.refreshUpstream);
12407
+ const includeSubmodules = optionalBoolean(args?.includeSubmodules);
12408
+ if (refreshUpstream !== void 0) statusParams.refreshUpstream = refreshUpstream;
12409
+ if (includeSubmodules !== void 0) statusParams.includeSubmodules = includeSubmodules;
12410
+ if (submoduleIgnorePaths && submoduleIgnorePaths.length > 0) statusParams.submoduleIgnorePaths = submoduleIgnorePaths;
12411
+ const status = await runService(() => services.getStatus(statusParams));
12338
12412
  return "success" in status ? status : { success: true, status };
12339
12413
  }
12340
12414
  case "git_diff_summary": {
@@ -12467,6 +12541,14 @@ async function gitCheckpoint(workspace, message, includeUntracked) {
12467
12541
  if (statusResult.hasConflicts) {
12468
12542
  throw new GitCommandError("conflict", "Repository has conflicts \u2014 resolve before checkpointing");
12469
12543
  }
12544
+ const dirtySubmodules = (statusResult.submodules || []).filter((submodule) => submodule.dirty);
12545
+ if (dirtySubmodules.length > 0) {
12546
+ const paths = dirtySubmodules.map((submodule) => submodule.path).join(", ");
12547
+ throw new GitCommandError(
12548
+ "dirty_index_required",
12549
+ `Repository has dirty submodules that must be checkpointed first: ${paths}. Checkpoint or commit each dirty submodule, then checkpoint this repository to record gitlink changes.`
12550
+ );
12551
+ }
12470
12552
  const addArgs = includeUntracked ? ["-A"] : ["-u"];
12471
12553
  await runGit(repo, ["add", ...addArgs], { cwd: repoRoot });
12472
12554
  const fullMsg = `adhdev: checkpoint ${message}`;
@@ -21788,6 +21870,14 @@ function hasVisibleAssistantMessage(messages) {
21788
21870
  return String(message.content || "").trim().length > 0;
21789
21871
  });
21790
21872
  }
21873
+ function hasFinalVisibleAssistantMessage(messages) {
21874
+ if (!Array.isArray(messages)) return false;
21875
+ const visible = filterUserFacingChatMessages(messages);
21876
+ const last = visible[visible.length - 1];
21877
+ const role = typeof last?.role === "string" ? last.role.trim().toLowerCase() : "";
21878
+ const content = last ? flattenContent(last.content).trim() : "";
21879
+ return (role === "assistant" || role === "model") && content.length > 0;
21880
+ }
21791
21881
  function shouldTrustCliAdapterTerminalStatus(parsedStatus, activeModal, adapter, adapterStatus) {
21792
21882
  if (!isGeneratingLikeStatus(parsedStatus)) return false;
21793
21883
  if (hasNonEmptyModalButtons(activeModal)) return false;
@@ -22642,6 +22732,18 @@ async function handleReadChat(h, args) {
22642
22732
  });
22643
22733
  }
22644
22734
  }
22735
+ if (isGeneratingLikeStatus(selectedStatus) && selectedTranscriptAuthority === "provider" && !hasNonEmptyModalButtons(activeModal) && hasFinalVisibleAssistantMessage(selectedMessages)) {
22736
+ selectedStatus = "idle";
22737
+ selectedMessages = finalizeStreamingMessagesWhenIdle(selectedMessages, selectedStatus);
22738
+ messageSource = {
22739
+ ...messageSource,
22740
+ statusReconciled: {
22741
+ from: returnedStatus,
22742
+ to: "idle",
22743
+ reason: "provider_native_final_assistant"
22744
+ }
22745
+ };
22746
+ }
22645
22747
  LOG.debug("Command", `[read_chat] cli-like parsed provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord.status || "")} parsedMsgCount=${parsedRecord.messages.length} returnedMsgCount=${returnedMessages.length}`);
22646
22748
  return buildReadChatCommandResult({
22647
22749
  messages: selectedMessages,
@@ -26228,7 +26330,18 @@ var SCHEMA = {
26228
26330
  "additionalProperties": false,
26229
26331
  "properties": {
26230
26332
  "busy_hold_ms": { "type": "integer", "minimum": 0 },
26231
- "startup_grace_ms": { "type": "integer", "minimum": 0 }
26333
+ "startup_grace_ms": { "type": "integer", "minimum": 0 },
26334
+ "completion_idle_after": {
26335
+ "type": "object",
26336
+ "additionalProperties": false,
26337
+ "required": ["regex", "hold_ms"],
26338
+ "properties": {
26339
+ "section": { "type": "string", "minLength": 1 },
26340
+ "regex": { "type": "string", "minLength": 1 },
26341
+ "flags": { "type": "string" },
26342
+ "hold_ms": { "type": "integer", "minimum": 0 }
26343
+ }
26344
+ }
26232
26345
  }
26233
26346
  }
26234
26347
  },
@@ -26708,6 +26821,30 @@ function resolveSubmitDelayMs(specBeforeSubmit, text) {
26708
26821
  const spec = typeof specBeforeSubmit === "number" && specBeforeSubmit > 0 ? specBeforeSubmit : 0;
26709
26822
  return Math.max(spec, SUBMIT_DELAY_FLOOR_MS + linesBonus);
26710
26823
  }
26824
+ function matchesCompletionIdleRule(spec, ev, screen) {
26825
+ const rule = spec.debounce?.completion_idle_after;
26826
+ if (!rule?.regex) return null;
26827
+ const haystack = rule.section ? ev.sections.find((section) => section.id === rule.section)?.text ?? "" : screen;
26828
+ if (!haystack) return null;
26829
+ try {
26830
+ const regex = new RegExp(rule.regex, rule.flags || "");
26831
+ const match = haystack.match(regex);
26832
+ return match?.[0] || null;
26833
+ } catch {
26834
+ return null;
26835
+ }
26836
+ }
26837
+ function matchesCompletionIdleTargetState(spec, ev, screen) {
26838
+ const target = spec.states.find((state) => state.id === spec.default_state) ?? spec.states.find((state) => state.id === "idle");
26839
+ if (!target?.when?.regex) return false;
26840
+ const haystack = target.when.section ? ev.sections.find((section) => section.id === target.when.section)?.text ?? "" : screen;
26841
+ if (!haystack) return false;
26842
+ try {
26843
+ return new RegExp(target.when.regex, target.when.flags || "i").test(haystack);
26844
+ } catch {
26845
+ return false;
26846
+ }
26847
+ }
26711
26848
  var SpecDriver = class {
26712
26849
  constructor(opts) {
26713
26850
  this.opts = opts;
@@ -26747,6 +26884,8 @@ var SpecDriver = class {
26747
26884
  * because the evaluator already moved past busy by the time the hold
26748
26885
  * kicks in. */
26749
26886
  lastBusyState = null;
26887
+ completionIdleFirstSeenAt = 0;
26888
+ completionIdleKey = "";
26750
26889
  /** Timer that re-runs evaluate() once the hold window expires. Needed
26751
26890
  * because the PTY stops emitting once the agent finishes; without an
26752
26891
  * explicit wake-up there's nothing to trigger the busy → idle
@@ -26870,10 +27009,40 @@ var SpecDriver = class {
26870
27009
  evState = this.lastBusyState ?? evState;
26871
27010
  }
26872
27011
  }
27012
+ const completionIdleRule = this.spec.debounce?.completion_idle_after;
27013
+ let busyWakeMs = busyHoldMs;
27014
+ if (evState.id === "busy" && completionIdleRule) {
27015
+ const completionKey = matchesCompletionIdleRule(this.spec, ev, screen);
27016
+ if (completionKey) {
27017
+ const now = Date.now();
27018
+ if (completionKey !== this.completionIdleKey) {
27019
+ this.completionIdleKey = completionKey;
27020
+ this.completionIdleFirstSeenAt = now;
27021
+ }
27022
+ const holdMs = Math.max(0, completionIdleRule.hold_ms || 0);
27023
+ const ageMs = now - this.completionIdleFirstSeenAt;
27024
+ if (ageMs >= holdMs) {
27025
+ if (matchesCompletionIdleTargetState(this.spec, ev, screen)) {
27026
+ const idle = this.spec.states.find((state) => state.id === this.spec.default_state) ?? this.spec.states.find((state) => state.id === "idle");
27027
+ evState = idle ? { id: idle.id, label: idle.label, title: null } : { id: "idle", label: "Ready", title: null };
27028
+ } else {
27029
+ busyWakeMs = Math.min(busyWakeMs, 1e3);
27030
+ }
27031
+ } else {
27032
+ busyWakeMs = Math.min(busyWakeMs, Math.max(holdMs - ageMs, 0));
27033
+ }
27034
+ } else {
27035
+ this.completionIdleKey = "";
27036
+ this.completionIdleFirstSeenAt = 0;
27037
+ }
27038
+ } else if (evState.id !== "busy") {
27039
+ this.completionIdleKey = "";
27040
+ this.completionIdleFirstSeenAt = 0;
27041
+ }
26873
27042
  if (evState.id === "busy") {
26874
27043
  this.lastBusyAt = Date.now();
26875
27044
  this.lastBusyState = evState;
26876
- this.scheduleBusyExpiry(busyHoldMs);
27045
+ this.scheduleBusyExpiry(busyWakeMs);
26877
27046
  }
26878
27047
  const changed = forceEmit || evState.id !== this.currentStateId || !shallowSameModal(ev, this.currentEval) || !shallowSameControls(ev, this.currentEval);
26879
27048
  if (this.pickerInProgress) this.tryAdvancePicker(screen);
@@ -27776,6 +27945,8 @@ var CliProviderInstance = class {
27776
27945
  historyWriter;
27777
27946
  runtimeMessages = [];
27778
27947
  lastPersistedHistoryMessages = [];
27948
+ lastAcknowledgedUserInputAt = 0;
27949
+ externalBusyIdleFingerprint = "";
27779
27950
  lastNativeSourceCanonicalCheckAt = 0;
27780
27951
  lastNativeSourceCanonicalCacheKey = void 0;
27781
27952
  cachedSqliteDb = null;
@@ -27904,7 +28075,11 @@ var CliProviderInstance = class {
27904
28075
  typeof adapterStatus?.providerSessionId === "string" ? adapterStatus.providerSessionId : ""
27905
28076
  );
27906
28077
  const autoApproveActive = this.maybeAutoApproveStatus(adapterStatus, Date.now());
27907
- const visibleStatus = parseErrorMessage || parsedStatus?.status === "error" ? "error" : autoApproveActive ? "generating" : adapterStatus.status;
28078
+ let visibleStatus = parseErrorMessage || parsedStatus?.status === "error" ? "error" : autoApproveActive ? "generating" : adapterStatus.status;
28079
+ const externalNativeFinal = this.getExternalNativeFinalReconciliation(parsedStatus?.messages, adapterStatus);
28080
+ if (externalNativeFinal && isCliGeneratingLikeStatus(visibleStatus)) {
28081
+ visibleStatus = "idle";
28082
+ }
27908
28083
  const runtime = this.adapter.getRuntimeMetadata();
27909
28084
  this.maybeAppendRuntimeRecoveryMessage(runtime);
27910
28085
  let parsedMessages = Array.isArray(parsedStatus?.messages) ? parsedStatus.messages : [];
@@ -28066,7 +28241,22 @@ var CliProviderInstance = class {
28066
28241
  };
28067
28242
  }
28068
28243
  updateSettings(newSettings) {
28069
- this.settings = { ...newSettings };
28244
+ const runtimeMeshSettings = {};
28245
+ for (const key of [
28246
+ "meshNodeFor",
28247
+ "meshNodeId",
28248
+ "meshActiveTaskId",
28249
+ "meshCoordinatorFor",
28250
+ "meshCoordinatorDaemonId",
28251
+ "meshCoordinatorNodeId",
28252
+ "spawnedSessionVisibility",
28253
+ "launchedByCoordinator"
28254
+ ]) {
28255
+ if (this.settings[key] !== void 0 && newSettings[key] === void 0) {
28256
+ runtimeMeshSettings[key] = this.settings[key];
28257
+ }
28258
+ }
28259
+ this.settings = { ...newSettings, ...runtimeMeshSettings };
28070
28260
  this.adapter.updateRuntimeSettings?.(this.settings);
28071
28261
  this.monitor.updateConfig({
28072
28262
  approvalAlert: this.settings.approvalAlert !== false,
@@ -28157,6 +28347,8 @@ var CliProviderInstance = class {
28157
28347
  const content = typeof input === "string" ? input.trim() : buildCliStructuredInputPrompt(input).trim();
28158
28348
  if (!content) return;
28159
28349
  const receivedAt = Date.now();
28350
+ this.lastAcknowledgedUserInputAt = receivedAt;
28351
+ this.externalBusyIdleFingerprint = "";
28160
28352
  const dedupKey = `user_input_ack:${crypto4.createHash("sha256").update(`${this.instanceId}:${content}:${receivedAt}`).digest("hex").slice(0, 24)}`;
28161
28353
  this.appendRuntimeMessage(buildChatMessage({
28162
28354
  role: "user",
@@ -28305,6 +28497,50 @@ var CliProviderInstance = class {
28305
28497
  const evidence = this.completionFinalAssistantEvidence(parsedMessages);
28306
28498
  return extractFinalSummaryFromMessages(evidence.messages);
28307
28499
  }
28500
+ externalNativeFinalFingerprint(evidence) {
28501
+ const messages = Array.isArray(evidence.messages) ? evidence.messages : [];
28502
+ const visibleMessages = messages.filter((message) => isUserFacingChatMessage(message));
28503
+ const lastVisible = visibleMessages[visibleMessages.length - 1];
28504
+ const content = lastVisible ? flattenContent(lastVisible.content).trim() : "";
28505
+ const receivedAt = lastVisible ? getMessageTime(lastVisible) : 0;
28506
+ const probe = this.lastExternalCompletionProbe;
28507
+ return crypto4.createHash("sha256").update([
28508
+ this.type,
28509
+ this.providerSessionId || "",
28510
+ probe?.sourcePath || "",
28511
+ String(probe?.sourceMtimeMs || 0),
28512
+ String(receivedAt || 0),
28513
+ content.slice(-500)
28514
+ ].join("\0")).digest("hex").slice(0, 24);
28515
+ }
28516
+ getExternalNativeFinalReconciliation(parsedMessages, adapterStatus) {
28517
+ const rawStatus = typeof adapterStatus?.status === "string" ? adapterStatus.status.trim() : "";
28518
+ if (!isCliGeneratingLikeStatus(rawStatus)) return null;
28519
+ if (hasNonEmptyCliModalButtons(adapterStatus?.activeModal ?? adapterStatus?.modal)) return null;
28520
+ const evidence = this.completionFinalAssistantEvidence(parsedMessages);
28521
+ if (evidence.source !== "external-native" || !evidence.present) return null;
28522
+ const messages = Array.isArray(evidence.messages) ? evidence.messages : [];
28523
+ const visibleMessages = messages.filter((message) => isUserFacingChatMessage(message));
28524
+ const lastVisible = visibleMessages[visibleMessages.length - 1];
28525
+ const lastMessageAt = lastVisible ? getMessageTime(lastVisible) : 0;
28526
+ const sourceMtimeMs = Number(this.lastExternalCompletionProbe?.sourceMtimeMs || 0);
28527
+ const minEvidenceAt = Math.max(
28528
+ this.startedAt > 0 ? this.startedAt - 5e3 : 0,
28529
+ this.generatingStartedAt > 0 ? this.generatingStartedAt - 5e3 : 0,
28530
+ this.lastAcknowledgedUserInputAt > 0 ? this.lastAcknowledgedUserInputAt - 1e3 : 0
28531
+ );
28532
+ if (minEvidenceAt > 0 && lastMessageAt > 0 && lastMessageAt < minEvidenceAt && sourceMtimeMs < minEvidenceAt) {
28533
+ return null;
28534
+ }
28535
+ const finalSummary = extractFinalSummaryFromMessages(evidence.messages);
28536
+ if (!finalSummary) return null;
28537
+ const fingerprint = this.externalNativeFinalFingerprint(evidence);
28538
+ if (fingerprint === this.externalBusyIdleFingerprint) {
28539
+ return { fingerprint, finalSummary, evidence };
28540
+ }
28541
+ this.externalBusyIdleFingerprint = fingerprint;
28542
+ return { fingerprint, finalSummary, evidence };
28543
+ }
28308
28544
  buildCompletedFinalizationDiagnostic(args) {
28309
28545
  let parsed = null;
28310
28546
  let parseError;
@@ -28375,17 +28611,18 @@ var CliProviderInstance = class {
28375
28611
  if (typeof adapterAny?.responseBuffer === "string" && adapterAny.responseBuffer.trim()) return false;
28376
28612
  return true;
28377
28613
  }
28378
- getCompletedFinalizationBlock(latestVisibleStatus, pending) {
28614
+ getCompletedFinalizationBlock(latestVisibleStatus, pending, opts) {
28379
28615
  if (latestVisibleStatus !== "idle") return { reason: `status:${latestVisibleStatus}`, terminal: true };
28380
28616
  const adapterAny = this.adapter;
28381
28617
  const approvalResolvedIdle = pending.previousStatus === "waiting_approval";
28382
- if (!approvalResolvedIdle) {
28618
+ const externalNativeFinal = opts?.externalNativeFinal || null;
28619
+ if (!approvalResolvedIdle && !externalNativeFinal) {
28383
28620
  if (adapterAny?.isWaitingForResponse === true) return { reason: "adapter_waiting_for_response", terminal: true };
28384
28621
  if (adapterAny?.currentTurnScope) return { reason: "adapter_turn_scope_active", terminal: true };
28385
28622
  if (this.hasAdapterPendingResponse()) return { reason: "adapter_pending_response", terminal: true };
28386
28623
  }
28387
28624
  const partial = typeof this.adapter.getPartialResponse === "function" ? this.adapter.getPartialResponse() : "";
28388
- if (typeof partial === "string" && partial.trim()) return { reason: "partial_response_pending", terminal: true };
28625
+ if (!externalNativeFinal && typeof partial === "string" && partial.trim()) return { reason: "partial_response_pending", terminal: true };
28389
28626
  let parsed;
28390
28627
  try {
28391
28628
  parsed = this.adapter.getScriptParsedStatus();
@@ -28395,6 +28632,7 @@ var CliProviderInstance = class {
28395
28632
  const parsedStatus = typeof parsed?.status === "string" ? parsed.status : "unknown";
28396
28633
  if (parsedStatus !== "idle") {
28397
28634
  const adapterStatus = this.adapter.getStatus({ allowParse: false });
28635
+ if (externalNativeFinal && isCliGeneratingLikeStatus(parsedStatus)) return null;
28398
28636
  if (this.shouldSuppressStaleParsedBusyStatus(parsed, adapterStatus)) return null;
28399
28637
  return { reason: `parsed_status:${parsedStatus}`, terminal: isCliGeneratingLikeStatus(parsedStatus) };
28400
28638
  }
@@ -28447,14 +28685,15 @@ var CliProviderInstance = class {
28447
28685
  }
28448
28686
  const latestStatus = this.adapter.getStatus({ allowParse: false });
28449
28687
  const latestAutoApproveActive = latestStatus.status === "waiting_approval" && this.shouldAutoApprove();
28450
- const latestVisibleStatus = latestAutoApproveActive ? "generating" : latestStatus.status;
28688
+ const externalNativeFinal = this.getExternalNativeFinalReconciliation(void 0, latestStatus);
28689
+ const latestVisibleStatus = externalNativeFinal && isCliGeneratingLikeStatus(latestStatus.status) ? "idle" : latestAutoApproveActive ? "generating" : latestStatus.status;
28451
28690
  if (latestVisibleStatus !== "idle") {
28452
28691
  LOG.info("CLI", `[${this.type}] cancelled pending completed (resumed ${latestVisibleStatus})`);
28453
28692
  this.completedDebouncePending = null;
28454
28693
  this.completedDebounceTimer = null;
28455
28694
  return;
28456
28695
  }
28457
- const block2 = this.getCompletedFinalizationBlock(latestVisibleStatus, pending);
28696
+ const block2 = this.getCompletedFinalizationBlock(latestVisibleStatus, pending, { externalNativeFinal });
28458
28697
  if (block2) {
28459
28698
  const blockReason = block2.reason;
28460
28699
  const waitedMs = Date.now() - pending.firstObservedAt;
@@ -28495,7 +28734,18 @@ var CliProviderInstance = class {
28495
28734
  chatTitle: pending.chatTitle,
28496
28735
  duration: pending.duration,
28497
28736
  timestamp: pending.timestamp,
28498
- finalSummary: this.completionFinalSummary(this.adapter?.getScriptParsedStatus()?.messages)
28737
+ finalSummary: externalNativeFinal?.finalSummary || this.completionFinalSummary(this.adapter?.getScriptParsedStatus()?.messages),
28738
+ ...externalNativeFinal ? {
28739
+ completionDiagnostic: {
28740
+ providerType: this.type,
28741
+ sessionId: this.instanceId,
28742
+ providerSessionId: this.providerSessionId || null,
28743
+ reconciliationReason: "external_native_final_assistant_while_adapter_busy",
28744
+ finalAssistantPresent: true,
28745
+ finalAssistantEvidenceSource: externalNativeFinal.evidence.source,
28746
+ externalFinalFingerprint: externalNativeFinal.fingerprint
28747
+ }
28748
+ } : {}
28499
28749
  });
28500
28750
  this.completedDebouncePending = null;
28501
28751
  this.completedDebounceTimer = null;
@@ -28551,7 +28801,8 @@ var CliProviderInstance = class {
28551
28801
  const parsedStatus = null;
28552
28802
  const rawStatus = adapterStatus.status;
28553
28803
  const autoApproveActive = this.maybeAutoApproveStatus(adapterStatus, now);
28554
- const newStatus = autoApproveActive ? "generating" : rawStatus;
28804
+ const externalNativeFinal = this.getExternalNativeFinalReconciliation(void 0, adapterStatus);
28805
+ const newStatus = externalNativeFinal && isCliGeneratingLikeStatus(rawStatus) ? "idle" : autoApproveActive ? "generating" : rawStatus;
28555
28806
  const dirName = this.workingDir.split("/").filter(Boolean).pop() || "session";
28556
28807
  const chatTitle = `${this.provider.name} \xB7 ${dirName}`;
28557
28808
  const partial = this.adapter.getPartialResponse();
@@ -30552,15 +30803,29 @@ function colorize(color, text) {
30552
30803
  const fn = chalkApi?.[color];
30553
30804
  return typeof fn === "function" ? fn(text) : text;
30554
30805
  }
30555
- var COORDINATOR_DELEGATED_ENV_UNSETS = {
30556
- ADHDEV_INLINE_MESH: "",
30557
- ADHDEV_MCP_TRANSPORT: "",
30558
- ADHDEV_MESH_ID: "",
30559
- HERMES_EPHEMERAL_SYSTEM_PROMPT: ""
30560
- };
30806
+ var DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS = [
30807
+ "ADHDEV_INLINE_MESH",
30808
+ "ADHDEV_MCP_TRANSPORT",
30809
+ "ADHDEV_MESH_ID",
30810
+ "HERMES_EPHEMERAL_SYSTEM_PROMPT"
30811
+ ];
30561
30812
  function hasCliArg(args, flag) {
30562
30813
  return args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
30563
30814
  }
30815
+ function hasConfigOverride(args, key) {
30816
+ for (let index = 0; index < args.length; index += 1) {
30817
+ const arg = args[index];
30818
+ const next = args[index + 1];
30819
+ if ((arg === "-c" || arg === "--config") && typeof next === "string") {
30820
+ if (next === key || next.startsWith(`${key}=`) || next.startsWith(`${key}.`)) return true;
30821
+ }
30822
+ if (arg.startsWith("--config=")) {
30823
+ const value = arg.slice("--config=".length);
30824
+ if (value === key || value.startsWith(`${key}=`) || value.startsWith(`${key}.`)) return true;
30825
+ }
30826
+ }
30827
+ return false;
30828
+ }
30564
30829
  function ensureEmptyDelegatedMcpConfig(workspace) {
30565
30830
  const baseDir = path23.join(os17.tmpdir(), "adhdev-delegated-agent-empty-mcp");
30566
30831
  (0, import_fs12.mkdirSync)(baseDir, { recursive: true });
@@ -30570,11 +30835,30 @@ function ensureEmptyDelegatedMcpConfig(workspace) {
30570
30835
  return filePath;
30571
30836
  }
30572
30837
  function buildCoordinatorDelegatedCliLaunchOptions(input) {
30573
- const cliType = String(input.cliType || "").trim();
30574
30838
  const cliArgs = Array.isArray(input.cliArgs) ? [...input.cliArgs] : [];
30575
- const env = { ...input.env || {}, ...COORDINATOR_DELEGATED_ENV_UNSETS };
30576
- if (cliType === "claude-cli" && !hasCliArg(cliArgs, "--mcp-config")) {
30577
- cliArgs.unshift("--mcp-config", ensureEmptyDelegatedMcpConfig(input.workspace));
30839
+ const env = { ...input.env || {} };
30840
+ const envUnsets = new Set(DEFAULT_COORDINATOR_DELEGATED_ENV_UNSETS);
30841
+ for (const key of input.isolation?.env?.unset || []) {
30842
+ if (typeof key === "string" && key.trim()) envUnsets.add(key.trim());
30843
+ }
30844
+ for (const key of envUnsets) env[key] = "";
30845
+ for (const rule of input.isolation?.args || []) {
30846
+ if (!rule || typeof rule !== "object") continue;
30847
+ if (rule.mode === "empty_mcp_config") {
30848
+ if (rule.flag && !hasCliArg(cliArgs, rule.flag)) {
30849
+ cliArgs.unshift(rule.flag, ensureEmptyDelegatedMcpConfig(input.workspace));
30850
+ }
30851
+ if (rule.strictFlag && !hasCliArg(cliArgs, rule.strictFlag)) {
30852
+ cliArgs.unshift(rule.strictFlag);
30853
+ }
30854
+ continue;
30855
+ }
30856
+ if (rule.mode === "config_override") {
30857
+ const key = String(rule.dedupeKey || rule.key || "").trim();
30858
+ const flag = String(rule.flag || "").trim();
30859
+ if (!key || !flag || hasConfigOverride(cliArgs, key)) continue;
30860
+ cliArgs.unshift(flag, `${rule.key}=${rule.value}`);
30861
+ }
30578
30862
  }
30579
30863
  return { cliArgs, env };
30580
30864
  }
@@ -31237,22 +31521,25 @@ Run 'adhdev doctor' for detailed diagnostics.`
31237
31521
  const dir = resolved.path;
31238
31522
  const launchSource = resolved.source;
31239
31523
  if (!cliType) throw new Error("cliType required");
31524
+ const providerType = this.providerLoader.resolveAlias(cliType);
31525
+ const provLookup = this.providerLoader.getMeta(providerType);
31240
31526
  const settingsOverride = args?.settings && typeof args.settings === "object" ? args.settings : void 0;
31241
31527
  const delegatedLaunch = settingsOverride?.launchedByCoordinator === true ? buildCoordinatorDelegatedCliLaunchOptions({
31242
31528
  cliType,
31243
31529
  workspace: dir,
31244
31530
  cliArgs: args?.cliArgs,
31245
- env: args?.env
31531
+ env: args?.env,
31532
+ isolation: provLookup?.meshCoordinator?.delegatedWorkerIsolation
31246
31533
  }) : null;
31247
- const provLookup = this.providerLoader.getMeta(this.providerLoader.resolveAlias(cliType));
31248
- const provTrust = provLookup?._sourceTrust;
31534
+ const provMeta = provLookup;
31535
+ const provTrust = provMeta?._sourceTrust;
31249
31536
  if (provTrust === "external-untrusted" && args?.confirmExternalUntrusted !== true) {
31250
31537
  return {
31251
31538
  success: false,
31252
31539
  error: "untrusted_external_provider",
31253
31540
  provider: {
31254
31541
  type: provLookup?.type ?? cliType,
31255
- sourceName: provLookup?._sourceName ?? null,
31542
+ sourceName: provMeta?._sourceName ?? null,
31256
31543
  trust: provTrust
31257
31544
  },
31258
31545
  hint: "Resend launch_cli with confirmExternalUntrusted=true after the user explicitly approves running JavaScript from this 3rd-party source."
@@ -31724,7 +32011,10 @@ function validateMeshCoordinator(raw, errors) {
31724
32011
  if (meshCoordinator.reason !== void 0 && (typeof meshCoordinator.reason !== "string" || !meshCoordinator.reason.trim())) {
31725
32012
  errors.push("meshCoordinator.reason must be a non-empty string when provided");
31726
32013
  }
31727
- const mcpConfig = meshCoordinator.mcpConfig;
32014
+ validateMeshCoordinatorMcpConfig(meshCoordinator.mcpConfig, errors);
32015
+ validateMeshCoordinatorDelegatedWorkerIsolation(meshCoordinator.delegatedWorkerIsolation, errors);
32016
+ }
32017
+ function validateMeshCoordinatorMcpConfig(mcpConfig, errors) {
31728
32018
  if (mcpConfig === void 0) return;
31729
32019
  if (!mcpConfig || typeof mcpConfig !== "object" || Array.isArray(mcpConfig)) {
31730
32020
  errors.push("meshCoordinator.mcpConfig must be an object");
@@ -31765,6 +32055,56 @@ function validateMeshCoordinator(raw, errors) {
31765
32055
  }
31766
32056
  }
31767
32057
  }
32058
+ function validateMeshCoordinatorDelegatedWorkerIsolation(raw, errors) {
32059
+ if (raw === void 0) return;
32060
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
32061
+ errors.push("meshCoordinator.delegatedWorkerIsolation must be an object");
32062
+ return;
32063
+ }
32064
+ const isolation = raw;
32065
+ const env = isolation.env;
32066
+ if (env !== void 0) {
32067
+ if (!env || typeof env !== "object" || Array.isArray(env)) {
32068
+ errors.push("meshCoordinator.delegatedWorkerIsolation.env must be an object");
32069
+ } else {
32070
+ const unset = env.unset;
32071
+ if (unset !== void 0 && (!Array.isArray(unset) || unset.some((key) => typeof key !== "string" || !key.trim()))) {
32072
+ errors.push("meshCoordinator.delegatedWorkerIsolation.env.unset must be an array of non-empty strings");
32073
+ }
32074
+ }
32075
+ }
32076
+ const args = isolation.args;
32077
+ if (args === void 0) return;
32078
+ if (!Array.isArray(args)) {
32079
+ errors.push("meshCoordinator.delegatedWorkerIsolation.args must be an array");
32080
+ return;
32081
+ }
32082
+ for (const [index, rule] of args.entries()) {
32083
+ const prefix = `meshCoordinator.delegatedWorkerIsolation.args[${index}]`;
32084
+ if (!rule || typeof rule !== "object" || Array.isArray(rule)) {
32085
+ errors.push(`${prefix} must be an object`);
32086
+ continue;
32087
+ }
32088
+ const item = rule;
32089
+ const mode = item.mode;
32090
+ if (mode !== "empty_mcp_config" && mode !== "config_override") {
32091
+ errors.push(`${prefix}.mode must be one of: empty_mcp_config, config_override`);
32092
+ continue;
32093
+ }
32094
+ for (const key of mode === "empty_mcp_config" ? ["flag"] : ["flag", "key", "value"]) {
32095
+ const value = item[key];
32096
+ if (typeof value !== "string" || !value.trim()) {
32097
+ errors.push(`${prefix}.${key} must be a non-empty string`);
32098
+ }
32099
+ }
32100
+ for (const key of ["strictFlag", "dedupeKey"]) {
32101
+ const value = item[key];
32102
+ if (value !== void 0 && (typeof value !== "string" || !value.trim())) {
32103
+ errors.push(`${prefix}.${key} must be a non-empty string when provided`);
32104
+ }
32105
+ }
32106
+ }
32107
+ }
31768
32108
  function validateControl(control, errors) {
31769
32109
  if (!control || typeof control !== "object") {
31770
32110
  errors.push("controls: each control must be an object");
@@ -37426,9 +37766,14 @@ function readCachedInlineMeshActiveSessionDetails(node) {
37426
37766
  node?.provider_type
37427
37767
  ),
37428
37768
  state: readStringValue(fallbackSession.status, fallbackSession.state, fallbackSession.lifecycle),
37769
+ chatStatus: readStringValue(fallbackSession.chatStatus, fallbackSession.chat_status),
37429
37770
  lifecycle: readStringValue(fallbackSession.lifecycle),
37430
37771
  title: readStringValue(fallbackSession.title, fallbackSession.displayName, fallbackSession.display_name) ?? null,
37431
37772
  workspace: readStringValue(fallbackSession.workspace, node?.workspace) ?? null,
37773
+ role: readStringValue(fallbackSession.role) ?? null,
37774
+ isSelfCoordinator: fallbackSession.isSelfCoordinator === true || fallbackSession.is_self_coordinator === true,
37775
+ createdAt: readStringValue(fallbackSession.createdAt, fallbackSession.created_at) ?? null,
37776
+ startedAt: readStringValue(fallbackSession.startedAt, fallbackSession.started_at) ?? null,
37432
37777
  lastActivityAt: readStringValue(fallbackSession.lastActivityAt, fallbackSession.last_activity_at) ?? null,
37433
37778
  recoveryState: readStringValue(fallbackSession.recoveryState, fallbackSession.recovery_state) ?? null,
37434
37779
  isCached: true
@@ -37569,15 +37914,26 @@ async function hydrateInlineMeshDirectTruth(args) {
37569
37914
  };
37570
37915
  }
37571
37916
  function summarizeMeshSessionRecord(record) {
37917
+ const meta = readObjectRecord(record?.meta);
37918
+ const isSelfCoordinator = Boolean(readStringValue(meta.meshCoordinatorFor));
37919
+ const chatStatus = readStringValue(record?.chatStatus, record?.activeChat?.status, meta.chatStatus, meta.sessionStatus);
37920
+ const state = readLiveMeshSessionState(record);
37921
+ const statusNote = isSelfCoordinator && (!chatStatus || chatStatus === "idle" || state === "idle") ? "Coordinator self status is sampled from the session host and may read idle while the coordinator is generating this response." : null;
37572
37922
  return {
37573
37923
  sessionId: readStringValue(record?.sessionId) || "unknown",
37574
37924
  providerType: readStringValue(record?.providerType),
37575
- state: readLiveMeshSessionState(record),
37925
+ state,
37926
+ chatStatus,
37576
37927
  lifecycle: readStringValue(record?.lifecycle),
37577
37928
  surfaceKind: getSessionHostSurfaceKind(record),
37578
- recoveryState: readStringValue(record?.meta?.runtimeRecoveryState) ?? null,
37929
+ recoveryState: readStringValue(meta.runtimeRecoveryState) ?? null,
37579
37930
  workspace: readStringValue(record?.workspace) ?? null,
37580
37931
  title: readStringValue(record?.displayName, record?.workspaceLabel) ?? null,
37932
+ role: isSelfCoordinator ? "coordinator" : readStringValue(meta.meshRole, meta.role) ?? null,
37933
+ isSelfCoordinator,
37934
+ statusNote,
37935
+ createdAt: toIsoTimestamp(record?.createdAt ?? record?.created_at),
37936
+ startedAt: toIsoTimestamp(record?.startedAt ?? record?.started_at ?? record?.spawnedAtMs ?? record?.spawned_at_ms),
37581
37937
  lastActivityAt: toIsoTimestamp(record?.updatedAt ?? record?.lastActivityAt ?? record?.last_activity_at),
37582
37938
  isCached: false
37583
37939
  };
@@ -38601,6 +38957,15 @@ var DaemonCommandRouter = class {
38601
38957
  this.aggregateMeshStatusCache.set(meshId, { builtAt, snapshot: this.cloneJsonValue(next), queueRevision: getMeshQueueRevision(meshId) });
38602
38958
  return next;
38603
38959
  }
38960
+ getCachedInlineMeshNodes() {
38961
+ const nodes = [];
38962
+ for (const mesh of this.inlineMeshCache.values()) {
38963
+ if (Array.isArray(mesh?.nodes)) {
38964
+ nodes.push(...mesh.nodes);
38965
+ }
38966
+ }
38967
+ return nodes;
38968
+ }
38604
38969
  getCachedInlineMesh(meshId, inlineMesh) {
38605
38970
  if (inlineMesh && typeof inlineMesh === "object") {
38606
38971
  return this.warmInlineMeshCache(meshId, inlineMesh);
@@ -38649,6 +39014,7 @@ var DaemonCommandRouter = class {
38649
39014
  }
38650
39015
  invalidateAggregateMeshStatus(meshId) {
38651
39016
  this.aggregateMeshStatusCache.delete(meshId);
39017
+ this.deps.onMeshStateChange?.(meshId);
38652
39018
  }
38653
39019
  async requireMeshHostMutationOwner(meshId, inlineMesh, operation) {
38654
39020
  const meshRecord = await this.getMeshForCommand(meshId, inlineMesh, { preferInline: true });
@@ -50134,6 +50500,7 @@ async function initDaemonComponents(config) {
50134
50500
  },
50135
50501
  onIdeConnected: () => poller?.start(),
50136
50502
  onStatusChange: config.onStatusChange,
50503
+ onMeshStateChange: config.onMeshStateChange,
50137
50504
  onPostChatCommand: config.onPostChatCommand,
50138
50505
  sessionHostControl: config.sessionHostControl,
50139
50506
  statusInstanceId: config.statusInstanceId,
@@ -50727,6 +51094,7 @@ var V1_CONTRACT_VERSION = "1.0.0";
50727
51094
  probeCdpPort,
50728
51095
  queuePendingMeshCoordinatorEvent,
50729
51096
  readAntigravityCliSession,
51097
+ readCachedInlineMeshActiveSessionDetails,
50730
51098
  readChatHistory,
50731
51099
  readClaudeCliSession,
50732
51100
  readCodexCliSession,