@phenx-inc/ctlsurf 0.3.15 → 0.4.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 (31) hide show
  1. package/out/headless/index.mjs +9 -6
  2. package/out/headless/index.mjs.map +2 -2
  3. package/out/main/index.js +12 -5
  4. package/out/preload/index.js +2 -0
  5. package/out/renderer/assets/{cssMode-D5dPwEy5.js → cssMode-DkmdBgO7.js} +3 -3
  6. package/out/renderer/assets/{freemarker2-c5jJjQ9s.js → freemarker2-CI-gkP-3.js} +1 -1
  7. package/out/renderer/assets/{handlebars-BTbmOxx9.js → handlebars-D5tEqanR.js} +1 -1
  8. package/out/renderer/assets/{html-3cIIQcxO.js → html-fH93EYfn.js} +1 -1
  9. package/out/renderer/assets/{htmlMode-DYbpW1yY.js → htmlMode-CRicxcwK.js} +3 -3
  10. package/out/renderer/assets/{index-D2MUZin7.js → index-BOOvUI7u.js} +192 -23
  11. package/out/renderer/assets/{index-6KvOnYL1.css → index-ezC-iarf.css} +40 -0
  12. package/out/renderer/assets/{javascript-CDuCMm-6.js → javascript-D1Baz4fV.js} +2 -2
  13. package/out/renderer/assets/{jsonMode-COLqbq0s.js → jsonMode-Bquqf3QN.js} +3 -3
  14. package/out/renderer/assets/{liquid-BFcqZizB.js → liquid-ByOcPjBF.js} +1 -1
  15. package/out/renderer/assets/{lspLanguageFeatures-CbkEcL-z.js → lspLanguageFeatures-BxPLl0yy.js} +1 -1
  16. package/out/renderer/assets/{mdx-DyK93oEE.js → mdx-yuNgx0rM.js} +1 -1
  17. package/out/renderer/assets/{python-D4lCwSVr.js → python-2OakgLlA.js} +1 -1
  18. package/out/renderer/assets/{razor-DdkE9XVt.js → razor-DnIVMSwa.js} +1 -1
  19. package/out/renderer/assets/{tsMode-BrQ4Fsc-.js → tsMode-CRIrHuii.js} +1 -1
  20. package/out/renderer/assets/{typescript-BakbYMnC.js → typescript-DJ3C8Yly.js} +1 -1
  21. package/out/renderer/assets/{xml-DHDW9Xhp.js → xml-CalvD5_C.js} +1 -1
  22. package/out/renderer/assets/{yaml-1Ayv_J3q.js → yaml-Cgs8pdVp.js} +1 -1
  23. package/out/renderer/index.html +2 -2
  24. package/package.json +1 -1
  25. package/src/main/index.ts +8 -1
  26. package/src/main/workerWs.ts +8 -6
  27. package/src/preload/index.ts +4 -0
  28. package/src/renderer/App.tsx +1 -0
  29. package/src/renderer/components/TerminalPanel.tsx +95 -2
  30. package/src/renderer/lib/tableToHtml.ts +146 -0
  31. package/src/renderer/styles.css +40 -0
