@phenx-inc/ctlsurf 0.15.2 → 0.16.1
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/out/headless/index.mjs +10 -3
- package/out/headless/index.mjs.map +2 -2
- package/out/main/index.js +54 -4
- package/out/preload/index.js +2 -0
- package/out/renderer/assets/{cssMode-CPfLk04b.js → cssMode-DwHD6JSn.js} +3 -3
- package/out/renderer/assets/{freemarker2-CDHpuFqv.js → freemarker2-Na9-bXYw.js} +1 -1
- package/out/renderer/assets/{handlebars-CgX9Jz36.js → handlebars-D7gzKLS8.js} +1 -1
- package/out/renderer/assets/{html-DdgFccDG.js → html-DDK7xN27.js} +1 -1
- package/out/renderer/assets/{htmlMode-CRHIwtvP.js → htmlMode-BfbLv-NB.js} +3 -3
- package/out/renderer/assets/{index-3sFJEz7i.css → index-DID1LlMU.css} +88 -0
- package/out/renderer/assets/{index-DVdWgw7p.js → index-HoDaBul3.js} +340 -96
- package/out/renderer/assets/{javascript-CHhxL0s7.js → javascript-DJjWOxID.js} +2 -2
- package/out/renderer/assets/{jsonMode-Cy7-eWai.js → jsonMode-BileWbig.js} +3 -3
- package/out/renderer/assets/{liquid-vMkF9pfk.js → liquid-DvNU_dI9.js} +1 -1
- package/out/renderer/assets/{lspLanguageFeatures-nAygNzuG.js → lspLanguageFeatures-Bb27EY8c.js} +1 -1
- package/out/renderer/assets/{mdx-C4UVz5dW.js → mdx-CLkNPVgD.js} +1 -1
- package/out/renderer/assets/{python-BHemzN9g.js → python-DOJdL4kC.js} +1 -1
- package/out/renderer/assets/{razor-DH6NPzbo.js → razor-CSr8UlJc.js} +1 -1
- package/out/renderer/assets/{tsMode-DxBdlGZB.js → tsMode-sbsAvk21.js} +1 -1
- package/out/renderer/assets/{typescript-BRCOaBQ5.js → typescript-r5QB4yRW.js} +1 -1
- package/out/renderer/assets/{xml-DVv9gDP1.js → xml-CYhKh3Pi.js} +1 -1
- package/out/renderer/assets/{yaml-jB-C3CdS.js → yaml-B8DsoaYW.js} +1 -1
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
- package/scripts/test-terminal-scroll.cjs +64 -0
- package/src/main/index.ts +52 -1
- package/src/main/orchestrator.ts +18 -3
- package/src/preload/index.ts +4 -0
- package/src/renderer/App.tsx +179 -50
- package/src/renderer/components/AgentPicker.tsx +61 -10
- package/src/renderer/components/ProjectPicker.tsx +44 -13
- package/src/renderer/components/TerminalPanel.tsx +88 -27
- package/src/renderer/styles.css +88 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-DwHD6JSn.js","./lspLanguageFeatures-Bb27EY8c.js","./htmlMode-BfbLv-NB.js","./jsonMode-BileWbig.js","./javascript-DJjWOxID.js","./typescript-r5QB4yRW.js"])))=>i.map(i=>d[i]);
|
|
2
2
|
function getDefaultExportFromCjs(x) {
|
|
3
3
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
4
4
|
}
|
|
@@ -19525,6 +19525,20 @@ function markGesture(tabId) {
|
|
|
19525
19525
|
const s = _terminals.get(tabId);
|
|
19526
19526
|
if (s) s.userScrollPending = true;
|
|
19527
19527
|
}
|
|
19528
|
+
function followLatest(state) {
|
|
19529
|
+
state.userScrollPending = false;
|
|
19530
|
+
setPinned(state, true);
|
|
19531
|
+
reassert(state);
|
|
19532
|
+
}
|
|
19533
|
+
function rememberScrollPosition(state) {
|
|
19534
|
+
state.userScrollPending = false;
|
|
19535
|
+
if (isAtBottom(state.terminal)) {
|
|
19536
|
+
setPinned(state, true);
|
|
19537
|
+
} else {
|
|
19538
|
+
state.anchorLine = state.terminal.buffer.active.viewportY;
|
|
19539
|
+
setPinned(state, false);
|
|
19540
|
+
}
|
|
19541
|
+
}
|
|
19528
19542
|
function getOrCreateTerminal(tabId, onExit) {
|
|
19529
19543
|
const existing = _terminals.get(tabId);
|
|
19530
19544
|
if (existing) {
|
|
@@ -19550,7 +19564,9 @@ function getOrCreateTerminal(tabId, onExit) {
|
|
|
19550
19564
|
fontFamily: "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', monospace",
|
|
19551
19565
|
theme: currentTheme().terminal,
|
|
19552
19566
|
scrollback: 1e4,
|
|
19553
|
-
|
|
19567
|
+
// Follow explicit keyboard/paste input below. xterm also counts mouse
|
|
19568
|
+
// reports as user input, which must not pull someone out of scrollback.
|
|
19569
|
+
scrollOnUserInput: false,
|
|
19554
19570
|
allowTransparency: false
|
|
19555
19571
|
});
|
|
19556
19572
|
const fitAddon = new addonFitExports.FitAddon();
|
|
@@ -19599,7 +19615,7 @@ function getOrCreateTerminal(tabId, onExit) {
|
|
|
19599
19615
|
fitAddon,
|
|
19600
19616
|
unsubData: null,
|
|
19601
19617
|
unsubExit: null,
|
|
19602
|
-
|
|
19618
|
+
spawnedSessionKey: null,
|
|
19603
19619
|
pinnedToBottom: true,
|
|
19604
19620
|
anchorLine: null,
|
|
19605
19621
|
userScrollPending: false,
|
|
@@ -19612,17 +19628,10 @@ function getOrCreateTerminal(tabId, onExit) {
|
|
|
19612
19628
|
reassert(state);
|
|
19613
19629
|
return;
|
|
19614
19630
|
}
|
|
19615
|
-
state
|
|
19616
|
-
if (isAtBottom(terminal)) {
|
|
19617
|
-
setPinned(state, true);
|
|
19618
|
-
} else {
|
|
19619
|
-
state.anchorLine = terminal.buffer.active.viewportY;
|
|
19620
|
-
setPinned(state, false);
|
|
19621
|
-
}
|
|
19631
|
+
rememberScrollPosition(state);
|
|
19622
19632
|
});
|
|
19633
|
+
terminal.onKey(() => followLatest(state));
|
|
19623
19634
|
terminal.onData((data) => {
|
|
19624
|
-
setPinned(state, true);
|
|
19625
|
-
terminal.scrollToBottom();
|
|
19626
19635
|
window.worker.writePty(tabId, data);
|
|
19627
19636
|
});
|
|
19628
19637
|
state.unsubData = window.worker.onPtyData((eventTabId, data) => {
|
|
@@ -19643,6 +19652,25 @@ function getOrCreateTerminal(tabId, onExit) {
|
|
|
19643
19652
|
function focusTerminal(tabId) {
|
|
19644
19653
|
_terminals.get(tabId)?.terminal.focus();
|
|
19645
19654
|
}
|
|
19655
|
+
const MAX_HANDOFF_CHARS = 1e6;
|
|
19656
|
+
function captureTerminalSession(tabId) {
|
|
19657
|
+
const terminal = _terminals.get(tabId)?.terminal;
|
|
19658
|
+
if (!terminal) return "";
|
|
19659
|
+
const buffer = terminal.buffer.active;
|
|
19660
|
+
const lines = [];
|
|
19661
|
+
for (let i2 = 0; i2 < buffer.length; i2++) {
|
|
19662
|
+
const line = buffer.getLine(i2);
|
|
19663
|
+
if (!line) continue;
|
|
19664
|
+
const text22 = line.translateToString(true);
|
|
19665
|
+
if (line.isWrapped && lines.length > 0) lines[lines.length - 1] += text22;
|
|
19666
|
+
else lines.push(text22);
|
|
19667
|
+
}
|
|
19668
|
+
while (lines.length && lines[lines.length - 1].trim() === "") lines.pop();
|
|
19669
|
+
const text2 = lines.join("\n").trim();
|
|
19670
|
+
if (text2.length <= MAX_HANDOFF_CHARS) return text2;
|
|
19671
|
+
return `[Earlier terminal output omitted; showing the last ${MAX_HANDOFF_CHARS.toLocaleString()} characters.]
|
|
19672
|
+
${text2.slice(-MAX_HANDOFF_CHARS)}`;
|
|
19673
|
+
}
|
|
19646
19674
|
function destroyTerminal(tabId) {
|
|
19647
19675
|
const state = _terminals.get(tabId);
|
|
19648
19676
|
if (!state) return;
|
|
@@ -19651,7 +19679,7 @@ function destroyTerminal(tabId) {
|
|
|
19651
19679
|
state.terminal.dispose();
|
|
19652
19680
|
_terminals.delete(tabId);
|
|
19653
19681
|
}
|
|
19654
|
-
function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
|
|
19682
|
+
function TerminalPanel({ tabId, agent, sessionVersion, onSpawn, onExit, isActive }) {
|
|
19655
19683
|
const containerRef = reactExports.useRef(null);
|
|
19656
19684
|
const [menu, setMenu] = reactExports.useState(null);
|
|
19657
19685
|
const [snapOpen, setSnapOpen] = reactExports.useState(false);
|
|
@@ -19661,8 +19689,7 @@ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
|
|
|
19661
19689
|
const jumpToLatest = () => {
|
|
19662
19690
|
const s = _terminals.get(tabId);
|
|
19663
19691
|
if (!s) return;
|
|
19664
|
-
|
|
19665
|
-
s.terminal.scrollToBottom();
|
|
19692
|
+
followLatest(s);
|
|
19666
19693
|
s.terminal.focus();
|
|
19667
19694
|
};
|
|
19668
19695
|
const handleContextMenu = (e) => {
|
|
@@ -19742,6 +19769,22 @@ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
|
|
|
19742
19769
|
if (attached) reassert(attached);
|
|
19743
19770
|
const onWheel = () => markGesture(tabId);
|
|
19744
19771
|
terminal.element?.addEventListener("wheel", onWheel, { capture: true, passive: true });
|
|
19772
|
+
const viewport = terminal.element?.querySelector(".xterm-viewport");
|
|
19773
|
+
const onViewportScroll = () => {
|
|
19774
|
+
const state = _terminals.get(tabId);
|
|
19775
|
+
if (state && !state.holding && state.userScrollPending) rememberScrollPosition(state);
|
|
19776
|
+
};
|
|
19777
|
+
viewport?.addEventListener("scroll", onViewportScroll);
|
|
19778
|
+
const onTextInput = () => {
|
|
19779
|
+
const state = _terminals.get(tabId);
|
|
19780
|
+
if (state) followLatest(state);
|
|
19781
|
+
};
|
|
19782
|
+
const onPaste = (event) => {
|
|
19783
|
+
if (event.clipboardData?.getData("text/plain")) onTextInput();
|
|
19784
|
+
};
|
|
19785
|
+
terminal.textarea?.addEventListener("paste", onPaste, true);
|
|
19786
|
+
terminal.textarea?.addEventListener("input", onTextInput, true);
|
|
19787
|
+
terminal.textarea?.addEventListener("compositionend", onTextInput, true);
|
|
19745
19788
|
let resizeTimeout;
|
|
19746
19789
|
const handleResize = () => {
|
|
19747
19790
|
clearTimeout(resizeTimeout);
|
|
@@ -19765,14 +19808,19 @@ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
|
|
|
19765
19808
|
window.removeEventListener("resize", handleResize);
|
|
19766
19809
|
observer.disconnect();
|
|
19767
19810
|
terminal.element?.removeEventListener("wheel", onWheel, true);
|
|
19811
|
+
viewport?.removeEventListener("scroll", onViewportScroll);
|
|
19812
|
+
terminal.textarea?.removeEventListener("paste", onPaste, true);
|
|
19813
|
+
terminal.textarea?.removeEventListener("input", onTextInput, true);
|
|
19814
|
+
terminal.textarea?.removeEventListener("compositionend", onTextInput, true);
|
|
19768
19815
|
};
|
|
19769
19816
|
}, [tabId, onExit]);
|
|
19770
19817
|
reactExports.useEffect(() => {
|
|
19771
19818
|
if (!agent) return;
|
|
19772
19819
|
const state = _terminals.get(tabId);
|
|
19773
19820
|
if (!state) return;
|
|
19774
|
-
|
|
19775
|
-
state.
|
|
19821
|
+
const sessionKey = `${agent.id}:${sessionVersion}`;
|
|
19822
|
+
if (state.spawnedSessionKey === sessionKey) return;
|
|
19823
|
+
state.spawnedSessionKey = sessionKey;
|
|
19776
19824
|
state.terminal.clear();
|
|
19777
19825
|
onSpawn(tabId, agent).then(() => {
|
|
19778
19826
|
const s = _terminals.get(tabId);
|
|
@@ -19785,7 +19833,7 @@ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
|
|
|
19785
19833
|
}
|
|
19786
19834
|
state.terminal.focus();
|
|
19787
19835
|
});
|
|
19788
|
-
}, [tabId, agent, onSpawn]);
|
|
19836
|
+
}, [tabId, agent, sessionVersion, onSpawn]);
|
|
19789
19837
|
reactExports.useEffect(() => {
|
|
19790
19838
|
if (isActive) {
|
|
19791
19839
|
window.worker.setActiveTab(tabId);
|
|
@@ -208423,7 +208471,7 @@ const lessDefaults = new LanguageServiceDefaultsImpl$3(
|
|
|
208423
208471
|
modeConfigurationDefault$2
|
|
208424
208472
|
);
|
|
208425
208473
|
function getMode$3() {
|
|
208426
|
-
return __vitePreload(() => import("./cssMode-
|
|
208474
|
+
return __vitePreload(() => import("./cssMode-DwHD6JSn.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
|
|
208427
208475
|
}
|
|
208428
208476
|
languages.onLanguage("less", () => {
|
|
208429
208477
|
getMode$3().then((mode2) => mode2.setupMode(lessDefaults));
|
|
@@ -208528,7 +208576,7 @@ const razorLanguageService = registerHTMLLanguageService(
|
|
|
208528
208576
|
);
|
|
208529
208577
|
const razorDefaults = razorLanguageService.defaults;
|
|
208530
208578
|
function getMode$2() {
|
|
208531
|
-
return __vitePreload(() => import("./htmlMode-
|
|
208579
|
+
return __vitePreload(() => import("./htmlMode-BfbLv-NB.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
|
|
208532
208580
|
}
|
|
208533
208581
|
function registerHTMLLanguageService(languageId, options = optionsDefault, modeConfiguration = getConfigurationDefault(languageId)) {
|
|
208534
208582
|
const defaults = new LanguageServiceDefaultsImpl$2(languageId, options, modeConfiguration);
|
|
@@ -208612,7 +208660,7 @@ const jsonDefaults = new LanguageServiceDefaultsImpl$1(
|
|
|
208612
208660
|
);
|
|
208613
208661
|
const getWorker$1 = () => getMode$1().then((mode2) => mode2.getWorker());
|
|
208614
208662
|
function getMode$1() {
|
|
208615
|
-
return __vitePreload(() => import("./jsonMode-
|
|
208663
|
+
return __vitePreload(() => import("./jsonMode-BileWbig.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
|
|
208616
208664
|
}
|
|
208617
208665
|
languages.register({
|
|
208618
208666
|
id: "json",
|
|
@@ -208858,7 +208906,7 @@ const getJavaScriptWorker = () => {
|
|
|
208858
208906
|
return getMode().then((mode) => mode.getJavaScriptWorker());
|
|
208859
208907
|
};
|
|
208860
208908
|
function getMode() {
|
|
208861
|
-
return __vitePreload(() => import("./tsMode-
|
|
208909
|
+
return __vitePreload(() => import("./tsMode-sbsAvk21.js"), true ? [] : void 0, import.meta.url);
|
|
208862
208910
|
}
|
|
208863
208911
|
languages.onLanguage("typescript", () => {
|
|
208864
208912
|
return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
|
|
@@ -209053,49 +209101,49 @@ registerLanguage({
|
|
|
209053
209101
|
extensions: [".ftl", ".ftlh", ".ftlx"],
|
|
209054
209102
|
aliases: ["FreeMarker2", "Apache FreeMarker2"],
|
|
209055
209103
|
loader: () => {
|
|
209056
|
-
return __vitePreload(() => import("./freemarker2-
|
|
209104
|
+
return __vitePreload(() => import("./freemarker2-Na9-bXYw.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
|
|
209057
209105
|
}
|
|
209058
209106
|
});
|
|
209059
209107
|
registerLanguage({
|
|
209060
209108
|
id: "freemarker2.tag-angle.interpolation-dollar",
|
|
209061
209109
|
aliases: ["FreeMarker2 (Angle/Dollar)", "Apache FreeMarker2 (Angle/Dollar)"],
|
|
209062
209110
|
loader: () => {
|
|
209063
|
-
return __vitePreload(() => import("./freemarker2-
|
|
209111
|
+
return __vitePreload(() => import("./freemarker2-Na9-bXYw.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
|
|
209064
209112
|
}
|
|
209065
209113
|
});
|
|
209066
209114
|
registerLanguage({
|
|
209067
209115
|
id: "freemarker2.tag-bracket.interpolation-dollar",
|
|
209068
209116
|
aliases: ["FreeMarker2 (Bracket/Dollar)", "Apache FreeMarker2 (Bracket/Dollar)"],
|
|
209069
209117
|
loader: () => {
|
|
209070
|
-
return __vitePreload(() => import("./freemarker2-
|
|
209118
|
+
return __vitePreload(() => import("./freemarker2-Na9-bXYw.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
|
|
209071
209119
|
}
|
|
209072
209120
|
});
|
|
209073
209121
|
registerLanguage({
|
|
209074
209122
|
id: "freemarker2.tag-angle.interpolation-bracket",
|
|
209075
209123
|
aliases: ["FreeMarker2 (Angle/Bracket)", "Apache FreeMarker2 (Angle/Bracket)"],
|
|
209076
209124
|
loader: () => {
|
|
209077
|
-
return __vitePreload(() => import("./freemarker2-
|
|
209125
|
+
return __vitePreload(() => import("./freemarker2-Na9-bXYw.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
|
|
209078
209126
|
}
|
|
209079
209127
|
});
|
|
209080
209128
|
registerLanguage({
|
|
209081
209129
|
id: "freemarker2.tag-bracket.interpolation-bracket",
|
|
209082
209130
|
aliases: ["FreeMarker2 (Bracket/Bracket)", "Apache FreeMarker2 (Bracket/Bracket)"],
|
|
209083
209131
|
loader: () => {
|
|
209084
|
-
return __vitePreload(() => import("./freemarker2-
|
|
209132
|
+
return __vitePreload(() => import("./freemarker2-Na9-bXYw.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
|
|
209085
209133
|
}
|
|
209086
209134
|
});
|
|
209087
209135
|
registerLanguage({
|
|
209088
209136
|
id: "freemarker2.tag-auto.interpolation-dollar",
|
|
209089
209137
|
aliases: ["FreeMarker2 (Auto/Dollar)", "Apache FreeMarker2 (Auto/Dollar)"],
|
|
209090
209138
|
loader: () => {
|
|
209091
|
-
return __vitePreload(() => import("./freemarker2-
|
|
209139
|
+
return __vitePreload(() => import("./freemarker2-Na9-bXYw.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
|
|
209092
209140
|
}
|
|
209093
209141
|
});
|
|
209094
209142
|
registerLanguage({
|
|
209095
209143
|
id: "freemarker2.tag-auto.interpolation-bracket",
|
|
209096
209144
|
aliases: ["FreeMarker2 (Auto/Bracket)", "Apache FreeMarker2 (Auto/Bracket)"],
|
|
209097
209145
|
loader: () => {
|
|
209098
|
-
return __vitePreload(() => import("./freemarker2-
|
|
209146
|
+
return __vitePreload(() => import("./freemarker2-Na9-bXYw.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
|
|
209099
209147
|
}
|
|
209100
209148
|
});
|
|
209101
209149
|
registerLanguage({
|
|
@@ -209116,7 +209164,7 @@ registerLanguage({
|
|
|
209116
209164
|
extensions: [".handlebars", ".hbs"],
|
|
209117
209165
|
aliases: ["Handlebars", "handlebars", "hbs"],
|
|
209118
209166
|
mimetypes: ["text/x-handlebars-template"],
|
|
209119
|
-
loader: () => __vitePreload(() => import("./handlebars-
|
|
209167
|
+
loader: () => __vitePreload(() => import("./handlebars-D7gzKLS8.js"), true ? [] : void 0, import.meta.url)
|
|
209120
209168
|
});
|
|
209121
209169
|
registerLanguage({
|
|
209122
209170
|
id: "hcl",
|
|
@@ -209129,7 +209177,7 @@ registerLanguage({
|
|
|
209129
209177
|
extensions: [".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm"],
|
|
209130
209178
|
aliases: ["HTML", "htm", "html", "xhtml"],
|
|
209131
209179
|
mimetypes: ["text/html", "text/x-jshtm", "text/template", "text/ng-template"],
|
|
209132
|
-
loader: () => __vitePreload(() => import("./html-
|
|
209180
|
+
loader: () => __vitePreload(() => import("./html-DDK7xN27.js"), true ? [] : void 0, import.meta.url)
|
|
209133
209181
|
});
|
|
209134
209182
|
registerLanguage({
|
|
209135
209183
|
id: "ini",
|
|
@@ -209152,7 +209200,7 @@ registerLanguage({
|
|
|
209152
209200
|
filenames: ["jakefile"],
|
|
209153
209201
|
aliases: ["JavaScript", "javascript", "js"],
|
|
209154
209202
|
mimetypes: ["text/javascript"],
|
|
209155
|
-
loader: () => __vitePreload(() => import("./javascript-
|
|
209203
|
+
loader: () => __vitePreload(() => import("./javascript-DJjWOxID.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
|
|
209156
209204
|
});
|
|
209157
209205
|
registerLanguage({
|
|
209158
209206
|
id: "julia",
|
|
@@ -209191,7 +209239,7 @@ registerLanguage({
|
|
|
209191
209239
|
extensions: [".liquid", ".html.liquid"],
|
|
209192
209240
|
aliases: ["Liquid", "liquid"],
|
|
209193
209241
|
mimetypes: ["application/liquid"],
|
|
209194
|
-
loader: () => __vitePreload(() => import("./liquid-
|
|
209242
|
+
loader: () => __vitePreload(() => import("./liquid-DvNU_dI9.js"), true ? [] : void 0, import.meta.url)
|
|
209195
209243
|
});
|
|
209196
209244
|
registerLanguage({
|
|
209197
209245
|
id: "m3",
|
|
@@ -209209,7 +209257,7 @@ registerLanguage({
|
|
|
209209
209257
|
id: "mdx",
|
|
209210
209258
|
extensions: [".mdx"],
|
|
209211
209259
|
aliases: ["MDX", "mdx"],
|
|
209212
|
-
loader: () => __vitePreload(() => import("./mdx-
|
|
209260
|
+
loader: () => __vitePreload(() => import("./mdx-CLkNPVgD.js"), true ? [] : void 0, import.meta.url)
|
|
209213
209261
|
});
|
|
209214
209262
|
registerLanguage({
|
|
209215
209263
|
id: "mips",
|
|
@@ -209308,7 +209356,7 @@ registerLanguage({
|
|
|
209308
209356
|
extensions: [".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi"],
|
|
209309
209357
|
aliases: ["Python", "py"],
|
|
209310
209358
|
firstLine: "^#!/.*\\bpython[0-9.-]*\\b",
|
|
209311
|
-
loader: () => __vitePreload(() => import("./python-
|
|
209359
|
+
loader: () => __vitePreload(() => import("./python-DOJdL4kC.js"), true ? [] : void 0, import.meta.url)
|
|
209312
209360
|
});
|
|
209313
209361
|
registerLanguage({
|
|
209314
209362
|
id: "qsharp",
|
|
@@ -209327,7 +209375,7 @@ registerLanguage({
|
|
|
209327
209375
|
extensions: [".cshtml"],
|
|
209328
209376
|
aliases: ["Razor", "razor"],
|
|
209329
209377
|
mimetypes: ["text/x-cshtml"],
|
|
209330
|
-
loader: () => __vitePreload(() => import("./razor-
|
|
209378
|
+
loader: () => __vitePreload(() => import("./razor-CSr8UlJc.js"), true ? [] : void 0, import.meta.url)
|
|
209331
209379
|
});
|
|
209332
209380
|
registerLanguage({
|
|
209333
209381
|
id: "redis",
|
|
@@ -209460,7 +209508,7 @@ registerLanguage({
|
|
|
209460
209508
|
aliases: ["TypeScript", "ts", "typescript"],
|
|
209461
209509
|
mimetypes: ["text/typescript"],
|
|
209462
209510
|
loader: () => {
|
|
209463
|
-
return __vitePreload(() => import("./typescript-
|
|
209511
|
+
return __vitePreload(() => import("./typescript-r5QB4yRW.js"), true ? [] : void 0, import.meta.url);
|
|
209464
209512
|
}
|
|
209465
209513
|
});
|
|
209466
209514
|
registerLanguage({
|
|
@@ -209505,14 +209553,14 @@ registerLanguage({
|
|
|
209505
209553
|
firstLine: "(\\<\\?xml.*)|(\\<svg)|(\\<\\!doctype\\s+svg)",
|
|
209506
209554
|
aliases: ["XML", "xml"],
|
|
209507
209555
|
mimetypes: ["text/xml", "application/xml", "application/xaml+xml", "application/xml-dtd"],
|
|
209508
|
-
loader: () => __vitePreload(() => import("./xml-
|
|
209556
|
+
loader: () => __vitePreload(() => import("./xml-CYhKh3Pi.js"), true ? [] : void 0, import.meta.url)
|
|
209509
209557
|
});
|
|
209510
209558
|
registerLanguage({
|
|
209511
209559
|
id: "yaml",
|
|
209512
209560
|
extensions: [".yaml", ".yml"],
|
|
209513
209561
|
aliases: ["YAML", "yaml", "YML", "yml"],
|
|
209514
209562
|
mimetypes: ["application/x-yaml", "text/x-yaml"],
|
|
209515
|
-
loader: () => __vitePreload(() => import("./yaml-
|
|
209563
|
+
loader: () => __vitePreload(() => import("./yaml-B8DsoaYW.js"), true ? [] : void 0, import.meta.url)
|
|
209516
209564
|
});
|
|
209517
209565
|
var __defProp = Object.defineProperty;
|
|
209518
209566
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -213286,11 +213334,14 @@ function RemoteConnect({ onConnect, onBack }) {
|
|
|
213286
213334
|
] })
|
|
213287
213335
|
] }) });
|
|
213288
213336
|
}
|
|
213289
|
-
function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
|
|
213290
|
-
const
|
|
213337
|
+
function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd, onCancel, restarting = false }) {
|
|
213338
|
+
const [selectedCwd, setSelectedCwd] = reactExports.useState(cwd2);
|
|
213339
|
+
const displayPath = selectedCwd.replace(/^\/Users\/[^/]+/, "~");
|
|
213291
213340
|
const [logChat, setLogChat] = reactExports.useState(false);
|
|
213292
213341
|
const [loaded, setLoaded] = reactExports.useState(false);
|
|
213293
213342
|
const [remoteMode, setRemoteMode] = reactExports.useState(false);
|
|
213343
|
+
const [handoff, setHandoff] = reactExports.useState("fresh");
|
|
213344
|
+
const [switching, setSwitching] = reactExports.useState(false);
|
|
213294
213345
|
reactExports.useEffect(() => {
|
|
213295
213346
|
let cancelled = false;
|
|
213296
213347
|
window.worker.getLogChat().then((r) => {
|
|
@@ -213311,20 +213362,30 @@ function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
|
|
|
213311
213362
|
}
|
|
213312
213363
|
};
|
|
213313
213364
|
const handleSelect = async (agent) => {
|
|
213365
|
+
if (switching) return;
|
|
213366
|
+
setSwitching(true);
|
|
213314
213367
|
if (loaded) {
|
|
213315
213368
|
try {
|
|
213316
213369
|
await window.worker.setLogChat(logChat);
|
|
213317
213370
|
} catch {
|
|
213318
213371
|
}
|
|
213319
213372
|
}
|
|
213320
|
-
|
|
213373
|
+
try {
|
|
213374
|
+
await onSelect(agent, selectedCwd, handoff);
|
|
213375
|
+
} finally {
|
|
213376
|
+
setSwitching(false);
|
|
213377
|
+
}
|
|
213378
|
+
};
|
|
213379
|
+
const changeCwd = async () => {
|
|
213380
|
+
const next = await onChangeCwd();
|
|
213381
|
+
if (next) setSelectedCwd(next);
|
|
213321
213382
|
};
|
|
213322
213383
|
if (remoteMode) {
|
|
213323
213384
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
213324
213385
|
RemoteConnect,
|
|
213325
213386
|
{
|
|
213326
213387
|
onConnect: (agent) => {
|
|
213327
|
-
handleSelect(agent);
|
|
213388
|
+
void handleSelect(agent);
|
|
213328
213389
|
},
|
|
213329
213390
|
onBack: () => setRemoteMode(false)
|
|
213330
213391
|
}
|
|
@@ -213332,18 +213393,55 @@ function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
|
|
|
213332
213393
|
}
|
|
213333
213394
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-overlay", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-modal", children: [
|
|
213334
213395
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-brand", children: "ctlsurf" }),
|
|
213335
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-cwd", onClick:
|
|
213396
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-cwd", onClick: () => void changeCwd(), title: "Click to change directory", children: [
|
|
213336
213397
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-cwd-icon", children: "📂" }),
|
|
213337
213398
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-cwd-path", children: displayPath }),
|
|
213338
213399
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-cwd-change", children: "change" })
|
|
213339
213400
|
] }),
|
|
213340
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-title", children: "SELECT AGENT" }),
|
|
213401
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-title", children: restarting ? "CHANGE SESSION" : "SELECT AGENT" }),
|
|
213402
|
+
restarting && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
213403
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-warning", children: "Choosing an agent restarts this terminal and ends its current process." }),
|
|
213404
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("fieldset", { className: "agent-handoff-options", children: [
|
|
213405
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("legend", { children: "NEW SESSION CONTEXT" }),
|
|
213406
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: handoff === "fresh" ? "selected" : "", children: [
|
|
213407
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
213408
|
+
"input",
|
|
213409
|
+
{
|
|
213410
|
+
type: "radio",
|
|
213411
|
+
name: "session-handoff",
|
|
213412
|
+
checked: handoff === "fresh",
|
|
213413
|
+
onChange: () => setHandoff("fresh")
|
|
213414
|
+
}
|
|
213415
|
+
),
|
|
213416
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
213417
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Start fresh" }),
|
|
213418
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: "Do not send anything from this terminal." })
|
|
213419
|
+
] })
|
|
213420
|
+
] }),
|
|
213421
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: handoff === "context" ? "selected" : "", children: [
|
|
213422
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
213423
|
+
"input",
|
|
213424
|
+
{
|
|
213425
|
+
type: "radio",
|
|
213426
|
+
name: "session-handoff",
|
|
213427
|
+
checked: handoff === "context",
|
|
213428
|
+
onChange: () => setHandoff("context")
|
|
213429
|
+
}
|
|
213430
|
+
),
|
|
213431
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
213432
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Share previous context" }),
|
|
213433
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: "Quote it inline, or use a temporary file when the session is long." })
|
|
213434
|
+
] })
|
|
213435
|
+
] })
|
|
213436
|
+
] })
|
|
213437
|
+
] }),
|
|
213341
213438
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-list", children: [
|
|
213342
213439
|
agents.map((a) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
213343
213440
|
"button",
|
|
213344
213441
|
{
|
|
213345
213442
|
className: "agent-picker-item",
|
|
213346
|
-
|
|
213443
|
+
disabled: switching,
|
|
213444
|
+
onClick: () => void handleSelect(a),
|
|
213347
213445
|
children: [
|
|
213348
213446
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-name", children: a.name }),
|
|
213349
213447
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-desc", children: a.description })
|
|
@@ -213355,6 +213453,7 @@ function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
|
|
|
213355
213453
|
"button",
|
|
213356
213454
|
{
|
|
213357
213455
|
className: "agent-picker-item",
|
|
213456
|
+
disabled: switching,
|
|
213358
213457
|
onClick: () => setRemoteMode(true),
|
|
213359
213458
|
children: [
|
|
213360
213459
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-name", children: "🌐 Remote (SSH)" }),
|
|
@@ -213374,15 +213473,17 @@ function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
|
|
|
213374
213473
|
),
|
|
213375
213474
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Log chat to ctlsurf" })
|
|
213376
213475
|
] }),
|
|
213377
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-hint", children: "Select an agent to start" })
|
|
213476
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-hint", children: restarting ? "Select an agent to restart in the directory above" : "Select an agent to start" }),
|
|
213477
|
+
onCancel && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "remote-link", disabled: switching, onClick: onCancel, children: "Cancel" })
|
|
213378
213478
|
] }) });
|
|
213379
213479
|
}
|
|
213380
|
-
function ProjectPicker({ onDone }) {
|
|
213480
|
+
function ProjectPicker({ onDone, currentProject }) {
|
|
213381
213481
|
const [state, setState2] = reactExports.useState("loading");
|
|
213382
213482
|
const [projects, setProjects] = reactExports.useState([]);
|
|
213383
213483
|
const [errorMsg, setErrorMsg] = reactExports.useState("");
|
|
213384
213484
|
const [binding, setBinding] = reactExports.useState(false);
|
|
213385
213485
|
const [filter, setFilter] = reactExports.useState("");
|
|
213486
|
+
const [notifyAgent, setNotifyAgent] = reactExports.useState(true);
|
|
213386
213487
|
reactExports.useEffect(() => {
|
|
213387
213488
|
let cancelled = false;
|
|
213388
213489
|
window.worker.listProjects().then((r) => {
|
|
@@ -213406,23 +213507,36 @@ function ProjectPicker({ onDone }) {
|
|
|
213406
213507
|
const pick = async (p) => {
|
|
213407
213508
|
setBinding(true);
|
|
213408
213509
|
try {
|
|
213409
|
-
await window.worker.bindProject(p.root_path);
|
|
213410
|
-
|
|
213510
|
+
const result = await window.worker.bindProject(p.root_path);
|
|
213511
|
+
if (!result.ok) {
|
|
213512
|
+
setErrorMsg(result.error || "Could not bind project");
|
|
213513
|
+
setState2("error");
|
|
213514
|
+
setBinding(false);
|
|
213515
|
+
return;
|
|
213516
|
+
}
|
|
213517
|
+
onDone({ project: p, notifyAgent });
|
|
213518
|
+
} catch (err) {
|
|
213519
|
+
setErrorMsg(err instanceof Error ? err.message : "Could not bind project");
|
|
213520
|
+
setState2("error");
|
|
213521
|
+
setBinding(false);
|
|
213411
213522
|
}
|
|
213412
|
-
onDone();
|
|
213413
213523
|
};
|
|
213414
213524
|
const shown = filter.trim() ? projects.filter((p) => p.name.toLowerCase().includes(filter.toLowerCase()) || p.root_path.toLowerCase().includes(filter.toLowerCase())) : projects;
|
|
213415
213525
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-overlay", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-modal", children: [
|
|
213416
213526
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-brand", children: "ctlsurf" }),
|
|
213417
213527
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-title", children: "SELECT CTLSURF PROJECT" }),
|
|
213418
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-target-line", children: "Bind
|
|
213528
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-target-line", children: "Bind the active session to a project" }),
|
|
213529
|
+
currentProject && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "remote-note", children: [
|
|
213530
|
+
"Currently linked to ",
|
|
213531
|
+
currentProject
|
|
213532
|
+
] }),
|
|
213419
213533
|
state === "loading" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "remote-status", children: [
|
|
213420
213534
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-spinner" }),
|
|
213421
213535
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading projects…" })
|
|
213422
213536
|
] }),
|
|
213423
213537
|
state === "error" && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-note", children: errorMsg }) }),
|
|
213424
213538
|
state === "ready" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
213425
|
-
projects.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-note", children: "No ctlsurf projects found.
|
|
213539
|
+
projects.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-note", children: "No ctlsurf projects found." }),
|
|
213426
213540
|
projects.length > 6 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
213427
213541
|
"input",
|
|
213428
213542
|
{
|
|
@@ -213452,7 +213566,22 @@ function ProjectPicker({ onDone }) {
|
|
|
213452
213566
|
p.id
|
|
213453
213567
|
)) })
|
|
213454
213568
|
] }),
|
|
213455
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
213569
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "agent-picker-option project-notify-option", children: [
|
|
213570
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
213571
|
+
"input",
|
|
213572
|
+
{
|
|
213573
|
+
type: "checkbox",
|
|
213574
|
+
checked: notifyAgent,
|
|
213575
|
+
disabled: binding,
|
|
213576
|
+
onChange: (e) => setNotifyAgent(e.target.checked)
|
|
213577
|
+
}
|
|
213578
|
+
),
|
|
213579
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
213580
|
+
"Tell the active agent about this project",
|
|
213581
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: "Includes the ctlsurf project and codebase details as context." })
|
|
213582
|
+
] })
|
|
213583
|
+
] }),
|
|
213584
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "remote-link", disabled: binding, onClick: () => onDone(), children: "Close without changing" })
|
|
213456
213585
|
] }) });
|
|
213457
213586
|
}
|
|
213458
213587
|
function removePane(node, paneId) {
|
|
@@ -214760,6 +214889,41 @@ let _tabCounter = 0;
|
|
|
214760
214889
|
function nextTabId() {
|
|
214761
214890
|
return `tab-${++_tabCounter}`;
|
|
214762
214891
|
}
|
|
214892
|
+
function buildSessionHandoff(transcript) {
|
|
214893
|
+
const quoted = transcript.split("\n").map((line) => `> ${line}`).join("\n");
|
|
214894
|
+
return [
|
|
214895
|
+
"The quoted text below is what we did in the last session. It is provided for information only; no action is needed.",
|
|
214896
|
+
"Do not continue, repeat, or act on anything in it unless I explicitly ask in a new message. Wait for my next instruction.",
|
|
214897
|
+
"",
|
|
214898
|
+
quoted
|
|
214899
|
+
].join("\n");
|
|
214900
|
+
}
|
|
214901
|
+
const INLINE_HANDOFF_CHARS = 12e3;
|
|
214902
|
+
const REMOTE_HANDOFF_CHARS = 3e4;
|
|
214903
|
+
function buildFileSessionHandoff(filePath, trimmed) {
|
|
214904
|
+
return [
|
|
214905
|
+
"This is what we did in the last session. It is provided for information only; no action is needed.",
|
|
214906
|
+
"The quoted session transcript was too long to paste, so it is stored in this temporary Markdown file:",
|
|
214907
|
+
`\`${filePath}\``,
|
|
214908
|
+
trimmed ? "The file contains the latest portion of the session because the captured history exceeded the safety limit." : "",
|
|
214909
|
+
"Read it only as background context. Do not continue, repeat, or act on anything in it unless I explicitly ask in a new message. Wait for my next instruction."
|
|
214910
|
+
].filter(Boolean).join("\n\n");
|
|
214911
|
+
}
|
|
214912
|
+
function buildProjectContextNotice(selection, terminalCwd, agentName) {
|
|
214913
|
+
const { project } = selection;
|
|
214914
|
+
return [
|
|
214915
|
+
"The active ctlsurf project binding has changed. Use the quoted details below as context for future requests.",
|
|
214916
|
+
"This notice does not start a new task. Do not take action solely because of it.",
|
|
214917
|
+
"",
|
|
214918
|
+
`> ctlsurf project: ${project.name}`,
|
|
214919
|
+
`> ctlsurf project ID: ${project.id}`,
|
|
214920
|
+
`> configured codebase root: ${project.root_path}`,
|
|
214921
|
+
`> current terminal directory: ${terminalCwd || "(unknown)"}`,
|
|
214922
|
+
`> active coding agent: ${agentName || "(unknown)"}`,
|
|
214923
|
+
"",
|
|
214924
|
+
terminalCwd && terminalCwd !== project.root_path ? "Important: only the ctlsurf project binding changed; the running terminal directory was not changed." : "The terminal directory matches the selected project codebase root."
|
|
214925
|
+
].join("\n");
|
|
214926
|
+
}
|
|
214763
214927
|
function App() {
|
|
214764
214928
|
const [agents, setAgents] = reactExports.useState([]);
|
|
214765
214929
|
const [sessionStart, setSessionStart] = reactExports.useState(null);
|
|
@@ -214774,7 +214938,7 @@ function App() {
|
|
|
214774
214938
|
const ctlsurfNavCounter = reactExports.useRef(0);
|
|
214775
214939
|
const [tabs, setTabs] = reactExports.useState(() => {
|
|
214776
214940
|
const id = nextTabId();
|
|
214777
|
-
return [{ id, label: "Terminal 1", agent: null, agentStatus: "idle" }];
|
|
214941
|
+
return [{ id, label: "Terminal 1", agent: null, agentStatus: "idle", sessionVersion: 0 }];
|
|
214778
214942
|
});
|
|
214779
214943
|
const [activeTabId, setActiveTabId] = reactExports.useState(tabs[0].id);
|
|
214780
214944
|
const [trackingActive, setTrackingActive] = reactExports.useState(false);
|
|
@@ -214887,21 +215051,44 @@ function App() {
|
|
|
214887
215051
|
setTimeout(() => window.worker.writePty(activeTabId, "\r"), 120);
|
|
214888
215052
|
}, [activeTabId]);
|
|
214889
215053
|
const cwdRef = reactExports.useRef(null);
|
|
215054
|
+
const pendingHandoffsRef = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
215055
|
+
const handoffTimersRef = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
215056
|
+
const handoffGenerationsRef = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
214890
215057
|
const handleSpawn = reactExports.useCallback(async (tabId, agent) => {
|
|
215058
|
+
const oldTimer = handoffTimersRef.current.get(tabId);
|
|
215059
|
+
if (oldTimer) clearTimeout(oldTimer);
|
|
215060
|
+
handoffTimersRef.current.delete(tabId);
|
|
215061
|
+
const handoffGeneration = (handoffGenerationsRef.current.get(tabId) || 0) + 1;
|
|
215062
|
+
handoffGenerationsRef.current.set(tabId, handoffGeneration);
|
|
214891
215063
|
setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "active" } : t));
|
|
214892
215064
|
setSessionStart(/* @__PURE__ */ new Date());
|
|
214893
215065
|
const spawnCwd = cwdRef.current || await window.worker.getCwd().catch(() => window.worker.getHomePath());
|
|
214894
215066
|
setCwd(spawnCwd);
|
|
214895
215067
|
cwdRef.current = spawnCwd;
|
|
214896
|
-
|
|
214897
|
-
|
|
214898
|
-
|
|
214899
|
-
|
|
214900
|
-
|
|
214901
|
-
|
|
214902
|
-
|
|
215068
|
+
try {
|
|
215069
|
+
await window.worker.spawnAgent(tabId, agent, spawnCwd);
|
|
215070
|
+
} catch (err) {
|
|
215071
|
+
console.error("[session] Failed to start agent", err);
|
|
215072
|
+
pendingHandoffsRef.current.delete(tabId);
|
|
215073
|
+
setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "exited" } : t));
|
|
215074
|
+
return;
|
|
215075
|
+
}
|
|
215076
|
+
const handoff = pendingHandoffsRef.current.get(tabId);
|
|
215077
|
+
pendingHandoffsRef.current.delete(tabId);
|
|
215078
|
+
if (handoff) {
|
|
215079
|
+
const timer = setTimeout(() => {
|
|
215080
|
+
if (handoffGenerationsRef.current.get(tabId) !== handoffGeneration) return;
|
|
215081
|
+
window.worker.writePty(tabId, handoff);
|
|
215082
|
+
focusTerminal(tabId);
|
|
215083
|
+
setTimeout(() => {
|
|
215084
|
+
if (handoffGenerationsRef.current.get(tabId) === handoffGeneration) {
|
|
215085
|
+
window.worker.writePty(tabId, "\r");
|
|
215086
|
+
}
|
|
215087
|
+
}, 120);
|
|
215088
|
+
}, 1200);
|
|
215089
|
+
handoffTimersRef.current.set(tabId, timer);
|
|
214903
215090
|
}
|
|
214904
|
-
}, [
|
|
215091
|
+
}, []);
|
|
214905
215092
|
const handleExit = reactExports.useCallback((tabId) => {
|
|
214906
215093
|
setTimeout(() => {
|
|
214907
215094
|
setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "exited" } : t));
|
|
@@ -214910,36 +215097,84 @@ function App() {
|
|
|
214910
215097
|
const handleChangeCwd = reactExports.useCallback(async () => {
|
|
214911
215098
|
const newCwd = await window.worker.browseCwd();
|
|
214912
215099
|
const activeTab = tabs.find((t) => t.id === activeTabId);
|
|
214913
|
-
if (!newCwd
|
|
215100
|
+
if (!newCwd) return;
|
|
214914
215101
|
cwdRef.current = newCwd;
|
|
214915
215102
|
setCwd(newCwd);
|
|
214916
|
-
|
|
214917
|
-
|
|
214918
|
-
|
|
214919
|
-
await window.worker.spawnAgent(activeTabId, activeTab.agent, newCwd);
|
|
215103
|
+
if (!activeTab?.agent) return;
|
|
215104
|
+
pendingHandoffsRef.current.delete(activeTabId);
|
|
215105
|
+
setTabs((prev) => prev.map((t) => t.id === activeTabId ? { ...t, agentStatus: "idle", sessionVersion: t.sessionVersion + 1 } : t));
|
|
214920
215106
|
}, [tabs, activeTabId]);
|
|
214921
215107
|
const addTab = reactExports.useCallback(() => {
|
|
214922
215108
|
const id = nextTabId();
|
|
214923
215109
|
const num = _tabCounter;
|
|
214924
|
-
setTabs((prev) => [...prev, { id, label: `Terminal ${num}`, agent: null, agentStatus: "idle" }]);
|
|
215110
|
+
setTabs((prev) => [...prev, { id, label: `Terminal ${num}`, agent: null, agentStatus: "idle", sessionVersion: 0 }]);
|
|
214925
215111
|
setActiveTabId(id);
|
|
214926
215112
|
setPickerTargetTabId(id);
|
|
214927
215113
|
setShowAgentPicker(true);
|
|
214928
215114
|
}, []);
|
|
214929
|
-
const handlePickerSelect = reactExports.useCallback((agent) => {
|
|
215115
|
+
const handlePickerSelect = reactExports.useCallback(async (agent, selectedCwd, handoff) => {
|
|
214930
215116
|
const tabId = pickerTargetTabId;
|
|
214931
215117
|
if (tabId) {
|
|
214932
|
-
|
|
214933
|
-
|
|
214934
|
-
|
|
215118
|
+
if (handoff === "context") {
|
|
215119
|
+
const transcript = captureTerminalSession(tabId);
|
|
215120
|
+
if (!transcript) {
|
|
215121
|
+
pendingHandoffsRef.current.delete(tabId);
|
|
215122
|
+
} else if (transcript.length > INLINE_HANDOFF_CHARS && !agent.id.startsWith("remote-")) {
|
|
215123
|
+
const result = await window.worker.createSessionHandoffFile(transcript);
|
|
215124
|
+
if (result.ok && result.path) {
|
|
215125
|
+
pendingHandoffsRef.current.set(tabId, buildFileSessionHandoff(result.path, !!result.trimmed));
|
|
215126
|
+
} else {
|
|
215127
|
+
console.warn("[session] Could not create handoff file; using a shortened inline handoff", result.error);
|
|
215128
|
+
pendingHandoffsRef.current.set(tabId, buildSessionHandoff(transcript.slice(-REMOTE_HANDOFF_CHARS)));
|
|
215129
|
+
}
|
|
215130
|
+
} else {
|
|
215131
|
+
const inline2 = transcript.length > REMOTE_HANDOFF_CHARS ? `[Earlier terminal output omitted.]
|
|
215132
|
+
${transcript.slice(-REMOTE_HANDOFF_CHARS)}` : transcript;
|
|
215133
|
+
pendingHandoffsRef.current.set(tabId, buildSessionHandoff(inline2));
|
|
215134
|
+
}
|
|
215135
|
+
} else {
|
|
215136
|
+
pendingHandoffsRef.current.delete(tabId);
|
|
215137
|
+
}
|
|
215138
|
+
cwdRef.current = selectedCwd;
|
|
215139
|
+
setCwd(selectedCwd);
|
|
215140
|
+
setTabs((prev) => {
|
|
215141
|
+
const matchingAgents = prev.filter((x) => x.agent?.id === agent.id).length;
|
|
215142
|
+
return prev.map((t) => t.id === tabId ? {
|
|
215143
|
+
...t,
|
|
215144
|
+
agent,
|
|
215145
|
+
agentStatus: "idle",
|
|
215146
|
+
label: `${agent.name} ${matchingAgents + (t.agent?.id === agent.id ? 0 : 1)}`,
|
|
215147
|
+
sessionVersion: t.sessionVersion + 1
|
|
215148
|
+
} : t);
|
|
215149
|
+
});
|
|
214935
215150
|
}
|
|
214936
215151
|
setShowAgentPicker(false);
|
|
214937
215152
|
setPickerTargetTabId(null);
|
|
214938
215153
|
if (agent.id.startsWith("remote-")) {
|
|
214939
215154
|
setShowProjectPicker(true);
|
|
214940
215155
|
}
|
|
214941
|
-
}, [pickerTargetTabId
|
|
215156
|
+
}, [pickerTargetTabId]);
|
|
215157
|
+
const openSessionPicker = reactExports.useCallback(() => {
|
|
215158
|
+
setPickerTargetTabId(activeTabId);
|
|
215159
|
+
setShowAgentPicker(true);
|
|
215160
|
+
}, [activeTabId]);
|
|
215161
|
+
const handleProjectPickerDone = reactExports.useCallback(async (selection) => {
|
|
215162
|
+
setShowProjectPicker(false);
|
|
215163
|
+
if (!selection?.notifyAgent) return;
|
|
215164
|
+
const activeAgent = tabs.find((t) => t.id === activeTabId)?.agent;
|
|
215165
|
+
if (!activeAgent) return;
|
|
215166
|
+
const terminalCwd = await window.worker.getActiveTabCwd().catch(() => cwd2);
|
|
215167
|
+
const notice = buildProjectContextNotice(selection, terminalCwd, activeAgent.name);
|
|
215168
|
+
window.worker.writePty(activeTabId, notice);
|
|
215169
|
+
focusTerminal(activeTabId);
|
|
215170
|
+
setTimeout(() => window.worker.writePty(activeTabId, "\r"), 120);
|
|
215171
|
+
}, [activeTabId, cwd2, tabs]);
|
|
214942
215172
|
const closeTab = reactExports.useCallback(async (tabId) => {
|
|
215173
|
+
pendingHandoffsRef.current.delete(tabId);
|
|
215174
|
+
handoffGenerationsRef.current.set(tabId, (handoffGenerationsRef.current.get(tabId) || 0) + 1);
|
|
215175
|
+
const handoffTimer = handoffTimersRef.current.get(tabId);
|
|
215176
|
+
if (handoffTimer) clearTimeout(handoffTimer);
|
|
215177
|
+
handoffTimersRef.current.delete(tabId);
|
|
214943
215178
|
await window.worker.killPty(tabId);
|
|
214944
215179
|
destroyTerminal(tabId);
|
|
214945
215180
|
setTabs((prev) => {
|
|
@@ -214953,7 +215188,7 @@ function App() {
|
|
|
214953
215188
|
setActiveTabId(id);
|
|
214954
215189
|
setPickerTargetTabId(id);
|
|
214955
215190
|
setShowAgentPicker(true);
|
|
214956
|
-
return [{ id, label: `Terminal ${num}`, agent: null, agentStatus: "idle" }];
|
|
215191
|
+
return [{ id, label: `Terminal ${num}`, agent: null, agentStatus: "idle", sessionVersion: 0 }];
|
|
214957
215192
|
}
|
|
214958
215193
|
return next;
|
|
214959
215194
|
});
|
|
@@ -215087,6 +215322,7 @@ function App() {
|
|
|
215087
215322
|
{
|
|
215088
215323
|
tabId: tab.id,
|
|
215089
215324
|
agent: tab.agent,
|
|
215325
|
+
sessionVersion: tab.sessionVersion,
|
|
215090
215326
|
onSpawn: handleSpawn,
|
|
215091
215327
|
onExit: handleExit,
|
|
215092
215328
|
isActive: tab.id === activeTabId
|
|
@@ -215217,19 +215453,28 @@ function App() {
|
|
|
215217
215453
|
),
|
|
215218
215454
|
/* @__PURE__ */ jsxRuntimeExports.jsx(SpeakControls, { remote: activeAgentIsRemote }),
|
|
215219
215455
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "titlebar-separator" }),
|
|
215220
|
-
|
|
215221
|
-
|
|
215222
|
-
|
|
215223
|
-
"
|
|
215224
|
-
|
|
215225
|
-
|
|
215226
|
-
|
|
215227
|
-
|
|
215228
|
-
|
|
215229
|
-
|
|
215230
|
-
|
|
215231
|
-
|
|
215232
|
-
|
|
215456
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
215457
|
+
"button",
|
|
215458
|
+
{
|
|
215459
|
+
className: "titlebar-agent-btn active",
|
|
215460
|
+
onClick: openSessionPicker,
|
|
215461
|
+
title: "Change coding agent or project directory for the active terminal",
|
|
215462
|
+
children: [
|
|
215463
|
+
"Agent: ",
|
|
215464
|
+
tabs.find((t) => t.id === activeTabId)?.agent?.name || "Choose",
|
|
215465
|
+
" ▾"
|
|
215466
|
+
]
|
|
215467
|
+
}
|
|
215468
|
+
),
|
|
215469
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
215470
|
+
"button",
|
|
215471
|
+
{
|
|
215472
|
+
className: "titlebar-btn",
|
|
215473
|
+
onClick: () => setShowProjectPicker(true),
|
|
215474
|
+
title: "Change the ctlsurf project linked to the active session",
|
|
215475
|
+
children: "Project…"
|
|
215476
|
+
}
|
|
215477
|
+
),
|
|
215233
215478
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "titlebar-separator" }),
|
|
215234
215479
|
ALL_PANE_IDS.map((id) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
215235
215480
|
"button",
|
|
@@ -215260,16 +215505,15 @@ function App() {
|
|
|
215260
215505
|
agents,
|
|
215261
215506
|
cwd: cwd2 || "",
|
|
215262
215507
|
onSelect: handlePickerSelect,
|
|
215263
|
-
onChangeCwd:
|
|
215264
|
-
|
|
215265
|
-
|
|
215266
|
-
|
|
215267
|
-
|
|
215268
|
-
|
|
215269
|
-
}
|
|
215508
|
+
onChangeCwd: () => window.worker.browseCwd(),
|
|
215509
|
+
onCancel: tabs.find((t) => t.id === pickerTargetTabId)?.agent ? () => {
|
|
215510
|
+
setShowAgentPicker(false);
|
|
215511
|
+
setPickerTargetTabId(null);
|
|
215512
|
+
} : void 0,
|
|
215513
|
+
restarting: !!tabs.find((t) => t.id === pickerTargetTabId)?.agent
|
|
215270
215514
|
}
|
|
215271
215515
|
),
|
|
215272
|
-
showProjectPicker && /* @__PURE__ */ jsxRuntimeExports.jsx(ProjectPicker, {
|
|
215516
|
+
showProjectPicker && /* @__PURE__ */ jsxRuntimeExports.jsx(ProjectPicker, { currentProject: projectName, onDone: handleProjectPickerDone }),
|
|
215273
215517
|
showFloatingMic && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
215274
215518
|
FloatingMic,
|
|
215275
215519
|
{
|