sliccy 6.110.0 → 6.110.1

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 (95) hide show
  1. package/dist/node-server/_cloud_core/src/operations/start.d.ts.map +1 -1
  2. package/dist/node-server/_cloud_core/src/operations/start.js +152 -132
  3. package/dist/ui/.vite/manifest.json +118 -118
  4. package/dist/ui/assets/{account-store-DmTUzOwD.js → account-store-BoX1x9kV.js} +1 -1
  5. package/dist/ui/assets/{account-store-C3hpxUnj.js → account-store-C_RjQ1LW.js} +1 -1
  6. package/dist/ui/assets/{adobe-C6blUXjx.js → adobe-B23Ywr-q.js} +1 -1
  7. package/dist/ui/assets/{adobe-CeRHOrV3.js → adobe-Cl3gYIGk.js} +1 -1
  8. package/dist/ui/assets/{agent-bridge-BytMhrHG.js → agent-bridge-BX3wCp2Y.js} +1 -1
  9. package/dist/ui/assets/{agent-panels-CW3VQhe5.js → agent-panels-Wkk7jZv2.js} +1 -1
  10. package/dist/ui/assets/{apply-layout-C9oYfek3.js → apply-layout-DZhC7tvZ.js} +1 -1
  11. package/dist/ui/assets/{apps-buLjOZpb.js → apps-CSqm019X.js} +1 -1
  12. package/dist/ui/assets/{azure-openai-BQJFNoBY.js → azure-openai-3gNI8EZk.js} +1 -1
  13. package/dist/ui/assets/{azure-openai-BvVWJJJ0.js → azure-openai-BzdIKLVJ.js} +1 -1
  14. package/dist/ui/assets/cdp-ws-page-bridge-CtHmog_w.js +1 -0
  15. package/dist/ui/assets/{cerebras-CokNYO8b.js → cerebras-Cw0x8F55.js} +1 -1
  16. package/dist/ui/assets/{cerebras-BjJmr6-W.js → cerebras-DVQI1HLQ.js} +1 -1
  17. package/dist/ui/assets/{connect-surface-BHqqK_uZ.js → connect-surface-B6KSgq_q.js} +1 -1
  18. package/dist/ui/assets/{directed-approval-CGapNvBZ.js → directed-approval-CLrepWJZ.js} +1 -1
  19. package/dist/ui/assets/{fs-D9DlVz0g.js → fs-Bt1lzDEz.js} +2 -2
  20. package/dist/ui/assets/{fs-b7tPDGDe.js → fs-CYCQ52sl.js} +1 -1
  21. package/dist/ui/assets/{github-rMrWcSVm.js → github-BhDAxQAC.js} +1 -1
  22. package/dist/ui/assets/{github-CAYwnl-b.js → github-DT8CXDfD.js} +2 -2
  23. package/dist/ui/assets/{github-copilot-BaEPoc2l.js → github-copilot-C_oyd3zr.js} +1 -1
  24. package/dist/ui/assets/{github-copilot-BaohZB3G.js → github-copilot-q7k6_hj_.js} +1 -1
  25. package/dist/ui/assets/{github-install-9ynDwgiQ.js → github-install-DVOtkLLc.js} +1 -1
  26. package/dist/ui/assets/{github-zip-nBMk_5yk.js → github-zip-DxRjJbti.js} +1 -1
  27. package/dist/ui/assets/{js-realm-worker-adzmez5_.js → js-realm-worker-BuPGQg5c.js} +1 -1
  28. package/dist/ui/assets/{kernel-worker-DqzdssFu.js → kernel-worker-BzXcNm5v.js} +28 -28
  29. package/dist/ui/assets/{local-llm-CiMne0-B.js → local-llm-MgK32jpS.js} +1 -1
  30. package/dist/ui/assets/{local-llm--yLtHAZU.js → local-llm-ezgB4Rhv.js} +1 -1
  31. package/dist/ui/assets/{main-CfZo7HyV.js → main-yMuFUfUo.js} +3 -3
  32. package/dist/ui/assets/{mount-rYO-8m8f.js → mount-CWJVI6cG.js} +2 -2
  33. package/dist/ui/assets/{mount-CC0djJXQ.js → mount-Dk8U-SsK.js} +1 -1
  34. package/dist/ui/assets/{mount-recovery-CvuTQnTL.js → mount-recovery-BFldcrCy.js} +1 -1
  35. package/dist/ui/assets/{new-session-BS3W0s9e.js → new-session-CH8hv33Z.js} +2 -2
  36. package/dist/ui/assets/{oauth-bootstrap-DpG29VCH.js → oauth-bootstrap-DtE-wVk8.js} +2 -2
  37. package/dist/ui/assets/{onboarding-orchestrator-BI0_TR0Z.js → onboarding-orchestrator--AtamMOt.js} +1 -1
  38. package/dist/ui/assets/{openai-codex-C8aOD0t8.js → openai-codex-BkhAYOFq.js} +1 -1
  39. package/dist/ui/assets/{openai-codex-BJ4JLVfo.js → openai-codex-ChSC2_RF.js} +1 -1
  40. package/dist/ui/assets/{openrouter-DHg1gMnT.js → openrouter-C6uKRX2s.js} +1 -1
  41. package/dist/ui/assets/{openrouter-LCca2Pyd.js → openrouter-M3t6me37.js} +1 -1
  42. package/dist/ui/assets/{openrouter-oauth-CRVMrh7E.js → openrouter-oauth-CQ5d6KxV.js} +1 -1
  43. package/dist/ui/assets/{openrouter-oauth-DukR2YjX.js → openrouter-oauth-q9Eaddvv.js} +1 -1
  44. package/dist/ui/assets/{panel-rpc-handlers-p0z9KK9s.js → panel-rpc-handlers-9Kh_edB6.js} +2 -2
  45. package/dist/ui/assets/{panelize-shell-DRCqD-hf.js → panelize-shell-BYN8cWYS.js} +1 -1
  46. package/dist/ui/assets/{provider-CMYr90tG.js → provider-6nrOEzoy.js} +2 -2
  47. package/dist/ui/assets/{provider-8X1TXGOz.js → provider-D1aUL7cR.js} +1 -1
  48. package/dist/ui/assets/{provider-settings-BbKZBkmj.js → provider-settings-bw9IwZz9.js} +1 -1
  49. package/dist/ui/assets/provider-store-access-BZyxBZSe.js +1 -0
  50. package/dist/ui/assets/provider-store-access-DBsr55Oe.js +1 -0
  51. package/dist/ui/assets/{providers-DuNEVEmM.js → providers-Bx6tfN25.js} +1 -1
  52. package/dist/ui/assets/{providers-B3XsxeEV.js → providers-DIS-LHtN.js} +2 -2
  53. package/dist/ui/assets/{quick-llm-BQeXAXhA.js → quick-llm-BgZdJ8Xu.js} +1 -1
  54. package/dist/ui/assets/{recovery-screen-Dg10xiZK.js → recovery-screen-lA16kcIk.js} +1 -1
  55. package/dist/ui/assets/{run-74Dp3xqK.js → run-BF2Vs8sX.js} +1 -1
  56. package/dist/ui/assets/{setup-feature-flags-remote-BDXotdTe.js → setup-feature-flags-remote-Dhp6wfKf.js} +1 -1
  57. package/dist/ui/assets/sidecar-repair-DBuhkumN.js +1 -0
  58. package/dist/ui/assets/{skills-fw01LxeE.js → skills-FlCqTkA2.js} +1 -1
  59. package/dist/ui/assets/slicc-version-Bcm7uZDt.js +1 -0
  60. package/dist/ui/assets/{state-YABVHFPR.js → state-B-6hESFq.js} +1 -1
  61. package/dist/ui/assets/{store-DuMDTOYq.js → store-Bn1BVnep.js} +1 -1
  62. package/dist/ui/assets/{store--DLIZTf_.js → store-CH1Vdm3C.js} +1 -1
  63. package/dist/ui/assets/{sudo-Lv8DoXxd.js → sudo-BAmfGa0_.js} +1 -1
  64. package/dist/ui/assets/{sync-dialog-B8ssqjz4.js → sync-dialog-DvEMJqPI.js} +1 -1
  65. package/dist/ui/assets/{tray-sidecar-B1xCDlFe.js → tray-sidecar-CI7F7zk4.js} +1 -1
  66. package/dist/ui/assets/{upgrade-detection-TlqXRH1-.js → upgrade-detection-Du0Zc5Vc.js} +1 -1
  67. package/dist/ui/assets/{voice-reply-CGJnZqW1.js → voice-reply-y0SVuHxl.js} +1 -1
  68. package/dist/ui/assets/{wc-attach-DANq4_X7.js → wc-attach-DNpV2C1V.js} +2 -2
  69. package/dist/ui/assets/{wc-extension-BRZxL5Z1.js → wc-extension-CxkCsjca.js} +2 -2
  70. package/dist/ui/assets/{wc-float-label-KQOIpgnm.js → wc-float-label-DcJd5glS.js} +1 -1
  71. package/dist/ui/assets/{wc-floatbar-online-D1LOCURF.js → wc-floatbar-online-DLKzoxMg.js} +1 -1
  72. package/dist/ui/assets/{wc-follower-D7D0OBf3.js → wc-follower-XKpP_jYM.js} +3 -3
  73. package/dist/ui/assets/{wc-follower-oauth-DZllVzrT.js → wc-follower-oauth-B2VtgZnu.js} +1 -1
  74. package/dist/ui/assets/{wc-live-RnON2Ugk.js → wc-live-BAcY7vuX.js} +7 -7
  75. package/dist/ui/assets/{wc-nav-Clor2VFZ.js → wc-nav-ui1eVAgs.js} +2 -2
  76. package/dist/ui/assets/{wc-onboarding-BUmFCg_U.js → wc-onboarding-CzLSlGtO.js} +2 -2
  77. package/dist/ui/assets/{wc-placeholder-8Judy9cG.js → wc-placeholder-CJdgmCF_.js} +3 -3
  78. package/dist/ui/assets/{wc-settings-Bvx2BLQv.js → wc-settings-BVkI9WSG.js} +3 -3
  79. package/dist/ui/assets/{wc-shell-CsfCsd9q.js → wc-shell--0d7OBBA.js} +2 -2
  80. package/dist/ui/assets/{wc-shortcut-config-BK4O1f_G.js → wc-shortcut-config-DWtAxJBs.js} +1 -1
  81. package/dist/ui/assets/{wc-sprinkles-D65r5HD-.js → wc-sprinkles-BBuXTi5P.js} +2 -2
  82. package/dist/ui/assets/{wc-transcript-export-UUnE-lk6.js → wc-transcript-export-CzlJYgix.js} +2 -2
  83. package/dist/ui/assets/{wc-tray-CPQsc5Us.js → wc-tray-CgVmWqZy.js} +4 -4
  84. package/dist/ui/assets/welcome-detection-D_bN1hbs.js +1 -0
  85. package/dist/ui/assets/{xai-grok-IHkw5Jqa.js → xai-grok-Bnn0c_v-.js} +1 -1
  86. package/dist/ui/assets/{xai-grok-DoYWlKs_.js → xai-grok-CpbT74JL.js} +1 -1
  87. package/dist/ui/index.html +3 -3
  88. package/dist/ui/packages/webapp/index.html +3 -3
  89. package/package.json +2 -2
  90. package/dist/ui/assets/cdp-ws-page-bridge-DI26JBMr.js +0 -1
  91. package/dist/ui/assets/provider-store-access-D5VrJP0f.js +0 -1
  92. package/dist/ui/assets/provider-store-access-DxHrtPBD.js +0 -1
  93. package/dist/ui/assets/sidecar-repair-Mh9rQVbp.js +0 -1
  94. package/dist/ui/assets/slicc-version-DF86HAGG.js +0 -1
  95. package/dist/ui/assets/welcome-detection-D7QFjBKz.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/operations/start.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B;wEACoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC;IACrB;iEAC6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;qEACiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;2DACuD;IACvD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;0DACsD;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,GAAG,CAAC,EAAE;QACJ,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF;;;2CAGuC;IACvC,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC;CAC/B;AA6BD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAwDpC;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAyJ9F"}
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/operations/start.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B;wEACoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC;IACrB;iEAC6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC;qEACiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,uDAAuD;IACvD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;2DACuD;IACvD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;0DACsD;IACtD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,gBAAgB,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,oDAAoD;IACpD,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,GAAG,CAAC,EAAE;QACJ,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IACF;;;2CAGuC;IACvC,eAAe,CAAC,EAAE,SAAS,EAAE,CAAC;CAC/B;AA2DD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAmCpC;AA6ID,wBAAsB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CA0D9F"}
@@ -26,6 +26,34 @@ function parseCapLimit(name, raw) {
26
26
  }
