@ogpoyraz/wtx 0.8.9 → 0.8.10

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.mjs +522 -257
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
2
3
  var __defProp = Object.defineProperty;
3
4
  var __returnValue = (v) => v;
4
5
  function __exportSetter(name, newValue) {
@@ -14,6 +15,7 @@ var __export = (target, all) => {
14
15
  });
15
16
  };
16
17
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
17
19
 
18
20
  // node_modules/zod/v4/core/core.js
19
21
  function $constructor(name, initializer, params) {
@@ -25100,6 +25102,18 @@ class Semaphore {
25100
25102
  }
25101
25103
  }
25102
25104
 
25105
+ // src/tui/env.ts
25106
+ var init_env = __esm(() => {
25107
+ process.env.RUST_LOG ??= "fatal";
25108
+ process.env.ZIG_LOG ??= "fatal";
25109
+ process.env.PAGE_LIST_LOG ??= "fatal";
25110
+ process.env.OPENTUI_LOG ??= "fatal";
25111
+ process.env.LOG_LEVEL ??= "fatal";
25112
+ process.env.ZIG_LOG_LEVEL ??= "fatal";
25113
+ process.env.OPENTUI_LOG_LEVEL ??= "fatal";
25114
+ process.env.BUN_DEBUG ??= "0";
25115
+ });
25116
+
25103
25117
  // src/tui/data.ts
25104
25118
  async function fetchWorktreeData(opts, scope) {
25105
25119
  const warnings = [];
@@ -25597,6 +25611,39 @@ async function copyTextToClipboard(renderer, text) {
25597
25611
  }
25598
25612
  return viaSystem || viaTerminal;
25599
25613
  }
