@phenx-inc/ctlsurf 0.15.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/out/headless/index.mjs +10 -3
  2. package/out/headless/index.mjs.map +2 -2
  3. package/out/main/index.js +54 -4
  4. package/out/preload/index.js +2 -0
  5. package/out/renderer/assets/{cssMode-CPfLk04b.js → cssMode-Xx1-SozN.js} +3 -3
  6. package/out/renderer/assets/{freemarker2-CDHpuFqv.js → freemarker2-DM49yPw1.js} +1 -1
  7. package/out/renderer/assets/{handlebars-CgX9Jz36.js → handlebars-DJJBblpV.js} +1 -1
  8. package/out/renderer/assets/{html-DdgFccDG.js → html-DnMnJOxw.js} +1 -1
  9. package/out/renderer/assets/{htmlMode-CRHIwtvP.js → htmlMode-BG5u2CSH.js} +3 -3
  10. package/out/renderer/assets/{index-DVdWgw7p.js → index-D65QIRev.js} +300 -84
  11. package/out/renderer/assets/{index-3sFJEz7i.css → index-DID1LlMU.css} +88 -0
  12. package/out/renderer/assets/{javascript-CHhxL0s7.js → javascript-Dci_phmN.js} +2 -2
  13. package/out/renderer/assets/{jsonMode-Cy7-eWai.js → jsonMode-Dmp3JJSm.js} +3 -3
  14. package/out/renderer/assets/{liquid-vMkF9pfk.js → liquid-C9KVysk1.js} +1 -1
  15. package/out/renderer/assets/{lspLanguageFeatures-nAygNzuG.js → lspLanguageFeatures-IDD0-KWa.js} +1 -1
  16. package/out/renderer/assets/{mdx-C4UVz5dW.js → mdx-ascmBFXX.js} +1 -1
  17. package/out/renderer/assets/{python-BHemzN9g.js → python-DcbM4Hy5.js} +1 -1
  18. package/out/renderer/assets/{razor-DH6NPzbo.js → razor-XJROxpYK.js} +1 -1
  19. package/out/renderer/assets/{tsMode-DxBdlGZB.js → tsMode-EXbzul3n.js} +1 -1
  20. package/out/renderer/assets/{typescript-BRCOaBQ5.js → typescript-DhTtFBLt.js} +1 -1
  21. package/out/renderer/assets/{xml-DVv9gDP1.js → xml-BLfEkVl1.js} +1 -1
  22. package/out/renderer/assets/{yaml-jB-C3CdS.js → yaml-DpzsqvWa.js} +1 -1
  23. package/out/renderer/index.html +2 -2
  24. package/package.json +1 -1
  25. package/src/main/index.ts +52 -1
  26. package/src/main/orchestrator.ts +18 -3
  27. package/src/preload/index.ts +4 -0
  28. package/src/renderer/App.tsx +179 -50
  29. package/src/renderer/components/AgentPicker.tsx +61 -10
  30. package/src/renderer/components/ProjectPicker.tsx +44 -13
  31. package/src/renderer/components/TerminalPanel.tsx +34 -7
  32. 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-CPfLk04b.js","./lspLanguageFeatures-nAygNzuG.js","./htmlMode-CRHIwtvP.js","./jsonMode-Cy7-eWai.js","./javascript-CHhxL0s7.js","./typescript-BRCOaBQ5.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-Xx1-SozN.js","./lspLanguageFeatures-IDD0-KWa.js","./htmlMode-BG5u2CSH.js","./jsonMode-Dmp3JJSm.js","./javascript-Dci_phmN.js","./typescript-DhTtFBLt.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
  }
