@hydra-acp/cli 0.1.38 → 0.1.40

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 (2) hide show
  1. package/dist/cli.js +132 -22
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -4941,6 +4941,35 @@ function disabled() {
4941
4941
  }
4942
4942
  return false;
4943
4943
  }
4944
+ function parseVersion(v) {
4945
+ const core = v.split("-", 1)[0] ?? v;
4946
+ const parts = core.split(".");
4947
+ const major = Number(parts[0]);
4948
+ const minor = Number(parts[1]);
4949
+ const patch = Number(parts[2]);
4950
+ if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) {
4951
+ return null;
4952
+ }
4953
+ return [major, minor, patch];
4954
+ }
4955
+ function isNewer(latest, current) {
4956
+ const a = parseVersion(latest);
4957
+ const b = parseVersion(current);
4958
+ if (!a || !b) {
4959
+ return latest !== current;
4960
+ }
4961
+ for (let i = 0; i < 3; i++) {
4962
+ const av = a[i];
4963
+ const bv = b[i];
4964
+ if (av > bv) {
4965
+ return true;
4966
+ }
4967
+ if (av < bv) {
4968
+ return false;
4969
+ }
4970
+ }
4971
+ return false;
4972
+ }
4944
4973
  async function getPendingUpdate() {
4945
4974
  if (cached !== void 0) {
4946
4975
  return cached;
@@ -4956,7 +4985,7 @@ async function getPendingUpdate() {
4956
4985
  pkg: { name: PKG_NAME, version: HYDRA_VERSION }
4957
4986
  });
4958
4987
  const u = notifier.update;
4959
- if (u && typeof u.latest === "string" && typeof u.current === "string" && u.latest !== u.current) {
4988
+ if (u && typeof u.latest === "string" && typeof u.current === "string" && isNewer(u.latest, u.current)) {
4960
4989
  try {
4961
4990
  notifier.config?.set?.("update", u);
4962
4991
  } catch {
@@ -4967,6 +4996,12 @@ async function getPendingUpdate() {
4967
4996
  type: typeof u.type === "string" ? u.type : "unknown"
4968
4997
  };
4969
4998
  } else {
4999
+ if (u && typeof u.latest === "string" && typeof u.current === "string") {
5000
+ try {
5001
+ notifier.config?.set?.("update", void 0);
5002
+ } catch {
5003
+ }
5004
+ }
4970
5005
  cached = null;
4971
5006
  }
4972
5007
  } catch {
@@ -6099,7 +6134,7 @@ function writeStyled(term, text, style) {
6099
6134
  term(text);
6100
6135
  return;
6101
6136
  case "thought":
6102
- term.dim.italic.noFormat(text);
6137
+ term.brightBlack.dim.noFormat(text);
6103
6138
  return;
6104
6139
  case "tool":
6105
6140
  term.brightBlue.noFormat(text);
@@ -8022,6 +8057,7 @@ uncaught: ${err.stack ?? err.message}
8022
8057
  this.lastFrameH = h;
8023
8058
  }
8024
8059
  withSync(() => {
8060
+ this.term.hideCursor();
8025
8061
  this.drawScrollback();
8026
8062
  this.drawCompletionZone();
8027
8063
  this.drawQueuedZone();
@@ -8034,6 +8070,9 @@ uncaught: ${err.stack ?? err.message}
8034
8070
  this.drawSeparator(h - SESSIONBAR_ROWS);
8035
8071
  this.drawSessionbar();
8036
8072
  this.placeCursor();
8073
+ if (this.permissionPrompt || this.confirmPrompt || this.helpPrompt) {
8074
+ this.term.hideCursor(false);
8075
+ }
8037
8076
  this.lastPromptRows = promptRows;
8038
8077
  });
8039
8078
  }
@@ -8852,14 +8891,11 @@ async function pickSession(term, opts) {
8852
8891
  const composerBoxInner = () => Math.max(2, termWidth - 2);
8853
8892
  const paintComposerTopBorder = () => {
8854
8893
  const inner = composerBoxInner();
8855
- const focused = selectedIdx === 0;
8856
8894
  const titleFragment = `\u2500 ${composerTitle} `;
8857
8895
  const dashCount = Math.max(1, inner - titleFragment.length);
8858
8896
  const dashes = "\u2500".repeat(dashCount);
8859
- if (focused) {
8860
- term.brightCyan.noFormat("\u256D");
8861
- term.brightCyan.bold.noFormat(titleFragment);
8862
- term.brightCyan.noFormat(`${dashes}\u256E`);
8897
+ if (selectedIdx === 0) {
8898
+ term.brightBlue.noFormat(`\u256D${titleFragment}${dashes}\u256E`);
8863
8899
  } else {
8864
8900
  term.dim.noFormat(`\u256D${titleFragment}${dashes}\u256E`);
8865
8901
  }
@@ -8868,15 +8904,13 @@ async function pickSession(term, opts) {
8868
8904
  const inner = composerBoxInner();
8869
8905
  const dashes = "\u2500".repeat(inner);
8870
8906
  if (selectedIdx === 0) {
8871
- term.brightCyan.noFormat(`\u2570${dashes}\u256F`);
8907
+ term.brightBlue.noFormat(`\u2570${dashes}\u256F`);
8872
8908
  } else {
8873
8909
  term.dim.noFormat(`\u2570${dashes}\u256F`);
8874
8910
  }
8875
8911
  };
8876
8912
  const paintComposerBodyRow = (visualIdx) => {
8877
8913
  const inner = composerBoxInner();
8878
- const sideStyle = selectedIdx === 0 ? term.brightCyan : term.dim;
8879
- sideStyle.noFormat("\u2502");
8880
8914
  const vr = composerVisualRows[visualIdx];
8881
8915
  let slice = "";
8882
8916
  if (vr) {
@@ -8885,13 +8919,17 @@ async function pickSession(term, opts) {
8885
8919
  vr.endCol
8886
8920
  );
8887
8921
  }
8888
- term.noFormat(" ");
8889
- term.noFormat(slice);
8890
8922
  const padWidth = Math.max(0, inner - 1 - slice.length);
8891
- if (padWidth > 0) {
8892
- term.noFormat(" ".repeat(padWidth));
8923
+ const pad = " ".repeat(padWidth);
8924
+ if (selectedIdx === 0) {
8925
+ term.brightBlue.noFormat("\u2502");
8926
+ term.noFormat(` ${slice}${pad}`);
8927
+ term.brightBlue.noFormat("\u2502");
8928
+ } else {
8929
+ term.dim.noFormat("\u2502");
8930
+ term.noFormat(` ${slice}${pad}`);
8931
+ term.dim.noFormat("\u2502");
8893
8932
  }
8894
- sideStyle.noFormat("\u2502");
8895
8933
  };
8896
8934
  const paintSessionRow = (sessionIdx) => {
8897
8935
  const label = sessionLines[sessionIdx] ?? "";
@@ -9085,6 +9123,58 @@ async function pickSession(term, opts) {
9085
9123
  paintIndicator();
9086
9124
  });
9087
9125
  };
9126
+ let pasteActive = false;
9127
+ let pasteBuffer = "";
9128
+ let tkStdinHandler = null;
9129
+ const PASTE_START = "\x1B[200~";
9130
+ const PASTE_END = "\x1B[201~";
9131
+ const rawStdinHandler = (chunk) => {
9132
+ let text = chunk.toString("binary");
9133
+ if (pasteActive) {
9134
+ const endIdx = text.indexOf(PASTE_END);
9135
+ if (endIdx === -1) {
9136
+ pasteBuffer += text;
9137
+ return;
9138
+ }
9139
+ pasteBuffer += text.slice(0, endIdx);
9140
+ pasteActive = false;
9141
+ const pasted = Buffer.from(pasteBuffer, "binary").toString("utf-8").replace(/\r\n?/g, "\n");
9142
+ pasteBuffer = "";
9143
+ const remaining = text.slice(endIdx + PASTE_END.length);
9144
+ if (selectedIdx === 0 && !searchActive) {
9145
+ composer.feed({ type: "paste", text: pasted });
9146
+ const after = composer.state();
9147
+ const newVr = computePromptVisualRows(after.buffer, composerRoom);
9148
+ const newLayout = computePromptLayout(
9149
+ newVr,
9150
+ after,
9151
+ PICKER_COMPOSER_MAX_ROWS
9152
+ );
9153
+ if (newLayout.rendered !== composerRows) {
9154
+ renderFromScratch();
9155
+ } else {
9156
+ repaintComposerBody();
9157
+ }
9158
+ }
9159
+ if (remaining.length > 0 && tkStdinHandler) {
9160
+ tkStdinHandler(Buffer.from(remaining, "binary"));
9161
+ }
9162
+ return;
9163
+ }
9164
+ const startIdx = text.indexOf(PASTE_START);
9165
+ if (startIdx === -1) {
9166
+ tkStdinHandler?.(chunk);
9167
+ return;
9168
+ }
9169
+ if (startIdx > 0) {
9170
+ tkStdinHandler?.(Buffer.from(text.slice(0, startIdx), "binary"));
9171
+ }
9172
+ text = text.slice(startIdx + PASTE_START.length);
9173
+ pasteActive = true;
9174
+ if (text.length > 0) {
9175
+ rawStdinHandler(Buffer.from(text, "binary"));
9176
+ }
9177
+ };
9088
9178
  renderFromScratch();
9089
9179
  return await new Promise((resolve6) => {
9090
9180
  let resolved = false;
@@ -9101,6 +9191,15 @@ async function pickSession(term, opts) {
9101
9191
  resolved = true;
9102
9192
  term.off("key", onKey);
9103
9193
  term.off("resize", onResize);
9194
+ process.stdout.write("\x1B[?2004l");
9195
+ const tClean = term;
9196
+ if (tClean.stdin && tkStdinHandler) {
9197
+ tClean.stdin.removeListener("data", rawStdinHandler);
9198
+ tClean.stdin.on("data", tkStdinHandler);
9199
+ tkStdinHandler = null;
9200
+ }
9201
+ pasteActive = false;
9202
+ pasteBuffer = "";
9104
9203
  term.grabInput(false);
9105
9204
  term.hideCursor(false);
9106
9205
  term.moveTo(1, indicatorRow() + 1);
@@ -9593,6 +9692,13 @@ async function pickSession(term, opts) {
9593
9692
  }
9594
9693
  };
9595
9694
  term.grabInput({});
9695
+ const tSetup = term;
9696
+ if (tSetup.stdin && typeof tSetup.onStdin === "function") {
9697
+ tkStdinHandler = tSetup.onStdin;
9698
+ tSetup.stdin.removeListener("data", tSetup.onStdin);
9699
+ tSetup.stdin.on("data", rawStdinHandler);
9700
+ process.stdout.write("\x1B[?2004h");
9701
+ }
9596
9702
  term.on("key", onKey);
9597
9703
  term.on("resize", onResize);
9598
9704
  });
@@ -11028,9 +11134,12 @@ async function runTuiApp(opts) {
11028
11134
  }
11029
11135
  const term = termkit.terminal;
11030
11136
  const exitHint = {};
11137
+ const viewPrefs = {
11138
+ showThoughts: config.tui.showThoughts
11139
+ };
11031
11140
  let nextOpts = opts;
11032
11141
  while (nextOpts !== null) {
11033
- nextOpts = await runSession(term, config, target, nextOpts, exitHint);
11142
+ nextOpts = await runSession(term, config, target, nextOpts, exitHint, viewPrefs);
11034
11143
  }
11035
11144
  const pendingUpdate = await getPendingUpdate();
11036
11145
  if (pendingUpdate) {
@@ -11047,7 +11156,7 @@ async function runTuiApp(opts) {
11047
11156
  );
11048
11157
  }
11049
11158
  }
11050
- async function runSession(term, config, target, opts, exitHint) {
11159
+ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
11051
11160
  const ctx = await resolveSession(term, config, target, opts);
11052
11161
  if (!ctx) {
11053
11162
  term.grabInput(false);
@@ -11555,7 +11664,6 @@ async function runSession(term, config, target, opts, exitHint) {
11555
11664
  }
11556
11665
  let turnInFlight = null;
11557
11666
  let pendingPrefill = null;
11558
- let showThoughts = config.tui.showThoughts;
11559
11667
  const screen = new Screen({
11560
11668
  term,
11561
11669
  dispatcher,
@@ -11760,7 +11868,7 @@ async function runSession(term, config, target, opts, exitHint) {
11760
11868
  const usage = { ...initialUsage ?? {} };
11761
11869
  installStatus.finalize();
11762
11870
  screen.start();
11763
- screen.setHideThoughts(!showThoughts);
11871
+ screen.setHideThoughts(!viewPrefs.showThoughts);
11764
11872
  screen.setSessionbar({
11765
11873
  agent: sessionbarAgent,
11766
11874
  cwd: resolvedCwd,
@@ -12147,9 +12255,11 @@ async function runSession(term, config, target, opts, exitHint) {
12147
12255
  renderToolsBlock();
12148
12256
  return;
12149
12257
  case "toggle-thoughts":
12150
- showThoughts = !showThoughts;
12151
- screen.setHideThoughts(!showThoughts);
12152
- screen.notify(showThoughts ? "thoughts shown" : "thoughts hidden");
12258
+ viewPrefs.showThoughts = !viewPrefs.showThoughts;
12259
+ screen.setHideThoughts(!viewPrefs.showThoughts);
12260
+ screen.notify(
12261
+ viewPrefs.showThoughts ? "thoughts shown" : "thoughts hidden"
12262
+ );
12153
12263
  return;
12154
12264
  case "toggle-mouse": {
12155
12265
  const next = !screen.isMouseEnabled();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydra-acp/cli",
3
- "version": "0.1.38",
3
+ "version": "0.1.40",
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",