@adhdev/daemon-core 0.9.82-rc.353 → 0.9.82-rc.354

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.mjs CHANGED
@@ -311,10 +311,10 @@ function readInjected(value) {
311
311
  }
312
312
  function getDaemonBuildInfo() {
313
313
  if (cached) return cached;
314
- const commit = readInjected(true ? "a680b74d9b940b82f691ebb85a725a1a72445bfc" : void 0) ?? "unknown";
315
- const commitShort = readInjected(true ? "a680b74d" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
- const version = readInjected(true ? "0.9.82-rc.353" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
- const builtAt = readInjected(true ? "2026-06-22T09:11:13.499Z" : void 0);
314
+ const commit = readInjected(true ? "5d100a177f412ae29a58048f0a211c3928b06910" : void 0) ?? "unknown";
315
+ const commitShort = readInjected(true ? "5d100a17" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
+ const version = readInjected(true ? "0.9.82-rc.354" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
+ const builtAt = readInjected(true ? "2026-06-22T11:32:05.389Z" : void 0);
318
318
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
319
319
  return cached;
320
320
  }
@@ -1067,6 +1067,9 @@ __export(git_diff_exports, {
1067
1067
  });
1068
1068
  import { readFile, realpath as realpath2 } from "fs/promises";
1069
1069
  import * as path2 from "path";
1070
+ function withCollectionTimeout(options) {
1071
+ return options.timeoutMs === void 0 ? { ...options, timeoutMs: GIT_STATUS_TIMEOUT_MS } : options;
1072
+ }
1070
1073
  function validateBaseRef(ref) {
1071
1074
  const trimmed = ref.trim();
1072
1075
  if (!trimmed || trimmed.startsWith("-") || trimmed.includes("..") || !/^[A-Za-z0-9][A-Za-z0-9._/@-]*$/.test(trimmed)) {
@@ -1076,14 +1079,15 @@ function validateBaseRef(ref) {
1076
1079
  }
1077
1080
  async function getGitDiffSummary(workspace, options = {}) {
1078
1081
  const lastCheckedAt = Date.now();
1082
+ const effectiveOptions = withCollectionTimeout(options);
1079
1083
  try {
1080
- const repo = await resolveGitRepository(workspace, options);
1084
+ const repo = await resolveGitRepository(workspace, effectiveOptions);
1081
1085
  const repoRoot = repo.repoRoot;
1082
1086
  if (options.baseRef) {
1083
1087
  const range = `${validateBaseRef(options.baseRef)}...HEAD`;
1084
1088
  const [nameStatus, numstat] = await Promise.all([
1085
- runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...options, cwd: repoRoot }),
1086
- runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...options, cwd: repoRoot })
1089
+ runGit(repo, ["diff", "--no-ext-diff", "--name-status", range, "--"], { ...effectiveOptions, cwd: repoRoot }),
1090
+ runGit(repo, ["diff", "--no-ext-diff", "--numstat", range, "--"], { ...effectiveOptions, cwd: repoRoot })
1087
1091
  ]);
1088
1092
  const outputBytes2 = byteLength(nameStatus.stdout + numstat.stdout);
1089
1093
  const changes2 = combineDiffEntries(nameStatus.stdout, numstat.stdout, false);
@@ -1102,11 +1106,11 @@ async function getGitDiffSummary(workspace, options = {}) {
1102
1106
  };
1103
1107
  }
1104
1108
  const [unstagedNameStatus, unstagedNumstat, stagedNameStatus, stagedNumstat, untracked] = await Promise.all([
1105
- runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
1106
- runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
1107
- runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
1108
- runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
1109
- runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...options, cwd: repoRoot })
1109
+ runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
1110
+ runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
1111
+ runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...effectiveOptions, cwd: repoRoot }),
1112
+ runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...effectiveOptions, cwd: repoRoot }),
1113
+ runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...effectiveOptions, cwd: repoRoot })
1110
1114
  ]);
