@adhdev/daemon-core 0.9.82-rc.208 → 0.9.82-rc.209

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 (30) hide show
  1. package/dist/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +1 -3
  2. package/dist/cli-adapters/terminal-backends/types.d.ts +1 -2
  3. package/dist/cli-adapters/terminal-screen.d.ts +2 -11
  4. package/dist/index.js +155 -213
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +140 -198
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/providers/spec/adapter.d.ts +11 -19
  9. package/dist/providers/spec/driver.d.ts +14 -0
  10. package/dist/providers/spec/schema.gen.d.ts +24 -1
  11. package/dist/providers/spec/types.d.ts +8 -1
  12. package/dist/shared-types-extra.d.ts +1 -3
  13. package/package.json +1 -3
  14. package/src/cli-adapters/provider-cli-adapter.ts +3 -2
  15. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.ts +11 -34
  16. package/src/cli-adapters/terminal-backends/types.ts +1 -3
  17. package/src/cli-adapters/terminal-screen.ts +11 -81
  18. package/src/commands/mesh-coordinator.ts +3 -2
  19. package/src/daemon/dev-auto-implement.ts +3 -2
  20. package/src/providers/spec/adapter.ts +40 -78
  21. package/src/providers/spec/cli-adapter.ts +2 -0
  22. package/src/providers/spec/driver.ts +68 -13
  23. package/src/providers/spec/evaluator.ts +44 -14
  24. package/src/providers/spec/loader.ts +6 -1
  25. package/src/providers/spec/schema.gen.ts +17 -1
  26. package/src/providers/spec/types.ts +5 -1
  27. package/src/shared-types-extra.ts +1 -3
  28. package/dist/cli-adapters/terminal-backends/xterm-backend.d.ts +0 -17
  29. package/src/cli-adapters/terminal-backends/ghostty-vt-backend.d.ts +0 -16
  30. package/src/cli-adapters/terminal-backends/xterm-backend.ts +0 -104
package/dist/index.js CHANGED
@@ -2300,8 +2300,8 @@ async function execUnderPty(command, args, options = {}) {
2300
2300
  try {
2301
2301
  child = ptyLib.spawn(command, args, {
2302
2302
  name: "xterm-256color",
2303
- cols: 120,
2304
- rows: 30,
2303
+ cols: import_session_host_core.DEFAULT_SESSION_HOST_COLS,
2304
+ rows: import_session_host_core.DEFAULT_SESSION_HOST_ROWS,
2305
2305
  cwd: options.cwd ?? process.cwd(),
2306
2306
  env
2307
2307
  });
@@ -2334,13 +2334,14 @@ async function execUnderPty(command, args, options = {}) {
2334
2334
  });
2335
2335
  });
2336
2336
  }