25614
+ function pasteCandidatesFor(platform2, env2 = process.env) {
25615
+ if (platform2 === "darwin")
25616
+ return [{ cmd: "pbpaste", args: [] }];
25617
+ if (platform2 === "win32")
25618
+ return [{ cmd: "powershell.exe", args: ["-command", "Get-Clipboard"] }];
25619
+ const candidates = [];
25620
+ if (env2.WAYLAND_DISPLAY)
25621
+ candidates.push({ cmd: "wl-paste", args: ["--no-newline"] });
25622
+ if (env2.DISPLAY) {
25623
+ candidates.push({ cmd: "xclip", args: ["-selection", "clipboard", "-o"] });
25624
+ candidates.push({ cmd: "xsel", args: ["--clipboard", "--output"] });
25625
+ }
25626
+ candidates.push({ cmd: "wl-paste", args: ["--no-newline"] });
25627
+ candidates.push({ cmd: "xclip", args: ["-selection", "clipboard", "-o"] });
25628
+ candidates.push({ cmd: "xsel", args: ["--clipboard", "--output"] });
25629
+ return candidates;
25630
+ }
25631
+ async function readTextFromClipboard() {
25632
+ for (const candidate of pasteCandidatesFor(process.platform)) {
25633
+ try {
25634
+ const proc = Bun.spawn([candidate.cmd, ...candidate.args], {
25635
+ stdin: "ignore",
25636
+ stdout: "pipe",
25637
+ stderr: "ignore"
25638
+ });
25639
+ const text = await new Response(proc.stdout).text();
25640
+ const code = await proc.exited;
25641
+ if (code === 0 && text)
25642
+ return text;
25643
+ } catch {}
25644
+ }
25645
+ return null;
25646
+ }
25600
25647
  function browserCommandFor(platform2, url2) {
25601
25648
  if (!/^https?:\/\//.test(url2))
25602
25649
  return null;
@@ -25926,8 +25973,255 @@ var init_TabBar = __esm(() => {
25926
25973
  init_use_tap();
25927
25974
  });
25928
25975
 
25929
- // src/tui/tabs/TabPane.tsx
25976
+ // src/tui/components/TerminalView.tsx
25977
+ import { useState as useState2, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback3 } from "react";
25930
25978
  import { jsx as jsx3, jsxs as jsxs3 } from "@opentui/react/jsx-runtime";
25979
+ function TerminalView({ session, focused, onFocus, onSend, onResize, registerListener, unregisterListener }) {
25980
+ const [draft, setDraft] = useState2("");
25981
+ const focusTap = useTapHandler(() => onFocus());
25982
+ const termRef = useRef4(null);
25983
+ const pipeScrollRef = useRef4(null);
25984
+ const handlePtyScroll = useCallback3((e) => {
25985
+ const ev = e;
25986
+ const dir = ev.scroll?.direction;
25987
+ if (dir !== "up" && dir !== "down")
25988
+ return;
25989
+ const term = termRef.current;
25990
+ if (term?.handle && term?.lib) {
25991
+ try {
25992
+ term.lib.embeddedTerminalScroll(term.handle, dir === "up" ? -8 : 8);
25993
+ term.requestRender?.();
25994
+ ev.preventDefault?.();
25995
+ ev.stopPropagation?.();
25996
+ } catch {}
25997
+ }
25998
+ }, []);
25999
+ const handlePipeScroll = useCallback3((e) => {
26000
+ const ev = e;
26001
+ const dir = ev.scroll?.direction;
26002
+ if (dir !== "up" && dir !== "down")
26003
+ return;
26004
+ try {
26005
+ pipeScrollRef.current?.scrollBy(dir === "up" ? -4 : 4);
26006
+ ev.preventDefault?.();
26007
+ ev.stopPropagation?.();
26008
+ } catch {}
26009
+ }, []);
26010
+ const handleData = useCallback3((data, source) => {
26011
+ if (source !== "input")
26012
+ return;
26013
+ if (session.usePty && focused)
26014
+ return;
26015
+ onSend(data);
26016
+ }, [onSend, focused, session.id, session.usePty]);
26017
+ const handleResize = useCallback3((cols, rows) => {
26018
+ onResize?.(cols, rows);
26019
+ }, [onResize]);
26020
+ useEffect3(() => {
26021
+ if (!session.usePty || !session.terminal)
26022
+ return;
26023
+ if (!termRef.current || !registerListener || !unregisterListener)
26024
+ return;
26025
+ const write = (data) => {
26026
+ try {
26027
+ termRef.current?.write(data);
26028
+ } catch {}
26029
+ };
26030
+ registerListener(session.id, write);
26031
+ try {
26032
+ termRef.current?.invalidate?.();
26033
+ } catch {}
26034
+ return () => unregisterListener(session.id);
26035
+ }, [session.id, session.usePty, session.terminal, registerListener, unregisterListener]);
26036
+ useEffect3(() => {
26037
+ if (!session.usePty)
26038
+ return;
26039
+ if (!termRef.current)
26040
+ return;
26041
+ try {
26042
+ if (focused)
26043
+ termRef.current.focus?.();
26044
+ else
26045
+ termRef.current.blur?.();
26046
+ } catch {}
26047
+ }, [focused, session.usePty]);
26048
+ useEffect3(() => {
26049
+ if (!session.usePty || !session.terminal)
26050
+ return;
26051
+ if (!termRef.current)
26052
+ return;
26053
+ try {
26054
+ termRef.current.invalidate?.();
26055
+ } catch {}
26056
+ }, [session.cols, session.rows, session.usePty]);
26057
+ useEffect3(() => {
26058
+ if (!session.usePty || !termRef.current)
26059
+ return;
26060
+ const term = termRef.current;
26061
+ const orig = term.forwardMouse?.bind(term);
26062
+ if (!orig)
26063
+ return;
26064
+ const patched = (event, action) => {
26065
+ const ev = event;
26066
+ if (ev.type === "scroll") {
26067
+ const dir = ev.scroll?.direction;
26068
+ const shift = ev.modifiers?.shift;
26069
+ if (dir === "up" || dir === "down") {
26070
+ const shouldScrollOuter = shift === true;
26071
+ if (!shouldScrollOuter) {
26072
+ return orig(event, action);
26073
+ }
26074
+ try {
26075
+ if (term.handle && term.lib) {
26076
+ term.lib.embeddedTerminalScroll(term.handle, dir === "up" ? -12 : 12);
26077
+ term.requestRender?.();
26078
+ }
26079
+ ev.preventDefault?.();
26080
+ ev.stopPropagation?.();
26081
+ return;
26082
+ } catch {}
26083
+ }
26084
+ }
26085
+ return orig(event, action);
26086
+ };
26087
+ term.forwardMouse = patched;
26088
+ return () => {
26089
+ term.forwardMouse = orig;
26090
+ };
26091
+ }, [session.id, session.usePty, session.terminal]);
26092
+ if (session.usePty && session.terminal) {
26093
+ return /* @__PURE__ */ jsxs3("box", {
26094
+ flexDirection: "column",
26095
+ flexGrow: 1,
26096
+ width: "100%",
26097
+ height: "100%",
26098
+ ...focusTap,
26099
+ onMouseScroll: handlePtyScroll,
26100
+ children: [
26101
+ /* @__PURE__ */ jsx3("box", {
26102
+ flexGrow: 1,
26103
+ width: "100%",
26104
+ height: "100%",
26105
+ flexDirection: "column",
26106
+ padding: 1,
26107
+ onMouseScroll: handlePtyScroll,
26108
+ children: /* @__PURE__ */ jsx3("embedded-terminal", {
26109
+ ref: termRef,
26110
+ width: "100%",
26111
+ height: "100%",
26112
+ cols: session.cols,
26113
+ rows: session.rows,
26114
+ maxScrollback: 1e4,
26115
+ onData: handleData,
26116
+ onTerminalResize: handleResize,
26117
+ selectable: true,
26118
+ focused
26119
+ })
26120
+ }),
26121
+ session.exited !== null && /* @__PURE__ */ jsxs3("text", {
26122
+ fg: tokens.warning,
26123
+ children: [
26124
+ "— exited with code ",
26125
+ session.exited,
26126
+ " — press t for new session"
26127
+ ]
26128
+ }),
26129
+ !focused && /* @__PURE__ */ jsxs3("text", {
26130
+ fg: tokens.dim,
26131
+ children: [
26132
+ "Click to focus · Ctrl+G or click table to unfocus · ",
26133
+ session.label,
26134
+ " PTY · scroll wheel to view history"
26135
+ ]
26136
+ }),
26137
+ focused && /* @__PURE__ */ jsx3("text", {
26138
+ fg: tokens.accent,
26139
+ children: "Focused PTY — all keys go to shell · Ctrl+G to unfocus · scroll wheel to view history"
26140
+ })
26141
+ ]
26142
+ });
26143
+ }
26144
+ const lines = session.lines;
26145
+ return /* @__PURE__ */ jsxs3("box", {
26146
+ flexDirection: "column",
26147
+ flexGrow: 1,
26148
+ width: "100%",
26149
+ height: "100%",
26150
+ ...focusTap,
26151
+ onMouseScroll: handlePipeScroll,
26152
+ children: [
26153
+ /* @__PURE__ */ jsxs3("scrollbox", {
26154
+ ref: pipeScrollRef,
26155
+ flexGrow: 1,
26156
+ width: "100%",
26157
+ border: false,
26158
+ focused: false,
26159
+ stickyScroll: false,
26160
+ style: { marginBottom: 1 },
26161
+ onMouseScroll: handlePipeScroll,
26162
+ children: [
26163
+ lines.length === 0 ? /* @__PURE__ */ jsx3("text", {
26164
+ fg: tokens.dim,
26165
+ children: "No output yet — type a command below."
26166
+ }) : lines.slice(-500).map((line, idx) => /* @__PURE__ */ jsx3("text", {
26167
+ fg: session.exited !== null ? tokens.dim : tokens.fg,
26168
+ children: line || " "
26169
+ }, idx)),
26170
+ session.exited !== null && /* @__PURE__ */ jsxs3("text", {
26171
+ fg: tokens.warning,
26172
+ children: [
26173
+ "— exited with code ",
26174
+ session.exited,
26175
+ " —"
26176
+ ]
26177
+ })
26178
+ ]
26179
+ }),
26180
+ /* @__PURE__ */ jsxs3("box", {
26181
+ flexDirection: "row",
26182
+ gap: 1,
26183
+ width: "100%",
26184
+ children: [
26185
+ /* @__PURE__ */ jsx3("text", {
26186
+ fg: tokens.dim,
26187
+ children: "$"
26188
+ }),
26189
+ /* @__PURE__ */ jsx3("box", {
26190
+ flexGrow: 1,
26191
+ children: /* @__PURE__ */ jsx3("input", {
26192
+ focused,
26193
+ value: draft,
26194
+ placeholder: focused ? "Type command, Enter to send, Esc to unfocus" : "Click to focus terminal",
26195
+ onInput: (v) => setDraft(v),
26196
+ onSubmit: () => {
26197
+ if (!draft)
26198
+ return;
26199
+ onSend(draft + `
26200
+ `);
26201
+ setDraft("");
26202
+ }
26203
+ })
26204
+ })
26205
+ ]
26206
+ }),
26207
+ !focused && /* @__PURE__ */ jsx3("text", {
26208
+ fg: tokens.dim,
26209
+ children: "Click terminal or press 't' to focus · Ctrl+G or click table to unfocus"
26210
+ }),
26211
+ focused && /* @__PURE__ */ jsx3("text", {
26212
+ fg: tokens.accent,
26213
+ children: "Focused — typing goes to shell · Ctrl+G to unfocus · max 5 per worktree persist across switches"
26214
+ })
26215
+ ]
26216
+ });
26217
+ }
26218
+ var init_TerminalView = __esm(() => {
26219
+ init_theme();
26220
+ init_use_tap();
26221
+ });
26222
+
26223
+ // src/tui/tabs/TabPane.tsx
26224
+ import { jsx as jsx4, jsxs as jsxs4 } from "@opentui/react/jsx-runtime";
25931
26225
  function TabPane({
25932
26226
  selectedRow,
25933
26227
  tabs,
@@ -25937,12 +26231,13 @@ function TabPane({
25937
26231
  onSelect,
25938
26232
  onAdd,
25939
26233
  onClose,
25940
- onFocusTerminal: _onFocusTerminal,
25941
- onBlurTerminal: _onBlurTerminal
26234
+ allSessionsFlat,
26235
+ terminalFocused,
26236
+ activeTabId,
26237
+ terminalSessions
25942
26238
  }) {
25943
- const activeTab = tabs.find((t) => t.id === activeId) ?? tabs[0] ?? null;
25944
26239
  const borderColor = focused ? tokens.accent : tokens.border;
25945
- return /* @__PURE__ */ jsxs3("box", {
26240
+ return /* @__PURE__ */ jsxs4("box", {
25946
26241
  flexDirection: "column",
25947
26242
  flexGrow: 1,
25948
26243
  width: "100%",
@@ -25953,7 +26248,7 @@ function TabPane({
25953
26248
  focusable: false,
25954
26249
  id: "detail-pane",
25955
26250
  children: [
25956
- /* @__PURE__ */ jsx3(TabBar, {
26251
+ /* @__PURE__ */ jsx4(TabBar, {
25957
26252
  tabs,
25958
26253
  activeId,
25959
26254
  canAdd,
@@ -25961,14 +26256,39 @@ function TabPane({
25961
26256
  onAdd,
25962
26257
  onClose
25963
26258
  }),
25964
- /* @__PURE__ */ jsx3("box", {
26259
+ /* @__PURE__ */ jsxs4("box", {
25965
26260
  flexGrow: 1,
25966
26261
  width: "100%",
25967
26262
  flexDirection: "column",
25968
- children: activeTab ? activeTab.render({ worktree: selectedRow, isActive: true }) : /* @__PURE__ */ jsx3("text", {
25969
- fg: tokens.dim,
25970
- children: "No tab"
25971
- })
26263
+ children: [
26264
+ tabs.map((t) => /* @__PURE__ */ jsx4("box", {
26265
+ flexGrow: 1,
26266
+ width: "100%",
26267
+ flexDirection: "column",
26268
+ visible: t.id === activeId && t.id === "details",
26269
+ children: t.render({ worktree: selectedRow, isActive: t.id === activeId })
26270
+ }, t.id)),
26271
+ allSessionsFlat?.map((s) => /* @__PURE__ */ jsx4("box", {
26272
+ flexGrow: 1,
26273
+ width: "100%",
26274
+ height: "100%",
26275
+ flexDirection: "column",
26276
+ visible: activeTabId === s.id,
26277
+ children: /* @__PURE__ */ jsx4(TerminalView, {
26278
+ session: s,
26279
+ focused: !!(terminalFocused && activeTabId === s.id),
26280
+ onFocus: () => {},
26281
+ onSend: (data) => terminalSessions?.sendInput(s.repoName, s.branch, s.worktreePath, s.id, data),
26282
+ onResize: (cols, rows) => terminalSessions?.resizeSession(s.repoName, s.branch, s.worktreePath, s.id, cols, rows),
26283
+ registerListener: terminalSessions?.registerListener,
26284
+ unregisterListener: terminalSessions?.unregisterListener
26285
+ })
26286
+ }, s.id)),
26287
+ tabs.length === 0 && (!allSessionsFlat || allSessionsFlat.length === 0) && /* @__PURE__ */ jsx4("text", {
26288
+ fg: tokens.dim,
26289
+ children: "No tab"
26290
+ })
26291
+ ]
25972
26292
  })
25973
26293
  ]
25974
26294
  });
@@ -25976,23 +26296,24 @@ function TabPane({
25976
26296
  var init_TabPane = __esm(() => {
25977
26297
  init_theme();
25978
26298
  init_TabBar();
26299
+ init_TerminalView();
25979
26300
  });
25980
26301
 
25981
26302
  // src/tui/components/DetailsTab.tsx
25982
- import { jsx as jsx4, jsxs as jsxs4, Fragment } from "@opentui/react/jsx-runtime";
26303
+ import { jsx as jsx5, jsxs as jsxs5, Fragment } from "@opentui/react/jsx-runtime";
25983
26304
  function DetailsContent({ selectedRow }) {
25984
26305
  const prTap = useTapHandler(() => {
25985
26306
  if (selectedRow?.prUrl)
25986
26307
  openInBrowser(selectedRow.prUrl);
25987
26308
  });
25988
26309
  if (!selectedRow) {
25989
- return /* @__PURE__ */ jsx4("box", {
26310
+ return /* @__PURE__ */ jsx5("box", {
25990
26311
  flexGrow: 1,
25991
26312
  width: "100%",
25992
26313
  height: "100%",
25993
26314
  justifyContent: "center",
25994
26315
  alignItems: "center",
25995
- children: /* @__PURE__ */ jsx4("text", {
26316
+ children: /* @__PURE__ */ jsx5("text", {
25996
26317
  fg: tokens.dim,
25997
26318
  children: "No worktree selected"
25998
26319
  })
@@ -26020,20 +26341,20 @@ function DetailsContent({ selectedRow }) {
26020
26341
  baseChanged
26021
26342
  } = selectedRow;
26022
26343
  const aheadBehindStr = ahead !== null && behind !== null ? `${ahead} ahead, ${behind} behind` : "unknown";
26023
- return /* @__PURE__ */ jsxs4("scrollbox", {
26344
+ return /* @__PURE__ */ jsxs5("scrollbox", {
26024
26345
  flexGrow: 1,
26025
26346
  width: "100%",
26026
26347
  height: "100%",
26027
26348
  focused: false,
26028
26349
  padding: 1,
26029
26350
  children: [
26030
- /* @__PURE__ */ jsxs4("text", {
26351
+ /* @__PURE__ */ jsxs5("text", {
26031
26352
  children: [
26032
- /* @__PURE__ */ jsx4("span", {
26353
+ /* @__PURE__ */ jsx5("span", {
26033
26354
  fg: tokens.dim,
26034
26355
  children: "Repo:"
26035
26356
  }),
26036
- /* @__PURE__ */ jsxs4("span", {
26357
+ /* @__PURE__ */ jsxs5("span", {
26037
26358
  fg: tokens.fg,
26038
26359
  children: [
26039
26360
  " ",
@@ -26042,13 +26363,13 @@ function DetailsContent({ selectedRow }) {
26042
26363
  })
26043
26364
  ]
26044
26365
  }),
26045
- /* @__PURE__ */ jsxs4("text", {
26366
+ /* @__PURE__ */ jsxs5("text", {
26046
26367
  children: [
26047
- /* @__PURE__ */ jsx4("span", {
26368
+ /* @__PURE__ */ jsx5("span", {
26048
26369
  fg: tokens.dim,
26049
26370
  children: "Branch:"
26050
26371
  }),
26051
- /* @__PURE__ */ jsxs4("span", {
26372
+ /* @__PURE__ */ jsxs5("span", {
26052
26373
  fg: tokens.fg,
26053
26374
  children: [
26054
26375
  " ",
@@ -26059,13 +26380,13 @@ function DetailsContent({ selectedRow }) {
26059
26380
  })
26060
26381
  ]
26061
26382
  }),
26062
- /* @__PURE__ */ jsxs4("text", {
26383
+ /* @__PURE__ */ jsxs5("text", {
26063
26384
  children: [
26064
- /* @__PURE__ */ jsx4("span", {
26385
+ /* @__PURE__ */ jsx5("span", {
26065
26386
  fg: tokens.dim,
26066
26387
  children: "Path:"
26067
26388
  }),
26068
- /* @__PURE__ */ jsxs4("span", {
26389
+ /* @__PURE__ */ jsxs5("span", {
26069
26390
  fg: tokens.fg,
26070
26391
  children: [
26071
26392
  " ",
@@ -26074,13 +26395,13 @@ function DetailsContent({ selectedRow }) {
26074
26395
  })
26075
26396
  ]
26076
26397
  }),
26077
- /* @__PURE__ */ jsxs4("text", {
26398
+ /* @__PURE__ */ jsxs5("text", {
26078
26399
  children: [
26079
- /* @__PURE__ */ jsx4("span", {
26400
+ /* @__PURE__ */ jsx5("span", {
26080
26401
  fg: tokens.dim,
26081
26402
  children: "Commit:"
26082
26403
  }),
26083
- /* @__PURE__ */ jsxs4("span", {
26404
+ /* @__PURE__ */ jsxs5("span", {
26084
26405
  fg: tokens.fg,
26085
26406
  children: [
26086
26407
  " ",
@@ -26089,13 +26410,13 @@ function DetailsContent({ selectedRow }) {
26089
26410
  })
26090
26411
  ]
26091
26412
  }),
26092
- owner && /* @__PURE__ */ jsxs4("text", {
26413
+ owner && /* @__PURE__ */ jsxs5("text", {
26093
26414
  children: [
26094
- /* @__PURE__ */ jsx4("span", {
26415
+ /* @__PURE__ */ jsx5("span", {
26095
26416
  fg: tokens.dim,
26096
26417
  children: "Owner:"
26097
26418
  }),
26098
- /* @__PURE__ */ jsxs4("span", {
26419
+ /* @__PURE__ */ jsxs5("span", {
26099
26420
  fg: tokens.fg,
26100
26421
  children: [
26101
26422
  " ",
@@ -26104,13 +26425,13 @@ function DetailsContent({ selectedRow }) {
26104
26425
  })
26105
26426
  ]
26106
26427
  }),
26107
- /* @__PURE__ */ jsxs4("text", {
26428
+ /* @__PURE__ */ jsxs5("text", {
26108
26429
  children: [
26109
- /* @__PURE__ */ jsx4("span", {
26430
+ /* @__PURE__ */ jsx5("span", {
26110
26431
  fg: tokens.dim,
26111
26432
  children: "Status:"
26112
26433
  }),
26113
- /* @__PURE__ */ jsxs4("span", {
26434
+ /* @__PURE__ */ jsxs5("span", {
26114
26435
  fg: tokens.fg,
26115
26436
  children: [
26116
26437
  " ",
@@ -26119,13 +26440,13 @@ function DetailsContent({ selectedRow }) {
26119
26440
  })
26120
26441
  ]
26121
26442
  }),
26122
- base2 && /* @__PURE__ */ jsxs4("text", {
26443
+ base2 && /* @__PURE__ */ jsxs5("text", {
26123
26444
  children: [
26124
- /* @__PURE__ */ jsx4("span", {
26445
+ /* @__PURE__ */ jsx5("span", {
26125
26446
  fg: tokens.dim,
26126
26447
  children: "Base:"
26127
26448
  }),
26128
- /* @__PURE__ */ jsxs4("span", {
26449
+ /* @__PURE__ */ jsxs5("span", {
26129
26450
  fg: tokens.accent,
26130
26451
  children: [
26131
26452
  " ",
@@ -26134,26 +26455,26 @@ function DetailsContent({ selectedRow }) {
26134
26455
  })
26135
26456
  ]
26136
26457
  }),
26137
- baseChanged && /* @__PURE__ */ jsxs4("text", {
26458
+ baseChanged && /* @__PURE__ */ jsxs5("text", {
26138
26459
  children: [
26139
- /* @__PURE__ */ jsx4("span", {
26460
+ /* @__PURE__ */ jsx5("span", {
26140
26461
  fg: tokens.dim,
26141
26462
  children: "Base state:"
26142
26463
  }),
26143
- /* @__PURE__ */ jsx4("span", {
26464
+ /* @__PURE__ */ jsx5("span", {
26144
26465
  fg: tokens.warning,
26145
26466
  children: " moved since recorded"
26146
26467
  })
26147
26468
  ]
26148
26469
  }),
26149
- /* @__PURE__ */ jsxs4("text", {
26470
+ /* @__PURE__ */ jsxs5("text", {
26150
26471
  style: { marginTop: 1 },
26151
26472
  children: [
26152
- /* @__PURE__ */ jsx4("span", {
26473
+ /* @__PURE__ */ jsx5("span", {
26153
26474
  fg: tokens.dim,
26154
26475
  children: base2 ? "vs base:" : "vs main:"
26155
26476
  }),
26156
- /* @__PURE__ */ jsxs4("span", {
26477
+ /* @__PURE__ */ jsxs5("span", {
26157
26478
  fg: tokens.fg,
26158
26479
  children: [
26159
26480
  " ",
@@ -26162,13 +26483,13 @@ function DetailsContent({ selectedRow }) {
26162
26483
  })
26163
26484
  ]
26164
26485
  }),
26165
- /* @__PURE__ */ jsxs4("text", {
26486
+ /* @__PURE__ */ jsxs5("text", {
26166
26487
  children: [
26167
- /* @__PURE__ */ jsx4("span", {
26488
+ /* @__PURE__ */ jsx5("span", {
26168
26489
  fg: tokens.dim,
26169
26490
  children: "Deps:"
26170
26491
  }),
26171
- /* @__PURE__ */ jsxs4("span", {
26492
+ /* @__PURE__ */ jsxs5("span", {
26172
26493
  fg: tokens.fg,
26173
26494
  children: [
26174
26495
  " ",
@@ -26177,13 +26498,13 @@ function DetailsContent({ selectedRow }) {
26177
26498
  })
26178
26499
  ]
26179
26500
  }),
26180
- rebaseStatus && /* @__PURE__ */ jsxs4("text", {
26501
+ rebaseStatus && /* @__PURE__ */ jsxs5("text", {
26181
26502
  children: [
26182
- /* @__PURE__ */ jsx4("span", {
26503
+ /* @__PURE__ */ jsx5("span", {
26183
26504
  fg: tokens.dim,
26184
26505
  children: "Rebase:"
26185
26506
  }),
26186
- /* @__PURE__ */ jsxs4("span", {
26507
+ /* @__PURE__ */ jsxs5("span", {
26187
26508
  fg: tokens.error,
26188
26509
  children: [
26189
26510
  " ",
@@ -26192,12 +26513,12 @@ function DetailsContent({ selectedRow }) {
26192
26513
  })
26193
26514
  ]
26194
26515
  }),
26195
- prNumber !== null && /* @__PURE__ */ jsxs4(Fragment, {
26516
+ prNumber !== null && /* @__PURE__ */ jsxs5(Fragment, {
26196
26517
  children: [
26197
- /* @__PURE__ */ jsxs4("text", {
26518
+ /* @__PURE__ */ jsxs5("text", {
26198
26519
  style: { marginTop: 1 },
26199
26520
  children: [
26200
- /* @__PURE__ */ jsxs4("span", {
26521
+ /* @__PURE__ */ jsxs5("span", {
26201
26522
  fg: tokens.accent,
26202
26523
  children: [
26203
26524
  "PR #",
@@ -26205,7 +26526,7 @@ function DetailsContent({ selectedRow }) {
26205
26526
  ":"
26206
26527
  ]
26207
26528
  }),
26208
- /* @__PURE__ */ jsxs4("span", {
26529
+ /* @__PURE__ */ jsxs5("span", {
26209
26530
  fg: tokens.dim,
26210
26531
  children: [
26211
26532
  " ",
@@ -26214,13 +26535,13 @@ function DetailsContent({ selectedRow }) {
26214
26535
  })
26215
26536
  ]
26216
26537
  }),
26217
- prChecks && /* @__PURE__ */ jsxs4("text", {
26538
+ prChecks && /* @__PURE__ */ jsxs5("text", {
26218
26539
  children: [
26219
- /* @__PURE__ */ jsx4("span", {
26540
+ /* @__PURE__ */ jsx5("span", {
26220
26541
  fg: tokens.dim,
26221
26542
  children: "Checks:"
26222
26543
  }),
26223
- /* @__PURE__ */ jsxs4("span", {
26544
+ /* @__PURE__ */ jsxs5("span", {
26224
26545
  fg: tokens.fg,
26225
26546
  children: [
26226
26547
  " ",
@@ -26229,20 +26550,20 @@ function DetailsContent({ selectedRow }) {
26229
26550
  })
26230
26551
  ]
26231
26552
  }),
26232
- prUrl && /* @__PURE__ */ jsx4("box", {
26553
+ prUrl && /* @__PURE__ */ jsx5("box", {
26233
26554
  ...prTap,
26234
- children: /* @__PURE__ */ jsxs4("text", {
26555
+ children: /* @__PURE__ */ jsxs5("text", {
26235
26556
  selectable: false,
26236
26557
  children: [
26237
- /* @__PURE__ */ jsx4("span", {
26558
+ /* @__PURE__ */ jsx5("span", {
26238
26559
  fg: tokens.dim,
26239
26560
  children: "URL:"
26240
26561
  }),
26241
- /* @__PURE__ */ jsx4("span", {
26562
+ /* @__PURE__ */ jsx5("span", {
26242
26563
  fg: tokens.accent,
26243
26564
  children: ` ${prUrl}`
26244
26565
  }),
26245
- /* @__PURE__ */ jsx4("span", {
26566
+ /* @__PURE__ */ jsx5("span", {
26246
26567
  fg: tokens.dim,
26247
26568
  children: " ↗ click"
26248
26569
  })
@@ -26251,11 +26572,11 @@ function DetailsContent({ selectedRow }) {
26251
26572
  })
26252
26573
  ]
26253
26574
  }),
26254
- dirtyFiles.length > 0 && /* @__PURE__ */ jsxs4("box", {
26575
+ dirtyFiles.length > 0 && /* @__PURE__ */ jsxs5("box", {
26255
26576
  flexDirection: "column",
26256
26577
  style: { marginTop: 1 },
26257
26578
  children: [
26258
- /* @__PURE__ */ jsxs4("text", {
26579
+ /* @__PURE__ */ jsxs5("text", {
26259
26580
  fg: tokens.warning,
26260
26581
  children: [
26261
26582
  "Dirty Files (",
@@ -26263,14 +26584,14 @@ function DetailsContent({ selectedRow }) {
26263
26584
  "):"
26264
26585
  ]
26265
26586
  }),
26266
- dirtyFiles.slice(0, 20).map((file2, idx) => /* @__PURE__ */ jsxs4("text", {
26587
+ dirtyFiles.slice(0, 20).map((file2, idx) => /* @__PURE__ */ jsxs5("text", {
26267
26588
  fg: tokens.warning,
26268
26589
  children: [
26269
26590
  " ",
26270
26591
  file2
26271
26592
  ]
26272
26593
  }, idx)),
26273
- dirtyFiles.length > 20 && /* @__PURE__ */ jsxs4("text", {
26594
+ dirtyFiles.length > 20 && /* @__PURE__ */ jsxs5("text", {
26274
26595
  fg: tokens.warning,
26275
26596
  children: [
26276
26597
  " ...and ",
@@ -26280,17 +26601,17 @@ function DetailsContent({ selectedRow }) {
26280
26601
  })
26281
26602
  ]
26282
26603
  }),
26283
- /* @__PURE__ */ jsxs4("box", {
26604
+ /* @__PURE__ */ jsxs5("box", {
26284
26605
  flexDirection: "column",
26285
26606
  style: { marginTop: 1 },
26286
26607
  children: [
26287
- /* @__PURE__ */ jsx4("text", {
26608
+ /* @__PURE__ */ jsx5("text", {
26288
26609
  fg: tokens.dim,
26289
26610
  children: "Actions:"
26290
26611
  }),
26291
- !isMainCheckout && /* @__PURE__ */ jsxs4(Fragment, {
26612
+ !isMainCheckout && /* @__PURE__ */ jsxs5(Fragment, {
26292
26613
  children: [
26293
- /* @__PURE__ */ jsxs4("text", {
26614
+ /* @__PURE__ */ jsxs5("text", {
26294
26615
  fg: tokens.dim,
26295
26616
  children: [
26296
26617
  " i install deps (",
@@ -26298,21 +26619,21 @@ function DetailsContent({ selectedRow }) {
26298
26619
  ")"
26299
26620
  ]
26300
26621
  }),
26301
- /* @__PURE__ */ jsx4("text", {
26622
+ /* @__PURE__ */ jsx5("text", {
26302
26623
  fg: tokens.dim,
26303
26624
  children: " m rename worktree"
26304
26625
  })
26305
26626
  ]
26306
26627
  }),
26307
- /* @__PURE__ */ jsx4("text", {
26628
+ /* @__PURE__ */ jsx5("text", {
26308
26629
  fg: tokens.dim,
26309
26630
  children: " p pull branch"
26310
26631
  }),
26311
- /* @__PURE__ */ jsx4("text", {
26632
+ /* @__PURE__ */ jsx5("text", {
26312
26633
  fg: tokens.dim,
26313
26634
  children: " b rebase · s sync · o open in IDE · d remove"
26314
26635
  }),
26315
- /* @__PURE__ */ jsx4("text", {
26636
+ /* @__PURE__ */ jsx5("text", {
26316
26637
  fg: tokens.dim,
26317
26638
  children: " t new terminal session (max 5)"
26318
26639
  })
@@ -26326,176 +26647,6 @@ var init_DetailsTab = __esm(() => {
26326
26647
  init_use_tap();
26327
26648
  });
26328
26649
 
26329
- // src/tui/components/TerminalView.tsx
26330
- import { useState as useState2, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback3 } from "react";
26331
- import { jsx as jsx5, jsxs as jsxs5 } from "@opentui/react/jsx-runtime";
26332
- function TerminalView({ session, focused, onFocus, onSend, onResize, registerListener, unregisterListener }) {
26333
- const [draft, setDraft] = useState2("");
26334
- const focusTap = useTapHandler(() => onFocus());
26335
- const termRef = useRef4(null);
26336
- const handleData = useCallback3((data, source) => {
26337
- if (source !== "input")
26338
- return;
26339
- if (session.usePty && focused)
26340
- return;
26341
- onSend(data);
26342
- }, [onSend, focused, session.id, session.usePty]);
26343
- const handleResize = useCallback3((cols, rows) => {
26344
- onResize?.(cols, rows);
26345
- }, [onResize]);
26346
- useEffect3(() => {
26347
- if (!session.usePty || !session.terminal)
26348
- return;
26349
- if (!termRef.current || !registerListener || !unregisterListener)
26350
- return;
26351
- try {
26352
- termRef.current.write(new TextEncoder().encode("\x1B[2J\x1B[H"));
26353
- } catch {}
26354
- const write = (data) => {
26355
- try {
26356
- termRef.current?.write(data);
26357
- } catch {}
26358
- };
26359
- registerListener(session.id, write);
26360
- return () => unregisterListener(session.id);
26361
- }, [session.id, session.usePty, session.terminal, registerListener, unregisterListener]);
26362
- useEffect3(() => {
26363
- if (!session.usePty)
26364
- return;
26365
- if (!termRef.current)
26366
- return;
26367
- try {
26368
- if (focused)
26369
- termRef.current.focus?.();
26370
- else
26371
- termRef.current.blur?.();
26372
- } catch {}
26373
- }, [focused, session.usePty]);
26374
- if (session.usePty && session.terminal) {
26375
- return /* @__PURE__ */ jsxs5("box", {
26376
- flexDirection: "column",
26377
- flexGrow: 1,
26378
- width: "100%",
26379
- height: "100%",
26380
- ...focusTap,
26381
- children: [
26382
- /* @__PURE__ */ jsx5("box", {
26383
- flexGrow: 1,
26384
- width: "100%",
26385
- height: "100%",
26386
- flexDirection: "column",
26387
- padding: 1,
26388
- children: /* @__PURE__ */ jsx5("embedded-terminal", {
26389
- ref: termRef,
26390
- width: "100%",
26391
- height: "100%",
26392
- cols: session.cols,
26393
- rows: session.rows,
26394
- maxScrollback: 1000,
26395
- onData: handleData,
26396
- onTerminalResize: handleResize,
26397
- selectable: true,
26398
- focused
26399
- })
26400
- }),
26401
- session.exited !== null && /* @__PURE__ */ jsxs5("text", {
26402
- fg: tokens.warning,
26403
- children: [
26404
- "— exited with code ",
26405
- session.exited,
26406
- " — press t for new session"
26407
- ]
26408
- }),
26409
- !focused && /* @__PURE__ */ jsxs5("text", {
26410
- fg: tokens.dim,
26411
- children: [
26412
- "Click to focus · Ctrl+G or click table to unfocus · ",
26413
- session.label,
26414
- " PTY"
26415
- ]
26416
- }),
26417
- focused && /* @__PURE__ */ jsx5("text", {
26418
- fg: tokens.accent,
26419
- children: "Focused PTY — all keys go to shell · Ctrl+G to unfocus"
26420
- })
26421
- ]
26422
- });
26423
- }
26424
- const lines = session.lines;
26425
- return /* @__PURE__ */ jsxs5("box", {
26426
- flexDirection: "column",
26427
- flexGrow: 1,
26428
- width: "100%",
26429
- height: "100%",
26430
- ...focusTap,
26431
- children: [
26432
- /* @__PURE__ */ jsxs5("scrollbox", {
26433
- flexGrow: 1,
26434
- width: "100%",
26435
- border: false,
26436
- focused: false,
26437
- style: { marginBottom: 1 },
26438
- children: [
26439
- lines.length === 0 ? /* @__PURE__ */ jsx5("text", {
26440
- fg: tokens.dim,
26441
- children: "No output yet — type a command below."
26442
- }) : lines.slice(-200).map((line, idx) => /* @__PURE__ */ jsx5("text", {
26443
- fg: session.exited !== null ? tokens.dim : tokens.fg,
26444
- children: line || " "
26445
- }, idx)),
26446
- session.exited !== null && /* @__PURE__ */ jsxs5("text", {
26447
- fg: tokens.warning,
26448
- children: [
26449
- "— exited with code ",
26450
- session.exited,
26451
- " —"
26452
- ]
26453
- })
26454
- ]
26455
- }),
26456
- /* @__PURE__ */ jsxs5("box", {
26457
- flexDirection: "row",
26458
- gap: 1,
26459
- width: "100%",
26460
- children: [
26461
- /* @__PURE__ */ jsx5("text", {
26462
- fg: tokens.dim,
26463
- children: "$"
26464
- }),
26465
- /* @__PURE__ */ jsx5("box", {
26466
- flexGrow: 1,
26467
- children: /* @__PURE__ */ jsx5("input", {
26468
- focused,
26469
- value: draft,
26470
- placeholder: focused ? "Type command, Enter to send, Esc to unfocus" : "Click to focus terminal",
26471
- onInput: (v) => setDraft(v),
26472
- onSubmit: () => {
26473
- if (!draft)
26474
- return;
26475
- onSend(draft + `
26476
- `);
26477
- setDraft("");
26478
- }
26479
- })
26480
- })
26481
- ]
26482
- }),
26483
- !focused && /* @__PURE__ */ jsx5("text", {
26484
- fg: tokens.dim,
26485
- children: "Click terminal or press 't' to focus · Ctrl+G or click table to unfocus"
26486
- }),
26487
- focused && /* @__PURE__ */ jsx5("text", {
26488
- fg: tokens.accent,
26489
- children: "Focused — typing goes to shell · Ctrl+G to unfocus · max 5 per worktree persist across switches"
26490
- })
26491
- ]
26492
- });
26493
- }
26494
- var init_TerminalView = __esm(() => {
26495
- init_theme();
26496
- init_use_tap();
26497
- });
26498
-
26499
26650
  // src/tui/components/Footer.tsx
26500
26651
  import { jsx as jsx6, jsxs as jsxs6 } from "@opentui/react/jsx-runtime";
26501
26652
  function HintItem({ hintKey, label, isFirst, onClick }) {
@@ -27831,9 +27982,24 @@ function useTerminalSessions() {
27831
27982
  });
27832
27983
  };
27833
27984
  const onPtyData = (data) => {
27985
+ if (data.length > 0) {
27986
+ const text = new TextDecoder().decode(data);
27987
+ if (text.includes("page_list") || text.includes("x icon") || text.includes("received and ignored")) {
27988
+ const reset2 = new TextEncoder().encode("\x1B[0m");
27989
+ const buf2 = rawBuffersRef.current.get(id) ?? [];
27990
+ buf2.push(reset2);
27991
+ if (buf2.length > 2000)
27992
+ buf2.shift();
27993
+ rawBuffersRef.current.set(id, buf2);
27994
+ const listener2 = listenersRef.current.get(id);
27995
+ if (listener2)
27996
+ listener2(reset2);
27997
+ return;
27998
+ }
27999
+ }
27834
28000
  const buf = rawBuffersRef.current.get(id) ?? [];
27835
28001
  buf.push(data);
27836
- if (buf.length > 500)
28002
+ if (buf.length > 2000)
27837
28003
  buf.shift();
27838
28004
  rawBuffersRef.current.set(id, buf);
27839
28005
  const listener = listenersRef.current.get(id);
@@ -28129,7 +28295,7 @@ var init_useTerminalSessions = () => {};
28129
28295
  // src/tui/components/App.tsx
28130
28296
  import { useState as useState10, useEffect as useEffect8, useMemo, useRef as useRef7, useCallback as useCallback6 } from "react";
28131
28297
  import { existsSync as existsSync4 } from "node:fs";
28132
- import { useKeyboard as useKeyboard3, useRenderer as useRenderer2, useSelectionHandler, useTerminalDimensions } from "@opentui/react";
28298
+ import { useKeyboard as useKeyboard3, usePaste, useRenderer as useRenderer2, useSelectionHandler, useTerminalDimensions } from "@opentui/react";
28133
28299
  import { jsx as jsx17, jsxs as jsxs15 } from "@opentui/react/jsx-runtime";
28134
28300
  function getWorktreePathFor(repoName, branch) {
28135
28301
  try {
@@ -28278,6 +28444,18 @@ function App({ opts }) {
28278
28444
  }
28279
28445
  }
28280
28446
  }, [sessionsForSelected, activeTabId, worktreeKey]);
28447
+ usePaste((event) => {
28448
+ if (!terminalFocused)
28449
+ return;
28450
+ const activeSession = sessionsForSelected.find((s) => s.id === activeTabId);
28451
+ if (!activeSession)
28452
+ return;
28453
+ event.preventDefault();
28454
+ const data = event.bytes;
28455
+ if (data.length === 0)
28456
+ return;
28457
+ terminalSessions.sendInput(activeSession.repoName, activeSession.branch, activeSession.worktreePath, activeSession.id, data);
28458
+ });
28281
28459
  const handleSelectTab = useCallback6((id) => {
28282
28460
  if (!worktreeKey)
28283
28461
  return;
@@ -28335,6 +28513,7 @@ function App({ opts }) {
28335
28513
  terminalSessions.pruneKey(key);
28336
28514
  }
28337
28515
  }, [blocks, terminalSessions]);
28516
+ const allSessionsFlat = useMemo(() => Array.from(terminalSessions.sessionsByKey.values()).flat(), [terminalSessions.sessionsByKey]);
28338
28517
  const tabsForSelected = useMemo(() => {
28339
28518
  const base2 = [
28340
28519
  {
@@ -28350,19 +28529,15 @@ function App({ opts }) {
28350
28529
  id: s.id,
28351
28530
  label: s.label,
28352
28531
  closable: true,
28353
- render: () => /* @__PURE__ */ jsx17(TerminalView, {
28354
- session: s,
28355
- focused: terminalFocused && activeTabId === s.id,
28356
- onFocus: () => setTerminalFocused(true),
28357
- onSend: (data) => terminalSessions.sendInput(s.repoName, s.branch, s.worktreePath, s.id, data),
28358
- onResize: (cols, rows) => terminalSessions.resizeSession(s.repoName, s.branch, s.worktreePath, s.id, cols, rows),
28359
- registerListener: terminalSessions.registerListener,
28360
- unregisterListener: terminalSessions.unregisterListener
28532
+ render: () => /* @__PURE__ */ jsx17("box", {
28533
+ flexGrow: 1,
28534
+ width: "100%",
28535
+ height: "100%"
28361
28536
  })
28362
28537
  });
28363
28538
  }
28364
28539
  return base2;
28365
- }, [sessionsForSelected, terminalFocused, activeTabId, terminalSessions]);
28540
+ }, [sessionsForSelected]);
28366
28541
  const { repoVerbs, rowVerbs } = useMemo(() => {
28367
28542
  const rv = new Map;
28368
28543
  const nv = new Map;
@@ -28673,6 +28848,13 @@ function App({ opts }) {
28673
28848
  }
28674
28849
  const activeSession = sessionsForSelected.find((s) => s.id === activeTabId);
28675
28850
  if (activeSession) {
28851
+ if ((key.ctrl || key.super || key.meta) && key.name === "v") {
28852
+ readTextFromClipboard().then((text) => {
28853
+ if (text)
28854
+ terminalSessions.sendInput(activeSession.repoName, activeSession.branch, activeSession.worktreePath, activeSession.id, text);
28855
+ });
28856
+ return;
28857
+ }
28676
28858
  let data = null;
28677
28859
  const seq = key.sequence;
28678
28860
  const raw = key.raw;
@@ -29108,7 +29290,11 @@ function App({ opts }) {
29108
29290
  canAdd: sessionsForSelected.length < MAX_TERMINAL_SESSIONS,
29109
29291
  onSelect: handleSelectTab,
29110
29292
  onAdd: handleAddSession,
29111
- onClose: handleCloseSession
29293
+ onClose: handleCloseSession,
29294
+ allSessionsFlat,
29295
+ terminalFocused,
29296
+ activeTabId,
29297
+ terminalSessions
29112
29298
  })
29113
29299
  })
29114
29300
  ]
@@ -29388,7 +29574,6 @@ var init_App = __esm(() => {
29388
29574
  init_WorktreeTable();
29389
29575
  init_TabPane();
29390
29576
  init_DetailsTab();
29391
- init_TerminalView();
29392
29577
  init_Footer();
29393
29578
  init_Divider();
29394
29579
  init_HelpOverlay();
@@ -29431,22 +29616,98 @@ import { createCliRenderer, TextTableRenderable, EmbeddedTerminalRenderable } fr
29431
29616
  import { createRoot, extend as extend2 } from "@opentui/react";
29432
29617
  import { jsx as jsx18 } from "@opentui/react/jsx-runtime";
29433
29618
  async function runTerminal(opts) {
29619
+ setQuiet(true);
29620
+ const prevLog = console.log;
29621
+ const prevInfo = console.info;
29622
+ const prevWarn = console.warn;
29623
+ const prevError = console.error;
29624
+ const prevStdoutWrite = process.stdout.write.bind(process.stdout);
29625
+ const prevStderrWrite = process.stderr.write.bind(process.stderr);
29626
+ const shouldSuppress = (chunk) => {
29627
+ const s = typeof chunk === "string" ? chunk : chunk instanceof Uint8Array ? new TextDecoder().decode(chunk) : String(chunk);
29628
+ return s.includes("page_list") || s.includes("adjusting page") || s.includes("x icon") || s.includes("received and ignored");
29629
+ };
29630
+ const suppressed = (..._args) => {};
29631
+ const filteredError = (...args) => {
29632
+ if (args.some(shouldSuppress))
29633
+ return;
29634
+ prevError(...args);
29635
+ };
29636
+ console.log = suppressed;
29637
+ console.info = suppressed;
29638
+ console.warn = suppressed;
29639
+ console.error = filteredError;
29640
+ process.stdout.write = (chunk, ...rest) => {
29641
+ if (shouldSuppress(chunk))
29642
+ return true;
29643
+ return prevStdoutWrite(chunk, ...rest);
29644
+ };
29645
+ process.stderr.write = (chunk, ...rest) => {
29646
+ if (shouldSuppress(chunk))
29647
+ return true;
29648
+ return prevStderrWrite(chunk, ...rest);
29649
+ };
29650
+ let nativeStderrSaved = null;
29651
+ let nativeLib = null;
29652
+ try {
29653
+ const { dlopen, FFIType } = await import("bun:ffi");
29654
+ nativeLib = dlopen("/usr/lib/libSystem.B.dylib", {
29655
+ dup: { args: [FFIType.i32], returns: FFIType.i32 },
29656
+ dup2: { args: [FFIType.i32, FFIType.i32], returns: FFIType.i32 },
29657
+ open: { args: [FFIType.cstring, FFIType.i32], returns: FFIType.i32 },
29658
+ close: { args: [FFIType.i32], returns: FFIType.i32 }
29659
+ });
29660
+ const nullFd = nativeLib.symbols.open("/dev/null", 1);
29661
+ if (nullFd >= 0) {
29662
+ const saved = nativeLib.symbols.dup(2);
29663
+ if (saved >= 0) {
29664
+ nativeStderrSaved = saved;
29665
+ nativeLib.symbols.dup2(nullFd, 2);
29666
+ }
29667
+ nativeLib.symbols.close(nullFd);
29668
+ }
29669
+ } catch {}
29434
29670
  const renderer = await createCliRenderer({
29435
- exitOnCtrlC: false
29436
- });
29671
+ exitOnCtrlC: false,
29672
+ consoleMode: "disabled"
29673
+ });
29674
+ const restoreConsole = () => {
29675
+ console.log = prevLog;
29676
+ console.info = prevInfo;
29677
+ console.warn = prevWarn;
29678
+ console.error = prevError;
29679
+ process.stdout.write = prevStdoutWrite;
29680
+ process.stderr.write = prevStderrWrite;
29681
+ if (nativeStderrSaved !== null && nativeStderrSaved >= 0 && nativeLib) {
29682
+ try {
29683
+ nativeLib.symbols.dup2(nativeStderrSaved, 2);
29684
+ nativeLib.symbols.close(nativeStderrSaved);
29685
+ } catch {}
29686
+ nativeStderrSaved = null;
29687
+ }
29688
+ setQuiet(false);
29689
+ };
29437
29690
  const root = createRoot(renderer);
29438
29691
  try {
29439
29692
  root.render(/* @__PURE__ */ jsx18(App, {
29440
29693
  opts
29441
29694
  }));
29442
29695
  } catch (err) {
29696
+ restoreConsole();
29443
29697
  renderer.destroy();
29444
29698
  console.error("Failed to render TUI:", err);
29445
29699
  process.exit(1);
29446
29700
  }
29701
+ const originalDestroy = renderer.destroy.bind(renderer);
29702
+ renderer.destroy = () => {
29703
+ restoreConsole();
29704
+ return originalDestroy();
29705
+ };
29447
29706
  }
29448
29707
  var init_tui = __esm(() => {
29708
+ init_env();
29449
29709
  init_App();
29710
+ init_log();
29450
29711
  extend2({ "text-table": TextTableRenderable, "embedded-terminal": EmbeddedTerminalRenderable });
29451
29712
  });
29452
29713
 
@@ -34422,6 +34683,10 @@ function registerTerminalCommand(program2) {
34422
34683
  `);
34423
34684
  process.exit(1);
34424
34685
  }
34686
+ process.env.RUST_LOG ??= "off";
34687
+ process.env.ZIG_LOG ??= "off";
34688
+ process.env.PAGE_LIST_LOG ??= "off";
34689
+ process.env.OPENTUI_LOG ??= "off";
34425
34690
  const { runTerminal: runTerminal2 } = await Promise.resolve().then(() => (init_tui(), exports_tui));
34426
34691
  await runTerminal2(opts);
34427
34692
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ogpoyraz/wtx",
3
- "version": "0.8.9",
3
+ "version": "0.8.10",
4
4
  "description": "Multi-repo git worktree manager",
5
5
  "type": "module",
6
6
  "bin": {