@hydra-acp/cli 0.1.31 → 0.1.32

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/README.md CHANGED
@@ -362,7 +362,9 @@ The service token lives in its own file (`~/.hydra-acp/auth-token`, mode 0600) a
362
362
 
363
363
  `daemon.sessionRecentMinutes` (default 30) controls how far back `hydra-acp session` (and the `/v1/sessions` REST endpoint without `?all=true`) looks for cold (disk-only) sessions. Set to `0` to never list cold sessions.
364
364
 
365
- `tui.mouse` (default `true`) controls whether the TUI captures mouse events. With capture on, the scroll wheel drives scrollback but selecting text requires `shift+drag` to bypass mouse reporting in your terminal. Set to `false` to disable capture plain click-drag selects text, but wheel-driven scrollback stops working (use `PgUp` / `PgDn` instead).
365
+ `tui.mouse` (default `false`) controls whether the TUI captures mouse events. With capture off (the default), plain click-drag selects text via your terminal emulator, but wheel-driven scrollback stops working use `PgUp` / `PgDn` instead. Set to `true` to enable capture, which lets the scroll wheel drive scrollback at the cost of requiring `shift+drag` to select text.
366
+
367
+ `tui.defaultEnterAction` (default `"amend"`) controls what the unmodified Enter key does in the prompt composer. With `"amend"` (the default), Enter amends the in-flight turn and `Shift+Enter` enqueues a new prompt; with no turn in flight either key just enqueues, since there's nothing to amend. Set to `"enqueue"` to flip the two: Enter enqueues (sends immediately when idle, queues behind an in-flight turn) and `Shift+Enter` amends.
366
368
 
367
369
  ### Extensions
368
370
 
