sparkecoder 0.1.107 → 0.1.109

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 (111) hide show
  1. package/dist/agent/index.d.ts +3 -3
  2. package/dist/agent/index.js +14 -1
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +109 -12
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +2 -2
  7. package/dist/{index-D5l-DMGC.d.ts → index-Biy5JTop.d.ts} +96 -83
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.js +87 -10
  10. package/dist/index.js.map +1 -1
  11. package/dist/{schema-ecQSnCMz.d.ts → schema-CYSKJZ3m.d.ts} +3 -3
  12. package/dist/{search-DOzC4ojH.d.ts → search-CVVfuBPZ.d.ts} +4 -4
  13. package/dist/server/index.js +87 -10
  14. package/dist/server/index.js.map +1 -1
  15. package/dist/tools/index.d.ts +3 -3
  16. package/dist/tools/index.js +8 -0
  17. package/dist/tools/index.js.map +1 -1
  18. package/package.json +1 -1
  19. package/web/.next/BUILD_ID +1 -1
  20. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  21. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  22. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  23. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  24. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  39. package/web/.next/standalone/web/.next/server/app/agents.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  66. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  75. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  78. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  83. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  86. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  89. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  91. package/web/.next/standalone/web/.next/server/app/settings.rsc +1 -1
  92. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +1 -1
  93. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  94. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  95. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  96. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  97. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  98. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  99. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  100. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  101. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  102. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  103. /package/web/.next/standalone/web/.next/static/{9B80CeRYeYvnsEougmuLs → 56Y89huUkFkd-4Ip1HcYY}/_buildManifest.js +0 -0
  104. /package/web/.next/standalone/web/.next/static/{9B80CeRYeYvnsEougmuLs → 56Y89huUkFkd-4Ip1HcYY}/_clientMiddlewareManifest.json +0 -0
  105. /package/web/.next/standalone/web/.next/static/{9B80CeRYeYvnsEougmuLs → 56Y89huUkFkd-4Ip1HcYY}/_ssgManifest.js +0 -0
  106. /package/web/.next/standalone/web/.next/static/static/{9B80CeRYeYvnsEougmuLs → 56Y89huUkFkd-4Ip1HcYY}/_buildManifest.js +0 -0
  107. /package/web/.next/standalone/web/.next/static/static/{9B80CeRYeYvnsEougmuLs → 56Y89huUkFkd-4Ip1HcYY}/_clientMiddlewareManifest.json +0 -0
  108. /package/web/.next/standalone/web/.next/static/static/{9B80CeRYeYvnsEougmuLs → 56Y89huUkFkd-4Ip1HcYY}/_ssgManifest.js +0 -0
  109. /package/web/.next/static/{9B80CeRYeYvnsEougmuLs → 56Y89huUkFkd-4Ip1HcYY}/_buildManifest.js +0 -0
  110. /package/web/.next/static/{9B80CeRYeYvnsEougmuLs → 56Y89huUkFkd-4Ip1HcYY}/_clientMiddlewareManifest.json +0 -0
  111. /package/web/.next/static/{9B80CeRYeYvnsEougmuLs → 56Y89huUkFkd-4Ip1HcYY}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -854,6 +854,14 @@ var init_types = __esm({
854
854
  // If not set, defaults to http://{host}:{port}
855
855
  publicUrl: z.string().url().optional()
856
856
  }).default({ port: 3141, host: "127.0.0.1" }),
857
+ // Per-tunnel unguessable webhook URL prefix. Set by
858
+ // `cloudflared-setup --remote` from the response of POST
859
+ // /tunnels/ensure. When present, the local server mounts public
860
+ // inbound webhooks (Slack events, inbox) under /w/<token>/...
861
+ // instead of /api/*. When absent, falls back to /api/*.
862
+ webhooks: z.object({
863
+ token: z.string().optional()
864
+ }).optional(),
857
865
  // Database path (used for local SQLite - ignored if remoteServer is configured)
858
866
  databasePath: z.string().optional().default("./sparkecoder.db"),
859
867
  // Remote server configuration (for centralized storage)
@@ -961,7 +969,9 @@ __export(config_exports, {
961
969
  saveAuthKey: () => saveAuthKey,
962
970
  setApiKey: () => setApiKey,
963
971
  setMcpServers: () => setMcpServers,
964
- setSlackConfig: () => setSlackConfig
972
+ setPublicUrl: () => setPublicUrl,
973
+ setSlackConfig: () => setSlackConfig,
974
+ setWebhookToken: () => setWebhookToken
965
975
  });
