@launchsecure/launch-kit 0.0.42 → 0.0.43

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 (77) hide show
  1. package/dist/chart-client/assets/index-DOKsFe5i.css +1 -0
  2. package/dist/chart-client/index.html +2 -2
  3. package/dist/client/assets/index-BqiDfvZi.js +294 -0
  4. package/dist/client/assets/index-Mewz-s77.css +32 -0
  5. package/dist/client/index.html +2 -2
  6. package/dist/council-client/assets/index-o_3y7Z0J.css +1 -0
  7. package/dist/council-client/index.html +2 -2
  8. package/dist/deck-client/assets/{_baseUniq-BrhDuG3C.js → _baseUniq-C6w7kg8x.js} +1 -1
  9. package/dist/deck-client/assets/{arc-DXtPHMhw.js → arc-Cx9pT3Nn.js} +1 -1
  10. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-Cs9IdLQQ.js → architectureDiagram-Q4EWVU46-BITSj3vA.js} +1 -1
  11. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D--wpvoBAt.js → blockDiagram-DXYQGD6D-BehOFuwh.js} +1 -1
  12. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-BNIKE8-Z.js → c4Diagram-AHTNJAMY-BZTYM4na.js} +1 -1
  13. package/dist/deck-client/assets/channel-Cw2WDt9a.js +1 -0
  14. package/dist/deck-client/assets/{chunk-4BX2VUAB-Bz3EWmUo.js → chunk-4BX2VUAB-CCUx5CTd.js} +1 -1
  15. package/dist/deck-client/assets/{chunk-4TB4RGXK-D55BBvVZ.js → chunk-4TB4RGXK-UDZXXga6.js} +1 -1
  16. package/dist/deck-client/assets/{chunk-55IACEB6-BzjEcoTi.js → chunk-55IACEB6-CfcU6PIW.js} +1 -1
  17. package/dist/deck-client/assets/{chunk-EDXVE4YY-CH1vs4Lu.js → chunk-EDXVE4YY-BK6F5Fof.js} +1 -1
  18. package/dist/deck-client/assets/{chunk-FMBD7UC4-CVRnaGM0.js → chunk-FMBD7UC4-C-2idlFB.js} +1 -1
  19. package/dist/deck-client/assets/{chunk-OYMX7WX6-BCTV_aEZ.js → chunk-OYMX7WX6-D6hBkYLP.js} +1 -1
  20. package/dist/deck-client/assets/{chunk-QZHKN3VN-BqM8r4ee.js → chunk-QZHKN3VN-DixNpysA.js} +1 -1
  21. package/dist/deck-client/assets/{chunk-YZCP3GAM-Rhbb691A.js → chunk-YZCP3GAM-Cd3pNBtQ.js} +1 -1
  22. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-JLUXVCUr.js +1 -0
  23. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-JLUXVCUr.js +1 -0
  24. package/dist/deck-client/assets/clone-H0XCnSb6.js +1 -0
  25. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-fWyBR9Nn.js → cose-bilkent-S5V4N54A-OF3JWdEt.js} +1 -1
  26. package/dist/deck-client/assets/{dagre-KV5264BT-Ds0Sqext.js → dagre-KV5264BT-Bqu-qcv4.js} +1 -1
  27. package/dist/deck-client/assets/{diagram-5BDNPKRD-BGz_X007.js → diagram-5BDNPKRD--0eHmUBS.js} +1 -1
  28. package/dist/deck-client/assets/{diagram-G4DWMVQ6-C78jeb-r.js → diagram-G4DWMVQ6-nss6oL20.js} +1 -1
  29. package/dist/deck-client/assets/{diagram-MMDJMWI5-BdoHW8mF.js → diagram-MMDJMWI5-D_gSGnLR.js} +1 -1
  30. package/dist/deck-client/assets/{diagram-TYMM5635-C8i9zc-U.js → diagram-TYMM5635-BIt-P6Pk.js} +1 -1
  31. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-DplAZ-yG.js → erDiagram-SMLLAGMA-Bi-E4KQm.js} +1 -1
  32. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-F3N9yTAB.js → flowDiagram-DWJPFMVM-DMJCvLMA.js} +1 -1
  33. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-DebdM4S5.js → ganttDiagram-T4ZO3ILL-C3xgEoPD.js} +1 -1
  34. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-htCk0oPz.js → gitGraphDiagram-UUTBAWPF-CD0BEGAW.js} +1 -1
  35. package/dist/deck-client/assets/{graph-Dtxc2PT4.js → graph-Dtsd9Jwe.js} +1 -1
  36. package/dist/deck-client/assets/index-C6YxyZay.css +1 -0
  37. package/dist/deck-client/assets/{index-CwAiam97.js → index-TFX8vtTG.js} +1 -1
  38. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-gTxegviJ.js → infoDiagram-42DDH7IO-7IcQYqe_.js} +1 -1
  39. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DYSEsfUK.js → ishikawaDiagram-UXIWVN3A-DsCEbx3u.js} +1 -1
  40. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-DgVc1q4D.js → journeyDiagram-VCZTEJTY-1mP2JwCk.js} +1 -1
  41. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-DcOf3i9N.js → kanban-definition-6JOO6SKY-vT0Xrqh9.js} +1 -1
  42. package/dist/deck-client/assets/{layout-CHP9HIw4.js → layout-Cw4rS2pn.js} +1 -1
  43. package/dist/deck-client/assets/{linear-XjVb7x4Q.js → linear-CzOjL-Ih.js} +1 -1
  44. package/dist/deck-client/assets/{mermaid.core-bouKOnsR.js → mermaid.core-DYi3A-qK.js} +4 -4
  45. package/dist/deck-client/assets/{min-Jl4GV9DB.js → min-DstloRoL.js} +1 -1
  46. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-FXXf4cJx.js → mindmap-definition-QFDTVHPH-D-cCX2d2.js} +1 -1
  47. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-Dl4plCTi.js → pieDiagram-DEJITSTG-BqW2NTmy.js} +1 -1
  48. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-BeOEeelg.js → quadrantDiagram-34T5L4WZ-DbJoWA8f.js} +1 -1
  49. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-CBh1jchM.js → requirementDiagram-MS252O5E-DQrUiz_d.js} +1 -1
  50. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BK6gG-ub.js → sankeyDiagram-XADWPNL6-kB7PZc3g.js} +1 -1
  51. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-BtQwzsF5.js → sequenceDiagram-FGHM5R23-CpyVu1TN.js} +1 -1
  52. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX--kLQOi8R.js → stateDiagram-FHFEXIEX-CjqQcnty.js} +1 -1
  53. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-tfMSn8xx.js +1 -0
  54. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-CQ_-CLh7.js → timeline-definition-GMOUNBTQ-B2PAO9bk.js} +1 -1
  55. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-DBhKYAFT.js → vennDiagram-DHZGUBPP-C0G3ItCr.js} +1 -1
  56. package/dist/deck-client/assets/{wardley-RL74JXVD-DLKe29q9.js → wardley-RL74JXVD-B0TVaOmp.js} +1 -1
  57. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-Brb8ezsV.js → wardleyDiagram-NUSXRM2D-B-qtbNZe.js} +1 -1
  58. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-LogZ0Az9.js → xychartDiagram-5P7HB3ND-41kcBoBE.js} +1 -1
  59. package/dist/deck-client/index.html +2 -2
  60. package/dist/server/cli.js +484 -77
  61. package/dist/server/init-entry.js +47 -21
  62. package/dist/server/launch-bot-entry.js +38 -4
  63. package/dist/server/radar-docker-init-entry.js +46 -20
  64. package/dist/server/rover-entry.js +6047 -5155
  65. package/package.json +1 -1
  66. package/dist/chart-client/assets/index-Dd6IotOZ.css +0 -1
  67. package/dist/client/assets/index-BoIjawzY.js +0 -294
  68. package/dist/client/assets/index-DE0uje6k.css +0 -32
  69. package/dist/council-client/assets/index-CGYusOCK.css +0 -1
  70. package/dist/deck-client/assets/channel-Bb5wIjTD.js +0 -1
  71. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-CN-ZYMbT.js +0 -1
  72. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-CN-ZYMbT.js +0 -1
  73. package/dist/deck-client/assets/clone-D6e7poKG.js +0 -1
  74. package/dist/deck-client/assets/index-evAPhGvM.css +0 -1
  75. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CHEPjgB0.js +0 -1
  76. /package/dist/chart-client/assets/{index-CrYM1-ac.js → index-DJQYgFcp.js} +0 -0
  77. /package/dist/council-client/assets/{index-DkTFX53U.js → index-Wn06apTg.js} +0 -0
