@ouro.bot/cli 0.1.0-alpha.255 → 0.1.0-alpha.256

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/changelog.json CHANGED
@@ -1,6 +1,14 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.256",
6
+ "changes": [
7
+ "fix(tui): cursor renders as inverse character (not inserted block) \u2014 matches standard terminal cursor behavior.",
8
+ "fix(tui): Alt+Enter via ESC-timing (50ms window) instead of raw stdin handler that interfered with arrow keys.",
9
+ "fix(tui): image path regex now matches backslash-escaped spaces from macOS drag-drop."
10
+ ]
11
+ },
4
12
  {
5
13
  "version": "0.1.0-alpha.255",
6
14
  "changes": [
@@ -113,8 +113,8 @@ function formatImageRef(n) {
113
113
  function replacePathsWithRefs(input) {
114
114
  const images = new Map();
115
115
  // Match absolute paths starting with / that end with an image extension.
116
- // Allow backslash-escaped characters (like `\ ` for spaces in macOS drag-drop).
117
- const pathRegex = /(\/(?:[^\s\\]|\\.)+\.(?:png|jpe?g|gif|webp))/gi;
116
+ // Allow backslash-escaped spaces (like `\ ` from macOS drag-drop).
117
+ const pathRegex = /(\/(?:[^\s]|\\ )+\.(?:png|jpe?g|gif|webp))/gi;
118
118
  let counter = 0;
119
119
  const text = input.replace(pathRegex, (match) => {
120
120
  counter++;
@@ -163,23 +163,10 @@ function InputArea({ onSubmit, onCtrlC, history, queuedInputs, onPopQueue, agent
163
163
  const cursorRef = (0, react_1.useRef)(0);
164
164
  const historyIdx = (0, react_1.useRef)(-1);
165
165
  const savedInput = (0, react_1.useRef)("");
166
- // Raw stdin handler for Alt+Enter (ESC + CR/LF) — Ink 3.2's useInput splits
167
- // \x1b\r into separate events, so we catch the combined sequence here.
168
- const { stdin } = (0, ink_1.useStdin)();
169
- (0, react_1.useEffect)(() => {
170
- if (!stdin)
171
- return;
172
- const onData = (data) => {
173
- const str = data.toString("utf-8");
174
- if (str === "\x1b\r" || str === "\x1b\n") {
175
- const before = inputRef.current.slice(0, cursorRef.current);
176
- const after = inputRef.current.slice(cursorRef.current);
177
- updateInput(before + "\n" + after, cursorRef.current + 1);
178
- }
179
- };
180
- stdin.on("data", onData);
181
- return () => { stdin.off("data", onData); };
182
- }, [stdin]); // eslint-disable-line react-hooks/exhaustive-deps
166
+ // Track last ESC timestamp for Alt+Enter detection.
167
+ // Ink 3.2 splits \x1b\r into separate escape + return events.
168
+ // We detect the pattern by checking if Return arrives within 50ms of Escape.
169
+ const lastEscTime = (0, react_1.useRef)(0);
183
170
  const tooltipTimerRef = (0, react_1.useRef)(null);
184
171
  (0, react_1.useEffect)(() => () => {
185
172
  if (tooltipTimerRef.current)
@@ -223,6 +210,7 @@ function InputArea({ onSubmit, onCtrlC, history, queuedInputs, onPopQueue, agent
223
210
  // Any non-Ctrl-C input clears tooltip
224
211
  setTooltip("");
225
212
  if (key.escape) {
213
+ lastEscTime.current = Date.now();
226
214
  if (inputRef.current) {
227
215
  updateInput("");
228
216
  historyIdx.current = -1;
@@ -243,8 +231,10 @@ function InputArea({ onSubmit, onCtrlC, history, queuedInputs, onPopQueue, agent
243
231
  return;
244
232
  }
245
233
  if (key.return) {
246
- // Alt+Enter or Shift+Enter: insert newline
247
- if (key.meta || key.shift) {
234
+ // Alt+Enter: detect via key.meta OR recent ESC (within 50ms — Ink splits \x1b\r)
235
+ const recentEsc = (Date.now() - lastEscTime.current) < 50;
236
+ if (key.meta || key.shift || recentEsc) {
237
+ lastEscTime.current = 0;
248
238
  const before = inputRef.current.slice(0, cursorRef.current);
249
239
  const after = inputRef.current.slice(cursorRef.current);
250
240
  updateInput(before + "\n" + after, cursorRef.current + 1);
@@ -399,7 +389,9 @@ function InputArea({ onSubmit, onCtrlC, history, queuedInputs, onPopQueue, agent
399
389
  });
400
390
  const isMultiline = input.includes("\n");
401
391
  const inputLines = input.split("\n");
402
- return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { dimColor: true, children: "─".repeat(termWidth()) }), isMultiline ? ((0, jsx_runtime_1.jsx)(ink_1.Box, { flexDirection: "column", children: inputLines.map((line, i) => ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.teal, bold: true, children: i === 0 ? ") " : "· " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.bone, children: line }), i === inputLines.length - 1 ? (cursorVisible ? (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.scale, children: "█" }) : (0, jsx_runtime_1.jsx)(ink_1.Text, { children: " " })) : null] }, i))) })) : ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.teal, bold: true, children: ") " }), !input && queuedInputs.length > 0 ? ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.shadow, children: "Press up to edit queued messages" })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.bone, children: input.slice(0, cursorPos) }), cursorVisible ? (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.scale, children: "█" }) : (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.bone, children: input[cursorPos] ?? " " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.bone, children: input.slice(cursorPos + (cursorVisible ? 0 : 1)) })] }))] })), (0, jsx_runtime_1.jsx)(ink_1.Text, { dimColor: true, children: "─".repeat(termWidth()) }), (0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: true, children: [" ", agentName, model ? ` · ${model}` : "", " \u00B7 /help"] }), (0, jsx_runtime_1.jsx)(ink_1.Box, { flexGrow: 1 }), tooltip ? (0, jsx_runtime_1.jsx)(ink_1.Text, { dimColor: true, children: tooltip }) : (0, jsx_runtime_1.jsx)(ink_1.Text, { dimColor: true, children: "opt+enter for newline" })] })] }));
392
+ return ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { dimColor: true, children: "─".repeat(termWidth()) }), isMultiline ? ((0, jsx_runtime_1.jsx)(ink_1.Box, { flexDirection: "column", children: inputLines.map((line, i) => ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.teal, bold: true, children: i === 0 ? ") " : "· " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.bone, children: line }), i === inputLines.length - 1 ? (cursorVisible ? (0, jsx_runtime_1.jsx)(ink_1.Text, { inverse: true, children: " " }) : (0, jsx_runtime_1.jsx)(ink_1.Text, { children: " " })) : null] }, i))) })) : ((0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.teal, bold: true, children: ") " }), !input && queuedInputs.length > 0 ? ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.shadow, children: "Press up to edit queued messages" })) : ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.bone, children: input.slice(0, cursorPos) }), cursorVisible
393
+ ? (0, jsx_runtime_1.jsx)(ink_1.Text, { inverse: true, children: input[cursorPos] ?? " " })
394
+ : (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.bone, children: input[cursorPos] ?? " " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: OURO.bone, children: input.slice(cursorPos + 1) })] }))] })), (0, jsx_runtime_1.jsx)(ink_1.Text, { dimColor: true, children: "─".repeat(termWidth()) }), (0, jsx_runtime_1.jsxs)(ink_1.Box, { children: [(0, jsx_runtime_1.jsxs)(ink_1.Text, { dimColor: true, children: [" ", agentName, model ? ` · ${model}` : "", " \u00B7 /help"] }), (0, jsx_runtime_1.jsx)(ink_1.Box, { flexGrow: 1 }), tooltip ? (0, jsx_runtime_1.jsx)(ink_1.Text, { dimColor: true, children: tooltip }) : (0, jsx_runtime_1.jsx)(ink_1.Text, { dimColor: true, children: "opt+enter for newline" })] })] }));
403
395
  }
404
396
  // ─── Main TUI Component ─────────────────────────────────────────────
405
397
  function OuroTui({ agentName, model, completedMessages, inputHistory, queuedInputs, live, elapsedSeconds, contextPercent, onSubmit, onCtrlC, onPopQueue, cwd, resumeInfo, onImageMap, }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.255",
3
+ "version": "0.1.0-alpha.256",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",