@launchsecure/launch-kit 0.0.37 → 0.0.39

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 (94) hide show
  1. package/dist/beacon/beacon.mjs +308 -298
  2. package/dist/beacon/beacon.mjs.map +1 -1
  3. package/dist/beacon/beacon.umd.js +6 -6
  4. package/dist/beacon/beacon.umd.js.map +1 -1
  5. package/dist/beacon/types/internal/screenshot.d.ts.map +1 -1
  6. package/dist/chart-client/assets/index-ysGpLeOW.css +1 -0
  7. package/dist/chart-client/index.html +2 -2
  8. package/dist/client/assets/index-CMN3tlGP.css +32 -0
  9. package/dist/client/index.html +2 -2
  10. package/dist/council-client/assets/index-ChmNX6bZ.css +1 -0
  11. package/dist/council-client/index.html +2 -2
  12. package/dist/deck-client/assets/{_baseUniq-Cn5TyL9s.js → _baseUniq-DOrnEQMI.js} +1 -1
  13. package/dist/deck-client/assets/{arc-D61amKYu.js → arc-DOWK7V3m.js} +1 -1
  14. package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-CpKrvC2W.js → architectureDiagram-Q4EWVU46-DPhzvk7q.js} +1 -1
  15. package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-Yj5OjxvG.js → blockDiagram-DXYQGD6D-CwAGy9lU.js} +1 -1
  16. package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-BIR810Tv.js → c4Diagram-AHTNJAMY-L_g_SS21.js} +1 -1
  17. package/dist/deck-client/assets/channel-DqiACUUq.js +1 -0
  18. package/dist/deck-client/assets/{chunk-4BX2VUAB-BeSHwGvx.js → chunk-4BX2VUAB-RKm0LXpu.js} +1 -1
  19. package/dist/deck-client/assets/{chunk-4TB4RGXK-CCqzsLpg.js → chunk-4TB4RGXK-Bk0FUbxU.js} +1 -1
  20. package/dist/deck-client/assets/{chunk-55IACEB6-CuW_aq4-.js → chunk-55IACEB6-Cl3hja-M.js} +1 -1
  21. package/dist/deck-client/assets/{chunk-EDXVE4YY-Dl35ixYh.js → chunk-EDXVE4YY-CNIMQCV2.js} +1 -1
  22. package/dist/deck-client/assets/{chunk-FMBD7UC4-TwreZQTv.js → chunk-FMBD7UC4-DqOvWr1k.js} +1 -1
  23. package/dist/deck-client/assets/{chunk-OYMX7WX6-Ahfw8EUo.js → chunk-OYMX7WX6-1Kd7yK5u.js} +1 -1
  24. package/dist/deck-client/assets/{chunk-QZHKN3VN-DlE_zlU-.js → chunk-QZHKN3VN-6_kraYpP.js} +1 -1
  25. package/dist/deck-client/assets/{chunk-YZCP3GAM-Dj6QWzSg.js → chunk-YZCP3GAM-FgAwIWlo.js} +1 -1
  26. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-D23cq2C3.js +1 -0
  27. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-D23cq2C3.js +1 -0
  28. package/dist/deck-client/assets/clone-C7jSigGq.js +1 -0
  29. package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-BO1z5aOM.js → cose-bilkent-S5V4N54A-CigVnnPr.js} +1 -1
  30. package/dist/deck-client/assets/{dagre-KV5264BT-DVsw17fE.js → dagre-KV5264BT-DHZXTktX.js} +1 -1
  31. package/dist/deck-client/assets/{diagram-5BDNPKRD-6jYs7oZk.js → diagram-5BDNPKRD-H5k0eauU.js} +1 -1
  32. package/dist/deck-client/assets/{diagram-G4DWMVQ6-6DbggeGE.js → diagram-G4DWMVQ6-Bg3dFhSY.js} +1 -1
  33. package/dist/deck-client/assets/{diagram-MMDJMWI5-CQtk1cSU.js → diagram-MMDJMWI5-CQLC410N.js} +1 -1
  34. package/dist/deck-client/assets/{diagram-TYMM5635-BR-gt75b.js → diagram-TYMM5635-DFTCHVkP.js} +1 -1
  35. package/dist/deck-client/assets/{erDiagram-SMLLAGMA-C9qMtjdY.js → erDiagram-SMLLAGMA-aiv9GZnL.js} +1 -1
  36. package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-CdaPhPYb.js → flowDiagram-DWJPFMVM-C6Fhvtsy.js} +1 -1
  37. package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-BRsZWUy4.js → ganttDiagram-T4ZO3ILL-DSaGMPM4.js} +1 -1
  38. package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-B8Z90jCj.js → gitGraphDiagram-UUTBAWPF-DMjL2Vix.js} +1 -1
  39. package/dist/deck-client/assets/{graph-my2Zphm4.js → graph-B7Vn5lkK.js} +1 -1
  40. package/dist/deck-client/assets/{index-DqAoYZwV.js → index-BD36e-tD.js} +64 -64
  41. package/dist/deck-client/assets/index-CGbNOpk9.css +1 -0
  42. package/dist/deck-client/assets/{infoDiagram-42DDH7IO-Csr9loin.js → infoDiagram-42DDH7IO-mNi4iygG.js} +1 -1
  43. package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-HWdvUNFi.js → ishikawaDiagram-UXIWVN3A-BwCUmUVt.js} +1 -1
  44. package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-CjYHG6EM.js → journeyDiagram-VCZTEJTY-C6qoqJmJ.js} +1 -1
  45. package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-CX3JdUu7.js → kanban-definition-6JOO6SKY-Dz1Tt3sA.js} +1 -1
  46. package/dist/deck-client/assets/{layout-Bcucv5Gi.js → layout-CZTyRhOG.js} +1 -1
  47. package/dist/deck-client/assets/{linear-CUGM5FJZ.js → linear--7n7iEvd.js} +1 -1
  48. package/dist/deck-client/assets/{min-Dw4g5w9z.js → min-Bh130DN8.js} +1 -1
  49. package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-C8oo61fg.js → mindmap-definition-QFDTVHPH-CfXcK1qH.js} +1 -1
  50. package/dist/deck-client/assets/{pieDiagram-DEJITSTG-D2WYGkq8.js → pieDiagram-DEJITSTG-DjVHLAVw.js} +1 -1
  51. package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-Vh00GISt.js → quadrantDiagram-34T5L4WZ-CXwvZ1i1.js} +1 -1
  52. package/dist/deck-client/assets/{requirementDiagram-MS252O5E-DxI-DFrN.js → requirementDiagram-MS252O5E-Cl6xm0fR.js} +1 -1
  53. package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-QgwyjasI.js → sankeyDiagram-XADWPNL6-BOH9sLyh.js} +1 -1
  54. package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-DmOmD5Ni.js → sequenceDiagram-FGHM5R23-BC1MYBn6.js} +1 -1
  55. package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-CRwglGg_.js → stateDiagram-FHFEXIEX-kNp9bv8K.js} +1 -1
  56. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-hRsAFc2t.js +1 -0
  57. package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-Dj9YGKOh.js → timeline-definition-GMOUNBTQ-DKnITsD4.js} +1 -1
  58. package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-xzIaOzEU.js → vennDiagram-DHZGUBPP-BdajXRrh.js} +1 -1
  59. package/dist/deck-client/assets/wardley-RL74JXVD-BL802-su.js +162 -0
  60. package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-BIYYh-JZ.js → wardleyDiagram-NUSXRM2D-B2hDCDl2.js} +1 -1
  61. package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-Cy9EoJCh.js → xychartDiagram-5P7HB3ND-CvnYFs51.js} +1 -1
  62. package/dist/deck-client/index.html +2 -2
  63. package/dist/server/cli.js +4 -0
  64. package/dist/server/council-entry.js +0 -0
  65. package/dist/server/deck-mcp-entry.js +3 -1
  66. package/dist/server/deck-serve.js +3 -1
  67. package/dist/server/fb-wizard.js +0 -0
  68. package/dist/server/init-entry.js +203 -39
  69. package/dist/server/radar-docker-init-entry.js +44 -14
  70. package/dist/server/radar-entrypoint-entry.js +0 -0
  71. package/dist/server/radar-teardown-entry.js +0 -0
  72. package/dist/server/rover-entry.js +44 -1
  73. package/package.json +23 -22
  74. package/scaffolds/ls-marketplace/plugins/kit/commands/activate-statusline.md +8 -7
  75. package/scaffolds/ls-marketplace/plugins/kit/commands/deactivate-statusline.md +2 -2
  76. package/scaffolds/ls-marketplace/plugins/kit/skills/comms/SKILL.md +88 -0
  77. package/scaffolds/ls-marketplace/plugins/kit/skills/project-info/SKILL.md +88 -0
  78. package/scaffolds/ls-marketplace/plugins/kit/skills/slides/SKILL.md +118 -0
  79. package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +0 -0
  80. package/scaffolds/recall-hook/scripts/ensure-recall.sh +0 -0
  81. package/scaffolds/statusline/statusline-base.sh +20 -0
  82. package/dist/chart-client/assets/index-DJrjyXbN.css +0 -1
  83. package/dist/client/assets/index-8eSXr3Ez.css +0 -32
  84. package/dist/council-client/assets/index-4K0t2WrZ.css +0 -1
  85. package/dist/deck-client/assets/channel-DrJz2x-n.js +0 -1
  86. package/dist/deck-client/assets/classDiagram-6PBFFD2Q-a3tg9w7z.js +0 -1
  87. package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-a3tg9w7z.js +0 -1
  88. package/dist/deck-client/assets/clone-Dd7JBCL5.js +0 -1
  89. package/dist/deck-client/assets/index-ByqxPEgU.css +0 -1
  90. package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BvZLEWAA.js +0 -1
  91. package/dist/deck-client/assets/wardley-RL74JXVD-CEAay09T.js +0 -162
  92. /package/dist/chart-client/assets/{index-BgUxHxwE.js → index-BlsuXuQ1.js} +0 -0
  93. /package/dist/client/assets/{index-CUivaQnN.js → index-BA7BHBWT.js} +0 -0
  94. /package/dist/council-client/assets/{index-DN8HN_5K.js → index-jjBWyhry.js} +0 -0
