@adhdev/daemon-core 0.9.82-rc.449 → 0.9.82-rc.450

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
@@ -404,10 +404,10 @@ function readInjected(value) {
404
404
  }
405
405
  function getDaemonBuildInfo() {
406
406
  if (cached) return cached;
407
- const commit = readInjected(true ? "fe0e4d2aa03aea2793c2379e5ffc89abef5143d6" : void 0) ?? "unknown";
408
- const commitShort = readInjected(true ? "fe0e4d2a" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
- const version = readInjected(true ? "0.9.82-rc.449" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
- const builtAt = readInjected(true ? "2026-07-03T01:58:07.610Z" : void 0);
407
+ const commit = readInjected(true ? "4d9f330890bc663a858fde1c84931144b825f8b2" : void 0) ?? "unknown";
408
+ const commitShort = readInjected(true ? "4d9f3308" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
409
+ const version = readInjected(true ? "0.9.82-rc.450" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
410
+ const builtAt = readInjected(true ? "2026-07-03T08:51:21.732Z" : void 0);
411
411
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
412
412
  return cached;
413
413
  }
@@ -19271,6 +19271,15 @@ function validateCondition(c, sectionIds, path44) {
19271
19271
  }
19272
19272
  if ("stable_ms" in w) {
19273
19273
  if (typeof w.stable_ms !== "number") errs.push(`${path44}.stable_ms must be a number`);
19274
+ if (w.section && !sectionIds.has(w.section)) errs.push(`${path44}.section "${w.section}" unknown`);
19275
+ if (w.ignore_lines !== void 0) {
19276
+ if (typeof w.ignore_lines !== "string") errs.push(`${path44}.ignore_lines must be a string`);
19277
+ else try {
19278
+ new RegExp(w.ignore_lines, "m");
19279
+ } catch (e) {
19280
+ errs.push(`${path44}.ignore_lines invalid regex: ${e.message}`);
19281
+ }
19282
+ }
19274
19283
  return errs;
19275
19284
  }
19276
19285
  errs.push(`${path44} is not a recognized condition`);
@@ -19571,10 +19580,13 @@ var init_evaluator = __esm({
19571
19580
  var fsm_evaluator_exports = {};
19572
19581
  __export(fsm_evaluator_exports, {
19573
19582
  evaluateConditionPreview: () => evaluateConditionPreview,
19574
- evaluateFsm: () => evaluateFsm
19583
+ evaluateFsm: () => evaluateFsm,
19584
+ stableRegionKey: () => stableRegionKey
19575
19585
  });
19576
- function regionKey(cursorAbove) {
19577
- return cursorAbove && cursorAbove > 0 ? cursorAbove : WHOLE_SCREEN;
19586
+ function stableRegionKey(cond) {
19587
+ const region = cond.section ? `section:${cond.section}` : cond.cursor_above && cond.cursor_above > 0 ? cond.cursor_above : WHOLE_SCREEN;
19588
+ if (!cond.ignore_lines) return region;
19589
+ return `${region}#ignore:${cond.ignore_lines}`;
19578
19590
  }
19579
19591
  function isRegex(c) {
19580
19592
  return "matches" in c;
@@ -19622,13 +19634,14 @@ function evalCond(cond, sections, fullScreen, cursor, prevLines, clock, legacyTr
19622
19634
  return { kind: "elapsed", result, detail: `elapsed ${age}ms / ${cond.elapsed_ms}ms`, remainingMs };
19623
19635
  }
19624
19636
  if (isStable(cond)) {
19625
- const key2 = regionKey(cond.cursor_above);
19637
+ const key2 = stableRegionKey(cond);
19626
19638
  const lastChanged = clock.regionLastChangedAt.get(key2) ?? clock.stateEnteredAt;
19627
19639
  const stableFor = clock.now - lastChanged;
19628
19640
  const result = stableFor >= cond.stable_ms;
19629
19641
  const remainingMs = result ? 0 : cond.stable_ms - stableFor;
19630
- const where = key2 === WHOLE_SCREEN ? "screen" : `cursor_above=${cond.cursor_above}`;
19631
- return { kind: "stable", result, detail: `stable ${where} ${stableFor}ms / ${cond.stable_ms}ms`, remainingMs };
19642
+ const where = cond.section ? `section=${cond.section}` : cond.cursor_above && cond.cursor_above > 0 ? `cursor_above=${cond.cursor_above}` : "screen";
19643
+ const ign = cond.ignore_lines ? " (ignore_lines)" : "";
19644
+ return { kind: "stable", result, detail: `stable ${where}${ign} ${stableFor}ms / ${cond.stable_ms}ms`, remainingMs };
19632
19645
  }
19633
19646
  if (isRegex(cond) || isChanged(cond)) {
19634
19647
  const result = evaluateCondition(cond, sections, fullScreen, cursor, prevLines, legacyTrace, stateId);
@@ -37788,8 +37801,10 @@ var FsmDriver = class {
37788
37801
  // ── Clock bookkeeping for time conditions.
37789
37802
  startedAtMs = 0;
37790
37803
  prevScreenLines = [];
37791
- /** Per cursor_above region (key: cursor_above, -1 = whole screen) last
37792
- * time that region's content changed. Drives stable_ms conditions. */
37804
+ /** Per stable region last time that region's content changed. Drives
37805
+ * stable_ms conditions. Key = stableRegionKey(cond): numeric cursor_above
37806
+ * (−1 = whole screen), or a `section:<id>` / `<region>#ignore:<pat>` string
37807
+ * when the clause scopes to a section or declares an ignore_lines filter. */
37793
37808
  regionLastChangedAt = /* @__PURE__ */ new Map();
37794
37809
  /** Timer that re-runs evaluate() when a time-condition would flip true
37795
37810
  * with no PTY frame to trigger it. */
@@ -38215,36 +38230,55 @@ var FsmDriver = class {
38215
38230
  }
38216
38231
  return out;
38217
38232
  }
38218
- /** Track which cursor_above regions changed since the previous frame so
38219
- * stable_ms conditions can measure quiet time. We record every region
38220
- * size referenced by a stable_ms condition in the spec, plus the whole
38221
- * screen (-1). */
38233
+ /** Track which stable regions changed since the previous frame so
38234
+ * stable_ms conditions can measure quiet time. We record every distinct
38235
+ * stable region referenced in the current state (numeric cursor_above /
38236
+ * whole-screen -1, and named `section:<id>` regions) plus, for each, the
38237
+ * optional `ignore_lines` filter that folds into its key.
38238
+ *
38239
+ * `ignore_lines` is the content-aware fix for the busy→idle wedge: lines
38240
+ * matching it are stripped from BOTH frames before the comparison, so a
38241
+ * benign residual ticker (bare token counter / elapsed timer that repaints
38242
+ * every frame post-generation) no longer resets the clock — while an active
38243
+ * spinner line, which does NOT match the benign pattern, still does (the
38244
+ * FALSEIDLE2 / FALSEBUSY-B whole-screen invariant is preserved). */
38222
38245
  trackRegionChanges(currentLines, cursor, now) {
38223
38246
  if (this.prevScreenLines.length === 0) return;
38224
- const sizes = this.stableRegionSizes();
38225
- for (const size of sizes) {
38226
- let cur;
38227
- let prev;
38228
- if (size < 0) {
38229
- cur = currentLines.join("\n");
38230
- prev = this.prevScreenLines.join("\n");
38247
+ const descs = this.stableRegionDescriptors();
38248
+ const needsSections = descs.some((d) => !!d.section);
38249
+ const curSections = needsSections ? resolveSections(this.spec.sections ?? {}, currentLines) : [];
38250
+ const prevSections = needsSections ? resolveSections(this.spec.sections ?? {}, this.prevScreenLines) : [];
38251
+ for (const d of descs) {
38252
+ let curLines;
38253
+ let prevLines;
38254
+ if (d.section) {
38255
+ curLines = sliceSectionLines(currentLines, curSections, d.section);
38256
+ prevLines = sliceSectionLines(this.prevScreenLines, prevSections, d.section);
38257
+ } else if (!d.cursor_above || d.cursor_above <= 0) {
38258
+ curLines = currentLines;
38259
+ prevLines = this.prevScreenLines;
38231
38260
  } else {
38232
- const start = Math.max(0, cursor.row - size);
38233
- cur = currentLines.slice(start, cursor.row).join("\n");
38234
- prev = this.prevScreenLines.slice(start, cursor.row).join("\n");
38235
- }
38236
- if (cur !== prev) this.regionLastChangedAt.set(size, now);
38237
- }
38238
- }
38239
- /** All cursor_above region sizes referenced by stable_ms conditions in the
38240
- * current state's outgoing transitions, plus whole-screen. Cached lazily
38241
- * per spec load would be nicer but the set is tiny. */
38242
- stableRegionSizes() {
38243
- const sizes = /* @__PURE__ */ new Set([-1]);
38261
+ const start = Math.max(0, cursor.row - d.cursor_above);
38262
+ curLines = currentLines.slice(start, cursor.row);
38263
+ prevLines = this.prevScreenLines.slice(start, cursor.row);
38264
+ }
38265
+ const cur = filterIgnoredLines(curLines, d.ignoreRe).join("\n");
38266
+ const prev = filterIgnoredLines(prevLines, d.ignoreRe).join("\n");
38267
+ if (cur !== prev) this.regionLastChangedAt.set(d.key, now);
38268
+ }
38269
+ }
38270
+ /** Every distinct stable-region descriptor referenced by stable_ms
38271
+ * conditions in the current state's outgoing transitions, plus the plain
38272
+ * whole-screen key (-1) that other machinery (stall watchdog) reads.
38273
+ * De-duplicated by key. Cached lazily per spec load would be nicer but the
38274
+ * set is tiny. */
38275
+ stableRegionDescriptors() {
38276
+ const byKey = /* @__PURE__ */ new Map();
38277
+ byKey.set(-1, { key: -1 });
38244
38278
  for (const t of outgoingTransitions(this.spec, this.currentStateId)) {
38245
- collectStableSizes(t.when, sizes);
38279
+ collectStableDescriptors(t.when, byKey);
38246
38280
  }
38247
- return sizes;
38281
+ return [...byKey.values()];
38248
38282
  }
38249
38283
  /** Schedule a re-evaluation for the soonest pending time-condition on any
38250
38284
  * outgoing transition (elapsed_ms / stable_ms / min_hold_ms). Without
@@ -38741,26 +38775,45 @@ function findStable(c) {
38741
38775
  }
38742
38776
  return null;
38743
38777
  }
38744
- function collectStableSizes(when, sizes) {
38778
+ function collectStableDescriptors(when, byKey) {
38745
38779
  if (!when) return;
38746
38780
  const w = when;
38747
38781
  if ("stable_ms" in w) {
38748
- sizes.add(w.cursor_above && w.cursor_above > 0 ? w.cursor_above : -1);
38782
+ const key2 = stableRegionKey(w);
38783
+ if (!byKey.has(key2)) {
38784
+ let ignoreRe;
38785
+ if (w.ignore_lines) {
38786
+ try {
38787
+ ignoreRe = new RegExp(w.ignore_lines, "m");
38788
+ } catch {
38789
+ }
38790
+ }
38791
+ byKey.set(key2, { key: key2, section: w.section, cursor_above: w.cursor_above, ignoreRe });
38792
+ }
38749
38793
  return;
38750
38794
  }
38751
38795
  if ("all" in w) {
38752
- for (const c of w.all) collectStableSizes(c, sizes);
38796
+ for (const c of w.all) collectStableDescriptors(c, byKey);
38753
38797
  return;
38754
38798
  }
38755
38799
  if ("any" in w) {
38756
- for (const c of w.any) collectStableSizes(c, sizes);
38800
+ for (const c of w.any) collectStableDescriptors(c, byKey);
38757
38801
  return;
38758
38802
  }
38759
38803
  if ("not" in w) {
38760
- collectStableSizes(w.not, sizes);
38804
+ collectStableDescriptors(w.not, byKey);
38761
38805
  return;
38762
38806
  }
38763
38807
  }
38808
+ function sliceSectionLines(lines, sections, id) {
38809
+ const sec = sections.find((s2) => s2.id === id);
38810
+ if (!sec) return [];
38811
+ return lines.slice(sec.fromLine, sec.toLine);
38812
+ }
38813
+ function filterIgnoredLines(lines, ignoreRe) {
38814
+ if (!ignoreRe) return lines;
38815
+ return lines.filter((l) => !ignoreRe.test(l));
38816
+ }
38764
38817
 
38765
38818
  // src/providers/spec/cli-adapter.ts
38766
38819
  init_evaluator();