@adhdev/daemon-core 0.9.82-rc.203 → 0.9.82-rc.205

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
@@ -27175,6 +27175,8 @@ var SpecDriver = class {
27175
27175
  * explicit wake-up there's nothing to trigger the busy → idle
27176
27176
  * downshift. */
27177
27177
  busyExpiryTimer = null;
27178
+ /** Set true while reevaluate() is invoked from busyExpiryTimer callback. */
27179
+ busyExpiryFired = false;
27178
27180
  /** Pending idle-commit timer. Armed when the evaluator first returns idle;
27179
27181
  * fires after idle_hold_ms if no non-idle reading has cancelled it. */
27180
27182
  idleHoldTimer = null;
@@ -27249,11 +27251,22 @@ var SpecDriver = class {
27249
27251
  }
27250
27252
  this.pendingIdleState = null;
27251
27253
  }
27252
- pushHistory(stateId, label) {
27254
+ pushHistory(stateId, label, meta) {
27253
27255
  const now = Date.now();
27254
27256
  const durationMs = this.prevStateAt > 0 ? now - this.prevStateAt : 0;
27255
27257
  this.prevStateAt = now;
27256
- this.stateHistory.push({ stateId, label, at: now, durationMs });
27258
+ this.stateHistory.push({
27259
+ stateId,
27260
+ label,
27261
+ at: now,
27262
+ durationMs,
27263
+ reason: meta?.reason ?? "eval_match",
27264
+ ...meta?.matchedStateId !== void 0 ? { matchedStateId: meta.matchedStateId } : {},
27265
+ ...meta?.matchedRules !== void 0 ? { matchedRules: meta.matchedRules } : {},
27266
+ ...meta?.debounceKind !== void 0 ? { debounceKind: meta.debounceKind } : {},
27267
+ ...meta?.idleHoldMs !== void 0 ? { idleHoldMs: meta.idleHoldMs } : {},
27268
+ ...meta?.busyHoldMs !== void 0 ? { busyHoldMs: meta.busyHoldMs } : {}
27269
+ });
27257
27270
  if (this.stateHistory.length > 50) this.stateHistory.shift();
27258
27271
  }
27259
27272
  getStateHistory() {
@@ -27337,7 +27350,9 @@ var SpecDriver = class {
27337
27350
  this.busyExpiryTimer = setTimeout(() => {
27338
27351
  this.busyExpiryTimer = null;
27339
27352
  LOG.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] busyExpiry fired holdMs=${holdMs}`);
27353
+ this.busyExpiryFired = true;
27340
27354
  this.reevaluate();
27355
+ this.busyExpiryFired = false;
27341
27356
  }, Math.max(holdMs + 50, 100));
27342
27357
  }
27343
27358
  reevaluate(forceEmit = false) {
@@ -27402,6 +27417,8 @@ var SpecDriver = class {
27402
27417
  if (isIdleState && idleHoldMs > 0 && this.currentStateId !== evState.id) {
27403
27418
  if (!this.idleHoldTimer) {
27404
27419
  this.pendingIdleState = evState;
27420
+ const capturedEv = ev;
27421
+ const capturedMatchedRules = extractMatchedRules(ev);
27405
27422
  this.idleHoldTimer = setTimeout(() => {
27406
27423
  this.idleHoldTimer = null;
27407
27424
  const committed = this.pendingIdleState;
@@ -27409,16 +27426,22 @@ var SpecDriver = class {
27409
27426
  if (!committed) return;
27410
27427
  LOG.debug("SpecDriver", `[${this.opts.specPath.split("/").slice(-3).join("/")}] idleHold committed after ${idleHoldMs}ms`);
27411
27428
  this.currentStateId = committed.id;
27412
- this.currentEval = ev;
27413
- this.pushHistory(committed.id, committed.label);
27429
+ this.currentEval = capturedEv;
27430
+ this.pushHistory(committed.id, committed.label, {
27431
+ reason: "idle_hold_committed",
27432
+ matchedStateId: capturedEv.state.id,
27433
+ matchedRules: capturedMatchedRules,
27434
+ debounceKind: "idle_hold",
27435
+ idleHoldMs
27436
+ });
27414
27437
  this.emit({
27415
27438
  kind: "state_changed",
27416
27439
  state: committed,
27417
27440
  modal: null,
27418
- controls: ev.controls.map((c) => ({ id: c.id, label: c.label, action_type: c.actionType }))
27441
+ controls: capturedEv.controls.map((c) => ({ id: c.id, label: c.label, action_type: c.actionType }))
27419
27442
  });
27420
27443
  this.armOrCancelDelegateTimers(committed.id);
27421
- if (this.opts.emitTrace) this.emit({ kind: "spec_trace", entries: ev.trace });
27444
+ if (this.opts.emitTrace) this.emit({ kind: "spec_trace", entries: capturedEv.trace });
27422
27445
  }, idleHoldMs);
27423
27446
  }
27424
27447
  this.currentEval = ev;
@@ -27445,7 +27468,31 @@ var SpecDriver = class {
27445
27468
  }
27446
27469
  if (changed) {
27447
27470
  this.currentStateId = evState.id;
27448
- this.pushHistory(evState.id, evState.label);
27471
+ const matchedRules = extractMatchedRules(ev);
27472
+ let transitionReason;
27473
+ let debounceKind;
27474
+ let transitionBusyHoldMs;
27475
+ if (forceEmit) {
27476
+ transitionReason = "forceEmit";
27477
+ debounceKind = "none";
27478
+ } else if (evState.id !== ev.state.id) {
27479
+ transitionReason = "completion_idle_after";
27480
+ debounceKind = "completion_idle_after";
27481
+ } else if (this.busyExpiryFired) {
27482
+ transitionReason = "busy_hold_expired";
27483
+ debounceKind = "busy_hold";
27484
+ transitionBusyHoldMs = busyHoldMs;
27485
+ } else {
27486
+ transitionReason = "eval_match";
27487
+ debounceKind = "none";
27488
+ }
27489
+ this.pushHistory(evState.id, evState.label, {
27490
+ reason: transitionReason,
27491
+ matchedStateId: ev.state.id,
27492
+ matchedRules,
27493
+ debounceKind,
27494
+ ...transitionBusyHoldMs !== void 0 ? { busyHoldMs: transitionBusyHoldMs } : {}
27495
+ });
27449
27496
  this.emit({
27450
27497
  kind: "state_changed",
27451
27498
  state: evState,
@@ -27608,6 +27655,10 @@ function guessExt(mime) {
27608
27655
  if (/webp/i.test(mime)) return ".webp";
27609
27656
  return ".bin";
27610
27657
  }
27658
+ function extractMatchedRules(ev) {
27659
+ if (!Array.isArray(ev.trace)) return [];
27660
+ return ev.trace.filter((t) => t.matched === true || t.kind === "state_match").map((t) => t.rule ?? t.stateId ?? t.id ?? String(t)).filter(Boolean);
27661
+ }
27611
27662
 
27612
27663
  // src/providers/spec/native-history-executor.ts
27613
27664
  import * as fs11 from "fs";
@@ -28550,21 +28601,11 @@ var SpecCliAdapter = class {
28550
28601
  let sections;
28551
28602
  try {
28552
28603
  screen = this.driver.snapshot();
28553
- const lines = screen.split("\n");
28554
- sections = {};
28555
- for (const sec of this.spec.layout?.sections ?? []) {
28556
- const from = sec.from_top;
28557
- const fromBottom = sec.from_bottom;
28558
- let start = 0;
28559
- let end = lines.length;
28560
- if (typeof from === "number") start = Math.max(0, from);
28561
- else if (typeof fromBottom === "number") start = Math.max(0, lines.length - fromBottom);
28562
- const until = sec.until;
28563
- if (until && typeof until === "object" && typeof until.section === "string") {
28564
- const ref = (this.spec.layout?.sections ?? []).find((s) => s.id === until.section);
28565
- if (ref && typeof ref.from_bottom === "number") end = Math.max(start, lines.length - ref.from_bottom);
28566
- }
28567
- sections[sec.id] = lines.slice(start, end).join("\n");
28604
+ const driverSections = this.driver.getSections?.();
28605
+ if (driverSections) {
28606
+ sections = Object.fromEntries(driverSections.map((s) => [s.id, s.text]));
28607
+ } else {
28608
+ sections = this.readCurrentScreenSections(screen);
28568
28609
  }
28569
28610
  } catch {
28570
28611
  }
@@ -30075,8 +30116,6 @@ var CliProviderInstance = class {
30075
30116
  clearTimeout(this.generatingDebounceTimer);
30076
30117
  this.generatingDebounceTimer = null;
30077
30118
  }
30078
- this.generatingDebouncePending = null;
30079
- this.generatingStartedAt = 0;
30080
30119
  let shortFinalSummary;
30081
30120
  let shortEvidenceSource = "unavailable";
30082
30121
  try {
@@ -30086,22 +30125,28 @@ var CliProviderInstance = class {
30086
30125
  shortFinalSummary = extractFinalSummaryFromMessages(evidence.messages);
30087
30126
  } catch {
30088
30127
  }
30089
- if ((this.provider.requiresFinalAssistantBeforeIdle === true || shortEvidenceSource === "external-native") && !shortFinalSummary) {
30090
- LOG.info("CLI", `[${this.type}] suppressed short completion without final assistant evidence`);
30091
- } else {
30092
- this.pushEvent({
30093
- event: "agent:generating_completed",
30094
- chatTitle,
30095
- duration: 0,
30096
- timestamp: now,
30097
- finalSummary: shortFinalSummary,
30098
- completionDiagnostic: {
30099
- reason: "short_generating_suppressed",
30100
- shortDurationMs,
30101
- finalAssistantEvidenceSource: shortEvidenceSource
30102
- }
30103
- });
30128
+ if (shortFinalSummary) {
30129
+ this.pushEvent({ event: "agent:generating_started", chatTitle, timestamp: now - shortDurationMs });
30130
+ }
30131
+ this.generatingDebouncePending = null;
30132
+ this.generatingStartedAt = 0;
30133
+ const missingEvidence = (this.provider.requiresFinalAssistantBeforeIdle === true || shortEvidenceSource === "external-native") && !shortFinalSummary;
30134
+ if (missingEvidence) {
30135
+ LOG.warn("CLI", `[${this.type}] short completion missing final assistant evidence (source=${shortEvidenceSource})`);
30104
30136
  }
30137
+ this.pushEvent({
30138
+ event: "agent:generating_completed",
30139
+ chatTitle,
30140
+ duration: 0,
30141
+ timestamp: now,
30142
+ finalSummary: shortFinalSummary,
30143
+ completionDiagnostic: {
30144
+ reason: "short_generating_suppressed",
30145
+ shortDurationMs,
30146
+ finalAssistantEvidenceSource: shortEvidenceSource,
30147
+ ...missingEvidence ? { blockReason: "missing_final_assistant" } : {}
30148
+ }
30149
+ });
30105
30150
  } else {
30106
30151
  this.completedDebouncePending = {
30107
30152
  chatTitle,