1111
1115
  const outputBytes = byteLength(
1112
1116
  unstagedNameStatus.stdout + unstagedNumstat.stdout + stagedNameStatus.stdout + stagedNumstat.stdout + untracked.stdout
@@ -1148,13 +1152,14 @@ async function getGitDiffSummary(workspace, options = {}) {
1148
1152
  }
1149
1153
  async function getGitFileDiff(workspace, filePath, options = {}) {
1150
1154
  const lastCheckedAt = Date.now();
1151
- const repo = await resolveGitRepository(workspace, options);
1155
+ const effectiveOptions = withCollectionTimeout(options);
1156
+ const repo = await resolveGitRepository(workspace, effectiveOptions);
1152
1157
  const repoRoot = repo.repoRoot;
1153
1158
  const selected = await resolveRepoFilePath(repoRoot, filePath);
1154
1159
  const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
1155
1160
  if (options.baseRef) {
1156
1161
  const range = `${validateBaseRef(options.baseRef)}...HEAD`;
1157
- const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...options, cwd: repoRoot });
1162
+ const result = await runGit(repo, ["diff", "--no-ext-diff", range, "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot });
1158
1163
  const bounded2 = truncateText(result.stdout, maxBytes);
1159
1164
  return {
1160
1165
  workspace: repo.workspace,
@@ -1167,13 +1172,13 @@ async function getGitFileDiff(workspace, filePath, options = {}) {
1167
1172
  };
1168
1173
  }
1169
1174
  const [unstaged, staged] = await Promise.all([
1170
- runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot }),
1171
- runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot })
1175
+ runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot }),
1176
+ runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...effectiveOptions, cwd: repoRoot })
1172
1177
  ]);
1173
1178
  let diff = [unstaged.stdout, staged.stdout].filter((part) => part.length > 0).join("\n");
1174
1179
  if (!diff) {
1175
1180
  const untracked = await runGit(repo, ["ls-files", "--others", "--exclude-standard", "--", selected.relativePath], {
1176
- ...options,
1181
+ ...effectiveOptions,
1177
1182
  cwd: repoRoot
1178
1183
  });
1179
1184
  const untrackedFiles = untracked.stdout.split("\n").filter(Boolean);
@@ -27072,6 +27077,42 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
27072
27077
  return fn() || null;
27073
27078
  }
27074
27079
 
27080
+ // src/providers/manual-attendance.ts
27081
+ var AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS = 6e4;
27082
+ var ManualAttendanceTracker = class {
27083
+ constructor(suppressMs = AUTO_APPROVE_MANUAL_ATTENDANCE_SUPPRESS_MS) {
27084
+ this.suppressMs = suppressMs;
27085
+ }
27086
+ lastInteractionAt = 0;
27087
+ /** Record that a human just drove this session by hand. */
27088
+ note(now = Date.now()) {
27089
+ this.lastInteractionAt = now;
27090
+ }
27091
+ /** True while a manual interaction is recent enough to suppress auto-approve. */
27092
+ isAttended(now = Date.now()) {
27093
+ return this.lastInteractionAt > 0 && now - this.lastInteractionAt < this.suppressMs;
27094
+ }
27095
+ /**
27096
+ * Milliseconds remaining in the current suppression window, or 0 when not
27097
+ * attended. Used to re-arm a re-check timer so auto-approve fires the moment
27098
+ * the window lapses even if the PTY/agent has since gone silent.
27099
+ */
27100
+ remainingMs(now = Date.now()) {
27101
+ if (this.lastInteractionAt <= 0) return 0;
27102
+ return Math.max(0, this.suppressMs - (now - this.lastInteractionAt));
27103
+ }
27104
+ };
27105
+ var MANUAL_ATTENDANCE_COMMANDS = /* @__PURE__ */ new Set([
27106
+ "select_session",
27107
+ "open_panel",
27108
+ "invoke_provider_script",
27109
+ "set_mode",
27110
+ "change_model",
27111
+ "set_thought_level",
27112
+ "resolve_action",
27113
+ "pty_input"
27114
+ ]);
27115
+
27075
27116
  // src/commands/chat-commands.ts
27076
27117
  init_contracts();
27077
27118
  init_provider_input_support();