package/dist/cli.js CHANGED
@@ -271,12 +271,12 @@ var init_config = __esm({
271
271
  // buffer. Oldest lines are dropped on overflow. The on-disk session
272
272
  // history is unaffected; this only bounds the TUI's local view buffer.
273
273
  maxScrollbackLines: z.number().int().positive().default(1e4),
274
- // When true (default), the TUI captures mouse events so the wheel can
275
- // drive scrollback. The cost: terminals route clicks to the app, so
276
- // text selection requires shift+drag to bypass mouse reporting. Set
277
- // false to disable capture — wheel scrollback stops working, but
278
- // plain click-drag selects text via the terminal emulator.
279
- mouse: z.boolean().default(true),
274
+ // When true, the TUI captures mouse events so the wheel can drive
275
+ // scrollback. The cost: terminals route clicks to the app, so text
276
+ // selection requires shift+drag to bypass mouse reporting. Default
277
+ // false — wheel scrollback stops working, but plain click-drag
278
+ // selects text via the terminal emulator. Set true to opt back in.
279
+ mouse: z.boolean().default(false),
280
280
  // Size at which the TUI's session/update debug log (tui.log) rotates
281
281
  // to tui.log.0 and resets. Bounds on-disk use at ~2x this value.
282
282
  logMaxBytes: z.number().int().positive().default(5 * 1024 * 1024),
@@ -291,13 +291,13 @@ var init_config = __esm({
291
291
  // just don't want it.
292
292
  progressIndicator: z.boolean().default(true),
293
293
  // What the unmodified Enter key does in the prompt composer.
294
- // "enqueue" (default) — Enter enqueues the prompt (sends immediately
295
- // when idle, queues behind an in-flight turn); Shift+Enter amends
296
- // the in-flight turn.
297
- // "amend" — flips the two: Enter amends the in-flight turn,
298
- // Shift+Enter enqueues. With no turn in flight either key just
299
- // enqueues, since there's nothing to amend.
300
- defaultEnterAction: z.enum(["enqueue", "amend"]).default("enqueue")
294
+ // "amend" (default) — Enter amends the in-flight turn; Shift+Enter
295
+ // enqueues. With no turn in flight either key just enqueues,
296
+ // since there's nothing to amend.
297
+ // "enqueue" — flips the two: Enter enqueues the prompt (sends
298
+ // immediately when idle, queues behind an in-flight turn);
299
+ // Shift+Enter amends the in-flight turn.
300
+ defaultEnterAction: z.enum(["enqueue", "amend"]).default("amend")
301
301
  });
302
302
  ExtensionName = z.string().min(1).regex(/^[A-Za-z0-9._-]+$/, "extension name must be filename-safe");
303
303
  ExtensionBody = z.object({
@@ -338,11 +338,11 @@ var init_config = __esm({
338
338
  tui: TuiConfig.default({
339
339
  repaintThrottleMs: 1e3,
340
340
  maxScrollbackLines: 1e4,
341
- mouse: true,
341
+ mouse: false,
342
342
  logMaxBytes: 5 * 1024 * 1024,
343
343
  cwdColumnMaxWidth: 24,
344
344
  progressIndicator: true,
345
- defaultEnterAction: "enqueue"
345
+ defaultEnterAction: "amend"
346
346
  })
347
347
  });
348
348
  }
@@ -819,9 +819,9 @@ var init_connection = __esm({
819
819
  }
820
820
  const id = nanoid();
821
821
  const message = { jsonrpc: "2.0", id, method, params };
822
- const response = new Promise((resolve5, reject) => {
822
+ const response = new Promise((resolve6, reject) => {
823
823
  this.pending.set(id, {
824
- resolve: (result) => resolve5(result),
824
+ resolve: (result) => resolve6(result),
825
825
  reject
826
826
  });
827
827
  this.stream.send(message).catch((err) => {
@@ -3074,7 +3074,7 @@ _(switched from \`${oldAgentId}\` to \`${newAgentId}\`)_
3074
3074
  }
3075
3075
  const clientParams = this.rewriteForClient(params);
3076
3076
  const toolCallId = extractToolCallId(clientParams);
3077
- return new Promise((resolve5, reject) => {
3077
+ return new Promise((resolve6, reject) => {
3078
3078
  let settled = false;
3079
3079
  const outbound = [];
3080
3080
  const entry = { addClient: sendTo };
@@ -3113,7 +3113,7 @@ _(switched from \`${oldAgentId}\` to \`${newAgentId}\`)_
3113
3113
  update
3114
3114
  }).catch(() => void 0);
3115
3115
  }
3116
- resolve5(result);
3116
+ resolve6(result);
3117
3117
  });
3118
3118
  }).catch((err) => {
3119
3119
  settle(() => reject(err));
@@ -3129,14 +3129,14 @@ _(switched from \`${oldAgentId}\` to \`${newAgentId}\`)_
3129
3129
  // in flight, but doesn't emit prompt_queue_* broadcasts — clients
3130
3130
  // shouldn't see hydra's housekeeping in their chip list.
3131
3131
  async enqueuePrompt(task) {
3132
- return new Promise((resolve5, reject) => {
3132
+ return new Promise((resolve6, reject) => {
3133
3133
  const entry = {
3134
3134
  kind: "internal",
3135
3135
  messageId: generateMessageId(),
3136
3136
  enqueuedAt: Date.now(),
3137
3137
  cancelled: false,
3138
3138
  task,
3139
- resolve: resolve5,
3139
+ resolve: resolve6,
3140
3140
  reject
3141
3141
  };
3142
3142
  this.promptQueue.push(entry);
@@ -3155,7 +3155,7 @@ _(switched from \`${oldAgentId}\` to \`${newAgentId}\`)_
3155
3155
  if (client.clientInfo?.name) originator.name = client.clientInfo.name;
3156
3156
  if (client.clientInfo?.version)
3157
3157
  originator.version = client.clientInfo.version;
3158
- return new Promise((resolve5, reject) => {
3158
+ return new Promise((resolve6, reject) => {
3159
3159
  const entry = {
3160
3160
  kind: "user",
3161
3161
  messageId,
@@ -3164,7 +3164,7 @@ _(switched from \`${oldAgentId}\` to \`${newAgentId}\`)_
3164
3164
  prompt: promptArray,
3165
3165
  enqueuedAt: Date.now(),
3166
3166
  cancelled: false,
3167
- resolve: resolve5,
3167
+ resolve: resolve6,
3168
3168
  reject
3169
3169
  };
3170
3170
  this.promptQueue.push(entry);
@@ -4352,13 +4352,13 @@ function wsToMessageStream(ws) {
4352
4352
  throw new Error("ws is closed");
4353
4353
  }
4354
4354
  const text = JSON.stringify(message);
4355
- await new Promise((resolve5, reject) => {
4355
+ await new Promise((resolve6, reject) => {
4356
4356
  ws.send(text, (err) => {
4357
4357
  if (err) {
4358
4358
  reject(err);
4359
4359
  return;
4360
4360
  }
4361
- resolve5();
4361
+ resolve6();
4362
4362
  });
4363
4363
  });
4364
4364
  },
@@ -4846,8 +4846,8 @@ async function runSessionsTranscript(idOrFile, outPath) {
4846
4846
  }
4847
4847
  async function readBundleFileIfExists(arg) {
4848
4848
  try {
4849
- const stat4 = await fs17.stat(arg);
4850
- if (!stat4.isFile()) {
4849
+ const stat5 = await fs17.stat(arg);
4850
+ if (!stat5.isFile()) {
4851
4851
  return null;
4852
4852
  }
4853
4853
  } catch {
@@ -4882,8 +4882,8 @@ async function runSessionsImport(file, opts = {}) {
4882
4882
  if (opts.cwd !== void 0) {
4883
4883
  const resolved = path11.resolve(opts.cwd);
4884
4884
  try {
4885
- const stat4 = await fs17.stat(resolved);
4886
- if (!stat4.isDirectory()) {
4885
+ const stat5 = await fs17.stat(resolved);
4886
+ if (!stat5.isDirectory()) {
4887
4887
  process.stderr.write(`--cwd ${resolved} is not a directory
4888
4888
  `);
4889
4889
  process.exit(1);
@@ -5029,11 +5029,11 @@ function isResponse(msg) {
5029
5029
  return !("method" in msg) && "id" in msg && msg.id !== void 0;
5030
5030
  }
5031
5031
  async function openWs(url, subprotocols) {
5032
- return new Promise((resolve5, reject) => {
5032
+ return new Promise((resolve6, reject) => {
5033
5033
  const ws = new WebSocket(url, subprotocols);
5034
5034
  const onOpen = () => {
5035
5035
  ws.off("error", onError);
5036
- resolve5(wsToMessageStream(ws));
5036
+ resolve6(wsToMessageStream(ws));
5037
5037
  };
5038
5038
  const onError = (err) => {
5039
5039
  ws.off("open", onOpen);
@@ -5104,8 +5104,8 @@ var init_resilient_ws = __esm({
5104
5104
  throw new Error("resilient ws stream not connected");
5105
5105
  }
5106
5106
  const id = message.id;
5107
- const promise = new Promise((resolve5, reject) => {
5108
- this.pendingRequests.set(id, { resolve: resolve5, reject });
5107
+ const promise = new Promise((resolve6, reject) => {
5108
+ this.pendingRequests.set(id, { resolve: resolve6, reject });
5109
5109
  });
5110
5110
  try {
5111
5111
  await this.current.send(message);
@@ -5133,8 +5133,8 @@ var init_resilient_ws = __esm({
5133
5133
  this.bindStream(stream);
5134
5134
  const wasFirst = this.firstConnect;
5135
5135
  this.firstConnect = false;
5136
- this.connectGate = new Promise((resolve5) => {
5137
- this.releaseConnectGate = resolve5;
5136
+ this.connectGate = new Promise((resolve6) => {
5137
+ this.releaseConnectGate = resolve6;
5138
5138
  });
5139
5139
  try {
5140
5140
  if (this.opts.onConnect) {
@@ -5667,7 +5667,7 @@ async function pickSession(term, opts) {
5667
5667
  };
5668
5668
  renderFromScratch();
5669
5669
  term.hideCursor();
5670
- return await new Promise((resolve5) => {
5670
+ return await new Promise((resolve6) => {
5671
5671
  let resolved = false;
5672
5672
  const onResize = () => {
5673
5673
  if (resolved) {
@@ -5807,7 +5807,7 @@ async function pickSession(term, opts) {
5807
5807
  if (mode === "help") {
5808
5808
  if (name === "CTRL_C") {
5809
5809
  cleanup();
5810
- resolve5({ kind: "abort" });
5810
+ resolve6({ kind: "abort" });
5811
5811
  return;
5812
5812
  }
5813
5813
  mode = "normal";
@@ -5921,12 +5921,12 @@ async function pickSession(term, opts) {
5921
5921
  }
5922
5922
  if (name === "c" || name === "C") {
5923
5923
  cleanup();
5924
- resolve5({ kind: "new" });
5924
+ resolve6({ kind: "new" });
5925
5925
  return;
5926
5926
  }
5927
5927
  if (name === "q" || name === "Q") {
5928
5928
  cleanup();
5929
- resolve5({ kind: "abort" });
5929
+ resolve6({ kind: "abort" });
5930
5930
  return;
5931
5931
  }
5932
5932
  if (name === "o" || name === "O") {
@@ -5976,7 +5976,7 @@ async function pickSession(term, opts) {
5976
5976
  if (session.agentId !== void 0) {
5977
5977
  result.agentId = session.agentId;
5978
5978
  }
5979
- resolve5(result);
5979
+ resolve6(result);
5980
5980
  return;
5981
5981
  }
5982
5982
  if ((name === "k" || name === "K") && selectedIdx > 0) {
@@ -6062,12 +6062,12 @@ async function pickSession(term, opts) {
6062
6062
  case "KP_ENTER": {
6063
6063
  cleanup();
6064
6064
  if (selectedIdx === 0) {
6065
- resolve5({ kind: "new" });
6065
+ resolve6({ kind: "new" });
6066
6066
  return;
6067
6067
  }
6068
6068
  const session = visible[selectedIdx - 1];
6069
6069
  if (!session) {
6070
- resolve5({ kind: "abort" });
6070
+ resolve6({ kind: "abort" });
6071
6071
  return;
6072
6072
  }
6073
6073
  const result = {
@@ -6077,14 +6077,14 @@ async function pickSession(term, opts) {
6077
6077
  if (session.agentId !== void 0) {
6078
6078
  result.agentId = session.agentId;
6079
6079
  }
6080
- resolve5(result);
6080
+ resolve6(result);
6081
6081
  return;
6082
6082
  }
6083
6083
  case "ESCAPE":
6084
6084
  case "CTRL_C":
6085
6085
  case "CTRL_D":
6086
6086
  cleanup();
6087
- resolve5({ kind: "abort" });
6087
+ resolve6({ kind: "abort" });
6088
6088
  return;
6089
6089
  }
6090
6090
  };
@@ -6185,10 +6185,184 @@ var init_picker = __esm({
6185
6185
  }
6186
6186
  });
6187
6187
 
6188
+ // src/core/cwd.ts
6189
+ import * as fs18 from "fs/promises";
6190
+ import * as path12 from "path";
6191
+ async function validateLocalCwd(input) {
6192
+ const trimmed = input.trim();
6193
+ if (trimmed.length === 0) {
6194
+ return { ok: false, reason: "path is empty" };
6195
+ }
6196
+ const resolved = path12.resolve(expandHome(trimmed));
6197
+ let stat5;
6198
+ try {
6199
+ stat5 = await fs18.stat(resolved);
6200
+ } catch {
6201
+ return { ok: false, reason: `${resolved} does not exist` };
6202
+ }
6203
+ if (!stat5.isDirectory()) {
6204
+ return { ok: false, reason: `${resolved} is not a directory` };
6205
+ }
6206
+ return { ok: true, path: resolved };
6207
+ }
6208
+ var init_cwd = __esm({
6209
+ "src/core/cwd.ts"() {
6210
+ "use strict";
6211
+ init_config();
6212
+ }
6213
+ });
6214
+
6215
+ // src/tui/import-cwd-prompt.ts
6216
+ import * as os4 from "os";
6217
+ async function promptForImportCwd(term, session, opts = {}) {
6218
+ const defaultCwd = opts.defaultCwd ?? os4.homedir();
6219
+ process.stdout.write("\x1B[<u");
6220
+ process.stdout.write("\x1B[?2004l");
6221
+ process.stdout.write("\x1B[>4;0m");
6222
+ process.stdout.write("\x1B[>5;0m");
6223
+ process.stdout.write("\x1B[?1000l");
6224
+ process.stdout.write("\x1B[?1002l");
6225
+ process.stdout.write("\x1B[?1006l");
6226
+ process.stdout.write("\x1B[?1l");
6227
+ process.stdout.write("\x1B>");
6228
+ const shortId2 = stripHydraSessionPrefix(session.sessionId);
6229
+ const fromMachine = session.importedFromMachine ?? "another machine";
6230
+ const originalCwd = session.cwd;
6231
+ let buffer = defaultCwd;
6232
+ let errorLine = null;
6233
+ let busy = false;
6234
+ const render = () => {
6235
+ term("\n");
6236
+ term.bold.cyan("Imported session: ");
6237
+ term(`${shortId2}
6238
+ `);
6239
+ term.dim(` from machine: `);
6240
+ term(`${fromMachine}
6241
+ `);
6242
+ term.dim(` original cwd: `);
6243
+ term(`${shortenHomePath(originalCwd)}
6244
+ `);
6245
+ term("\n");
6246
+ term(
6247
+ "This session has never been launched on this machine. Pick a local\n"
6248
+ );
6249
+ term("cwd for the agent (Enter to accept, Esc to cancel):\n\n");
6250
+ paintInput();
6251
+ if (errorLine) {
6252
+ term("\n");
6253
+ term.red(` ${errorLine}
6254
+ `);
6255
+ }
6256
+ };
6257
+ const paintInput = () => {
6258
+ term.bold("cwd: ");
6259
+ term(buffer);
6260
+ if (!busy) {
6261
+ term.bgWhite(" ");
6262
+ }
6263
+ };
6264
+ const repaintInput = () => {
6265
+ term.column(1);
6266
+ term.eraseLine();
6267
+ paintInput();
6268
+ if (errorLine !== null) {
6269
+ term("\n");
6270
+ term.eraseLine();
6271
+ term.red(` ${errorLine}`);
6272
+ term.up(1);
6273
+ term.column(1);
6274
+ }
6275
+ };
6276
+ render();
6277
+ return await new Promise((resolve6) => {
6278
+ let resolved = false;
6279
+ const cleanup = () => {
6280
+ if (resolved) {
6281
+ return;
6282
+ }
6283
+ resolved = true;
6284
+ term.off("key", onKey);
6285
+ term.grabInput(false);
6286
+ term.hideCursor(false);
6287
+ term("\n\n");
6288
+ };
6289
+ const finish = (value) => {
6290
+ cleanup();
6291
+ resolve6(value);
6292
+ };
6293
+ const onKey = (name, _matches, data) => {
6294
+ if (busy) {
6295
+ return;
6296
+ }
6297
+ if (name === "ENTER" || name === "KP_ENTER") {
6298
+ const candidate = buffer;
6299
+ busy = true;
6300
+ errorLine = null;
6301
+ repaintInput();
6302
+ void validateLocalCwd(candidate).then((result) => {
6303
+ busy = false;
6304
+ if (result.ok) {
6305
+ finish(result.path);
6306
+ return;
6307
+ }
6308
+ errorLine = result.reason;
6309
+ repaintInput();
6310
+ });
6311
+ return;
6312
+ }
6313
+ if (name === "ESCAPE" || name === "CTRL_C" || name === "CTRL_D") {
6314
+ finish(null);
6315
+ return;
6316
+ }
6317
+ if (name === "BACKSPACE") {
6318
+ if (buffer.length > 0) {
6319
+ buffer = buffer.slice(0, -1);
6320
+ errorLine = null;
6321
+ repaintInput();
6322
+ }
6323
+ return;
6324
+ }
6325
+ if (name === "CTRL_U") {
6326
+ buffer = "";
6327
+ errorLine = null;
6328
+ repaintInput();
6329
+ return;
6330
+ }
6331
+ if (name === "CTRL_W") {
6332
+ const trimmedRight = buffer.replace(/[/\s]+$/, "");
6333
+ const lastSep = Math.max(
6334
+ trimmedRight.lastIndexOf("/"),
6335
+ trimmedRight.lastIndexOf(" ")
6336
+ );
6337
+ buffer = lastSep >= 0 ? trimmedRight.slice(0, lastSep + 1) : "";
6338
+ errorLine = null;
6339
+ repaintInput();
6340
+ return;
6341
+ }
6342
+ if (data?.isCharacter) {
6343
+ buffer += name;
6344
+ errorLine = null;
6345
+ repaintInput();
6346
+ return;
6347
+ }
6348
+ };
6349
+ term.grabInput({});
6350
+ term.on("key", onKey);
6351
+ });
6352
+ }
6353
+ var init_import_cwd_prompt = __esm({
6354
+ "src/tui/import-cwd-prompt.ts"() {
6355
+ "use strict";
6356
+ init_paths();
6357
+ init_session();
6358
+ init_cwd();
6359
+ }
6360
+ });
6361
+
6188
6362
  // src/tui/attachments.ts
6189
- import path12 from "path";
6363
+ import path13 from "path";
6190
6364
  function mimeFromExtension(p) {
6191
- return EXTENSION_TO_MIME[path12.extname(p).toLowerCase()] ?? null;
6365
+ return EXTENSION_TO_MIME[path13.extname(p).toLowerCase()] ?? null;
6192
6366
  }
6193
6367
  function isSupportedImagePath(p) {
6194
6368
  return mimeFromExtension(p) !== null;
@@ -6832,6 +7006,8 @@ function mapKeyName(name) {
6832
7006
  return "ctrl-v";
6833
7007
  case "CTRL_W":
6834
7008
  return "ctrl-w";
7009
+ case "CTRL_X":
7010
+ return "ctrl-x";
6835
7011
  case "CTRL_Y":
6836
7012
  return "ctrl-y";
6837
7013
  case "ESCAPE":
@@ -7097,7 +7273,7 @@ var init_screen = __esm({
7097
7273
  this.onKey = opts.onKey;
7098
7274
  this.contentRepaintThrottleMs = opts.repaintThrottleMs ?? DEFAULT_CONTENT_REPAINT_THROTTLE_MS;
7099
7275
  this.maxScrollbackLines = opts.maxScrollbackLines ?? DEFAULT_MAX_SCROLLBACK_LINES;
7100
- this.mouseEnabled = opts.mouse ?? true;
7276
+ this.mouseEnabled = opts.mouse ?? false;
7101
7277
  this.progressIndicatorEnabled = opts.progressIndicator ?? true;
7102
7278
  this.readonly = opts.readonly ?? false;
7103
7279
  this.resizeHandler = () => this.repaint();
@@ -7614,6 +7790,57 @@ uncaught: ${err.stack ?? err.message}
7614
7790
  this.drawBanner();
7615
7791
  this.placeCursor();
7616
7792
  }
7793
+ // Runtime toggle for terminal mouse capture. With capture on, the
7794
+ // wheel drives scrollback but text selection requires shift+drag
7795
+ // (terminals route mouse events to the app). With capture off, plain
7796
+ // click-drag selects text but the wheel does nothing in the app —
7797
+ // use PgUp/PgDn for scrollback instead. Bound to ^X so users can
7798
+ // flip on demand without a config reload + restart. Idempotent.
7799
+ //
7800
+ // Re-issuing grabInput() reinstalls terminal-kit's own stdin "data"
7801
+ // listener, so we have to redo the same listener swap that
7802
+ // installBracketedPaste() did at startup — otherwise our raw handler
7803
+ // and terminal-kit's both fire for every keystroke (each character
7804
+ // appears twice in the prompt).
7805
+ setMouseEnabled(enabled) {
7806
+ if (this.mouseEnabled === enabled) {
7807
+ return;
7808
+ }
7809
+ this.mouseEnabled = enabled;
7810
+ if (!this.started) {
7811
+ return;
7812
+ }
7813
+ if (enabled) {
7814
+ this.term.grabInput({ mouse: "button" });
7815
+ this.term.on("mouse", this.mouseHandler);
7816
+ } else {
7817
+ this.term.off("mouse", this.mouseHandler);
7818
+ this.term.grabInput(true);
7819
+ }
7820
+ this.reclaimStdinAfterGrabInput();
7821
+ }
7822
+ // After a grabInput() re-issue, terminal-kit has put its own "data"
7823
+ // listener back on stdin. Pull it back off and reinstall hydra's
7824
+ // rawStdinHandler — keeping the captured terminal-kit handler so our
7825
+ // bracketed-paste extractor can still delegate non-paste bytes to it.
7826
+ // No-op if installBracketedPaste() hasn't run yet (start() does it
7827
+ // before any toggle path can reach here).
7828
+ reclaimStdinAfterGrabInput() {
7829
+ if (this.terminalKitStdinHandler === null) {
7830
+ return;
7831
+ }
7832
+ const t = this.term;
7833
+ if (!t.stdin || typeof t.onStdin !== "function") {
7834
+ return;
7835
+ }
7836
+ this.terminalKitStdinHandler = t.onStdin;
7837
+ t.stdin.removeListener("data", t.onStdin);
7838
+ t.stdin.removeListener("data", this.rawStdinHandler);
7839
+ t.stdin.on("data", this.rawStdinHandler);
7840
+ }
7841
+ isMouseEnabled() {
7842
+ return this.mouseEnabled;
7843
+ }
7617
7844
  // Pushed by the app each onKey tick to reflect prompt-history
7618
7845
  // reverse-search state in the banner — the only place that mode's
7619
7846
  // query is visible. Pass null when not searching.
@@ -9101,6 +9328,8 @@ var init_input = __esm({
9101
9328
  case "ctrl-w":
9102
9329
  this.killWord();
9103
9330
  return [];
9331
+ case "ctrl-x":
9332
+ return [{ type: "toggle-mouse" }];
9104
9333
  case "ctrl-y":
9105
9334
  this.yank();
9106
9335
  return [];
@@ -9683,9 +9912,9 @@ var init_input = __esm({
9683
9912
 
9684
9913
  // src/tui/clipboard.ts
9685
9914
  import { spawn as nodeSpawn } from "child_process";
9686
- import fs18 from "fs/promises";
9687
- import os4 from "os";
9688
- import path13 from "path";
9915
+ import fs19 from "fs/promises";
9916
+ import os5 from "os";
9917
+ import path14 from "path";
9689
9918
  async function readClipboard(envIn = {}) {
9690
9919
  const env = { ...defaultEnv, ...envIn };
9691
9920
  if (env.platform === "darwin") {
@@ -9700,7 +9929,7 @@ async function readClipboard(envIn = {}) {
9700
9929
  };
9701
9930
  }
9702
9931
  async function readMacOS(env) {
9703
- const tmpPath = path13.join(
9932
+ const tmpPath = path14.join(
9704
9933
  env.tmpdir(),
9705
9934
  `hydra-clipboard-${Date.now()}-${process.pid}.png`
9706
9935
  );
@@ -9724,7 +9953,7 @@ async function readMacOS(env) {
9724
9953
  return img;
9725
9954
  }
9726
9955
  } catch {
9727
- await fs18.unlink(tmpPath).catch(() => void 0);
9956
+ await fs19.unlink(tmpPath).catch(() => void 0);
9728
9957
  }
9729
9958
  try {
9730
9959
  const buf = await runCapture(env.spawn, "pbpaste", []);
@@ -9839,9 +10068,9 @@ async function which(env, cmd) {
9839
10068
  }
9840
10069
  async function readFileAsAttachment(p, unlinkAfter) {
9841
10070
  try {
9842
- const buf = await fs18.readFile(p);
10071
+ const buf = await fs19.readFile(p);
9843
10072
  if (unlinkAfter) {
9844
- await fs18.unlink(p).catch(() => void 0);
10073
+ await fs19.unlink(p).catch(() => void 0);
9845
10074
  }
9846
10075
  if (buf.length === 0) {
9847
10076
  return { ok: false, reason: "no image on clipboard" };
@@ -9867,14 +10096,14 @@ async function readFileAsAttachment(p, unlinkAfter) {
9867
10096
  }
9868
10097
  }
9869
10098
  function run2(spawn6, cmd, args) {
9870
- return new Promise((resolve5, reject) => {
10099
+ return new Promise((resolve6, reject) => {
9871
10100
  const proc = spawn6(cmd, args);
9872
10101
  proc.stdout?.on("data", () => void 0);
9873
10102
  proc.stderr?.on("data", () => void 0);
9874
10103
  proc.on("error", reject);
9875
10104
  proc.on("close", (code) => {
9876
10105
  if (code === 0) {
9877
- resolve5();
10106
+ resolve6();
9878
10107
  } else {
9879
10108
  reject(new Error(`${cmd} exited ${code}`));
9880
10109
  }
@@ -9882,7 +10111,7 @@ function run2(spawn6, cmd, args) {
9882
10111
  });
9883
10112
  }
9884
10113
  function runCapture(spawn6, cmd, args) {
9885
- return new Promise((resolve5, reject) => {
10114
+ return new Promise((resolve6, reject) => {
9886
10115
  const proc = spawn6(cmd, args);
9887
10116
  const chunks = [];
9888
10117
  let stdoutEnded = proc.stdout === null;
@@ -9894,7 +10123,7 @@ function runCapture(spawn6, cmd, args) {
9894
10123
  }
9895
10124
  settled = true;
9896
10125
  if (closedCode === 0) {
9897
- resolve5(Buffer.concat(chunks));
10126
+ resolve6(Buffer.concat(chunks));
9898
10127
  } else {
9899
10128
  reject(new Error(`${cmd} exited ${closedCode}`));
9900
10129
  }
@@ -9929,7 +10158,7 @@ var init_clipboard = __esm({
9929
10158
  platform: process.platform,
9930
10159
  env: process.env,
9931
10160
  spawn: nodeSpawn,
9932
- tmpdir: os4.tmpdir
10161
+ tmpdir: os5.tmpdir
9933
10162
  };
9934
10163
  SUPPORTED_IMAGE_MIMES = [
9935
10164
  "image/png",
@@ -10446,8 +10675,8 @@ var init_format = __esm({
10446
10675
  import { appendFileSync, statSync, renameSync } from "fs";
10447
10676
  import { nanoid as nanoid3 } from "nanoid";
10448
10677
  import termkit from "terminal-kit";
10449
- import fs19 from "fs/promises";
10450
- import path14 from "path";
10678
+ import fs20 from "fs/promises";
10679
+ import path15 from "path";
10451
10680
  function isReadonlyForbiddenEffect(effect) {
10452
10681
  switch (effect.type) {
10453
10682
  case "send":
@@ -10775,10 +11004,10 @@ async function runSession(term, config, serviceToken, opts, exitHint) {
10775
11004
  if (pendingPermission.toolCallId && toolCallId && pendingPermission.toolCallId !== toolCallId) {
10776
11005
  return;
10777
11006
  }
10778
- const resolve5 = pendingPermission.resolve;
11007
+ const resolve6 = pendingPermission.resolve;
10779
11008
  pendingPermission = null;
10780
11009
  screen.setPermissionPrompt(null);
10781
- resolve5(result ?? { outcome: { outcome: "cancelled" } });
11010
+ resolve6(result ?? { outcome: { outcome: "cancelled" } });
10782
11011
  };
10783
11012
  const maybeDismissPermissionByToolUpdate = (update) => {
10784
11013
  if (!pendingPermission?.toolCallId) {
@@ -10811,14 +11040,14 @@ async function runSession(term, config, serviceToken, opts, exitHint) {
10811
11040
  if (!pendingPermission) {
10812
11041
  return;
10813
11042
  }
10814
- const { options, resolve: resolve5 } = pendingPermission;
11043
+ const { options, resolve: resolve6 } = pendingPermission;
10815
11044
  pendingPermission = null;
10816
11045
  screen.setPermissionPrompt(null);
10817
11046
  if (optionId === null) {
10818
- resolve5({ outcome: { outcome: "cancelled" } });
11047
+ resolve6({ outcome: { outcome: "cancelled" } });
10819
11048
  return;
10820
11049
  }
10821
- resolve5({ outcome: { outcome: "selected", optionId } });
11050
+ resolve6({ outcome: { outcome: "selected", optionId } });
10822
11051
  void options;
10823
11052
  };
10824
11053
  conn.onRequest("session/request_permission", async (params) => {
@@ -10845,12 +11074,12 @@ async function runSession(term, config, serviceToken, opts, exitHint) {
10845
11074
  ]);
10846
11075
  return { outcome: { outcome: "cancelled" } };
10847
11076
  }
10848
- return new Promise((resolve5) => {
11077
+ return new Promise((resolve6) => {
10849
11078
  pendingPermission = {
10850
11079
  title,
10851
11080
  options,
10852
11081
  selectedIndex: 0,
10853
- resolve: resolve5,
11082
+ resolve: resolve6,
10854
11083
  toolCallId
10855
11084
  };
10856
11085
  refreshPermissionPrompt();
@@ -10939,7 +11168,23 @@ async function runSession(term, config, serviceToken, opts, exitHint) {
10939
11168
  sessionId: ctx.sessionId,
10940
11169
  historyPolicy: "full",
10941
11170
  clientInfo: { name: "hydra-acp-tui", version: HYDRA_VERSION },
10942
- ...opts.readonly === true ? { readonly: true } : {}
11171
+ ...opts.readonly === true ? { readonly: true } : {},
11172
+ // Forward the user-chosen cwd for first-launch imported sessions
11173
+ // via a full resume hint. upstreamSessionId is empty so the
11174
+ // daemon routes through doResurrectFromImport (session-manager.ts)
11175
+ // with the user-supplied cwd instead of silently falling back to
11176
+ // $HOME in resolveImportCwd.
11177
+ ...ctx.importAttachHint !== void 0 ? {
11178
+ _meta: {
11179
+ [HYDRA_META_KEY]: {
11180
+ resume: {
11181
+ upstreamSessionId: "",
11182
+ agentId: ctx.importAttachHint.agentId,
11183
+ cwd: ctx.importAttachHint.cwd
11184
+ }
11185
+ }
11186
+ }
11187
+ } : {}
10943
11188
  });
10944
11189
  resolvedSessionId = attached.sessionId;
10945
11190
  if (attached.clientId) {
@@ -11200,8 +11445,8 @@ async function runSession(term, config, serviceToken, opts, exitHint) {
11200
11445
  }
11201
11446
  });
11202
11447
  let finishSession = null;
11203
- const sessionDone = new Promise((resolve5) => {
11204
- finishSession = resolve5;
11448
+ const sessionDone = new Promise((resolve6) => {
11449
+ finishSession = resolve6;
11205
11450
  });
11206
11451
  const cancelRemoteTurn = () => {
11207
11452
  conn.notify("session/cancel", { sessionId: resolvedSessionId }).catch(() => void 0);
@@ -11518,6 +11763,14 @@ async function runSession(term, config, serviceToken, opts, exitHint) {
11518
11763
  toolsExpanded = !toolsExpanded;
11519
11764
  renderToolsBlock();
11520
11765
  return;
11766
+ case "toggle-mouse": {
11767
+ const next = !screen.isMouseEnabled();
11768
+ screen.setMouseEnabled(next);
11769
+ screen.notify(
11770
+ next ? "mouse capture on \u2014 wheel scrolls; shift+drag to select text" : "mouse capture off \u2014 click-drag selects text; PgUp/PgDn scrolls"
11771
+ );
11772
+ return;
11773
+ }
11521
11774
  case "show-help":
11522
11775
  toggleHelpModal();
11523
11776
  return;
@@ -11560,11 +11813,11 @@ async function runSession(term, config, serviceToken, opts, exitHint) {
11560
11813
  }
11561
11814
  const mimeType = mimeFromExtension(token);
11562
11815
  if (!mimeType) {
11563
- screen.notify(`unsupported image type: ${path14.basename(token)}`);
11816
+ screen.notify(`unsupported image type: ${path15.basename(token)}`);
11564
11817
  continue;
11565
11818
  }
11566
11819
  try {
11567
- const buf = await fs19.readFile(token);
11820
+ const buf = await fs20.readFile(token);
11568
11821
  if (buf.length > MAX_ATTACHMENT_BYTES) {
11569
11822
  screen.notify(
11570
11823
  `image too large (${formatSize(buf.length)}, max ${formatSize(MAX_ATTACHMENT_BYTES)})`
@@ -11574,13 +11827,13 @@ async function runSession(term, config, serviceToken, opts, exitHint) {
11574
11827
  dispatcher.addAttachment({
11575
11828
  mimeType,
11576
11829
  data: buf.toString("base64"),
11577
- name: path14.basename(token),
11830
+ name: path15.basename(token),
11578
11831
  sizeBytes: buf.length
11579
11832
  });
11580
11833
  added++;
11581
11834
  } catch (err) {
11582
11835
  screen.notify(
11583
- `cannot read ${path14.basename(token)}: ${err.message}`
11836
+ `cannot read ${path15.basename(token)}: ${err.message}`
11584
11837
  );
11585
11838
  }
11586
11839
  }
@@ -12297,10 +12550,10 @@ async function runSession(term, config, serviceToken, opts, exitHint) {
12297
12550
  }
12298
12551
  const resetInFlightUiState = () => {
12299
12552
  if (pendingPermission) {
12300
- const resolve5 = pendingPermission.resolve;
12553
+ const resolve6 = pendingPermission.resolve;
12301
12554
  pendingPermission = null;
12302
12555
  screen.setPermissionPrompt(null);
12303
- resolve5({ outcome: { outcome: "cancelled" } });
12556
+ resolve6({ outcome: { outcome: "cancelled" } });
12304
12557
  }
12305
12558
  closeAgentText();
12306
12559
  };
@@ -12465,6 +12718,21 @@ async function resolveSession(term, config, serviceToken, opts) {
12465
12718
  return newCtx(opts, cwd, config);
12466
12719
  }
12467
12720
  opts.readonly = choice.readonly === true;
12721
+ const chosen = sessions.find((s) => s.sessionId === choice.sessionId);
12722
+ const isImportedFirstLaunch = chosen !== void 0 && !!chosen.importedFromMachine && !chosen.upstreamSessionId && !opts.readonly;
12723
+ if (isImportedFirstLaunch) {
12724
+ const promptedCwd = await promptForImportCwd(term, chosen);
12725
+ if (promptedCwd === null) {
12726
+ return null;
12727
+ }
12728
+ const agentId = choice.agentId ?? chosen.agentId ?? "";
12729
+ return {
12730
+ sessionId: choice.sessionId,
12731
+ agentId,
12732
+ cwd: promptedCwd,
12733
+ importAttachHint: { agentId, cwd: promptedCwd }
12734
+ };
12735
+ }
12468
12736
  return {
12469
12737
  sessionId: choice.sessionId,
12470
12738
  agentId: choice.agentId ?? "",
@@ -12593,8 +12861,8 @@ function createInstallStatusLine(term, baseLabel) {
12593
12861
  }
12594
12862
  function rotateIfBig(target) {
12595
12863
  try {
12596
- const stat4 = statSync(target);
12597
- if (stat4.size < logMaxBytes) {
12864
+ const stat5 = statSync(target);
12865
+ if (stat5.size < logMaxBytes) {
12598
12866
  return;
12599
12867
  }
12600
12868
  renameSync(target, `${target}.0`);
@@ -12618,6 +12886,7 @@ var init_app = __esm({
12618
12886
  init_history();
12619
12887
  init_discovery();
12620
12888
  init_picker();
12889
+ init_import_cwd_prompt();
12621
12890
  init_screen();
12622
12891
  init_input();
12623
12892
  init_attachments();
@@ -12647,6 +12916,7 @@ var init_app = __esm({
12647
12916
  ["^R / ^S", "history reverse / forward search"],
12648
12917
  ["PgUp / PgDn", "scroll scrollback"],
12649
12918
  ["Mouse wheel", "scroll scrollback (when mouse capture is on)"],
12919
+ ["^X", "toggle mouse capture (wheel scroll vs. text selection)"],
12650
12920
  null,
12651
12921
  ["^C", "cancel turn (twice to exit)"],
12652
12922
  ["Esc", "cancel turn and prefill draft"],
@@ -12673,7 +12943,7 @@ var init_tui = __esm({
12673
12943
  // src/cli.ts
12674
12944
  import { readFileSync as readFileSync2 } from "fs";
12675
12945
  import { fileURLToPath as fileURLToPath2 } from "url";
12676
- import { dirname as dirname6, resolve as resolve4 } from "path";
12946
+ import { dirname as dirname6, resolve as resolve5 } from "path";
12677
12947
 
12678
12948
  // src/cli/parse-args.ts
12679
12949
  var KNOWN_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
@@ -12971,10 +13241,10 @@ async function downloadTo(args) {
12971
13241
  logSink(formatProgress(args.agentId, received, total));
12972
13242
  }
12973
13243
  });
12974
- await new Promise((resolve5, reject) => {
13244
+ await new Promise((resolve6, reject) => {
12975
13245
  nodeStream.on("error", reject);
12976
13246
  out.on("error", reject);
12977
- out.on("finish", () => resolve5());
13247
+ out.on("finish", () => resolve6());
12978
13248
  nodeStream.pipe(out);
12979
13249
  });
12980
13250
  logSink(formatProgress(
@@ -13026,14 +13296,14 @@ async function extract(archivePath, dest) {
13026
13296
  throw new Error(`Unsupported archive format: ${archivePath}`);
13027
13297
  }
13028
13298
  function run(cmd, args) {
13029
- return new Promise((resolve5, reject) => {
13299
+ return new Promise((resolve6, reject) => {
13030
13300
  const child = spawn(cmd, args, {
13031
13301
  stdio: ["ignore", "ignore", "inherit"]
13032
13302
  });
13033
13303
  child.on("error", reject);
13034
13304
  child.on("exit", (code, signal) => {
13035
13305
  if (code === 0) {
13036
- resolve5();
13306
+ resolve6();
13037
13307
  return;
13038
13308
  }
13039
13309
  reject(
@@ -13045,11 +13315,11 @@ function run(cmd, args) {
13045
13315
  });
13046
13316
  }
13047
13317
  async function hasCommand(name) {
13048
- return new Promise((resolve5) => {
13318
+ return new Promise((resolve6) => {
13049
13319
  const finder = process.platform === "win32" ? "where" : "which";
13050
13320
  const child = spawn(finder, [name], { stdio: "ignore" });
13051
- child.on("error", () => resolve5(false));
13052
- child.on("exit", (code) => resolve5(code === 0));
13321
+ child.on("error", () => resolve6(false));
13322
+ child.on("exit", (code) => resolve6(code === 0));
13053
13323
  });
13054
13324
  }
13055
13325
  async function fileExists(p) {
@@ -13167,7 +13437,7 @@ function runNpmInstall(args) {
13167
13437
  }
13168
13438
  async function runNpmInstallOnce(args, attempt) {
13169
13439
  try {
13170
- await new Promise((resolve5, reject) => {
13440
+ await new Promise((resolve6, reject) => {
13171
13441
  const registryArgs = args.registry ? ["--registry", args.registry] : [];
13172
13442
  let child;
13173
13443
  try {
@@ -13209,7 +13479,7 @@ async function runNpmInstallOnce(args, attempt) {
13209
13479
  });
13210
13480
  child.on("exit", (code, signal) => {
13211
13481
  if (code === 0) {
13212
- resolve5();
13482
+ resolve6();
13213
13483
  return;
13214
13484
  }
13215
13485
  const reason = code !== null ? `exit code ${code}` : `signal ${signal ?? "unknown"}`;
@@ -13537,13 +13807,13 @@ function ndjsonStreamFromStdio(stdout, stdin) {
13537
13807
  throw new Error("stream is closed");
13538
13808
  }
13539
13809
  const line = JSON.stringify(message) + "\n";
13540
- await new Promise((resolve5, reject) => {
13810
+ await new Promise((resolve6, reject) => {
13541
13811
  stdin.write(line, (err) => {
13542
13812
  if (err) {
13543
13813
  reject(err);
13544
13814
  return;
13545
13815
  }
13546
- resolve5();
13816
+ resolve6();
13547
13817
  });
13548
13818
  });
13549
13819
  },
@@ -14058,8 +14328,8 @@ var SessionManager = class {
14058
14328
  }
14059
14329
  async resolveImportCwd(cwd) {
14060
14330
  try {
14061
- const stat4 = await fs11.stat(cwd);
14062
- if (stat4.isDirectory()) {
14331
+ const stat5 = await fs11.stat(cwd);
14332
+ if (stat5.isDirectory()) {
14063
14333
  return cwd;
14064
14334
  }
14065
14335
  } catch {
@@ -14982,9 +15252,9 @@ var ExtensionManager = class {
14982
15252
  } catch {
14983
15253
  }
14984
15254
  tasks.push(
14985
- new Promise((resolve5) => {
15255
+ new Promise((resolve6) => {
14986
15256
  if (child.exitCode !== null || child.signalCode !== null) {
14987
- resolve5();
15257
+ resolve6();
14988
15258
  return;
14989
15259
  }
14990
15260
  const timer = setTimeout(() => {
@@ -14992,11 +15262,11 @@ var ExtensionManager = class {
14992
15262
  child.kill("SIGKILL");
14993
15263
  } catch {
14994
15264
  }
14995
- resolve5();
15265
+ resolve6();
14996
15266
  }, STOP_GRACE_MS);
14997
15267
  child.on("exit", () => {
14998
15268
  clearTimeout(timer);
14999
- resolve5();
15269
+ resolve6();
15000
15270
  });
15001
15271
  })
15002
15272
  );
@@ -15104,8 +15374,8 @@ var ExtensionManager = class {
15104
15374
  if (child.exitCode !== null || child.signalCode !== null) {
15105
15375
  return;
15106
15376
  }
15107
- const exited = new Promise((resolve5) => {
15108
- entry.exitWaiters.push(resolve5);
15377
+ const exited = new Promise((resolve6) => {
15378
+ entry.exitWaiters.push(resolve6);
15109
15379
  });
15110
15380
  try {
15111
15381
  child.kill("SIGTERM");
@@ -15302,8 +15572,8 @@ var ExtensionManager = class {
15302
15572
  entry.pid = void 0;
15303
15573
  entry.lastExitCode = typeof code === "number" ? code : void 0;
15304
15574
  const waiters = entry.exitWaiters.splice(0);
15305
- for (const resolve5 of waiters) {
15306
- resolve5();
15575
+ for (const resolve6 of waiters) {
15576
+ resolve6();
15307
15577
  }
15308
15578
  if (this.stopping || entry.manuallyStopped) {
15309
15579
  try {
@@ -17174,9 +17444,9 @@ import * as fs16 from "fs";
17174
17444
  import * as fsp6 from "fs/promises";
17175
17445
  async function runLogTail(logPath, argv, notFoundMessage) {
17176
17446
  const opts = parseLogTailFlags(argv);
17177
- let stat4;
17447
+ let stat5;
17178
17448
  try {
17179
- stat4 = await fsp6.stat(logPath);
17449
+ stat5 = await fsp6.stat(logPath);
17180
17450
  } catch (err) {
17181
17451
  const e = err;
17182
17452
  if (e.code === "ENOENT") {
@@ -17187,7 +17457,7 @@ async function runLogTail(logPath, argv, notFoundMessage) {
17187
17457
  }
17188
17458
  throw err;
17189
17459
  }
17190
- let position = await printTail(logPath, stat4.size, opts.tail);
17460
+ let position = await printTail(logPath, stat5.size, opts.tail);
17191
17461
  if (!opts.follow) {
17192
17462
  return;
17193
17463
  }
@@ -17222,10 +17492,10 @@ async function runLogTail(logPath, argv, notFoundMessage) {
17222
17492
  }
17223
17493
  });
17224
17494
  });
17225
- await new Promise((resolve5) => {
17495
+ await new Promise((resolve6) => {
17226
17496
  const finish = () => {
17227
17497
  watcher.close();
17228
- resolve5();
17498
+ resolve6();
17229
17499
  };
17230
17500
  process.once("SIGINT", finish);
17231
17501
  process.once("SIGTERM", finish);
@@ -18031,7 +18301,7 @@ async function promptPassword(prompt) {
18031
18301
  if (!process.stdin.isTTY) {
18032
18302
  return readLineFromStdin();
18033
18303
  }
18034
- return new Promise((resolve5, reject) => {
18304
+ return new Promise((resolve6, reject) => {
18035
18305
  const stdin = process.stdin;
18036
18306
  const wasRaw = stdin.isRaw === true;
18037
18307
  let buffer = "";
@@ -18048,7 +18318,7 @@ async function promptPassword(prompt) {
18048
18318
  if (byte === 10 || byte === 13) {
18049
18319
  process.stdout.write("\n");
18050
18320
  cleanup();
18051
- resolve5(buffer);
18321
+ resolve6(buffer);
18052
18322
  return;
18053
18323
  }
18054
18324
  if (byte === 3) {
@@ -18074,7 +18344,7 @@ async function promptPassword(prompt) {
18074
18344
  });
18075
18345
  }
18076
18346
  function readLineFromStdin() {
18077
- return new Promise((resolve5, reject) => {
18347
+ return new Promise((resolve6, reject) => {
18078
18348
  let buffer = "";
18079
18349
  process.stdin.setEncoding("utf8");
18080
18350
  const onData = (chunk) => {
@@ -18083,7 +18353,7 @@ function readLineFromStdin() {
18083
18353
  if (nl !== -1) {
18084
18354
  process.stdin.removeListener("data", onData);
18085
18355
  process.stdin.removeListener("error", onError);
18086
- resolve5(buffer.slice(0, nl).replace(/\r$/, ""));
18356
+ resolve6(buffer.slice(0, nl).replace(/\r$/, ""));
18087
18357
  }
18088
18358
  };
18089
18359
  const onError = (err) => {
@@ -18916,7 +19186,7 @@ function readVersion() {
18916
19186
  try {
18917
19187
  const here = dirname6(fileURLToPath2(import.meta.url));
18918
19188
  const pkg = JSON.parse(
18919
- readFileSync2(resolve4(here, "../package.json"), "utf8")
19189
+ readFileSync2(resolve5(here, "../package.json"), "utf8")
18920
19190
  );
18921
19191
  return pkg.version ?? "unknown";
18922
19192
  } catch {
package/dist/index.js CHANGED
@@ -168,12 +168,12 @@ var TuiConfig = z.object({
168
168
  // buffer. Oldest lines are dropped on overflow. The on-disk session
169
169
  // history is unaffected; this only bounds the TUI's local view buffer.
170
170
  maxScrollbackLines: z.number().int().positive().default(1e4),
171
- // When true (default), the TUI captures mouse events so the wheel can
172
- // drive scrollback. The cost: terminals route clicks to the app, so
173
- // text selection requires shift+drag to bypass mouse reporting. Set
174
- // false to disable capture — wheel scrollback stops working, but
175
- // plain click-drag selects text via the terminal emulator.
176
- mouse: z.boolean().default(true),
171
+ // When true, the TUI captures mouse events so the wheel can drive
172
+ // scrollback. The cost: terminals route clicks to the app, so text
173
+ // selection requires shift+drag to bypass mouse reporting. Default
174
+ // false — wheel scrollback stops working, but plain click-drag
175
+ // selects text via the terminal emulator. Set true to opt back in.
176
+ mouse: z.boolean().default(false),
177
177
  // Size at which the TUI's session/update debug log (tui.log) rotates
178
178
  // to tui.log.0 and resets. Bounds on-disk use at ~2x this value.
179
179
  logMaxBytes: z.number().int().positive().default(5 * 1024 * 1024),
@@ -188,13 +188,13 @@ var TuiConfig = z.object({
188
188
  // just don't want it.
189
189
  progressIndicator: z.boolean().default(true),
190
190
  // What the unmodified Enter key does in the prompt composer.
191
- // "enqueue" (default) — Enter enqueues the prompt (sends immediately
192
- // when idle, queues behind an in-flight turn); Shift+Enter amends
193
- // the in-flight turn.
194
- // "amend" — flips the two: Enter amends the in-flight turn,
195
- // Shift+Enter enqueues. With no turn in flight either key just
196
- // enqueues, since there's nothing to amend.
197
- defaultEnterAction: z.enum(["enqueue", "amend"]).default("enqueue")
191
+ // "amend" (default) — Enter amends the in-flight turn; Shift+Enter
192
+ // enqueues. With no turn in flight either key just enqueues,
193
+ // since there's nothing to amend.
194
+ // "enqueue" — flips the two: Enter enqueues the prompt (sends
195
+ // immediately when idle, queues behind an in-flight turn);
196
+ // Shift+Enter amends the in-flight turn.
197
+ defaultEnterAction: z.enum(["enqueue", "amend"]).default("amend")
198
198
  });
199
199
  var ExtensionName = z.string().min(1).regex(/^[A-Za-z0-9._-]+$/, "extension name must be filename-safe");
200
200
  var ExtensionBody = z.object({
@@ -235,11 +235,11 @@ var HydraConfig = z.object({
235
235
  tui: TuiConfig.default({
236
236
  repaintThrottleMs: 1e3,
237
237
  maxScrollbackLines: 1e4,
238
- mouse: true,
238
+ mouse: false,
239
239
  logMaxBytes: 5 * 1024 * 1024,
240
240
  cwdColumnMaxWidth: 24,
241
241
  progressIndicator: true,
242
- defaultEnterAction: "enqueue"
242
+ defaultEnterAction: "amend"
243
243
  })
244
244
  });
245
245
  function extensionList(config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydra-acp/cli",
3
- "version": "0.1.31",
3
+ "version": "0.1.32",
4
4
  "description": "Multi-client ACP session daemon: spawn agents, attach over WSS, multiplex sessions across editors.",
5
5
  "license": "MIT",
6
6
  "type": "module",