@adhdev/daemon-core 0.9.82-rc.267 → 0.9.82-rc.269

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
@@ -260,10 +260,10 @@ function readInjected(value) {
260
260
  }
261
261
  function getDaemonBuildInfo() {
262
262
  if (cached) return cached;
263
- const commit = readInjected(true ? "bf805cc2b4d63e722d2e330fa10a9890db3b4668" : void 0) ?? "unknown";
264
- const commitShort = readInjected(true ? "bf805cc2" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
265
- const version = readInjected(true ? "0.9.82-rc.267" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
266
- const builtAt = readInjected(true ? "2026-06-14T20:01:43.506Z" : void 0);
263
+ const commit = readInjected(true ? "025d8bef81a66e7b44a5ba5d5a04e063db46db4e" : void 0) ?? "unknown";
264
+ const commitShort = readInjected(true ? "025d8bef" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
265
+ const version = readInjected(true ? "0.9.82-rc.269" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
266
+ const builtAt = readInjected(true ? "2026-06-14T22:11:38.134Z" : void 0);
267
267
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
268
268
  return cached;
269
269
  }
@@ -9496,7 +9496,7 @@ var init_ghostty_vt_backend = __esm({
9496
9496
  "@adhdev/ghostty-vt-node"
9497
9497
  ];
9498
9498
  cachedBindingError = null;
9499
- GhosttyVtTerminalBackend = class {
9499
+ GhosttyVtTerminalBackend = class _GhosttyVtTerminalBackend {
9500
9500
  kind = "ghostty-vt";
9501
9501
  terminal;
9502
9502
  rows;
@@ -9518,17 +9518,30 @@ var init_ghostty_vt_backend = __esm({
9518
9518
  if (!data || this.disposed) return;
9519
9519
  this.terminal.write(data);
9520
9520
  }
9521
+ formatLines() {
9522
+ const raw = this.terminal.formatPlainText({ trim: false }) || "";
9523
+ if (!raw) return [];
9524
+ return raw.split("\n").map((row) => row.replace(/\s+$/, ""));
9525
+ }
9526
+ static trimBlankEnds(lines) {
9527
+ let first = 0;
9528
+ let last = lines.length;
9529
+ while (first < last && !lines[first]) first += 1;
9530
+ while (last > first && !lines[last - 1]) last -= 1;
9531
+ return lines.slice(first, last).join("\n");
9532
+ }
9521
9533
  getText() {
9522
9534
  if (this.disposed) return "";
9523
- const raw = this.terminal.formatPlainText({ trim: false }) || "";
9524
- if (!raw) return "";
9525
- const lines = raw.split("\n").map((row) => row.replace(/\s+$/, ""));
9535
+ const lines = this.formatLines();
9536
+ if (lines.length === 0) return "";
9526
9537
  const viewport = lines.length > this.rows ? lines.slice(-this.rows) : lines;
9527
- let first = 0;
9528
- let last = viewport.length;
9529
- while (first < last && !viewport[first]) first += 1;
9530
- while (last > first && !viewport[last - 1]) last -= 1;
9531
- return viewport.slice(first, last).join("\n");
9538
+ return _GhosttyVtTerminalBackend.trimBlankEnds(viewport);
9539
+ }
9540
+ getTextWithScrollback() {
9541
+ if (this.disposed) return "";
9542
+ const lines = this.formatLines();
9543
+ if (lines.length === 0) return "";
9544
+ return _GhosttyVtTerminalBackend.trimBlankEnds(lines);
9532
9545
  }
9533
9546
  getCursorPosition() {
9534
9547
  if (this.disposed) return { col: 0, row: 0 };
@@ -9581,6 +9594,10 @@ var init_terminal_screen = __esm({
9581
9594
  getText() {
9582
9595
  return this.terminal.getText();
9583
9596
  }
9597
+ /** Full buffer including scrollback history (see backend doc). */
9598
+ getTextWithScrollback() {
9599
+ return this.terminal.getTextWithScrollback();
9600
+ }
9584
9601
  getCursorPosition() {
9585
9602
  return this.terminal.getCursorPosition();
9586
9603
  }
@@ -14716,11 +14733,22 @@ function buildClaudeInteractiveTuiAnswerSteps(prompt, response) {
14716
14733
  if (response.promptId !== prompt.promptId) throw new Error("Interactive prompt response does not match active prompt");
14717
14734
  const steps = [];
14718
14735
  for (const question of prompt.questions) {
14719
- if (question.multiSelect) throw new Error("Claude TUI multi-select prompts are not supported yet");
14720
14736
  const answer = response.answers[question.questionId];
14721
14737
  if (!answer) throw new Error(`Missing answer for ${question.questionId}`);
14722
14738
  const freeformText = answer.freeformText?.trim() ?? "";
14723
- if (freeformText) {
14739
+ if (question.multiSelect) {
14740
+ const labels = answer.selectedLabels;
14741
+ if (labels.length === 0) {
14742
+ throw new Error(`Expected at least one selected label for ${question.questionId}`);
14743
+ }
14744
+ for (const label of labels) {
14745
+ const selectedIndex = question.options.findIndex((option) => option.label === label);
14746
+ if (selectedIndex < 0) throw new Error(`Unknown option for ${question.questionId}: ${label}`);
14747
+ steps.push(String(selectedIndex + 1));
14748
+ steps.push(" ");
14749
+ }
14750
+ steps.push("\r");
14751
+ } else if (freeformText) {
14724
14752
  const typeOptionIndex = question.options.findIndex((o) => /^Type something\.?$/i.test(o.label));
14725
14753
  const optionNumber = typeOptionIndex >= 0 ? typeOptionIndex + 1 : question.options.length;
14726
14754
  steps.push(String(optionNumber));
@@ -19897,6 +19925,24 @@ var savedHistorySessionCache = /* @__PURE__ */ new Map();
19897
19925
  var savedHistoryFileSummaryCache = /* @__PURE__ */ new Map();
19898
19926
  var savedHistoryBackgroundRefresh = /* @__PURE__ */ new Set();
19899
19927
  var savedHistoryRollupInFlight = /* @__PURE__ */ new Set();
19928
+ var BOUNDED_TAIL_CACHE_MAX_ENTRIES = 64;
19929
+ var boundedTailReadCache = /* @__PURE__ */ new Map();
19930
+ function readBoundedTailCache(key, signature) {
19931
+ const cached2 = boundedTailReadCache.get(key);
19932
+ if (!cached2 || cached2.signature !== signature) return null;
19933
+ boundedTailReadCache.delete(key);
19934
+ boundedTailReadCache.set(key, cached2);
19935
+ return cached2.result;
19936
+ }
19937
+ function writeBoundedTailCache(key, signature, result) {
19938
+ boundedTailReadCache.delete(key);
19939
+ boundedTailReadCache.set(key, { signature, result });
19940
+ while (boundedTailReadCache.size > BOUNDED_TAIL_CACHE_MAX_ENTRIES) {
19941
+ const oldest = boundedTailReadCache.keys().next().value;
19942
+ if (oldest === void 0) break;
19943
+ boundedTailReadCache.delete(oldest);
19944
+ }
19945
+ }
19900
19946
  function normalizeHistoryComparable(text) {
19901
19947
  return String(text || "").replace(/\s+/g, " ").trim();
19902
19948
  }
@@ -20781,12 +20827,73 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
20781
20827
  const sliced = collapsed.slice(startInclusive, endExclusive);
20782
20828
  return { messages: sliced, hasMore: startInclusive > 0 };
20783
20829
  }
20830
+ var BOUNDED_TAIL_MAX_LIMIT = 5e3;
20831
+ var BOUNDED_TAIL_SLACK = 50;
20832
+ function isBoundedTailRequest(limit, offset, excludeRecentCount) {
20833
+ const numericLimit = Number(limit);
20834
+ if (!Number.isFinite(numericLimit) || numericLimit <= 0) return false;
20835
+ if (numericLimit > BOUNDED_TAIL_MAX_LIMIT) return false;
20836
+ const numericOffset = Number(offset);
20837
+ const numericExclude = Number(excludeRecentCount);
20838
+ if (!Number.isFinite(numericOffset) || !Number.isFinite(numericExclude)) return false;
20839
+ return true;
20840
+ }
20841
+ function readBoundedTailRecords(agentType, dir, files, needed) {
20842
+ const collected = [];
20843
+ const seen = /* @__PURE__ */ new Set();
20844
+ let readAllFiles = true;
20845
+ for (let f = 0; f < files.length; f++) {
20846
+ const filePath = path12.join(dir, files[f]);
20847
+ let content;
20848
+ try {
20849
+ content = fs5.readFileSync(filePath, "utf-8");
20850
+ } catch {
20851
+ continue;
20852
+ }
20853
+ const lines = content.trim().split("\n").filter(Boolean);
20854
+ for (let i = lines.length - 1; i >= 0; i--) {
20855
+ try {
20856
+ const parsed = JSON.parse(lines[i]);
20857
+ const sanitizedMessage = sanitizeHistoryMessage(agentType, parsed);
20858
+ if (!sanitizedMessage) continue;
20859
+ const hash = buildHistoryMessageHash(agentType, sanitizedMessage);
20860
+ if (seen.has(hash)) continue;
20861
+ seen.add(hash);
20862
+ collected.push(sanitizedMessage);
20863
+ } catch {
20864
+ }
20865
+ }
20866
+ if (collected.length >= needed && f < files.length - 1) {
20867
+ readAllFiles = false;
20868
+ break;
20869
+ }
20870
+ }
20871
+ collected.reverse();
20872
+ return { records: collected, readAllFiles };
20873
+ }
20784
20874
  function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
20785
20875
  try {
20786
20876
  const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
20787
20877
  const dir = path12.join(HISTORY_DIR, sanitized);
20788
20878
  if (!fs5.existsSync(dir)) return { messages: [], hasMore: false };
20789
20879
  const files = listHistoryFiles(dir, historySessionId);
20880
+ const bounded = isBoundedTailRequest(limit, offset, excludeRecentCount);
20881
+ if (bounded) {
20882
+ const fileSignatures = buildSavedHistoryFileSignatureMap(dir, files);
20883
+ const cacheKey = `${sanitized}\0${historySessionId || ""}\0${offset}\0${limit}\0${excludeRecentCount}\0${historyBehavior?.collapseConsecutiveAssistantTurns ? "1" : "0"}`;
20884
+ const signature = buildSavedHistoryCacheSignature(files, fileSignatures);
20885
+ const cached2 = readBoundedTailCache(cacheKey, signature);
20886
+ if (cached2) return cached2;
20887
+ const numericLimit = Math.max(1, Number(limit));
20888
+ const numericOffset = Math.max(0, Number(offset));
20889
+ const numericExclude = Math.max(0, Number(excludeRecentCount));
20890
+ const needed = numericLimit + numericOffset + numericExclude + Math.max(BOUNDED_TAIL_SLACK, numericLimit);
20891
+ const { records, readAllFiles } = readBoundedTailRecords(agentType, dir, files, needed);
20892
+ const result = pageHistoryRecords(agentType, records, offset, limit, excludeRecentCount, historyBehavior);
20893
+ const boundedResult = readAllFiles ? result : { messages: result.messages, hasMore: true };
20894
+ writeBoundedTailCache(cacheKey, signature, boundedResult);
20895
+ return boundedResult;
20896
+ }
20790
20897
  const allMessages = [];
20791
20898
  const seen = /* @__PURE__ */ new Set();
20792
20899
  for (const file of files) {
@@ -23996,6 +24103,7 @@ var CHAT_SOURCE_REGISTRY = new ChatSourceRegistry();
23996
24103
  // src/commands/chat-commands.ts
23997
24104
  var RECENT_SEND_WINDOW_MS = 1200;
23998
24105
  var READ_CHAT_PROVIDER_EVAL_TIMEOUT_MS = 25e3;
24106
+ var HOT_TAIL_MIN_LIMIT = 60;
23999
24107
  var HERMES_CLI_STARTING_SEND_SETTLE_MS = 2e3;
24000
24108
  var CLI_NATIVE_TRANSCRIPT_PROVIDERS = /* @__PURE__ */ new Set(["codex-cli", "claude-cli", "hermes-cli", "antigravity-cli"]);
24001
24109
  var warnedLegacyNativeAllowlistHits = /* @__PURE__ */ new Set();
@@ -24538,7 +24646,7 @@ function readExactRuntimeMirrorMessages(args) {
24538
24646
  const history = readChatHistory(
24539
24647
  args.providerType,
24540
24648
  0,
24541
- Math.max(args.tailLimit || 0, 200),
24649
+ Math.max(args.tailLimit || 0, HOT_TAIL_MIN_LIMIT),
24542
24650
  targetSessionId,
24543
24651
  0,
24544
24652
  args.historyBehavior
@@ -25431,7 +25539,7 @@ async function handleReadChat(h, args) {
25431
25539
  const nativeHistoryLimit = Math.max(
25432
25540
  normalizeReadChatTailLimit(args) || 0,
25433
25541
  returnedMessages.length,
25434
- 200
25542
+ HOT_TAIL_MIN_LIMIT
25435
25543
  );
25436
25544
  const nativeHistorySessionId = supportsNative ? resolveCliNativeHistorySessionId(args, historySessionId, providerSessionId) : void 0;
25437
25545
  const targetSessionId = typeof args?.targetSessionId === "string" ? args.targetSessionId.trim() : "";
@@ -28894,6 +29002,15 @@ var TerminalAdapter = class {
28894
29002
  snapshot() {
28895
29003
  return this.lastScreen || this.computeScreen();
28896
29004
  }
29005
+ /**
29006
+ * Full-buffer snapshot including scrollback history. Unlike snapshot()
29007
+ * (visible viewport only), this survives a tall prompt whose top has
29008
+ * scrolled off-screen — used for content-pattern extraction (modal
29009
+ * buttons / approval anchors), NOT for cursor-relative conditions.
29010
+ */
29011
+ snapshotWithScrollback() {
29012
+ return this.screen.getTextWithScrollback();
29013
+ }
28897
29014
  getCursorPosition() {
28898
29015
  const pos = this.screen.getCursorPosition();
28899
29016
  return { row: pos.row, col: pos.col };
@@ -29068,6 +29185,18 @@ var FsmDriver = class {
29068
29185
  getScreen() {
29069
29186
  return this.adapter.snapshot();
29070
29187
  }
29188
+ /** Scrollback-inclusive screen as line array — used only for modal/button
29189
+ * content extraction so a tall prompt's off-screen anchors stay matchable.
29190
+ * Falls back to the viewport snapshot if scrollback read is unavailable. */
29191
+ scrollbackLines() {
29192
+ let screen = "";
29193
+ try {
29194
+ screen = this.adapter.snapshotWithScrollback();
29195
+ } catch {
29196
+ }
29197
+ if (!screen) screen = this.adapter.snapshot();
29198
+ return screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
29199
+ }
29071
29200
  getSpecPath() {
29072
29201
  return this.opts.specPath;
29073
29202
  }
@@ -29249,9 +29378,12 @@ var FsmDriver = class {
29249
29378
  const screen = this.adapter.snapshot();
29250
29379
  const lines = screen.split("\n").map((l) => l.endsWith("\r") ? l.slice(0, -1) : l);
29251
29380
  const sections = resolveSections(this.spec.sections ?? {}, lines);
29252
- const modal = this.deriveModal(state, sections, lines.join("\n"));
29381
+ const modalLines = state.modal ? this.scrollbackLines() : lines;
29382
+ const modalSections = state.modal ? resolveSections(this.spec.sections ?? {}, modalLines) : sections;
29383
+ const modalFullScreen = modalLines.join("\n");
29384
+ const modal = this.deriveModal(state, modalSections, modalFullScreen);
29253
29385
  const controls = this.deriveControls(state.id);
29254
- const title = modal?.title ?? this.deriveTitle(state, sections, lines.join("\n"));
29386
+ const title = modal?.title ?? this.deriveTitle(state, modalSections, modalFullScreen);
29255
29387
  const next = {
29256
29388
  // status is derived from the FSM state itself (statusForState), NOT from
29257
29389
  // whether a modal was parsed this frame. A modal state whose buttons briefly
@@ -31122,7 +31254,7 @@ async function waitForCliAdapterReady(adapter, options) {
31122
31254
  }
31123
31255
  throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
31124
31256
  }
31125
- var CliProviderInstance = class {
31257
+ var CliProviderInstance = class _CliProviderInstance {
31126
31258
  constructor(provider, workingDir, cliArgs = [], instanceId, transportFactory, options) {
31127
31259
  this.provider = provider;
31128
31260
  this.workingDir = workingDir;
@@ -31142,6 +31274,18 @@ var CliProviderInstance = class {
31142
31274
  }
31143
31275
  type;
31144
31276
  category = "cli";
31277
+ /**
31278
+ * Quiet period an approval modal's signature must be stable before
31279
+ * auto-approve sends the approve key. Guards against firing on a prompt
31280
+ * that is still streaming into the PTY (the "resolves too fast" symptom):
31281
+ * while the modal text/buttons are still changing, every frame yields a
31282
+ * new signature and the settle clock restarts. Once the prompt finishes
31283
+ * rendering the signature holds and the key is sent after this window.
31284
+ * Bounded + small so genuine approvals stay timely. The FSM is already
31285
+ * authoritative over the `waiting_approval` state; this only delays the
31286
+ * keystroke until the modal *content* has settled.
31287
+ */
31288
+ static AUTO_APPROVE_SETTLE_MS = 600;
31145
31289
  adapter;
31146
31290
  context = null;
31147
31291
  events = [];
@@ -31155,6 +31299,14 @@ var CliProviderInstance = class {
31155
31299
  autoApproveBusy = false;
31156
31300
  autoApproveBusyTimer = null;
31157
31301
  lastAutoApprovalSignature = "";
31302
+ // Settle gate: the approval modal's signature + the wall-clock when this
31303
+ // exact signature was first observed. Auto-approve only fires once the
31304
+ // SAME signature has been stable for AUTO_APPROVE_SETTLE_MS, so a prompt
31305
+ // still streaming into the PTY (its buttons/message changing frame to
31306
+ // frame) keeps resetting the timer and is never approved half-rendered.
31307
+ pendingAutoApprovalSignature = "";
31308
+ pendingAutoApprovalSince = 0;
31309
+ autoApproveSettleTimer = null;
31158
31310
  controlValues = {};
31159
31311
  summaryMetadata = void 0;
31160
31312
  appliedEffectKeys = /* @__PURE__ */ new Set();
@@ -31589,6 +31741,14 @@ var CliProviderInstance = class {
31589
31741
  dispose() {
31590
31742
  this.adapter.shutdown();
31591
31743
  this.monitor.reset();
31744
+ if (this.autoApproveSettleTimer) {
31745
+ clearTimeout(this.autoApproveSettleTimer);
31746
+ this.autoApproveSettleTimer = null;
31747
+ }
31748
+ if (this.autoApproveBusyTimer) {
31749
+ clearTimeout(this.autoApproveBusyTimer);
31750
+ this.autoApproveBusyTimer = null;
31751
+ }
31592
31752
  this.appliedEffectKeys.clear();
31593
31753
  try {
31594
31754
  this.cachedSqliteDb?.close();
@@ -31939,6 +32099,12 @@ var CliProviderInstance = class {
31939
32099
  const autoApproveActive = adapterStatus?.status === "waiting_approval" && this.shouldAutoApprove();
31940
32100
  if (!autoApproveActive) {
31941
32101
  this.lastAutoApprovalSignature = "";
32102
+ this.pendingAutoApprovalSignature = "";
32103
+ this.pendingAutoApprovalSince = 0;
32104
+ if (this.autoApproveSettleTimer) {
32105
+ clearTimeout(this.autoApproveSettleTimer);
32106
+ this.autoApproveSettleTimer = null;
32107
+ }
31942
32108
  return autoApproveActive;
31943
32109
  }
31944
32110
  const modal = adapterStatus.activeModal;
@@ -31957,22 +32123,57 @@ var CliProviderInstance = class {
31957
32123
  buttons.join("|"),
31958
32124
  buttonIndex
31959
32125
  ].join("::");
31960
- if (!this.autoApproveBusy || signature !== this.lastAutoApprovalSignature) {
31961
- this.autoApproveBusy = true;
31962
- this.lastAutoApprovalSignature = signature;
31963
- if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
31964
- this.autoApproveBusyTimer = setTimeout(() => {
31965
- this.autoApproveBusy = false;
31966
- this.autoApproveBusyTimer = null;
31967
- this.lastAutoApprovalSignature = "";
31968
- }, 5e3);
31969
- this.recordAutoApproval(modal?.message, buttonLabel, now);
31970
- setTimeout(() => {
31971
- this.adapter.resolveModal(buttonIndex);
31972
- }, 0);
32126
+ if (this.autoApproveBusy && signature === this.lastAutoApprovalSignature) {
32127
+ return autoApproveActive;
32128
+ }
32129
+ if (signature !== this.pendingAutoApprovalSignature) {
32130
+ this.pendingAutoApprovalSignature = signature;
32131
+ this.pendingAutoApprovalSince = now;
32132
+ }
32133
+ const settledForMs = now - this.pendingAutoApprovalSince;
32134
+ if (settledForMs < _CliProviderInstance.AUTO_APPROVE_SETTLE_MS) {
32135
+ if (this.autoApproveSettleTimer) clearTimeout(this.autoApproveSettleTimer);
32136
+ this.autoApproveSettleTimer = setTimeout(() => {
32137
+ this.autoApproveSettleTimer = null;
32138
+ this.recheckAutoApproveSettled();
32139
+ }, _CliProviderInstance.AUTO_APPROVE_SETTLE_MS - settledForMs + 20);
32140
+ return autoApproveActive;
32141
+ }
32142
+ if (this.autoApproveSettleTimer) {
32143
+ clearTimeout(this.autoApproveSettleTimer);
32144
+ this.autoApproveSettleTimer = null;
31973
32145
  }
32146
+ this.autoApproveBusy = true;
32147
+ this.lastAutoApprovalSignature = signature;
32148
+ this.pendingAutoApprovalSignature = "";
32149
+ this.pendingAutoApprovalSince = 0;
32150
+ if (this.autoApproveBusyTimer) clearTimeout(this.autoApproveBusyTimer);
32151
+ this.autoApproveBusyTimer = setTimeout(() => {
32152
+ this.autoApproveBusy = false;
32153
+ this.autoApproveBusyTimer = null;
32154
+ this.lastAutoApprovalSignature = "";
32155
+ }, 5e3);
32156
+ this.recordAutoApproval(modal?.message, buttonLabel, now);
32157
+ setTimeout(() => {
32158
+ this.adapter.resolveModal(buttonIndex);
32159
+ }, 0);
31974
32160
  return autoApproveActive;
31975
32161
  }
32162
+ /**
32163
+ * Re-drive the auto-approve check after the settle quiet window elapses.
32164
+ * The PTY may have gone silent once the approval prompt finished painting,
32165
+ * so no status-change frame is guaranteed to re-enter maybeAutoApproveStatus
32166
+ * — this timer-driven re-check picks up the now-settled modal and fires.
32167
+ * Deliberately lighter than detectStatusTransition(): it only re-evaluates
32168
+ * the approval decision; the next real PTY frame refreshes visible status.
32169
+ */
32170
+ recheckAutoApproveSettled() {
32171
+ try {
32172
+ const adapterStatus = this.adapter.getStatus({ allowParse: false });
32173
+ this.maybeAutoApproveStatus(adapterStatus, Date.now());
32174
+ } catch {
32175
+ }
32176
+ }
31976
32177
  detectStatusTransition() {
31977
32178
  const now = Date.now();
31978
32179
  const adapterStatus = this.adapter.getStatus({ allowParse: false });