@phenx-inc/ctlsurf 0.5.0 → 0.5.2

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 (29) hide show
  1. package/out/headless/index.mjs +36 -18
  2. package/out/headless/index.mjs.map +2 -2
  3. package/out/main/index.js +35 -6
  4. package/out/preload/index.js +3 -0
  5. package/out/renderer/assets/{cssMode-DkmdBgO7.js → cssMode-D9-xaWSI.js} +3 -3
  6. package/out/renderer/assets/{freemarker2-CI-gkP-3.js → freemarker2-CoRAVxnv.js} +1 -1
  7. package/out/renderer/assets/{handlebars-D5tEqanR.js → handlebars-B0p9Wgkw.js} +1 -1
  8. package/out/renderer/assets/{html-fH93EYfn.js → html-D_XFJJtO.js} +1 -1
  9. package/out/renderer/assets/{htmlMode-CRicxcwK.js → htmlMode-naWw6PWr.js} +3 -3
  10. package/out/renderer/assets/{index-BOOvUI7u.js → index-DBt_rov1.js} +64 -26
  11. package/out/renderer/assets/{javascript-D1Baz4fV.js → javascript-DDLsFUr-.js} +2 -2
  12. package/out/renderer/assets/{jsonMode-Bquqf3QN.js → jsonMode-Ixhcm5I6.js} +3 -3
  13. package/out/renderer/assets/{liquid-ByOcPjBF.js → liquid-BHgSYEHk.js} +1 -1
  14. package/out/renderer/assets/{lspLanguageFeatures-BxPLl0yy.js → lspLanguageFeatures-ClbEdD0U.js} +1 -1
  15. package/out/renderer/assets/{mdx-yuNgx0rM.js → mdx-DMngMjHR.js} +1 -1
  16. package/out/renderer/assets/{python-2OakgLlA.js → python-D_czoeY2.js} +1 -1
  17. package/out/renderer/assets/{razor-DnIVMSwa.js → razor-CLMDGvL7.js} +1 -1
  18. package/out/renderer/assets/{tsMode-CRIrHuii.js → tsMode-EIuSGG42.js} +1 -1
  19. package/out/renderer/assets/{typescript-DJ3C8Yly.js → typescript-DQkV4kKA.js} +1 -1
  20. package/out/renderer/assets/{xml-CalvD5_C.js → xml-DJ0OOQTu.js} +1 -1
  21. package/out/renderer/assets/{yaml-Cgs8pdVp.js → yaml-DxX26XLN.js} +1 -1
  22. package/out/renderer/index.html +1 -1
  23. package/package.json +1 -1
  24. package/src/main/index.ts +42 -2
  25. package/src/main/tui.ts +39 -17
  26. package/src/preload/index.ts +4 -0
  27. package/src/renderer/App.tsx +21 -1
  28. package/src/renderer/components/CtlsurfPanel.tsx +19 -3
  29. package/src/renderer/components/TerminalPanel.tsx +26 -1
package/out/main/index.js CHANGED
@@ -8754,7 +8754,7 @@ function requireWebsocket() {
8754
8754
  const tls = require$$4;
8755
8755
  const { randomBytes, createHash } = require$$1;
8756
8756
  const { Duplex, Readable } = require$$0$2;
8757
- const { URL } = require$$7;
8757
+ const { URL: URL2 } = require$$7;
8758
8758
  const PerMessageDeflate = requirePermessageDeflate();
8759
8759
  const Receiver = requireReceiver();
8760
8760
  const Sender = requireSender();
@@ -9247,11 +9247,11 @@ function requireWebsocket() {
9247
9247
  );
9248
9248
  }
9249
9249
  let parsedUrl;