@@ -1076,14 +1076,30 @@ async function setupFromCloud() {
1076
1076
  console.log(`[entrypoint] bundle from cloud: org=${orgSlug} project=${projectSlug} git=${process.env.GIT_USER_NAME} <${process.env.GIT_USER_EMAIL}> github=${bundle.githubTokenStatus.toLowerCase()} ${cfNote}`);
1077
1077
  return bundle;
1078
1078
  }
1079
+ function hasUsableCredentials(credsPath) {
1080
+ if (!(0, import_node_fs4.existsSync)(credsPath)) return false;
1081
+ try {
1082
+ const raw = (0, import_node_fs4.readFileSync)(credsPath, "utf8").trim();
1083
+ if (raw.length === 0) return false;
1084
+ const parsed = JSON.parse(raw);
1085
+ return parsed != null && typeof parsed === "object" && "claudeAiOauth" in parsed;
1086
+ } catch {
1087
+ return false;
1088
+ }
1089
+ }
1079
1090
  function setupClaudeCredentials() {
1080
1091
  const home = process.env.HOME ?? "/home/launchpod";
1081
1092
  const claudeDir = (0, import_node_path4.join)(home, ".claude");
1082
1093
  (0, import_node_fs4.mkdirSync)(claudeDir, { recursive: true });
1083
- const decoded = Buffer.from(requireEnv("CLAUDE_CREDENTIALS_B64"), "base64").toString("utf8");
1084
1094
  const credsPath = (0, import_node_path4.join)(claudeDir, ".credentials.json");
1085
- (0, import_node_fs4.writeFileSync)(credsPath, decoded);
1086
- (0, import_node_fs4.chmodSync)(credsPath, 384);
1095
+ if (hasUsableCredentials(credsPath)) {
1096
+ console.log("[entrypoint] ~/.claude/.credentials.json already present \u2014 leaving Claude Code's own (refreshed) credentials intact");
1097
+ } else {
1098
+ const decoded = Buffer.from(requireEnv("CLAUDE_CREDENTIALS_B64"), "base64").toString("utf8");
1099
+ (0, import_node_fs4.writeFileSync)(credsPath, decoded);
1100
+ (0, import_node_fs4.chmodSync)(credsPath, 384);
1101
+ console.log("[entrypoint] seeded ~/.claude/.credentials.json from CLAUDE_CREDENTIALS_B64");
1102
+ }
1087
1103
  const configPath = (0, import_node_path4.join)(home, ".claude.json");
1088
1104
  let cfg = {};
1089
1105
  if ((0, import_node_fs4.existsSync)(configPath)) {
@@ -1107,7 +1123,7 @@ function setupClaudeCredentials() {
1107
1123
  "launch-sequencer"
1108
1124
  ];
1109
1125
  const projects = cfg.projects ?? {};
1110
- const wsKey = "/workspace";
1126
+ const wsKey = POD_WS;
1111
1127
  const wsProject = projects[wsKey] ?? {};
1112
1128
  const existingEnabled = Array.isArray(wsProject.enabledMcpjsonServers) ? wsProject.enabledMcpjsonServers : [];
1113
1129
  const mergedEnabled = Array.from(/* @__PURE__ */ new Set([...existingEnabled, ...PREAPPROVED_MCPS]));
@@ -1126,7 +1142,7 @@ function setupGitAndGh() {
1126
1142
  function detectAndSetPreviewPort() {
1127
1143
  if (process.env.PREVIEW_PORT) return;
1128
1144
  try {
1129
- const pkgPath = "/workspace/package.json";
1145
+ const pkgPath = (0, import_node_path4.join)(POD_WS, "package.json");
1130
1146
  if (!(0, import_node_fs4.existsSync)(pkgPath)) return;
1131
1147
  const pkg = JSON.parse((0, import_node_fs4.readFileSync)(pkgPath, "utf-8"));
1132
1148
  const scripts = pkg.scripts ?? {};
@@ -1145,23 +1161,27 @@ function detectAndSetPreviewPort() {
1145
1161
  }
1146
1162
  }
1147
1163
  function initWorkspaceIfEmpty() {
1148
- process.chdir("/workspace");
1164
+ process.chdir(POD_WS);
1149
1165
  if ((0, import_node_fs4.existsSync)(".git")) {
1150
- console.log("[entrypoint] /workspace already initialized \u2014 skipping init");
1166
+ console.log(`[entrypoint] ${POD_WS} already initialized \u2014 skipping init`);
1151
1167
  return;
1152
1168
  }
1153
- console.log("[entrypoint] /workspace is empty \u2014 running launch-kit init");
1169
+ console.log(`[entrypoint] ${POD_WS} is empty \u2014 running launch-kit init`);
1154
1170
  const status = run2("launch-kit", [
1155
1171
  "init",
1156
1172
  `--token=${requireEnv("LS_PAT")}`,
1157
1173
  `--org=${requireEnv("LS_ORG_SLUG")}`,
1158
1174
  `--project=${requireEnv("LS_PROJECT_SLUG")}`,
1159
1175
  `--url=${process.env.LS_SERVER_URL ?? "https://launchsecure-v2.vercel.app"}`,
1160
- `--dir=/workspace`
1176
+ `--dir=${POD_WS}`
1161
1177
  ]);
1162
1178
  if (status !== 0) fail2(`[entrypoint] launch-kit init failed (status ${status})`);
1163
1179
  }
1164
1180
  async function maybeProvisionIngress(bundle, services, projectSlug) {
1181
+ if (LOCAL_ONLY) {
1182
+ console.log("[entrypoint] LAUNCHKIT_LOCAL_ONLY=1 \u2014 skipping CF ingress; services run on localhost only");
1183
+ return null;
1184
+ }
1165
1185
  const token = bundle.cloudflareToken ?? null;
1166
1186
  const accountId = bundle.cloudflareAccountId ?? null;
1167
1187
  const zones = bundle.cloudflareZones ?? [];
@@ -1181,7 +1201,7 @@ async function maybeProvisionIngress(bundle, services, projectSlug) {
1181
1201
  } else {
1182
1202
  fail2(`[entrypoint] cloudflare token covers ${zones.length} zones (${zones.map((z) => z.name).join(", ")}) \u2014 set LAUNCHKIT_CF_BASE_DOMAIN to pick one.`);
1183
1203
  }
1184
- const stateFile = "/workspace/.launchpod/launch-kit-tunnel.json";
1204
+ const stateFile = (0, import_node_path4.join)(POD_WS, ".launchpod", "launch-kit-tunnel.json");
1185
1205
  const slugLabel = projectSlug.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
1186
1206
  const DNS_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
1187
1207
  for (const s of services) {
@@ -1247,7 +1267,7 @@ async function maybeProvisionAccess(bundle, ingress) {
1247
1267
  }
1248
1268
  const serverUrl = process.env.LS_SERVER_URL ?? "https://launchsecure-v2.vercel.app";
1249
1269
  const pat = requireEnv("LS_PAT");
1250
- const stateFile = "/workspace/.launchpod/launch-kit-access.json";
1270
+ const stateFile = (0, import_node_path4.join)(POD_WS, ".launchpod", "launch-kit-access.json");
1251
1271
  const gatedHosts = services.filter((s) => !s.bypass).map((s) => s.hostname);
1252
1272
  const bypassed = services.filter((s) => s.bypass).map((s) => `${s.hostname}${s.path ?? ""}`);
1253
1273
  console.log(`[entrypoint] gating ${gatedHosts.join(", ")} behind CF Access (IdP: ${serverUrl})`);
@@ -1346,11 +1366,13 @@ function spawnServiceGroup(services) {
1346
1366
  }).finally(removeSignals);
1347
1367
  }
1348
1368
  async function main() {
1349
- const priorCrashes = readCrashState()?.count ?? 0;
1350
- if (priorCrashes >= MAX_BOOT_CRASHES) await parkAfterCrashLoop(priorCrashes);
1351
- const bootAttempt = bumpCrashCount();
1352
- if (bootAttempt > 1) {
1353
- console.warn(`[entrypoint] boot attempt ${bootAttempt}/${MAX_BOOT_CRASHES} \u2014 prior boot(s) crashed before becoming stable`);
1369
+ if (!NO_PARK) {
1370
+ const priorCrashes = readCrashState()?.count ?? 0;
1371
+ if (priorCrashes >= MAX_BOOT_CRASHES) await parkAfterCrashLoop(priorCrashes);
1372
+ const bootAttempt = bumpCrashCount();
1373
+ if (bootAttempt > 1) {
1374
+ console.warn(`[entrypoint] boot attempt ${bootAttempt}/${MAX_BOOT_CRASHES} \u2014 prior boot(s) crashed before becoming stable`);
1375
+ }
1354
1376
  }
1355
1377
  for (const k of REQUIRED_ENV) requireEnv(k);
1356
1378
  const bundle = await setupFromCloud();
@@ -1384,8 +1406,10 @@ async function main() {
1384
1406
  }
1385
1407
  }
1386
1408
  const stableTimer = setTimeout(() => {
1387
- clearCrashCount();
1388
- console.log(`[entrypoint] services stable for ${Math.round(STABLE_AFTER_MS / 1e3)}s \u2014 boot-crash counter cleared`);
1409
+ if (!NO_PARK) {
1410
+ clearCrashCount();
1411
+ console.log(`[entrypoint] services stable for ${Math.round(STABLE_AFTER_MS / 1e3)}s \u2014 boot-crash counter cleared`);
1412
+ }
1389
1413
  }, STABLE_AFTER_MS);
1390
1414
  stableTimer.unref?.();
1391
1415
  try {
@@ -1398,7 +1422,7 @@ async function main() {
1398
1422
  process.exit(1);
1399
1423
  }
1400
1424
  }
1401
- var import_node_child_process2, import_node_fs4, import_node_path4, REQUIRED_ENV, LAUNCHPOD_DIR, CRASH_STATE_FILE, MAX_BOOT_CRASHES, STABLE_AFTER_MS, GATED_SERVICES;
1425
+ var import_node_child_process2, import_node_fs4, import_node_path4, REQUIRED_ENV, POD_WS, NO_PARK, LOCAL_ONLY, LAUNCHPOD_DIR, CRASH_STATE_FILE, MAX_BOOT_CRASHES, STABLE_AFTER_MS, GATED_SERVICES;
1402
1426
  var init_radar_docker_init_entry = __esm({
1403
1427
  "src/server/radar-docker-init-entry.ts"() {
1404
1428
  "use strict";
@@ -1411,12 +1435,14 @@ var init_radar_docker_init_entry = __esm({
1411
1435
  init_cf_access();
1412
1436
  init_registration();
1413
1437
  REQUIRED_ENV = [
1414
- "CLAUDE_CREDENTIALS_B64",
1415
1438
  "LS_PAT",
1416
1439
  "LS_ORG_SLUG",
1417
1440
  "LS_PROJECT_SLUG"
1418
1441
  ];
1419
- LAUNCHPOD_DIR = "/workspace/.launchpod";
1442
+ POD_WS = process.env.LAUNCHPOD_WORKSPACE ?? "/workspace";
1443
+ NO_PARK = process.env.LAUNCHPOD_NO_PARK === "1";
1444
+ LOCAL_ONLY = process.env.LAUNCHKIT_LOCAL_ONLY === "1";
1445
+ LAUNCHPOD_DIR = (0, import_node_path4.join)(POD_WS, ".launchpod");
1420
1446
  CRASH_STATE_FILE = (0, import_node_path4.join)(LAUNCHPOD_DIR, ".boot-crash.json");
1421
1447
  MAX_BOOT_CRASHES = 5;
1422
1448
  STABLE_AFTER_MS = 3e4;
@@ -611,6 +611,14 @@ var require_claude_bridge = __commonJS({
611
611
  },
612
612
  onError = () => {
613
613
  },
614
+ // Fired (at most once per session) when Claude Code prints its
615
+ // authentication-failure banner — i.e. the credential it resolved was
616
+ // rejected by the Anthropic API. In a headless pod nobody is watching the
617
+ // pty, so this is the only signal the credential died; callers surface it
618
+ // (radar card + status banner) instead of failing silently. Detail is a
619
+ // short human string.
620
+ onAuthFailure = () => {
621
+ },
614
622
  cols = 80,
615
623
  rows = 24,
616
624
  // When true, spawn `claude --resume <sessionId>` instead of starting a
@@ -671,6 +679,7 @@ var require_claude_bridge = __commonJS({
671
679
  this.sessions.set(sessionId, session);
672
680
  let trustPromptHandled = false;
673
681
  let autoStartSent = !!initialPrompt;
682
+ let authFailureReported = false;
674
683
  let dataBuffer = "";
675
684
  claudeProcess.onData((data) => {
676
685
  if (process.env.DEBUG) {
@@ -685,6 +694,15 @@ var require_claude_bridge = __commonJS({
685
694
  console.log(`Sent Enter to accept trust prompt for session ${sessionId}`);
686
695
  }, 500);
687
696
  }
697
+ if (!authFailureReported && /Please run \/login|Invalid authentication credentials/i.test(dataBuffer)) {
698
+ authFailureReported = true;
699
+ console.error(`Claude session ${sessionId}: authentication failed (credential rejected by Anthropic API)`);
700
+ try {
701
+ onAuthFailure("Claude credential rejected (401) \u2014 pod could not authenticate to the Anthropic API.");
702
+ } catch (e) {
703
+ console.error(`onAuthFailure handler threw for session ${sessionId}:`, e);
704
+ }
705
+ }
688
706
  if (!autoStartSent && appendSystemPrompt && dataBuffer.includes("\u276F")) {
689
707
  autoStartSent = true;
690
708
  console.log(`Auto-starting agent in session ${sessionId}`);
@@ -3246,6 +3264,13 @@ var require_src = __commonJS({
3246
3264
  message: error.message
3247
3265
  });
3248
3266
  },
3267
+ onAuthFailure: (detail) => {
3268
+ this.broadcastToSession(sessionId, {
3269
+ type: "auth_failed",
3270
+ sessionId,
3271
+ message: detail
3272
+ });
3273
+ },
3249
3274
  ...options
3250
3275
  });
3251
3276
  session.active = true;
@@ -3717,13 +3742,22 @@ var require_src = __commonJS({
3717
3742
  return new TerminalHandler(options);
3718
3743
  }
3719
3744
  function createWebSocketHandler2(httpServer, handler2, wsPath = "/terminal/ws") {
3720
- const wss2 = new WebSocket.Server({
3721
- server: httpServer,
3722
- path: wsPath
3723
- });
3745
+ const wss2 = new WebSocket.Server({ noServer: true });
3724
3746
  wss2.on("connection", (ws, req) => {
3725
3747
  handler2.handleWebSocketConnection(ws, req);
3726
3748
  });
3749
+ httpServer.on("upgrade", (req, socket, head) => {
3750
+ let pathname;
3751
+ try {
3752
+ pathname = new URL(req.url || "/", "http://localhost").pathname;
3753
+ } catch {
3754
+ return;
3755
+ }
3756
+ if (pathname !== wsPath) return;
3757
+ wss2.handleUpgrade(req, socket, head, (ws) => {
3758
+ wss2.emit("connection", ws, req);
3759
+ });
3760
+ });
3727
3761
  return wss2;
3728
3762
  }
3729
3763
  function detectClaudeCli2() {
@@ -613,11 +613,13 @@ var RECEIVER_PATH = "/api/radar/ingest";
613
613
 
614
614
  // src/server/radar-docker-init-entry.ts
615
615
  var REQUIRED_ENV = [
616
- "CLAUDE_CREDENTIALS_B64",
617
616
  "LS_PAT",
618
617
  "LS_ORG_SLUG",
619
618
  "LS_PROJECT_SLUG"
620
619
  ];
620
+ var POD_WS = process.env.LAUNCHPOD_WORKSPACE ?? "/workspace";
621
+ var NO_PARK = process.env.LAUNCHPOD_NO_PARK === "1";
622
+ var LOCAL_ONLY = process.env.LAUNCHKIT_LOCAL_ONLY === "1";
621
623
  function fail2(message) {
622
624
  console.error(message);
623
625
  process.exit(1);
@@ -631,7 +633,7 @@ function run(cmd, args, stdio = "inherit") {
631
633
  const r = (0, import_node_child_process.spawnSync)(cmd, args, { stdio });
632
634
  return r.status ?? 1;
633
635
  }
634
- var LAUNCHPOD_DIR = "/workspace/.launchpod";
636
+ var LAUNCHPOD_DIR = (0, import_node_path4.join)(POD_WS, ".launchpod");
635
637
  var CRASH_STATE_FILE = (0, import_node_path4.join)(LAUNCHPOD_DIR, ".boot-crash.json");
636
638
  var MAX_BOOT_CRASHES = 5;
637
639
  var STABLE_AFTER_MS = 3e4;
@@ -714,14 +716,30 @@ async function setupFromCloud() {
714
716
  console.log(`[entrypoint] bundle from cloud: org=${orgSlug} project=${projectSlug} git=${process.env.GIT_USER_NAME} <${process.env.GIT_USER_EMAIL}> github=${bundle.githubTokenStatus.toLowerCase()} ${cfNote}`);
715
717
  return bundle;
716
718
  }
719
+ function hasUsableCredentials(credsPath) {
720
+ if (!(0, import_node_fs4.existsSync)(credsPath)) return false;
721
+ try {
722
+ const raw = (0, import_node_fs4.readFileSync)(credsPath, "utf8").trim();
723
+ if (raw.length === 0) return false;
724
+ const parsed = JSON.parse(raw);
725
+ return parsed != null && typeof parsed === "object" && "claudeAiOauth" in parsed;
726
+ } catch {
727
+ return false;
728
+ }
729
+ }
717
730
  function setupClaudeCredentials() {
718
731
  const home = process.env.HOME ?? "/home/launchpod";
719
732
  const claudeDir = (0, import_node_path4.join)(home, ".claude");
720
733
  (0, import_node_fs4.mkdirSync)(claudeDir, { recursive: true });
721
- const decoded = Buffer.from(requireEnv("CLAUDE_CREDENTIALS_B64"), "base64").toString("utf8");
722
734
  const credsPath = (0, import_node_path4.join)(claudeDir, ".credentials.json");
723
- (0, import_node_fs4.writeFileSync)(credsPath, decoded);
724
- (0, import_node_fs4.chmodSync)(credsPath, 384);
735
+ if (hasUsableCredentials(credsPath)) {
736
+ console.log("[entrypoint] ~/.claude/.credentials.json already present \u2014 leaving Claude Code's own (refreshed) credentials intact");
737
+ } else {
738
+ const decoded = Buffer.from(requireEnv("CLAUDE_CREDENTIALS_B64"), "base64").toString("utf8");
739
+ (0, import_node_fs4.writeFileSync)(credsPath, decoded);
740
+ (0, import_node_fs4.chmodSync)(credsPath, 384);
741
+ console.log("[entrypoint] seeded ~/.claude/.credentials.json from CLAUDE_CREDENTIALS_B64");
742
+ }
725
743
  const configPath = (0, import_node_path4.join)(home, ".claude.json");
726
744
  let cfg = {};
727
745
  if ((0, import_node_fs4.existsSync)(configPath)) {
@@ -745,7 +763,7 @@ function setupClaudeCredentials() {
745
763
  "launch-sequencer"
746
764
  ];
747
765
  const projects = cfg.projects ?? {};
748
- const wsKey = "/workspace";
766
+ const wsKey = POD_WS;
749
767
  const wsProject = projects[wsKey] ?? {};
750
768
  const existingEnabled = Array.isArray(wsProject.enabledMcpjsonServers) ? wsProject.enabledMcpjsonServers : [];
751
769
  const mergedEnabled = Array.from(/* @__PURE__ */ new Set([...existingEnabled, ...PREAPPROVED_MCPS]));
@@ -764,7 +782,7 @@ function setupGitAndGh() {
764
782
  function detectAndSetPreviewPort() {
765
783
  if (process.env.PREVIEW_PORT) return;
766
784
  try {
767
- const pkgPath = "/workspace/package.json";
785
+ const pkgPath = (0, import_node_path4.join)(POD_WS, "package.json");
768
786
  if (!(0, import_node_fs4.existsSync)(pkgPath)) return;
769
787
  const pkg = JSON.parse((0, import_node_fs4.readFileSync)(pkgPath, "utf-8"));
770
788
  const scripts = pkg.scripts ?? {};
@@ -783,23 +801,27 @@ function detectAndSetPreviewPort() {
783
801
  }
784
802
  }
785
803
  function initWorkspaceIfEmpty() {
786
- process.chdir("/workspace");
804
+ process.chdir(POD_WS);
787
805
  if ((0, import_node_fs4.existsSync)(".git")) {
788
- console.log("[entrypoint] /workspace already initialized \u2014 skipping init");
806
+ console.log(`[entrypoint] ${POD_WS} already initialized \u2014 skipping init`);
789
807
  return;
790
808
  }
791
- console.log("[entrypoint] /workspace is empty \u2014 running launch-kit init");
809
+ console.log(`[entrypoint] ${POD_WS} is empty \u2014 running launch-kit init`);
792
810
  const status = run("launch-kit", [
793
811
  "init",
794
812
  `--token=${requireEnv("LS_PAT")}`,
795
813
  `--org=${requireEnv("LS_ORG_SLUG")}`,
796
814
  `--project=${requireEnv("LS_PROJECT_SLUG")}`,
797
815
  `--url=${process.env.LS_SERVER_URL ?? "https://launchsecure-v2.vercel.app"}`,
798
- `--dir=/workspace`
816
+ `--dir=${POD_WS}`
799
817
  ]);
800
818
  if (status !== 0) fail2(`[entrypoint] launch-kit init failed (status ${status})`);
801
819
  }
802
820
  async function maybeProvisionIngress(bundle, services, projectSlug) {
821
+ if (LOCAL_ONLY) {
822
+ console.log("[entrypoint] LAUNCHKIT_LOCAL_ONLY=1 \u2014 skipping CF ingress; services run on localhost only");
823
+ return null;
824
+ }
803
825
  const token = bundle.cloudflareToken ?? null;
804
826
  const accountId = bundle.cloudflareAccountId ?? null;
805
827
  const zones = bundle.cloudflareZones ?? [];
@@ -819,7 +841,7 @@ async function maybeProvisionIngress(bundle, services, projectSlug) {
819
841
  } else {
820
842
  fail2(`[entrypoint] cloudflare token covers ${zones.length} zones (${zones.map((z) => z.name).join(", ")}) \u2014 set LAUNCHKIT_CF_BASE_DOMAIN to pick one.`);
821
843
  }
822
- const stateFile = "/workspace/.launchpod/launch-kit-tunnel.json";
844
+ const stateFile = (0, import_node_path4.join)(POD_WS, ".launchpod", "launch-kit-tunnel.json");
823
845
  const slugLabel = projectSlug.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
824
846
  const DNS_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
825
847
  for (const s of services) {
@@ -895,7 +917,7 @@ async function maybeProvisionAccess(bundle, ingress) {
895
917
  }
896
918
  const serverUrl = process.env.LS_SERVER_URL ?? "https://launchsecure-v2.vercel.app";
897
919
  const pat = requireEnv("LS_PAT");
898
- const stateFile = "/workspace/.launchpod/launch-kit-access.json";
920
+ const stateFile = (0, import_node_path4.join)(POD_WS, ".launchpod", "launch-kit-access.json");
899
921
  const gatedHosts = services.filter((s) => !s.bypass).map((s) => s.hostname);
900
922
  const bypassed = services.filter((s) => s.bypass).map((s) => `${s.hostname}${s.path ?? ""}`);
901
923
  console.log(`[entrypoint] gating ${gatedHosts.join(", ")} behind CF Access (IdP: ${serverUrl})`);
@@ -994,11 +1016,13 @@ function spawnServiceGroup(services) {
994
1016
  }).finally(removeSignals);
995
1017
  }
996
1018
  async function main() {
997
- const priorCrashes = readCrashState()?.count ?? 0;
998
- if (priorCrashes >= MAX_BOOT_CRASHES) await parkAfterCrashLoop(priorCrashes);
999
- const bootAttempt = bumpCrashCount();
1000
- if (bootAttempt > 1) {
1001
- console.warn(`[entrypoint] boot attempt ${bootAttempt}/${MAX_BOOT_CRASHES} \u2014 prior boot(s) crashed before becoming stable`);
1019
+ if (!NO_PARK) {
1020
+ const priorCrashes = readCrashState()?.count ?? 0;
1021
+ if (priorCrashes >= MAX_BOOT_CRASHES) await parkAfterCrashLoop(priorCrashes);
1022
+ const bootAttempt = bumpCrashCount();
1023
+ if (bootAttempt > 1) {
1024
+ console.warn(`[entrypoint] boot attempt ${bootAttempt}/${MAX_BOOT_CRASHES} \u2014 prior boot(s) crashed before becoming stable`);
1025
+ }
1002
1026
  }
1003
1027
  for (const k of REQUIRED_ENV) requireEnv(k);
1004
1028
  const bundle = await setupFromCloud();
@@ -1032,8 +1056,10 @@ async function main() {
1032
1056
  }
1033
1057
  }
1034
1058
  const stableTimer = setTimeout(() => {
1035
- clearCrashCount();
1036
- console.log(`[entrypoint] services stable for ${Math.round(STABLE_AFTER_MS / 1e3)}s \u2014 boot-crash counter cleared`);
1059
+ if (!NO_PARK) {
1060
+ clearCrashCount();
1061
+ console.log(`[entrypoint] services stable for ${Math.round(STABLE_AFTER_MS / 1e3)}s \u2014 boot-crash counter cleared`);
1062
+ }
1037
1063
  }, STABLE_AFTER_MS);
1038
1064
  stableTimer.unref?.();
1039
1065
  try {