@@ -31411,11 +31452,38 @@ var DaemonCommandHandler = class {
31411
31452
  setAgentStreamManager(manager) {
31412
31453
  this._agentStream = manager;
31413
31454
  }
31455
+ /**
31456
+ * When a command in the manual-attendance set arrives for a session this
31457
+ * daemon hosts, stamp the live instance so auto-approve holds while the user
31458
+ * drives the session by hand. Provider-common: the signal is the command
31459
+ * (foreground select_session / open_panel, controlbar invoke_provider_script
31460
+ * / set_mode / change_model / set_thought_level, manual resolve_action,
31461
+ * pty_input), never any CLI-specific modal text — so it works identically for
31462
+ * every CLI/ACP provider. send_chat is deliberately excluded because a
31463
+ * coordinator delegating a task to a worker also uses send_chat; counting it
31464
+ * would wrongly suppress the worker's delegated auto-approve. For a remote
31465
+ * mesh worker session the controlbar commands are forwarded to the owning
31466
+ * worker daemon, which runs this same hook there, so attendance is recorded
31467
+ * on the daemon that actually hosts the instance.
31468
+ */
31469
+ noteManualAttendanceIfApplicable(cmd, args) {
31470
+ if (!MANUAL_ATTENDANCE_COMMANDS.has(cmd)) return;
31471
+ const sessionId = this._currentRoute.session?.sessionId || (typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "");
31472
+ if (!sessionId) return;
31473
+ const session = this._ctx.sessionRegistry?.get(sessionId);
31474
+ const instanceKey = session?.adapterKey || session?.instanceKey || sessionId;
31475
+ const instance = this._ctx.instanceManager?.getInstance(instanceKey);
31476
+ try {
31477
+ instance?.noteManualInteraction?.();
31478
+ } catch {
31479
+ }
31480
+ }
31414
31481
  // ─── Command Dispatcher ──────────────────────────
31415
31482
  async handle(cmd, args) {
31416
31483
  this._currentRoute = this.resolveRoute(args);
31417
31484
  const startedAt = Date.now();
31418
31485
  this.logCommandStart(cmd, args);
31486
+ this.noteManualAttendanceIfApplicable(cmd, args);
31419
31487
  let result;
31420
31488
  if (isGitCommandName(cmd)) {
31421
31489
  result = await handleGitCommand(cmd, args, this._ctx.gitCommandServices);
@@ -35369,6 +35437,11 @@ var CliProviderInstance = class _CliProviderInstance {
35369
35437
  // a settle gate was in progress. Drives AUTO_APPROVE_GATE_HYSTERESIS_MS so a
35370
35438
  // brief generating flip does not immediately wipe the settle clock.
35371
35439
  autoApproveInactiveSince = 0;
35440
+ // Provider-common manual-attendance signal: while a human is actively driving
35441
+ // this session from the dashboard, auto-approve holds so they can take manual
35442
+ // control. Background mesh workers are never attended → delegated auto-approve
35443
+ // is unaffected.
35444
+ manualAttendance = new ManualAttendanceTracker();
35372
35445
  controlValues = {};
35373
35446
  summaryMetadata = void 0;
35374
35447
  appliedEffectKeys = /* @__PURE__ */ new Set();
@@ -35644,7 +35717,7 @@ var CliProviderInstance = class _CliProviderInstance {
35644
35717
  }
35645
35718
  getHotChatSessionState() {
35646
35719
  const adapterStatus = this.adapter.getStatus({ allowParse: false });
35647
- const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
35720
+ const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
35648
35721
  const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
35649
35722
  const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
35650
35723
  const runtime = this.adapter.getRuntimeMetadata();
@@ -35659,7 +35732,7 @@ var CliProviderInstance = class _CliProviderInstance {
35659
35732
  }
35660
35733
  getSessionModalState(sessionId) {
35661
35734
  const adapterStatus = this.adapter.getStatus({ allowParse: true });
35662
- const autoApproveActive = adapterStatus.status === "waiting_approval" && this.shouldAutoApprove();
35735
+ const autoApproveActive = this.autoApproveEffectivelyActive(adapterStatus.status);
35663
35736
  const autoApproveHoldIdle = this.autoApproveBusy && adapterStatus.status === "idle";
35664
35737
  const visibleStatus = autoApproveActive || autoApproveHoldIdle ? "generating" : adapterStatus.status;
35665
35738
  const dirName = workingDirBasename(this.workingDir);
@@ -35740,7 +35813,7 @@ var CliProviderInstance = class _CliProviderInstance {
35740
35813
  } catch {
35741
35814
  return null;
35742
35815
  }
35743
- if (adapterStatus.status === "waiting_approval" && !this.shouldAutoApprove()) {
35816
+ if (adapterStatus.status === "waiting_approval" && !this.autoApproveEffectivelyActive(adapterStatus.status)) {
35744
35817
  return "waiting_approval";
35745
35818
  }
35746
35819
  return null;
@@ -36186,6 +36259,18 @@ var CliProviderInstance = class _CliProviderInstance {
36186
36259
  this.lastApprovalEventFingerprint = "";
36187
36260
  }
36188
36261
  maybeAutoApproveStatus(adapterStatus, now = Date.now()) {
36262
+ if (adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove() && this.manualAttendance.isAttended(now)) {
36263
+ this.lastAutoApprovalSignature = "";
36264
+ this.pendingAutoApprovalSignature = "";
36265
+ this.pendingAutoApprovalSince = 0;
36266
+ this.autoApproveInactiveSince = 0;
36267
+ if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
36268
+ this.autoApproveSettleTimer = setTimeout(() => {
36269
+ this.autoApproveSettleTimer = null;
36270
+ this.recheckAutoApproveSettled();
36271
+ }, this.manualAttendance.remainingMs(now) + 20);
36272
+ return false;
36273
+ }
36189
36274
  const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
36190
36275
  if (!autoApproveActive) {
36191
36276
  this.lastAutoApprovalSignature = "";
@@ -36651,6 +36736,21 @@ ${effect.notification.body || ""}`.trim();
36651
36736
  }
36652
36737
  return false;
36653
36738
  }
36739
+ /** @see ProviderInstance.noteManualInteraction */
36740
+ noteManualInteraction(now = Date.now()) {
36741
+ this.manualAttendance.note(now);
36742
+ }
36743
+ /**
36744
+ * Whether auto-approve should be treated as active *right now* for display
36745
+ * and firing decisions: the configured intent AND the user is not currently
36746
+ * attending this session by hand. When a human is attending, auto-approve is
36747
+ * held so the modal stays visible and they can drive it via the controlbar.
36748
+ * Provider-agnostic — the attendance signal is the command set, never any
36749
+ * CLI-specific modal text.
36750
+ */
36751
+ autoApproveEffectivelyActive(status, now = Date.now()) {
36752
+ return status === "waiting_approval" && this.shouldAutoApprove() && !this.manualAttendance.isAttended(now);
36753
+ }
36654
36754
  recordAutoApproval(modalMessage, buttonLabel, now = Date.now()) {
36655
36755
  this.appendRuntimeSystemMessage(
36656
36756
  formatAutoApprovalMessage(modalMessage, buttonLabel),
@@ -37601,7 +37701,7 @@ var AcpProviderInstance = class {
37601
37701
  input: tc.rawInput ? typeof tc.rawInput === "string" ? tc.rawInput : JSON.stringify(tc.rawInput) : void 0
37602
37702
  });
37603
37703
  }
37604
- if (this.settings.autoApprove !== false) {
37704
+ if (this.settings.autoApprove !== false && !this.manualAttendance.isAttended()) {
37605
37705
  const toolTitle = tc.title || tc.toolCallId || "tool call";
37606
37706
  this.log.info(`[${this.type}] Auto-approving: ${toolTitle}`);
37607
37707
  this.appendSystemMessage(`Auto-approved: ${toolTitle}`);
@@ -37832,6 +37932,15 @@ var AcpProviderInstance = class {
37832
37932
  this.detectStatusTransition();
37833
37933
  }
37834
37934
  permissionResolvers = [];
37935
+ // Provider-common manual-attendance signal: while a human is actively driving
37936
+ // this session from the dashboard, auto-approve holds so they can decide on
37937
+ // the permission request themselves. Background workers are never attended →
37938
+ // delegated auto-approve is unaffected.
37939
+ manualAttendance = new ManualAttendanceTracker();
37940
+ /** @see ProviderInstance.noteManualInteraction */
37941
+ noteManualInteraction(now = Date.now()) {
37942
+ this.manualAttendance.note(now);
37943
+ }
37835
37944
  async resolvePermission(approved) {
37836
37945
  const resolver = this.permissionResolvers.shift();
37837
37946
  if (resolver) {
@@ -38989,6 +39098,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
38989
39098
  );
38990
39099
  continue;
38991
39100
  }
39101
+ const restoredSettings = { ...this.providerLoader.getSettings(normalizedType) };
39102
+ const coordinatorEntry = getCoordinatorForSession(record.runtimeId);
39103
+ if (coordinatorEntry?.meshId) {
39104
+ restoredSettings.meshCoordinatorFor = coordinatorEntry.meshId;
39105
+ }
38992
39106
  try {
38993
39107
  await this.registerCliInstance(
38994
39108
  record.runtimeId,
@@ -38997,7 +39111,7 @@ Run 'adhdev doctor' for detailed diagnostics.`
38997
39111
  record.workspace,
38998
39112
  record.cliArgs,
38999
39113
  resolvedProvider,
39000
- {},
39114
+ restoredSettings,
39001
39115
  true,
39002
39116
  {
39003
39117
  providerSessionId: sessionBinding.providerSessionId,