9250
- if (address instanceof URL) {
9250
+ if (address instanceof URL2) {
9251
9251
  parsedUrl = address;
9252
9252
  } else {
9253
9253
  try {
9254
- parsedUrl = new URL(address);
9254
+ parsedUrl = new URL2(address);
9255
9255
  } catch {
9256
9256
  throw new SyntaxError(`Invalid URL: ${address}`);
9257
9257
  }
@@ -9388,7 +9388,7 @@ function requireWebsocket() {
9388
9388
  req.abort();
9389
9389
  let addr;
9390
9390
  try {
9391
- addr = new URL(location, address);
9391
+ addr = new URL2(location, address);
9392
9392
  } catch (e) {
9393
9393
  const err = new SyntaxError(`Invalid URL: ${location}`);
9394
9394
  emitErrorAndClose(websocket2, err);
@@ -11682,10 +11682,13 @@ electron.ipcMain.handle("worker:createProject", async () => {
11682
11682
  return { ok: false, error: err.message };
11683
11683
  }
11684
11684
  });
11685
- electron.ipcMain.handle("worker:getWebviewInfo", async () => {
11685
+ function getCtlsurfFrontendUrl() {
11686
11686
  const profile = orchestrator.getActiveProfile();
11687
11687
  const baseUrl = profile.baseUrl || process.env.CTLSURF_BASE_URL || "https://app.ctlsurf.com";
11688
- const frontendUrl = baseUrl.includes("localhost:8000") ? baseUrl.replace(":8000", ":88") : baseUrl;
11688
+ return baseUrl.includes("localhost:8000") ? baseUrl.replace(":8000", ":88") : baseUrl;
11689
+ }
11690
+ electron.ipcMain.handle("worker:getWebviewInfo", async () => {
11691
+ const frontendUrl = getCtlsurfFrontendUrl();
11689
11692
  if (!orchestrator.ctlsurfApi.getApiKey()) {
11690
11693
  return { frontendUrl: `${frontendUrl}?embed=1`, authenticated: false };
11691
11694
  }
@@ -11726,6 +11729,32 @@ electron.ipcMain.handle("worker:getWebviewInfo", async () => {
11726
11729
  return { frontendUrl: `${frontendUrl}?embed=1`, authenticated: false };
11727
11730
  }
11728
11731
  });
11732
+ electron.ipcMain.handle("worker:getEmbedUrl", async (_event, targetUrl) => {
11733
+ try {
11734
+ if (!targetUrl) return null;
11735
+ const frontendUrl = getCtlsurfFrontendUrl();
11736
+ const profile = orchestrator.getActiveProfile();
11737
+ const rawBaseUrl = profile.baseUrl || process.env.CTLSURF_BASE_URL || "https://app.ctlsurf.com";
11738
+ const target = new URL(targetUrl);
11739
+ const front = new URL(frontendUrl);
11740
+ const origins = /* @__PURE__ */ new Set([front.origin]);
11741
+ try {
11742
+ origins.add(new URL(rawBaseUrl).origin);
11743
+ } catch {
11744
+ }
11745
+ if (!origins.has(target.origin)) return null;
11746
+ const out = new URL(target.pathname + target.search + target.hash, front.origin);
11747
+ out.searchParams.set("embed", "1");
11748
+ if (orchestrator.ctlsurfApi.getApiKey()) {
11749
+ const { code } = await orchestrator.ctlsurfApi.getAuthCode();
11750
+ out.searchParams.set("_code", code);
11751
+ }
11752
+ return out.toString();
11753
+ } catch (err) {
11754
+ log("[worker] getEmbedUrl failed:", err?.message);
11755
+ return null;
11756
+ }
11757
+ });
11729
11758
  electron.ipcMain.handle("profiles:list", () => orchestrator.listProfiles());
11730
11759
  electron.ipcMain.handle("profiles:get", (_event, id) => orchestrator.getProfile(id));
11731
11760
  electron.ipcMain.handle("profiles:save", (_event, id, data) => {
@@ -70,6 +70,9 @@ const api = {
70
70
  getWorkerId: () => electron.ipcRenderer.invoke("worker:getWorkerId"),
71
71
  createProject: () => electron.ipcRenderer.invoke("worker:createProject"),
72
72
  getWebviewInfo: () => electron.ipcRenderer.invoke("worker:getWebviewInfo"),
73
+ // Resolve a terminal-printed URL to an authenticated ctlsurf embed URL, or
74
+ // null if it isn't a ctlsurf link (caller opens those externally).
75
+ getEmbedUrl: (targetUrl) => electron.ipcRenderer.invoke("worker:getEmbedUrl", targetUrl),
73
76
  onWorkerStatus: (callback) => {
74
77
  const listener = (_event, status) => callback(status);
75
78
  electron.ipcRenderer.on("worker:status", listener);
@@ -1,6 +1,6 @@
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";
1
+ import { c as createWebWorker, l as languages } from "./index-DBt_rov1.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-ClbEdD0U.js";
3
+ import { h, i, j, t, k } from "./lspLanguageFeatures-ClbEdD0U.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-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.js";
2
2
  const EMPTY_ELEMENTS = [
3
3
  "assign",
4
4
  "flush",
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.js";
2
2
  const EMPTY_ELEMENTS = [
3
3
  "area",
4
4
  "base",
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.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-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";
1
+ import { c as createWebWorker, l as languages } from "./index-DBt_rov1.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-ClbEdD0U.js";
3
+ import { a, e, d, R, i, j, t, k } from "./lspLanguageFeatures-ClbEdD0U.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-DkmdBgO7.js","./lspLanguageFeatures-BxPLl0yy.js","./htmlMode-CRicxcwK.js","./jsonMode-Bquqf3QN.js","./javascript-D1Baz4fV.js","./typescript-DJ3C8Yly.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-D9-xaWSI.js","./lspLanguageFeatures-ClbEdD0U.js","./htmlMode-naWw6PWr.js","./jsonMode-Ixhcm5I6.js","./javascript-DDLsFUr-.js","./typescript-DQkV4kKA.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
  }
@@ -18829,6 +18829,25 @@ function copySelectionAsEmailTable(terminal) {
18829
18829
  })
18830
18830
  );
18831
18831
  }
18832
+ function openExternal(uri) {
18833
+ const win = window.open();
18834
+ if (win) {
18835
+ try {
18836
+ win.opener = null;
18837
+ } catch {
18838
+ }
18839
+ win.location.href = uri;
18840
+ }
18841
+ }
18842
+ function handleTerminalLink(_event, uri) {
18843
+ window.worker.getEmbedUrl(uri).then((embedUrl) => {
18844
+ if (embedUrl) {
18845
+ window.dispatchEvent(new CustomEvent("ctlsurf-open-url", { detail: { url: embedUrl } }));
18846
+ } else {
18847
+ openExternal(uri);
18848
+ }
18849
+ }).catch(() => openExternal(uri));
18850
+ }
18832
18851
  const _terminals = /* @__PURE__ */ new Map();
18833
18852
  function isAtBottom(terminal) {
18834
18853
  const buf = terminal.buffer.active;
@@ -18880,7 +18899,7 @@ function getOrCreateTerminal(tabId, onExit) {
18880
18899
  });
18881
18900
  const fitAddon = new addonFitExports.FitAddon();
18882
18901
  terminal.loadAddon(fitAddon);
18883
- terminal.loadAddon(new addonWebLinksExports.WebLinksAddon());
18902
+ terminal.loadAddon(new addonWebLinksExports.WebLinksAddon(handleTerminalLink));
18884
18903
  terminal.attachCustomKeyEventHandler((e) => {
18885
18904
  if (e.type !== "keydown") return true;
18886
18905
  const isCombo = (e.metaKey || e.ctrlKey) && e.shiftKey && e.code === "KeyE";
@@ -19054,7 +19073,7 @@ function TerminalPanel({ tabId, agent, onSpawn, onExit, isActive }) {
19054
19073
  toast && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "term-toast", children: toast })
19055
19074
  ] });
19056
19075
  }
19057
- function CtlsurfPanel() {
19076
+ function CtlsurfPanel({ navigate }) {
19058
19077
  const webviewRef = reactExports.useRef(null);
19059
19078
  const [url, setUrl] = reactExports.useState(null);
19060
19079
  const [key, setKey] = reactExports.useState(0);
@@ -19068,8 +19087,14 @@ function CtlsurfPanel() {
19068
19087
  }
19069
19088
  };
19070
19089
  reactExports.useEffect(() => {
19071
- loadUrl();
19090
+ if (!navigate?.url) loadUrl();
19072
19091
  }, []);
19092
+ reactExports.useEffect(() => {
19093
+ if (navigate?.url) {
19094
+ setUrl(navigate.url);
19095
+ setKey((k2) => k2 + 1);
19096
+ }
19097
+ }, [navigate?.n]);
19073
19098
  reactExports.useEffect(() => {
19074
19099
  const unsub = window.worker.onCwdChanged(() => {
19075
19100
  setUrl(null);
@@ -206727,7 +206752,7 @@ const lessDefaults = new LanguageServiceDefaultsImpl$3(
206727
206752
  modeConfigurationDefault$2
206728
206753
  );
206729
206754
  function getMode$3() {
206730
- return __vitePreload(() => import("./cssMode-DkmdBgO7.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
206755
+ return __vitePreload(() => import("./cssMode-D9-xaWSI.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
206731
206756
  }
206732
206757
  languages.onLanguage("less", () => {
206733
206758
  getMode$3().then((mode2) => mode2.setupMode(lessDefaults));
@@ -206832,7 +206857,7 @@ const razorLanguageService = registerHTMLLanguageService(
206832
206857
  );
206833
206858
  const razorDefaults = razorLanguageService.defaults;
206834
206859
  function getMode$2() {
206835
- return __vitePreload(() => import("./htmlMode-CRicxcwK.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
206860
+ return __vitePreload(() => import("./htmlMode-naWw6PWr.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
206836
206861
  }
206837
206862
  function registerHTMLLanguageService(languageId, options = optionsDefault, modeConfiguration = getConfigurationDefault(languageId)) {
206838
206863
  const defaults = new LanguageServiceDefaultsImpl$2(languageId, options, modeConfiguration);
@@ -206916,7 +206941,7 @@ const jsonDefaults = new LanguageServiceDefaultsImpl$1(
206916
206941
  );
206917
206942
  const getWorker$1 = () => getMode$1().then((mode2) => mode2.getWorker());
206918
206943
  function getMode$1() {
206919
- return __vitePreload(() => import("./jsonMode-Bquqf3QN.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
206944
+ return __vitePreload(() => import("./jsonMode-Ixhcm5I6.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
206920
206945
  }
206921
206946
  languages.register({
206922
206947
  id: "json",
@@ -207162,7 +207187,7 @@ const getJavaScriptWorker = () => {
207162
207187
  return getMode().then((mode) => mode.getJavaScriptWorker());
207163
207188
  };
207164
207189
  function getMode() {
207165
- return __vitePreload(() => import("./tsMode-CRIrHuii.js"), true ? [] : void 0, import.meta.url);
207190
+ return __vitePreload(() => import("./tsMode-EIuSGG42.js"), true ? [] : void 0, import.meta.url);
207166
207191
  }
207167
207192
  languages.onLanguage("typescript", () => {
207168
207193
  return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
@@ -207357,49 +207382,49 @@ registerLanguage({
207357
207382
  extensions: [".ftl", ".ftlh", ".ftlx"],
207358
207383
  aliases: ["FreeMarker2", "Apache FreeMarker2"],
207359
207384
  loader: () => {
207360
- return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207385
+ return __vitePreload(() => import("./freemarker2-CoRAVxnv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207361
207386
  }
207362
207387
  });
207363
207388
  registerLanguage({
207364
207389
  id: "freemarker2.tag-angle.interpolation-dollar",
207365
207390
  aliases: ["FreeMarker2 (Angle/Dollar)", "Apache FreeMarker2 (Angle/Dollar)"],
207366
207391
  loader: () => {
207367
- return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
207392
+ return __vitePreload(() => import("./freemarker2-CoRAVxnv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
207368
207393
  }
207369
207394
  });
207370
207395
  registerLanguage({
207371
207396
  id: "freemarker2.tag-bracket.interpolation-dollar",
207372
207397
  aliases: ["FreeMarker2 (Bracket/Dollar)", "Apache FreeMarker2 (Bracket/Dollar)"],
207373
207398
  loader: () => {
207374
- return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
207399
+ return __vitePreload(() => import("./freemarker2-CoRAVxnv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
207375
207400
  }
207376
207401
  });
207377
207402
  registerLanguage({
207378
207403
  id: "freemarker2.tag-angle.interpolation-bracket",
207379
207404
  aliases: ["FreeMarker2 (Angle/Bracket)", "Apache FreeMarker2 (Angle/Bracket)"],
207380
207405
  loader: () => {
207381
- return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
207406
+ return __vitePreload(() => import("./freemarker2-CoRAVxnv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
207382
207407
  }
207383
207408
  });
207384
207409
  registerLanguage({
207385
207410
  id: "freemarker2.tag-bracket.interpolation-bracket",
207386
207411
  aliases: ["FreeMarker2 (Bracket/Bracket)", "Apache FreeMarker2 (Bracket/Bracket)"],
207387
207412
  loader: () => {
207388
- return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
207413
+ return __vitePreload(() => import("./freemarker2-CoRAVxnv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
207389
207414
  }
207390
207415
  });
207391
207416
  registerLanguage({
207392
207417
  id: "freemarker2.tag-auto.interpolation-dollar",
207393
207418
  aliases: ["FreeMarker2 (Auto/Dollar)", "Apache FreeMarker2 (Auto/Dollar)"],
207394
207419
  loader: () => {
207395
- return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207420
+ return __vitePreload(() => import("./freemarker2-CoRAVxnv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
207396
207421
  }
207397
207422
  });
207398
207423
  registerLanguage({
207399
207424
  id: "freemarker2.tag-auto.interpolation-bracket",
207400
207425
  aliases: ["FreeMarker2 (Auto/Bracket)", "Apache FreeMarker2 (Auto/Bracket)"],
207401
207426
  loader: () => {
207402
- return __vitePreload(() => import("./freemarker2-CI-gkP-3.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
207427
+ return __vitePreload(() => import("./freemarker2-CoRAVxnv.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
207403
207428
  }
207404
207429
  });
207405
207430
  registerLanguage({
@@ -207420,7 +207445,7 @@ registerLanguage({
207420
207445
  extensions: [".handlebars", ".hbs"],
207421
207446
  aliases: ["Handlebars", "handlebars", "hbs"],
207422
207447
  mimetypes: ["text/x-handlebars-template"],
207423
- loader: () => __vitePreload(() => import("./handlebars-D5tEqanR.js"), true ? [] : void 0, import.meta.url)
207448
+ loader: () => __vitePreload(() => import("./handlebars-B0p9Wgkw.js"), true ? [] : void 0, import.meta.url)
207424
207449
  });
207425
207450
  registerLanguage({
207426
207451
  id: "hcl",
@@ -207433,7 +207458,7 @@ registerLanguage({
207433
207458
  extensions: [".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm"],
207434
207459
  aliases: ["HTML", "htm", "html", "xhtml"],
207435
207460
  mimetypes: ["text/html", "text/x-jshtm", "text/template", "text/ng-template"],
207436
- loader: () => __vitePreload(() => import("./html-fH93EYfn.js"), true ? [] : void 0, import.meta.url)
207461
+ loader: () => __vitePreload(() => import("./html-D_XFJJtO.js"), true ? [] : void 0, import.meta.url)
207437
207462
  });
207438
207463
  registerLanguage({
207439
207464
  id: "ini",
@@ -207456,7 +207481,7 @@ registerLanguage({
207456
207481
  filenames: ["jakefile"],
207457
207482
  aliases: ["JavaScript", "javascript", "js"],
207458
207483
  mimetypes: ["text/javascript"],
207459
- loader: () => __vitePreload(() => import("./javascript-D1Baz4fV.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
207484
+ loader: () => __vitePreload(() => import("./javascript-DDLsFUr-.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
207460
207485
  });
207461
207486
  registerLanguage({
207462
207487
  id: "julia",
@@ -207495,7 +207520,7 @@ registerLanguage({
207495
207520
  extensions: [".liquid", ".html.liquid"],
207496
207521
  aliases: ["Liquid", "liquid"],
207497
207522
  mimetypes: ["application/liquid"],
207498
- loader: () => __vitePreload(() => import("./liquid-ByOcPjBF.js"), true ? [] : void 0, import.meta.url)
207523
+ loader: () => __vitePreload(() => import("./liquid-BHgSYEHk.js"), true ? [] : void 0, import.meta.url)
207499
207524
  });
207500
207525
  registerLanguage({
207501
207526
  id: "m3",
@@ -207513,7 +207538,7 @@ registerLanguage({
207513
207538
  id: "mdx",
207514
207539
  extensions: [".mdx"],
207515
207540
  aliases: ["MDX", "mdx"],
207516
- loader: () => __vitePreload(() => import("./mdx-yuNgx0rM.js"), true ? [] : void 0, import.meta.url)
207541
+ loader: () => __vitePreload(() => import("./mdx-DMngMjHR.js"), true ? [] : void 0, import.meta.url)
207517
207542
  });
207518
207543
  registerLanguage({
207519
207544
  id: "mips",
@@ -207612,7 +207637,7 @@ registerLanguage({
207612
207637
  extensions: [".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi"],
207613
207638
  aliases: ["Python", "py"],
207614
207639
  firstLine: "^#!/.*\\bpython[0-9.-]*\\b",
207615
- loader: () => __vitePreload(() => import("./python-2OakgLlA.js"), true ? [] : void 0, import.meta.url)
207640
+ loader: () => __vitePreload(() => import("./python-D_czoeY2.js"), true ? [] : void 0, import.meta.url)
207616
207641
  });
207617
207642
  registerLanguage({
207618
207643
  id: "qsharp",
@@ -207631,7 +207656,7 @@ registerLanguage({
207631
207656
  extensions: [".cshtml"],
207632
207657
  aliases: ["Razor", "razor"],
207633
207658
  mimetypes: ["text/x-cshtml"],
207634
- loader: () => __vitePreload(() => import("./razor-DnIVMSwa.js"), true ? [] : void 0, import.meta.url)
207659
+ loader: () => __vitePreload(() => import("./razor-CLMDGvL7.js"), true ? [] : void 0, import.meta.url)
207635
207660
  });
207636
207661
  registerLanguage({
207637
207662
  id: "redis",
@@ -207764,7 +207789,7 @@ registerLanguage({
207764
207789
  aliases: ["TypeScript", "ts", "typescript"],
207765
207790
  mimetypes: ["text/typescript"],
207766
207791
  loader: () => {
207767
- return __vitePreload(() => import("./typescript-DJ3C8Yly.js"), true ? [] : void 0, import.meta.url);
207792
+ return __vitePreload(() => import("./typescript-DQkV4kKA.js"), true ? [] : void 0, import.meta.url);
207768
207793
  }
207769
207794
  });
207770
207795
  registerLanguage({
@@ -207809,14 +207834,14 @@ registerLanguage({
207809
207834
  firstLine: "(\\<\\?xml.*)|(\\<svg)|(\\<\\!doctype\\s+svg)",
207810
207835
  aliases: ["XML", "xml"],
207811
207836
  mimetypes: ["text/xml", "application/xml", "application/xaml+xml", "application/xml-dtd"],
207812
- loader: () => __vitePreload(() => import("./xml-CalvD5_C.js"), true ? [] : void 0, import.meta.url)
207837
+ loader: () => __vitePreload(() => import("./xml-DJ0OOQTu.js"), true ? [] : void 0, import.meta.url)
207813
207838
  });
207814
207839
  registerLanguage({
207815
207840
  id: "yaml",
207816
207841
  extensions: [".yaml", ".yml"],
207817
207842
  aliases: ["YAML", "yaml", "YML", "yml"],
207818
207843
  mimetypes: ["application/x-yaml", "text/x-yaml"],
207819
- loader: () => __vitePreload(() => import("./yaml-Cgs8pdVp.js"), true ? [] : void 0, import.meta.url)
207844
+ loader: () => __vitePreload(() => import("./yaml-DxX26XLN.js"), true ? [] : void 0, import.meta.url)
207820
207845
  });
207821
207846
  var __defProp = Object.defineProperty;
207822
207847
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -212210,6 +212235,8 @@ function App() {
212210
212235
  const [cwd2, setCwd] = reactExports.useState(null);
212211
212236
  const [projectName, setProjectName] = reactExports.useState(null);
212212
212237
  const [updateInfo, setUpdateInfo] = reactExports.useState(null);
212238
+ const [ctlsurfNav, setCtlsurfNav] = reactExports.useState(null);
212239
+ const ctlsurfNavCounter = reactExports.useRef(0);
212213
212240
  const [tabs, setTabs] = reactExports.useState(() => {
212214
212241
  const id = nextTabId();
212215
212242
  return [{ id, label: "Terminal 1", agent: null, agentStatus: "idle" }];
@@ -212418,6 +212445,17 @@ function App() {
212418
212445
  window.addEventListener("keydown", handleKeyDown);
212419
212446
  return () => window.removeEventListener("keydown", handleKeyDown);
212420
212447
  }, [togglePane]);
212448
+ reactExports.useEffect(() => {
212449
+ const onOpen = (e) => {
212450
+ const url = e.detail?.url;
212451
+ if (!url) return;
212452
+ if (!findPaneIds(layout2).includes("ctlsurf")) togglePane("ctlsurf");
212453
+ ctlsurfNavCounter.current += 1;
212454
+ setCtlsurfNav({ url, n: ctlsurfNavCounter.current });
212455
+ };
212456
+ window.addEventListener("ctlsurf-open-url", onOpen);
212457
+ return () => window.removeEventListener("ctlsurf-open-url", onOpen);
212458
+ }, [layout2, togglePane]);
212421
212459
  const panes = [
212422
212460
  { id: "editor", label: "Editor", content: /* @__PURE__ */ jsxRuntimeExports.jsx(EditorPanel, { cwd: cwd2 }) },
212423
212461
  {
@@ -212477,7 +212515,7 @@ function App() {
212477
212515
  )) })
212478
212516
  ] })
212479
212517
  },
212480
- { id: "ctlsurf", label: "ctlsurf", content: /* @__PURE__ */ jsxRuntimeExports.jsx(CtlsurfPanel, {}) }
212518
+ { id: "ctlsurf", label: "ctlsurf", content: /* @__PURE__ */ jsxRuntimeExports.jsx(CtlsurfPanel, { navigate: ctlsurfNav }) }
212481
212519
  ];
212482
212520
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "app", children: [
212483
212521
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "titlebar", children: [
@@ -1,5 +1,5 @@
1
- import { conf as conf$1, language as language$1 } from "./typescript-DJ3C8Yly.js";
2
- import "./index-BOOvUI7u.js";
1
+ import { conf as conf$1, language as language$1 } from "./typescript-DQkV4kKA.js";
2
+ import "./index-DBt_rov1.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-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";
1
+ import { c as createWebWorker, l as languages, e as editor } from "./index-DBt_rov1.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-ClbEdD0U.js";
3
+ import { a, D, h, R, c, i, j, t, k } from "./lspLanguageFeatures-ClbEdD0U.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-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.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-BOOvUI7u.js";
1
+ import { R as Range$1, l as languages, e as editor, U as Uri, M as MarkerSeverity } from "./index-DBt_rov1.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-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.js";
2
2
  const conf = {
3
3
  comments: {
4
4
  blockComment: ["{/*", "*/}"]
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.js";
2
2
  const conf = {
3
3
  comments: {
4
4
  lineComment: "#",
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.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-BOOvUI7u.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-DBt_rov1.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-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.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-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.js";
2
2
  const conf = {
3
3
  comments: {
4
4
  blockComment: ["<!--", "-->"]
@@ -1,4 +1,4 @@
1
- import { l as languages } from "./index-BOOvUI7u.js";
1
+ import { l as languages } from "./index-DBt_rov1.js";
2
2
  const conf = {
3
3
  comments: {
4
4
  lineComment: "#"
@@ -4,7 +4,7 @@
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-BOOvUI7u.js"></script>
7
+ <script type="module" crossorigin src="./assets/index-DBt_rov1.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="./assets/index-ezC-iarf.css">
9
9
  </head>
10
10
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phenx-inc/ctlsurf",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
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": {
package/src/main/index.ts CHANGED
@@ -300,12 +300,18 @@ ipcMain.handle('worker:createProject', async () => {
300
300
  }
301
301
  })
302
302
 
303
- ipcMain.handle('worker:getWebviewInfo', async () => {
303
+ // Resolve the ctlsurf frontend URL (the origin the embedded webview loads from)
304
+ // from the active profile, applying the dev localhost:8000 → :88 rewrite.
305
+ function getCtlsurfFrontendUrl(): string {
304
306
  const profile = orchestrator.getActiveProfile()
305
307
  const baseUrl = profile.baseUrl || process.env.CTLSURF_BASE_URL || 'https://app.ctlsurf.com'
306
- const frontendUrl = baseUrl.includes('localhost:8000')
308
+ return baseUrl.includes('localhost:8000')
307
309
  ? baseUrl.replace(':8000', ':88')
308
310
  : baseUrl
311
+ }
312
+
313
+ ipcMain.handle('worker:getWebviewInfo', async () => {
314
+ const frontendUrl = getCtlsurfFrontendUrl()
309
315
 
310
316
  if (!orchestrator.ctlsurfApi.getApiKey()) {
311
317
  return { frontendUrl: `${frontendUrl}?embed=1`, authenticated: false }
@@ -348,6 +354,40 @@ ipcMain.handle('worker:getWebviewInfo', async () => {
348
354
  }
349
355
  })
350
356
 
357
+ // Given a URL the agent printed in the terminal, return an authenticated embed
358
+ // URL if it points at the ctlsurf frontend, else null (so the caller opens it
359
+ // in the default browser instead).
360
+ ipcMain.handle('worker:getEmbedUrl', async (_event, targetUrl: string) => {
361
+ try {
362
+ if (!targetUrl) return null
363
+ const frontendUrl = getCtlsurfFrontendUrl()
364
+ const profile = orchestrator.getActiveProfile()
365
+ const rawBaseUrl = profile.baseUrl || process.env.CTLSURF_BASE_URL || 'https://app.ctlsurf.com'
366
+
367
+ const target = new URL(targetUrl)
368
+ const front = new URL(frontendUrl)
369
+
370
+ // Treat both the frontend origin and the raw (dev :8000) base as ctlsurf.
371
+ const origins = new Set<string>([front.origin])
372
+ try { origins.add(new URL(rawBaseUrl).origin) } catch { /* ignore */ }
373
+ if (!origins.has(target.origin)) return null
374
+
375
+ // Rebuild on the frontend origin (handles the dev :8000 → :88 case) so the
376
+ // webview loads from the same origin its auth code is valid for.
377
+ const out = new URL(target.pathname + target.search + target.hash, front.origin)
378
+ out.searchParams.set('embed', '1')
379
+
380
+ if (orchestrator.ctlsurfApi.getApiKey()) {
381
+ const { code } = await orchestrator.ctlsurfApi.getAuthCode()
382
+ out.searchParams.set('_code', code)
383
+ }
384
+ return out.toString()
385
+ } catch (err: any) {
386
+ log('[worker] getEmbedUrl failed:', err?.message)
387
+ return null
388
+ }
389
+ })
390
+
351
391
  // ─── Profile IPC ──────────────────────────────────
352
392
 
353
393
  ipcMain.handle('profiles:list', () => orchestrator.listProfiles())