@ogpoyraz/wtx 0.8.8 → 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.
- package/dist/cli.mjs +1541 -419
- 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) {
|
|
@@ -14672,7 +14674,7 @@ function getVersion() {
|
|
|
14672
14674
|
return "0.0.0";
|
|
14673
14675
|
}
|
|
14674
14676
|
}
|
|
14675
|
-
var DepsManagerEnum, DepsStrategyEnum, DepsConfigSchema, AgentConfigSchema, PortsConfigSchema, LEGACY_REPO_KEYS, RepoConfigSchema, ConfigSchema, VERSION;
|
|
14677
|
+
var DepsManagerEnum, DepsStrategyEnum, DepsConfigSchema, AgentConfigSchema, PortsConfigSchema, TuiConfigSchema, LEGACY_REPO_KEYS, RepoConfigSchema, ConfigSchema, VERSION;
|
|
14676
14678
|
var init_types = __esm(() => {
|
|
14677
14679
|
init_v4();
|
|
14678
14680
|
DepsManagerEnum = exports_external.enum(["auto", "npm", "bun", "pnpm", "yarn", "go", "python", "cargo"]);
|
|
@@ -14688,6 +14690,10 @@ var init_types = __esm(() => {
|
|
|
14688
14690
|
min: exports_external.number().int().min(1024).max(65535).default(4100),
|
|
14689
14691
|
max: exports_external.number().int().min(1024).max(65535).default(4999)
|
|
14690
14692
|
}).refine((v) => v.min <= v.max, { message: "ports.min must be less than or equal to ports.max" });
|
|
14693
|
+
TuiConfigSchema = exports_external.object({
|
|
14694
|
+
leftPaneWidthWeight: exports_external.number().int().min(1).max(10).default(3),
|
|
14695
|
+
rightPaneWidthWeight: exports_external.number().int().min(1).max(10).default(7)
|
|
14696
|
+
});
|
|
14691
14697
|
LEGACY_REPO_KEYS = {
|
|
14692
14698
|
pr: "check_prs",
|
|
14693
14699
|
forge: "forge_provider",
|
|
@@ -14730,7 +14736,8 @@ var init_types = __esm(() => {
|
|
|
14730
14736
|
user: exports_external.string().trim().min(1, { message: "must not be empty if provided" }).nullable().default(null),
|
|
14731
14737
|
repos: exports_external.record(exports_external.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/, "Invalid repo key format"), RepoConfigSchema),
|
|
14732
14738
|
agents: exports_external.record(exports_external.string().regex(/^[a-z][a-z0-9_-]*$/, "Agent names must be lowercase alphanumeric with dashes/underscores"), AgentConfigSchema).optional(),
|
|
14733
|
-
ports: PortsConfigSchema.default({ min: 4100, max: 4999 })
|
|
14739
|
+
ports: PortsConfigSchema.default({ min: 4100, max: 4999 }),
|
|
14740
|
+
tui: TuiConfigSchema.default({ leftPaneWidthWeight: 3, rightPaneWidthWeight: 7 })
|
|
14734
14741
|
});
|
|
14735
14742
|
VERSION = getVersion();
|
|
14736
14743
|
});
|
|
@@ -25010,80 +25017,6 @@ var init_owner = __esm(() => {
|
|
|
25010
25017
|
init_git();
|
|
25011
25018
|
});
|
|
25012
25019
|
|
|
25013
|
-
// src/lib/agents.ts
|
|
25014
|
-
function resolveAgentCommand(name, configured) {
|
|
25015
|
-
return configured?.[name]?.command ?? DEFAULT_AGENTS[name] ?? null;
|
|
25016
|
-
}
|
|
25017
|
-
function listAvailableAgents(configured) {
|
|
25018
|
-
return [...new Set([...Object.keys(DEFAULT_AGENTS), ...Object.keys(configured ?? {})])];
|
|
25019
|
-
}
|
|
25020
|
-
async function isTmuxAvailable() {
|
|
25021
|
-
if (tmuxAvailable !== undefined)
|
|
25022
|
-
return tmuxAvailable;
|
|
25023
|
-
try {
|
|
25024
|
-
await execa("tmux", ["-V"]);
|
|
25025
|
-
tmuxAvailable = true;
|
|
25026
|
-
} catch {
|
|
25027
|
-
tmuxAvailable = false;
|
|
25028
|
-
}
|
|
25029
|
-
return tmuxAvailable;
|
|
25030
|
-
}
|
|
25031
|
-
function tmuxSessionName(repoName, branch) {
|
|
25032
|
-
const sanitized = `${repoName}-${branch}`.replace(/[\/.:]/g, "-");
|
|
25033
|
-
return `wtx-${sanitized}`.substring(0, 60);
|
|
25034
|
-
}
|
|
25035
|
-
function buildTmuxArgs(session, wtPath, cmd) {
|
|
25036
|
-
return ["new-session", "-d", "-s", session, "-c", wtPath, cmd];
|
|
25037
|
-
}
|
|
25038
|
-
async function spawnAgentInWorktree(commandTemplate, wtPath, opts = {}) {
|
|
25039
|
-
const cmd = buildAgentCommand(commandTemplate, wtPath, opts.prompt, {
|
|
25040
|
-
branch: opts.branch,
|
|
25041
|
-
repo: opts.repoName
|
|
25042
|
-
});
|
|
25043
|
-
const session = opts.repoName && opts.branch ? tmuxSessionName(opts.repoName, opts.branch) : undefined;
|
|
25044
|
-
if (opts.dryRun) {
|
|
25045
|
-
if (session && await isTmuxAvailable()) {
|
|
25046
|
-
return { mode: "tmux", session };
|
|
25047
|
-
}
|
|
25048
|
-
return { mode: "direct" };
|
|
25049
|
-
}
|
|
25050
|
-
if (session && await isTmuxAvailable()) {
|
|
25051
|
-
try {
|
|
25052
|
-
const args = buildTmuxArgs(session, wtPath, cmd);
|
|
25053
|
-
await execa("tmux", args, { stdio: "inherit" });
|
|
25054
|
-
return { mode: "tmux", session };
|
|
25055
|
-
} catch {}
|
|
25056
|
-
}
|
|
25057
|
-
await execa(cmd, { shell: true, cwd: wtPath, stdio: "inherit" });
|
|
25058
|
-
return { mode: "direct" };
|
|
25059
|
-
}
|
|
25060
|
-
function shellQuote(value) {
|
|
25061
|
-
return `'${value.replaceAll("'", `'''`)}'`;
|
|
25062
|
-
}
|
|
25063
|
-
function buildAgentCommand(commandTemplate, wtPath, prompt, vars) {
|
|
25064
|
-
let cmd = commandTemplate.replaceAll("{wt}", shellQuote(wtPath));
|
|
25065
|
-
if (vars?.branch) {
|
|
25066
|
-
cmd = cmd.replaceAll("{branch}", shellQuote(vars.branch));
|
|
25067
|
-
}
|
|
25068
|
-
if (vars?.repo) {
|
|
25069
|
-
cmd = cmd.replaceAll("{repo}", shellQuote(vars.repo));
|
|
25070
|
-
}
|
|
25071
|
-
if (prompt) {
|
|
25072
|
-
cmd += ` ${shellQuote(prompt)}`;
|
|
25073
|
-
}
|
|
25074
|
-
return cmd;
|
|
25075
|
-
}
|
|
25076
|
-
var DEFAULT_AGENTS, tmuxAvailable = undefined;
|
|
25077
|
-
var init_agents = __esm(() => {
|
|
25078
|
-
init_execa();
|
|
25079
|
-
DEFAULT_AGENTS = {
|
|
25080
|
-
claude: "claude",
|
|
25081
|
-
codex: "codex",
|
|
25082
|
-
opencode: "opencode",
|
|
25083
|
-
cursor: "cursor"
|
|
25084
|
-
};
|
|
25085
|
-
});
|
|
25086
|
-
|
|
25087
25020
|
// src/lib/forge/types.ts
|
|
25088
25021
|
function displayStateRank(state) {
|
|
25089
25022
|
return DISPLAY_PRIORITY.indexOf(state);
|
|
@@ -25169,6 +25102,18 @@ class Semaphore {
|
|
|
25169
25102
|
}
|
|
25170
25103
|
}
|
|
25171
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
|
+
|
|
25172
25117
|
// src/tui/data.ts
|
|
25173
25118
|
async function fetchWorktreeData(opts, scope) {
|
|
25174
25119
|
const warnings = [];
|
|
@@ -25666,6 +25611,39 @@ async function copyTextToClipboard(renderer, text) {
|
|
|
25666
25611
|
}
|
|
25667
25612
|
return viaSystem || viaTerminal;
|
|
25668
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
|
+
}
|
|
25669
25647
|
function browserCommandFor(platform2, url2) {
|
|
25670
25648
|
if (!/^https?:\/\//.test(url2))
|
|
25671
25649
|
return null;
|
|
@@ -25935,28 +25913,407 @@ var init_WorktreeTable = __esm(() => {
|
|
|
25935
25913
|
init_use_tap();
|
|
25936
25914
|
});
|
|
25937
25915
|
|
|
25938
|
-
// src/tui/
|
|
25939
|
-
import { jsx as jsx2, jsxs as jsxs2
|
|
25940
|
-
function
|
|
25916
|
+
// src/tui/tabs/TabBar.tsx
|
|
25917
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "@opentui/react/jsx-runtime";
|
|
25918
|
+
function TabItem({
|
|
25919
|
+
id,
|
|
25920
|
+
label,
|
|
25921
|
+
closable,
|
|
25922
|
+
active,
|
|
25923
|
+
onSelect,
|
|
25924
|
+
onClose
|
|
25925
|
+
}) {
|
|
25926
|
+
const tap = useTapHandler(() => onSelect(id));
|
|
25927
|
+
const closeTap = useTapHandler((e) => {
|
|
25928
|
+
e.stopPropagation();
|
|
25929
|
+
onClose?.(id);
|
|
25930
|
+
});
|
|
25931
|
+
return /* @__PURE__ */ jsxs2("box", {
|
|
25932
|
+
flexDirection: "row",
|
|
25933
|
+
paddingRight: 1,
|
|
25934
|
+
...tap,
|
|
25935
|
+
children: [
|
|
25936
|
+
/* @__PURE__ */ jsx2("text", {
|
|
25937
|
+
fg: active ? tokens.accent : tokens.dim,
|
|
25938
|
+
attributes: active ? 1 : 0,
|
|
25939
|
+
children: label
|
|
25940
|
+
}),
|
|
25941
|
+
closable ? /* @__PURE__ */ jsx2("box", {
|
|
25942
|
+
...closeTap,
|
|
25943
|
+
style: { marginLeft: 1 },
|
|
25944
|
+
children: /* @__PURE__ */ jsx2("text", {
|
|
25945
|
+
fg: active ? tokens.accent : tokens.dim,
|
|
25946
|
+
children: "✕"
|
|
25947
|
+
})
|
|
25948
|
+
}) : null,
|
|
25949
|
+
/* @__PURE__ */ jsx2("text", {
|
|
25950
|
+
children: " "
|
|
25951
|
+
})
|
|
25952
|
+
]
|
|
25953
|
+
});
|
|
25954
|
+
}
|
|
25955
|
+
function TabBar({ tabs, activeId, onSelect, onClose }) {
|
|
25956
|
+
return /* @__PURE__ */ jsx2("box", {
|
|
25957
|
+
flexDirection: "row",
|
|
25958
|
+
width: "100%",
|
|
25959
|
+
alignItems: "center",
|
|
25960
|
+
paddingLeft: 1,
|
|
25961
|
+
children: tabs.map((tab) => /* @__PURE__ */ jsx2(TabItem, {
|
|
25962
|
+
id: tab.id,
|
|
25963
|
+
label: tab.label,
|
|
25964
|
+
closable: tab.closable,
|
|
25965
|
+
active: tab.id === activeId,
|
|
25966
|
+
onSelect,
|
|
25967
|
+
onClose
|
|
25968
|
+
}, tab.id))
|
|
25969
|
+
});
|
|
25970
|
+
}
|
|
25971
|
+
var init_TabBar = __esm(() => {
|
|
25972
|
+
init_theme();
|
|
25973
|
+
init_use_tap();
|
|
25974
|
+
});
|
|
25975
|
+
|
|
25976
|
+
// src/tui/components/TerminalView.tsx
|
|
25977
|
+
import { useState as useState2, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback3 } from "react";
|
|
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";
|
|
26225
|
+
function TabPane({
|
|
26226
|
+
selectedRow,
|
|
26227
|
+
tabs,
|
|
26228
|
+
activeId,
|
|
26229
|
+
focused,
|
|
26230
|
+
canAdd,
|
|
26231
|
+
onSelect,
|
|
26232
|
+
onAdd,
|
|
26233
|
+
onClose,
|
|
26234
|
+
allSessionsFlat,
|
|
26235
|
+
terminalFocused,
|
|
26236
|
+
activeTabId,
|
|
26237
|
+
terminalSessions
|
|
26238
|
+
}) {
|
|
26239
|
+
const borderColor = focused ? tokens.accent : tokens.border;
|
|
26240
|
+
return /* @__PURE__ */ jsxs4("box", {
|
|
26241
|
+
flexDirection: "column",
|
|
26242
|
+
flexGrow: 1,
|
|
26243
|
+
width: "100%",
|
|
26244
|
+
height: "100%",
|
|
26245
|
+
border: true,
|
|
26246
|
+
borderColor,
|
|
26247
|
+
focusedBorderColor: borderColor,
|
|
26248
|
+
focusable: false,
|
|
26249
|
+
id: "detail-pane",
|
|
26250
|
+
children: [
|
|
26251
|
+
/* @__PURE__ */ jsx4(TabBar, {
|
|
26252
|
+
tabs,
|
|
26253
|
+
activeId,
|
|
26254
|
+
canAdd,
|
|
26255
|
+
onSelect,
|
|
26256
|
+
onAdd,
|
|
26257
|
+
onClose
|
|
26258
|
+
}),
|
|
26259
|
+
/* @__PURE__ */ jsxs4("box", {
|
|
26260
|
+
flexGrow: 1,
|
|
26261
|
+
width: "100%",
|
|
26262
|
+
flexDirection: "column",
|
|
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
|
+
]
|
|
26292
|
+
})
|
|
26293
|
+
]
|
|
26294
|
+
});
|
|
26295
|
+
}
|
|
26296
|
+
var init_TabPane = __esm(() => {
|
|
26297
|
+
init_theme();
|
|
26298
|
+
init_TabBar();
|
|
26299
|
+
init_TerminalView();
|
|
26300
|
+
});
|
|
26301
|
+
|
|
26302
|
+
// src/tui/components/DetailsTab.tsx
|
|
26303
|
+
import { jsx as jsx5, jsxs as jsxs5, Fragment } from "@opentui/react/jsx-runtime";
|
|
26304
|
+
function DetailsContent({ selectedRow }) {
|
|
25941
26305
|
const prTap = useTapHandler(() => {
|
|
25942
26306
|
if (selectedRow?.prUrl)
|
|
25943
26307
|
openInBrowser(selectedRow.prUrl);
|
|
25944
26308
|
});
|
|
25945
26309
|
if (!selectedRow) {
|
|
25946
|
-
return /* @__PURE__ */
|
|
25947
|
-
id: "detail-pane",
|
|
26310
|
+
return /* @__PURE__ */ jsx5("box", {
|
|
25948
26311
|
flexGrow: 1,
|
|
25949
26312
|
width: "100%",
|
|
25950
26313
|
height: "100%",
|
|
25951
|
-
border: true,
|
|
25952
|
-
borderColor: tokens.border,
|
|
25953
|
-
focusedBorderColor: tokens.border,
|
|
25954
|
-
focusable: false,
|
|
25955
|
-
title: "Details",
|
|
25956
|
-
padding: 1,
|
|
25957
26314
|
justifyContent: "center",
|
|
25958
26315
|
alignItems: "center",
|
|
25959
|
-
children: /* @__PURE__ */
|
|
26316
|
+
children: /* @__PURE__ */ jsx5("text", {
|
|
25960
26317
|
fg: tokens.dim,
|
|
25961
26318
|
children: "No worktree selected"
|
|
25962
26319
|
})
|
|
@@ -25984,26 +26341,20 @@ function DetailPane({ selectedRow }) {
|
|
|
25984
26341
|
baseChanged
|
|
25985
26342
|
} = selectedRow;
|
|
25986
26343
|
const aheadBehindStr = ahead !== null && behind !== null ? `${ahead} ahead, ${behind} behind` : "unknown";
|
|
25987
|
-
return /* @__PURE__ */
|
|
25988
|
-
id: "detail-pane",
|
|
26344
|
+
return /* @__PURE__ */ jsxs5("scrollbox", {
|
|
25989
26345
|
flexGrow: 1,
|
|
25990
26346
|
width: "100%",
|
|
25991
26347
|
height: "100%",
|
|
25992
|
-
border: true,
|
|
25993
|
-
borderColor: tokens.border,
|
|
25994
|
-
focusedBorderColor: tokens.border,
|
|
25995
|
-
focusable: false,
|
|
25996
|
-
title: "Details",
|
|
25997
|
-
padding: 1,
|
|
25998
26348
|
focused: false,
|
|
26349
|
+
padding: 1,
|
|
25999
26350
|
children: [
|
|
26000
|
-
/* @__PURE__ */
|
|
26351
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26001
26352
|
children: [
|
|
26002
|
-
/* @__PURE__ */
|
|
26353
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26003
26354
|
fg: tokens.dim,
|
|
26004
26355
|
children: "Repo:"
|
|
26005
26356
|
}),
|
|
26006
|
-
/* @__PURE__ */
|
|
26357
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26007
26358
|
fg: tokens.fg,
|
|
26008
26359
|
children: [
|
|
26009
26360
|
" ",
|
|
@@ -26012,13 +26363,13 @@ function DetailPane({ selectedRow }) {
|
|
|
26012
26363
|
})
|
|
26013
26364
|
]
|
|
26014
26365
|
}),
|
|
26015
|
-
/* @__PURE__ */
|
|
26366
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26016
26367
|
children: [
|
|
26017
|
-
/* @__PURE__ */
|
|
26368
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26018
26369
|
fg: tokens.dim,
|
|
26019
26370
|
children: "Branch:"
|
|
26020
26371
|
}),
|
|
26021
|
-
/* @__PURE__ */
|
|
26372
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26022
26373
|
fg: tokens.fg,
|
|
26023
26374
|
children: [
|
|
26024
26375
|
" ",
|
|
@@ -26029,13 +26380,13 @@ function DetailPane({ selectedRow }) {
|
|
|
26029
26380
|
})
|
|
26030
26381
|
]
|
|
26031
26382
|
}),
|
|
26032
|
-
/* @__PURE__ */
|
|
26383
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26033
26384
|
children: [
|
|
26034
|
-
/* @__PURE__ */
|
|
26385
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26035
26386
|
fg: tokens.dim,
|
|
26036
26387
|
children: "Path:"
|
|
26037
26388
|
}),
|
|
26038
|
-
/* @__PURE__ */
|
|
26389
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26039
26390
|
fg: tokens.fg,
|
|
26040
26391
|
children: [
|
|
26041
26392
|
" ",
|
|
@@ -26044,13 +26395,13 @@ function DetailPane({ selectedRow }) {
|
|
|
26044
26395
|
})
|
|
26045
26396
|
]
|
|
26046
26397
|
}),
|
|
26047
|
-
/* @__PURE__ */
|
|
26398
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26048
26399
|
children: [
|
|
26049
|
-
/* @__PURE__ */
|
|
26400
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26050
26401
|
fg: tokens.dim,
|
|
26051
26402
|
children: "Commit:"
|
|
26052
26403
|
}),
|
|
26053
|
-
/* @__PURE__ */
|
|
26404
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26054
26405
|
fg: tokens.fg,
|
|
26055
26406
|
children: [
|
|
26056
26407
|
" ",
|
|
@@ -26059,13 +26410,13 @@ function DetailPane({ selectedRow }) {
|
|
|
26059
26410
|
})
|
|
26060
26411
|
]
|
|
26061
26412
|
}),
|
|
26062
|
-
owner && /* @__PURE__ */
|
|
26413
|
+
owner && /* @__PURE__ */ jsxs5("text", {
|
|
26063
26414
|
children: [
|
|
26064
|
-
/* @__PURE__ */
|
|
26415
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26065
26416
|
fg: tokens.dim,
|
|
26066
26417
|
children: "Owner:"
|
|
26067
26418
|
}),
|
|
26068
|
-
/* @__PURE__ */
|
|
26419
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26069
26420
|
fg: tokens.fg,
|
|
26070
26421
|
children: [
|
|
26071
26422
|
" ",
|
|
@@ -26074,13 +26425,13 @@ function DetailPane({ selectedRow }) {
|
|
|
26074
26425
|
})
|
|
26075
26426
|
]
|
|
26076
26427
|
}),
|
|
26077
|
-
/* @__PURE__ */
|
|
26428
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26078
26429
|
children: [
|
|
26079
|
-
/* @__PURE__ */
|
|
26430
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26080
26431
|
fg: tokens.dim,
|
|
26081
26432
|
children: "Status:"
|
|
26082
26433
|
}),
|
|
26083
|
-
/* @__PURE__ */
|
|
26434
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26084
26435
|
fg: tokens.fg,
|
|
26085
26436
|
children: [
|
|
26086
26437
|
" ",
|
|
@@ -26089,13 +26440,13 @@ function DetailPane({ selectedRow }) {
|
|
|
26089
26440
|
})
|
|
26090
26441
|
]
|
|
26091
26442
|
}),
|
|
26092
|
-
base2 && /* @__PURE__ */
|
|
26443
|
+
base2 && /* @__PURE__ */ jsxs5("text", {
|
|
26093
26444
|
children: [
|
|
26094
|
-
/* @__PURE__ */
|
|
26445
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26095
26446
|
fg: tokens.dim,
|
|
26096
26447
|
children: "Base:"
|
|
26097
26448
|
}),
|
|
26098
|
-
/* @__PURE__ */
|
|
26449
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26099
26450
|
fg: tokens.accent,
|
|
26100
26451
|
children: [
|
|
26101
26452
|
" ",
|
|
@@ -26104,26 +26455,26 @@ function DetailPane({ selectedRow }) {
|
|
|
26104
26455
|
})
|
|
26105
26456
|
]
|
|
26106
26457
|
}),
|
|
26107
|
-
baseChanged && /* @__PURE__ */
|
|
26458
|
+
baseChanged && /* @__PURE__ */ jsxs5("text", {
|
|
26108
26459
|
children: [
|
|
26109
|
-
/* @__PURE__ */
|
|
26460
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26110
26461
|
fg: tokens.dim,
|
|
26111
26462
|
children: "Base state:"
|
|
26112
26463
|
}),
|
|
26113
|
-
/* @__PURE__ */
|
|
26464
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26114
26465
|
fg: tokens.warning,
|
|
26115
26466
|
children: " moved since recorded"
|
|
26116
26467
|
})
|
|
26117
26468
|
]
|
|
26118
26469
|
}),
|
|
26119
|
-
/* @__PURE__ */
|
|
26470
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26120
26471
|
style: { marginTop: 1 },
|
|
26121
26472
|
children: [
|
|
26122
|
-
/* @__PURE__ */
|
|
26473
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26123
26474
|
fg: tokens.dim,
|
|
26124
26475
|
children: base2 ? "vs base:" : "vs main:"
|
|
26125
26476
|
}),
|
|
26126
|
-
/* @__PURE__ */
|
|
26477
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26127
26478
|
fg: tokens.fg,
|
|
26128
26479
|
children: [
|
|
26129
26480
|
" ",
|
|
@@ -26132,13 +26483,13 @@ function DetailPane({ selectedRow }) {
|
|
|
26132
26483
|
})
|
|
26133
26484
|
]
|
|
26134
26485
|
}),
|
|
26135
|
-
/* @__PURE__ */
|
|
26486
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26136
26487
|
children: [
|
|
26137
|
-
/* @__PURE__ */
|
|
26488
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26138
26489
|
fg: tokens.dim,
|
|
26139
26490
|
children: "Deps:"
|
|
26140
26491
|
}),
|
|
26141
|
-
/* @__PURE__ */
|
|
26492
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26142
26493
|
fg: tokens.fg,
|
|
26143
26494
|
children: [
|
|
26144
26495
|
" ",
|
|
@@ -26147,13 +26498,13 @@ function DetailPane({ selectedRow }) {
|
|
|
26147
26498
|
})
|
|
26148
26499
|
]
|
|
26149
26500
|
}),
|
|
26150
|
-
rebaseStatus && /* @__PURE__ */
|
|
26501
|
+
rebaseStatus && /* @__PURE__ */ jsxs5("text", {
|
|
26151
26502
|
children: [
|
|
26152
|
-
/* @__PURE__ */
|
|
26503
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26153
26504
|
fg: tokens.dim,
|
|
26154
26505
|
children: "Rebase:"
|
|
26155
26506
|
}),
|
|
26156
|
-
/* @__PURE__ */
|
|
26507
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26157
26508
|
fg: tokens.error,
|
|
26158
26509
|
children: [
|
|
26159
26510
|
" ",
|
|
@@ -26162,12 +26513,12 @@ function DetailPane({ selectedRow }) {
|
|
|
26162
26513
|
})
|
|
26163
26514
|
]
|
|
26164
26515
|
}),
|
|
26165
|
-
prNumber !== null && /* @__PURE__ */
|
|
26516
|
+
prNumber !== null && /* @__PURE__ */ jsxs5(Fragment, {
|
|
26166
26517
|
children: [
|
|
26167
|
-
/* @__PURE__ */
|
|
26518
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26168
26519
|
style: { marginTop: 1 },
|
|
26169
26520
|
children: [
|
|
26170
|
-
/* @__PURE__ */
|
|
26521
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26171
26522
|
fg: tokens.accent,
|
|
26172
26523
|
children: [
|
|
26173
26524
|
"PR #",
|
|
@@ -26175,7 +26526,7 @@ function DetailPane({ selectedRow }) {
|
|
|
26175
26526
|
":"
|
|
26176
26527
|
]
|
|
26177
26528
|
}),
|
|
26178
|
-
/* @__PURE__ */
|
|
26529
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26179
26530
|
fg: tokens.dim,
|
|
26180
26531
|
children: [
|
|
26181
26532
|
" ",
|
|
@@ -26184,13 +26535,13 @@ function DetailPane({ selectedRow }) {
|
|
|
26184
26535
|
})
|
|
26185
26536
|
]
|
|
26186
26537
|
}),
|
|
26187
|
-
prChecks && /* @__PURE__ */
|
|
26538
|
+
prChecks && /* @__PURE__ */ jsxs5("text", {
|
|
26188
26539
|
children: [
|
|
26189
|
-
/* @__PURE__ */
|
|
26540
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26190
26541
|
fg: tokens.dim,
|
|
26191
26542
|
children: "Checks:"
|
|
26192
26543
|
}),
|
|
26193
|
-
/* @__PURE__ */
|
|
26544
|
+
/* @__PURE__ */ jsxs5("span", {
|
|
26194
26545
|
fg: tokens.fg,
|
|
26195
26546
|
children: [
|
|
26196
26547
|
" ",
|
|
@@ -26199,20 +26550,20 @@ function DetailPane({ selectedRow }) {
|
|
|
26199
26550
|
})
|
|
26200
26551
|
]
|
|
26201
26552
|
}),
|
|
26202
|
-
prUrl && /* @__PURE__ */
|
|
26553
|
+
prUrl && /* @__PURE__ */ jsx5("box", {
|
|
26203
26554
|
...prTap,
|
|
26204
|
-
children: /* @__PURE__ */
|
|
26555
|
+
children: /* @__PURE__ */ jsxs5("text", {
|
|
26205
26556
|
selectable: false,
|
|
26206
26557
|
children: [
|
|
26207
|
-
/* @__PURE__ */
|
|
26558
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26208
26559
|
fg: tokens.dim,
|
|
26209
26560
|
children: "URL:"
|
|
26210
26561
|
}),
|
|
26211
|
-
/* @__PURE__ */
|
|
26562
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26212
26563
|
fg: tokens.accent,
|
|
26213
26564
|
children: ` ${prUrl}`
|
|
26214
26565
|
}),
|
|
26215
|
-
/* @__PURE__ */
|
|
26566
|
+
/* @__PURE__ */ jsx5("span", {
|
|
26216
26567
|
fg: tokens.dim,
|
|
26217
26568
|
children: " ↗ click"
|
|
26218
26569
|
})
|
|
@@ -26221,11 +26572,11 @@ function DetailPane({ selectedRow }) {
|
|
|
26221
26572
|
})
|
|
26222
26573
|
]
|
|
26223
26574
|
}),
|
|
26224
|
-
dirtyFiles.length > 0 && /* @__PURE__ */
|
|
26575
|
+
dirtyFiles.length > 0 && /* @__PURE__ */ jsxs5("box", {
|
|
26225
26576
|
flexDirection: "column",
|
|
26226
26577
|
style: { marginTop: 1 },
|
|
26227
26578
|
children: [
|
|
26228
|
-
/* @__PURE__ */
|
|
26579
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26229
26580
|
fg: tokens.warning,
|
|
26230
26581
|
children: [
|
|
26231
26582
|
"Dirty Files (",
|
|
@@ -26233,14 +26584,14 @@ function DetailPane({ selectedRow }) {
|
|
|
26233
26584
|
"):"
|
|
26234
26585
|
]
|
|
26235
26586
|
}),
|
|
26236
|
-
dirtyFiles.slice(0, 20).map((file2, idx) => /* @__PURE__ */
|
|
26587
|
+
dirtyFiles.slice(0, 20).map((file2, idx) => /* @__PURE__ */ jsxs5("text", {
|
|
26237
26588
|
fg: tokens.warning,
|
|
26238
26589
|
children: [
|
|
26239
26590
|
" ",
|
|
26240
26591
|
file2
|
|
26241
26592
|
]
|
|
26242
26593
|
}, idx)),
|
|
26243
|
-
dirtyFiles.length > 20 && /* @__PURE__ */
|
|
26594
|
+
dirtyFiles.length > 20 && /* @__PURE__ */ jsxs5("text", {
|
|
26244
26595
|
fg: tokens.warning,
|
|
26245
26596
|
children: [
|
|
26246
26597
|
" ...and ",
|
|
@@ -26250,17 +26601,17 @@ function DetailPane({ selectedRow }) {
|
|
|
26250
26601
|
})
|
|
26251
26602
|
]
|
|
26252
26603
|
}),
|
|
26253
|
-
/* @__PURE__ */
|
|
26604
|
+
/* @__PURE__ */ jsxs5("box", {
|
|
26254
26605
|
flexDirection: "column",
|
|
26255
26606
|
style: { marginTop: 1 },
|
|
26256
26607
|
children: [
|
|
26257
|
-
/* @__PURE__ */
|
|
26608
|
+
/* @__PURE__ */ jsx5("text", {
|
|
26258
26609
|
fg: tokens.dim,
|
|
26259
26610
|
children: "Actions:"
|
|
26260
26611
|
}),
|
|
26261
|
-
!isMainCheckout && /* @__PURE__ */
|
|
26612
|
+
!isMainCheckout && /* @__PURE__ */ jsxs5(Fragment, {
|
|
26262
26613
|
children: [
|
|
26263
|
-
/* @__PURE__ */
|
|
26614
|
+
/* @__PURE__ */ jsxs5("text", {
|
|
26264
26615
|
fg: tokens.dim,
|
|
26265
26616
|
children: [
|
|
26266
26617
|
" i install deps (",
|
|
@@ -26268,44 +26619,48 @@ function DetailPane({ selectedRow }) {
|
|
|
26268
26619
|
")"
|
|
26269
26620
|
]
|
|
26270
26621
|
}),
|
|
26271
|
-
/* @__PURE__ */
|
|
26622
|
+
/* @__PURE__ */ jsx5("text", {
|
|
26272
26623
|
fg: tokens.dim,
|
|
26273
26624
|
children: " m rename worktree"
|
|
26274
26625
|
})
|
|
26275
26626
|
]
|
|
26276
26627
|
}),
|
|
26277
|
-
/* @__PURE__ */
|
|
26628
|
+
/* @__PURE__ */ jsx5("text", {
|
|
26278
26629
|
fg: tokens.dim,
|
|
26279
26630
|
children: " p pull branch"
|
|
26280
26631
|
}),
|
|
26281
|
-
/* @__PURE__ */
|
|
26632
|
+
/* @__PURE__ */ jsx5("text", {
|
|
26282
26633
|
fg: tokens.dim,
|
|
26283
26634
|
children: " b rebase · s sync · o open in IDE · d remove"
|
|
26635
|
+
}),
|
|
26636
|
+
/* @__PURE__ */ jsx5("text", {
|
|
26637
|
+
fg: tokens.dim,
|
|
26638
|
+
children: " t new terminal session (max 5)"
|
|
26284
26639
|
})
|
|
26285
26640
|
]
|
|
26286
26641
|
})
|
|
26287
26642
|
]
|
|
26288
26643
|
});
|
|
26289
26644
|
}
|
|
26290
|
-
var
|
|
26645
|
+
var init_DetailsTab = __esm(() => {
|
|
26291
26646
|
init_theme();
|
|
26292
26647
|
init_use_tap();
|
|
26293
26648
|
});
|
|
26294
26649
|
|
|
26295
26650
|
// src/tui/components/Footer.tsx
|
|
26296
|
-
import { jsx as
|
|
26651
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "@opentui/react/jsx-runtime";
|
|
26297
26652
|
function HintItem({ hintKey, label, isFirst, onClick }) {
|
|
26298
26653
|
const tap = useTapHandler(() => onClick?.(hintKey));
|
|
26299
|
-
return /* @__PURE__ */
|
|
26654
|
+
return /* @__PURE__ */ jsx6("box", {
|
|
26300
26655
|
flexDirection: "row",
|
|
26301
26656
|
...onClick ? tap : {},
|
|
26302
|
-
children: /* @__PURE__ */
|
|
26657
|
+
children: /* @__PURE__ */ jsxs6("text", {
|
|
26303
26658
|
children: [
|
|
26304
|
-
/* @__PURE__ */
|
|
26659
|
+
/* @__PURE__ */ jsx6("span", {
|
|
26305
26660
|
fg: tokens.dim,
|
|
26306
26661
|
children: isFirst ? "" : " · "
|
|
26307
26662
|
}),
|
|
26308
|
-
/* @__PURE__ */
|
|
26663
|
+
/* @__PURE__ */ jsx6("span", {
|
|
26309
26664
|
fg: tokens.dim,
|
|
26310
26665
|
children: `${hintKey} ${label}`
|
|
26311
26666
|
})
|
|
@@ -26315,15 +26670,15 @@ function HintItem({ hintKey, label, isFirst, onClick }) {
|
|
|
26315
26670
|
}
|
|
26316
26671
|
function ErrorBadge({ count: count2, onClick }) {
|
|
26317
26672
|
const tap = useTapHandler(() => onClick?.());
|
|
26318
|
-
return /* @__PURE__ */
|
|
26673
|
+
return /* @__PURE__ */ jsx6("box", {
|
|
26319
26674
|
...onClick ? tap : {},
|
|
26320
|
-
children: /* @__PURE__ */
|
|
26675
|
+
children: /* @__PURE__ */ jsxs6("text", {
|
|
26321
26676
|
children: [
|
|
26322
|
-
/* @__PURE__ */
|
|
26677
|
+
/* @__PURE__ */ jsx6("span", {
|
|
26323
26678
|
fg: tokens.error,
|
|
26324
26679
|
children: `${count2} error${count2 !== 1 ? "s" : ""}`
|
|
26325
26680
|
}),
|
|
26326
|
-
/* @__PURE__ */
|
|
26681
|
+
/* @__PURE__ */ jsx6("span", {
|
|
26327
26682
|
fg: tokens.dim,
|
|
26328
26683
|
children: " · e view"
|
|
26329
26684
|
})
|
|
@@ -26333,7 +26688,7 @@ function ErrorBadge({ count: count2, onClick }) {
|
|
|
26333
26688
|
}
|
|
26334
26689
|
function Footer({ loading, lastRefreshed, errorCount, message, busyText, spinnerFrame, filter, onHintClick, onErrorClick }) {
|
|
26335
26690
|
const frame = spinnerFrame ?? "◌";
|
|
26336
|
-
return /* @__PURE__ */
|
|
26691
|
+
return /* @__PURE__ */ jsxs6("box", {
|
|
26337
26692
|
id: "footer",
|
|
26338
26693
|
width: "100%",
|
|
26339
26694
|
height: 3,
|
|
@@ -26344,29 +26699,29 @@ function Footer({ loading, lastRefreshed, errorCount, message, busyText, spinner
|
|
|
26344
26699
|
justifyContent: "space-between",
|
|
26345
26700
|
alignItems: "center",
|
|
26346
26701
|
children: [
|
|
26347
|
-
busyText ? /* @__PURE__ */
|
|
26702
|
+
busyText ? /* @__PURE__ */ jsx6("text", {
|
|
26348
26703
|
fg: tokens.accent,
|
|
26349
26704
|
children: `${frame} ${busyText}`
|
|
26350
|
-
}) : /* @__PURE__ */
|
|
26705
|
+
}) : /* @__PURE__ */ jsx6("box", {
|
|
26351
26706
|
flexDirection: "row",
|
|
26352
26707
|
gap: 1,
|
|
26353
|
-
children: HINTS.map(([key, label], idx) => /* @__PURE__ */
|
|
26708
|
+
children: HINTS.map(([key, label], idx) => /* @__PURE__ */ jsx6(HintItem, {
|
|
26354
26709
|
hintKey: key,
|
|
26355
26710
|
label,
|
|
26356
26711
|
isFirst: idx === 0,
|
|
26357
26712
|
onClick: onHintClick
|
|
26358
26713
|
}, key))
|
|
26359
26714
|
}),
|
|
26360
|
-
/* @__PURE__ */
|
|
26715
|
+
/* @__PURE__ */ jsxs6("box", {
|
|
26361
26716
|
flexDirection: "row",
|
|
26362
26717
|
gap: 2,
|
|
26363
26718
|
alignItems: "center",
|
|
26364
26719
|
children: [
|
|
26365
|
-
message ? /* @__PURE__ */
|
|
26720
|
+
message ? /* @__PURE__ */ jsx6("text", {
|
|
26366
26721
|
fg: tokens.warning,
|
|
26367
26722
|
children: message
|
|
26368
26723
|
}) : null,
|
|
26369
|
-
filter ? /* @__PURE__ */
|
|
26724
|
+
filter ? /* @__PURE__ */ jsxs6("text", {
|
|
26370
26725
|
fg: "magenta",
|
|
26371
26726
|
children: [
|
|
26372
26727
|
"filter: ",
|
|
@@ -26378,17 +26733,17 @@ function Footer({ loading, lastRefreshed, errorCount, message, busyText, spinner
|
|
|
26378
26733
|
")"
|
|
26379
26734
|
]
|
|
26380
26735
|
}) : null,
|
|
26381
|
-
errorCount > 0 ? /* @__PURE__ */
|
|
26736
|
+
errorCount > 0 ? /* @__PURE__ */ jsx6(ErrorBadge, {
|
|
26382
26737
|
count: errorCount,
|
|
26383
26738
|
onClick: onErrorClick
|
|
26384
26739
|
}) : null,
|
|
26385
|
-
/* @__PURE__ */
|
|
26740
|
+
/* @__PURE__ */ jsx6(HintItem, {
|
|
26386
26741
|
hintKey: "?",
|
|
26387
26742
|
label: "help",
|
|
26388
26743
|
isFirst: errorCount === 0,
|
|
26389
26744
|
onClick: onHintClick
|
|
26390
26745
|
}),
|
|
26391
|
-
/* @__PURE__ */
|
|
26746
|
+
/* @__PURE__ */ jsx6("text", {
|
|
26392
26747
|
fg: tokens.dim,
|
|
26393
26748
|
children: loading ? `${frame} Refreshing…` : `Updated ${lastRefreshed}`
|
|
26394
26749
|
})
|
|
@@ -26408,16 +26763,16 @@ var init_Footer = __esm(() => {
|
|
|
26408
26763
|
});
|
|
26409
26764
|
|
|
26410
26765
|
// src/tui/components/Divider.tsx
|
|
26411
|
-
import { useState as
|
|
26766
|
+
import { useState as useState3, useRef as useRef5, useCallback as useCallback4 } from "react";
|
|
26412
26767
|
import { useRenderer } from "@opentui/react";
|
|
26413
|
-
import { jsx as
|
|
26768
|
+
import { jsx as jsx7 } from "@opentui/react/jsx-runtime";
|
|
26414
26769
|
function Divider({ splitRatio, totalWidth, onChange, onDraggingChange }) {
|
|
26415
26770
|
const renderer = useRenderer();
|
|
26416
|
-
const [hovered, setHovered] =
|
|
26417
|
-
const [dragging, setDragging] =
|
|
26418
|
-
const startXRef =
|
|
26419
|
-
const startRatioRef =
|
|
26420
|
-
const handleMouseDown =
|
|
26771
|
+
const [hovered, setHovered] = useState3(false);
|
|
26772
|
+
const [dragging, setDragging] = useState3(false);
|
|
26773
|
+
const startXRef = useRef5(null);
|
|
26774
|
+
const startRatioRef = useRef5(splitRatio);
|
|
26775
|
+
const handleMouseDown = useCallback4((e) => {
|
|
26421
26776
|
if (e.button !== 0)
|
|
26422
26777
|
return;
|
|
26423
26778
|
startXRef.current = e.x;
|
|
@@ -26427,7 +26782,7 @@ function Divider({ splitRatio, totalWidth, onChange, onDraggingChange }) {
|
|
|
26427
26782
|
renderer.clearSelection();
|
|
26428
26783
|
e.stopPropagation();
|
|
26429
26784
|
}, [splitRatio, onDraggingChange, renderer]);
|
|
26430
|
-
const handleMouseUp =
|
|
26785
|
+
const handleMouseUp = useCallback4((e) => {
|
|
26431
26786
|
if (e.button !== 0)
|
|
26432
26787
|
return;
|
|
26433
26788
|
startXRef.current = null;
|
|
@@ -26435,7 +26790,7 @@ function Divider({ splitRatio, totalWidth, onChange, onDraggingChange }) {
|
|
|
26435
26790
|
onDraggingChange?.(false);
|
|
26436
26791
|
e.stopPropagation();
|
|
26437
26792
|
}, [onDraggingChange]);
|
|
26438
|
-
const handleMouseDrag =
|
|
26793
|
+
const handleMouseDrag = useCallback4((e) => {
|
|
26439
26794
|
if (startXRef.current === null)
|
|
26440
26795
|
return;
|
|
26441
26796
|
renderer.clearSelection();
|
|
@@ -26450,7 +26805,7 @@ function Divider({ splitRatio, totalWidth, onChange, onDraggingChange }) {
|
|
|
26450
26805
|
onMouseDrag: handleMouseDrag,
|
|
26451
26806
|
onMouseMove: handleMouseDrag
|
|
26452
26807
|
};
|
|
26453
|
-
return /* @__PURE__ */
|
|
26808
|
+
return /* @__PURE__ */ jsx7("box", {
|
|
26454
26809
|
width: 3,
|
|
26455
26810
|
height: "100%",
|
|
26456
26811
|
backgroundColor: dragging ? tokens.selectionBg : hovered ? tokens.panelBg : undefined,
|
|
@@ -26459,7 +26814,7 @@ function Divider({ splitRatio, totalWidth, onChange, onDraggingChange }) {
|
|
|
26459
26814
|
onMouseOut: () => setHovered(false),
|
|
26460
26815
|
alignItems: "center",
|
|
26461
26816
|
justifyContent: "center",
|
|
26462
|
-
children: /* @__PURE__ */
|
|
26817
|
+
children: /* @__PURE__ */ jsx7("text", {
|
|
26463
26818
|
fg: dragging ? tokens.accent : hovered ? tokens.borderActive : tokens.border,
|
|
26464
26819
|
...dragHandlers,
|
|
26465
26820
|
onMouseOver: () => setHovered(true),
|
|
@@ -26474,9 +26829,9 @@ var init_Divider = __esm(() => {
|
|
|
26474
26829
|
});
|
|
26475
26830
|
|
|
26476
26831
|
// src/tui/components/Overlay.tsx
|
|
26477
|
-
import { jsx as
|
|
26832
|
+
import { jsx as jsx8 } from "@opentui/react/jsx-runtime";
|
|
26478
26833
|
function Overlay({ title, borderColor = tokens.border, width = 64, children }) {
|
|
26479
|
-
return /* @__PURE__ */
|
|
26834
|
+
return /* @__PURE__ */ jsx8("box", {
|
|
26480
26835
|
id: "overlay-scrim",
|
|
26481
26836
|
position: "absolute",
|
|
26482
26837
|
width: "100%",
|
|
@@ -26488,7 +26843,7 @@ function Overlay({ title, borderColor = tokens.border, width = 64, children }) {
|
|
|
26488
26843
|
flexDirection: "row",
|
|
26489
26844
|
justifyContent: "center",
|
|
26490
26845
|
alignItems: "center",
|
|
26491
|
-
children: /* @__PURE__ */
|
|
26846
|
+
children: /* @__PURE__ */ jsx8("box", {
|
|
26492
26847
|
id: "overlay-panel",
|
|
26493
26848
|
width,
|
|
26494
26849
|
border: true,
|
|
@@ -26508,37 +26863,38 @@ var init_Overlay = __esm(() => {
|
|
|
26508
26863
|
});
|
|
26509
26864
|
|
|
26510
26865
|
// src/tui/components/HelpOverlay.tsx
|
|
26511
|
-
import { jsx as
|
|
26866
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "@opentui/react/jsx-runtime";
|
|
26512
26867
|
function HelpOverlay() {
|
|
26513
|
-
return /* @__PURE__ */
|
|
26868
|
+
return /* @__PURE__ */ jsxs7(Overlay, {
|
|
26514
26869
|
title: "Help",
|
|
26515
26870
|
borderColor: tokens.border,
|
|
26516
26871
|
width: 84,
|
|
26517
26872
|
children: [
|
|
26518
|
-
/* @__PURE__ */
|
|
26873
|
+
/* @__PURE__ */ jsx9("box", {
|
|
26519
26874
|
flexDirection: "column",
|
|
26520
26875
|
style: { maxHeight: 36 },
|
|
26521
|
-
children: /* @__PURE__ */
|
|
26876
|
+
children: /* @__PURE__ */ jsx9("scrollbox", {
|
|
26522
26877
|
flexGrow: 1,
|
|
26523
|
-
children: HELP_ENTRIES.map(([key, desc]) => /* @__PURE__ */
|
|
26878
|
+
children: HELP_ENTRIES.map(([key, desc]) => /* @__PURE__ */ jsxs7("box", {
|
|
26524
26879
|
flexDirection: "row",
|
|
26525
26880
|
gap: 1,
|
|
26526
26881
|
children: [
|
|
26527
|
-
/* @__PURE__ */
|
|
26882
|
+
/* @__PURE__ */ jsx9("box", {
|
|
26528
26883
|
width: 18,
|
|
26529
26884
|
flexShrink: 0,
|
|
26530
|
-
|
|
26885
|
+
justifyContent: "flex-end",
|
|
26886
|
+
children: /* @__PURE__ */ jsx9("text", {
|
|
26531
26887
|
fg: tokens.accent,
|
|
26532
26888
|
children: key
|
|
26533
26889
|
})
|
|
26534
26890
|
}),
|
|
26535
|
-
/* @__PURE__ */
|
|
26891
|
+
/* @__PURE__ */ jsx9("text", {
|
|
26536
26892
|
fg: tokens.dim,
|
|
26537
26893
|
children: "-"
|
|
26538
26894
|
}),
|
|
26539
|
-
/* @__PURE__ */
|
|
26895
|
+
/* @__PURE__ */ jsx9("box", {
|
|
26540
26896
|
flexGrow: 1,
|
|
26541
|
-
children: /* @__PURE__ */
|
|
26897
|
+
children: /* @__PURE__ */ jsx9("text", {
|
|
26542
26898
|
fg: tokens.fg,
|
|
26543
26899
|
children: desc
|
|
26544
26900
|
})
|
|
@@ -26547,7 +26903,7 @@ function HelpOverlay() {
|
|
|
26547
26903
|
}, key))
|
|
26548
26904
|
})
|
|
26549
26905
|
}),
|
|
26550
|
-
/* @__PURE__ */
|
|
26906
|
+
/* @__PURE__ */ jsx9("text", {
|
|
26551
26907
|
style: { marginTop: 1, fg: tokens.dim },
|
|
26552
26908
|
children: "Press any key to close"
|
|
26553
26909
|
})
|
|
@@ -26572,7 +26928,9 @@ var init_HelpOverlay = __esm(() => {
|
|
|
26572
26928
|
["i", "Install dependencies in selection (worktrees and main)"],
|
|
26573
26929
|
["m", "Rename selected worktree (branch + directory)"],
|
|
26574
26930
|
["o", "Open selected in IDE"],
|
|
26575
|
-
["
|
|
26931
|
+
["t", "New terminal session (max 5 per worktree, Details ↔ Session tabs)"],
|
|
26932
|
+
["click tab", "Switch Details ↔ Session (professional tabs with ▎ active)"],
|
|
26933
|
+
["Ctrl+G / click table", "Leave terminal focus — focused terminal gets all keys"],
|
|
26576
26934
|
["d", "Remove selected worktree(s)"],
|
|
26577
26935
|
["e", "View data warnings (when count > 0)"],
|
|
26578
26936
|
["r", "Refresh data"],
|
|
@@ -26586,50 +26944,50 @@ var init_HelpOverlay = __esm(() => {
|
|
|
26586
26944
|
});
|
|
26587
26945
|
|
|
26588
26946
|
// src/tui/components/ConfirmModal.tsx
|
|
26589
|
-
import { jsx as
|
|
26947
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "@opentui/react/jsx-runtime";
|
|
26590
26948
|
function ConfirmModal({ title, message, onConfirm, onCancel }) {
|
|
26591
26949
|
const yesTap = useTapHandler(() => onConfirm?.());
|
|
26592
26950
|
const noTap = useTapHandler(() => onCancel?.());
|
|
26593
|
-
return /* @__PURE__ */
|
|
26951
|
+
return /* @__PURE__ */ jsx10(Overlay, {
|
|
26594
26952
|
title,
|
|
26595
26953
|
borderColor: tokens.warning,
|
|
26596
|
-
children: /* @__PURE__ */
|
|
26954
|
+
children: /* @__PURE__ */ jsxs8("box", {
|
|
26597
26955
|
flexDirection: "column",
|
|
26598
26956
|
justifyContent: "center",
|
|
26599
26957
|
alignItems: "center",
|
|
26600
26958
|
children: [
|
|
26601
|
-
/* @__PURE__ */
|
|
26959
|
+
/* @__PURE__ */ jsx10("text", {
|
|
26602
26960
|
children: message
|
|
26603
26961
|
}),
|
|
26604
|
-
/* @__PURE__ */
|
|
26962
|
+
/* @__PURE__ */ jsxs8("box", {
|
|
26605
26963
|
flexDirection: "row",
|
|
26606
26964
|
gap: 2,
|
|
26607
26965
|
style: { marginTop: 2 },
|
|
26608
26966
|
children: [
|
|
26609
|
-
/* @__PURE__ */
|
|
26967
|
+
/* @__PURE__ */ jsx10("box", {
|
|
26610
26968
|
...onConfirm ? yesTap : {},
|
|
26611
|
-
children: /* @__PURE__ */
|
|
26969
|
+
children: /* @__PURE__ */ jsxs8("text", {
|
|
26612
26970
|
children: [
|
|
26613
|
-
/* @__PURE__ */
|
|
26971
|
+
/* @__PURE__ */ jsx10("span", {
|
|
26614
26972
|
fg: tokens.dim,
|
|
26615
26973
|
children: "[y] "
|
|
26616
26974
|
}),
|
|
26617
|
-
/* @__PURE__ */
|
|
26975
|
+
/* @__PURE__ */ jsx10("span", {
|
|
26618
26976
|
fg: tokens.success,
|
|
26619
26977
|
children: "Yes"
|
|
26620
26978
|
})
|
|
26621
26979
|
]
|
|
26622
26980
|
})
|
|
26623
26981
|
}),
|
|
26624
|
-
/* @__PURE__ */
|
|
26982
|
+
/* @__PURE__ */ jsx10("box", {
|
|
26625
26983
|
...onCancel ? noTap : {},
|
|
26626
|
-
children: /* @__PURE__ */
|
|
26984
|
+
children: /* @__PURE__ */ jsxs8("text", {
|
|
26627
26985
|
children: [
|
|
26628
|
-
/* @__PURE__ */
|
|
26986
|
+
/* @__PURE__ */ jsx10("span", {
|
|
26629
26987
|
fg: tokens.dim,
|
|
26630
26988
|
children: "[n/esc] "
|
|
26631
26989
|
}),
|
|
26632
|
-
/* @__PURE__ */
|
|
26990
|
+
/* @__PURE__ */ jsx10("span", {
|
|
26633
26991
|
children: "Cancel"
|
|
26634
26992
|
})
|
|
26635
26993
|
]
|
|
@@ -26705,52 +27063,52 @@ async function runWtxAction(args, onLine) {
|
|
|
26705
27063
|
}
|
|
26706
27064
|
|
|
26707
27065
|
// src/tui/components/ActionLogModal.tsx
|
|
26708
|
-
import { jsx as
|
|
27066
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "@opentui/react/jsx-runtime";
|
|
26709
27067
|
function ActionLogModal({ title, lines, done, exitCode, remaining }) {
|
|
26710
|
-
return /* @__PURE__ */
|
|
27068
|
+
return /* @__PURE__ */ jsxs9(Overlay, {
|
|
26711
27069
|
title,
|
|
26712
27070
|
borderColor: tokens.border,
|
|
26713
27071
|
children: [
|
|
26714
|
-
/* @__PURE__ */
|
|
27072
|
+
/* @__PURE__ */ jsx11("box", {
|
|
26715
27073
|
flexGrow: 1,
|
|
26716
27074
|
flexDirection: "column",
|
|
26717
27075
|
style: { minHeight: 10, maxHeight: 20 },
|
|
26718
|
-
children: /* @__PURE__ */
|
|
27076
|
+
children: /* @__PURE__ */ jsx11("scrollbox", {
|
|
26719
27077
|
flexGrow: 1,
|
|
26720
27078
|
stickyScroll: true,
|
|
26721
|
-
children: lines.map((line, i2) => /* @__PURE__ */
|
|
27079
|
+
children: lines.map((line, i2) => /* @__PURE__ */ jsx11("text", {
|
|
26722
27080
|
fg: line.type === "err" ? tokens.error : tokens.fg,
|
|
26723
27081
|
children: line.text
|
|
26724
27082
|
}, i2))
|
|
26725
27083
|
})
|
|
26726
27084
|
}),
|
|
26727
|
-
/* @__PURE__ */
|
|
27085
|
+
/* @__PURE__ */ jsxs9("box", {
|
|
26728
27086
|
marginTop: 1,
|
|
26729
27087
|
flexDirection: "row",
|
|
26730
27088
|
justifyContent: "center",
|
|
26731
27089
|
children: [
|
|
26732
|
-
!done && /* @__PURE__ */
|
|
27090
|
+
!done && /* @__PURE__ */ jsx11("text", {
|
|
26733
27091
|
fg: tokens.warning,
|
|
26734
27092
|
children: "Running..."
|
|
26735
27093
|
}),
|
|
26736
|
-
done && exitCode === 0 && /* @__PURE__ */
|
|
27094
|
+
done && exitCode === 0 && /* @__PURE__ */ jsx11("text", {
|
|
26737
27095
|
fg: tokens.success,
|
|
26738
27096
|
children: "✓ Done (exit 0)"
|
|
26739
27097
|
}),
|
|
26740
|
-
done && exitCode !== 0 && /* @__PURE__ */
|
|
27098
|
+
done && exitCode !== 0 && /* @__PURE__ */ jsxs9("text", {
|
|
26741
27099
|
children: [
|
|
26742
|
-
/* @__PURE__ */
|
|
27100
|
+
/* @__PURE__ */ jsxs9("span", {
|
|
26743
27101
|
fg: tokens.error,
|
|
26744
27102
|
children: [
|
|
26745
27103
|
"✗ Exit ",
|
|
26746
27104
|
exitCode
|
|
26747
27105
|
]
|
|
26748
27106
|
}),
|
|
26749
|
-
remaining !== undefined && remaining > 0 && /* @__PURE__ */
|
|
27107
|
+
remaining !== undefined && remaining > 0 && /* @__PURE__ */ jsx11("span", {
|
|
26750
27108
|
fg: tokens.warning,
|
|
26751
27109
|
children: ` · ${remaining} more failure${remaining > 1 ? "s" : ""}`
|
|
26752
27110
|
}),
|
|
26753
|
-
/* @__PURE__ */
|
|
27111
|
+
/* @__PURE__ */ jsx11("span", {
|
|
26754
27112
|
fg: tokens.dim,
|
|
26755
27113
|
children: " - press any key to close"
|
|
26756
27114
|
})
|
|
@@ -26837,8 +27195,8 @@ var init_history = __esm(() => {
|
|
|
26837
27195
|
});
|
|
26838
27196
|
|
|
26839
27197
|
// src/tui/components/HistoryOverlay.tsx
|
|
26840
|
-
import { useEffect as
|
|
26841
|
-
import { jsx as
|
|
27198
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
27199
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "@opentui/react/jsx-runtime";
|
|
26842
27200
|
function formatShortTime(iso) {
|
|
26843
27201
|
const d = new Date(iso);
|
|
26844
27202
|
if (Number.isNaN(d.getTime()))
|
|
@@ -26851,16 +27209,16 @@ function HistoryEntryLine({ entry }) {
|
|
|
26851
27209
|
const duration3 = entry.durationMs !== null && entry.durationMs !== undefined ? ` ${entry.durationMs}ms` : "";
|
|
26852
27210
|
const prefix = `${formatShortTime(entry.ts)} ${entry.source.padEnd(8)} ${args}`;
|
|
26853
27211
|
if (entry.exit === null || entry.exit === undefined) {
|
|
26854
|
-
return /* @__PURE__ */
|
|
27212
|
+
return /* @__PURE__ */ jsxs10("text", {
|
|
26855
27213
|
children: [
|
|
26856
|
-
/* @__PURE__ */
|
|
27214
|
+
/* @__PURE__ */ jsxs10("span", {
|
|
26857
27215
|
fg: tokens.dim,
|
|
26858
27216
|
children: [
|
|
26859
27217
|
"◌ ",
|
|
26860
27218
|
prefix
|
|
26861
27219
|
]
|
|
26862
27220
|
}),
|
|
26863
|
-
duration3 && /* @__PURE__ */
|
|
27221
|
+
duration3 && /* @__PURE__ */ jsx12("span", {
|
|
26864
27222
|
fg: tokens.dim,
|
|
26865
27223
|
children: duration3
|
|
26866
27224
|
})
|
|
@@ -26868,32 +27226,32 @@ function HistoryEntryLine({ entry }) {
|
|
|
26868
27226
|
});
|
|
26869
27227
|
}
|
|
26870
27228
|
if (entry.exit === 0) {
|
|
26871
|
-
return /* @__PURE__ */
|
|
27229
|
+
return /* @__PURE__ */ jsxs10("text", {
|
|
26872
27230
|
children: [
|
|
26873
|
-
/* @__PURE__ */
|
|
27231
|
+
/* @__PURE__ */ jsxs10("span", {
|
|
26874
27232
|
fg: tokens.success,
|
|
26875
27233
|
children: [
|
|
26876
27234
|
"✓ ",
|
|
26877
27235
|
prefix
|
|
26878
27236
|
]
|
|
26879
27237
|
}),
|
|
26880
|
-
duration3 && /* @__PURE__ */
|
|
27238
|
+
duration3 && /* @__PURE__ */ jsx12("span", {
|
|
26881
27239
|
fg: tokens.dim,
|
|
26882
27240
|
children: duration3
|
|
26883
27241
|
})
|
|
26884
27242
|
]
|
|
26885
27243
|
});
|
|
26886
27244
|
}
|
|
26887
|
-
return /* @__PURE__ */
|
|
27245
|
+
return /* @__PURE__ */ jsxs10("text", {
|
|
26888
27246
|
children: [
|
|
26889
|
-
/* @__PURE__ */
|
|
27247
|
+
/* @__PURE__ */ jsx12("span", {
|
|
26890
27248
|
fg: tokens.error,
|
|
26891
27249
|
children: "✗ "
|
|
26892
27250
|
}),
|
|
26893
|
-
/* @__PURE__ */
|
|
27251
|
+
/* @__PURE__ */ jsx12("span", {
|
|
26894
27252
|
children: prefix
|
|
26895
27253
|
}),
|
|
26896
|
-
/* @__PURE__ */
|
|
27254
|
+
/* @__PURE__ */ jsxs10("span", {
|
|
26897
27255
|
fg: tokens.dim,
|
|
26898
27256
|
children: [
|
|
26899
27257
|
" (exit ",
|
|
@@ -26906,32 +27264,32 @@ function HistoryEntryLine({ entry }) {
|
|
|
26906
27264
|
});
|
|
26907
27265
|
}
|
|
26908
27266
|
function HistoryOverlay() {
|
|
26909
|
-
const [entries, setEntries] =
|
|
26910
|
-
|
|
27267
|
+
const [entries, setEntries] = useState4([]);
|
|
27268
|
+
useEffect4(() => {
|
|
26911
27269
|
setEntries(readRecentHistory(500));
|
|
26912
27270
|
}, []);
|
|
26913
|
-
return /* @__PURE__ */
|
|
27271
|
+
return /* @__PURE__ */ jsxs10(Overlay, {
|
|
26914
27272
|
title: "Action History",
|
|
26915
27273
|
borderColor: tokens.border,
|
|
26916
27274
|
width: 110,
|
|
26917
27275
|
children: [
|
|
26918
|
-
/* @__PURE__ */
|
|
27276
|
+
/* @__PURE__ */ jsx12("box", {
|
|
26919
27277
|
flexGrow: 1,
|
|
26920
27278
|
flexDirection: "column",
|
|
26921
27279
|
style: { minHeight: 30, maxHeight: 46 },
|
|
26922
|
-
children: entries.length === 0 ? /* @__PURE__ */
|
|
27280
|
+
children: entries.length === 0 ? /* @__PURE__ */ jsx12("text", {
|
|
26923
27281
|
fg: tokens.dim,
|
|
26924
27282
|
children: "No actions recorded yet."
|
|
26925
|
-
}) : /* @__PURE__ */
|
|
27283
|
+
}) : /* @__PURE__ */ jsx12("scrollbox", {
|
|
26926
27284
|
flexGrow: 1,
|
|
26927
|
-
children: entries.map((entry, i2) => /* @__PURE__ */
|
|
27285
|
+
children: entries.map((entry, i2) => /* @__PURE__ */ jsx12(HistoryEntryLine, {
|
|
26928
27286
|
entry
|
|
26929
27287
|
}, i2))
|
|
26930
27288
|
})
|
|
26931
27289
|
}),
|
|
26932
|
-
/* @__PURE__ */
|
|
27290
|
+
/* @__PURE__ */ jsx12("box", {
|
|
26933
27291
|
marginTop: 1,
|
|
26934
|
-
children: /* @__PURE__ */
|
|
27292
|
+
children: /* @__PURE__ */ jsx12("text", {
|
|
26935
27293
|
fg: tokens.dim,
|
|
26936
27294
|
children: "Press any key to close · newest first"
|
|
26937
27295
|
})
|
|
@@ -26946,28 +27304,28 @@ var init_HistoryOverlay = __esm(() => {
|
|
|
26946
27304
|
});
|
|
26947
27305
|
|
|
26948
27306
|
// src/tui/components/InputModal.tsx
|
|
26949
|
-
import { useState as
|
|
26950
|
-
import { jsx as
|
|
27307
|
+
import { useState as useState5 } from "react";
|
|
27308
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "@opentui/react/jsx-runtime";
|
|
26951
27309
|
function InputModal({ title, placeholder, initialValue, errorMessage: errorMessage2, onSubmit }) {
|
|
26952
|
-
const [value, setValue] =
|
|
26953
|
-
return /* @__PURE__ */
|
|
27310
|
+
const [value, setValue] = useState5(initialValue ?? "");
|
|
27311
|
+
return /* @__PURE__ */ jsx13(Overlay, {
|
|
26954
27312
|
title,
|
|
26955
27313
|
borderColor: tokens.accent,
|
|
26956
|
-
children: /* @__PURE__ */
|
|
27314
|
+
children: /* @__PURE__ */ jsxs11("box", {
|
|
26957
27315
|
flexDirection: "column",
|
|
26958
27316
|
children: [
|
|
26959
|
-
/* @__PURE__ */
|
|
27317
|
+
/* @__PURE__ */ jsx13("input", {
|
|
26960
27318
|
focused: true,
|
|
26961
27319
|
value: initialValue ?? "",
|
|
26962
27320
|
placeholder,
|
|
26963
27321
|
onInput: (val) => setValue(val),
|
|
26964
27322
|
onSubmit: () => onSubmit(value)
|
|
26965
27323
|
}),
|
|
26966
|
-
errorMessage2 ? /* @__PURE__ */
|
|
27324
|
+
errorMessage2 ? /* @__PURE__ */ jsx13("text", {
|
|
26967
27325
|
fg: tokens.error,
|
|
26968
27326
|
style: { marginTop: 1 },
|
|
26969
27327
|
children: errorMessage2
|
|
26970
|
-
}) : /* @__PURE__ */
|
|
27328
|
+
}) : /* @__PURE__ */ jsx13("text", {
|
|
26971
27329
|
fg: tokens.dim,
|
|
26972
27330
|
style: { marginTop: 1 },
|
|
26973
27331
|
children: "Press Enter to submit, empty to cancel"
|
|
@@ -26982,23 +27340,23 @@ var init_InputModal = __esm(() => {
|
|
|
26982
27340
|
});
|
|
26983
27341
|
|
|
26984
27342
|
// src/tui/components/ChoiceModal.tsx
|
|
26985
|
-
import { useState as
|
|
27343
|
+
import { useState as useState6 } from "react";
|
|
26986
27344
|
import { useKeyboard } from "@opentui/react";
|
|
26987
|
-
import { jsx as
|
|
27345
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "@opentui/react/jsx-runtime";
|
|
26988
27346
|
function ChoiceOptionRow({ option, index, isSelected, onSelect }) {
|
|
26989
27347
|
const tap = useTapHandler(() => onSelect(option.value));
|
|
26990
|
-
return /* @__PURE__ */
|
|
27348
|
+
return /* @__PURE__ */ jsxs12("box", {
|
|
26991
27349
|
flexDirection: "column",
|
|
26992
27350
|
backgroundColor: isSelected ? tokens.selectionBg : undefined,
|
|
26993
27351
|
...tap,
|
|
26994
27352
|
children: [
|
|
26995
|
-
/* @__PURE__ */
|
|
26996
|
-
children: /* @__PURE__ */
|
|
27353
|
+
/* @__PURE__ */ jsx14("text", {
|
|
27354
|
+
children: /* @__PURE__ */ jsx14("span", {
|
|
26997
27355
|
fg: isSelected ? tokens.bright : tokens.fg,
|
|
26998
27356
|
children: `${index + 1}. ${option.label}`
|
|
26999
27357
|
})
|
|
27000
27358
|
}),
|
|
27001
|
-
option.desc && /* @__PURE__ */
|
|
27359
|
+
option.desc && /* @__PURE__ */ jsx14("text", {
|
|
27002
27360
|
fg: tokens.dim,
|
|
27003
27361
|
children: ` ${option.desc}`
|
|
27004
27362
|
})
|
|
@@ -27006,7 +27364,7 @@ function ChoiceOptionRow({ option, index, isSelected, onSelect }) {
|
|
|
27006
27364
|
});
|
|
27007
27365
|
}
|
|
27008
27366
|
function ChoiceModal({ title, options, initialIndex = 0, onSubmit, onCancel }) {
|
|
27009
|
-
const [index, setIndex] =
|
|
27367
|
+
const [index, setIndex] = useState6(Math.min(Math.max(initialIndex, 0), options.length - 1));
|
|
27010
27368
|
useKeyboard((key) => {
|
|
27011
27369
|
if (key.name === "escape") {
|
|
27012
27370
|
onCancel();
|
|
@@ -27033,19 +27391,19 @@ function ChoiceModal({ title, options, initialIndex = 0, onSubmit, onCancel }) {
|
|
|
27033
27391
|
onSubmit(option.value);
|
|
27034
27392
|
}
|
|
27035
27393
|
});
|
|
27036
|
-
return /* @__PURE__ */
|
|
27394
|
+
return /* @__PURE__ */ jsx14(Overlay, {
|
|
27037
27395
|
title,
|
|
27038
27396
|
borderColor: tokens.accent,
|
|
27039
|
-
children: /* @__PURE__ */
|
|
27397
|
+
children: /* @__PURE__ */ jsxs12("box", {
|
|
27040
27398
|
flexDirection: "column",
|
|
27041
27399
|
children: [
|
|
27042
|
-
options.map((option, i2) => /* @__PURE__ */
|
|
27400
|
+
options.map((option, i2) => /* @__PURE__ */ jsx14(ChoiceOptionRow, {
|
|
27043
27401
|
option,
|
|
27044
27402
|
index: i2,
|
|
27045
27403
|
isSelected: i2 === index,
|
|
27046
27404
|
onSelect: onSubmit
|
|
27047
27405
|
}, option.value)),
|
|
27048
|
-
/* @__PURE__ */
|
|
27406
|
+
/* @__PURE__ */ jsxs12("text", {
|
|
27049
27407
|
fg: tokens.dim,
|
|
27050
27408
|
style: { marginTop: 1 },
|
|
27051
27409
|
children: [
|
|
@@ -27065,16 +27423,16 @@ var init_ChoiceModal = __esm(() => {
|
|
|
27065
27423
|
});
|
|
27066
27424
|
|
|
27067
27425
|
// src/tui/components/ConfigOverlay.tsx
|
|
27068
|
-
import { useState as
|
|
27426
|
+
import { useState as useState7, useEffect as useEffect5 } from "react";
|
|
27069
27427
|
import { useKeyboard as useKeyboard2 } from "@opentui/react";
|
|
27070
|
-
import { jsx as
|
|
27428
|
+
import { jsx as jsx15, jsxs as jsxs13, Fragment as Fragment2 } from "@opentui/react/jsx-runtime";
|
|
27071
27429
|
function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
27072
|
-
const [config2, setConfig] =
|
|
27073
|
-
const [viewState, setViewState] =
|
|
27074
|
-
const [selectedIndex, setSelectedIndex] =
|
|
27075
|
-
const [windowStart, setWindowStart] =
|
|
27076
|
-
const [editState, setEditState] =
|
|
27077
|
-
|
|
27430
|
+
const [config2, setConfig] = useState7(null);
|
|
27431
|
+
const [viewState, setViewState] = useState7({ type: "main" });
|
|
27432
|
+
const [selectedIndex, setSelectedIndex] = useState7(1);
|
|
27433
|
+
const [windowStart, setWindowStart] = useState7(0);
|
|
27434
|
+
const [editState, setEditState] = useState7({ type: "none" });
|
|
27435
|
+
useEffect5(() => {
|
|
27078
27436
|
try {
|
|
27079
27437
|
setConfig(loadConfig());
|
|
27080
27438
|
} catch (err) {
|
|
@@ -27110,7 +27468,7 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27110
27468
|
detailRows.push({ type: "remove_repo" });
|
|
27111
27469
|
}
|
|
27112
27470
|
const activeRows = viewState.type === "main" ? mainRows : detailRows;
|
|
27113
|
-
|
|
27471
|
+
useEffect5(() => {
|
|
27114
27472
|
if (!activeRows || selectedIndex >= activeRows.length) {
|
|
27115
27473
|
let newIdx = activeRows.length - 1;
|
|
27116
27474
|
while (newIdx > 0 && activeRows[newIdx]?.type === "header") {
|
|
@@ -27330,17 +27688,17 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27330
27688
|
hint = "Remove this repository from config";
|
|
27331
27689
|
}
|
|
27332
27690
|
}
|
|
27333
|
-
return /* @__PURE__ */
|
|
27691
|
+
return /* @__PURE__ */ jsxs13(Fragment2, {
|
|
27334
27692
|
children: [
|
|
27335
|
-
/* @__PURE__ */
|
|
27693
|
+
/* @__PURE__ */ jsx15(Overlay, {
|
|
27336
27694
|
title: "Configuration",
|
|
27337
27695
|
borderColor: tokens.border,
|
|
27338
|
-
children: /* @__PURE__ */
|
|
27696
|
+
children: /* @__PURE__ */ jsxs13("box", {
|
|
27339
27697
|
flexDirection: "column",
|
|
27340
27698
|
width: "100%",
|
|
27341
27699
|
height: 24,
|
|
27342
27700
|
children: [
|
|
27343
|
-
/* @__PURE__ */
|
|
27701
|
+
/* @__PURE__ */ jsx15("box", {
|
|
27344
27702
|
flexDirection: "column",
|
|
27345
27703
|
flexGrow: 1,
|
|
27346
27704
|
overflow: "hidden",
|
|
@@ -27348,7 +27706,7 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27348
27706
|
const i2 = windowStart + idx;
|
|
27349
27707
|
const isSelected = i2 === selectedIndex;
|
|
27350
27708
|
if (row.type === "header") {
|
|
27351
|
-
return /* @__PURE__ */
|
|
27709
|
+
return /* @__PURE__ */ jsx15("text", {
|
|
27352
27710
|
fg: tokens.dim,
|
|
27353
27711
|
style: { marginTop: i2 === 0 ? 0 : 1 },
|
|
27354
27712
|
children: row.label
|
|
@@ -27377,11 +27735,11 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27377
27735
|
labelText = "Remove this repo";
|
|
27378
27736
|
valText = "";
|
|
27379
27737
|
}
|
|
27380
|
-
return /* @__PURE__ */
|
|
27738
|
+
return /* @__PURE__ */ jsxs13("box", {
|
|
27381
27739
|
flexDirection: "row",
|
|
27382
27740
|
width: "100%",
|
|
27383
27741
|
children: [
|
|
27384
|
-
/* @__PURE__ */
|
|
27742
|
+
/* @__PURE__ */ jsxs13("text", {
|
|
27385
27743
|
fg: isSelected ? tokens.bright : tokens.fg,
|
|
27386
27744
|
bg: isSelected ? tokens.selectionBg : undefined,
|
|
27387
27745
|
width: 24,
|
|
@@ -27390,7 +27748,7 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27390
27748
|
labelText
|
|
27391
27749
|
]
|
|
27392
27750
|
}),
|
|
27393
|
-
valText && /* @__PURE__ */
|
|
27751
|
+
valText && /* @__PURE__ */ jsx15("text", {
|
|
27394
27752
|
fg: isSelected ? tokens.accent : tokens.dim,
|
|
27395
27753
|
bg: isSelected ? tokens.selectionBg : undefined,
|
|
27396
27754
|
flexShrink: 1,
|
|
@@ -27400,14 +27758,14 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27400
27758
|
}, i2);
|
|
27401
27759
|
})
|
|
27402
27760
|
}),
|
|
27403
|
-
/* @__PURE__ */
|
|
27761
|
+
/* @__PURE__ */ jsx15("box", {
|
|
27404
27762
|
flexDirection: "row",
|
|
27405
27763
|
border: true,
|
|
27406
27764
|
borderColor: tokens.border,
|
|
27407
27765
|
paddingTop: 1,
|
|
27408
27766
|
marginTop: 1,
|
|
27409
27767
|
minHeight: 3,
|
|
27410
|
-
children: /* @__PURE__ */
|
|
27768
|
+
children: /* @__PURE__ */ jsx15("text", {
|
|
27411
27769
|
fg: tokens.dim,
|
|
27412
27770
|
children: hint
|
|
27413
27771
|
})
|
|
@@ -27415,14 +27773,14 @@ function ConfigOverlay({ onClose, onSaved, onError }) {
|
|
|
27415
27773
|
]
|
|
27416
27774
|
})
|
|
27417
27775
|
}),
|
|
27418
|
-
editState.type === "input" && /* @__PURE__ */
|
|
27776
|
+
editState.type === "input" && /* @__PURE__ */ jsx15(InputModal, {
|
|
27419
27777
|
title: editState.title,
|
|
27420
27778
|
initialValue: editState.currentValue,
|
|
27421
27779
|
placeholder: "Enter value...",
|
|
27422
27780
|
errorMessage: editState.error,
|
|
27423
27781
|
onSubmit: handleInputSubmit
|
|
27424
27782
|
}),
|
|
27425
|
-
editState.type === "confirm_remove" && /* @__PURE__ */
|
|
27783
|
+
editState.type === "confirm_remove" && /* @__PURE__ */ jsx15(ConfirmModal, {
|
|
27426
27784
|
title: "Remove Repo",
|
|
27427
27785
|
message: `Remove repo ${editState.repo} from config?`
|
|
27428
27786
|
})
|
|
@@ -27439,29 +27797,29 @@ var init_ConfigOverlay = __esm(() => {
|
|
|
27439
27797
|
});
|
|
27440
27798
|
|
|
27441
27799
|
// src/tui/components/WarningsOverlay.tsx
|
|
27442
|
-
import { jsx as
|
|
27800
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "@opentui/react/jsx-runtime";
|
|
27443
27801
|
function WarningsOverlay({ warnings, onAcknowledge, onClose }) {
|
|
27444
27802
|
const ackTap = useTapHandler(() => onAcknowledge?.());
|
|
27445
27803
|
const closeTap = useTapHandler(() => onClose?.());
|
|
27446
|
-
return /* @__PURE__ */
|
|
27804
|
+
return /* @__PURE__ */ jsxs14(Overlay, {
|
|
27447
27805
|
title: `Warnings (${warnings.length})`,
|
|
27448
27806
|
borderColor: tokens.warning,
|
|
27449
27807
|
width: 80,
|
|
27450
27808
|
children: [
|
|
27451
|
-
/* @__PURE__ */
|
|
27809
|
+
/* @__PURE__ */ jsx16("box", {
|
|
27452
27810
|
flexDirection: "column",
|
|
27453
27811
|
style: { maxHeight: 28 },
|
|
27454
|
-
children: /* @__PURE__ */
|
|
27812
|
+
children: /* @__PURE__ */ jsx16("scrollbox", {
|
|
27455
27813
|
flexGrow: 1,
|
|
27456
|
-
children: warnings.map((warning, i2) => /* @__PURE__ */
|
|
27814
|
+
children: warnings.map((warning, i2) => /* @__PURE__ */ jsxs14("box", {
|
|
27457
27815
|
flexDirection: "column",
|
|
27458
27816
|
style: { marginBottom: 1 },
|
|
27459
27817
|
children: [
|
|
27460
|
-
/* @__PURE__ */
|
|
27818
|
+
/* @__PURE__ */ jsx16("text", {
|
|
27461
27819
|
fg: tokens.warning,
|
|
27462
27820
|
children: `⚠ ${warning.repoName}`
|
|
27463
27821
|
}),
|
|
27464
|
-
wrapText(warning.message, 72).map((line, j) => /* @__PURE__ */
|
|
27822
|
+
wrapText(warning.message, 72).map((line, j) => /* @__PURE__ */ jsx16("text", {
|
|
27465
27823
|
fg: tokens.fg,
|
|
27466
27824
|
children: ` ${line}`
|
|
27467
27825
|
}, j))
|
|
@@ -27469,36 +27827,36 @@ function WarningsOverlay({ warnings, onAcknowledge, onClose }) {
|
|
|
27469
27827
|
}, i2))
|
|
27470
27828
|
})
|
|
27471
27829
|
}),
|
|
27472
|
-
/* @__PURE__ */
|
|
27830
|
+
/* @__PURE__ */ jsxs14("box", {
|
|
27473
27831
|
flexDirection: "row",
|
|
27474
27832
|
gap: 3,
|
|
27475
27833
|
style: { marginTop: 2 },
|
|
27476
27834
|
justifyContent: "center",
|
|
27477
27835
|
children: [
|
|
27478
|
-
/* @__PURE__ */
|
|
27836
|
+
/* @__PURE__ */ jsx16("box", {
|
|
27479
27837
|
...ackTap,
|
|
27480
|
-
children: /* @__PURE__ */
|
|
27838
|
+
children: /* @__PURE__ */ jsxs14("text", {
|
|
27481
27839
|
children: [
|
|
27482
|
-
/* @__PURE__ */
|
|
27840
|
+
/* @__PURE__ */ jsx16("span", {
|
|
27483
27841
|
fg: tokens.dim,
|
|
27484
27842
|
children: "[a] "
|
|
27485
27843
|
}),
|
|
27486
|
-
/* @__PURE__ */
|
|
27844
|
+
/* @__PURE__ */ jsx16("span", {
|
|
27487
27845
|
fg: tokens.success,
|
|
27488
27846
|
children: "Acknowledge"
|
|
27489
27847
|
})
|
|
27490
27848
|
]
|
|
27491
27849
|
})
|
|
27492
27850
|
}),
|
|
27493
|
-
/* @__PURE__ */
|
|
27851
|
+
/* @__PURE__ */ jsx16("box", {
|
|
27494
27852
|
...closeTap,
|
|
27495
|
-
children: /* @__PURE__ */
|
|
27853
|
+
children: /* @__PURE__ */ jsxs14("text", {
|
|
27496
27854
|
children: [
|
|
27497
|
-
/* @__PURE__ */
|
|
27855
|
+
/* @__PURE__ */ jsx16("span", {
|
|
27498
27856
|
fg: tokens.dim,
|
|
27499
27857
|
children: "[esc] "
|
|
27500
27858
|
}),
|
|
27501
|
-
/* @__PURE__ */
|
|
27859
|
+
/* @__PURE__ */ jsx16("span", {
|
|
27502
27860
|
children: "Close"
|
|
27503
27861
|
})
|
|
27504
27862
|
]
|
|
@@ -27506,7 +27864,7 @@ function WarningsOverlay({ warnings, onAcknowledge, onClose }) {
|
|
|
27506
27864
|
})
|
|
27507
27865
|
]
|
|
27508
27866
|
}),
|
|
27509
|
-
/* @__PURE__ */
|
|
27867
|
+
/* @__PURE__ */ jsx16("text", {
|
|
27510
27868
|
style: { marginTop: 1, fg: tokens.dim },
|
|
27511
27869
|
children: "Press a to acknowledge and clear errors"
|
|
27512
27870
|
})
|
|
@@ -27521,10 +27879,10 @@ var init_WarningsOverlay = __esm(() => {
|
|
|
27521
27879
|
});
|
|
27522
27880
|
|
|
27523
27881
|
// src/tui/hooks/useSpinnerFrame.ts
|
|
27524
|
-
import { useEffect as
|
|
27882
|
+
import { useEffect as useEffect6, useState as useState8 } from "react";
|
|
27525
27883
|
function useSpinnerFrame(active) {
|
|
27526
|
-
const [index, setIndex] =
|
|
27527
|
-
|
|
27884
|
+
const [index, setIndex] = useState8(0);
|
|
27885
|
+
useEffect6(() => {
|
|
27528
27886
|
if (!active)
|
|
27529
27887
|
return;
|
|
27530
27888
|
const id = setInterval(() => setIndex((i2) => (i2 + 1) % FRAMES.length), INTERVAL_MS);
|
|
@@ -27537,11 +27895,408 @@ var init_useSpinnerFrame = __esm(() => {
|
|
|
27537
27895
|
FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
27538
27896
|
});
|
|
27539
27897
|
|
|
27898
|
+
// src/tui/hooks/useTerminalSessions.ts
|
|
27899
|
+
import { useState as useState9, useCallback as useCallback5, useRef as useRef6, useEffect as useEffect7 } from "react";
|
|
27900
|
+
function worktreeKeyFor(repoName, branch, path37) {
|
|
27901
|
+
return path37 || `${repoName}:${branch}`;
|
|
27902
|
+
}
|
|
27903
|
+
function nextTerminalSessionLabel(existingCount) {
|
|
27904
|
+
return `Session ${existingCount + 1}`;
|
|
27905
|
+
}
|
|
27906
|
+
function isSameSize(session, cols, rows) {
|
|
27907
|
+
return session.cols === cols && session.rows === rows;
|
|
27908
|
+
}
|
|
27909
|
+
function updateSessionSize(session, cols, rows) {
|
|
27910
|
+
return isSameSize(session, cols, rows) ? session : { ...session, cols, rows };
|
|
27911
|
+
}
|
|
27912
|
+
function relabelTerminalSessions(sessions) {
|
|
27913
|
+
return sessions.map((session, index) => ({ ...session, label: nextTerminalSessionLabel(index) }));
|
|
27914
|
+
}
|
|
27915
|
+
function useTerminalSessions() {
|
|
27916
|
+
const [sessionsByKey, setSessionsByKey] = useState9(() => new Map);
|
|
27917
|
+
const procsRef = useRef6(new Map);
|
|
27918
|
+
const listenersRef = useRef6(new Map);
|
|
27919
|
+
const rawBuffersRef = useRef6(new Map);
|
|
27920
|
+
const getSessions = useCallback5((repoName, branch, path37) => {
|
|
27921
|
+
const key = worktreeKeyFor(repoName, branch, path37);
|
|
27922
|
+
return sessionsByKey.get(key) ?? [];
|
|
27923
|
+
}, [sessionsByKey]);
|
|
27924
|
+
const getKey = useCallback5((repoName, branch, path37) => worktreeKeyFor(repoName, branch, path37), []);
|
|
27925
|
+
const createSession = useCallback5((repoName, branch, path37, opts) => {
|
|
27926
|
+
const key = worktreeKeyFor(repoName, branch, path37);
|
|
27927
|
+
const existing = sessionsByKey.get(key) ?? [];
|
|
27928
|
+
if (existing.length >= MAX_TERMINAL_SESSIONS) {
|
|
27929
|
+
return { session: null, error: `Max ${MAX_TERMINAL_SESSIONS} sessions per worktree` };
|
|
27930
|
+
}
|
|
27931
|
+
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
27932
|
+
const label = nextTerminalSessionLabel(existing.length);
|
|
27933
|
+
const cols = opts?.cols ?? 80;
|
|
27934
|
+
const rows = opts?.rows ?? 24;
|
|
27935
|
+
const session = {
|
|
27936
|
+
id,
|
|
27937
|
+
label,
|
|
27938
|
+
worktreeKey: key,
|
|
27939
|
+
worktreePath: path37,
|
|
27940
|
+
repoName,
|
|
27941
|
+
branch,
|
|
27942
|
+
lines: [],
|
|
27943
|
+
inputBuffer: "",
|
|
27944
|
+
exited: null,
|
|
27945
|
+
proc: null,
|
|
27946
|
+
terminal: null,
|
|
27947
|
+
cols,
|
|
27948
|
+
rows,
|
|
27949
|
+
usePty: false
|
|
27950
|
+
};
|
|
27951
|
+
const shell = process.env.SHELL || "/bin/bash";
|
|
27952
|
+
const appendPipe = (data) => {
|
|
27953
|
+
const text = new TextDecoder().decode(data);
|
|
27954
|
+
const parts = text.split(`
|
|
27955
|
+
`);
|
|
27956
|
+
setSessionsByKey((prev) => {
|
|
27957
|
+
const next = new Map(prev);
|
|
27958
|
+
const list = next.get(key);
|
|
27959
|
+
if (!list)
|
|
27960
|
+
return prev;
|
|
27961
|
+
const idx = list.findIndex((s) => s.id === id);
|
|
27962
|
+
if (idx === -1)
|
|
27963
|
+
return prev;
|
|
27964
|
+
const updated = [...list];
|
|
27965
|
+
const sess = updated[idx];
|
|
27966
|
+
const newLines = [...sess.lines];
|
|
27967
|
+
for (let i2 = 0;i2 < parts.length; i2++) {
|
|
27968
|
+
const part = parts[i2];
|
|
27969
|
+
if (i2 === 0 && newLines.length > 0) {
|
|
27970
|
+
if (part)
|
|
27971
|
+
newLines[newLines.length - 1] = (newLines[newLines.length - 1] ?? "") + part;
|
|
27972
|
+
} else {
|
|
27973
|
+
if (part || i2 < parts.length - 1)
|
|
27974
|
+
newLines.push(part);
|
|
27975
|
+
}
|
|
27976
|
+
}
|
|
27977
|
+
if (newLines.length > 1000)
|
|
27978
|
+
newLines.splice(0, newLines.length - 1000);
|
|
27979
|
+
updated[idx] = { ...sess, lines: newLines };
|
|
27980
|
+
next.set(key, updated);
|
|
27981
|
+
return next;
|
|
27982
|
+
});
|
|
27983
|
+
};
|
|
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
|
+
}
|
|
28000
|
+
const buf = rawBuffersRef.current.get(id) ?? [];
|
|
28001
|
+
buf.push(data);
|
|
28002
|
+
if (buf.length > 2000)
|
|
28003
|
+
buf.shift();
|
|
28004
|
+
rawBuffersRef.current.set(id, buf);
|
|
28005
|
+
const listener = listenersRef.current.get(id);
|
|
28006
|
+
if (listener) {
|
|
28007
|
+
listener(data);
|
|
28008
|
+
return;
|
|
28009
|
+
}
|
|
28010
|
+
};
|
|
28011
|
+
const onExit2 = (code) => {
|
|
28012
|
+
setSessionsByKey((prev) => {
|
|
28013
|
+
const next = new Map(prev);
|
|
28014
|
+
const list = next.get(key);
|
|
28015
|
+
if (!list)
|
|
28016
|
+
return prev;
|
|
28017
|
+
const idx = list.findIndex((s) => s.id === id);
|
|
28018
|
+
if (idx === -1)
|
|
28019
|
+
return prev;
|
|
28020
|
+
const updated = [...list];
|
|
28021
|
+
updated[idx] = { ...updated[idx], exited: code ?? 0, proc: null, terminal: null };
|
|
28022
|
+
next.set(key, updated);
|
|
28023
|
+
return next;
|
|
28024
|
+
});
|
|
28025
|
+
procsRef.current.delete(id);
|
|
28026
|
+
listenersRef.current.delete(id);
|
|
28027
|
+
};
|
|
28028
|
+
let usePty = false;
|
|
28029
|
+
try {
|
|
28030
|
+
if (typeof Bun !== "undefined" && typeof Bun.spawn === "function") {
|
|
28031
|
+
try {
|
|
28032
|
+
const proc = Bun.spawn([shell], {
|
|
28033
|
+
cwd: path37 || process.cwd(),
|
|
28034
|
+
env: { ...process.env, TERM: "xterm-256color", COLORTERM: "truecolor", WTX_SESSION: label },
|
|
28035
|
+
terminal: {
|
|
28036
|
+
cols,
|
|
28037
|
+
rows,
|
|
28038
|
+
name: "xterm-256color",
|
|
28039
|
+
data(_terminal, data) {
|
|
28040
|
+
onPtyData(data);
|
|
28041
|
+
},
|
|
28042
|
+
exit(_terminal, exitCode) {
|
|
28043
|
+
onExit2(exitCode);
|
|
28044
|
+
}
|
|
28045
|
+
}
|
|
28046
|
+
});
|
|
28047
|
+
if (proc && proc.terminal) {
|
|
28048
|
+
session.proc = proc;
|
|
28049
|
+
session.terminal = proc.terminal;
|
|
28050
|
+
session.usePty = true;
|
|
28051
|
+
usePty = true;
|
|
28052
|
+
procsRef.current.set(id, proc);
|
|
28053
|
+
(async () => {
|
|
28054
|
+
try {
|
|
28055
|
+
const code = await proc.exited;
|
|
28056
|
+
onExit2(code);
|
|
28057
|
+
} catch {}
|
|
28058
|
+
})();
|
|
28059
|
+
}
|
|
28060
|
+
} catch {}
|
|
28061
|
+
}
|
|
28062
|
+
if (!usePty)
|
|
28063
|
+
throw new Error("pty not available");
|
|
28064
|
+
} catch {
|
|
28065
|
+
try {
|
|
28066
|
+
const proc = Bun.spawn([shell], {
|
|
28067
|
+
cwd: path37 || process.cwd(),
|
|
28068
|
+
stdin: "pipe",
|
|
28069
|
+
stdout: "pipe",
|
|
28070
|
+
stderr: "pipe",
|
|
28071
|
+
env: { ...process.env, TERM: "xterm-256color", WTX_SESSION: label }
|
|
28072
|
+
});
|
|
28073
|
+
session.proc = proc;
|
|
28074
|
+
session.usePty = false;
|
|
28075
|
+
procsRef.current.set(id, proc);
|
|
28076
|
+
(async () => {
|
|
28077
|
+
const stdout = proc.stdout;
|
|
28078
|
+
if (stdout) {
|
|
28079
|
+
const reader = stdout.getReader();
|
|
28080
|
+
try {
|
|
28081
|
+
while (true) {
|
|
28082
|
+
const { value, done } = await reader.read();
|
|
28083
|
+
if (done)
|
|
28084
|
+
break;
|
|
28085
|
+
if (value)
|
|
28086
|
+
appendPipe(value);
|
|
28087
|
+
}
|
|
28088
|
+
} catch {}
|
|
28089
|
+
}
|
|
28090
|
+
})();
|
|
28091
|
+
(async () => {
|
|
28092
|
+
const stderr = proc.stderr;
|
|
28093
|
+
if (stderr) {
|
|
28094
|
+
const reader = stderr.getReader();
|
|
28095
|
+
try {
|
|
28096
|
+
while (true) {
|
|
28097
|
+
const { value, done } = await reader.read();
|
|
28098
|
+
if (done)
|
|
28099
|
+
break;
|
|
28100
|
+
if (value)
|
|
28101
|
+
appendPipe(value);
|
|
28102
|
+
}
|
|
28103
|
+
} catch {}
|
|
28104
|
+
}
|
|
28105
|
+
})();
|
|
28106
|
+
(async () => {
|
|
28107
|
+
try {
|
|
28108
|
+
const code = await proc.exited;
|
|
28109
|
+
onExit2(code);
|
|
28110
|
+
} catch {}
|
|
28111
|
+
})();
|
|
28112
|
+
} catch (e) {
|
|
28113
|
+
session.lines = [`Failed to spawn shell: ${e.message}`];
|
|
28114
|
+
}
|
|
28115
|
+
}
|
|
28116
|
+
if (session.usePty) {
|
|
28117
|
+
session.lines = [`${label} — ${path37} (${shell}) [pty]`, ""];
|
|
28118
|
+
} else if (session.lines.length === 0) {
|
|
28119
|
+
session.lines = [`${label} — ${path37} (${shell})`, ""];
|
|
28120
|
+
}
|
|
28121
|
+
setSessionsByKey((prev) => {
|
|
28122
|
+
const next = new Map(prev);
|
|
28123
|
+
const list = next.get(key) ?? [];
|
|
28124
|
+
next.set(key, [...list, session]);
|
|
28125
|
+
return next;
|
|
28126
|
+
});
|
|
28127
|
+
return { session };
|
|
28128
|
+
}, [sessionsByKey]);
|
|
28129
|
+
const removeSession = useCallback5((repoName, branch, path37, id) => {
|
|
28130
|
+
const key = worktreeKeyFor(repoName, branch, path37);
|
|
28131
|
+
setSessionsByKey((prev) => {
|
|
28132
|
+
const next = new Map(prev);
|
|
28133
|
+
const list = next.get(key);
|
|
28134
|
+
if (!list)
|
|
28135
|
+
return prev;
|
|
28136
|
+
const sess = list.find((s) => s.id === id);
|
|
28137
|
+
if (sess?.proc) {
|
|
28138
|
+
try {
|
|
28139
|
+
if (sess.terminal) {
|
|
28140
|
+
try {
|
|
28141
|
+
sess.terminal.close();
|
|
28142
|
+
} catch {}
|
|
28143
|
+
}
|
|
28144
|
+
sess.proc.kill();
|
|
28145
|
+
} catch {}
|
|
28146
|
+
procsRef.current.delete(id);
|
|
28147
|
+
listenersRef.current.delete(id);
|
|
28148
|
+
rawBuffersRef.current.delete(id);
|
|
28149
|
+
}
|
|
28150
|
+
const filtered = list.filter((s) => s.id !== id);
|
|
28151
|
+
const relabeled = relabelTerminalSessions(filtered);
|
|
28152
|
+
if (relabeled.length === 0) {
|
|
28153
|
+
next.delete(key);
|
|
28154
|
+
} else {
|
|
28155
|
+
next.set(key, relabeled);
|
|
28156
|
+
}
|
|
28157
|
+
return next;
|
|
28158
|
+
});
|
|
28159
|
+
}, []);
|
|
28160
|
+
const sendInput = useCallback5((repoName, branch, path37, id, data) => {
|
|
28161
|
+
const key = worktreeKeyFor(repoName, branch, path37);
|
|
28162
|
+
const list = sessionsByKey.get(key) ?? [];
|
|
28163
|
+
const sess = list.find((s) => s.id === id);
|
|
28164
|
+
if (!sess?.proc)
|
|
28165
|
+
return;
|
|
28166
|
+
try {
|
|
28167
|
+
if (sess.usePty && sess.terminal) {
|
|
28168
|
+
if (typeof data === "string") {
|
|
28169
|
+
sess.terminal.write(new TextEncoder().encode(data));
|
|
28170
|
+
} else {
|
|
28171
|
+
sess.terminal.write(data);
|
|
28172
|
+
}
|
|
28173
|
+
return;
|
|
28174
|
+
}
|
|
28175
|
+
const proc = sess.proc;
|
|
28176
|
+
const str = typeof data === "string" ? data : new TextDecoder().decode(data);
|
|
28177
|
+
if (proc.stdin && typeof proc.stdin.write === "function") {
|
|
28178
|
+
proc.stdin.write(str);
|
|
28179
|
+
} else if (proc.stdin instanceof WritableStream) {
|
|
28180
|
+
const writer = proc.stdin.getWriter();
|
|
28181
|
+
writer.write(new TextEncoder().encode(str));
|
|
28182
|
+
writer.releaseLock();
|
|
28183
|
+
} else {
|
|
28184
|
+
proc.stdin?.write?.(str);
|
|
28185
|
+
}
|
|
28186
|
+
} catch {}
|
|
28187
|
+
if (!sess.usePty) {
|
|
28188
|
+
const str = typeof data === "string" ? data : new TextDecoder().decode(data);
|
|
28189
|
+
if (str.endsWith(`
|
|
28190
|
+
`)) {
|
|
28191
|
+
const cmd = str.slice(0, -1);
|
|
28192
|
+
if (cmd) {
|
|
28193
|
+
setSessionsByKey((prev) => {
|
|
28194
|
+
const next = new Map(prev);
|
|
28195
|
+
const l = next.get(key);
|
|
28196
|
+
if (!l)
|
|
28197
|
+
return prev;
|
|
28198
|
+
const idx = l.findIndex((s2) => s2.id === id);
|
|
28199
|
+
if (idx === -1)
|
|
28200
|
+
return prev;
|
|
28201
|
+
const updated = [...l];
|
|
28202
|
+
const s = updated[idx];
|
|
28203
|
+
updated[idx] = { ...s, lines: [...s.lines, `$ ${cmd}`] };
|
|
28204
|
+
next.set(key, updated);
|
|
28205
|
+
return next;
|
|
28206
|
+
});
|
|
28207
|
+
}
|
|
28208
|
+
}
|
|
28209
|
+
}
|
|
28210
|
+
}, [sessionsByKey]);
|
|
28211
|
+
const resizeSession = useCallback5((repoName, branch, path37, id, cols, rows) => {
|
|
28212
|
+
const key = worktreeKeyFor(repoName, branch, path37);
|
|
28213
|
+
setSessionsByKey((prev) => {
|
|
28214
|
+
const list = prev.get(key);
|
|
28215
|
+
if (!list)
|
|
28216
|
+
return prev;
|
|
28217
|
+
const idx = list.findIndex((s) => s.id === id);
|
|
28218
|
+
if (idx === -1)
|
|
28219
|
+
return prev;
|
|
28220
|
+
const sess = list[idx];
|
|
28221
|
+
if (isSameSize(sess, cols, rows))
|
|
28222
|
+
return prev;
|
|
28223
|
+
try {
|
|
28224
|
+
sess.terminal?.resize?.(cols, rows);
|
|
28225
|
+
} catch {}
|
|
28226
|
+
const next = new Map(prev);
|
|
28227
|
+
const updated = [...list];
|
|
28228
|
+
updated[idx] = updateSessionSize(sess, cols, rows);
|
|
28229
|
+
next.set(key, updated);
|
|
28230
|
+
return next;
|
|
28231
|
+
});
|
|
28232
|
+
}, []);
|
|
28233
|
+
const registerListener = useCallback5((id, fn) => {
|
|
28234
|
+
listenersRef.current.set(id, fn);
|
|
28235
|
+
const buf = rawBuffersRef.current.get(id);
|
|
28236
|
+
if (buf) {
|
|
28237
|
+
for (const chunk of buf) {
|
|
28238
|
+
try {
|
|
28239
|
+
fn(chunk);
|
|
28240
|
+
} catch {}
|
|
28241
|
+
}
|
|
28242
|
+
}
|
|
28243
|
+
}, []);
|
|
28244
|
+
const unregisterListener = useCallback5((id) => {
|
|
28245
|
+
listenersRef.current.delete(id);
|
|
28246
|
+
}, []);
|
|
28247
|
+
const cleanupAll = useCallback5(() => {
|
|
28248
|
+
for (const proc of procsRef.current.values()) {
|
|
28249
|
+
try {
|
|
28250
|
+
if (proc.terminal) {
|
|
28251
|
+
try {
|
|
28252
|
+
proc.terminal.close();
|
|
28253
|
+
} catch {}
|
|
28254
|
+
}
|
|
28255
|
+
proc.kill();
|
|
28256
|
+
} catch {}
|
|
28257
|
+
}
|
|
28258
|
+
procsRef.current.clear();
|
|
28259
|
+
listenersRef.current.clear();
|
|
28260
|
+
rawBuffersRef.current.clear();
|
|
28261
|
+
}, []);
|
|
28262
|
+
useEffect7(() => {
|
|
28263
|
+
return () => cleanupAll();
|
|
28264
|
+
}, [cleanupAll]);
|
|
28265
|
+
const pruneKey = useCallback5((key) => {
|
|
28266
|
+
setSessionsByKey((prev) => {
|
|
28267
|
+
const next = new Map(prev);
|
|
28268
|
+
const list = next.get(key);
|
|
28269
|
+
if (!list)
|
|
28270
|
+
return prev;
|
|
28271
|
+
for (const s of list) {
|
|
28272
|
+
if (s.proc) {
|
|
28273
|
+
try {
|
|
28274
|
+
if (s.terminal) {
|
|
28275
|
+
try {
|
|
28276
|
+
s.terminal.close();
|
|
28277
|
+
} catch {}
|
|
28278
|
+
}
|
|
28279
|
+
s.proc.kill();
|
|
28280
|
+
} catch {}
|
|
28281
|
+
procsRef.current.delete(s.id);
|
|
28282
|
+
listenersRef.current.delete(s.id);
|
|
28283
|
+
rawBuffersRef.current.delete(s.id);
|
|
28284
|
+
}
|
|
28285
|
+
}
|
|
28286
|
+
next.delete(key);
|
|
28287
|
+
return next;
|
|
28288
|
+
});
|
|
28289
|
+
}, []);
|
|
28290
|
+
return { sessionsByKey, getSessions, getKey, createSession, removeSession, sendInput, resizeSession, registerListener, unregisterListener, pruneKey, cleanupAll };
|
|
28291
|
+
}
|
|
28292
|
+
var MAX_TERMINAL_SESSIONS = 5;
|
|
28293
|
+
var init_useTerminalSessions = () => {};
|
|
28294
|
+
|
|
27540
28295
|
// src/tui/components/App.tsx
|
|
27541
|
-
import { useState as
|
|
28296
|
+
import { useState as useState10, useEffect as useEffect8, useMemo, useRef as useRef7, useCallback as useCallback6 } from "react";
|
|
27542
28297
|
import { existsSync as existsSync4 } from "node:fs";
|
|
27543
|
-
import { useKeyboard as useKeyboard3, useRenderer as useRenderer2, useSelectionHandler, useTerminalDimensions } from "@opentui/react";
|
|
27544
|
-
import { jsx as
|
|
28298
|
+
import { useKeyboard as useKeyboard3, usePaste, useRenderer as useRenderer2, useSelectionHandler, useTerminalDimensions } from "@opentui/react";
|
|
28299
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "@opentui/react/jsx-runtime";
|
|
27545
28300
|
function getWorktreePathFor(repoName, branch) {
|
|
27546
28301
|
try {
|
|
27547
28302
|
const config2 = loadConfig();
|
|
@@ -27554,37 +28309,51 @@ function getWorktreePathFor(repoName, branch) {
|
|
|
27554
28309
|
function App({ opts }) {
|
|
27555
28310
|
const renderer = useRenderer2();
|
|
27556
28311
|
const { blocks, loading, refreshing, error: error52, warnings, lastRefreshed, pendingRepos, refresh, clearWarnings } = useWorktrees(opts);
|
|
27557
|
-
const [selectedIndex, setSelectedIndex] =
|
|
27558
|
-
const [modal, setModal] =
|
|
27559
|
-
const [actionMessage, setActionMessage] =
|
|
27560
|
-
const messageTimer =
|
|
27561
|
-
const [ops, setOps] =
|
|
27562
|
-
const [failedLogs, setFailedLogs] =
|
|
27563
|
-
const nextOpId =
|
|
27564
|
-
const [createModal, setCreateModal] =
|
|
27565
|
-
const [createError, setCreateError] =
|
|
27566
|
-
const [createBaseModal, setCreateBaseModal] =
|
|
27567
|
-
const [createBaseError, setCreateBaseError] =
|
|
27568
|
-
const [createDepsChoice, setCreateDepsChoice] =
|
|
27569
|
-
const [pullPrModal, setPullPrModal] =
|
|
27570
|
-
const [pullPrError, setPullPrError] =
|
|
27571
|
-
const [pullForceChoice, setPullForceChoice] =
|
|
27572
|
-
const [renameModal, setRenameModal] =
|
|
27573
|
-
const [renameError, setRenameError] =
|
|
27574
|
-
const [configOpen, setConfigOpen] =
|
|
27575
|
-
const [refreshScopes, setRefreshScopes] =
|
|
27576
|
-
const [filterText, setFilterText] =
|
|
27577
|
-
const [isFiltering, setIsFiltering] =
|
|
27578
|
-
const [selection, setSelection] =
|
|
27579
|
-
const [splitRatio, setSplitRatio] =
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27584
|
-
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
28312
|
+
const [selectedIndex, setSelectedIndex] = useState10(0);
|
|
28313
|
+
const [modal, setModal] = useState10({ type: "none" });
|
|
28314
|
+
const [actionMessage, setActionMessage] = useState10();
|
|
28315
|
+
const messageTimer = useRef7(null);
|
|
28316
|
+
const [ops, setOps] = useState10([]);
|
|
28317
|
+
const [failedLogs, setFailedLogs] = useState10([]);
|
|
28318
|
+
const nextOpId = useRef7(1);
|
|
28319
|
+
const [createModal, setCreateModal] = useState10(false);
|
|
28320
|
+
const [createError, setCreateError] = useState10();
|
|
28321
|
+
const [createBaseModal, setCreateBaseModal] = useState10(null);
|
|
28322
|
+
const [createBaseError, setCreateBaseError] = useState10();
|
|
28323
|
+
const [createDepsChoice, setCreateDepsChoice] = useState10(null);
|
|
28324
|
+
const [pullPrModal, setPullPrModal] = useState10(false);
|
|
28325
|
+
const [pullPrError, setPullPrError] = useState10();
|
|
28326
|
+
const [pullForceChoice, setPullForceChoice] = useState10(null);
|
|
28327
|
+
const [renameModal, setRenameModal] = useState10(false);
|
|
28328
|
+
const [renameError, setRenameError] = useState10();
|
|
28329
|
+
const [configOpen, setConfigOpen] = useState10(false);
|
|
28330
|
+
const [refreshScopes, setRefreshScopes] = useState10([]);
|
|
28331
|
+
const [filterText, setFilterText] = useState10("");
|
|
28332
|
+
const [isFiltering, setIsFiltering] = useState10(false);
|
|
28333
|
+
const [selection, setSelection] = useState10(new Set);
|
|
28334
|
+
const [splitRatio, setSplitRatio] = useState10(() => {
|
|
28335
|
+
try {
|
|
28336
|
+
const cfg = loadConfig();
|
|
28337
|
+
const left = cfg.tui?.leftPaneWidthWeight ?? 3;
|
|
28338
|
+
const right = cfg.tui?.rightPaneWidthWeight ?? 7;
|
|
28339
|
+
const total = left + right;
|
|
28340
|
+
if (total > 0)
|
|
28341
|
+
return left / total;
|
|
28342
|
+
} catch {}
|
|
28343
|
+
return 3 / 10;
|
|
28344
|
+
});
|
|
28345
|
+
const [isResizing, setIsResizing] = useState10(false);
|
|
28346
|
+
const terminalSessions = useTerminalSessions();
|
|
28347
|
+
const [activeTabByWorktree, setActiveTabByWorktree] = useState10(() => new Map);
|
|
28348
|
+
const [terminalFocused, setTerminalFocused] = useState10(false);
|
|
28349
|
+
const { width: termW, height: termH } = useTerminalDimensions();
|
|
28350
|
+
const totalWidth = termW || renderer.width || 80;
|
|
28351
|
+
const totalHeight = termH || renderer.height || 24;
|
|
28352
|
+
useEffect8(() => {
|
|
28353
|
+
if (termW)
|
|
28354
|
+
setSplitRatio((prev) => clampSplitRatio(termW, prev));
|
|
28355
|
+
}, [termW]);
|
|
28356
|
+
const doRefresh = useCallback6(async (scope) => {
|
|
27588
28357
|
const targets = scope ?? [
|
|
27589
28358
|
...new Set([...blocks.map((b) => b.repoName), ...pendingRepos])
|
|
27590
28359
|
];
|
|
@@ -27595,18 +28364,18 @@ function App({ opts }) {
|
|
|
27595
28364
|
setRefreshScopes([]);
|
|
27596
28365
|
}
|
|
27597
28366
|
}, [blocks, pendingRepos, refresh]);
|
|
27598
|
-
|
|
28367
|
+
useEffect8(() => {
|
|
27599
28368
|
if (error52) {
|
|
27600
28369
|
setModal({ type: "error", message: error52 });
|
|
27601
28370
|
}
|
|
27602
28371
|
}, [error52]);
|
|
27603
|
-
const flash =
|
|
28372
|
+
const flash = useCallback6((message, ms = 3000) => {
|
|
27604
28373
|
if (messageTimer.current)
|
|
27605
28374
|
clearTimeout(messageTimer.current);
|
|
27606
28375
|
setActionMessage(message);
|
|
27607
28376
|
messageTimer.current = setTimeout(() => setActionMessage(undefined), ms);
|
|
27608
28377
|
}, []);
|
|
27609
|
-
const copySelectedText =
|
|
28378
|
+
const copySelectedText = useCallback6((warnOnEmpty) => {
|
|
27610
28379
|
if (isResizing) {
|
|
27611
28380
|
renderer.clearSelection();
|
|
27612
28381
|
return;
|
|
@@ -27636,12 +28405,139 @@ function App({ opts }) {
|
|
|
27636
28405
|
const flatRows = useMemo(() => displayBlocks.flatMap((b) => b.rows.filter((r) => !r.isPendingCreate)), [displayBlocks]);
|
|
27637
28406
|
const totalRows = blocks.flatMap((b) => b.rows).length;
|
|
27638
28407
|
const maxIndex = Math.max(0, flatRows.length - 1);
|
|
27639
|
-
|
|
28408
|
+
useEffect8(() => {
|
|
27640
28409
|
if (selectedIndex > maxIndex && maxIndex >= 0) {
|
|
27641
28410
|
setSelectedIndex(maxIndex);
|
|
27642
28411
|
}
|
|
27643
28412
|
}, [maxIndex, selectedIndex]);
|
|
27644
28413
|
const selectedRow = flatRows[selectedIndex] ?? null;
|
|
28414
|
+
const worktreeKey = selectedRow ? terminalSessions.getKey(selectedRow.repoName, selectedRow.branch, selectedRow.path) : "";
|
|
28415
|
+
const sessionsForSelected = selectedRow ? terminalSessions.getSessions(selectedRow.repoName, selectedRow.branch, selectedRow.path) : [];
|
|
28416
|
+
const activeTabId = worktreeKey ? activeTabByWorktree.get(worktreeKey) ?? "details" : "details";
|
|
28417
|
+
useEffect8(() => {
|
|
28418
|
+
if (worktreeKey && !activeTabByWorktree.has(worktreeKey)) {
|
|
28419
|
+
setActiveTabByWorktree((prev) => {
|
|
28420
|
+
if (prev.has(worktreeKey))
|
|
28421
|
+
return prev;
|
|
28422
|
+
const next = new Map(prev);
|
|
28423
|
+
next.set(worktreeKey, "details");
|
|
28424
|
+
return next;
|
|
28425
|
+
});
|
|
28426
|
+
}
|
|
28427
|
+
}, [worktreeKey, activeTabByWorktree]);
|
|
28428
|
+
useEffect8(() => {
|
|
28429
|
+
if (sessionsForSelected.length === 0 && activeTabId !== "details") {
|
|
28430
|
+
setActiveTabByWorktree((prev) => {
|
|
28431
|
+
const next = new Map(prev);
|
|
28432
|
+
next.set(worktreeKey, "details");
|
|
28433
|
+
return next;
|
|
28434
|
+
});
|
|
28435
|
+
setTerminalFocused(false);
|
|
28436
|
+
} else if (sessionsForSelected.length > 0) {
|
|
28437
|
+
const exists = sessionsForSelected.some((s) => s.id === activeTabId) || activeTabId === "details";
|
|
28438
|
+
if (!exists) {
|
|
28439
|
+
setActiveTabByWorktree((prev) => {
|
|
28440
|
+
const next = new Map(prev);
|
|
28441
|
+
next.set(worktreeKey, sessionsForSelected[0].id);
|
|
28442
|
+
return next;
|
|
28443
|
+
});
|
|
28444
|
+
}
|
|
28445
|
+
}
|
|
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
|
+
});
|
|
28459
|
+
const handleSelectTab = useCallback6((id) => {
|
|
28460
|
+
if (!worktreeKey)
|
|
28461
|
+
return;
|
|
28462
|
+
setActiveTabByWorktree((prev) => {
|
|
28463
|
+
const next = new Map(prev);
|
|
28464
|
+
next.set(worktreeKey, id);
|
|
28465
|
+
return next;
|
|
28466
|
+
});
|
|
28467
|
+
const isSession = sessionsForSelected.some((s) => s.id === id);
|
|
28468
|
+
setTerminalFocused(isSession);
|
|
28469
|
+
}, [worktreeKey, sessionsForSelected]);
|
|
28470
|
+
const handleAddSession = useCallback6(() => {
|
|
28471
|
+
if (!selectedRow) {
|
|
28472
|
+
flash("No worktree selected");
|
|
28473
|
+
return;
|
|
28474
|
+
}
|
|
28475
|
+
const rawLeftTmp = Math.floor(totalWidth * splitRatio);
|
|
28476
|
+
const leftColsTmp = Math.max(20, Math.min(totalWidth - 20 - DIVIDER_WIDTH, rawLeftTmp));
|
|
28477
|
+
const rightColsTmp = Math.max(20, totalWidth - leftColsTmp - DIVIDER_WIDTH);
|
|
28478
|
+
const cols = Math.max(20, rightColsTmp - 4);
|
|
28479
|
+
const rows = Math.max(10, totalHeight - 10);
|
|
28480
|
+
const { session, error: error53 } = terminalSessions.createSession(selectedRow.repoName, selectedRow.branch, selectedRow.path, { cols, rows });
|
|
28481
|
+
if (error53 || !session) {
|
|
28482
|
+
flash(error53 ?? "Failed to create session");
|
|
28483
|
+
return;
|
|
28484
|
+
}
|
|
28485
|
+
const key = terminalSessions.getKey(selectedRow.repoName, selectedRow.branch, selectedRow.path);
|
|
28486
|
+
setActiveTabByWorktree((prev) => {
|
|
28487
|
+
const next = new Map(prev);
|
|
28488
|
+
next.set(key, session.id);
|
|
28489
|
+
return next;
|
|
28490
|
+
});
|
|
28491
|
+
setTerminalFocused(true);
|
|
28492
|
+
flash(`Session ${session.label} created`, 2000);
|
|
28493
|
+
}, [selectedRow, terminalSessions, flash, totalWidth, splitRatio, totalHeight]);
|
|
28494
|
+
const handleCloseSession = useCallback6((id) => {
|
|
28495
|
+
if (!selectedRow)
|
|
28496
|
+
return;
|
|
28497
|
+
terminalSessions.removeSession(selectedRow.repoName, selectedRow.branch, selectedRow.path, id);
|
|
28498
|
+
const key = terminalSessions.getKey(selectedRow.repoName, selectedRow.branch, selectedRow.path);
|
|
28499
|
+
setActiveTabByWorktree((prev) => {
|
|
28500
|
+
const next = new Map(prev);
|
|
28501
|
+
const current = next.get(key);
|
|
28502
|
+
if (current === id)
|
|
28503
|
+
next.set(key, "details");
|
|
28504
|
+
return next;
|
|
28505
|
+
});
|
|
28506
|
+
setTerminalFocused(false);
|
|
28507
|
+
flash("Session closed", 2000);
|
|
28508
|
+
}, [selectedRow, terminalSessions, flash]);
|
|
28509
|
+
useEffect8(() => {
|
|
28510
|
+
const existingKeys = new Set(blocks.flatMap((b) => b.rows.map((r) => terminalSessions.getKey(r.repoName, r.branch, r.path))));
|
|
28511
|
+
for (const key of terminalSessions.sessionsByKey.keys()) {
|
|
28512
|
+
if (!existingKeys.has(key))
|
|
28513
|
+
terminalSessions.pruneKey(key);
|
|
28514
|
+
}
|
|
28515
|
+
}, [blocks, terminalSessions]);
|
|
28516
|
+
const allSessionsFlat = useMemo(() => Array.from(terminalSessions.sessionsByKey.values()).flat(), [terminalSessions.sessionsByKey]);
|
|
28517
|
+
const tabsForSelected = useMemo(() => {
|
|
28518
|
+
const base2 = [
|
|
28519
|
+
{
|
|
28520
|
+
id: "details",
|
|
28521
|
+
label: "Details",
|
|
28522
|
+
render: ({ worktree }) => /* @__PURE__ */ jsx17(DetailsContent, {
|
|
28523
|
+
selectedRow: worktree
|
|
28524
|
+
})
|
|
28525
|
+
}
|
|
28526
|
+
];
|
|
28527
|
+
for (const s of sessionsForSelected) {
|
|
28528
|
+
base2.push({
|
|
28529
|
+
id: s.id,
|
|
28530
|
+
label: s.label,
|
|
28531
|
+
closable: true,
|
|
28532
|
+
render: () => /* @__PURE__ */ jsx17("box", {
|
|
28533
|
+
flexGrow: 1,
|
|
28534
|
+
width: "100%",
|
|
28535
|
+
height: "100%"
|
|
28536
|
+
})
|
|
28537
|
+
});
|
|
28538
|
+
}
|
|
28539
|
+
return base2;
|
|
28540
|
+
}, [sessionsForSelected]);
|
|
27645
28541
|
const { repoVerbs, rowVerbs } = useMemo(() => {
|
|
27646
28542
|
const rv = new Map;
|
|
27647
28543
|
const nv = new Map;
|
|
@@ -27780,7 +28676,7 @@ function App({ opts }) {
|
|
|
27780
28676
|
args.push("--force");
|
|
27781
28677
|
executeOp(op, args, [repoName]);
|
|
27782
28678
|
};
|
|
27783
|
-
const handleHintClick =
|
|
28679
|
+
const handleHintClick = useCallback6((key) => {
|
|
27784
28680
|
if (key === "c") {
|
|
27785
28681
|
setConfigOpen(true);
|
|
27786
28682
|
return;
|
|
@@ -27932,8 +28828,79 @@ function App({ opts }) {
|
|
|
27932
28828
|
setModal({ type: "confirm_sync", rows: targets });
|
|
27933
28829
|
return;
|
|
27934
28830
|
}
|
|
27935
|
-
|
|
28831
|
+
if (key === "t") {
|
|
28832
|
+
if (!selectedRow)
|
|
28833
|
+
return;
|
|
28834
|
+
const sessions = terminalSessions.getSessions(selectedRow.repoName, selectedRow.branch, selectedRow.path);
|
|
28835
|
+
if (sessions.length >= MAX_TERMINAL_SESSIONS) {
|
|
28836
|
+
flash(`Max ${MAX_TERMINAL_SESSIONS} sessions per worktree`);
|
|
28837
|
+
return;
|
|
28838
|
+
}
|
|
28839
|
+
handleAddSession();
|
|
28840
|
+
return;
|
|
28841
|
+
}
|
|
28842
|
+
}, [selectedRow, selection, warnings, busyRepos, busyRowPaths, doRefresh, flash, blocks, terminalSessions]);
|
|
27936
28843
|
useKeyboard3((key) => {
|
|
28844
|
+
if (terminalFocused) {
|
|
28845
|
+
if (key.ctrl && key.name === "g") {
|
|
28846
|
+
setTerminalFocused(false);
|
|
28847
|
+
return;
|
|
28848
|
+
}
|
|
28849
|
+
const activeSession = sessionsForSelected.find((s) => s.id === activeTabId);
|
|
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
|
+
}
|
|
28858
|
+
let data = null;
|
|
28859
|
+
const seq = key.sequence;
|
|
28860
|
+
const raw = key.raw;
|
|
28861
|
+
if (key.ctrl && key.name && key.name.length === 1) {
|
|
28862
|
+
const code = key.name.charCodeAt(0) - 96;
|
|
28863
|
+
if (code >= 1 && code <= 26)
|
|
28864
|
+
data = String.fromCharCode(code);
|
|
28865
|
+
else if (seq)
|
|
28866
|
+
data = seq;
|
|
28867
|
+
else if (raw)
|
|
28868
|
+
data = raw;
|
|
28869
|
+
} else if (seq) {
|
|
28870
|
+
data = seq;
|
|
28871
|
+
} else if (raw) {
|
|
28872
|
+
data = raw;
|
|
28873
|
+
} else if (key.name === "return" || key.name === "enter") {
|
|
28874
|
+
data = "\r";
|
|
28875
|
+
} else if (key.name === "backspace") {
|
|
28876
|
+
data = "";
|
|
28877
|
+
} else if (key.name === "tab") {
|
|
28878
|
+
data = "\t";
|
|
28879
|
+
} else if (key.name === "escape") {
|
|
28880
|
+
data = "\x1B";
|
|
28881
|
+
} else if (key.name && key.name.length === 1) {
|
|
28882
|
+
data = key.name;
|
|
28883
|
+
}
|
|
28884
|
+
if (data !== null) {
|
|
28885
|
+
terminalSessions.sendInput(activeSession.repoName, activeSession.branch, activeSession.worktreePath, activeSession.id, data);
|
|
28886
|
+
}
|
|
28887
|
+
}
|
|
28888
|
+
return;
|
|
28889
|
+
}
|
|
28890
|
+
if (key.ctrl && key.name === "g") {
|
|
28891
|
+
if (sessionsForSelected.length > 0) {
|
|
28892
|
+
const targetId = activeTabId !== "details" ? activeTabId : sessionsForSelected[0].id;
|
|
28893
|
+
if (worktreeKey) {
|
|
28894
|
+
setActiveTabByWorktree((prev) => {
|
|
28895
|
+
const next = new Map(prev);
|
|
28896
|
+
next.set(worktreeKey, targetId);
|
|
28897
|
+
return next;
|
|
28898
|
+
});
|
|
28899
|
+
}
|
|
28900
|
+
setTerminalFocused(true);
|
|
28901
|
+
return;
|
|
28902
|
+
}
|
|
28903
|
+
}
|
|
27937
28904
|
if (isFiltering) {
|
|
27938
28905
|
if (key.name === "escape") {
|
|
27939
28906
|
setIsFiltering(false);
|
|
@@ -28245,108 +29212,110 @@ function App({ opts }) {
|
|
|
28245
29212
|
setModal({ type: "confirm_sync", rows: targets });
|
|
28246
29213
|
return;
|
|
28247
29214
|
}
|
|
28248
|
-
if (key.name === "
|
|
28249
|
-
|
|
28250
|
-
|
|
29215
|
+
if (key.name === "t") {
|
|
29216
|
+
if (!selectedRow) {
|
|
29217
|
+
flash("No worktree selected");
|
|
28251
29218
|
return;
|
|
28252
|
-
|
|
28253
|
-
|
|
28254
|
-
|
|
28255
|
-
|
|
28256
|
-
if (conflict) {
|
|
28257
|
-
flash(conflict);
|
|
29219
|
+
}
|
|
29220
|
+
const sessions = terminalSessions.getSessions(selectedRow.repoName, selectedRow.branch, selectedRow.path);
|
|
29221
|
+
if (sessions.length >= MAX_TERMINAL_SESSIONS) {
|
|
29222
|
+
flash(`Max ${MAX_TERMINAL_SESSIONS} sessions per worktree`);
|
|
28258
29223
|
return;
|
|
28259
29224
|
}
|
|
28260
|
-
(
|
|
28261
|
-
|
|
28262
|
-
try {
|
|
28263
|
-
const config2 = await loadConfig();
|
|
28264
|
-
const cmdTemplate = resolveAgentCommand("claude", config2.agents) ?? "claude";
|
|
28265
|
-
const result = await spawnAgentInWorktree(cmdTemplate, target.path, { repoName: target.repoName, branch: target.branch });
|
|
28266
|
-
appendHistory({
|
|
28267
|
-
ts: new Date().toISOString(),
|
|
28268
|
-
source: "terminal",
|
|
28269
|
-
command: "agent",
|
|
28270
|
-
args: ["agent", target.branch, "--repo", target.repoName],
|
|
28271
|
-
durationMs: Date.now() - startedAt,
|
|
28272
|
-
exit: 0
|
|
28273
|
-
});
|
|
28274
|
-
flash(`Agent spawned (${result.mode}${result.session ? ` session ${result.session}` : ""})`, 5000);
|
|
28275
|
-
} catch (e) {
|
|
28276
|
-
appendHistory({
|
|
28277
|
-
ts: new Date().toISOString(),
|
|
28278
|
-
source: "terminal",
|
|
28279
|
-
command: "agent",
|
|
28280
|
-
args: ["agent", target.branch, "--repo", target.repoName],
|
|
28281
|
-
durationMs: Date.now() - startedAt,
|
|
28282
|
-
exit: 1
|
|
28283
|
-
});
|
|
28284
|
-
flash(`Agent failed: ${e.message}`, 5000);
|
|
28285
|
-
}
|
|
28286
|
-
})();
|
|
29225
|
+
handleAddSession();
|
|
29226
|
+
return;
|
|
28287
29227
|
}
|
|
28288
29228
|
});
|
|
28289
29229
|
const rawLeft = Math.floor(totalWidth * splitRatio);
|
|
28290
29230
|
const leftCols = Math.max(20, Math.min(totalWidth - 20 - DIVIDER_WIDTH, rawLeft));
|
|
28291
29231
|
const rightCols = Math.max(20, totalWidth - leftCols - DIVIDER_WIDTH);
|
|
28292
|
-
|
|
29232
|
+
const paneCols = Math.max(20, rightCols - 4);
|
|
29233
|
+
const paneRows = Math.max(10, totalHeight - 10);
|
|
29234
|
+
useEffect8(() => {
|
|
29235
|
+
for (const sessions of terminalSessions.sessionsByKey.values()) {
|
|
29236
|
+
for (const s of sessions) {
|
|
29237
|
+
if (s.usePty && s.terminal && (s.cols !== paneCols || s.rows !== paneRows)) {
|
|
29238
|
+
terminalSessions.resizeSession(s.repoName, s.branch, s.worktreePath, s.id, paneCols, paneRows);
|
|
29239
|
+
}
|
|
29240
|
+
}
|
|
29241
|
+
}
|
|
29242
|
+
}, [paneCols, paneRows, terminalSessions]);
|
|
29243
|
+
useEffect8(() => {
|
|
29244
|
+
setTerminalFocused(false);
|
|
29245
|
+
}, [selectedIndex]);
|
|
29246
|
+
return /* @__PURE__ */ jsxs15("box", {
|
|
28293
29247
|
flexDirection: "column",
|
|
28294
29248
|
width: "100%",
|
|
28295
29249
|
height: "100%",
|
|
28296
29250
|
children: [
|
|
28297
|
-
/* @__PURE__ */
|
|
29251
|
+
/* @__PURE__ */ jsxs15("box", {
|
|
28298
29252
|
flexDirection: "row",
|
|
28299
29253
|
width: "100%",
|
|
28300
29254
|
flexGrow: 1,
|
|
28301
29255
|
children: [
|
|
28302
|
-
/* @__PURE__ */
|
|
29256
|
+
/* @__PURE__ */ jsx17("box", {
|
|
28303
29257
|
width: leftCols,
|
|
28304
29258
|
height: "100%",
|
|
28305
29259
|
flexDirection: "column",
|
|
28306
|
-
|
|
29260
|
+
onMouseDown: () => setTerminalFocused(false),
|
|
29261
|
+
children: /* @__PURE__ */ jsx17(WorktreeTable, {
|
|
28307
29262
|
blocks: displayBlocks,
|
|
28308
29263
|
selectedIndex,
|
|
28309
29264
|
selection,
|
|
28310
29265
|
frame: spinnerFrame,
|
|
28311
29266
|
repoVerbs,
|
|
28312
29267
|
rowVerbs,
|
|
28313
|
-
onRowClick: (idx) =>
|
|
29268
|
+
onRowClick: (idx) => {
|
|
29269
|
+
setTerminalFocused(false);
|
|
29270
|
+
setSelectedIndex(idx);
|
|
29271
|
+
},
|
|
28314
29272
|
onToggleSelect: (path37) => setSelection((prev) => toggleSelection(prev, path37))
|
|
28315
29273
|
})
|
|
28316
29274
|
}),
|
|
28317
|
-
/* @__PURE__ */
|
|
29275
|
+
/* @__PURE__ */ jsx17(Divider, {
|
|
28318
29276
|
splitRatio,
|
|
28319
29277
|
totalWidth,
|
|
28320
29278
|
onChange: setSplitRatio,
|
|
28321
29279
|
onDraggingChange: setIsResizing
|
|
28322
29280
|
}),
|
|
28323
|
-
/* @__PURE__ */
|
|
29281
|
+
/* @__PURE__ */ jsx17("box", {
|
|
28324
29282
|
width: rightCols,
|
|
28325
29283
|
height: "100%",
|
|
28326
29284
|
flexDirection: "column",
|
|
28327
|
-
children: /* @__PURE__ */
|
|
28328
|
-
selectedRow
|
|
29285
|
+
children: /* @__PURE__ */ jsx17(TabPane, {
|
|
29286
|
+
selectedRow,
|
|
29287
|
+
tabs: tabsForSelected,
|
|
29288
|
+
activeId: activeTabId,
|
|
29289
|
+
focused: terminalFocused && tabsForSelected.some((t) => t.id === activeTabId && t.id !== "details"),
|
|
29290
|
+
canAdd: sessionsForSelected.length < MAX_TERMINAL_SESSIONS,
|
|
29291
|
+
onSelect: handleSelectTab,
|
|
29292
|
+
onAdd: handleAddSession,
|
|
29293
|
+
onClose: handleCloseSession,
|
|
29294
|
+
allSessionsFlat,
|
|
29295
|
+
terminalFocused,
|
|
29296
|
+
activeTabId,
|
|
29297
|
+
terminalSessions
|
|
28329
29298
|
})
|
|
28330
29299
|
})
|
|
28331
29300
|
]
|
|
28332
29301
|
}),
|
|
28333
|
-
isFiltering && /* @__PURE__ */
|
|
29302
|
+
isFiltering && /* @__PURE__ */ jsxs15("box", {
|
|
28334
29303
|
flexDirection: "row",
|
|
28335
29304
|
paddingX: 1,
|
|
28336
29305
|
border: true,
|
|
28337
29306
|
borderColor: "magenta",
|
|
28338
29307
|
children: [
|
|
28339
|
-
/* @__PURE__ */
|
|
29308
|
+
/* @__PURE__ */ jsx17("text", {
|
|
28340
29309
|
children: "filter: "
|
|
28341
29310
|
}),
|
|
28342
|
-
/* @__PURE__ */
|
|
29311
|
+
/* @__PURE__ */ jsx17("input", {
|
|
28343
29312
|
focused: true,
|
|
28344
29313
|
placeholder: "Type to filter...",
|
|
28345
29314
|
onInput: (v) => setFilterText(v)
|
|
28346
29315
|
})
|
|
28347
29316
|
]
|
|
28348
29317
|
}),
|
|
28349
|
-
/* @__PURE__ */
|
|
29318
|
+
/* @__PURE__ */ jsx17(Footer, {
|
|
28350
29319
|
loading: loading || refreshing,
|
|
28351
29320
|
lastRefreshed,
|
|
28352
29321
|
errorCount: warnings.length,
|
|
@@ -28357,9 +29326,9 @@ function App({ opts }) {
|
|
|
28357
29326
|
onHintClick: handleHintClick,
|
|
28358
29327
|
onErrorClick: () => setModal({ type: "warnings" })
|
|
28359
29328
|
}),
|
|
28360
|
-
modal.type === "help" && /* @__PURE__ */
|
|
28361
|
-
modal.type === "history" && /* @__PURE__ */
|
|
28362
|
-
modal.type === "warnings" && /* @__PURE__ */
|
|
29329
|
+
modal.type === "help" && /* @__PURE__ */ jsx17(HelpOverlay, {}),
|
|
29330
|
+
modal.type === "history" && /* @__PURE__ */ jsx17(HistoryOverlay, {}),
|
|
29331
|
+
modal.type === "warnings" && /* @__PURE__ */ jsx17(WarningsOverlay, {
|
|
28363
29332
|
warnings,
|
|
28364
29333
|
onAcknowledge: () => {
|
|
28365
29334
|
clearWarnings();
|
|
@@ -28367,7 +29336,7 @@ function App({ opts }) {
|
|
|
28367
29336
|
},
|
|
28368
29337
|
onClose: () => setModal({ type: "none" })
|
|
28369
29338
|
}),
|
|
28370
|
-
modal.type === "error" && /* @__PURE__ */
|
|
29339
|
+
modal.type === "error" && /* @__PURE__ */ jsx17(ConfirmModal, {
|
|
28371
29340
|
title: "Error",
|
|
28372
29341
|
message: modal.message,
|
|
28373
29342
|
onConfirm: () => {
|
|
@@ -28385,7 +29354,7 @@ function App({ opts }) {
|
|
|
28385
29354
|
}
|
|
28386
29355
|
}
|
|
28387
29356
|
}),
|
|
28388
|
-
modal.type === "confirm_remove" && /* @__PURE__ */
|
|
29357
|
+
modal.type === "confirm_remove" && /* @__PURE__ */ jsx17(ConfirmModal, {
|
|
28389
29358
|
title: `Remove ${modal.rows.length} Worktree(s)`,
|
|
28390
29359
|
message: (() => {
|
|
28391
29360
|
const count2 = modal.rows.length;
|
|
@@ -28414,7 +29383,7 @@ function App({ opts }) {
|
|
|
28414
29383
|
},
|
|
28415
29384
|
onCancel: () => setModal({ type: "none" })
|
|
28416
29385
|
}),
|
|
28417
|
-
modal.type === "confirm_rebase" && /* @__PURE__ */
|
|
29386
|
+
modal.type === "confirm_rebase" && /* @__PURE__ */ jsx17(ConfirmModal, {
|
|
28418
29387
|
title: `Rebase ${modal.rows.length} Worktree(s)`,
|
|
28419
29388
|
message: `Are you sure you want to fetch and rebase ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}?`,
|
|
28420
29389
|
onConfirm: () => {
|
|
@@ -28424,7 +29393,7 @@ function App({ opts }) {
|
|
|
28424
29393
|
},
|
|
28425
29394
|
onCancel: () => setModal({ type: "none" })
|
|
28426
29395
|
}),
|
|
28427
|
-
modal.type === "confirm_sync" && /* @__PURE__ */
|
|
29396
|
+
modal.type === "confirm_sync" && /* @__PURE__ */ jsx17(ConfirmModal, {
|
|
28428
29397
|
title: `Sync ${modal.rows.length} Worktree(s)`,
|
|
28429
29398
|
message: `Are you sure you want to sync ${modal.rows.length === 1 ? modal.rows[0]?.branch : modal.rows.length + " worktrees"}?`,
|
|
28430
29399
|
onConfirm: () => {
|
|
@@ -28434,7 +29403,7 @@ function App({ opts }) {
|
|
|
28434
29403
|
},
|
|
28435
29404
|
onCancel: () => setModal({ type: "none" })
|
|
28436
29405
|
}),
|
|
28437
|
-
createModal && /* @__PURE__ */
|
|
29406
|
+
createModal && /* @__PURE__ */ jsx17(InputModal, {
|
|
28438
29407
|
title: `New worktree branch in ${selectedRow?.repoName ?? ""}`,
|
|
28439
29408
|
placeholder: "Branch name (empty to cancel)",
|
|
28440
29409
|
errorMessage: createError,
|
|
@@ -28461,7 +29430,7 @@ function App({ opts }) {
|
|
|
28461
29430
|
setCreateBaseModal({ branch, repoName });
|
|
28462
29431
|
}
|
|
28463
29432
|
}),
|
|
28464
|
-
createBaseModal && /* @__PURE__ */
|
|
29433
|
+
createBaseModal && /* @__PURE__ */ jsx17(InputModal, {
|
|
28465
29434
|
title: `Base ref for ${createBaseModal.branch}`,
|
|
28466
29435
|
placeholder: "origin/main (empty for default main)",
|
|
28467
29436
|
errorMessage: createBaseError,
|
|
@@ -28477,7 +29446,7 @@ function App({ opts }) {
|
|
|
28477
29446
|
setCreateDepsChoice({ branch, repoName, base: base2 || undefined });
|
|
28478
29447
|
}
|
|
28479
29448
|
}),
|
|
28480
|
-
createDepsChoice && /* @__PURE__ */
|
|
29449
|
+
createDepsChoice && /* @__PURE__ */ jsx17(ChoiceModal, {
|
|
28481
29450
|
title: `Dependencies for ${createDepsChoice.branch}`,
|
|
28482
29451
|
options: DEPS_CHOICES,
|
|
28483
29452
|
onSubmit: (choice) => {
|
|
@@ -28487,7 +29456,7 @@ function App({ opts }) {
|
|
|
28487
29456
|
},
|
|
28488
29457
|
onCancel: () => setCreateDepsChoice(null)
|
|
28489
29458
|
}),
|
|
28490
|
-
pullPrModal && /* @__PURE__ */
|
|
29459
|
+
pullPrModal && /* @__PURE__ */ jsx17(InputModal, {
|
|
28491
29460
|
title: `Pull PR into ${selectedRow?.repoName ?? ""}`,
|
|
28492
29461
|
placeholder: "https://github.com/owner/repo/pull/123",
|
|
28493
29462
|
errorMessage: pullPrError,
|
|
@@ -28515,7 +29484,7 @@ function App({ opts }) {
|
|
|
28515
29484
|
setPullForceChoice({ link, repoName });
|
|
28516
29485
|
}
|
|
28517
29486
|
}),
|
|
28518
|
-
pullForceChoice && /* @__PURE__ */
|
|
29487
|
+
pullForceChoice && /* @__PURE__ */ jsx17(ChoiceModal, {
|
|
28519
29488
|
title: `Pull ${pullForceChoice.link.split("/").pop()}?`,
|
|
28520
29489
|
options: [
|
|
28521
29490
|
{ value: "normal", label: "Pull (skip if exists)", desc: "Fails if branch already exists" },
|
|
@@ -28528,7 +29497,7 @@ function App({ opts }) {
|
|
|
28528
29497
|
},
|
|
28529
29498
|
onCancel: () => setPullForceChoice(null)
|
|
28530
29499
|
}),
|
|
28531
|
-
renameModal && selectedRow && /* @__PURE__ */
|
|
29500
|
+
renameModal && selectedRow && /* @__PURE__ */ jsx17(InputModal, {
|
|
28532
29501
|
title: `Rename branch ${selectedRow.branch}`,
|
|
28533
29502
|
initialValue: selectedRow.branch,
|
|
28534
29503
|
placeholder: "New branch name",
|
|
@@ -28553,7 +29522,7 @@ function App({ opts }) {
|
|
|
28553
29522
|
setModal({ type: "confirm_rename", row: target, to });
|
|
28554
29523
|
}
|
|
28555
29524
|
}),
|
|
28556
|
-
modal.type === "confirm_rename" && /* @__PURE__ */
|
|
29525
|
+
modal.type === "confirm_rename" && /* @__PURE__ */ jsx17(ConfirmModal, {
|
|
28557
29526
|
title: "Rename Worktree",
|
|
28558
29527
|
message: [
|
|
28559
29528
|
`${modal.row.branch} → ${modal.to}`,
|
|
@@ -28584,12 +29553,12 @@ function App({ opts }) {
|
|
|
28584
29553
|
},
|
|
28585
29554
|
onCancel: () => setModal({ type: "none" })
|
|
28586
29555
|
}),
|
|
28587
|
-
configOpen && /* @__PURE__ */
|
|
29556
|
+
configOpen && /* @__PURE__ */ jsx17(ConfigOverlay, {
|
|
28588
29557
|
onClose: () => setConfigOpen(false),
|
|
28589
29558
|
onSaved: () => void doRefresh(),
|
|
28590
29559
|
onError: (msg) => setModal({ type: "error", message: msg })
|
|
28591
29560
|
}),
|
|
28592
|
-
failedLogs.length > 0 && /* @__PURE__ */
|
|
29561
|
+
failedLogs.length > 0 && /* @__PURE__ */ jsx17(ActionLogModal, {
|
|
28593
29562
|
title: failedLogs[0].title,
|
|
28594
29563
|
lines: failedLogs[0].lines,
|
|
28595
29564
|
done: true,
|
|
@@ -28603,7 +29572,8 @@ var VERBS, capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1), DEPS_CHOI
|
|
|
28603
29572
|
var init_App = __esm(() => {
|
|
28604
29573
|
init_useWorktrees();
|
|
28605
29574
|
init_WorktreeTable();
|
|
28606
|
-
|
|
29575
|
+
init_TabPane();
|
|
29576
|
+
init_DetailsTab();
|
|
28607
29577
|
init_Footer();
|
|
28608
29578
|
init_Divider();
|
|
28609
29579
|
init_HelpOverlay();
|
|
@@ -28616,10 +29586,9 @@ var init_App = __esm(() => {
|
|
|
28616
29586
|
init_ConfigOverlay();
|
|
28617
29587
|
init_WarningsOverlay();
|
|
28618
29588
|
init_utils();
|
|
28619
|
-
init_agents();
|
|
28620
29589
|
init_config();
|
|
28621
|
-
init_history();
|
|
28622
29590
|
init_useSpinnerFrame();
|
|
29591
|
+
init_useTerminalSessions();
|
|
28623
29592
|
VERBS = {
|
|
28624
29593
|
create: "creating worktree",
|
|
28625
29594
|
remove: "deleting",
|
|
@@ -28643,27 +29612,103 @@ var exports_tui = {};
|
|
|
28643
29612
|
__export(exports_tui, {
|
|
28644
29613
|
runTerminal: () => runTerminal
|
|
28645
29614
|
});
|
|
28646
|
-
import { createCliRenderer, TextTableRenderable } from "@opentui/core";
|
|
29615
|
+
import { createCliRenderer, TextTableRenderable, EmbeddedTerminalRenderable } from "@opentui/core";
|
|
28647
29616
|
import { createRoot, extend as extend2 } from "@opentui/react";
|
|
28648
|
-
import { jsx as
|
|
29617
|
+
import { jsx as jsx18 } from "@opentui/react/jsx-runtime";
|
|
28649
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 {}
|
|
28650
29670
|
const renderer = await createCliRenderer({
|
|
28651
|
-
exitOnCtrlC: false
|
|
28652
|
-
|
|
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
|
+
};
|
|
28653
29690
|
const root = createRoot(renderer);
|
|
28654
29691
|
try {
|
|
28655
|
-
root.render(/* @__PURE__ */
|
|
29692
|
+
root.render(/* @__PURE__ */ jsx18(App, {
|
|
28656
29693
|
opts
|
|
28657
29694
|
}));
|
|
28658
29695
|
} catch (err) {
|
|
29696
|
+
restoreConsole();
|
|
28659
29697
|
renderer.destroy();
|
|
28660
29698
|
console.error("Failed to render TUI:", err);
|
|
28661
29699
|
process.exit(1);
|
|
28662
29700
|
}
|
|
29701
|
+
const originalDestroy = renderer.destroy.bind(renderer);
|
|
29702
|
+
renderer.destroy = () => {
|
|
29703
|
+
restoreConsole();
|
|
29704
|
+
return originalDestroy();
|
|
29705
|
+
};
|
|
28663
29706
|
}
|
|
28664
29707
|
var init_tui = __esm(() => {
|
|
29708
|
+
init_env();
|
|
28665
29709
|
init_App();
|
|
28666
|
-
|
|
29710
|
+
init_log();
|
|
29711
|
+
extend2({ "text-table": TextTableRenderable, "embedded-terminal": EmbeddedTerminalRenderable });
|
|
28667
29712
|
});
|
|
28668
29713
|
|
|
28669
29714
|
// node_modules/commander/lib/error.js
|
|
@@ -31002,7 +32047,80 @@ async function runPostCreateSetup(params) {
|
|
|
31002
32047
|
init_deps();
|
|
31003
32048
|
init_forge();
|
|
31004
32049
|
init_owner();
|
|
31005
|
-
|
|
32050
|
+
|
|
32051
|
+
// src/lib/agents.ts
|
|
32052
|
+
init_execa();
|
|
32053
|
+
var DEFAULT_AGENTS = {
|
|
32054
|
+
claude: "claude",
|
|
32055
|
+
codex: "codex",
|
|
32056
|
+
opencode: "opencode",
|
|
32057
|
+
cursor: "cursor"
|
|
32058
|
+
};
|
|
32059
|
+
function resolveAgentCommand(name, configured) {
|
|
32060
|
+
return configured?.[name]?.command ?? DEFAULT_AGENTS[name] ?? null;
|
|
32061
|
+
}
|
|
32062
|
+
function listAvailableAgents(configured) {
|
|
32063
|
+
return [...new Set([...Object.keys(DEFAULT_AGENTS), ...Object.keys(configured ?? {})])];
|
|
32064
|
+
}
|
|
32065
|
+
var tmuxAvailable = undefined;
|
|
32066
|
+
async function isTmuxAvailable() {
|
|
32067
|
+
if (tmuxAvailable !== undefined)
|
|
32068
|
+
return tmuxAvailable;
|
|
32069
|
+
try {
|
|
32070
|
+
await execa("tmux", ["-V"]);
|
|
32071
|
+
tmuxAvailable = true;
|
|
32072
|
+
} catch {
|
|
32073
|
+
tmuxAvailable = false;
|
|
32074
|
+
}
|
|
32075
|
+
return tmuxAvailable;
|
|
32076
|
+
}
|
|
32077
|
+
function tmuxSessionName(repoName, branch) {
|
|
32078
|
+
const sanitized = `${repoName}-${branch}`.replace(/[\/.:]/g, "-");
|
|
32079
|
+
return `wtx-${sanitized}`.substring(0, 60);
|
|
32080
|
+
}
|
|
32081
|
+
function buildTmuxArgs(session, wtPath, cmd) {
|
|
32082
|
+
return ["new-session", "-d", "-s", session, "-c", wtPath, cmd];
|
|
32083
|
+
}
|
|
32084
|
+
async function spawnAgentInWorktree(commandTemplate, wtPath, opts = {}) {
|
|
32085
|
+
const cmd = buildAgentCommand(commandTemplate, wtPath, opts.prompt, {
|
|
32086
|
+
branch: opts.branch,
|
|
32087
|
+
repo: opts.repoName
|
|
32088
|
+
});
|
|
32089
|
+
const session = opts.repoName && opts.branch ? tmuxSessionName(opts.repoName, opts.branch) : undefined;
|
|
32090
|
+
if (opts.dryRun) {
|
|
32091
|
+
if (session && await isTmuxAvailable()) {
|
|
32092
|
+
return { mode: "tmux", session };
|
|
32093
|
+
}
|
|
32094
|
+
return { mode: "direct" };
|
|
32095
|
+
}
|
|
32096
|
+
if (session && await isTmuxAvailable()) {
|
|
32097
|
+
try {
|
|
32098
|
+
const args = buildTmuxArgs(session, wtPath, cmd);
|
|
32099
|
+
await execa("tmux", args, { stdio: "inherit" });
|
|
32100
|
+
return { mode: "tmux", session };
|
|
32101
|
+
} catch {}
|
|
32102
|
+
}
|
|
32103
|
+
await execa(cmd, { shell: true, cwd: wtPath, stdio: "inherit" });
|
|
32104
|
+
return { mode: "direct" };
|
|
32105
|
+
}
|
|
32106
|
+
function shellQuote(value) {
|
|
32107
|
+
return `'${value.replaceAll("'", `'''`)}'`;
|
|
32108
|
+
}
|
|
32109
|
+
function buildAgentCommand(commandTemplate, wtPath, prompt, vars) {
|
|
32110
|
+
let cmd = commandTemplate.replaceAll("{wt}", shellQuote(wtPath));
|
|
32111
|
+
if (vars?.branch) {
|
|
32112
|
+
cmd = cmd.replaceAll("{branch}", shellQuote(vars.branch));
|
|
32113
|
+
}
|
|
32114
|
+
if (vars?.repo) {
|
|
32115
|
+
cmd = cmd.replaceAll("{repo}", shellQuote(vars.repo));
|
|
32116
|
+
}
|
|
32117
|
+
if (prompt) {
|
|
32118
|
+
cmd += ` ${shellQuote(prompt)}`;
|
|
32119
|
+
}
|
|
32120
|
+
return cmd;
|
|
32121
|
+
}
|
|
32122
|
+
|
|
32123
|
+
// src/commands/create.ts
|
|
31006
32124
|
var DEPS_STRATEGIES = ["auto", "link", "symlink", "install", "off"];
|
|
31007
32125
|
async function applyDepsStrategy(strategy, wtPath, mainPath, opts) {
|
|
31008
32126
|
if (strategy === "install") {
|
|
@@ -33565,6 +34683,10 @@ function registerTerminalCommand(program2) {
|
|
|
33565
34683
|
`);
|
|
33566
34684
|
process.exit(1);
|
|
33567
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";
|
|
33568
34690
|
const { runTerminal: runTerminal2 } = await Promise.resolve().then(() => (init_tui(), exports_tui));
|
|
33569
34691
|
await runTerminal2(opts);
|
|
33570
34692
|
});
|