2337
- var import_node_crypto, import_node_fs3, os4, import_node_path, DEFAULT_SERVER_NAME, DEFAULT_ADHDEV_MCP_COMMAND, HERMES_CLI_TYPE, HERMES_MCP_CONFIG_PATH;
2337
+ var import_node_crypto, import_node_fs3, os4, import_session_host_core, import_node_path, DEFAULT_SERVER_NAME, DEFAULT_ADHDEV_MCP_COMMAND, HERMES_CLI_TYPE, HERMES_MCP_CONFIG_PATH;
2338
2338
  var init_mesh_coordinator = __esm({
2339
2339
  "src/commands/mesh-coordinator.ts"() {
2340
2340
  "use strict";
2341
2341
  import_node_crypto = require("crypto");
2342
2342
  import_node_fs3 = require("fs");
2343
2343
  os4 = __toESM(require("os"));
2344
+ import_session_host_core = require("@adhdev/session-host-core");
2344
2345
  import_node_path = require("path");
2345
2346
  init_logger();
2346
2347
  DEFAULT_SERVER_NAME = "adhdev-mesh";
@@ -7050,11 +7051,9 @@ function getBindingCandidates() {
7050
7051
  const explicit = process.env.ADHDEV_GHOSTTY_VT_BINDING?.trim();
7051
7052
  return explicit ? [explicit] : DEFAULT_BINDING_CANDIDATES;
7052
7053
  }
7053
- function loadGhosttyVtBinding(required) {
7054
+ function loadGhosttyVtBinding() {
7054
7055
  if (cachedBinding !== void 0) {
7055
- if (!cachedBinding && required && cachedBindingError) {
7056
- throw cachedBindingError;
7057
- }
7056
+ if (!cachedBinding && cachedBindingError) throw cachedBindingError;
7058
7057
  return cachedBinding;
7059
7058
  }
7060
7059
  const errors = [];
@@ -7075,18 +7074,9 @@ function loadGhosttyVtBinding(required) {
7075
7074
  }
7076
7075
  cachedBinding = null;
7077
7076
  cachedBindingError = new Error(
7078
- `ghostty-vt backend requested but no binding is available (${errors.join("; ") || "no candidates tried"})`
7077
+ `ghostty-vt binding unavailable (${errors.join("; ") || "no candidates tried"})`
7079
7078
  );
7080
- if (required) throw cachedBindingError;
7081
- return null;
7082
- }
7083
- function resolveTerminalBackendPreference() {
7084
- const raw = process.env.ADHDEV_TERMINAL_BACKEND?.trim().toLowerCase();
7085
- if (raw === "ghostty-vt" || raw === "xterm" || raw === "auto") return raw;
7086
- return "auto";
7087
- }
7088
- function isGhosttyVtBackendAvailable() {
7089
- return !!loadGhosttyVtBinding(false);
7079
+ throw cachedBindingError;
7090
7080
  }
7091
7081
  var DEFAULT_BINDING_CANDIDATES, cachedBinding, cachedBindingError, GhosttyVtTerminalBackend;
7092
7082
  var init_ghostty_vt_backend = __esm({
@@ -7100,10 +7090,7 @@ var init_ghostty_vt_backend = __esm({
7100
7090
  kind = "ghostty-vt";
7101
7091
  terminal;
7102
7092
  constructor(options) {
7103
- const binding = loadGhosttyVtBinding(true);
7104
- if (!binding) {
7105
- throw new Error("ghostty-vt backend requested but no binding is available");
7106
- }
7093
+ const binding = loadGhosttyVtBinding();
7107
7094
  this.terminal = binding.createTerminal({
7108
7095
  cols: Math.max(1, options.cols | 0),
7109
7096
  rows: Math.max(1, options.rows | 0),
@@ -7137,141 +7124,26 @@ var init_ghostty_vt_backend = __esm({
7137
7124
  }
7138
7125
  });
7139
7126
 
7140
- // src/cli-adapters/terminal-backends/xterm-backend.ts
7141
- function loadTerminalCtor() {
7142
- if (!TerminalCtor) {
7143
- const mod = require("@xterm/xterm");
7144
- TerminalCtor = mod.Terminal || mod.default?.Terminal || mod.default;
7145
- if (!TerminalCtor) {
7146
- throw new Error("@xterm/xterm Terminal export not found");
7147
- }
7148
- }
7149
- return TerminalCtor;
7150
- }
7151
- var TerminalCtor, XtermTerminalBackend;
7152
- var init_xterm_backend = __esm({
7153
- "src/cli-adapters/terminal-backends/xterm-backend.ts"() {
7154
- "use strict";
7155
- TerminalCtor = null;
7156
- XtermTerminalBackend = class {
7157
- kind = "xterm";
7158
- rows;
7159
- cols;
7160
- terminal;
7161
- constructor(options) {
7162
- this.rows = Math.max(1, options.rows | 0);
7163
- this.cols = Math.max(1, options.cols | 0);
7164
- this.terminal = this.createTerminal(options.scrollback);
7165
- }
7166
- resize(rows, cols) {
7167
- this.rows = Math.max(1, rows | 0);
7168
- this.cols = Math.max(1, cols | 0);
7169
- this.terminal.resize(this.cols, this.rows);
7170
- }
7171
- write(data) {
7172
- if (!data) return;
7173
- this.terminal.write(data);
7174
- }
7175
- getText() {
7176
- const buffer = this.terminal.buffer.active;
7177
- const start = Math.max(0, buffer.viewportY || 0);
7178
- const end = Math.max(start, Math.min(buffer.length || 0, start + this.rows));
7179
- const lines = [];
7180
- for (let i = start; i < end; i++) {
7181
- const line = buffer.getLine(i);
7182
- const raw = line ? line.translateToString(false) : "";
7183
- lines.push(raw.replace(/\s+$/, ""));
7184
- }
7185
- let first = 0;
7186
- let last = lines.length;
7187
- while (first < last && !lines[first]?.trim()) first++;
7188
- while (last > first && !lines[last - 1]?.trim()) last--;
7189
- return lines.slice(first, last).join("\n");
7190
- }
7191
- getCursorPosition() {
7192
- const buffer = this.terminal.buffer.active;
7193
- return {
7194
- col: Math.max(0, buffer.cursorX || 0),
7195
- row: Math.max(0, buffer.cursorY || 0)
7196
- };
7197
- }
7198
- dispose() {
7199
- this.terminal.dispose();
7200
- }
7201
- createTerminal(scrollback) {
7202
- const Terminal2 = loadTerminalCtor();
7203
- return new Terminal2({
7204
- cols: this.cols,
7205
- rows: this.rows,
7206
- scrollback
7207
- });
7208
- }
7209
- };
7210
- }
7211
- });
7212
-
7213
7127
  // src/cli-adapters/terminal-screen.ts
7214
7128
  function getTerminalBackendRuntimeStatus() {
7215
- const preference = resolveTerminalBackendPreference();
7216
- const ghosttyAvailable = isGhosttyVtBackendAvailable();
7217
- const backend = preference === "ghostty-vt" || preference === "auto" && ghosttyAvailable ? "ghostty-vt" : "xterm";
7218
- return { backend, preference, ghosttyAvailable };
7219
- }
7220
- function createTerminalBackend(options, preference) {
7221
- const ghosttyAvailable = isGhosttyVtBackendAvailable();
7222
- if (preference === "ghostty-vt") {
7223
- const backend2 = new GhosttyVtTerminalBackend(options);
7224
- logTerminalBackendSelection(preference, ghosttyAvailable, backend2.kind);
7225
- return backend2;
7226
- }
7227
- if (preference === "auto" && ghosttyAvailable) {
7228
- const backend2 = new GhosttyVtTerminalBackend(options);
7229
- logTerminalBackendSelection(preference, ghosttyAvailable, backend2.kind);
7230
- return backend2;
7231
- }
7232
- const backend = new XtermTerminalBackend(options);
7233
- logTerminalBackendSelection(preference, ghosttyAvailable, backend.kind);
7234
- return backend;
7235
- }
7236
- function logTerminalBackendSelection(preference, ghosttyAvailable, backendKind) {
7237
- const key = `${preference}:${ghosttyAvailable}:${backendKind}`;
7238
- if (loggedTerminalBackends.has(key)) return;
7239
- loggedTerminalBackends.add(key);
7240
- if (backendKind === "xterm" && preference !== "xterm" && !ghosttyAvailable) {
7241
- const message = `[terminal-screen] ghostty-vt unavailable; using xterm fallback (preference=${preference})`;
7242
- if (preference === "auto") {
7243
- LOG.info("Terminal", message);
7244
- } else {
7245
- LOG.warn("Terminal", message);
7246
- }
7247
- return;
7248
- }
7249
- LOG.info(
7250
- "Terminal",
7251
- `[terminal-screen] backend=${backendKind} preference=${preference} ghosttyAvailable=${ghosttyAvailable}`
7252
- );
7129
+ return { backend: "ghostty-vt" };
7253
7130
  }
7254
- var DEFAULT_SCROLLBACK, loggedTerminalBackends, TerminalScreen;
7131
+ var import_session_host_core2, DEFAULT_SCROLLBACK, TerminalScreen;
7255
7132
  var init_terminal_screen = __esm({
7256
7133
  "src/cli-adapters/terminal-screen.ts"() {
7257
7134
  "use strict";
7258
- init_logger();
7259
7135
  init_ghostty_vt_backend();
7260
- init_xterm_backend();
7136
+ import_session_host_core2 = require("@adhdev/session-host-core");
7261
7137
  DEFAULT_SCROLLBACK = 2e3;
7262
- loggedTerminalBackends = /* @__PURE__ */ new Set();
7263
7138
  TerminalScreen = class {
7264
- backendKind;
7139
+ backendKind = "ghostty-vt";
7265
7140
  rows;
7266
7141
  cols;
7267
- preference;
7268
7142
  terminal;
7269
- constructor(rows = 40, cols = 120) {
7143
+ constructor(rows = import_session_host_core2.DEFAULT_SESSION_HOST_ROWS, cols = import_session_host_core2.DEFAULT_SESSION_HOST_COLS) {
7270
7144
  this.rows = Math.max(1, rows | 0);
7271
7145
  this.cols = Math.max(1, cols | 0);
7272
- this.preference = resolveTerminalBackendPreference();
7273
7146
  this.terminal = this.createBackend();
7274
- this.backendKind = this.terminal.kind;
7275
7147
  }
7276
7148
  reset(rows = this.rows, cols = this.cols) {
7277
7149
  this.rows = Math.max(1, rows | 0);
@@ -7297,31 +7169,35 @@ var init_terminal_screen = __esm({
7297
7169
  this.terminal.dispose();
7298
7170
  }
7299
7171
  createBackend() {
7300
- return createTerminalBackend({
7172
+ return new GhosttyVtTerminalBackend({
7301
7173
  cols: this.cols,
7302
7174
  rows: this.rows,
7303
7175
  scrollback: DEFAULT_SCROLLBACK
7304
- }, this.preference);
7176
+ });
7305
7177
  }
7306
7178
  };
7307
7179
  }
7308
7180
  });
7309
7181
 
7310
7182
  // src/cli-adapters/spawn-env.ts
7311
- var import_session_host_core;
7183
+ var import_session_host_core3;
7312
7184
  var init_spawn_env = __esm({
7313
7185
  "src/cli-adapters/spawn-env.ts"() {
7314
7186
  "use strict";
7315
- import_session_host_core = require("@adhdev/session-host-core");
7187
+ import_session_host_core3 = require("@adhdev/session-host-core");
7316
7188
  }
7317
7189
  });
7318
7190
 
7319
7191
  // src/cli-adapters/pty-transport.ts
7192
+ var pty_transport_exports = {};
7193
+ __export(pty_transport_exports, {
7194
+ NodePtyTransportFactory: () => NodePtyTransportFactory
7195
+ });
7320
7196
  function loadNodePty() {
7321
7197
  if (cachedPty !== void 0) return cachedPty;
7322
7198
  try {
7323
7199
  cachedPty = require("node-pty");
7324
- (0, import_session_host_core.ensureNodePtySpawnHelperPermissions)();
7200
+ (0, import_session_host_core3.ensureNodePtySpawnHelperPermissions)();
7325
7201
  } catch {
7326
7202
  cachedPty = null;
7327
7203
  }
@@ -7758,7 +7634,7 @@ var init_provider_cli_shared = __esm({
7758
7634
  this.ensureRow();
7759
7635
  }
7760
7636
  };
7761
- buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
7637
+ buildCliSpawnEnv = import_session_host_core3.sanitizeSpawnEnv;
7762
7638
  }
7763
7639
  });
7764
7640
 
@@ -9542,8 +9418,8 @@ function resolveCliSpawnPlan(options) {
9542
9418
  isWin,
9543
9419
  useShell,
9544
9420
  ptyOptions: {
9545
- cols: import_session_host_core2.DEFAULT_SESSION_HOST_COLS,
9546
- rows: import_session_host_core2.DEFAULT_SESSION_HOST_ROWS,
9421
+ cols: import_session_host_core4.DEFAULT_SESSION_HOST_COLS,
9422
+ rows: import_session_host_core4.DEFAULT_SESSION_HOST_ROWS,
9547
9423
  cwd: workingDir,
9548
9424
  env
9549
9425
  }
@@ -9594,13 +9470,13 @@ function respondToCliTerminalQueries(options) {
9594
9470
  }
9595
9471
  return "";
9596
9472
  }
9597
- var os13, path17, import_session_host_core2;
9473
+ var os13, path17, import_session_host_core4;
9598
9474
  var init_provider_cli_runtime = __esm({
9599
9475
  "src/cli-adapters/provider-cli-runtime.ts"() {
9600
9476
  "use strict";
9601
9477
  os13 = __toESM(require("os"));
9602
9478
  path17 = __toESM(require("path"));
9603
- import_session_host_core2 = require("@adhdev/session-host-core");
9479
+ import_session_host_core4 = require("@adhdev/session-host-core");
9604
9480
  init_provider_cli_shared();
9605
9481
  }
9606
9482
  });
@@ -9620,7 +9496,7 @@ function appendBoundedText(current, chunk, maxChars) {
9620
9496
  if (current.length <= keepFromCurrent) return current + chunk;
9621
9497
  return current.slice(-keepFromCurrent) + chunk;
9622
9498
  }
9623
- var os14, ProviderCliAdapter;
9499
+ var os14, import_session_host_core5, ProviderCliAdapter;
9624
9500
  var init_provider_cli_adapter = __esm({
9625
9501
  "src/cli-adapters/provider-cli-adapter.ts"() {
9626
9502
  "use strict";
@@ -9628,6 +9504,7 @@ var init_provider_cli_adapter = __esm({
9628
9504
  init_logger();
9629
9505
  init_debug_config();
9630
9506
  init_terminal_screen();
9507
+ import_session_host_core5 = require("@adhdev/session-host-core");
9631
9508
  init_pty_transport();
9632
9509
  init_provider_cli_shared();
9633
9510
  init_cli_script_runner();
@@ -9779,7 +9656,7 @@ var init_provider_cli_adapter = __esm({
9779
9656
  /** Full accumulated raw PTY output (with ANSI) */
9780
9657
  accumulatedRawBuffer = "";
9781
9658
  /** Current visible terminal screen snapshot */
9782
- terminalScreen = new TerminalScreen(24, 80);
9659
+ terminalScreen = new TerminalScreen(import_session_host_core5.DEFAULT_SESSION_HOST_ROWS, import_session_host_core5.DEFAULT_SESSION_HOST_COLS);
9783
9660
  static MAX_RESPONSE_BUFFER = 8e3;
9784
9661
  static MAX_RECENT_OUTPUT_BUFFER = 1e3;
9785
9662
  responseBufferDroppedChars = 0;
@@ -9992,7 +9869,7 @@ ${lastSnapshot}`;
9992
9869
  clearTimeout(this.startupSettleTimer);
9993
9870
  this.startupSettleTimer = null;
9994
9871
  }
9995
- this.resetTerminalScreen(24, 80);
9872
+ this.resetTerminalScreen(import_session_host_core5.DEFAULT_SESSION_HOST_ROWS, import_session_host_core5.DEFAULT_SESSION_HOST_COLS);
9996
9873
  this.pendingTerminalQueryTail = "";
9997
9874
  this.ready = false;
9998
9875
  await this.ptyProcess.ready;
@@ -26394,33 +26271,33 @@ var os15 = __toESM(require("os"));
26394
26271
  var path19 = __toESM(require("path"));
26395
26272
 
26396
26273
  // src/providers/spec/adapter.ts
26397
- var xtermHeadlessNs = __toESM(require("@xterm/headless"));
26398
- init_pty_transport();
26399
- var TerminalCtor2 = xtermHeadlessNs.Terminal ?? xtermHeadlessNs.default?.Terminal;
26274
+ init_terminal_screen();
26275
+ var import_session_host_core6 = require("@adhdev/session-host-core");
26400
26276
  var TerminalAdapter = class {
26401
26277
  constructor(opts, handlers) {
26402
26278
  this.opts = opts;
26403
26279
  this.handlers = handlers;
26404
- this.cols = opts.cols ?? 100;
26405
- this.rows = opts.rows ?? 30;
26280
+ this.cols = opts.cols ?? import_session_host_core6.DEFAULT_SESSION_HOST_COLS;
26281
+ this.rows = opts.rows ?? import_session_host_core6.DEFAULT_SESSION_HOST_ROWS;
26406
26282
  this.screenDebounceMs = opts.screenChangeDebounceMs ?? 80;
26407
26283
  this.tickIntervalMs = opts.tickIntervalMs ?? 0;
26408
- this.factory = opts.transportFactory ?? new NodePtyTransportFactory();
26409
- this.term = new TerminalCtor2({ cols: this.cols, rows: this.rows, allowProposedApi: true, scrollback: 1e3 });
26284
+ const { NodePtyTransportFactory: NodePtyTransportFactory2 } = (init_pty_transport(), __toCommonJS(pty_transport_exports));
26285
+ this.factory = opts.transportFactory ?? new NodePtyTransportFactory2();
26286
+ this.screen = new TerminalScreen(this.rows, this.cols);
26410
26287
  }
26411
- term;
26412
- pty = null;
26413
- factory;
26414
- cols;
26415
26288
  rows;
26289
+ cols;
26416
26290
  screenDebounceMs;
26417
26291
  tickIntervalMs;
26292
+ factory;
26293
+ screen;
26294
+ pty = null;
26418
26295
  screenTimer = null;
26419
26296
  tickTimer = null;
26420
26297
  lastScreen = "";
26421
26298
  start() {
26422
26299
  this.pty = this.factory.spawn(this.opts.binary, this.opts.args ?? [], {
26423
- cwd: this.opts.cwd,
26300
+ cwd: this.opts.cwd ?? process.cwd(),
26424
26301
  env: { ...process.env, ...this.opts.env ?? {} },
26425
26302
  cols: this.cols,
26426
26303
  rows: this.rows
@@ -26436,24 +26313,21 @@ var TerminalAdapter = class {
26436
26313
  this.tickTimer = setInterval(() => this.handlers.tick?.(), this.tickIntervalMs);
26437
26314
  }
26438
26315
  }
26439
- send_keys(s) {
26440
- this.pty?.write(s);
26441
- }
26442
26316
  resize(cols, rows) {
26443
26317
  this.cols = cols;
26444
26318
  this.rows = rows;
26445
26319
  this.pty?.resize(cols, rows);
26446
- this.term.resize(cols, rows);
26320
+ this.screen.resize(rows, cols);
26447
26321
  }
26448
26322
  snapshot() {
26449
26323
  return this.lastScreen || this.computeScreen();
26450
26324
  }
26451
26325
  getCursorPosition() {
26452
- const buf = this.term.buffer.active;
26453
- return {
26454
- row: Math.max(0, buf.cursorY ?? 0),
26455
- col: Math.max(0, buf.cursorX ?? 0)
26456
- };
26326
+ const pos = this.screen.getCursorPosition();
26327
+ return { row: pos.row, col: pos.col };
26328
+ }
26329
+ send_keys(text) {
26330
+ this.pty?.write(text);
26457
26331
  }
26458
26332
  kill() {
26459
26333
  this.stopTimers();
@@ -26462,14 +26336,14 @@ var TerminalAdapter = class {
26462
26336
  } catch {
26463
26337
  }
26464
26338
  this.pty = null;
26465
- this.term.dispose();
26339
+ this.screen.dispose();
26466
26340
  }
26467
26341
  onChunk(chunk) {
26468
26342
  try {
26469
26343
  this.handlers.on_pty_data?.(chunk);
26470
26344
  } catch {
26471
26345
  }
26472
- this.term.write(chunk);
26346
+ this.screen.write(chunk);
26473
26347
  if (this.screenTimer) return;
26474
26348
  this.screenTimer = setTimeout(() => {
26475
26349
  this.screenTimer = null;
@@ -26483,15 +26357,7 @@ var TerminalAdapter = class {
26483
26357
  }, this.screenDebounceMs);
26484
26358
  }
26485
26359
  computeScreen() {
26486
- const buf = this.term.buffer.active;
26487
- const out = [];
26488
- for (let y = 0; y < buf.length; y += 1) {
26489
- const line = buf.getLine(y);
26490
- if (!line) continue;
26491
- out.push(line.translateToString(true));
26492
- }
26493
- while (out.length > 0 && out[out.length - 1].trim() === "") out.pop();
26494
- return out.join("\n");
26360
+ return this.screen.getText();
26495
26361
  }
26496
26362
  stopTimers() {
26497
26363
  if (this.screenTimer) {
@@ -26505,6 +26371,9 @@ var TerminalAdapter = class {
26505
26371
  }
26506
26372
  };
26507
26373
 
26374
+ // src/providers/spec/driver.ts
26375
+ var import_session_host_core7 = require("@adhdev/session-host-core");
26376
+
26508
26377
  // src/providers/spec/evaluator.ts
26509
26378
  function resolveSize(size, total) {
26510
26379
  if (size === void 0) return 0;
@@ -26632,12 +26501,10 @@ function matchState(state, sections, fullScreen, trace, cursor) {
26632
26501
  }
26633
26502
  return { matched: true, title };
26634
26503
  }
26635
- function extractModal(state, sections, fullScreen, title, trace) {
26636
- if (!state.modal_buttons) return null;
26637
- const hay = sectionText(sections, state.modal_buttons.section, fullScreen);
26504
+ function extractButtonsWithPattern(rule, hay, keyTemplate, continuationLines) {
26638
26505
  const buttons = [];
26639
- if (state.modal_buttons.continuation_lines) {
26640
- const re = compileLinePattern(state.modal_buttons);
26506
+ if (continuationLines) {
26507
+ const re = compileLinePattern(rule);
26641
26508
  const lines = hay.split("\n");
26642
26509
  for (let i = 0; i < lines.length; i += 1) {
26643
26510
  const m = re.exec(lines[i]);
@@ -26655,24 +26522,40 @@ function extractModal(state, sections, fullScreen, title, trace) {
26655
26522
  j += 1;
26656
26523
  }
26657
26524
  if (buttons.some((b) => b.index === idx)) continue;
26658
- const key = state.modal_buttons.key_for_index.replace(/\{index\}/g, String(idx));
26525
+ const key = keyTemplate.replace(/\{index\}/g, String(idx));
26659
26526
  buttons.push({ index: idx, label, key });
26660
26527
  i = j - 1;
26661
26528
  }
26662
26529
  } else {
26663
- const re = compilePattern(state.modal_buttons);
26530
+ const re = compilePattern(rule);
26664
26531
  let m;
26665
26532
  while ((m = re.exec(hay)) !== null) {
26666
26533
  const idx = Number(m[1]);
26667
26534
  const label = String(m[2] ?? "").trim();
26668
26535
  if (!Number.isFinite(idx) || idx <= 0 || !label) continue;
26669
26536
  if (buttons.some((b) => b.index === idx)) continue;
26670
- const key = state.modal_buttons.key_for_index.replace(/\{index\}/g, String(idx));
26537
+ const key = keyTemplate.replace(/\{index\}/g, String(idx));
26671
26538
  buttons.push({ index: idx, label, key });
26672
26539
  }
26673
26540
  }
26674
26541
  buttons.sort((a, b) => a.index - b.index);
26542
+ return buttons;
26543
+ }
26544
+ function extractModal(state, sections, fullScreen, title, trace) {
26545
+ if (!state.modal_buttons) return null;
26546
+ const hay = sectionText(sections, state.modal_buttons.section, fullScreen);
26675
26547
  const minCount = state.modal_buttons.min_count ?? 2;
26548
+ const keyTemplate = state.modal_buttons.key_for_index;
26549
+ const continuationLines = state.modal_buttons.continuation_lines ?? false;
26550
+ const candidates = state.modal_buttons.patterns?.length ? state.modal_buttons.patterns : state.modal_buttons.pattern ? [{ pattern: state.modal_buttons.pattern, flags: state.modal_buttons.flags }] : [];
26551
+ let buttons = [];
26552
+ for (const candidate of candidates) {
26553
+ const result = extractButtonsWithPattern(candidate, hay, keyTemplate, continuationLines);
26554
+ if (result.length >= minCount) {
26555
+ buttons = result;
26556
+ break;
26557
+ }
26558
+ }
26676
26559
  if (buttons.length < minCount) {
26677
26560
  trace.push({ kind: "modal", text: `modal_buttons matched ${buttons.length}/${minCount} required \u2014 discarded` });
26678
26561
  return null;
@@ -27050,9 +26933,12 @@ var SCHEMA = {
27050
26933
  "type": "object",
27051
26934
  "additionalProperties": false,
27052
26935
  "required": [
27053
- "pattern",
27054
26936
  "key_for_index"
27055
26937
  ],
26938
+ "oneOf": [
26939
+ { "required": ["pattern"] },
26940
+ { "required": ["patterns"] }
26941
+ ],
27056
26942
  "properties": {
27057
26943
  "section": {
27058
26944
  "type": "string"
@@ -27064,6 +26950,19 @@ var SCHEMA = {
27064
26950
  "flags": {
27065
26951
  "type": "string"
27066
26952
  },
26953
+ "patterns": {
26954
+ "type": "array",
26955
+ "minItems": 1,
26956
+ "items": {
26957
+ "type": "object",
26958
+ "additionalProperties": false,
26959
+ "required": ["pattern"],
26960
+ "properties": {
26961
+ "pattern": { "type": "string", "minLength": 1 },
26962
+ "flags": { "type": "string" }
26963
+ }
26964
+ }
26965
+ },
27067
26966
  "key_for_index": {
27068
26967
  "type": "string",
27069
26968
  "minLength": 1
@@ -27351,7 +27250,12 @@ function validateRefs(spec) {
27351
27250
  if (s.modal_buttons.section && !sectionIds.has(s.modal_buttons.section)) {
27352
27251
  errs.push(`states[${s.id}].modal_buttons.section "${s.modal_buttons.section}" unknown`);
27353
27252
  }
27354
- compileRegex2(s.modal_buttons.pattern, s.modal_buttons.flags ?? "m", `states[${s.id}].modal_buttons.pattern`, errs);
27253
+ if (s.modal_buttons.pattern) {
27254
+ compileRegex2(s.modal_buttons.pattern, s.modal_buttons.flags ?? "m", `states[${s.id}].modal_buttons.pattern`, errs);
27255
+ }
27256
+ for (const [pi, p] of (s.modal_buttons.patterns ?? []).entries()) {
27257
+ compileRegex2(p.pattern, p.flags ?? "m", `states[${s.id}].modal_buttons.patterns[${pi}]`, errs);
27258
+ }
27355
27259
  }
27356
27260
  }
27357
27261
  for (const c of spec.control_bar ?? []) {
@@ -27421,8 +27325,8 @@ function matchesCompletionIdleRule(spec, ev, screen) {
27421
27325
  if (!haystack) return null;
27422
27326
  try {
27423
27327
  const regex = new RegExp(rule.regex, rule.flags || "");
27424
- const match = haystack.match(regex);
27425
- return match?.[0] || null;
27328
+ const matched = regex.test(haystack);
27329
+ return matched ? rule.regex : null;
27426
27330
  } catch {
27427
27331
  return null;
27428
27332
  }
@@ -27484,6 +27388,14 @@ var SpecDriver = class {
27484
27388
  * because the evaluator already moved past busy by the time the hold
27485
27389
  * kicks in. */
27486
27390
  lastBusyState = null;
27391
+ /** Timestamp of the last time we entered a modal state (approval/picker or
27392
+ * any non-busy non-idle state). Used to suppress brief busy blips that
27393
+ * appear while the modal is still on screen — Claude Code streams body
27394
+ * text that transiently shows a spinner even while an approval modal is
27395
+ * visible, causing rapid approval→busy→approval flicker on the dashboard. */
27396
+ lastModalAt = 0;
27397
+ /** The modal state snapshot held across busy blips. */
27398
+ lastModalState = null;
27487
27399
  completionIdleFirstSeenAt = 0;
27488
27400
  completionIdleKey = "";
27489
27401
  /** Timer that re-runs evaluate() once the hold window expires. Needed
@@ -27597,6 +27509,17 @@ var SpecDriver = class {
27597
27509
  getSpecPath() {
27598
27510
  return this.opts.specPath;
27599
27511
  }
27512
+ getCompletionIdleDebounceState() {
27513
+ if (!this.completionIdleKey || !this.completionIdleFirstSeenAt) return null;
27514
+ const rule = this.spec.debounce?.completion_idle_after;
27515
+ if (!rule) return null;
27516
+ return {
27517
+ active: true,
27518
+ ageMs: Date.now() - this.completionIdleFirstSeenAt,
27519
+ holdMs: rule.hold_ms ?? 0,
27520
+ forceAfterMs: typeof rule.force_after_ms === "number" ? rule.force_after_ms : 0
27521
+ };
27522
+ }
27600
27523
  getScreen() {
27601
27524
  return this.adapter.snapshot();
27602
27525
  }
@@ -27625,8 +27548,8 @@ var SpecDriver = class {
27625
27548
  args: [...baseArgs, ...extra],
27626
27549
  cwd: this.opts.workingDir,
27627
27550
  env: { ...this.spec.env ?? {}, ...this.opts.extraEnv ?? {} },
27628
- cols: this.opts.cols ?? 100,
27629
- rows: this.opts.rows ?? 30,
27551
+ cols: this.opts.cols ?? import_session_host_core7.DEFAULT_SESSION_HOST_COLS,
27552
+ rows: this.opts.rows ?? import_session_host_core7.DEFAULT_SESSION_HOST_ROWS,
27630
27553
  transportFactory: this.opts.transportFactory
27631
27554
  };
27632
27555
  }
@@ -27683,6 +27606,14 @@ var SpecDriver = class {
27683
27606
  evState = this.lastBusyState ?? evState;
27684
27607
  }
27685
27608
  }
27609
+ const idleStateId = this.spec.default_state ?? "idle";
27610
+ const isModalState = (id) => id !== null && id !== "busy" && id !== idleStateId;
27611
+ if (isModalState(this.currentStateId) && evState.id === "busy") {
27612
+ const ageMs = Date.now() - this.lastModalAt;
27613
+ if (ageMs < busyHoldMs && this.lastModalState) {
27614
+ evState = this.lastModalState;
27615
+ }
27616
+ }
27686
27617
  const completionIdleRule = this.spec.debounce?.completion_idle_after;
27687
27618
  let busyWakeMs = busyHoldMs;
27688
27619
  if (evState.id === "busy" && completionIdleRule) {
@@ -27722,13 +27653,21 @@ var SpecDriver = class {
27722
27653
  this.lastBusyAt = Date.now();
27723
27654
  this.lastBusyState = evState;
27724
27655
  this.cancelIdleHold();
27725
- this.completionIdleKey = "";
27726
- this.completionIdleFirstSeenAt = 0;
27656
+ if (!this.completionIdleKey) {
27657
+ this.completionIdleFirstSeenAt = 0;
27658
+ }
27727
27659
  this.scheduleBusyExpiry(busyWakeMs);
27728
27660
  } else if (evState.id !== this.currentStateId && evState.id !== "busy") {
27729
27661
  if (evState.id !== (this.spec.default_state ?? "idle")) {
27730
27662
  this.cancelIdleHold();
27731
27663
  }
27664
+ if (isModalState(evState.id)) {
27665
+ this.lastModalAt = Date.now();
27666
+ this.lastModalState = evState;
27667
+ } else {
27668
+ this.lastModalAt = 0;
27669
+ this.lastModalState = null;
27670
+ }
27732
27671
  }
27733
27672
  const idleHoldMs = this.spec.debounce?.idle_hold_ms ?? 0;
27734
27673
  const isIdleState = evState.id === (this.spec.default_state ?? "idle");
@@ -28956,6 +28895,8 @@ var SpecCliAdapter = class {
28956
28895
  idleHoldPending: this.driver.hasIdleHoldPending(),
28957
28896
  lastBusyAt: this.driver.getLastBusyAt(),
28958
28897
  specPath: this.driver.getSpecPath(),
28898
+ cursorPosition: this.driver.getCursorPosition(),
28899
+ completionIdleDebounce: this.driver.getCompletionIdleDebounceState(),
28959
28900
  // Extended fields
28960
28901
  name: this.cliName,
28961
28902
  status: this.getStatus().status,
@@ -47408,6 +47349,7 @@ async function handleCliRaw(ctx, req, res) {
47408
47349
  var fs26 = __toESM(require("fs"));
47409
47350
  var path38 = __toESM(require("path"));
47410
47351
  var os28 = __toESM(require("os"));
47352
+ var import_session_host_core8 = require("@adhdev/session-host-core");
47411
47353
  function getAutoImplPid(ctx) {
47412
47354
  const pid = ctx.autoImplProcess?.pid;
47413
47355
  return typeof pid === "number" && pid > 0 ? pid : null;
@@ -47805,8 +47747,8 @@ async function handleAutoImplement(ctx, type, req, res) {
47805
47747
  const isWin2 = os28.platform() === "win32";
47806
47748
  child = pty.spawn(isWin2 ? "cmd.exe" : process.env.SHELL || "/bin/zsh", [isWin2 ? "/c" : "-c", shellCmd], {
47807
47749
  name: "xterm-256color",
47808
- cols: 120,
47809
- rows: 40,
47750
+ cols: import_session_host_core8.DEFAULT_SESSION_HOST_COLS,
47751
+ rows: import_session_host_core8.DEFAULT_SESSION_HOST_ROWS,
47810
47752
  cwd: providerDir,
47811
47753
  env: { ...process.env, ...spawn4.env || {} }
47812
47754
  });
@@ -50257,7 +50199,7 @@ init_provider_cli_adapter();
50257
50199
  init_pty_transport();
50258
50200
 
50259
50201
  // src/cli-adapters/session-host-transport.ts
50260
- var import_session_host_core3 = require("@adhdev/session-host-core");
50202
+ var import_session_host_core9 = require("@adhdev/session-host-core");
50261
50203
  init_logger();
50262
50204
  function shouldResumeAttachedSession(record) {
50263
50205
  if (!record) return false;
@@ -50269,7 +50211,7 @@ function shouldResumeAttachedSession(record) {
50269
50211
  var SessionHostRuntimeTransport = class {
50270
50212
  constructor(options) {
50271
50213
  this.options = options;
50272
- this.client = new import_session_host_core3.SessionHostClient({
50214
+ this.client = new import_session_host_core9.SessionHostClient({
50273
50215
  endpoint: options.endpoint,
50274
50216
  appName: options.appName
50275
50217
  });
@@ -50647,7 +50589,7 @@ var SessionHostPtyTransportFactory = class {
50647
50589
 
50648
50590
  // src/cli-adapters/raw-terminal-io.ts
50649
50591
  var import_crypto7 = require("crypto");
50650
- var import_session_host_core4 = require("@adhdev/session-host-core");
50592
+ var import_session_host_core10 = require("@adhdev/session-host-core");
50651
50593
  var BASE_KEY_SEQUENCES = {
50652
50594
  enter: "\r",
50653
50595
  escape: "\x1B",
@@ -50745,7 +50687,7 @@ var RawTerminalAttachment = class _RawTerminalAttachment {
50745
50687
  if (!sessionId) throw new Error("sessionId is required");
50746
50688
  const mode = options.mode || "read";
50747
50689
  const clientId = options.clientId || `raw-terminal-${process.pid}-${(0, import_crypto7.randomUUID)().slice(0, 8)}`;
50748
- const client = options.client || new import_session_host_core4.SessionHostClient({ endpoint: options.endpoint });
50690
+ const client = options.client || new import_session_host_core10.SessionHostClient({ endpoint: options.endpoint });
50749
50691
  await client.connect();
50750
50692
  const attachResponse = await client.request({
50751
50693
  type: "attach_session",
@@ -50872,7 +50814,7 @@ function resolveSessionHostAppName(options = {}) {
50872
50814
  }
50873
50815
 
50874
50816
  // src/session-host/runtime-support.ts
50875
- var import_session_host_core5 = require("@adhdev/session-host-core");
50817
+ var import_session_host_core11 = require("@adhdev/session-host-core");
50876
50818
  var STARTUP_TIMEOUT_MS = DEFAULT_SESSION_HOST_READY_TIMEOUT_MS;
50877
50819
  var STARTUP_POLL_MS = 200;
50878
50820
  var SessionHostCompatibilityError = class extends Error {
@@ -50900,7 +50842,7 @@ async function assertRequiredRequestTypes(client, requiredRequestTypes) {
50900
50842
  }
50901
50843
  }
50902
50844
  async function canConnect(endpoint, requiredRequestTypes = []) {
50903
- const client = new import_session_host_core5.SessionHostClient({ endpoint });
50845
+ const client = new import_session_host_core11.SessionHostClient({ endpoint });
50904
50846
  try {
50905
50847
  await client.connect();
50906
50848
  await assertRequiredRequestTypes(client, requiredRequestTypes);
@@ -50922,7 +50864,7 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS, requiredRe
50922
50864
  throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
50923
50865
  }
50924
50866
  async function ensureSessionHostReady(options) {
50925
- const endpoint = (0, import_session_host_core5.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
50867
+ const endpoint = (0, import_session_host_core11.getDefaultSessionHostEndpoint)(options.appName || "adhdev");
50926
50868
  const requiredRequestTypes = options.requiredRequestTypes || [];
50927
50869
  if (await canConnect(endpoint, requiredRequestTypes)) return endpoint;
50928
50870
  options.spawnHost();
@@ -50930,7 +50872,7 @@ async function ensureSessionHostReady(options) {
50930
50872
  return endpoint;
50931
50873
  }
50932
50874
  async function listHostedCliRuntimes(endpoint) {
50933
- const client = new import_session_host_core5.SessionHostClient({ endpoint });
50875
+ const client = new import_session_host_core11.SessionHostClient({ endpoint });
50934
50876
  try {
50935
50877
  const response = await client.request({
50936
50878
  type: "list_sessions",