966
976
  import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
967
977
  import { resolve, dirname, join } from "path";
@@ -1223,6 +1233,55 @@ function setMcpServers(servers2) {
1223
1233
  console.warn("[config] failed to persist mcp config:", err?.message || err);
1224
1234
  }
1225
1235
  }
1236
+ function setWebhookToken(token) {
1237
+ if (cachedConfig) {
1238
+ cachedConfig.webhooks = {
1239
+ ...cachedConfig.webhooks ?? {},
1240
+ token
1241
+ };
1242
+ }
1243
+ try {
1244
+ const cwdPath = resolve(process.cwd(), "sparkecoder.config.json");
1245
+ const target = existsSync(cwdPath) ? cwdPath : join(ensureAppDataDirectory(), "sparkecoder.config.json");
1246
+ let raw = {};
1247
+ if (existsSync(target)) {
1248
+ try {
1249
+ raw = JSON.parse(readFileSync(target, "utf-8"));
1250
+ } catch {
1251
+ raw = {};
1252
+ }
1253
+ } else {
1254
+ raw = createDefaultConfig();
1255
+ }
1256
+ raw.webhooks = { ...raw.webhooks || {}, token };
1257
+ writeFileSync(target, JSON.stringify(raw, null, 2));
1258
+ } catch (err) {
1259
+ console.warn("[config] failed to persist webhook token:", err?.message || err);
1260
+ }
1261
+ }
1262
+ function setPublicUrl(publicUrl) {
1263
+ if (cachedConfig) {
1264
+ cachedConfig.server = { ...cachedConfig.server ?? {}, publicUrl };
1265
+ }
1266
+ try {
1267
+ const cwdPath = resolve(process.cwd(), "sparkecoder.config.json");
1268
+ const target = existsSync(cwdPath) ? cwdPath : join(ensureAppDataDirectory(), "sparkecoder.config.json");
1269
+ let raw = {};
1270
+ if (existsSync(target)) {
1271
+ try {
1272
+ raw = JSON.parse(readFileSync(target, "utf-8"));
1273
+ } catch {
1274
+ raw = {};
1275
+ }
1276
+ } else {
1277
+ raw = createDefaultConfig();
1278
+ }
1279
+ raw.server = { ...raw.server || {}, publicUrl };
1280
+ writeFileSync(target, JSON.stringify(raw, null, 2));
1281
+ } catch (err) {
1282
+ console.warn("[config] failed to persist publicUrl:", err?.message || err);
1283
+ }
1284
+ }
1226
1285
  function clearSlackConfig() {
1227
1286
  if (cachedConfig) cachedConfig.slack = {};
1228
1287
  try {
@@ -9557,7 +9616,9 @@ function buildScheduleTool(opts) {
9557
9616
  }
9558
9617
  function buildWebhookUrl(opts, token) {
9559
9618
  const base = opts.publicBaseUrl?.replace(/\/$/, "") || opts.baseUrl.replace(/\/$/, "");
9560
- return `${base}/api/inbox/${token}`;
9619
+ const cfg = getConfig();
9620
+ const webhookPrefix2 = cfg?.webhooks?.token ? `/w/${cfg.webhooks.token}` : "/api";
9621
+ return `${base}${webhookPrefix2}/inbox/${token}`;
9561
9622
  }
9562
9623
  function buildWebhookTool(opts) {
9563
9624
  return tool14({
@@ -9607,6 +9668,7 @@ var init_orchestrator_actions = __esm({
9607
9668
  "use strict";
9608
9669
  init_messenger();
9609
9670
  init_schedules_store();
9671
+ init_config();
9610
9672
  init_webhooks_store();
9611
9673
  AGENT_STATUS_ENUM = z15.enum(["running", "needs_attention", "completed", "failed", "idle"]);
9612
9674
  agentInputSchema = z15.object({
@@ -14656,8 +14718,8 @@ async function findOrCreateOrchestratorId() {
14656
14718
  const all = await sessionQueries.list(500, 0);
14657
14719
  const existing = all.find((s) => s.config?.role === "orchestrator");
14658
14720
  if (existing) return existing.id;
14659
- const { getConfig: getConfig3 } = await Promise.resolve().then(() => (init_config(), config_exports));
14660
- const cfg = getConfig3();
14721
+ const { getConfig: getConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
14722
+ const cfg = getConfig2();
14661
14723
  const created = await sessionQueries.create({
14662
14724
  name: getDefaultOrchestratorName() || "Orchestrator",
14663
14725
  workingDirectory: cfg.resolvedWorkingDirectory,
@@ -14782,6 +14844,11 @@ function publicBase() {
14782
14844
  const cfg = getConfig();
14783
14845
  return cfg.server?.publicUrl?.replace(/\/$/, "") || `http://${cfg.server?.host || "127.0.0.1"}:${cfg.server?.port || 3141}`;
14784
14846
  }
14847
+ function webhookPrefix() {
14848
+ const cfg = getConfig();
14849
+ const token = cfg?.webhooks?.token;
14850
+ return token ? `/w/${token}` : "/api";
14851
+ }
14785
14852
  integrations.get("/", async (c) => {
14786
14853
  const cfg = getConfig();
14787
14854
  return c.json({
@@ -14791,7 +14858,7 @@ integrations.get("/", async (c) => {
14791
14858
  botTokenSet: !!cfg?.slack?.botToken,
14792
14859
  signingSecretSet: !!cfg?.slack?.signingSecret,
14793
14860
  defaultOrchestratorName: cfg?.slack?.defaultOrchestratorName || null,
14794
- eventsUrl: `${publicBase()}/api/slack/events`,
14861
+ eventsUrl: `${publicBase()}${webhookPrefix()}/slack/events`,
14795
14862
  allowedUsers: cfg?.slack?.allowedUsers ?? [],
14796
14863
  allowedChannels: cfg?.slack?.allowedChannels ?? [],
14797
14864
  allowDmsFromAnyone: cfg?.slack?.allowDmsFromAnyone !== false,
@@ -14884,7 +14951,7 @@ schedulesRouter.delete("/:id", async (c) => {
14884
14951
  });
14885
14952
  var webhooksRouter = new Hono8();
14886
14953
  function withUrl(row) {
14887
- return { ...row, url: `${publicBase()}/api/inbox/${row.token}` };
14954
+ return { ...row, url: `${publicBase()}${webhookPrefix()}/inbox/${row.token}` };
14888
14955
  }
14889
14956
  webhooksRouter.get("/", async (c) => {
14890
14957
  const orcId = await getOrchestratorId();
@@ -14987,7 +15054,7 @@ mcpRouter.post("/:id/test", async (c) => {
14987
15054
  // src/server/auth/cf-access.ts
14988
15055
  init_config();
14989
15056
  import { createRemoteJWKSet, jwtVerify } from "jose";
14990
- var EXEMPT_PATH_PREFIXES = ["/health", "/api/slack/events", "/api/inbox/"];
15057
+ var EXEMPT_PATH_PREFIXES = ["/health", "/api/slack/events", "/api/inbox/", "/w/"];
14991
15058
  var cachedJWKS = null;
14992
15059
  var cachedJWKSUrl = null;
14993
15060
  function getOrCreateJWKS(teamDomain) {
@@ -15512,13 +15579,23 @@ async function createApp(options = {}) {
15512
15579
  app.route("/sessions", terminals);
15513
15580
  app.route("/terminals", terminals);
15514
15581
  app.route("/tasks", tasks_default);
15515
- app.route("/api/slack", slack);
15516
- app.route("/api/inbox", inbox);
15517
15582
  app.route("/api/integrations", integrations);
15518
15583
  app.route("/api/schedules", schedulesRouter);
15519
- app.route("/api/webhooks", webhooksRouter);
15520
15584
  app.route("/api/orchestrator", orchestratorRouter);
15521
15585
  app.route("/api/mcp", mcpRouter);
15586
+ app.route("/api/webhooks", webhooksRouter);
15587
+ const config = getConfig();
15588
+ const webhookToken = config?.webhooks?.token;
15589
+ if (webhookToken) {
15590
+ app.route(`/w/${webhookToken}/slack`, slack);
15591
+ app.route(`/w/${webhookToken}/inbox`, inbox);
15592
+ if (!options.quiet) {
15593
+ console.log(` \u2192 Public webhooks mounted at /w/${webhookToken.slice(0, 4)}\u2026/<service>`);
15594
+ }
15595
+ } else {
15596
+ app.route("/api/slack", slack);
15597
+ app.route("/api/inbox", inbox);
15598
+ }
15522
15599
  app.get("/openapi.json", async (c) => {
15523
15600
  return c.json(generateOpenAPISpec());
15524
15601
  });
@@ -16703,13 +16780,19 @@ program.name("sparkecoder").description("AI coding agent - just type sparkecoder
16703
16780
  }
16704
16781
  await runChat(options);
16705
16782
  });
16706
- program.command("server").description("Start the SparkECoder server (API + Web UI)").option("-p, --port <port>", "API server port", "3141").option("-h, --host <host>", "Server host", "127.0.0.1").option("-c, --config <path>", "Path to config file").option("-w, --working-dir <path>", "Working directory").option("--web-port <port>", "Web UI port", "6969").option("--no-web", "Do not start web UI").option("--public-url <url>", "Public URL for web UI to connect to API (for Docker/remote access)").option("-v, --verbose", "Enable verbose logging for web server").option("--enable-computer-use", "Enable the Anthropic computer use tool for all new sessions by default (macOS only)").action(async (options) => {
16783
+ program.command("server").description("Start the SparkECoder server (API + Web UI)").option("-p, --port <port>", "API server port", "3141").option("-h, --host <host>", "Server host", "127.0.0.1").option("-c, --config <path>", "Path to config file").option("-w, --working-dir <path>", "Working directory").option("--web-port <port>", "Web UI port", "6969").option("--no-web", "Do not start web UI").option("--public-url <url>", "Public URL for web UI to connect to API (for Docker/remote access)").option("-v, --verbose", "Enable verbose logging for web server").option("--enable-computer-use", "Enable the Anthropic computer use tool for all new sessions by default (macOS only)").option("--setup-secret <secret>", "Setup secret (or short-lived JWT) used for /auth/register and /tunnels when the remote server has SETUP_SECRET configured. Equivalent to setting SPARKECODER_SETUP_SECRET env.").action(async (options) => {
16707
16784
  const globalOpts = program.opts();
16708
16785
  const enableCU = options.enableComputerUse || globalOpts.enableComputerUse;
16709
16786
  if (enableCU) {
16710
16787
  process.env.SPARKECODER_COMPUTER_USE = "1";
16711
16788
  console.log(chalk.cyan("\u2192 Computer use enabled by default for new sessions."));
16712
16789
  }
16790
+ if (options.setupSecret) {
16791
+ process.env.SPARKECODER_SETUP_SECRET = options.setupSecret;
16792
+ if (!process.env.SPARKECODER_TUNNEL_SECRET) {
16793
+ process.env.SPARKECODER_TUNNEL_SECRET = options.setupSecret;
16794
+ }
16795
+ }
16713
16796
  await ensureDependencies({ quiet: false });
16714
16797
  const spinner = ora("Starting SparkECoder server...").start();
16715
16798
  try {
@@ -17004,10 +17087,24 @@ program.command("cloudflared-setup").description("Auto-detect cloudflared + set
17004
17087
  process.exitCode = 1;
17005
17088
  return;
17006
17089
  }
17007
- const { tunnelToken, hostname: provisionedHost, apiHostname, reused } = await res.json();
17090
+ const { tunnelToken, hostname: provisionedHost, apiHostname, reused, webhookToken, webhookBaseUrl } = await res.json();
17008
17091
  if (reused) {
17009
17092
  console.log(chalk.dim("\u2713 Re-using existing tunnel \u2014 no new tunnel created on Cloudflare."));
17010
17093
  }
17094
+ try {
17095
+ setPublicUrl(`https://${apiHostname}`);
17096
+ console.log(chalk.dim(`\u2713 Saved publicUrl = https://${apiHostname} into config.`));
17097
+ } catch (err) {
17098
+ console.warn(chalk.yellow(`Could not persist publicUrl: ${err?.message ?? err}`));
17099
+ }
17100
+ if (webhookToken) {
17101
+ try {
17102
+ setWebhookToken(webhookToken);
17103
+ console.log(chalk.dim(`\u2713 Saved webhook prefix into config: ${webhookBaseUrl ?? `https://${apiHostname}/w/${webhookToken}`}`));
17104
+ } catch (err) {
17105
+ console.warn(chalk.yellow(`Could not persist webhook token: ${err?.message ?? err}`));
17106
+ }
17107
+ }
17011
17108
  const cfPath = await installCloudflaredIfNeeded();
17012
17109
  if (!cfPath) {
17013
17110
  console.log(chalk.yellow("cloudflared not installed; run this once installed:"));