termbridge 0.3.8 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -1756,7 +1756,7 @@ import { config as loadEnv } from "dotenv";
1756
1756
  // src/cli/run.ts
1757
1757
  import qrcode2 from "qrcode-terminal";
1758
1758
 
1759
- // src/cli/args.ts
1759
+ // src/utils/parse.ts
1760
1760
  var parseNumber = (value) => {
1761
1761
  if (!value) {
1762
1762
  return null;
@@ -1764,6 +1764,97 @@ var parseNumber = (value) => {
1764
1764
  const parsed = Number.parseInt(value, 10);
1765
1765
  return Number.isNaN(parsed) ? null : parsed;
1766
1766
  };
1767
+ var parseOptionalNumber = (value) => {
1768
+ if (!value) {
1769
+ return void 0;
1770
+ }
1771
+ const parsed = Number.parseInt(value, 10);
1772
+ return Number.isFinite(parsed) ? parsed : void 0;
1773
+ };
1774
+ var parseBoolean = (value) => {
1775
+ if (!value) {
1776
+ return false;
1777
+ }
1778
+ const normalized = value.trim().toLowerCase();
1779
+ return normalized === "1" || normalized === "true" || normalized === "yes";
1780
+ };
1781
+ var parseList = (value) => {
1782
+ if (!value) {
1783
+ return [];
1784
+ }
1785
+ return value.split(/[,\s]+/).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
1786
+ };
1787
+ var parseSessionCount = (value) => {
1788
+ if (!value) {
1789
+ return 1;
1790
+ }
1791
+ const parsed = Number.parseInt(value, 10);
1792
+ if (!Number.isFinite(parsed) || parsed < 1) {
1793
+ return 1;
1794
+ }
1795
+ return parsed;
1796
+ };
1797
+
1798
+ // src/utils/url.ts
1799
+ var normalizePublicUrl = (value) => {
1800
+ const trimmed = value.trim();
1801
+ if (!trimmed) {
1802
+ throw new Error("missing public url");
1803
+ }
1804
+ let parsed;
1805
+ try {
1806
+ parsed = new URL(trimmed);
1807
+ } catch {
1808
+ throw new Error("invalid public url");
1809
+ }
1810
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
1811
+ throw new Error("invalid public url");
1812
+ }
1813
+ return trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
1814
+ };
1815
+ var buildShareUrl = (publicUrl, token) => {
1816
+ let parsed;
1817
+ try {
1818
+ parsed = new URL(publicUrl);
1819
+ } catch {
1820
+ throw new Error("invalid public url");
1821
+ }
1822
+ const basePath = parsed.pathname.endsWith("/") ? parsed.pathname : `${parsed.pathname}/`;
1823
+ parsed.pathname = `${basePath}__tb/s/${token}`;
1824
+ parsed.hash = "";
1825
+ return parsed.toString();
1826
+ };
1827
+ var deriveRepoPath = (repoUrl) => {
1828
+ const trimmed = repoUrl.replace(/\/$/, "");
1829
+ const last = trimmed.split("/").pop();
1830
+ if (!last) {
1831
+ return "repo";
1832
+ }
1833
+ return last.endsWith(".git") ? last.slice(0, -4) : last;
1834
+ };
1835
+
1836
+ // src/utils/path.ts
1837
+ import { resolve } from "path";
1838
+ import { statSync } from "fs";
1839
+ var expandHome = (value, home) => {
1840
+ if (value === "~") {
1841
+ return home;
1842
+ }
1843
+ if (value.startsWith("~/")) {
1844
+ return `${home}/${value.slice(2)}`;
1845
+ }
1846
+ return value;
1847
+ };
1848
+ var resolvePath = (value, home) => resolve(expandHome(value, home));
1849
+ var safeStat = (path) => {
1850
+ try {
1851
+ return statSync(path);
1852
+ } catch {
1853
+ return null;
1854
+ }
1855
+ };
1856
+
1857
+ // src/cli/args.ts
1767
1858
  var parseArgs = (argv) => {
1768
1859
  const args = [...argv];
1769
1860
  let command = "start";
@@ -1969,7 +2060,7 @@ import { EventEmitter } from "events";
1969
2060
  import { execFile as execFileCallback } from "child_process";
1970
2061
  import { promisify } from "util";
1971
2062
  import { accessSync, chmodSync, constants as fsConstants } from "fs";
1972
- import { dirname, resolve } from "path";
2063
+ import { dirname, resolve as resolve2 } from "path";
1973
2064
  import { createRequire } from "module";
1974
2065
  import * as pty from "node-pty";
1975
2066
  var execFile = promisify(execFileCallback);
@@ -2009,7 +2100,7 @@ var ensureSpawnHelperExecutable = (platform) => {
2009
2100
  const { loadNativeModule } = requireFromHere("node-pty/lib/utils");
2010
2101
  const native = loadNativeModule("pty");
2011
2102
  const unixTerminalPath = requireFromHere.resolve("node-pty/lib/unixTerminal");
2012
- const helperPath = resolve(dirname(unixTerminalPath), `${native.dir}/spawn-helper`);
2103
+ const helperPath = resolve2(dirname(unixTerminalPath), `${native.dir}/spawn-helper`);
2013
2104
  try {
2014
2105
  accessSync(helperPath, fsConstants.X_OK);
2015
2106
  } catch {
@@ -2526,7 +2617,7 @@ var TERMINAL_CONTROL_KEYS = [
2526
2617
 
2527
2618
  // src/server/static.ts
2528
2619
  import { readFile } from "fs/promises";
2529
- import { extname, resolve as resolve2 } from "path";
2620
+ import { extname, resolve as resolve3 } from "path";
2530
2621
  var contentTypes = {
2531
2622
  ".html": "text/html",
2532
2623
  ".js": "text/javascript",
@@ -2552,7 +2643,7 @@ var createStaticHandler = (uiDistPath, basePath) => {
2552
2643
  }
2553
2644
  const relative2 = url.pathname.slice(normalizedBase.length) || "/";
2554
2645
  const filePath = relative2 === "/" ? "/index.html" : relative2;
2555
- const absolutePath = resolve2(uiDistPath, `.${filePath}`);
2646
+ const absolutePath = resolve3(uiDistPath, `.${filePath}`);
2556
2647
  try {
2557
2648
  const payload = await readFile(absolutePath);
2558
2649
  response.statusCode = 200;
@@ -2561,7 +2652,7 @@ var createStaticHandler = (uiDistPath, basePath) => {
2561
2652
  return true;
2562
2653
  } catch {
2563
2654
  try {
2564
- const fallback = await readFile(resolve2(uiDistPath, "index.html"));
2655
+ const fallback = await readFile(resolve3(uiDistPath, "index.html"));
2565
2656
  response.statusCode = 200;
2566
2657
  response.setHeader("Content-Type", "text/html");
2567
2658
  response.end(fallback);
@@ -3035,9 +3126,9 @@ var installAgents = async (sandbox, options, logger) => {
3035
3126
 
3036
3127
  // src/sandbox/daytona/agent-auth.ts
3037
3128
  import { homedir } from "os";
3038
- import { basename, dirname as dirname2, join, relative, resolve as resolve3 } from "path";
3129
+ import { basename, dirname as dirname2, join, relative, resolve as resolve4 } from "path";
3039
3130
  import { readdir, stat } from "fs/promises";
3040
- var expandHome = (value, home) => {
3131
+ var expandHome2 = (value, home) => {
3041
3132
  if (value === "~") {
3042
3133
  return home;
3043
3134
  }
@@ -3048,7 +3139,7 @@ var expandHome = (value, home) => {
3048
3139
  };
3049
3140
  var resolveDestination = (spec, sourcePath, localHome, remoteHome) => {
3050
3141
  if (spec.destination) {
3051
- return expandHome(spec.destination, remoteHome);
3142
+ return expandHome2(spec.destination, remoteHome);
3052
3143
  }
3053
3144
  if (sourcePath.startsWith(localHome)) {
3054
3145
  const rel = relative(localHome, sourcePath);
@@ -3088,7 +3179,7 @@ var syncAgentAuth = async (sandbox, options, logger) => {
3088
3179
  const uploads = [];
3089
3180
  const mkdirs = /* @__PURE__ */ new Set();
3090
3181
  for (const spec of options.specs) {
3091
- const sourcePath = resolve3(expandHome(spec.source, localHome));
3182
+ const sourcePath = resolve4(expandHome2(spec.source, localHome));
3092
3183
  let stats;
3093
3184
  try {
3094
3185
  stats = await stat(sourcePath);
@@ -3139,7 +3230,7 @@ var noopLogger = {
3139
3230
  warn: () => void 0,
3140
3231
  error: () => void 0
3141
3232
  };
3142
- var deriveRepoPath = (repoUrl) => {
3233
+ var deriveRepoPath2 = (repoUrl) => {
3143
3234
  const trimmed = repoUrl.replace(/\/$/, "");
3144
3235
  const last = trimmed.split("/").pop();
3145
3236
  if (!last) {
@@ -3165,7 +3256,7 @@ var createSandboxDaytonaBackend = (options) => {
3165
3256
  logger.info(`Sandbox (Daytona): creating sandbox ${name}`);
3166
3257
  const sandbox = await daytona.create({ name, public: options.public });
3167
3258
  await sandbox.start();
3168
- const repoPath = options.repoPath ?? deriveRepoPath(options.repoUrl);
3259
+ const repoPath = options.repoPath ?? deriveRepoPath2(options.repoUrl);
3169
3260
  logger.info(`Sandbox (Daytona): cloning ${options.repoUrl}`);
3170
3261
  await sandbox.git.clone(
3171
3262
  options.repoUrl,
@@ -3353,8 +3444,6 @@ var createSandboxDaytonaBackend = (options) => {
3353
3444
 
3354
3445
  // src/sandbox/daytona/agent-auto.ts
3355
3446
  import { homedir as homedir2 } from "os";
3356
- import { resolve as resolve4 } from "path";
3357
- import { statSync } from "fs";
3358
3447
  var agentDefinitions = {
3359
3448
  "claude-code": {
3360
3449
  packages: ["@anthropic-ai/claude-code"],
@@ -3382,23 +3471,6 @@ var agentAliasMap = {
3382
3471
  "@openai/codex": "codex",
3383
3472
  opencode: "opencode"
3384
3473
  };
3385
- var expandHome2 = (value, home) => {
3386
- if (value === "~") {
3387
- return home;
3388
- }
3389
- if (value.startsWith("~/")) {
3390
- return `${home}/${value.slice(2)}`;
3391
- }
3392
- return value;
3393
- };
3394
- var resolvePath = (value, home) => resolve4(expandHome2(value, home));
3395
- var safeStat = (path) => {
3396
- try {
3397
- return statSync(path);
3398
- } catch {
3399
- return null;
3400
- }
3401
- };
3402
3474
  var normalizeAgentName = (value) => {
3403
3475
  const normalized = value.trim().toLowerCase();
3404
3476
  if (normalized === "") {
@@ -3522,30 +3594,6 @@ var installLocalTermbridge = async (sandbox, startOptions, logger) => {
3522
3594
  logger.info("Sandbox (Daytona): installed local termbridge package");
3523
3595
  return { useLocal: true };
3524
3596
  };
3525
- var deriveRepoPath2 = (repoUrl) => {
3526
- const trimmed = repoUrl.replace(/\/$/, "");
3527
- const last = trimmed.split("/").pop();
3528
- if (!last) {
3529
- return "repo";
3530
- }
3531
- return last.endsWith(".git") ? last.slice(0, -4) : last;
3532
- };
3533
- var normalizePublicUrl = (value) => {
3534
- const trimmed = value.trim();
3535
- if (!trimmed) {
3536
- throw new Error("missing public url");
3537
- }
3538
- let parsed;
3539
- try {
3540
- parsed = new URL(trimmed);
3541
- } catch {
3542
- throw new Error("invalid public url");
3543
- }
3544
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
3545
- throw new Error("invalid public url");
3546
- }
3547
- return trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
3548
- };
3549
3597
  var delay = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
3550
3598
  var ensureTmux = async (sandbox, logger) => {
3551
3599
  const check = await sandbox.process.executeCommand("command -v tmux");
@@ -3673,7 +3721,7 @@ var createSandboxDaytonaServerProvider = (options = {}) => {
3673
3721
  const sandbox = await daytona.create({ name, public: startOptions.public });
3674
3722
  sandboxRef = sandbox;
3675
3723
  await sandbox.start();
3676
- const repoPath = startOptions.repoPath ?? deriveRepoPath2(startOptions.repoUrl);
3724
+ const repoPath = startOptions.repoPath ?? deriveRepoPath(startOptions.repoUrl);
3677
3725
  logger.info(`Sandbox (Daytona): cloning ${startOptions.repoUrl}`);
3678
3726
  await sandbox.git.clone(
3679
3727
  startOptions.repoUrl,
@@ -3837,36 +3885,6 @@ var createDefaultLogger = () => ({
3837
3885
  warn: (message) => console.warn(message),
3838
3886
  error: (message) => console.error(message)
3839
3887
  });
3840
- var parseSessionCount = (value) => {
3841
- if (!value) {
3842
- return 1;
3843
- }
3844
- const parsed = Number.parseInt(value, 10);
3845
- if (!Number.isFinite(parsed) || parsed < 1) {
3846
- return 1;
3847
- }
3848
- return parsed;
3849
- };
3850
- var parseBoolean = (value) => {
3851
- if (!value) {
3852
- return false;
3853
- }
3854
- const normalized = value.trim().toLowerCase();
3855
- return normalized === "1" || normalized === "true" || normalized === "yes";
3856
- };
3857
- var parseOptionalNumber = (value) => {
3858
- if (!value) {
3859
- return void 0;
3860
- }
3861
- const parsed = Number.parseInt(value, 10);
3862
- return Number.isFinite(parsed) ? parsed : void 0;
3863
- };
3864
- var parseList = (value) => {
3865
- if (!value) {
3866
- return [];
3867
- }
3868
- return value.split(/[,\s]+/).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
3869
- };
3870
3888
  var defaultAgentEnvKeys = [
3871
3889
  "OPENAI_API_KEY",
3872
3890
  "OPENAI_BASE_URL",
@@ -3946,50 +3964,6 @@ var resolveBackendMode = (value) => {
3946
3964
  }
3947
3965
  throw new Error("invalid backend");
3948
3966
  };
3949
- var deriveRepoPath3 = (repoUrl) => {
3950
- const trimmed = repoUrl.replace(/\/$/, "");
3951
- const last = trimmed.split("/").pop();
3952
- if (!last) {
3953
- return "repo";
3954
- }
3955
- return last.endsWith(".git") ? last.slice(0, -4) : last;
3956
- };
3957
- var normalizePublicUrl2 = (value) => {
3958
- let parsed;
3959
- try {
3960
- parsed = new URL(value);
3961
- } catch {
3962
- throw new Error("invalid tunnel url");
3963
- }
3964
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
3965
- throw new Error("invalid tunnel url");
3966
- }
3967
- return value.endsWith("/") ? value.slice(0, -1) : value;
3968
- };
3969
- var normalizeExternalUrl = (value) => {
3970
- let parsed;
3971
- try {
3972
- parsed = new URL(value);
3973
- } catch {
3974
- throw new Error("invalid public url");
3975
- }
3976
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
3977
- throw new Error("invalid public url");
3978
- }
3979
- return value.endsWith("/") ? value.slice(0, -1) : value;
3980
- };
3981
- var buildShareUrl = (publicUrl, token) => {
3982
- let parsed;
3983
- try {
3984
- parsed = new URL(publicUrl);
3985
- } catch {
3986
- throw new Error("invalid public url");
3987
- }
3988
- const basePath = parsed.pathname.endsWith("/") ? parsed.pathname : `${parsed.pathname}/`;
3989
- parsed.pathname = `${basePath}__tb/s/${token}`;
3990
- parsed.hash = "";
3991
- return parsed.toString();
3992
- };
3993
3967
  var resolveTunnelMode = (value) => {
3994
3968
  if (!value) {
3995
3969
  return "cloudflare";
@@ -4020,8 +3994,8 @@ var startCommand = async (options, deps = {}) => {
4020
3994
  const cookieSameSite = cookieSameSiteRaw === "none" ? "None" : cookieSameSiteRaw === "strict" ? "Strict" : cookieSameSiteRaw === "lax" ? "Lax" : sandboxDirect && !insecureCookie ? "None" : "Lax";
4021
3995
  const auth = (deps.createAuth ?? (() => createAuth({
4022
3996
  tokenTtlMs: 9e4,
4023
- sessionIdleMs: 30 * 6e4,
4024
- sessionMaxMs: 8 * 60 * 6e4,
3997
+ sessionIdleMs: Infinity,
3998
+ sessionMaxMs: Infinity,
4025
3999
  cookieSecure: !insecureCookie,
4026
4000
  cookieSameSite
4027
4001
  })))();
@@ -4047,7 +4021,7 @@ var startCommand = async (options, deps = {}) => {
4047
4021
  target: env.TERMBRIDGE_DAYTONA_TARGET,
4048
4022
  repoUrl: sandboxRepo,
4049
4023
  repoBranch: options.sandboxBranch ?? env.TERMBRIDGE_SANDBOX_BRANCH,
4050
- repoPath: options.sandboxPath ?? env.TERMBRIDGE_SANDBOX_PATH ?? deriveRepoPath3(sandboxRepo),
4024
+ repoPath: options.sandboxPath ?? env.TERMBRIDGE_SANDBOX_PATH ?? deriveRepoPath(sandboxRepo),
4051
4025
  sandboxName: options.sandboxName ?? env.TERMBRIDGE_SANDBOX_NAME,
4052
4026
  public: sandboxPublic,
4053
4027
  deleteOnExit: sandboxDeleteOnExit,
@@ -4112,7 +4086,7 @@ var startCommand = async (options, deps = {}) => {
4112
4086
  const tunnelTokenRaw = options.tunnelToken ?? env.TERMBRIDGE_TUNNEL_TOKEN;
4113
4087
  const tunnelToken = tunnelTokenRaw?.trim() || void 0;
4114
4088
  const tunnelUrlRaw = options.tunnelUrl ?? env.TERMBRIDGE_TUNNEL_URL;
4115
- const tunnelUrl = tunnelToken && tunnelUrlRaw ? normalizePublicUrl2(tunnelUrlRaw) : void 0;
4089
+ const tunnelUrl = tunnelToken && tunnelUrlRaw ? normalizePublicUrl(tunnelUrlRaw) : void 0;
4116
4090
  let devProxyUrl = options.devProxyUrl;
4117
4091
  let devProxyHeaders;
4118
4092
  let publicUrl = "";
@@ -4123,7 +4097,7 @@ var startCommand = async (options, deps = {}) => {
4123
4097
  if (tunnelToken || tunnelUrlRaw) {
4124
4098
  throw new Error("tunnel token/url not supported when tunnel disabled");
4125
4099
  }
4126
- publicUrl = normalizeExternalUrl(publicUrlOverride);
4100
+ publicUrl = normalizePublicUrl(publicUrlOverride);
4127
4101
  }
4128
4102
  if (!devProxyUrl && backendMode === "sandbox-daytona" && sandboxPreviewPort) {
4129
4103
  const previewInfo = await terminalBackend.getPreviewUrl?.(sandboxPreviewPort);