package/out/main/index.js CHANGED
@@ -9953,11 +9953,9 @@ class WorkerWsClient {
9953
9953
  workerId = null;
9954
9954
  _status = "disconnected";
9955
9955
  shouldReconnect = false;
9956
- fingerprint;
9957
9956
  constructor(events, baseUrl) {
9958
9957
  this.events = events;
9959
9958
  this.baseUrl = baseUrl || "wss://app.ctlsurf.com";
9960
- this.fingerprint = this.generateFingerprint();
9961
9959
  }
9962
9960
  get status() {
9963
9961
  return this._status;
@@ -9971,8 +9969,12 @@ class WorkerWsClient {
9971
9969
  setBaseUrl(url) {
9972
9970
  this.baseUrl = url;
9973
9971
  }
9974
- generateFingerprint() {
9975
- const data = `${os.hostname()}:${os.userInfo().username}:${os.platform()}:${os.arch()}`;
9972
+ // Per-directory fingerprint: each working directory is a distinct worker, so
9973
+ // multiple instances on the same machine (one per project) don't collide as a
9974
+ // single worker server-side. cwd is included so the same folder maps to the
9975
+ // same worker across restarts.
9976
+ generateFingerprint(cwd) {
9977
+ const data = `${os.hostname()}:${os.userInfo().username}:${os.platform()}:${os.arch()}:${cwd}`;
9976
9978
  return require$$1.createHash("sha256").update(data).digest("hex").slice(0, 32);
9977
9979
  }
9978
9980
  setStatus(status) {
@@ -9982,7 +9984,8 @@ class WorkerWsClient {
9982
9984
  }
9983
9985
  }
9984
9986
  connect(registration) {
9985
- this.registration = { ...registration, fingerprint: this.fingerprint };
9987
+ const fingerprint = this.generateFingerprint(registration.cwd);
9988
+ this.registration = { ...registration, fingerprint };
9986
9989
  this.shouldReconnect = true;
9987
9990
  this.doConnect();
9988
9991
  }
@@ -11298,6 +11301,10 @@ function createWindow() {
11298
11301
  mainWindow = null;
11299
11302
  });
11300
11303
  }
11304
+ electron.ipcMain.handle("clipboard:writeTable", (_event, html, text) => {
11305
+ electron.clipboard.write({ html, text });
11306
+ return { ok: true };
11307
+ });
11301
11308
  electron.ipcMain.handle("pty:spawn", async (_event, tabId, agent, cwd) => {
11302
11309
  await orchestrator.spawnAgent(tabId, agent, cwd);
11303
11310
  return { ok: true };
@@ -31,6 +31,8 @@ const api = {
31
31
  return () => electron.ipcRenderer.removeListener("app:projectChanged", listener);
32
32
  },
33
33
  browseCwd: () => electron.ipcRenderer.invoke("app:browseCwd"),
34
+ // Clipboard — write a rich-HTML table (+ plain-text fallback) for email paste.
35
+ copyEmailTable: (html, text) => electron.ipcRenderer.invoke("clipboard:writeTable", html, text),
34
36
  getVersion: () => electron.ipcRenderer.invoke("app:getVersion"),
35
37
  getUpdateInfo: () => electron.ipcRenderer.invoke("app:getUpdateInfo"),
36
38
  onUpdateInfo: (callback) => {
@@ -1,6 +1,6 @@
1
- import { c as createWebWorker, l as languages } from "./index-D2MUZin7.js";
2
- import { C as CompletionAdapter, H as HoverAdapter, D as DocumentHighlightAdapter, a as DefinitionAdapter, R as ReferenceAdapter, b as DocumentSymbolAdapter, c as RenameAdapter, d as DocumentColorAdapter, F as FoldingRangeAdapter, e as DiagnosticsAdapter, S as SelectionRangeAdapter, f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider } from "./lspLanguageFeatures-CbkEcL-z.js";
3
- import { h, i, j, t, k } from "./lspLanguageFeatures-CbkEcL-z.js";
1
+ import { c as createWebWorker, l as languages } from "./index-BOOvUI7u.js";
2
+ import { C as CompletionAdapter, H as HoverAdapter, D as DocumentHighlightAdapter, a as DefinitionAdapter, R as ReferenceAdapter, b as DocumentSymbolAdapter, c as RenameAdapter, d as DocumentColorAdapter, F as FoldingRangeAdapter, e as DiagnosticsAdapter, S as SelectionRangeAdapter, f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider } from "./lspLanguageFeatures-BxPLl0yy.js";
3
+ import { h, i, j, t, k } from "./lspLanguageFeatures-BxPLl0yy.js";
4
4
  const STOP_WHEN_IDLE_FOR = 2 * 60 * 1e3;
5
5
  class WorkerManager {
6
6
  constructor(defaults) {
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const EMPTY_ELEMENTS = [
3
3
  "assign",
4
4
  "flush",
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const EMPTY_ELEMENTS = [
3
3
  "area",
4
4
  "base",
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const EMPTY_ELEMENTS = [
3
3
  "area",
4
4
  "base",
@@ -1,6 +1,6 @@
1
- import { c as createWebWorker, l as languages } from "./index-D2MUZin7.js";
2
- import { H as HoverAdapter, D as DocumentHighlightAdapter, h as DocumentLinkAdapter, F as FoldingRangeAdapter, b as DocumentSymbolAdapter, S as SelectionRangeAdapter, c as RenameAdapter, f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider, C as CompletionAdapter } from "./lspLanguageFeatures-CbkEcL-z.js";
3
- import { a, e, d, R, i, j, t, k } from "./lspLanguageFeatures-CbkEcL-z.js";
1
+ import { c as createWebWorker, l as languages } from "./index-BOOvUI7u.js";
2
+ import { H as HoverAdapter, D as DocumentHighlightAdapter, h as DocumentLinkAdapter, F as FoldingRangeAdapter, b as DocumentSymbolAdapter, S as SelectionRangeAdapter, c as RenameAdapter, f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider, C as CompletionAdapter } from "./lspLanguageFeatures-BxPLl0yy.js";
3
+ import { a, e, d, R, i, j, t, k } from "./lspLanguageFeatures-BxPLl0yy.js";
4
4
  const STOP_WHEN_IDLE_FOR = 2 * 60 * 1e3;
5
5
  class WorkerManager {
6
6
  constructor(defaults) {
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-D5dPwEy5.js","./lspLanguageFeatures-CbkEcL-z.js","./htmlMode-DYbpW1yY.js","./jsonMode-COLqbq0s.js","./javascript-CDuCMm-6.js","./typescript-BakbYMnC.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-DkmdBgO7.js","./lspLanguageFeatures-BxPLl0yy.js","./htmlMode-CRicxcwK.js","./jsonMode-Bquqf3QN.js","./javascript-D1Baz4fV.js","./typescript-DJ3C8Yly.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
  }
@@ -18721,6 +18721,114 @@ function requireAddonWebLinks() {
18721
18721
  return addonWebLinks.exports;
18722
18722
  }
18723
18723
  var addonWebLinksExports = requireAddonWebLinks();
18724
+ const VERTICAL = /[│┃┆┇┊┋|]/;
18725
+ const BOX_CHARS = /[─-╿]/g;
18726
+ const ANSI = /\x1B(?:\[[0-9;?]*[ -\/]*[@-~]|[@-_])/g;
18727
+ const INVISIBLE = /[​-‍⁠]/g;
18728
+ const ODD_SPACE = /[  -    ]/g;
18729
+ function cleanInput(input) {
18730
+ return input.replace(ANSI, "").replace(INVISIBLE, "").replace(ODD_SPACE, " ");
18731
+ }
18732
+ function splitRow(line) {
18733
+ const parts = line.split(VERTICAL).map((c) => c.trim());
18734
+ if (parts.length && parts[0] === "") parts.shift();
18735
+ if (parts.length && parts[parts.length - 1] === "") parts.pop();
18736
+ return parts;
18737
+ }
18738
+ function isBorderLine(line) {
18739
+ return line.replace(BOX_CHARS, "").trim() === "";
18740
+ }
18741
+ function isMarkdownSeparator(line) {
18742
+ return /-/.test(line) && /^[\s|:\-]+$/.test(line.trim());
18743
+ }
18744
+ function looksLikeBox(input) {
18745
+ return /[─-╿]/.test(input);
18746
+ }
18747
+ function normalizeWidth(rows) {
18748
+ const cols = rows.reduce((m, r) => Math.max(m, r.length), 0);
18749
+ return rows.map((r) => {
18750
+ const copy = r.slice();
18751
+ while (copy.length < cols) copy.push("");
18752
+ return copy;
18753
+ });
18754
+ }
18755
+ function parseBox(lines) {
18756
+ const rows = [];
18757
+ for (const line of lines) {
18758
+ if (line.trim() === "") continue;
18759
+ if (isBorderLine(line)) continue;
18760
+ if (!VERTICAL.test(line)) continue;
18761
+ rows.push(splitRow(line));
18762
+ }
18763
+ return { rows: normalizeWidth(rows), hasHeader: rows.length > 1 };
18764
+ }
18765
+ function parseMarkdown(lines) {
18766
+ const rows = [];
18767
+ let separatorIndex = -1;
18768
+ for (const line of lines) {
18769
+ if (line.trim() === "") continue;
18770
+ if (!line.includes("|") && !isMarkdownSeparator(line)) continue;
18771
+ if (isMarkdownSeparator(line)) {
18772
+ separatorIndex = rows.length;
18773
+ continue;
18774
+ }
18775
+ rows.push(splitRow(line));
18776
+ }
18777
+ return {
18778
+ rows: normalizeWidth(rows),
18779
+ hasHeader: separatorIndex === 1 || separatorIndex === -1 && rows.length > 1
18780
+ };
18781
+ }
18782
+ function parseTable(input) {
18783
+ if (!input || !input.trim()) return { rows: [], hasHeader: false };
18784
+ const cleaned = cleanInput(input);
18785
+ const lines = cleaned.replace(/\r\n?/g, "\n").split("\n");
18786
+ if (looksLikeBox(cleaned)) return parseBox(lines);
18787
+ if (cleaned.includes("|")) return parseMarkdown(lines);
18788
+ return parseBox(lines);
18789
+ }
18790
+ const TABLE_STYLE = "border-collapse:collapse;border:1px solid #d0d7de;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Arial,sans-serif;font-size:14px;color:#1f2328;";
18791
+ const TH_STYLE = "border:1px solid #d0d7de;padding:8px 12px;text-align:left;background:#f0f3f6;font-weight:600;";
18792
+ const TD_STYLE = "border:1px solid #d0d7de;padding:8px 12px;text-align:left;vertical-align:top;";
18793
+ function escapeHtml(s) {
18794
+ return String(s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
18795
+ }
18796
+ function buildHtml(rows, hasHeader) {
18797
+ const out = ['<table cellspacing="0" cellpadding="0" style="' + TABLE_STYLE + '">'];
18798
+ rows.forEach((row, i2) => {
18799
+ const isHeader = hasHeader && i2 === 0;
18800
+ const tag2 = isHeader ? "th" : "td";
18801
+ const style = isHeader ? TH_STYLE : TD_STYLE;
18802
+ out.push("<tr>");
18803
+ for (const cell of row) {
18804
+ out.push("<" + tag2 + ' style="' + style + '">' + escapeHtml(cell) + "</" + tag2 + ">");
18805
+ }
18806
+ out.push("</tr>");
18807
+ });
18808
+ out.push("</table>");
18809
+ return out.join("");
18810
+ }
18811
+ function convertToEmailTable(raw) {
18812
+ const { rows, hasHeader } = parseTable(raw);
18813
+ if (!rows.length || rows[0].length < 2) return null;
18814
+ return {
18815
+ html: buildHtml(rows, hasHeader),
18816
+ text: rows.map((r) => r.join(" ")).join("\n"),
18817
+ rows: rows.length,
18818
+ cols: rows[0].length
18819
+ };
18820
+ }
18821
+ function copySelectionAsEmailTable(terminal) {
18822
+ const result = convertToEmailTable(terminal.getSelection());
18823
+ if (result) {
18824
+ window.worker.copyEmailTable(result.html, result.text);
18825
+ }
18826
+ window.dispatchEvent(
18827
+ new CustomEvent("email-table-result", {
18828
+ detail: result ? { ok: true, message: `Copied ${result.rows}×${result.cols} table to clipboard` } : { ok: false, message: "No table found in selection" }
18829
+ })
18830
+ );
18831
+ }
18724
18832
  const _terminals = /* @__PURE__ */ new Map();
18725
18833
  function isAtBottom(terminal) {
18726
18834
  const buf = terminal.buffer.active;
@@ -18739,6 +18847,9 @@ function getOrCreateTerminal(tabId, onExit) {
18739
18847
  }
18740
18848
  const terminal = new xtermExports.Terminal({
18741
18849
  cursorBlink: true,
18850
+ // Off by default on macOS; without this a right-click would reselect the
18851
+ // word under the cursor and clobber a multi-line table selection.
18852
+ rightClickSelectsWord: false,
18742
18853
  fontSize: 14,
18743
18854
  fontFamily: "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', monospace",
18744
18855
  theme: {
@@ -18770,6 +18881,14 @@ function getOrCreateTerminal(tabId, onExit) {
18770
18881
  const fitAddon = new addonFitExports.FitAddon();
18771
18882
  terminal.loadAddon(fitAddon);
18772
18883
  terminal.loadAddon(new addonWebLinksExports.WebLinksAddon());
18884
+ terminal.attachCustomKeyEventHandler((e) => {
18885
+ if (e.type !== "keydown") return true;
18886
+ const isCombo = (e.metaKey || e.ctrlKey) && e.shiftKey && e.code === "KeyE";
18887
+ if (!isCombo) return true;
18888
+ e.preventDefault();
18889
+ copySelectionAsEmailTable(terminal);
18890
+ return false;
18891
+ });
18773
18892
  const state = {
18774
18893
  terminal,
18775
18894
  fitAddon,
@@ -18812,6 +18931,49 @@ function destroyTerminal(tabId) {
18812
18931
  }
18813
18932
  function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
18814
18933
  const containerRef = reactExports.useRef(null);
18934
+ const [menu, setMenu] = reactExports.useState(null);
18935
+ const [toast, setToast] = reactExports.useState(null);
18936
+ const handleContextMenu = (e) => {
18937
+ const sel = _terminals.get(tabId)?.terminal.getSelection() ?? "";
18938
+ if (!convertToEmailTable(sel)) return;
18939
+ e.preventDefault();
18940
+ setMenu({ x: e.clientX, y: e.clientY });
18941
+ };
18942
+ const runConvert = () => {
18943
+ const term = _terminals.get(tabId)?.terminal;
18944
+ if (term) copySelectionAsEmailTable(term);
18945
+ setMenu(null);
18946
+ };
18947
+ reactExports.useEffect(() => {
18948
+ const onResult = (e) => {
18949
+ const detail = e.detail;
18950
+ if (detail) setToast(detail.message);
18951
+ };
18952
+ window.addEventListener("email-table-result", onResult);
18953
+ return () => window.removeEventListener("email-table-result", onResult);
18954
+ }, []);
18955
+ reactExports.useEffect(() => {
18956
+ if (!toast) return;
18957
+ const t = setTimeout(() => setToast(null), 2200);
18958
+ return () => clearTimeout(t);
18959
+ }, [toast]);
18960
+ reactExports.useEffect(() => {
18961
+ if (!menu) return;
18962
+ const close = () => setMenu(null);
18963
+ const onKey = (e) => {
18964
+ if (e.key === "Escape") close();
18965
+ };
18966
+ window.addEventListener("click", close);
18967
+ window.addEventListener("blur", close);
18968
+ window.addEventListener("wheel", close, { passive: true });
18969
+ document.addEventListener("keydown", onKey);
18970
+ return () => {
18971
+ window.removeEventListener("click", close);
18972
+ window.removeEventListener("blur", close);
18973
+ window.removeEventListener("wheel", close);
18974
+ document.removeEventListener("keydown", onKey);
18975
+ };
18976
+ }, [menu]);
18815
18977
  reactExports.useEffect(() => {
18816
18978
  if (!containerRef.current) return;
18817
18979
  const { terminal, fitAddon } = getOrCreateTerminal(tabId, onExit);
@@ -18883,7 +19045,14 @@ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
18883
19045
  });
18884
19046
  }
18885
19047
  }, [isActive, tabId]);
18886
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "terminal-container", ref: containerRef });
19048
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
19049
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "terminal-container", ref: containerRef, onContextMenu: handleContextMenu }),
19050
+ menu && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "term-context-menu", style: { position: "fixed", left: menu.x, top: menu.y }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", onMouseDown: (e) => {
19051
+ e.preventDefault();
19052
+ runConvert();
19053
+ }, children: "Copy as email table" }) }),
19054
+ toast && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "term-toast", children: toast })
19055
+ ] });
18887
19056
  }
18888
19057
  function CtlsurfPanel() {
18889
19058
  const webviewRef = reactExports.useRef(null);
@@ -206558,7 +206727,7 @@ const lessDefaults = new LanguageServiceDefaultsImpl$3(
206558
206727
  modeConfigurationDefault$2
206559
206728
  );
206560
206729
  function getMode$3() {
206561
- return __vitePreload(() => import("./cssMode-D5dPwEy5.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
206730
+ return __vitePreload(() => import("./cssMode-DkmdBgO7.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
206562
206731
  }
206563
206732
  languages.onLanguage("less", () => {
206564
206733
  getMode$3().then((mode2) => mode2.setupMode(lessDefaults));
@@ -206663,7 +206832,7 @@ const razorLanguageService = registerHTMLLanguageService(
206663
206832
  );
206664
206833
  const razorDefaults = razorLanguageService.defaults;
206665
206834
  function getMode$2() {
206666
- return __vitePreload(() => import("./htmlMode-DYbpW1yY.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
206835
+ return __vitePreload(() => import("./htmlMode-CRicxcwK.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
206667
206836
  }
206668
206837
  function registerHTMLLanguageService(languageId, options = optionsDefault, modeConfiguration = getConfigurationDefault(languageId)) {
206669
206838
  const defaults = new LanguageServiceDefaultsImpl$2(languageId, options, modeConfiguration);
@@ -206747,7 +206916,7 @@ const jsonDefaults = new LanguageServiceDefaultsImpl$1(
206747
206916
  );
206748
206917
  const getWorker$1 = () => getMode$1().then((mode2) => mode2.getWorker());
206749
206918
  function getMode$1() {
206750
- return __vitePreload(() => import("./jsonMode-COLqbq0s.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
206919
+ return __vitePreload(() => import("./jsonMode-Bquqf3QN.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
206751
206920
  }
206752
206921
  languages.register({
206753
206922
  id: "json",
@@ -206993,7 +207162,7 @@ const getJavaScriptWorker = () => {
206993
207162
  return getMode().then((mode) => mode.getJavaScriptWorker());
206994
207163
  };
206995
207164
  function getMode() {
206996
- return __vitePreload(() => import("./tsMode-BrQ4Fsc-.js"), true ? [] : void 0, import.meta.url);
207165
+ return __vitePreload(() => import("./tsMode-CRIrHuii.js"), true ? [] : void 0, import.meta.url);
206997
207166
  }
206998
207167
  languages.onLanguage("typescript", () => {
206999
207168
  return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
@@ -207188,49 +207357,49 @@ registerLanguage({
207188
207357
  extensions: [".ftl", ".ftlh", ".ftlx"],
207189
207358
  aliases: ["FreeMarker2", "Apache FreeMarker2"],
207190
207359
  loader: () => {
207191
- return __vitePreload(() => import("./freemarker2-c5jJjQ9s.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207360
+ return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207192
207361
  }
207193
207362
  });
207194
207363
  registerLanguage({
207195
207364
  id: "freemarker2.tag-angle.interpolation-dollar",
207196
207365
  aliases: ["FreeMarker2 (Angle/Dollar)", "Apache FreeMarker2 (Angle/Dollar)"],
207197
207366
  loader: () => {
207198
- return __vitePreload(() => import("./freemarker2-c5jJjQ9s.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
207367
+ return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
207199
207368
  }
207200
207369
  });
207201
207370
  registerLanguage({
207202
207371
  id: "freemarker2.tag-bracket.interpolation-dollar",
207203
207372
  aliases: ["FreeMarker2 (Bracket/Dollar)", "Apache FreeMarker2 (Bracket/Dollar)"],
207204
207373
  loader: () => {
207205
- return __vitePreload(() => import("./freemarker2-c5jJjQ9s.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
207374
+ return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
207206
207375
  }
207207
207376
  });
207208
207377
  registerLanguage({
207209
207378
  id: "freemarker2.tag-angle.interpolation-bracket",
207210
207379
  aliases: ["FreeMarker2 (Angle/Bracket)", "Apache FreeMarker2 (Angle/Bracket)"],
207211
207380
  loader: () => {
207212
- return __vitePreload(() => import("./freemarker2-c5jJjQ9s.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
207381
+ return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
207213
207382
  }
207214
207383
  });
207215
207384
  registerLanguage({
207216
207385
  id: "freemarker2.tag-bracket.interpolation-bracket",
207217
207386
  aliases: ["FreeMarker2 (Bracket/Bracket)", "Apache FreeMarker2 (Bracket/Bracket)"],
207218
207387
  loader: () => {
207219
- return __vitePreload(() => import("./freemarker2-c5jJjQ9s.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
207388
+ return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
207220
207389
  }
207221
207390
  });
207222
207391
  registerLanguage({
207223
207392
  id: "freemarker2.tag-auto.interpolation-dollar",
207224
207393
  aliases: ["FreeMarker2 (Auto/Dollar)", "Apache FreeMarker2 (Auto/Dollar)"],
207225
207394
  loader: () => {
207226
- return __vitePreload(() => import("./freemarker2-c5jJjQ9s.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207395
+ return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207227
207396
  }
207228
207397
  });
207229
207398
  registerLanguage({
207230
207399
  id: "freemarker2.tag-auto.interpolation-bracket",
207231
207400
  aliases: ["FreeMarker2 (Auto/Bracket)", "Apache FreeMarker2 (Auto/Bracket)"],
207232
207401
  loader: () => {
207233
- return __vitePreload(() => import("./freemarker2-c5jJjQ9s.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
207402
+ return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
207234
207403
  }
207235
207404
  });
207236
207405
  registerLanguage({
@@ -207251,7 +207420,7 @@ registerLanguage({
207251
207420
  extensions: [".handlebars", ".hbs"],
207252
207421
  aliases: ["Handlebars", "handlebars", "hbs"],
207253
207422
  mimetypes: ["text/x-handlebars-template"],
207254
- loader: () => __vitePreload(() => import("./handlebars-BTbmOxx9.js"), true ? [] : void 0, import.meta.url)
207423
+ loader: () => __vitePreload(() => import("./handlebars-D5tEqanR.js"), true ? [] : void 0, import.meta.url)
207255
207424
  });
207256
207425
  registerLanguage({
207257
207426
  id: "hcl",
@@ -207264,7 +207433,7 @@ registerLanguage({
207264
207433
  extensions: [".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm"],
207265
207434
  aliases: ["HTML", "htm", "html", "xhtml"],
207266
207435
  mimetypes: ["text/html", "text/x-jshtm", "text/template", "text/ng-template"],
207267
- loader: () => __vitePreload(() => import("./html-3cIIQcxO.js"), true ? [] : void 0, import.meta.url)
207436
+ loader: () => __vitePreload(() => import("./html-fH93EYfn.js"), true ? [] : void 0, import.meta.url)
207268
207437
  });
207269
207438
  registerLanguage({
207270
207439
  id: "ini",
@@ -207287,7 +207456,7 @@ registerLanguage({
207287
207456
  filenames: ["jakefile"],
207288
207457
  aliases: ["JavaScript", "javascript", "js"],
207289
207458
  mimetypes: ["text/javascript"],
207290
- loader: () => __vitePreload(() => import("./javascript-CDuCMm-6.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
207459
+ loader: () => __vitePreload(() => import("./javascript-D1Baz4fV.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
207291
207460
  });
207292
207461
  registerLanguage({
207293
207462
  id: "julia",
@@ -207326,7 +207495,7 @@ registerLanguage({
207326
207495
  extensions: [".liquid", ".html.liquid"],
207327
207496
  aliases: ["Liquid", "liquid"],
207328
207497
  mimetypes: ["application/liquid"],
207329
- loader: () => __vitePreload(() => import("./liquid-BFcqZizB.js"), true ? [] : void 0, import.meta.url)
207498
+ loader: () => __vitePreload(() => import("./liquid-ByOcPjBF.js"), true ? [] : void 0, import.meta.url)
207330
207499
  });
207331
207500
  registerLanguage({
207332
207501
  id: "m3",
@@ -207344,7 +207513,7 @@ registerLanguage({
207344
207513
  id: "mdx",
207345
207514
  extensions: [".mdx"],
207346
207515
  aliases: ["MDX", "mdx"],
207347
- loader: () => __vitePreload(() => import("./mdx-DyK93oEE.js"), true ? [] : void 0, import.meta.url)
207516
+ loader: () => __vitePreload(() => import("./mdx-yuNgx0rM.js"), true ? [] : void 0, import.meta.url)
207348
207517
  });
207349
207518
  registerLanguage({
207350
207519
  id: "mips",
@@ -207443,7 +207612,7 @@ registerLanguage({
207443
207612
  extensions: [".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi"],
207444
207613
  aliases: ["Python", "py"],
207445
207614
  firstLine: "^#!/.*\\bpython[0-9.-]*\\b",
207446
- loader: () => __vitePreload(() => import("./python-D4lCwSVr.js"), true ? [] : void 0, import.meta.url)
207615
+ loader: () => __vitePreload(() => import("./python-2OakgLlA.js"), true ? [] : void 0, import.meta.url)
207447
207616
  });
207448
207617
  registerLanguage({
207449
207618
  id: "qsharp",
@@ -207462,7 +207631,7 @@ registerLanguage({
207462
207631
  extensions: [".cshtml"],
207463
207632
  aliases: ["Razor", "razor"],
207464
207633
  mimetypes: ["text/x-cshtml"],
207465
- loader: () => __vitePreload(() => import("./razor-DdkE9XVt.js"), true ? [] : void 0, import.meta.url)
207634
+ loader: () => __vitePreload(() => import("./razor-DnIVMSwa.js"), true ? [] : void 0, import.meta.url)
207466
207635
  });
207467
207636
  registerLanguage({
207468
207637
  id: "redis",
@@ -207595,7 +207764,7 @@ registerLanguage({
207595
207764
  aliases: ["TypeScript", "ts", "typescript"],
207596
207765
  mimetypes: ["text/typescript"],
207597
207766
  loader: () => {
207598
- return __vitePreload(() => import("./typescript-BakbYMnC.js"), true ? [] : void 0, import.meta.url);
207767
+ return __vitePreload(() => import("./typescript-DJ3C8Yly.js"), true ? [] : void 0, import.meta.url);
207599
207768
  }
207600
207769
  });
207601
207770
  registerLanguage({
@@ -207640,14 +207809,14 @@ registerLanguage({
207640
207809
  firstLine: "(\\<\\?xml.*)|(\\<svg)|(\\<\\!doctype\\s+svg)",
207641
207810
  aliases: ["XML", "xml"],
207642
207811
  mimetypes: ["text/xml", "application/xml", "application/xaml+xml", "application/xml-dtd"],
207643
- loader: () => __vitePreload(() => import("./xml-DHDW9Xhp.js"), true ? [] : void 0, import.meta.url)
207812
+ loader: () => __vitePreload(() => import("./xml-CalvD5_C.js"), true ? [] : void 0, import.meta.url)
207644
207813
  });
207645
207814
  registerLanguage({
207646
207815
  id: "yaml",
207647
207816
  extensions: [".yaml", ".yml"],
207648
207817
  aliases: ["YAML", "yaml", "YML", "yml"],
207649
207818
  mimetypes: ["application/x-yaml", "text/x-yaml"],
207650
- loader: () => __vitePreload(() => import("./yaml-1Ayv_J3q.js"), true ? [] : void 0, import.meta.url)
207819
+ loader: () => __vitePreload(() => import("./yaml-Cgs8pdVp.js"), true ? [] : void 0, import.meta.url)
207651
207820
  });
207652
207821
  var __defProp = Object.defineProperty;
207653
207822
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -8817,3 +8817,43 @@ html, body, #root {
8817
8817
  padding: 2px 8px;
8818
8818
  flex-shrink: 0;
8819
8819
  }
8820
+
8821
+ /* ─── Terminal "Copy as email table" context menu + toast ─── */
8822
+ .term-context-menu {
8823
+ z-index: 1000;
8824
+ background: #1f2335;
8825
+ border: 1px solid #414868;
8826
+ border-radius: 6px;
8827
+ padding: 4px;
8828
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
8829
+ min-width: 180px;
8830
+ }
8831
+ .term-context-menu button {
8832
+ display: block;
8833
+ width: 100%;
8834
+ text-align: left;
8835
+ background: transparent;
8836
+ border: none;
8837
+ border-radius: 4px;
8838
+ color: #c0caf5;
8839
+ font-size: 13px;
8840
+ padding: 7px 10px;
8841
+ cursor: pointer;
8842
+ }
8843
+ .term-context-menu button:hover {
8844
+ background: #2a2b3d;
8845
+ }
8846
+ .term-toast {
8847
+ position: fixed;
8848
+ bottom: 24px;
8849
+ right: 24px;
8850
+ z-index: 1000;
8851
+ background: #1f2335;
8852
+ border: 1px solid #7aa2f7;
8853
+ color: #c0caf5;
8854
+ font-size: 13px;
8855
+ padding: 9px 14px;
8856
+ border-radius: 6px;
8857
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
8858
+ pointer-events: none;
8859
+ }
@@ -1,5 +1,5 @@
1
- import { conf as conf$1, language as language$1 } from "./typescript-BakbYMnC.js";
2
- import "./index-D2MUZin7.js";
1
+ import { conf as conf$1, language as language$1 } from "./typescript-DJ3C8Yly.js";
2
+ import "./index-BOOvUI7u.js";
3
3
  const conf = conf$1;
4
4
  const language = {
5
5
  // Set defaultToken to invalid to see what you do not tokenize yet
@@ -1,6 +1,6 @@
1
- import { c as createWebWorker, l as languages, e as editor } from "./index-D2MUZin7.js";
2
- import { f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider, C as CompletionAdapter, H as HoverAdapter, b as DocumentSymbolAdapter, d as DocumentColorAdapter, F as FoldingRangeAdapter, S as SelectionRangeAdapter, e as DiagnosticsAdapter } from "./lspLanguageFeatures-CbkEcL-z.js";
3
- import { a, D, h, R, c, i, j, t, k } from "./lspLanguageFeatures-CbkEcL-z.js";
1
+ import { c as createWebWorker, l as languages, e as editor } from "./index-BOOvUI7u.js";
2
+ import { f as DocumentFormattingEditProvider, g as DocumentRangeFormattingEditProvider, C as CompletionAdapter, H as HoverAdapter, b as DocumentSymbolAdapter, d as DocumentColorAdapter, F as FoldingRangeAdapter, S as SelectionRangeAdapter, e as DiagnosticsAdapter } from "./lspLanguageFeatures-BxPLl0yy.js";
3
+ import { a, D, h, R, c, i, j, t, k } from "./lspLanguageFeatures-BxPLl0yy.js";
4
4
  const STOP_WHEN_IDLE_FOR = 2 * 60 * 1e3;
5
5
  class WorkerManager {
6
6
  constructor(defaults) {
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const EMPTY_ELEMENTS = [
3
3
  "area",
4
4
  "base",
@@ -1,4 +1,4 @@
1
- import { R as Range$1, l as languages, e as editor, U as Uri, M as MarkerSeverity } from "./index-D2MUZin7.js";
1
+ import { R as Range$1, l as languages, e as editor, U as Uri, M as MarkerSeverity } from "./index-BOOvUI7u.js";
2
2
  var DocumentUri;
3
3
  (function(DocumentUri2) {
4
4
  function is(value) {
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const conf = {
3
3
  comments: {
4
4
  blockComment: ["{/*", "*/}"]
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const conf = {
3
3
  comments: {
4
4
  lineComment: "#",
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const EMPTY_ELEMENTS = [
3
3
  "area",
4
4
  "base",
@@ -1,4 +1,4 @@
1
- import { c as createWebWorker, e as editor, U as Uri, a as MarkerTag, M as MarkerSeverity, l as languages, t as typescriptDefaults, R as Range } from "./index-D2MUZin7.js";
1
+ import { c as createWebWorker, e as editor, U as Uri, a as MarkerTag, M as MarkerSeverity, l as languages, t as typescriptDefaults, R as Range } from "./index-BOOvUI7u.js";
2
2
  class WorkerManager {
3
3
  constructor(_modeId, _defaults) {
4
4
  this._modeId = _modeId;
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const conf = {
3
3
  wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
4
4
  comments: {
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const conf = {
3
3
  comments: {
4
4
  blockComment: ["<!--", "-->"]
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-D2MUZin7.js";
1
+ import { l as languages } from "./index-BOOvUI7u.js";
2
2
  const conf = {
3
3
  comments: {
4
4
  lineComment: "#"
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>ctlsurf-worker</title>
7
- <script type="module" crossorigin src="./assets/index-D2MUZin7.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/index-6KvOnYL1.css">
7
+ <script type="module" crossorigin src="./assets/index-BOOvUI7u.js"></script>
8
+ <link rel="stylesheet" crossorigin href="./assets/index-ezC-iarf.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phenx-inc/ctlsurf",
3
- "version": "0.3.15",
3
+ "version": "0.4.0",
4
4
  "description": "Agent-agnostic terminal and desktop app for ctlsurf — run Claude Code, Codex, or any coding agent with live session logging and remote control",
5
5
  "main": "out/main/index.js",
6
6
  "bin": {