@@ -19599,7 +19599,7 @@ function getOrCreateTerminal(tabId, onExit) {
19599
19599
  fitAddon,
19600
19600
  unsubData: null,
19601
19601
  unsubExit: null,
19602
- spawnedAgentId: null,
19602
+ spawnedSessionKey: null,
19603
19603
  pinnedToBottom: true,
19604
19604
  anchorLine: null,
19605
19605
  userScrollPending: false,
@@ -19643,6 +19643,25 @@ function getOrCreateTerminal(tabId, onExit) {
19643
19643
  function focusTerminal(tabId) {
19644
19644
  _terminals.get(tabId)?.terminal.focus();
19645
19645
  }
19646
+ const MAX_HANDOFF_CHARS = 1e6;
19647
+ function captureTerminalSession(tabId) {
19648
+ const terminal = _terminals.get(tabId)?.terminal;
19649
+ if (!terminal) return "";
19650
+ const buffer = terminal.buffer.active;
19651
+ const lines = [];
19652
+ for (let i2 = 0; i2 < buffer.length; i2++) {
19653
+ const line = buffer.getLine(i2);
19654
+ if (!line) continue;
19655
+ const text22 = line.translateToString(true);
19656
+ if (line.isWrapped && lines.length > 0) lines[lines.length - 1] += text22;
19657
+ else lines.push(text22);
19658
+ }
19659
+ while (lines.length && lines[lines.length - 1].trim() === "") lines.pop();
19660
+ const text2 = lines.join("\n").trim();
19661
+ if (text2.length <= MAX_HANDOFF_CHARS) return text2;
19662
+ return `[Earlier terminal output omitted; showing the last ${MAX_HANDOFF_CHARS.toLocaleString()} characters.]
19663
+ ${text2.slice(-MAX_HANDOFF_CHARS)}`;
19664
+ }
19646
19665
  function destroyTerminal(tabId) {
19647
19666
  const state = _terminals.get(tabId);
19648
19667
  if (!state) return;
@@ -19651,7 +19670,7 @@ function destroyTerminal(tabId) {
19651
19670
  state.terminal.dispose();
19652
19671
  _terminals.delete(tabId);
19653
19672
  }
19654
- function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
19673
+ function TerminalPanel({ tabId, agent, sessionVersion, onSpawn, onExit, isActive }) {
19655
19674
  const containerRef = reactExports.useRef(null);
19656
19675
  const [menu, setMenu] = reactExports.useState(null);
19657
19676
  const [snapOpen, setSnapOpen] = reactExports.useState(false);
@@ -19771,8 +19790,9 @@ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
19771
19790
  if (!agent) return;
19772
19791
  const state = _terminals.get(tabId);
19773
19792
  if (!state) return;
19774
- if (state.spawnedAgentId === agent.id) return;
19775
- state.spawnedAgentId = agent.id;
19793
+ const sessionKey = `${agent.id}:${sessionVersion}`;
19794
+ if (state.spawnedSessionKey === sessionKey) return;
19795
+ state.spawnedSessionKey = sessionKey;
19776
19796
  state.terminal.clear();
19777
19797
  onSpawn(tabId, agent).then(() => {
19778
19798
  const s = _terminals.get(tabId);
@@ -19785,7 +19805,7 @@ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
19785
19805
  }
19786
19806
  state.terminal.focus();
19787
19807
  });
19788
- }, [tabId, agent, onSpawn]);
19808
+ }, [tabId, agent, sessionVersion, onSpawn]);
19789
19809
  reactExports.useEffect(() => {
19790
19810
  if (isActive) {
19791
19811
  window.worker.setActiveTab(tabId);
@@ -208423,7 +208443,7 @@ const lessDefaults = new LanguageServiceDefaultsImpl$3(
208423
208443
  modeConfigurationDefault$2
208424
208444
  );
208425
208445
  function getMode$3() {
208426
- return __vitePreload(() => import("./cssMode-CPfLk04b.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
208446
+ return __vitePreload(() => import("./cssMode-Xx1-SozN.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
208427
208447
  }
208428
208448
  languages.onLanguage("less", () => {
208429
208449
  getMode$3().then((mode2) => mode2.setupMode(lessDefaults));
@@ -208528,7 +208548,7 @@ const razorLanguageService = registerHTMLLanguageService(
208528
208548
  );
208529
208549
  const razorDefaults = razorLanguageService.defaults;
208530
208550
  function getMode$2() {
208531
- return __vitePreload(() => import("./htmlMode-CRHIwtvP.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
208551
+ return __vitePreload(() => import("./htmlMode-BG5u2CSH.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
208532
208552
  }
208533
208553
  function registerHTMLLanguageService(languageId, options = optionsDefault, modeConfiguration = getConfigurationDefault(languageId)) {
208534
208554
  const defaults = new LanguageServiceDefaultsImpl$2(languageId, options, modeConfiguration);
@@ -208612,7 +208632,7 @@ const jsonDefaults = new LanguageServiceDefaultsImpl$1(
208612
208632
  );
208613
208633
  const getWorker$1 = () => getMode$1().then((mode2) => mode2.getWorker());
208614
208634
  function getMode$1() {
208615
- return __vitePreload(() => import("./jsonMode-Cy7-eWai.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
208635
+ return __vitePreload(() => import("./jsonMode-Dmp3JJSm.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
208616
208636
  }
208617
208637
  languages.register({
208618
208638
  id: "json",
@@ -208858,7 +208878,7 @@ const getJavaScriptWorker = () => {
208858
208878
  return getMode().then((mode) => mode.getJavaScriptWorker());
208859
208879
  };
208860
208880
  function getMode() {
208861
- return __vitePreload(() => import("./tsMode-DxBdlGZB.js"), true ? [] : void 0, import.meta.url);
208881
+ return __vitePreload(() => import("./tsMode-EXbzul3n.js"), true ? [] : void 0, import.meta.url);
208862
208882
  }
208863
208883
  languages.onLanguage("typescript", () => {
208864
208884
  return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
@@ -209053,49 +209073,49 @@ registerLanguage({
209053
209073
  extensions: [".ftl", ".ftlh", ".ftlx"],
209054
209074
  aliases: ["FreeMarker2", "Apache FreeMarker2"],
209055
209075
  loader: () => {
209056
- return __vitePreload(() => import("./freemarker2-CDHpuFqv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
209076
+ return __vitePreload(() => import("./freemarker2-DM49yPw1.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
209057
209077
  }
209058
209078
  });
209059
209079
  registerLanguage({
209060
209080
  id: "freemarker2.tag-angle.interpolation-dollar",
209061
209081
  aliases: ["FreeMarker2 (Angle/Dollar)", "Apache FreeMarker2 (Angle/Dollar)"],
209062
209082
  loader: () => {
209063
- return __vitePreload(() => import("./freemarker2-CDHpuFqv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
209083
+ return __vitePreload(() => import("./freemarker2-DM49yPw1.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
209064
209084
  }
209065
209085
  });
209066
209086
  registerLanguage({
209067
209087
  id: "freemarker2.tag-bracket.interpolation-dollar",
209068
209088
  aliases: ["FreeMarker2 (Bracket/Dollar)", "Apache FreeMarker2 (Bracket/Dollar)"],
209069
209089
  loader: () => {
209070
- return __vitePreload(() => import("./freemarker2-CDHpuFqv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
209090
+ return __vitePreload(() => import("./freemarker2-DM49yPw1.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
209071
209091
  }
209072
209092
  });
209073
209093
  registerLanguage({
209074
209094
  id: "freemarker2.tag-angle.interpolation-bracket",
209075
209095
  aliases: ["FreeMarker2 (Angle/Bracket)", "Apache FreeMarker2 (Angle/Bracket)"],
209076
209096
  loader: () => {
209077
- return __vitePreload(() => import("./freemarker2-CDHpuFqv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
209097
+ return __vitePreload(() => import("./freemarker2-DM49yPw1.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
209078
209098
  }
209079
209099
  });
209080
209100
  registerLanguage({
209081
209101
  id: "freemarker2.tag-bracket.interpolation-bracket",
209082
209102
  aliases: ["FreeMarker2 (Bracket/Bracket)", "Apache FreeMarker2 (Bracket/Bracket)"],
209083
209103
  loader: () => {
209084
- return __vitePreload(() => import("./freemarker2-CDHpuFqv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
209104
+ return __vitePreload(() => import("./freemarker2-DM49yPw1.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
209085
209105
  }
209086
209106
  });
209087
209107
  registerLanguage({
209088
209108
  id: "freemarker2.tag-auto.interpolation-dollar",
209089
209109
  aliases: ["FreeMarker2 (Auto/Dollar)", "Apache FreeMarker2 (Auto/Dollar)"],
209090
209110
  loader: () => {
209091
- return __vitePreload(() => import("./freemarker2-CDHpuFqv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
209111
+ return __vitePreload(() => import("./freemarker2-DM49yPw1.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
209092
209112
  }
209093
209113
  });
209094
209114
  registerLanguage({
209095
209115
  id: "freemarker2.tag-auto.interpolation-bracket",
209096
209116
  aliases: ["FreeMarker2 (Auto/Bracket)", "Apache FreeMarker2 (Auto/Bracket)"],
209097
209117
  loader: () => {
209098
- return __vitePreload(() => import("./freemarker2-CDHpuFqv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
209118
+ return __vitePreload(() => import("./freemarker2-DM49yPw1.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
209099
209119
  }
209100
209120
  });
209101
209121
  registerLanguage({
@@ -209116,7 +209136,7 @@ registerLanguage({
209116
209136
  extensions: [".handlebars", ".hbs"],
209117
209137
  aliases: ["Handlebars", "handlebars", "hbs"],
209118
209138
  mimetypes: ["text/x-handlebars-template"],
209119
- loader: () => __vitePreload(() => import("./handlebars-CgX9Jz36.js"), true ? [] : void 0, import.meta.url)
209139
+ loader: () => __vitePreload(() => import("./handlebars-DJJBblpV.js"), true ? [] : void 0, import.meta.url)
209120
209140
  });
209121
209141
  registerLanguage({
209122
209142
  id: "hcl",
@@ -209129,7 +209149,7 @@ registerLanguage({
209129
209149
  extensions: [".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm"],
209130
209150
  aliases: ["HTML", "htm", "html", "xhtml"],
209131
209151
  mimetypes: ["text/html", "text/x-jshtm", "text/template", "text/ng-template"],
209132
- loader: () => __vitePreload(() => import("./html-DdgFccDG.js"), true ? [] : void 0, import.meta.url)
209152
+ loader: () => __vitePreload(() => import("./html-DnMnJOxw.js"), true ? [] : void 0, import.meta.url)
209133
209153
  });
209134
209154
  registerLanguage({
209135
209155
  id: "ini",
@@ -209152,7 +209172,7 @@ registerLanguage({
209152
209172
  filenames: ["jakefile"],
209153
209173
  aliases: ["JavaScript", "javascript", "js"],
209154
209174
  mimetypes: ["text/javascript"],
209155
- loader: () => __vitePreload(() => import("./javascript-CHhxL0s7.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
209175
+ loader: () => __vitePreload(() => import("./javascript-Dci_phmN.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
209156
209176
  });
209157
209177
  registerLanguage({
209158
209178
  id: "julia",
@@ -209191,7 +209211,7 @@ registerLanguage({
209191
209211
  extensions: [".liquid", ".html.liquid"],
209192
209212
  aliases: ["Liquid", "liquid"],
209193
209213
  mimetypes: ["application/liquid"],
209194
- loader: () => __vitePreload(() => import("./liquid-vMkF9pfk.js"), true ? [] : void 0, import.meta.url)
209214
+ loader: () => __vitePreload(() => import("./liquid-C9KVysk1.js"), true ? [] : void 0, import.meta.url)
209195
209215
  });
209196
209216
  registerLanguage({
209197
209217
  id: "m3",
@@ -209209,7 +209229,7 @@ registerLanguage({
209209
209229
  id: "mdx",
209210
209230
  extensions: [".mdx"],
209211
209231
  aliases: ["MDX", "mdx"],
209212
- loader: () => __vitePreload(() => import("./mdx-C4UVz5dW.js"), true ? [] : void 0, import.meta.url)
209232
+ loader: () => __vitePreload(() => import("./mdx-ascmBFXX.js"), true ? [] : void 0, import.meta.url)
209213
209233
  });
209214
209234
  registerLanguage({
209215
209235
  id: "mips",
@@ -209308,7 +209328,7 @@ registerLanguage({
209308
209328
  extensions: [".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi"],
209309
209329
  aliases: ["Python", "py"],
209310
209330
  firstLine: "^#!/.*\\bpython[0-9.-]*\\b",
209311
- loader: () => __vitePreload(() => import("./python-BHemzN9g.js"), true ? [] : void 0, import.meta.url)
209331
+ loader: () => __vitePreload(() => import("./python-DcbM4Hy5.js"), true ? [] : void 0, import.meta.url)
209312
209332
  });
209313
209333
  registerLanguage({
209314
209334
  id: "qsharp",
@@ -209327,7 +209347,7 @@ registerLanguage({
209327
209347
  extensions: [".cshtml"],
209328
209348
  aliases: ["Razor", "razor"],
209329
209349
  mimetypes: ["text/x-cshtml"],
209330
- loader: () => __vitePreload(() => import("./razor-DH6NPzbo.js"), true ? [] : void 0, import.meta.url)
209350
+ loader: () => __vitePreload(() => import("./razor-XJROxpYK.js"), true ? [] : void 0, import.meta.url)
209331
209351
  });
209332
209352
  registerLanguage({
209333
209353
  id: "redis",
@@ -209460,7 +209480,7 @@ registerLanguage({
209460
209480
  aliases: ["TypeScript", "ts", "typescript"],
209461
209481
  mimetypes: ["text/typescript"],
209462
209482
  loader: () => {
209463
- return __vitePreload(() => import("./typescript-BRCOaBQ5.js"), true ? [] : void 0, import.meta.url);
209483
+ return __vitePreload(() => import("./typescript-DhTtFBLt.js"), true ? [] : void 0, import.meta.url);
209464
209484
  }
209465
209485
  });
209466
209486
  registerLanguage({
@@ -209505,14 +209525,14 @@ registerLanguage({
209505
209525
  firstLine: "(\\<\\?xml.*)|(\\<svg)|(\\<\\!doctype\\s+svg)",
209506
209526
  aliases: ["XML", "xml"],
209507
209527
  mimetypes: ["text/xml", "application/xml", "application/xaml+xml", "application/xml-dtd"],
209508
- loader: () => __vitePreload(() => import("./xml-DVv9gDP1.js"), true ? [] : void 0, import.meta.url)
209528
+ loader: () => __vitePreload(() => import("./xml-BLfEkVl1.js"), true ? [] : void 0, import.meta.url)
209509
209529
  });
209510
209530
  registerLanguage({
209511
209531
  id: "yaml",
209512
209532
  extensions: [".yaml", ".yml"],
209513
209533
  aliases: ["YAML", "yaml", "YML", "yml"],
209514
209534
  mimetypes: ["application/x-yaml", "text/x-yaml"],
209515
- loader: () => __vitePreload(() => import("./yaml-jB-C3CdS.js"), true ? [] : void 0, import.meta.url)
209535
+ loader: () => __vitePreload(() => import("./yaml-DpzsqvWa.js"), true ? [] : void 0, import.meta.url)
209516
209536
  });
209517
209537
  var __defProp = Object.defineProperty;
209518
209538
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -213286,11 +213306,14 @@ function RemoteConnect({ onConnect, onBack }) {
213286
213306
  ] })
213287
213307
  ] }) });
213288
213308
  }
213289
- function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
213290
- const displayPath = cwd2.replace(/^\/Users\/[^/]+/, "~");
213309
+ function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd, onCancel, restarting = false }) {
213310
+ const [selectedCwd, setSelectedCwd] = reactExports.useState(cwd2);
213311
+ const displayPath = selectedCwd.replace(/^\/Users\/[^/]+/, "~");
213291
213312
  const [logChat, setLogChat] = reactExports.useState(false);
213292
213313
  const [loaded, setLoaded] = reactExports.useState(false);
213293
213314
  const [remoteMode, setRemoteMode] = reactExports.useState(false);
213315
+ const [handoff, setHandoff] = reactExports.useState("fresh");
213316
+ const [switching, setSwitching] = reactExports.useState(false);
213294
213317
  reactExports.useEffect(() => {
213295
213318
  let cancelled = false;
213296
213319
  window.worker.getLogChat().then((r) => {
@@ -213311,20 +213334,30 @@ function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
213311
213334
  }
213312
213335
  };
213313
213336
  const handleSelect = async (agent) => {
213337
+ if (switching) return;
213338
+ setSwitching(true);
213314
213339
  if (loaded) {
213315
213340
  try {
213316
213341
  await window.worker.setLogChat(logChat);
213317
213342
  } catch {
213318
213343
  }
213319
213344
  }
213320
- onSelect(agent);
213345
+ try {
213346
+ await onSelect(agent, selectedCwd, handoff);
213347
+ } finally {
213348
+ setSwitching(false);
213349
+ }
213350
+ };
213351
+ const changeCwd = async () => {
213352
+ const next = await onChangeCwd();
213353
+ if (next) setSelectedCwd(next);
213321
213354
  };
213322
213355
  if (remoteMode) {
213323
213356
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
213324
213357
  RemoteConnect,
213325
213358
  {
213326
213359
  onConnect: (agent) => {
213327
- handleSelect(agent);
213360
+ void handleSelect(agent);
213328
213361
  },
213329
213362
  onBack: () => setRemoteMode(false)
213330
213363
  }
@@ -213332,18 +213365,55 @@ function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
213332
213365
  }
213333
213366
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-overlay", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-modal", children: [
213334
213367
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-brand", children: "ctlsurf" }),
213335
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-cwd", onClick: onChangeCwd, title: "Click to change directory", children: [
213368
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-cwd", onClick: () => void changeCwd(), title: "Click to change directory", children: [
213336
213369
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-cwd-icon", children: "📂" }),
213337
213370
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-cwd-path", children: displayPath }),
213338
213371
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-cwd-change", children: "change" })
213339
213372
  ] }),
213340
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-title", children: "SELECT AGENT" }),
213373
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-title", children: restarting ? "CHANGE SESSION" : "SELECT AGENT" }),
213374
+ restarting && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
213375
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-warning", children: "Choosing an agent restarts this terminal and ends its current process." }),
213376
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("fieldset", { className: "agent-handoff-options", children: [
213377
+ /* @__PURE__ */ jsxRuntimeExports.jsx("legend", { children: "NEW SESSION CONTEXT" }),
213378
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: handoff === "fresh" ? "selected" : "", children: [
213379
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
213380
+ "input",
213381
+ {
213382
+ type: "radio",
213383
+ name: "session-handoff",
213384
+ checked: handoff === "fresh",
213385
+ onChange: () => setHandoff("fresh")
213386
+ }
213387
+ ),
213388
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
213389
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Start fresh" }),
213390
+ /* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: "Do not send anything from this terminal." })
213391
+ ] })
213392
+ ] }),
213393
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: handoff === "context" ? "selected" : "", children: [
213394
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
213395
+ "input",
213396
+ {
213397
+ type: "radio",
213398
+ name: "session-handoff",
213399
+ checked: handoff === "context",
213400
+ onChange: () => setHandoff("context")
213401
+ }
213402
+ ),
213403
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
213404
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Share previous context" }),
213405
+ /* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: "Quote it inline, or use a temporary file when the session is long." })
213406
+ ] })
213407
+ ] })
213408
+ ] })
213409
+ ] }),
213341
213410
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-list", children: [
213342
213411
  agents.map((a) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
213343
213412
  "button",
213344
213413
  {
213345
213414
  className: "agent-picker-item",
213346
- onClick: () => handleSelect(a),
213415
+ disabled: switching,
213416
+ onClick: () => void handleSelect(a),
213347
213417
  children: [
213348
213418
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-name", children: a.name }),
213349
213419
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-desc", children: a.description })
@@ -213355,6 +213425,7 @@ function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
213355
213425
  "button",
213356
213426
  {
213357
213427
  className: "agent-picker-item",
213428
+ disabled: switching,
213358
213429
  onClick: () => setRemoteMode(true),
213359
213430
  children: [
213360
213431
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "agent-picker-name", children: "🌐 Remote (SSH)" }),
@@ -213374,15 +213445,17 @@ function AgentPicker({ agents, cwd: cwd2, onSelect, onChangeCwd }) {
213374
213445
  ),
213375
213446
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Log chat to ctlsurf" })
213376
213447
  ] }),
213377
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-hint", children: "Select an agent to start" })
213448
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-hint", children: restarting ? "Select an agent to restart in the directory above" : "Select an agent to start" }),
213449
+ onCancel && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "remote-link", disabled: switching, onClick: onCancel, children: "Cancel" })
213378
213450
  ] }) });
213379
213451
  }
213380
- function ProjectPicker({ onDone }) {
213452
+ function ProjectPicker({ onDone, currentProject }) {
213381
213453
  const [state, setState2] = reactExports.useState("loading");
213382
213454
  const [projects, setProjects] = reactExports.useState([]);
213383
213455
  const [errorMsg, setErrorMsg] = reactExports.useState("");
213384
213456
  const [binding, setBinding] = reactExports.useState(false);
213385
213457
  const [filter, setFilter] = reactExports.useState("");
213458
+ const [notifyAgent, setNotifyAgent] = reactExports.useState(true);
213386
213459
  reactExports.useEffect(() => {
213387
213460
  let cancelled = false;
213388
213461
  window.worker.listProjects().then((r) => {
@@ -213406,23 +213479,36 @@ function ProjectPicker({ onDone }) {
213406
213479
  const pick = async (p) => {
213407
213480
  setBinding(true);
213408
213481
  try {
213409
- await window.worker.bindProject(p.root_path);
213410
- } catch {
213482
+ const result = await window.worker.bindProject(p.root_path);
213483
+ if (!result.ok) {
213484
+ setErrorMsg(result.error || "Could not bind project");
213485
+ setState2("error");
213486
+ setBinding(false);
213487
+ return;
213488
+ }
213489
+ onDone({ project: p, notifyAgent });
213490
+ } catch (err) {
213491
+ setErrorMsg(err instanceof Error ? err.message : "Could not bind project");
213492
+ setState2("error");
213493
+ setBinding(false);
213411
213494
  }
213412
- onDone();
213413
213495
  };
213414
213496
  const shown = filter.trim() ? projects.filter((p) => p.name.toLowerCase().includes(filter.toLowerCase()) || p.root_path.toLowerCase().includes(filter.toLowerCase())) : projects;
213415
213497
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-overlay", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "agent-picker-modal", children: [
213416
213498
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-brand", children: "ctlsurf" }),
213417
213499
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "agent-picker-title", children: "SELECT CTLSURF PROJECT" }),
213418
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-target-line", children: "Bind this remote session to a project" }),
213500
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-target-line", children: "Bind the active session to a project" }),
213501
+ currentProject && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "remote-note", children: [
213502
+ "Currently linked to ",
213503
+ currentProject
213504
+ ] }),
213419
213505
  state === "loading" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "remote-status", children: [
213420
213506
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-spinner" }),
213421
213507
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading projects…" })
213422
213508
  ] }),
213423
213509
  state === "error" && /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-note", children: errorMsg }) }),
213424
213510
  state === "ready" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
213425
- projects.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-note", children: "No ctlsurf projects found. You can skip and bind one later." }),
213511
+ projects.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "remote-note", children: "No ctlsurf projects found." }),
213426
213512
  projects.length > 6 && /* @__PURE__ */ jsxRuntimeExports.jsx(
213427
213513
  "input",
213428
213514
  {
@@ -213452,7 +213538,22 @@ function ProjectPicker({ onDone }) {
213452
213538
  p.id
213453
213539
  )) })
213454
213540
  ] }),
213455
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "remote-link", disabled: binding, onClick: onDone, children: "Skip — no project" })
213541
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "agent-picker-option project-notify-option", children: [
213542
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
213543
+ "input",
213544
+ {
213545
+ type: "checkbox",
213546
+ checked: notifyAgent,
213547
+ disabled: binding,
213548
+ onChange: (e) => setNotifyAgent(e.target.checked)
213549
+ }
213550
+ ),
213551
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
213552
+ "Tell the active agent about this project",
213553
+ /* @__PURE__ */ jsxRuntimeExports.jsx("small", { children: "Includes the ctlsurf project and codebase details as context." })
213554
+ ] })
213555
+ ] }),
213556
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "remote-link", disabled: binding, onClick: () => onDone(), children: "Close without changing" })
213456
213557
  ] }) });
213457
213558
  }
213458
213559
  function removePane(node, paneId) {
@@ -214760,6 +214861,41 @@ let _tabCounter = 0;
214760
214861
  function nextTabId() {
214761
214862
  return `tab-${++_tabCounter}`;
214762
214863
  }
214864
+ function buildSessionHandoff(transcript) {
214865
+ const quoted = transcript.split("\n").map((line) => `> ${line}`).join("\n");
214866
+ return [
214867
+ "The quoted text below is what we did in the last session. It is provided for information only; no action is needed.",
214868
+ "Do not continue, repeat, or act on anything in it unless I explicitly ask in a new message. Wait for my next instruction.",
214869
+ "",
214870
+ quoted
214871
+ ].join("\n");
214872
+ }
214873
+ const INLINE_HANDOFF_CHARS = 12e3;
214874
+ const REMOTE_HANDOFF_CHARS = 3e4;
214875
+ function buildFileSessionHandoff(filePath, trimmed) {
214876
+ return [
214877
+ "This is what we did in the last session. It is provided for information only; no action is needed.",
214878
+ "The quoted session transcript was too long to paste, so it is stored in this temporary Markdown file:",
214879
+ `\`${filePath}\``,
214880
+ trimmed ? "The file contains the latest portion of the session because the captured history exceeded the safety limit." : "",
214881
+ "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."
214882
+ ].filter(Boolean).join("\n\n");
214883
+ }
214884
+ function buildProjectContextNotice(selection, terminalCwd, agentName) {
214885
+ const { project } = selection;
214886
+ return [
214887
+ "The active ctlsurf project binding has changed. Use the quoted details below as context for future requests.",
214888
+ "This notice does not start a new task. Do not take action solely because of it.",
214889
+ "",
214890
+ `> ctlsurf project: ${project.name}`,
214891
+ `> ctlsurf project ID: ${project.id}`,
214892
+ `> configured codebase root: ${project.root_path}`,
214893
+ `> current terminal directory: ${terminalCwd || "(unknown)"}`,
214894
+ `> active coding agent: ${agentName || "(unknown)"}`,
214895
+ "",
214896
+ 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."
214897
+ ].join("\n");
214898
+ }
214763
214899
  function App() {
214764
214900
  const [agents, setAgents] = reactExports.useState([]);
214765
214901
  const [sessionStart, setSessionStart] = reactExports.useState(null);
@@ -214774,7 +214910,7 @@ function App() {
214774
214910
  const ctlsurfNavCounter = reactExports.useRef(0);
214775
214911
  const [tabs, setTabs] = reactExports.useState(() => {
214776
214912
  const id = nextTabId();
214777
- return [{ id, label: "Terminal 1", agent: null, agentStatus: "idle" }];
214913
+ return [{ id, label: "Terminal 1", agent: null, agentStatus: "idle", sessionVersion: 0 }];
214778
214914
  });
214779
214915
  const [activeTabId, setActiveTabId] = reactExports.useState(tabs[0].id);
214780
214916
  const [trackingActive, setTrackingActive] = reactExports.useState(false);
@@ -214887,21 +215023,44 @@ function App() {
214887
215023
  setTimeout(() => window.worker.writePty(activeTabId, "\r"), 120);
214888
215024
  }, [activeTabId]);
214889
215025
  const cwdRef = reactExports.useRef(null);
215026
+ const pendingHandoffsRef = reactExports.useRef(/* @__PURE__ */ new Map());
215027
+ const handoffTimersRef = reactExports.useRef(/* @__PURE__ */ new Map());
215028
+ const handoffGenerationsRef = reactExports.useRef(/* @__PURE__ */ new Map());
214890
215029
  const handleSpawn = reactExports.useCallback(async (tabId, agent) => {
215030
+ const oldTimer = handoffTimersRef.current.get(tabId);
215031
+ if (oldTimer) clearTimeout(oldTimer);
215032
+ handoffTimersRef.current.delete(tabId);
215033
+ const handoffGeneration = (handoffGenerationsRef.current.get(tabId) || 0) + 1;
215034
+ handoffGenerationsRef.current.set(tabId, handoffGeneration);
214891
215035
  setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "active" } : t));
214892
215036
  setSessionStart(/* @__PURE__ */ new Date());
214893
215037
  const spawnCwd = cwdRef.current || await window.worker.getCwd().catch(() => window.worker.getHomePath());
214894
215038
  setCwd(spawnCwd);
214895
215039
  cwdRef.current = spawnCwd;
214896
- await window.worker.spawnAgent(tabId, agent, spawnCwd);
214897
- }, []);
214898
- const handleAgentChange = reactExports.useCallback(async (agentId) => {
214899
- const agent = agents.find((a) => a.id === agentId);
214900
- if (agent) {
214901
- await window.worker.killPty(activeTabId);
214902
- setTabs((prev) => prev.map((t) => t.id === activeTabId ? { ...t, agent, agentStatus: "idle" } : t));
215040
+ try {
215041
+ await window.worker.spawnAgent(tabId, agent, spawnCwd);
215042
+ } catch (err) {
215043
+ console.error("[session] Failed to start agent", err);
215044
+ pendingHandoffsRef.current.delete(tabId);
215045
+ setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "exited" } : t));
215046
+ return;
214903
215047
  }
214904
- }, [agents, activeTabId]);
215048
+ const handoff = pendingHandoffsRef.current.get(tabId);
215049
+ pendingHandoffsRef.current.delete(tabId);
215050
+ if (handoff) {
215051
+ const timer = setTimeout(() => {
215052
+ if (handoffGenerationsRef.current.get(tabId) !== handoffGeneration) return;
215053
+ window.worker.writePty(tabId, handoff);
215054
+ focusTerminal(tabId);
215055
+ setTimeout(() => {
215056
+ if (handoffGenerationsRef.current.get(tabId) === handoffGeneration) {
215057
+ window.worker.writePty(tabId, "\r");
215058
+ }
215059
+ }, 120);
215060
+ }, 1200);
215061
+ handoffTimersRef.current.set(tabId, timer);
215062
+ }
215063
+ }, []);
214905
215064
  const handleExit = reactExports.useCallback((tabId) => {
214906
215065
  setTimeout(() => {
214907
215066
  setTabs((prev) => prev.map((t) => t.id === tabId ? { ...t, agentStatus: "exited" } : t));
@@ -214910,36 +215069,84 @@ function App() {
214910
215069
  const handleChangeCwd = reactExports.useCallback(async () => {
214911
215070
  const newCwd = await window.worker.browseCwd();
214912
215071
  const activeTab = tabs.find((t) => t.id === activeTabId);
214913
- if (!newCwd || !activeTab?.agent) return;
215072
+ if (!newCwd) return;
214914
215073
  cwdRef.current = newCwd;
214915
215074
  setCwd(newCwd);
214916
- await window.worker.killPty(activeTabId);
214917
- setTabs((prev) => prev.map((t) => t.id === activeTabId ? { ...t, agentStatus: "active" } : t));
214918
- setSessionStart(/* @__PURE__ */ new Date());
214919
- await window.worker.spawnAgent(activeTabId, activeTab.agent, newCwd);
215075
+ if (!activeTab?.agent) return;
215076
+ pendingHandoffsRef.current.delete(activeTabId);
215077
+ setTabs((prev) => prev.map((t) => t.id === activeTabId ? { ...t, agentStatus: "idle", sessionVersion: t.sessionVersion + 1 } : t));
214920
215078
  }, [tabs, activeTabId]);
214921
215079
  const addTab = reactExports.useCallback(() => {
214922
215080
  const id = nextTabId();
214923
215081
  const num = _tabCounter;
214924
- setTabs((prev) => [...prev, { id, label: `Terminal ${num}`, agent: null, agentStatus: "idle" }]);
215082
+ setTabs((prev) => [...prev, { id, label: `Terminal ${num}`, agent: null, agentStatus: "idle", sessionVersion: 0 }]);
214925
215083
  setActiveTabId(id);
214926
215084
  setPickerTargetTabId(id);
214927
215085
  setShowAgentPicker(true);
214928
215086
  }, []);
214929
- const handlePickerSelect = reactExports.useCallback((agent) => {
215087
+ const handlePickerSelect = reactExports.useCallback(async (agent, selectedCwd, handoff) => {
214930
215088
  const tabId = pickerTargetTabId;
214931
215089
  if (tabId) {
214932
- setTabs((prev) => prev.map(
214933
- (t) => t.id === tabId ? { ...t, agent, label: `${agent.name} ${tabs.filter((x) => x.agent?.id === agent.id).length + 1}` } : t
214934
- ));
215090
+ if (handoff === "context") {
215091
+ const transcript = captureTerminalSession(tabId);
215092
+ if (!transcript) {
215093
+ pendingHandoffsRef.current.delete(tabId);
215094
+ } else if (transcript.length > INLINE_HANDOFF_CHARS && !agent.id.startsWith("remote-")) {
215095
+ const result = await window.worker.createSessionHandoffFile(transcript);
215096
+ if (result.ok && result.path) {
215097
+ pendingHandoffsRef.current.set(tabId, buildFileSessionHandoff(result.path, !!result.trimmed));
215098
+ } else {
215099
+ console.warn("[session] Could not create handoff file; using a shortened inline handoff", result.error);
215100
+ pendingHandoffsRef.current.set(tabId, buildSessionHandoff(transcript.slice(-REMOTE_HANDOFF_CHARS)));
215101
+ }
215102
+ } else {
215103
+ const inline2 = transcript.length > REMOTE_HANDOFF_CHARS ? `[Earlier terminal output omitted.]
215104
+ ${transcript.slice(-REMOTE_HANDOFF_CHARS)}` : transcript;
215105
+ pendingHandoffsRef.current.set(tabId, buildSessionHandoff(inline2));
215106
+ }
215107
+ } else {
215108
+ pendingHandoffsRef.current.delete(tabId);
215109
+ }
215110
+ cwdRef.current = selectedCwd;
215111
+ setCwd(selectedCwd);
215112
+ setTabs((prev) => {
215113
+ const matchingAgents = prev.filter((x) => x.agent?.id === agent.id).length;
215114
+ return prev.map((t) => t.id === tabId ? {
215115
+ ...t,
215116
+ agent,
215117
+ agentStatus: "idle",
215118
+ label: `${agent.name} ${matchingAgents + (t.agent?.id === agent.id ? 0 : 1)}`,
215119
+ sessionVersion: t.sessionVersion + 1
215120
+ } : t);
215121
+ });
214935
215122
  }
214936
215123
  setShowAgentPicker(false);
214937
215124
  setPickerTargetTabId(null);
214938
215125
  if (agent.id.startsWith("remote-")) {
214939
215126
  setShowProjectPicker(true);
214940
215127
  }
214941
- }, [pickerTargetTabId, tabs]);
215128
+ }, [pickerTargetTabId]);
215129
+ const openSessionPicker = reactExports.useCallback(() => {
215130
+ setPickerTargetTabId(activeTabId);
215131
+ setShowAgentPicker(true);
215132
+ }, [activeTabId]);
215133
+ const handleProjectPickerDone = reactExports.useCallback(async (selection) => {
215134
+ setShowProjectPicker(false);
215135
+ if (!selection?.notifyAgent) return;
215136
+ const activeAgent = tabs.find((t) => t.id === activeTabId)?.agent;
215137
+ if (!activeAgent) return;
215138
+ const terminalCwd = await window.worker.getActiveTabCwd().catch(() => cwd2);
215139
+ const notice = buildProjectContextNotice(selection, terminalCwd, activeAgent.name);
215140
+ window.worker.writePty(activeTabId, notice);
215141
+ focusTerminal(activeTabId);
215142
+ setTimeout(() => window.worker.writePty(activeTabId, "\r"), 120);
215143
+ }, [activeTabId, cwd2, tabs]);
214942
215144
  const closeTab = reactExports.useCallback(async (tabId) => {
215145
+ pendingHandoffsRef.current.delete(tabId);
215146
+ handoffGenerationsRef.current.set(tabId, (handoffGenerationsRef.current.get(tabId) || 0) + 1);
215147
+ const handoffTimer = handoffTimersRef.current.get(tabId);
215148
+ if (handoffTimer) clearTimeout(handoffTimer);
215149
+ handoffTimersRef.current.delete(tabId);
214943
215150
  await window.worker.killPty(tabId);
214944
215151
  destroyTerminal(tabId);
214945
215152
  setTabs((prev) => {
@@ -214953,7 +215160,7 @@ function App() {
214953
215160
  setActiveTabId(id);
214954
215161
  setPickerTargetTabId(id);
214955
215162
  setShowAgentPicker(true);
214956
- return [{ id, label: `Terminal ${num}`, agent: null, agentStatus: "idle" }];
215163
+ return [{ id, label: `Terminal ${num}`, agent: null, agentStatus: "idle", sessionVersion: 0 }];
214957
215164
  }
214958
215165
  return next;
214959
215166
  });
@@ -215087,6 +215294,7 @@ function App() {
215087
215294
  {
215088
215295
  tabId: tab.id,
215089
215296
  agent: tab.agent,
215297
+ sessionVersion: tab.sessionVersion,
215090
215298
  onSpawn: handleSpawn,
215091
215299
  onExit: handleExit,
215092
215300
  isActive: tab.id === activeTabId
@@ -215217,19 +215425,28 @@ function App() {
215217
215425
  ),
215218
215426
  /* @__PURE__ */ jsxRuntimeExports.jsx(SpeakControls, { remote: activeAgentIsRemote }),
215219
215427
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "titlebar-separator" }),
215220
- agents.map((a) => {
215221
- const activeTab = tabs.find((t) => t.id === activeTabId);
215222
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
215223
- "button",
215224
- {
215225
- className: `titlebar-agent-btn ${activeTab?.agent?.id === a.id ? "active" : ""}`,
215226
- onClick: () => handleAgentChange(a.id),
215227
- title: a.description,
215228
- children: a.name
215229
- },
215230
- a.id
215231
- );
215232
- }),
215428
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
215429
+ "button",
215430
+ {
215431
+ className: "titlebar-agent-btn active",
215432
+ onClick: openSessionPicker,
215433
+ title: "Change coding agent or project directory for the active terminal",
215434
+ children: [
215435
+ "Agent: ",
215436
+ tabs.find((t) => t.id === activeTabId)?.agent?.name || "Choose",
215437
+ " ▾"
215438
+ ]
215439
+ }
215440
+ ),
215441
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
215442
+ "button",
215443
+ {
215444
+ className: "titlebar-btn",
215445
+ onClick: () => setShowProjectPicker(true),
215446
+ title: "Change the ctlsurf project linked to the active session",
215447
+ children: "Project…"
215448
+ }
215449
+ ),
215233
215450
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "titlebar-separator" }),
215234
215451
  ALL_PANE_IDS.map((id) => /* @__PURE__ */ jsxRuntimeExports.jsx(
215235
215452
  "button",
@@ -215260,16 +215477,15 @@ function App() {
215260
215477
  agents,
215261
215478
  cwd: cwd2 || "",
215262
215479
  onSelect: handlePickerSelect,
215263
- onChangeCwd: async () => {
215264
- const newCwd = await window.worker.browseCwd();
215265
- if (newCwd) {
215266
- setCwd(newCwd);
215267
- cwdRef.current = newCwd;
215268
- }
215269
- }
215480
+ onChangeCwd: () => window.worker.browseCwd(),
215481
+ onCancel: tabs.find((t) => t.id === pickerTargetTabId)?.agent ? () => {
215482
+ setShowAgentPicker(false);
215483
+ setPickerTargetTabId(null);
215484
+ } : void 0,
215485
+ restarting: !!tabs.find((t) => t.id === pickerTargetTabId)?.agent
215270
215486
  }
215271
215487
  ),
215272
- showProjectPicker && /* @__PURE__ */ jsxRuntimeExports.jsx(ProjectPicker, { onDone: () => setShowProjectPicker(false) }),
215488
+ showProjectPicker && /* @__PURE__ */ jsxRuntimeExports.jsx(ProjectPicker, { currentProject: projectName, onDone: handleProjectPickerDone }),
215273
215489
  showFloatingMic && /* @__PURE__ */ jsxRuntimeExports.jsx(
215274
215490
  FloatingMic,
215275
215491
  {