@@ -274,6 +274,11 @@ function writeScripts() {
274
274
  fs4.writeFileSync(WRAPPER_PATH, readScaffold("statusline-wrapper.sh"), { mode: 493 });
275
275
  fs4.writeFileSync(CHIP_PATH, readScaffold("statusline-mcp.sh"), { mode: 493 });
276
276
  }
277
+ function writeBaseScript() {
278
+ fs4.mkdirSync(LK_DIR, { recursive: true });
279
+ fs4.writeFileSync(BASE_PATH, readScaffold("statusline-base.sh"), { mode: 493 });
280
+ return `bash ${BASE_PATH}`;
281
+ }
277
282
  function wrapperCommand(opts) {
278
283
  const env = [];
279
284
  if (opts.show) env.push(`LK_STATUSLINE_SHOW=${opts.show}`);
@@ -282,10 +287,7 @@ function wrapperCommand(opts) {
282
287
  return `${prefix}bash ${WRAPPER_PATH}`;
283
288
  }
284
289
  function activateStatusline(opts = {}) {
285
- const settings = readSettings();
286
- if (!settings) {
287
- return { ok: false, outcome: "no-settings", message: `no ~/.claude/settings.json \u2014 nothing to wrap` };
288
- }
290
+ const settings = readSettings() ?? {};
289
291
  const currentCmd = settings.statusLine?.command;
290
292
  const alreadyWrapped = typeof currentCmd === "string" && currentCmd.includes(WRAPPER_PATH);
291
293
  if (alreadyWrapped) {
@@ -304,20 +306,22 @@ function activateStatusline(opts = {}) {
304
306
  }
305
307
  return { ok: true, outcome: "refreshed", message: "statusline already wrapped \u2014 refreshed chip scripts only" };
306
308
  }
307
- if (!currentCmd) {
308
- return { ok: false, outcome: "no-statusline", message: "no statusLine.command in ~/.claude/settings.json \u2014 launch-kit only extends an existing statusline" };
309
- }
310
309
  writeScripts();
310
+ const scaffolded = !currentCmd;
311
+ const original = scaffolded ? { type: "command", command: writeBaseScript() } : settings.statusLine;
311
312
  const wrapped = {
312
313
  ...settings,
313
314
  statusLine: { type: "command", command: wrapperCommand(opts) },
314
- [ORIGINAL_KEY]: settings.statusLine
315
+ [ORIGINAL_KEY]: original
315
316
  };
316
317
  writeSettings(wrapped);
317
318
  const modeParts = [];
318
319
  if (opts.show) modeParts.push(`chips: ${opts.show}`);
319
320
  if (opts.compact) modeParts.push("compact mode");
320
321
  const modeDesc = modeParts.length > 0 ? ` (${modeParts.join(", ")})` : "";
322
+ if (scaffolded) {
323
+ return { ok: true, outcome: "scaffolded", message: `no statusline found \u2014 scaffolded Claude Code's default base line and wrapped it with chips${modeDesc}; base stashed under ${ORIGINAL_KEY}` };
324
+ }
321
325
  return { ok: true, outcome: "activated", message: `wrapped statusLine.command${modeDesc}; original stashed under ${ORIGINAL_KEY}` };
322
326
  }
323
327
  function deactivateStatusline() {
@@ -327,18 +331,26 @@ function deactivateStatusline() {
327
331
  if (!original) {
328
332
  return { ok: false, outcome: "not-active", message: `no ${ORIGINAL_KEY} in settings.json \u2014 statusline isn't wrapped by launch-kit` };
329
333
  }
330
- const restored = { ...settings, statusLine: original };
334
+ const wasScaffolded = original.command?.includes(BASE_PATH) ?? false;
335
+ const restored = { ...settings };
336
+ if (wasScaffolded) delete restored.statusLine;
337
+ else restored.statusLine = original;
331
338
  delete restored[ORIGINAL_KEY];
332
339
  writeSettings(restored);
333
- for (const p of [WRAPPER_PATH, CHIP_PATH]) {
340
+ const toRemove = wasScaffolded ? [WRAPPER_PATH, CHIP_PATH, BASE_PATH] : [WRAPPER_PATH, CHIP_PATH];
341
+ for (const p of toRemove) {
334
342
  try {
335
343
  fs4.unlinkSync(p);
336
344
  } catch {
337
345
  }
338
346
  }
339
- return { ok: true, outcome: "deactivated", message: "restored original statusLine.command" };
347
+ return {
348
+ ok: true,
349
+ outcome: "deactivated",
350
+ message: wasScaffolded ? "removed launch-kit statusline and scaffolded base line \u2014 back to no statusline" : "restored original statusLine.command"
351
+ };
340
352
  }
341
- var fs4, path4, import_node_os, LK_DIR, WRAPPER_PATH, CHIP_PATH, SETTINGS_PATH, ORIGINAL_KEY;
353
+ var fs4, path4, import_node_os, LK_DIR, WRAPPER_PATH, CHIP_PATH, BASE_PATH, SETTINGS_PATH, ORIGINAL_KEY;
342
354
  var init_statusline_install = __esm({
343
355
  "src/server/statusline-install.ts"() {
344
356
  "use strict";
@@ -348,6 +360,7 @@ var init_statusline_install = __esm({
348
360
  LK_DIR = path4.join((0, import_node_os.homedir)(), ".launchsecure");
349
361
  WRAPPER_PATH = path4.join(LK_DIR, "statusline-wrapper.sh");
350
362
  CHIP_PATH = path4.join(LK_DIR, "statusline-mcp.sh");
363
+ BASE_PATH = path4.join(LK_DIR, "statusline-base.sh");
351
364
  SETTINGS_PATH = path4.join((0, import_node_os.homedir)(), ".claude", "settings.json");
352
365
  ORIGINAL_KEY = "_launchKitStatuslineOriginal";
353
366
  }
@@ -857,7 +870,13 @@ async function ensureAccessIdp(input) {
857
870
  return created.result.id;
858
871
  }
859
872
  async function ensureAccessApp(input) {
860
- const policy = {
873
+ const { service } = input;
874
+ const appDomain = service.path ? `${service.hostname}${service.path}` : service.hostname;
875
+ const policy = service.bypass ? {
876
+ name: "launch-kit-public-bypass",
877
+ decision: "bypass",
878
+ include: [{ everyone: {} }]
879
+ } : {
861
880
  name: "launch-kit-org-allow",
862
881
  decision: "allow",
863
882
  include: [
@@ -870,12 +889,17 @@ async function ensureAccessApp(input) {
870
889
  }
871
890
  ]
872
891
  };
873
- const body = {
874
- name: `launch-kit ${input.service.hostname}`,
875
- domain: input.service.hostname,
892
+ const body = service.bypass ? {
893
+ name: `launch-kit ${appDomain} (public)`,
894
+ domain: appDomain,
895
+ type: "self_hosted",
896
+ policies: [policy]
897
+ } : {
898
+ name: `launch-kit ${appDomain}`,
899
+ domain: appDomain,
876
900
  type: "self_hosted",
877
901
  // Bot terminal = RCE surface → short session. Read portals = a workday.
878
- session_duration: input.service.strict ? "30m" : "24h",
902
+ session_duration: service.strict ? "30m" : "24h",
879
903
  allowed_idps: [input.idpId],
880
904
  auto_redirect_to_identity: true,
881
905
  policies: [policy]
@@ -886,7 +910,7 @@ async function ensureAccessApp(input) {
886
910
  path: `/accounts/${input.accountId}/access/apps`
887
911
  });
888
912
  if (!list.success) fail(list, "list access apps");
889
- const existing = (list.result ?? []).find((a) => a.domain === input.service.hostname);
913
+ const existing = (list.result ?? []).find((a) => a.domain === appDomain);
890
914
  if (existing) {
891
915
  const upd = await cf2({
892
916
  apiToken: input.apiToken,
@@ -894,7 +918,7 @@ async function ensureAccessApp(input) {
894
918
  path: `/accounts/${input.accountId}/access/apps/${existing.id}`,
895
919
  body
896
920
  });
897
- if (!upd.success || !upd.result) fail(upd, `update access app ${input.service.hostname}`);
921
+ if (!upd.success || !upd.result) fail(upd, `update access app ${appDomain}`);
898
922
  return upd.result.id;
899
923
  }
900
924
  const created = await cf2({
@@ -903,7 +927,7 @@ async function ensureAccessApp(input) {
903
927
  path: `/accounts/${input.accountId}/access/apps`,
904
928
  body
905
929
  });
906
- if (!created.success || !created.result) fail(created, `create access app ${input.service.hostname}`);
930
+ if (!created.success || !created.result) fail(created, `create access app ${appDomain}`);
907
931
  return created.result.id;
908
932
  }
909
933
  async function provisionAccess(input) {
@@ -922,7 +946,8 @@ async function provisionAccess(input) {
922
946
  saveState2(input.stateFile, { idpId, accountId: input.accountId });
923
947
  const appIds = {};
924
948
  for (const service of input.services) {
925
- appIds[service.hostname] = await ensureAccessApp({
949
+ const appDomain = service.path ? `${service.hostname}${service.path}` : service.hostname;
950
+ appIds[appDomain] = await ensureAccessApp({
926
951
  apiToken: input.apiToken,
927
952
  accountId: input.accountId,
928
953
  idpId,
@@ -943,6 +968,15 @@ var init_cf_access = __esm({
943
968
  }
944
969
  });
945
970
 
971
+ // src/server/radar/registration.ts
972
+ var RECEIVER_PATH;
973
+ var init_registration = __esm({
974
+ "src/server/radar/registration.ts"() {
975
+ "use strict";
976
+ RECEIVER_PATH = "/api/radar/ingest";
977
+ }
978
+ });
979
+
946
980
  // src/server/radar-docker-init-entry.ts
947
981
  var radar_docker_init_entry_exports = {};
948
982
  __export(radar_docker_init_entry_exports, {
@@ -1195,20 +1229,31 @@ async function maybeProvisionAccess(bundle, ingress) {
1195
1229
  const skipped = [];
1196
1230
  for (const [name, hostname] of Object.entries(ingress.hostnames)) {
1197
1231
  const cfg = GATED_SERVICES[name];
1198
- if (cfg) services.push({ hostname, strict: cfg.strict });
1199
- else skipped.push(name);
1232
+ if (!cfg) {
1233
+ skipped.push(name);
1234
+ continue;
1235
+ }
1236
+ services.push({ hostname, strict: cfg.strict });
1237
+ for (const path6 of cfg.publicPaths ?? []) {
1238
+ services.push({ hostname, path: path6, bypass: true });
1239
+ }
1200
1240
  }
1201
1241
  if (skipped.length > 0) {
1202
1242
  console.log(`[entrypoint] CF Access: leaving machine surface(s) ungated: ${skipped.join(", ")}`);
1203
1243
  }
1204
1244
  if (services.length === 0) {
1205
- console.log("[entrypoint] CF Access: no human-facing service to gate (bot/preview not provisioned)");
1245
+ console.log("[entrypoint] CF Access: no human-facing service to gate (bot/preview/radar/deck not provisioned)");
1206
1246
  return;
1207
1247
  }
1208
1248
  const serverUrl = process.env.LS_SERVER_URL ?? "https://launchsecure-v2.vercel.app";
1209
1249
  const pat = requireEnv("LS_PAT");
1210
1250
  const stateFile = "/workspace/.launchpod/launch-kit-access.json";
1211
- console.log(`[entrypoint] gating ${services.map((s) => s.hostname).join(", ")} behind CF Access (IdP: ${serverUrl})`);
1251
+ const gatedHosts = services.filter((s) => !s.bypass).map((s) => s.hostname);
1252
+ const bypassed = services.filter((s) => s.bypass).map((s) => `${s.hostname}${s.path ?? ""}`);
1253
+ console.log(`[entrypoint] gating ${gatedHosts.join(", ")} behind CF Access (IdP: ${serverUrl})`);
1254
+ if (bypassed.length > 0) {
1255
+ console.log(`[entrypoint] CF Access: public bypass for ${bypassed.join(", ")}`);
1256
+ }
1212
1257
  const result = await provisionAccess({
1213
1258
  apiToken: token,
1214
1259
  accountId,
@@ -1364,6 +1409,7 @@ var init_radar_docker_init_entry = __esm({
1364
1409
  init_launch_kit_services();
1365
1410
  init_cf_ingress();
1366
1411
  init_cf_access();
1412
+ init_registration();
1367
1413
  REQUIRED_ENV = [
1368
1414
  "CLAUDE_CREDENTIALS_B64",
1369
1415
  "LS_PAT",
@@ -1378,7 +1424,11 @@ var init_radar_docker_init_entry = __esm({
1378
1424
  // Claude web terminal — live drivable shell ⇒ RCE surface ⇒ short session.
1379
1425
  bot: { strict: true },
1380
1426
  // The user's own dev/preview server — a workday-length session is fine.
1381
- preview: { strict: false }
1427
+ preview: { strict: false },
1428
+ // Radar: gate the UI, bypass the (HMAC-verified) webhook receiver path.
1429
+ radar: { strict: false, publicPaths: [RECEIVER_PATH] },
1430
+ // Deck: gate the whole host — its push is localhost-only, never hits the edge.
1431
+ deck: { strict: false }
1382
1432
  };
1383
1433
  if (!process.env.VITEST) {
1384
1434
  main().catch((err) => {
@@ -1584,6 +1634,7 @@ var ALL_STEP_IDS = [
1584
1634
  "migrate-safety",
1585
1635
  "ls-marketplace",
1586
1636
  "recall-hook",
1637
+ "project-info",
1587
1638
  "statusline"
1588
1639
  ];
1589
1640
  var PRESETS = {
@@ -1591,6 +1642,7 @@ var PRESETS = {
1591
1642
  refresh: ["resolve", "clone", "install", "onboard", "recall"]
1592
1643
  };
1593
1644
  var LAUNCH_KIT_PKG = "@launchsecure/launch-kit";
1645
+ var LAUNCH_KIT_PKG_LATEST = `${LAUNCH_KIT_PKG}@latest`;
1594
1646
  var LAUNCH_KIT_TOOLS_GUIDE_STATIC_HEAD = `
1595
1647
  Wired in Claude Code (.mcp.json):
1596
1648
  launch-secure \u2014 LS API: work items, comms, secrets, members, board
@@ -1661,6 +1713,7 @@ var KNOWN_BOOL_FLAGS = /* @__PURE__ */ new Set([
1661
1713
  "--no-migrate-safety",
1662
1714
  "--no-ls-marketplace",
1663
1715
  "--no-recall-hook",
1716
+ "--no-project-info",
1664
1717
  "--refresh-scaffolds",
1665
1718
  "--quiet",
1666
1719
  "--force",
@@ -1694,6 +1747,7 @@ function parseArgs(argv) {
1694
1747
  noMigrateSafety: false,
1695
1748
  noLsMarketplace: false,
1696
1749
  noRecallHook: false,
1750
+ noProjectInfo: false,
1697
1751
  refreshScaffolds: false,
1698
1752
  quiet: false,
1699
1753
  force: false,
@@ -1738,6 +1792,10 @@ function parseArgs(argv) {
1738
1792
  args.noRecallHook = true;
1739
1793
  continue;
1740
1794
  }
1795
+ if (raw === "--no-project-info") {
1796
+ args.noProjectInfo = true;
1797
+ continue;
1798
+ }
1741
1799
  if (raw === "--refresh-scaffolds") {
1742
1800
  args.refreshScaffolds = true;
1743
1801
  continue;
@@ -1872,6 +1930,8 @@ Options:
1872
1930
  --no-migrate-safety Skip refreshing the migrate-safety scaffold.
1873
1931
  --no-ls-marketplace Skip refreshing the launch-secure marketplace.
1874
1932
  --no-recall-hook Skip refreshing the recall-hook scaffold.
1933
+ --no-project-info Skip wiring the gitignored CLAUDE.md-imported
1934
+ project-info snapshot (/kit:project-info refreshes it).
1875
1935
  --refresh-scaffolds Force-overwrite migrate-safety files (default is to
1876
1936
  preserve user edits). Use this to pull updates
1877
1937
  published to @launchsecure/launch-kit.
@@ -1907,8 +1967,8 @@ Subcommands:
1907
1967
  Env resolved from --env \u2192 $LS_ENV \u2192 server-side project default \u2192
1908
1968
  single-env auto-pick. See \`launch-kit secrets --help\`.
1909
1969
  statusline activate Wrap ~/.claude/settings.json's statusLine.command so MCP daemon
1910
- chips (recall, chart, deck, council) get appended. Refuses to
1911
- create one if none exists \u2014 additive only.
1970
+ chips (recall, chart, deck, council) get appended. If no
1971
+ statusline exists, scaffolds Claude Code's default base line first.
1912
1972
  statusline deactivate Restore the original statusLine.command and remove kit scripts.
1913
1973
 
1914
1974
  Usage:
@@ -1979,7 +2039,7 @@ Options:
1979
2039
 
1980
2040
  Step selection (one-command flow \u2014 compose over the preset):
1981
2041
  Steps: resolve, clone, cred, mcp, gitignore, install, onboard, recall,
1982
- migrate-safety, ls-marketplace, recall-hook, statusline
2042
+ migrate-safety, ls-marketplace, recall-hook, project-info, statusline
1983
2043
  --preset=<name> init (everything) or refresh (skips resolve/clone/
1984
2044
  install/onboard/recall). Default: init. \`init\` and
1985
2045
  \`refresh\` subcommands just select this.
@@ -2285,19 +2345,19 @@ function buildLaunchKitMcpEntries(cfg) {
2285
2345
  },
2286
2346
  "launch-chart": {
2287
2347
  command: "npx",
2288
- args: ["-y", "-p", LAUNCH_KIT_PKG, "launch-chart"]
2348
+ args: ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-chart"]
2289
2349
  },
2290
2350
  "launch-deck": {
2291
2351
  command: "npx",
2292
- args: ["-y", "-p", LAUNCH_KIT_PKG, "launch-deck"]
2352
+ args: ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-deck"]
2293
2353
  },
2294
2354
  "launch-orbit": {
2295
2355
  command: "npx",
2296
- args: ["-y", "-p", LAUNCH_KIT_PKG, "launch-orbit", "mcp"]
2356
+ args: ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-orbit", "mcp"]
2297
2357
  },
2298
2358
  "launch-recall": {
2299
2359
  command: "npx",
2300
- args: ["-y", "-p", LAUNCH_KIT_PKG, "launch-recall", "mcp"]
2360
+ args: ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-recall", "mcp"]
2301
2361
  }
2302
2362
  };
2303
2363
  }
@@ -2317,6 +2377,18 @@ function mergeMcpEntry(existing, ours) {
2317
2377
  }
2318
2378
  return merged;
2319
2379
  }
2380
+ function pinLaunchKitLatest(servers) {
2381
+ const fixed = [];
2382
+ for (const [name, entry] of Object.entries(servers)) {
2383
+ if (entry.command !== "npx" || !Array.isArray(entry.args)) continue;
2384
+ const i = entry.args.indexOf(LAUNCH_KIT_PKG);
2385
+ if (i !== -1) {
2386
+ entry.args[i] = LAUNCH_KIT_PKG_LATEST;
2387
+ fixed.push(name);
2388
+ }
2389
+ }
2390
+ return fixed;
2391
+ }
2320
2392
  function mergeMcpFile(targetDir, launchKitEntries) {
2321
2393
  const p = path5.join(targetDir, ".mcp.json");
2322
2394
  const hadExisting = fs5.existsSync(p);
@@ -2342,12 +2414,14 @@ function mergeMcpFile(targetDir, launchKitEntries) {
2342
2414
  merged.mcpServers[name] = entry;
2343
2415
  }
2344
2416
  }
2417
+ const pinned = pinLaunchKitLatest(merged.mcpServers);
2345
2418
  if (DRY_RUN) {
2346
2419
  const action = hadExisting && existingServerCount > 0 ? "would merge into" : "would write";
2347
- dryNote(`${action} .mcp.json \u2014 overwriting [${overwrites.join(", ") || "none"}], adding [${additions.join(", ") || "none"}]`);
2420
+ dryNote(`${action} .mcp.json \u2014 overwriting [${overwrites.join(", ") || "none"}], adding [${additions.join(", ") || "none"}], pinning @latest on [${pinned.join(", ") || "none"}]`);
2348
2421
  return { status: "skipped", summary: "(dry-run)" };
2349
2422
  }
2350
2423
  fs5.writeFileSync(p, JSON.stringify(merged, null, 2) + "\n", "utf-8");
2424
+ if (pinned.length > 0) info(`pinned @latest on ${pinned.length} launch-kit MCP entr${pinned.length === 1 ? "y" : "ies"}: ${pinned.join(", ")}`);
2351
2425
  const verb = hadExisting && existingServerCount > 0 ? "merged" : "wrote";
2352
2426
  ok(`${verb === "merged" ? "merged into" : "wrote"} .mcp.json (${Object.keys(launchKitEntries).length} launch-kit entries)`);
2353
2427
  const total = Object.keys(launchKitEntries).length;
@@ -2433,14 +2507,14 @@ function runRecallInit(repoDir) {
2433
2507
  const recallEntry = path5.resolve(__dirname, "recall-entry.js");
2434
2508
  const useSibling = fs5.existsSync(recallEntry);
2435
2509
  const cmd = useSibling ? process.execPath : "npx";
2436
- const args = useSibling ? [recallEntry, "init"] : ["-y", "-p", LAUNCH_KIT_PKG, "launch-recall", "init"];
2510
+ const args = useSibling ? [recallEntry, "init"] : ["-y", "-p", LAUNCH_KIT_PKG_LATEST, "launch-recall", "init"];
2437
2511
  if (DRY_RUN) {
2438
2512
  dryNote(`would run launch-recall init: ${cmd} ${args.join(" ")} (cwd: ${repoDir})`);
2439
2513
  return;
2440
2514
  }
2441
2515
  const res = (0, import_node_child_process3.spawnSync)(cmd, args, { cwd: repoDir, stdio: "inherit" });
2442
2516
  if (res.status !== 0) {
2443
- info(`\u26A0 launch-recall init failed (exit ${res.status}). Main onboarding is complete \u2014 you can retry later: cd ${path5.basename(repoDir)} && npx -y -p ${LAUNCH_KIT_PKG} launch-recall init`);
2517
+ info(`\u26A0 launch-recall init failed (exit ${res.status}). Main onboarding is complete \u2014 you can retry later: cd ${path5.basename(repoDir)} && npx -y -p ${LAUNCH_KIT_PKG_LATEST} launch-recall init`);
2444
2518
  return;
2445
2519
  }
2446
2520
  ok(`launch-recall ready (shadow git initialized)`);
@@ -2731,7 +2805,7 @@ function wireRecallHook(targetDir) {
2731
2805
  }
2732
2806
  function tryActivateStatusline() {
2733
2807
  if (DRY_RUN) {
2734
- dryNote(`would wrap ~/.claude/settings.json statusLine.command with launch-kit's MCP chip wrapper (skips silently if no statusline configured)`);
2808
+ dryNote(`would wrap ~/.claude/settings.json statusLine.command with launch-kit's MCP chip wrapper (scaffolds Claude Code's default base line first if none is configured)`);
2735
2809
  return { status: "skipped", summary: "(dry-run)" };
2736
2810
  }
2737
2811
  const res = activateStatusline();
@@ -2739,6 +2813,10 @@ function tryActivateStatusline() {
2739
2813
  ok(`statusline wrapped \u2014 MCP chips will render alongside your existing statusline next session`);
2740
2814
  return { status: "ok", summary: "wrapped \u2014 MCP chips render next session" };
2741
2815
  }
2816
+ if (res.ok && res.outcome === "scaffolded") {
2817
+ ok(`no statusline found \u2014 scaffolded Claude Code's default base line; MCP chips render alongside it next session`);
2818
+ return { status: "ok", summary: "scaffolded default base line + chips" };
2819
+ }
2742
2820
  if (res.ok && res.outcome === "refreshed") {
2743
2821
  info(`statusline already wrapped \u2014 refreshed chip scripts`);
2744
2822
  return { status: "ok", summary: "chip scripts refreshed" };
@@ -2797,8 +2875,8 @@ async function main2() {
2797
2875
  if (action === "activate") res = activateStatusline2({ show: showArg, compact: compactArg });
2798
2876
  else if (action === "deactivate") res = deactivateStatusline2();
2799
2877
  else fail3(`Unknown statusline action: "${action}". Supported: activate, deactivate.`);
2800
- if (res.ok) ok(`statusline ${res.outcome} \u2014 ${res.message}`);
2801
- else info(`statusline ${res.outcome} \u2014 ${res.message}`);
2878
+ const mark = res.ok ? "\u2713" : "\u2717";
2879
+ console.log(`[launch-kit] ${mark} statusline ${res.outcome} \u2014 ${res.message}`);
2802
2880
  return;
2803
2881
  }
2804
2882
  if (subcommand === "secrets") {
@@ -2876,6 +2954,7 @@ function resolveEnabledSteps(args) {
2876
2954
  if (args.noMigrateSafety) enabled.delete("migrate-safety");
2877
2955
  if (args.noLsMarketplace) enabled.delete("ls-marketplace");
2878
2956
  if (args.noRecallHook) enabled.delete("recall-hook");
2957
+ if (args.noProjectInfo) enabled.delete("project-info");
2879
2958
  return enabled;
2880
2959
  }
2881
2960
  async function stepResolve(ctx) {
@@ -3105,6 +3184,90 @@ function stepStatusline(_ctx) {
3105
3184
  const slR = tryActivateStatusline();
3106
3185
  if (slR) phase("statusline", slR);
3107
3186
  }
3187
+ var PROJECT_INFO_REL = ".claude/launch-kit/project-info.md";
3188
+ function ensureClaudeMdImport(targetDir) {
3189
+ const p = path5.join(targetDir, "CLAUDE.md");
3190
+ const importLine = `@${PROJECT_INFO_REL}`;
3191
+ const block = `<!-- launch-kit:project-info \u2014 generated import; safe to move, keep the line -->
3192
+ ${importLine}
3193
+ <!-- /launch-kit:project-info -->
3194
+ `;
3195
+ if (fs5.existsSync(p)) {
3196
+ const content = fs5.readFileSync(p, "utf-8");
3197
+ if (content.includes(importLine)) return "in-sync";
3198
+ if (DRY_RUN) {
3199
+ dryNote(`would add ${importLine} import to CLAUDE.md`);
3200
+ return "added";
3201
+ }
3202
+ fs5.writeFileSync(p, content + (content.endsWith("\n") ? "" : "\n") + "\n" + block, "utf-8");
3203
+ return "added";
3204
+ }
3205
+ if (DRY_RUN) {
3206
+ dryNote(`would create CLAUDE.md with ${importLine} import`);
3207
+ return "created";
3208
+ }
3209
+ fs5.writeFileSync(p, `# CLAUDE.md
3210
+
3211
+ ${block}`, "utf-8");
3212
+ return "created";
3213
+ }
3214
+ function renderProjectInfoSkeleton(ctx) {
3215
+ const cfg = ctx.cfg;
3216
+ const projectName = ctx.resolved?.projectName ?? cfg.projectSlug;
3217
+ const repo = ctx.resolved?.repositoryUrl ?? "\u2014";
3218
+ const todo = "_Not populated yet \u2014 run `/kit:project-info` in Claude Code._";
3219
+ return [
3220
+ `# Project Info \u2014 ${projectName}`,
3221
+ ``,
3222
+ `<!-- launch-kit:generated \u2014 local, git-ignored snapshot. NOT a source of truth. -->`,
3223
+ `> Wired by \`launch-kit\` init. This is a **local, git-ignored snapshot** of`,
3224
+ `> project facts so Claude doesn't re-query them every session. Members,`,
3225
+ `> providers, and environments are filled from LaunchSecure by the`,
3226
+ `> \`/kit:project-info\` skill \u2014 run it to populate or refresh. Treat as a`,
3227
+ `> cache: it can go stale, so re-run after team/provider/env changes.`,
3228
+ ``,
3229
+ `## Identity`,
3230
+ `- **Org:** ${cfg.orgSlug}`,
3231
+ `- **Project:** ${projectName} (\`${cfg.projectSlug}\`)`,
3232
+ `- **Server:** ${cfg.serverUrl}`,
3233
+ `- **Course:** ${ctx.courseName ?? "\u2014"}`,
3234
+ `- **Repo:** ${repo}`,
3235
+ ``,
3236
+ `## Members`,
3237
+ todo,
3238
+ ``,
3239
+ `## Providers / integrations`,
3240
+ todo,
3241
+ ``,
3242
+ `## Environments`,
3243
+ todo,
3244
+ ``
3245
+ ].join("\n");
3246
+ }
3247
+ function stepProjectInfo(ctx) {
3248
+ if (!ctx.cfg) {
3249
+ phase("project-info", { status: "skipped", summary: "no cred resolved" });
3250
+ return;
3251
+ }
3252
+ ensureGitignoreLine(ctx.targetDir, PROJECT_INFO_REL);
3253
+ const importResult = ensureClaudeMdImport(ctx.targetDir);
3254
+ const dest = path5.join(ctx.targetDir, PROJECT_INFO_REL);
3255
+ const existed = fs5.existsSync(dest);
3256
+ if (!existed) {
3257
+ if (DRY_RUN) {
3258
+ dryNote(`would write ${PROJECT_INFO_REL} identity skeleton`);
3259
+ } else {
3260
+ fs5.mkdirSync(path5.dirname(dest), { recursive: true });
3261
+ fs5.writeFileSync(dest, renderProjectInfoSkeleton(ctx), "utf-8");
3262
+ ok(`wrote ${PROJECT_INFO_REL}`);
3263
+ }
3264
+ }
3265
+ const summary = existed ? `kept file \xB7 CLAUDE.md ${importResult} \xB7 /kit:project-info to refresh` : `wrote skeleton \xB7 CLAUDE.md ${importResult} \xB7 /kit:project-info to populate`;
3266
+ phase("project-info", {
3267
+ status: existed && importResult === "in-sync" ? "in-sync" : "ok",
3268
+ summary
3269
+ });
3270
+ }
3108
3271
  var STEPS = [
3109
3272
  { id: "resolve", run: stepResolve },
3110
3273
  { id: "clone", requires: ["resolve"], run: stepClone },
@@ -3117,6 +3280,7 @@ var STEPS = [
3117
3280
  { id: "migrate-safety", run: stepMigrateSafety },
3118
3281
  { id: "ls-marketplace", run: stepLsMarketplace },
3119
3282
  { id: "recall-hook", run: stepRecallHook },
3283
+ { id: "project-info", requires: ["cred"], run: stepProjectInfo },
3120
3284
  { id: "statusline", run: stepStatusline }
3121
3285
  ];
3122
3286
  function buildCtx(args, enabled) {
@@ -520,7 +520,13 @@ async function ensureAccessIdp(input) {
520
520
  return created.result.id;
521
521
  }
522
522
  async function ensureAccessApp(input) {
523
- const policy = {
523
+ const { service } = input;
524
+ const appDomain = service.path ? `${service.hostname}${service.path}` : service.hostname;
525
+ const policy = service.bypass ? {
526
+ name: "launch-kit-public-bypass",
527
+ decision: "bypass",
528
+ include: [{ everyone: {} }]
529
+ } : {
524
530
  name: "launch-kit-org-allow",
525
531
  decision: "allow",
526
532
  include: [
@@ -533,12 +539,17 @@ async function ensureAccessApp(input) {
533
539
  }
534
540
  ]
535
541
  };
536
- const body = {
537
- name: `launch-kit ${input.service.hostname}`,
538
- domain: input.service.hostname,
542
+ const body = service.bypass ? {
543
+ name: `launch-kit ${appDomain} (public)`,
544
+ domain: appDomain,
545
+ type: "self_hosted",
546
+ policies: [policy]
547
+ } : {
548
+ name: `launch-kit ${appDomain}`,
549
+ domain: appDomain,
539
550
  type: "self_hosted",
540
551
  // Bot terminal = RCE surface → short session. Read portals = a workday.
541
- session_duration: input.service.strict ? "30m" : "24h",
552
+ session_duration: service.strict ? "30m" : "24h",
542
553
  allowed_idps: [input.idpId],
543
554
  auto_redirect_to_identity: true,
544
555
  policies: [policy]
@@ -549,7 +560,7 @@ async function ensureAccessApp(input) {
549
560
  path: `/accounts/${input.accountId}/access/apps`
550
561
  });
551
562
  if (!list.success) fail(list, "list access apps");
552
- const existing = (list.result ?? []).find((a) => a.domain === input.service.hostname);
563
+ const existing = (list.result ?? []).find((a) => a.domain === appDomain);
553
564
  if (existing) {
554
565
  const upd = await cf2({
555
566
  apiToken: input.apiToken,
@@ -557,7 +568,7 @@ async function ensureAccessApp(input) {
557
568
  path: `/accounts/${input.accountId}/access/apps/${existing.id}`,
558
569
  body
559
570
  });
560
- if (!upd.success || !upd.result) fail(upd, `update access app ${input.service.hostname}`);
571
+ if (!upd.success || !upd.result) fail(upd, `update access app ${appDomain}`);
561
572
  return upd.result.id;
562
573
  }
563
574
  const created = await cf2({
@@ -566,7 +577,7 @@ async function ensureAccessApp(input) {
566
577
  path: `/accounts/${input.accountId}/access/apps`,
567
578
  body
568
579
  });
569
- if (!created.success || !created.result) fail(created, `create access app ${input.service.hostname}`);
580
+ if (!created.success || !created.result) fail(created, `create access app ${appDomain}`);
570
581
  return created.result.id;
571
582
  }
572
583
  async function provisionAccess(input) {
@@ -585,7 +596,8 @@ async function provisionAccess(input) {
585
596
  saveState2(input.stateFile, { idpId, accountId: input.accountId });
586
597
  const appIds = {};
587
598
  for (const service of input.services) {
588
- appIds[service.hostname] = await ensureAccessApp({
599
+ const appDomain = service.path ? `${service.hostname}${service.path}` : service.hostname;
600
+ appIds[appDomain] = await ensureAccessApp({
589
601
  apiToken: input.apiToken,
590
602
  accountId: input.accountId,
591
603
  idpId,
@@ -596,6 +608,9 @@ async function provisionAccess(input) {
596
608
  return { idpId, authDomain, appIds };
597
609
  }
598
610
 
611
+ // src/server/radar/registration.ts
612
+ var RECEIVER_PATH = "/api/radar/ingest";
613
+
599
614
  // src/server/radar-docker-init-entry.ts
600
615
  var REQUIRED_ENV = [
601
616
  "CLAUDE_CREDENTIALS_B64",
@@ -831,7 +846,11 @@ var GATED_SERVICES = {
831
846
  // Claude web terminal — live drivable shell ⇒ RCE surface ⇒ short session.
832
847
  bot: { strict: true },
833
848
  // The user's own dev/preview server — a workday-length session is fine.
834
- preview: { strict: false }
849
+ preview: { strict: false },
850
+ // Radar: gate the UI, bypass the (HMAC-verified) webhook receiver path.
851
+ radar: { strict: false, publicPaths: [RECEIVER_PATH] },
852
+ // Deck: gate the whole host — its push is localhost-only, never hits the edge.
853
+ deck: { strict: false }
835
854
  };
836
855
  async function registerOidcClient(serverUrl, pat, redirectUris) {
837
856
  const res = await fetch(new URL("/api/rover/oidc-client", serverUrl), {
@@ -858,20 +877,31 @@ async function maybeProvisionAccess(bundle, ingress) {
858
877
  const skipped = [];
859
878
  for (const [name, hostname] of Object.entries(ingress.hostnames)) {
860
879
  const cfg = GATED_SERVICES[name];
861
- if (cfg) services.push({ hostname, strict: cfg.strict });
862
- else skipped.push(name);
880
+ if (!cfg) {
881
+ skipped.push(name);
882
+ continue;
883
+ }
884
+ services.push({ hostname, strict: cfg.strict });
885
+ for (const path of cfg.publicPaths ?? []) {
886
+ services.push({ hostname, path, bypass: true });
887
+ }
863
888
  }
864
889
  if (skipped.length > 0) {
865
890
  console.log(`[entrypoint] CF Access: leaving machine surface(s) ungated: ${skipped.join(", ")}`);
866
891
  }
867
892
  if (services.length === 0) {
868
- console.log("[entrypoint] CF Access: no human-facing service to gate (bot/preview not provisioned)");
893
+ console.log("[entrypoint] CF Access: no human-facing service to gate (bot/preview/radar/deck not provisioned)");
869
894
  return;
870
895
  }
871
896
  const serverUrl = process.env.LS_SERVER_URL ?? "https://launchsecure-v2.vercel.app";
872
897
  const pat = requireEnv("LS_PAT");
873
898
  const stateFile = "/workspace/.launchpod/launch-kit-access.json";
874
- console.log(`[entrypoint] gating ${services.map((s) => s.hostname).join(", ")} behind CF Access (IdP: ${serverUrl})`);
899
+ const gatedHosts = services.filter((s) => !s.bypass).map((s) => s.hostname);
900
+ const bypassed = services.filter((s) => s.bypass).map((s) => `${s.hostname}${s.path ?? ""}`);
901
+ console.log(`[entrypoint] gating ${gatedHosts.join(", ")} behind CF Access (IdP: ${serverUrl})`);
902
+ if (bypassed.length > 0) {
903
+ console.log(`[entrypoint] CF Access: public bypass for ${bypassed.join(", ")}`);
904
+ }
875
905
  const result = await provisionAccess({
876
906
  apiToken: token,
877
907
  accountId,
File without changes
File without changes