27
27
  return n;
28
28
  }
29
+ function errMessage(err) {
30
+ return err instanceof Error ? err.message : String(err);
31
+ }
32
+ /** Enforce running/paused caps when env caps are provided. */
33
+ function enforceCaps(existing, env) {
34
+ const running = existing.filter((e) => e.state === 'running' || e.state === 'reserved').length;
35
+ const paused = existing.filter((e) => e.state === 'paused').length;
36
+ const runningCap = parseCapLimit('CONE_CAP_RUNNING', env.CONE_CAP_RUNNING);
37
+ const pausedCap = parseCapLimit('CONE_CAP_PAUSED', env.CONE_CAP_PAUSED);
38
+ if (running >= runningCap) {
39
+ throw new CloudError('CAP_EXCEEDED', `at running cap (${running}/${runningCap})`, {
40
+ running,
41
+ cap: runningCap,
42
+ });
43
+ }
44
+ if (paused >= pausedCap) {
45
+ throw new CloudError('CAP_EXCEEDED', `at paused cap (${paused}/${pausedCap})`, {
46
+ paused,
47
+ cap: pausedCap,
48
+ });
49
+ }
50
+ }
51
+ async function loadExistingCones(deps, opts) {
52
+ if (opts.reconciledCones)
53
+ return opts.reconciledCones;
54
+ const { listCones } = await import('./list.js');
55
+ return listCones(deps, opts.userId ? { metadata: { userId: opts.userId } } : {});
56
+ }
29
57
  /**
30
58
  * Reserve a slot in the registry atomically under DO lock, BEFORE substrate.create.
31
59
  * Returns a synthetic reservationId (pending-<uuid>) that counts toward the cap.
@@ -40,32 +68,10 @@ export async function reserveSlot(deps, opts) {
40
68
  // Read existing entries to enforce caps + name conflicts.
41
69
  // If caller provided a pre-reconciled list (worker DO path), use it directly.
42
70
  // Otherwise (CLI path), do a full reconciliation via listCones.
43
- let existing;
44
- if (opts.reconciledCones) {
45
- existing = opts.reconciledCones;
46
- }
47
- else {
48
- const { listCones } = await import('./list.js');
49
- existing = await listCones(deps, opts.userId ? { metadata: { userId: opts.userId } } : {});
50
- }
71
+ const existing = await loadExistingCones(deps, opts);
51
72
  // Cap check: count both running and reserved entries (reservations count as running)
52
73
  if (opts.env) {
53
- const running = existing.filter((e) => e.state === 'running' || e.state === 'reserved').length;
54
- const paused = existing.filter((e) => e.state === 'paused').length;
55
- const runningCap = parseCapLimit('CONE_CAP_RUNNING', opts.env.CONE_CAP_RUNNING);
56
- const pausedCap = parseCapLimit('CONE_CAP_PAUSED', opts.env.CONE_CAP_PAUSED);
57
- if (running >= runningCap) {
58
- throw new CloudError('CAP_EXCEEDED', `at running cap (${running}/${runningCap})`, {
59
- running,
60
- cap: runningCap,
61
- });
62
- }
63
- if (paused >= pausedCap) {
64
- throw new CloudError('CAP_EXCEEDED', `at paused cap (${paused}/${pausedCap})`, {
65
- paused,
66
- cap: pausedCap,
67
- });
68
- }
74
+ enforceCaps(existing, opts.env);
69
75
  }
70
76
  // Name conflict check
71
77
  const requestedName = opts.name?.trim();
@@ -87,6 +93,121 @@ export async function reserveSlot(deps, opts) {
87
93
  await deps.registry.append(placeholder);
88
94
  return { reservationId };
89
95
  }
96
+ function buildCreateEnvVars(opts, safeSecrets) {
97
+ return {
98
+ SLICC_TRAY_WORKER_BASE_URL: opts.workerBaseUrl,
99
+ SLICC_SECRETS_ENV_B64: encodeBundleEnv(safeSecrets),
100
+ ...(opts.coneConfigJson ? { SLICC_CONE_CONFIG_B64: encodeBundleEnv(opts.coneConfigJson) } : {}),
101
+ ...(opts.envs ?? {}),
102
+ };
103
+ }
104
+ function buildCreateMetadata(opts) {
105
+ return {
106
+ sliccVersion: opts.sliccVersion,
107
+ ...(opts.name ? { name: opts.name } : {}),
108
+ ...(opts.metadata ?? {}),
109
+ };
110
+ }
111
+ /**
112
+ * Swap a reservation for the real sandbox entry, or append a legacy placeholder.
113
+ * Returns the registry key that is now active (the real sandboxId).
114
+ *
115
+ * The placeholder ensures concurrent /list-cones calls see the cone in the registry
116
+ * (pass 1) instead of treating it as an orphan (pass 2). The empty joinUrl
117
+ * means the dashboard hides the Open button until pollCloudStatus completes
118
+ * and the entry is updated below. State is 'reserved' until poll completes.
119
+ */
120
+ async function registerStartPlaceholder(registry, substrateId, handle, opts, createdAt) {
121
+ if (opts.reservationId) {
122
+ // Remove the reservation entry and append the real one
123
+ await registry.remove(opts.reservationId);
124
+ const placeholder = {
125
+ substrate: substrateId,
126
+ sandboxId: handle.sandboxId,
127
+ name: opts.name,
128
+ createdAt,
129
+ lastSeen: createdAt,
130
+ state: 'reserved',
131
+ joinUrl: '',
132
+ metadata: opts.metadata,
133
+ };
134
+ await registry.append(placeholder);
135
+ }
136
+ else {
137
+ // Legacy path: no reservation, append directly
138
+ const placeholder = {
139
+ substrate: substrateId,
140
+ sandboxId: handle.sandboxId,
141
+ name: opts.name,
142
+ createdAt,
143
+ lastSeen: createdAt,
144
+ state: 'reserved',
145
+ joinUrl: '',
146
+ };
147
+ await registry.append(placeholder);
148
+ }
149
+ return handle.sandboxId;
150
+ }
151
+ /**
152
+ * Two-layer secrets bootstrap (see Plan B):
153
+ * 1. start.sh writes /slicc/secrets.env from $ADOBE_IMS_TOKEN if the file
154
+ * doesn't already exist (fallback for race-free worker path where env-vars
155
+ * arrive before this writeFile lands).
156
+ * 2. THIS writeFile uploads the full filtered secrets.env. Worker overwrites
157
+ * with Adobe-only content (effectively a no-op since start.sh already wrote
158
+ * the same token). CLI overwrites with non-Adobe secrets (GitHub PATs, S3
159
+ * keys, etc.), load-bearing for CLI-launched cones. The CLI race is benign
160
+ * because the page-side bootstrap polls /api/hosted-bootstrap after a 5s
161
+ * delay, by which time this writeFile has landed.
162
+ */
163
+ async function writeBootstrapFiles(handle, safeSecrets, coneConfigJson) {
164
+ await handle.writeFile('/slicc/secrets.env', safeSecrets);
165
+ if (coneConfigJson) {
166
+ await handle.writeFile('/slicc/cone-config.json', coneConfigJson);
167
+ }
168
+ }
169
+ async function pollStatusOrThrow(handle, opts, minUpdatedAt) {
170
+ try {
171
+ return await pollCloudStatus(handle, {
172
+ timeoutMs: opts.pollTimeoutMs ?? 60_000,
173
+ intervalMs: opts.pollIntervalMs ?? 500,
174
+ minUpdatedAt,
175
+ });
176
+ }
177
+ catch (pollErr) {
178
+ // Surface boot diagnostics before tearing down. Spec failure mode #7.
179
+ const stderr = await tailStderr(handle, 50);
180
+ throw new CloudError('SANDBOX_NOT_READY', `${errMessage(pollErr)}\n` + `--- last 50 lines of /tmp/slicc-stderr.log ---\n${stderr}`, { sandboxId: handle.sandboxId });
181
+ }
182
+ }
183
+ async function bestEffortCleanup(registry, activeRegistryId, handle) {
184
+ // Best-effort cleanup: remove whichever registry entry is currently active.
185
+ if (activeRegistryId) {
186
+ try {
187
+ await registry.remove(activeRegistryId);
188
+ }
189
+ catch (cleanupErr) {
190
+ console.warn('[cloud-core] start cleanup', {
191
+ phase: 'registry-remove',
192
+ sandboxId: activeRegistryId,
193
+ err: errMessage(cleanupErr),
194
+ });
195
+ }
196
+ }
197
+ // Always kill the real sandbox if it was created (handle exists at this point)
198
+ if (handle) {
199
+ try {
200
+ await handle.kill();
201
+ }
202
+ catch (cleanupErr) {
203
+ console.warn('[cloud-core] start cleanup', {
204
+ phase: 'handle-kill',
205
+ sandboxId: handle.sandboxId,
206
+ err: errMessage(cleanupErr),
207
+ });
208
+ }
209
+ }
210
+ }
90
211
  export async function startCone(deps, opts) {
91
212
  const safeSecrets = filterSecretsEnv(opts.envContents);
92
213
  // Track whichever registry entry is currently live, for cleanup on failure.
@@ -97,19 +218,8 @@ export async function startCone(deps, opts) {
97
218
  handle = await deps.substrate.create({
98
219
  template: opts.template ?? 'slicc',
99
220
  autoPauseOnCap: opts.autoPauseOnCap ?? true,
100
- envVars: {
101
- SLICC_TRAY_WORKER_BASE_URL: opts.workerBaseUrl,
102
- SLICC_SECRETS_ENV_B64: encodeBundleEnv(safeSecrets),
103
- ...(opts.coneConfigJson
104
- ? { SLICC_CONE_CONFIG_B64: encodeBundleEnv(opts.coneConfigJson) }
105
- : {}),
106
- ...(opts.envs ?? {}),
107
- },
108
- metadata: {
109
- sliccVersion: opts.sliccVersion,
110
- ...(opts.name ? { name: opts.name } : {}),
111
- ...(opts.metadata ?? {}),
112
- },
221
+ envVars: buildCreateEnvVars(opts, safeSecrets),
222
+ metadata: buildCreateMetadata(opts),
113
223
  name: opts.name,
114
224
  });
115
225
  // Capture freshness baseline AFTER sandbox creation: any /tmp/slicc-join.json
@@ -121,73 +231,10 @@ export async function startCone(deps, opts) {
121
231
  const minUpdatedAt = new Date(Date.now() - 5_000).toISOString();
122
232
  const createdAt = new Date().toISOString();
123
233
  // Update or append placeholder depending on whether we have a reservation.
124
- // If reservationId is provided, update it to the real sandboxId and remove the old entry.
125
- // Otherwise, append a new placeholder as before.
126
- //
127
- // The placeholder ensures concurrent /list-cones calls see the cone in the registry
128
- // (pass 1) instead of treating it as an orphan (pass 2). The empty joinUrl
129
- // means the dashboard hides the Open button until pollCloudStatus completes
130
- // and the entry is updated below. State is 'reserved' until poll completes.
131
- if (opts.reservationId) {
132
- // Remove the reservation entry and append the real one
133
- await deps.registry.remove(opts.reservationId);
134
- const placeholder = {
135
- substrate: deps.substrate.id,
136
- sandboxId: handle.sandboxId,
137
- name: opts.name,
138
- createdAt,
139
- lastSeen: createdAt,
140
- state: 'reserved',
141
- joinUrl: '',
142
- metadata: opts.metadata,
143
- };
144
- await deps.registry.append(placeholder);
145
- // After swapping, the real sandboxId is the active registry key.
146
- activeRegistryId = handle.sandboxId;
147
- }
148
- else {
149
- // Legacy path: no reservation, append directly
150
- const placeholder = {
151
- substrate: deps.substrate.id,
152
- sandboxId: handle.sandboxId,
153
- name: opts.name,
154
- createdAt,
155
- lastSeen: createdAt,
156
- state: 'reserved',
157
- joinUrl: '',
158
- };
159
- await deps.registry.append(placeholder);
160
- // The newly-appended sandboxId is the active registry key.
161
- activeRegistryId = handle.sandboxId;
162
- }
163
- // Two-layer secrets bootstrap (see Plan B):
164
- // 1. start.sh writes /slicc/secrets.env from $ADOBE_IMS_TOKEN if the file
165
- // doesn't already exist (fallback for race-free worker path where env-vars
166
- // arrive before this writeFile lands).
167
- // 2. THIS writeFile uploads the full filtered secrets.env. Worker overwrites
168
- // with Adobe-only content (effectively a no-op since start.sh already wrote
169
- // the same token). CLI overwrites with non-Adobe secrets (GitHub PATs, S3
170
- // keys, etc.), load-bearing for CLI-launched cones. The CLI race is benign
171
- // because the page-side bootstrap polls /api/hosted-bootstrap after a 5s
172
- // delay, by which time this writeFile has landed.
173
- await handle.writeFile('/slicc/secrets.env', safeSecrets);
174
- if (opts.coneConfigJson) {
175
- await handle.writeFile('/slicc/cone-config.json', opts.coneConfigJson);
176
- }
177
- let status;
178
- try {
179
- status = await pollCloudStatus(handle, {
180
- timeoutMs: opts.pollTimeoutMs ?? 60_000,
181
- intervalMs: opts.pollIntervalMs ?? 500,
182
- minUpdatedAt,
183
- });
184
- }
185
- catch (pollErr) {
186
- // Surface boot diagnostics before tearing down. Spec failure mode #7.
187
- const stderr = await tailStderr(handle, 50);
188
- throw new CloudError('SANDBOX_NOT_READY', `${pollErr instanceof Error ? pollErr.message : String(pollErr)}\n` +
189
- `--- last 50 lines of /tmp/slicc-stderr.log ---\n${stderr}`, { sandboxId: handle.sandboxId });
190
- }
234
+ // After swapping/appending, the real sandboxId is the active registry key.
235
+ activeRegistryId = await registerStartPlaceholder(deps.registry, deps.substrate.id, handle, opts, createdAt);
236
+ await writeBootstrapFiles(handle, safeSecrets, opts.coneConfigJson);
237
+ const status = await pollStatusOrThrow(handle, opts, minUpdatedAt);
191
238
  // Promote the placeholder to a fully-populated running entry.
192
239
  await deps.registry.update(handle.sandboxId, {
193
240
  state: 'running',
@@ -203,34 +250,7 @@ export async function startCone(deps, opts) {
203
250
  };
204
251
  }
205
252
  catch (err) {
206
- // Best-effort cleanup: remove whichever registry entry is currently active.
207
- if (activeRegistryId) {
208
- try {
209
- await deps.registry.remove(activeRegistryId);
210
- }
211
- catch (cleanupErr) {
212
- const msg = cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr);
213
- console.warn('[cloud-core] start cleanup', {
214
- phase: 'registry-remove',
215
- sandboxId: activeRegistryId,
216
- err: msg,
217
- });
218
- }
219
- }
220
- // Always kill the real sandbox if it was created (handle exists at this point)
221
- if (handle) {
222
- try {
223
- await handle.kill();
224
- }
225
- catch (cleanupErr) {
226
- const msg = cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr);
227
- console.warn('[cloud-core] start cleanup', {
228
- phase: 'handle-kill',
229
- sandboxId: handle.sandboxId,
230
- err: msg,
231
- });
232
- }
233
- }
253
+ await bestEffortCleanup(deps.registry, activeRegistryId, handle);
234
254
  throw err;
235
255
  }
236
256
  }