sliccy 6.256.7 → 6.256.8

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 (145) hide show
  1. package/dist/node-server/_cloud_core/src/cone-config/cone-config-rules.d.mts +89 -0
  2. package/dist/node-server/_cloud_core/src/cone-config/cone-config-rules.d.mts.map +1 -0
  3. package/dist/node-server/_cloud_core/src/cone-config/cone-config-rules.mjs +170 -0
  4. package/dist/node-server/_cloud_core/src/cone-config/index.d.ts +2 -3
  5. package/dist/node-server/_cloud_core/src/cone-config/index.d.ts.map +1 -1
  6. package/dist/node-server/_cloud_core/src/cone-config/index.js +13 -79
  7. package/dist/node-server/_cloud_core/tests/cone-config/bundle-cases.test.d.ts +2 -0
  8. package/dist/node-server/_cloud_core/tests/cone-config/bundle-cases.test.d.ts.map +1 -0
  9. package/dist/node-server/_cloud_core/tests/cone-config/bundle-cases.test.js +57 -0
  10. package/dist/node-server/_cloud_core/tests/cone-config/cone-config.test.js +7 -5
  11. package/dist/node-server/_cloud_core/tests/fixtures/cone-config-cases.d.mts +37 -0
  12. package/dist/node-server/_cloud_core/tests/fixtures/cone-config-cases.d.mts.map +1 -0
  13. package/dist/node-server/_cloud_core/tests/fixtures/cone-config-cases.mjs +139 -0
  14. package/dist/node-server/_cloud_core/tests/resume-cone-config.test.js +17 -0
  15. package/dist/ui/.vite/manifest.json +179 -179
  16. package/dist/ui/assets/{account-store-btH-rhSC.js → account-store-BD1MW0QM.js} +1 -1
  17. package/dist/ui/assets/{account-store-CzcIBhIW.js → account-store-F-Hva1nS.js} +1 -1
  18. package/dist/ui/assets/{adobe-CJagkQaj.js → adobe-CLl8UgcL.js} +1 -1
  19. package/dist/ui/assets/{adobe-CbwrOy6h.js → adobe-CndWdX0c.js} +1 -1
  20. package/dist/ui/assets/{agent-panels-CWkdH3No.js → agent-panels-DH8GU_hC.js} +1 -1
  21. package/dist/ui/assets/{almost-bash-shell-headless-CJ_eP6rj.js → almost-bash-shell-headless-DhugB1_j.js} +12 -12
  22. package/dist/ui/assets/{apply-layout-BIG5g9tp.js → apply-layout-D8ntAMP_.js} +1 -1
  23. package/dist/ui/assets/{azure-openai-DmBsM65e.js → azure-openai-D-1XQgyJ.js} +1 -1
  24. package/dist/ui/assets/{azure-openai-Cw7yGm0E.js → azure-openai-LY9c836N.js} +1 -1
  25. package/dist/ui/assets/{cdp-fHtNpyG6.js → cdp-BpNgBtOj.js} +1 -1
  26. package/dist/ui/assets/{cerebras-BF4ZkjX5.js → cerebras-BZFZs9Ht.js} +1 -1
  27. package/dist/ui/assets/{cerebras-BRvzPIo6.js → cerebras-C2TF1niJ.js} +1 -1
  28. package/dist/ui/assets/{composer-speech-CYKpfumH.js → composer-speech-Dxe7pRbz.js} +1 -1
  29. package/dist/ui/assets/{connect-surface-eAvkKA7C.js → connect-surface-j7CbcbrP.js} +1 -1
  30. package/dist/ui/assets/{directed-approval-FuN8_c_j.js → directed-approval-1NtgYEGb.js} +1 -1
  31. package/dist/ui/assets/{emscripten-vfs-hook-Cc4WeSPd.js → emscripten-vfs-hook-Orkw8aUI.js} +1 -1
  32. package/dist/ui/assets/{frozen-archive-writer-CmH9_k8F.js → frozen-archive-writer-CXiseW3m.js} +1 -1
  33. package/dist/ui/assets/{frozen-session-delete-fM62FhkX.js → frozen-session-delete-CLQSNT5q.js} +1 -1
  34. package/dist/ui/assets/{frozen-session-identity-blXQV4n9.js → frozen-session-identity-Dla2v_H8.js} +1 -1
  35. package/dist/ui/assets/{gelatiere-unit-Bo7PCnbF.js → gelatiere-unit-DS5kYHdl.js} +1 -1
  36. package/dist/ui/assets/{github-C1rbK9rb.js → github-CwFqHwM7.js} +1 -1
  37. package/dist/ui/assets/{github-CQol1Ste.js → github-DkBtRTtj.js} +1 -1
  38. package/dist/ui/assets/{github-copilot-Dh5Sw_oV.js → github-copilot-BgtimT-5.js} +1 -1
  39. package/dist/ui/assets/{github-copilot-Da1-tlWc.js → github-copilot-DvlR4p1V.js} +1 -1
  40. package/dist/ui/assets/{hear-DhXegde8.js → hear-DgkNLpQK.js} +1 -1
  41. package/dist/ui/assets/{js-realm-worker-BSYR2sfX.js → js-realm-worker-DvaOkd8I.js} +2 -2
  42. package/dist/ui/assets/{jsh-executor-v3qKqkZF.js → jsh-executor-ByYCAfVx.js} +3 -3
  43. package/dist/ui/assets/{kernel-worker-BItmIWYW.js → kernel-worker-xyDnHfnE.js} +8 -8
  44. package/dist/ui/assets/{lick-ws-bridge-BOvw32aW.js → lick-ws-bridge-BztgRobQ.js} +1 -1
  45. package/dist/ui/assets/{lick-ws-bridge-gBNtu0RL.js → lick-ws-bridge-ViIkTZhn.js} +1 -1
  46. package/dist/ui/assets/{live-session-curation-8wVj6wZH.js → live-session-curation-CwlsC5Wo.js} +1 -1
  47. package/dist/ui/assets/{live-session-curation-7CTGumla.js → live-session-curation-vx6yGkHy.js} +1 -1
  48. package/dist/ui/assets/{live-session-snapshot-D8qPxZ7E.js → live-session-snapshot-CjDUliT7.js} +1 -1
  49. package/dist/ui/assets/{local-llm-DvbP3RyJ.js → local-llm-BDGbw8KW.js} +1 -1
  50. package/dist/ui/assets/{local-llm-CgwaZ6Gd.js → local-llm-Ck0NLGhL.js} +1 -1
  51. package/dist/ui/assets/{main-IZrprgCE.js → main-YhmBlckm.js} +3 -3
  52. package/dist/ui/assets/{main-cherry-CiVZP2ux.js → main-cherry-B2tRa4cV.js} +1 -1
  53. package/dist/ui/assets/{mcp-command-BQnTrbHl.js → mcp-command-DCFbOqLb.js} +10 -10
  54. package/dist/ui/assets/{memory-curation-seam-CjpYohBK.js → memory-curation-seam-bu5MdUMf.js} +1 -1
  55. package/dist/ui/assets/{memory-health-DiVvDJo6.js → memory-health-Cwv7orty.js} +1 -1
  56. package/dist/ui/assets/{memory-write-execute-CPlnwj08.js → memory-write-execute-DKunhcVV.js} +1 -1
  57. package/dist/ui/assets/{merge-folded-cost-into-frozen-CDpUEipJ.js → merge-folded-cost-into-frozen-DI9twAuG.js} +1 -1
  58. package/dist/ui/assets/{new-session-DMBvlX7U.js → new-session-DdoKKj2v.js} +2 -2
  59. package/dist/ui/assets/{oauth-bootstrap-z9Ak2U5k.js → oauth-bootstrap-D2zeCkqT.js} +2 -2
  60. package/dist/ui/assets/{onboarding-orchestrator-Cmp_7XS6.js → onboarding-orchestrator-DTY6LK4k.js} +1 -1
  61. package/dist/ui/assets/{openai-codex-XtzU7AV5.js → openai-codex-BtZ0emDz.js} +1 -1
  62. package/dist/ui/assets/{openai-codex-DObnOrti.js → openai-codex-C4ntaXUk.js} +1 -1
  63. package/dist/ui/assets/{openrouter-h4PBvqqd.js → openrouter-D9MOwkyn.js} +1 -1
  64. package/dist/ui/assets/{openrouter-B9YPpMez.js → openrouter-DbvLMk3L.js} +1 -1
  65. package/dist/ui/assets/{openrouter-free-DsUNrtke.js → openrouter-free-BLccMR3p.js} +1 -1
  66. package/dist/ui/assets/{openrouter-free-Bw98ZXz_.js → openrouter-free-CytTm0tL.js} +1 -1
  67. package/dist/ui/assets/{openrouter-oauth-DlBVHDiI.js → openrouter-oauth-DnEx9Rqh.js} +1 -1
  68. package/dist/ui/assets/{openrouter-oauth-CtAf-wKQ.js → openrouter-oauth-G9EtfjRV.js} +1 -1
  69. package/dist/ui/assets/{panel-rpc-handlers-C2H1GujD.js → panel-rpc-handlers-CnI0y8vs.js} +2 -2
  70. package/dist/ui/assets/{panelize-shell-DjEoCne9.js → panelize-shell-DUBjt6H_.js} +1 -1
  71. package/dist/ui/assets/{pi-edit-execution-DdXRrxQk.js → pi-edit-execution-CX4GKvdv.js} +1 -1
  72. package/dist/ui/assets/{provider-D88ZP1Lj.js → provider-DVbu5LnO.js} +1 -1
  73. package/dist/ui/assets/{provider-CkcZnU60.js → provider-Dbkq5LeU.js} +1 -1
  74. package/dist/ui/assets/{provider-settings-D6OJgUt2.js → provider-settings-CQsfoQ1J.js} +1 -1
  75. package/dist/ui/assets/provider-store-access-CYY1izR6.js +1 -0
  76. package/dist/ui/assets/provider-store-access-DCHamof5.js +1 -0
  77. package/dist/ui/assets/{providers-CNaCaxZH.js → providers-DAe9H_v8.js} +2 -2
  78. package/dist/ui/assets/{providers-Bh-gB-84.js → providers-IlvLc68Q.js} +1 -1
  79. package/dist/ui/assets/{quick-llm-D3vw1Iw4.js → quick-llm-CS859Yj_.js} +1 -1
  80. package/dist/ui/assets/{realm-inprocess-c5_SKCj3.js → realm-inprocess-COL-iKh1.js} +2 -2
  81. package/dist/ui/assets/{realm-unhandled-rejections-B-HhibQP.js → realm-unhandled-rejections-B6xaTDVi.js} +1 -1
  82. package/dist/ui/assets/{realm-unhandled-rejections-V5oYilet.js → realm-unhandled-rejections-C7hmQxXs.js} +1 -1
  83. package/dist/ui/assets/{remote-terminal-view-ByfloxIg.js → remote-terminal-view-BvUG4DYc.js} +2 -2
  84. package/dist/ui/assets/{restore-BByLi1Yd.js → restore-Bwl6K7p3.js} +1 -1
  85. package/dist/ui/assets/{run-BG76L9eu.js → run-B5g_uI07.js} +1 -1
  86. package/dist/ui/assets/{run-C-tci7Wb.js → run-BGGEfu-c.js} +1 -1
  87. package/dist/ui/assets/{run-BZCg7fqf.js → run-ibUaNBQQ.js} +2 -2
  88. package/dist/ui/assets/{run-CJQ6QgvR.js → run-wjLp7772.js} +2 -2
  89. package/dist/ui/assets/{serve-command-fOeuDlHT.js → serve-command-Dz9Stwu3.js} +2 -2
  90. package/dist/ui/assets/{serve-runtime-BgsoA65p.js → serve-runtime-DifvoJEx.js} +1 -1
  91. package/dist/ui/assets/{session-command-memory-Z4gG5kc5.js → session-command-memory-DL2jJXMG.js} +2 -2
  92. package/dist/ui/assets/{session-jsonl-CRoUGl0k.js → session-jsonl-C3C8hKnt.js} +1 -1
  93. package/dist/ui/assets/{session-search-index-C9AzKIIE.js → session-search-index-CwvVidcF.js} +1 -1
  94. package/dist/ui/assets/{setup-feature-flags-remote-HCx9Z23R.js → setup-feature-flags-remote-CXXeeHW_.js} +1 -1
  95. package/dist/ui/assets/{setup-model-catalog-C_9E6bou.js → setup-model-catalog-CbbCvN8c.js} +1 -1
  96. package/dist/ui/assets/{silent-renew-backoff-ByLo6zsQ.js → silent-renew-backoff-Dt40GINt.js} +1 -1
  97. package/dist/ui/assets/slicc-version-B12B_nYb.js +1 -0
  98. package/dist/ui/assets/{soundscape-KuEhg0nr.js → soundscape-BnzHIiac.js} +1 -1
  99. package/dist/ui/assets/{speak-Di_o2s0D.js → speak-s6Ezas3_.js} +1 -1
  100. package/dist/ui/assets/{sprinkle-manager-4tRf736T.js → sprinkle-manager-B6_Tq3WN.js} +1 -1
  101. package/dist/ui/assets/{sprinkle-renderer-EbUVsHUB.js → sprinkle-renderer-DyptAyk4.js} +1 -1
  102. package/dist/ui/assets/{sudo-BlHPVMLU.js → sudo-9bM5adw9.js} +1 -1
  103. package/dist/ui/assets/{supervisor-BjtHX13A.js → supervisor-DWUb8N1P.js} +1 -1
  104. package/dist/ui/assets/{sync-dialog-CG5xrbzN.js → sync-dialog-DB9gPfcg.js} +1 -1
  105. package/dist/ui/assets/{transformers-env-BCIh311V.js → transformers-env-D4iwHGI1.js} +1 -1
  106. package/dist/ui/assets/{tray-leader-DfoPsK4G.js → tray-leader-CbyHPI0I.js} +1 -1
  107. package/dist/ui/assets/{tray-leave-runtime-Cn6l6kQM.js → tray-leave-runtime-CbvRdJPQ.js} +1 -1
  108. package/dist/ui/assets/{tray-sidecar-AttyJaV8.js → tray-sidecar-B5huBZkI.js} +1 -1
  109. package/dist/ui/assets/{upgrade-detection-BPnMErp6.js → upgrade-detection-6edCinYk.js} +1 -1
  110. package/dist/ui/assets/{upgrade-to-seven-oM6Y2jpf.js → upgrade-to-seven-BHUcE9wq.js} +1 -1
  111. package/dist/ui/assets/{voice-reply-DhFXmtN1.js → voice-reply-c7d6CY7I.js} +1 -1
  112. package/dist/ui/assets/{wc-attach-B2_dNi4B.js → wc-attach-lm3QnyXs.js} +2 -2
  113. package/dist/ui/assets/{wc-browser-BvSPcFnk.js → wc-browser-BILPcbgN.js} +1 -1
  114. package/dist/ui/assets/{wc-computers-P_YXw5mk.js → wc-computers-iCzCAT2C.js} +1 -1
  115. package/dist/ui/assets/{wc-detached-C4uhpekQ.js → wc-detached-DFwwR4RF.js} +1 -1
  116. package/dist/ui/assets/{wc-extension-D3l9KUxg.js → wc-extension-0IbGxHjs.js} +2 -2
  117. package/dist/ui/assets/{wc-follower-BN7GwkbB.js → wc-follower-DkgntXOp.js} +3 -3
  118. package/dist/ui/assets/{wc-follower-oauth-PiJAsXE9.js → wc-follower-oauth-C3BLIGbb.js} +1 -1
  119. package/dist/ui/assets/{wc-gelatiere-aEAOP3ay.js → wc-gelatiere-CXX1_rMS.js} +1 -1
  120. package/dist/ui/assets/{wc-live-BeX-_7T4.js → wc-live-B-b1eo1g.js} +5 -5
  121. package/dist/ui/assets/{wc-nav-D7tE4cOW.js → wc-nav-CZXzwu-g.js} +2 -2
  122. package/dist/ui/assets/{wc-onboarding-BsRWvnNO.js → wc-onboarding-BWu-7vxU.js} +2 -2
  123. package/dist/ui/assets/{wc-permissions-xh98BF4d.js → wc-permissions--gzVrLeD.js} +2 -2
  124. package/dist/ui/assets/{wc-placeholder-C2e75ECK.js → wc-placeholder-B2d2q6zQ.js} +2 -2
  125. package/dist/ui/assets/{wc-profile-export-BOUD9Teb.js → wc-profile-export-rlkoo2cb.js} +3 -3
  126. package/dist/ui/assets/{wc-secret-request-9hLiDY0q.js → wc-secret-request-C0MKjBVT.js} +1 -1
  127. package/dist/ui/assets/{wc-settings-C1Ew3xtK.js → wc-settings-Dc8Gmy2S.js} +3 -3
  128. package/dist/ui/assets/{wc-shell-BQm4_AZ-.js → wc-shell-BhkIyAXa.js} +3 -3
  129. package/dist/ui/assets/{wc-shortcut-config-CG3A_xXd.js → wc-shortcut-config-b1PO-pxP.js} +1 -1
  130. package/dist/ui/assets/{wc-sprinkles-DfhVMlB0.js → wc-sprinkles-D20m3z91.js} +2 -2
  131. package/dist/ui/assets/{wc-transcript-export-D5lf1B5S.js → wc-transcript-export-mAAWaVHR.js} +2 -2
  132. package/dist/ui/assets/{wc-tray-DrfK5jNi.js → wc-tray-COZfixoH.js} +4 -4
  133. package/dist/ui/assets/welcome-detection-DMNkjk4H.js +1 -0
  134. package/dist/ui/assets/{whisper-session-B-Uac3-A.js → whisper-session-SzPFfAP_.js} +2 -2
  135. package/dist/ui/assets/{xai-grok-CHwFD6MH.js → xai-grok-B9OK_us-.js} +1 -1
  136. package/dist/ui/assets/{xai-grok-xZGJWELa.js → xai-grok-BC6ijUtp.js} +1 -1
  137. package/dist/ui/index.html +3 -3
  138. package/dist/ui/packages/webapp/index.html +3 -3
  139. package/dist/ui/packages/webapp/upgrade-to-seven.html +1 -1
  140. package/dist/ui/upgrade-to-seven.html +1 -1
  141. package/package.json +1 -1
  142. package/dist/ui/assets/provider-store-access-Am4wDSnr.js +0 -1
  143. package/dist/ui/assets/provider-store-access-bHvRNk17.js +0 -1
  144. package/dist/ui/assets/slicc-version-BOvQ0meA.js +0 -1
  145. package/dist/ui/assets/welcome-detection-D98VbCw6.js +0 -1
@@ -0,0 +1,89 @@
1
+ export type EffortLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
2
+ export type OAuthAccount = {
3
+ providerId: string;
4
+ kind: 'oauth';
5
+ accessToken: string;
6
+ refreshToken?: string;
7
+ tokenExpiresAt?: number;
8
+ userName?: string;
9
+ baseUrl?: string;
10
+ };
11
+ export type ApiKeyAccount = {
12
+ providerId: string;
13
+ kind: 'apikey';
14
+ apiKey: string;
15
+ baseUrl?: string;
16
+ deployment?: string;
17
+ apiVersion?: string;
18
+ };
19
+ export type SecretEntry = {
20
+ name: string;
21
+ value: string;
22
+ domains: string[];
23
+ };
24
+ /** @typedef {'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'} EffortLevel */
25
+ /**
26
+ * @typedef {{
27
+ * providerId: string;
28
+ * kind: 'oauth';
29
+ * accessToken: string;
30
+ * refreshToken?: string;
31
+ * tokenExpiresAt?: number;
32
+ * userName?: string;
33
+ * baseUrl?: string;
34
+ * }} OAuthAccount
35
+ */
36
+ /**
37
+ * @typedef {{
38
+ * providerId: string;
39
+ * kind: 'apikey';
40
+ * apiKey: string;
41
+ * baseUrl?: string;
42
+ * deployment?: string;
43
+ * apiVersion?: string;
44
+ * }} ApiKeyAccount
45
+ */
46
+ /** @typedef {{ name: string; value: string; domains: string[] }} SecretEntry */
47
+ /** @type {readonly EffortLevel[]} */
48
+ export declare const EFFORT_LEVELS: readonly EffortLevel[];
49
+ /**
50
+ * @param {unknown} value
51
+ * @returns {value is EffortLevel}
52
+ */
53
+ export declare function isEffortLevel(value: unknown): value is EffortLevel;
54
+ /**
55
+ * Secret names: identifier-shaped, plus `.` and `-` for namespaced subsystem
56
+ * secrets (`s3.<profile>.access_key_id`). The `secrets.env` key is everything
57
+ * before the first `=`, so none of these characters can split a line; only
58
+ * POSIX-identifier names ever reach the agent shell as `$NAME`.
59
+ */
60
+ export declare const SECRET_NAME_RE: RegExp;
61
+ /**
62
+ * Validate one untrusted provider account. Only the known fields of the
63
+ * chosen kind survive; the credential and `providerId` must be non-empty.
64
+ * @param {unknown} input
65
+ * @param {string} where error-message prefix, e.g. `cone-config: accounts[0]`
66
+ * @returns {OAuthAccount | ApiKeyAccount}
67
+ */
68
+ export declare function validateAccount(input: unknown, where: string): OAuthAccount | ApiKeyAccount;
69
+ /**
70
+ * Validate one untrusted secret against the line-oriented `secrets.env`
71
+ * schema (no escaping): a {@link SECRET_NAME_RE} name outside the reserved
72
+ * `oauth.*` namespace and not ending in `_DOMAINS`, a single-line value, and
73
+ * at least one domain, each trimmed, non-blank, single-line and comma-free.
74
+ * node-server drops a secret with no domains, so `[]` is rejected here
75
+ * rather than shipped as a secret that silently never loads.
76
+ * @param {unknown} input
77
+ * @param {string} where error-message prefix, e.g. `cone-config: secrets[0]`
78
+ * @returns {SecretEntry}
79
+ */
80
+ export declare function validateSecret(input: unknown, where: string): SecretEntry;
81
+ /**
82
+ * Serialize validated secrets to the `NAME=value` / `NAME_DOMAINS=a,b` lines
83
+ * node-server's EnvSecretStore reads. Values are written verbatim, so callers
84
+ * pass entries that went through {@link validateSecret}.
85
+ * @param {readonly SecretEntry[]} secrets
86
+ * @returns {string}
87
+ */
88
+ export declare function serializeSecretsEnv(secrets: readonly SecretEntry[]): string;
89
+ //# sourceMappingURL=cone-config-rules.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cone-config-rules.d.mts","sourceRoot":"","sources":["../../../src/cone-config/cone-config-rules.mjs"],"names":[],"mappings":"AAaI,YAAmE,WAAW,GAApE,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAa;AAG/E,YAQG,YAAY,GARL;IACR,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAc;AAIf,YAOG,aAAa,GAPN;IACR,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAe;AAGf,YAA8D,WAAW,GAA/D;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAa;AAzB7E,qFAAqF;AAErF;;;;;;;;;;GAUG;AAEH;;;;;;;;;GASG;AAEH,gFAAgF;AAEhF,qCAAqC;AACrC,eAAO,MAAM,aAAa,EADf,SAAS,WAAW,EACiE,CAAC;AAEjG;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAHxB,OAGwB,GAFtB,KAAK,IAAI,WAAW,CAMhC;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QAA+B,CAAC;AAkC3D;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAJ1B,OAI0B,EAAE,KAAK,EAHjC,MAGiC,GAF/B,YAAY,GAAG,aAAa,CAgCxC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAJzB,OAIyB,EAAE,KAAK,EAHhC,MAGgC,GAF9B,WAAW,CAyBvB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAHhC,SAAS,WAAW,EAGY,GAF9B,MAAM,CASlB"}
@@ -0,0 +1,170 @@
1
+ // @ts-check
2
+ // Zero-dependency rules for the untrusted cone-config bundle: provider
3
+ // accounts, domain-scoped secrets, the effort-level set, and the `secrets.env`
4
+ // serializer. Plain JS with no imports, so both floats that write a cone's
5
+ // credential files run the exact same checks.
6
+ //
7
+ // CANONICAL COPY: packages/cloud-core/src/cone-config/cone-config-rules.mjs
8
+ // (wrapped with types by cone-config/index.ts). packages/github-workflow/
9
+ // scripts/cone-config-rules.mjs is a byte-identical vendored copy, because the
10
+ // workflow scripts run from a sparse checkout of packages/github-workflow and
11
+ // cannot import another package. Edit the canonical file, then copy it over;
12
+ // github-workflow's cone-config-rules.test.mjs fails while the two differ.
13
+ /** @typedef {'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'} EffortLevel */
14
+ /**
15
+ * @typedef {{
16
+ * providerId: string;
17
+ * kind: 'oauth';
18
+ * accessToken: string;
19
+ * refreshToken?: string;
20
+ * tokenExpiresAt?: number;
21
+ * userName?: string;
22
+ * baseUrl?: string;
23
+ * }} OAuthAccount
24
+ */
25
+ /**
26
+ * @typedef {{
27
+ * providerId: string;
28
+ * kind: 'apikey';
29
+ * apiKey: string;
30
+ * baseUrl?: string;
31
+ * deployment?: string;
32
+ * apiVersion?: string;
33
+ * }} ApiKeyAccount
34
+ */
35
+ /** @typedef {{ name: string; value: string; domains: string[] }} SecretEntry */
36
+ /** @type {readonly EffortLevel[]} */
37
+ export const EFFORT_LEVELS = Object.freeze(['off', 'minimal', 'low', 'medium', 'high', 'xhigh']);
38
+ /**
39
+ * @param {unknown} value
40
+ * @returns {value is EffortLevel}
41
+ */
42
+ export function isEffortLevel(value) {
43
+ return (typeof value === 'string' && /** @type {readonly string[]} */ (EFFORT_LEVELS).includes(value));
44
+ }
45
+ /**
46
+ * Secret names: identifier-shaped, plus `.` and `-` for namespaced subsystem
47
+ * secrets (`s3.<profile>.access_key_id`). The `secrets.env` key is everything
48
+ * before the first `=`, so none of these characters can split a line; only
49
+ * POSIX-identifier names ever reach the agent shell as `$NAME`.
50
+ */
51
+ export const SECRET_NAME_RE = /^[A-Za-z_][A-Za-z0-9_.-]*$/;
52
+ /** Owned by node-server's in-memory OAuth replica store; a bundle may not write it. */
53
+ const RESERVED_PREFIX = 'oauth.';
54
+ /** `secrets.env` reads any `<NAME>_DOMAINS` key as NAME's domain list. */
55
+ const DOMAINS_SUFFIX = '_DOMAINS';
56
+ /**
57
+ * @param {unknown} v
58
+ * @returns {v is string}
59
+ */
60
+ function isStr(v) {
61
+ return typeof v === 'string';
62
+ }
63
+ /**
64
+ * @param {string} v
65
+ * @returns {boolean}
66
+ */
67
+ function hasNewline(v) {
68
+ return /[\r\n]/.test(v);
69
+ }
70
+ /**
71
+ * @param {Record<string, unknown>} obj
72
+ * @param {string} key
73
+ * @returns {Record<string, string>}
74
+ */
75
+ function optionalStr(obj, key) {
76
+ const v = obj[key];
77
+ return isStr(v) ? { [key]: v } : {};
78
+ }
79
+ /**
80
+ * Validate one untrusted provider account. Only the known fields of the
81
+ * chosen kind survive; the credential and `providerId` must be non-empty.
82
+ * @param {unknown} input
83
+ * @param {string} where error-message prefix, e.g. `cone-config: accounts[0]`
84
+ * @returns {OAuthAccount | ApiKeyAccount}
85
+ */
86
+ export function validateAccount(input, where) {
87
+ if (input === null || typeof input !== 'object')
88
+ throw new Error(`${where} is not an object`);
89
+ const a = /** @type {Record<string, unknown>} */ (input);
90
+ if (!isStr(a.providerId) || !a.providerId)
91
+ throw new Error(`${where}.providerId required`);
92
+ if (a.kind === 'oauth') {
93
+ if (!isStr(a.accessToken) || !a.accessToken) {
94
+ throw new Error(`${where}: oauth account requires accessToken`);
95
+ }
96
+ return {
97
+ providerId: a.providerId,
98
+ kind: 'oauth',
99
+ accessToken: a.accessToken,
100
+ ...optionalStr(a, 'refreshToken'),
101
+ ...(typeof a.tokenExpiresAt === 'number' ? { tokenExpiresAt: a.tokenExpiresAt } : {}),
102
+ ...optionalStr(a, 'userName'),
103
+ ...optionalStr(a, 'baseUrl'),
104
+ };
105
+ }
106
+ if (a.kind === 'apikey') {
107
+ if (!isStr(a.apiKey) || !a.apiKey)
108
+ throw new Error(`${where}: apikey account requires apiKey`);
109
+ return {
110
+ providerId: a.providerId,
111
+ kind: 'apikey',
112
+ apiKey: a.apiKey,
113
+ ...optionalStr(a, 'baseUrl'),
114
+ ...optionalStr(a, 'deployment'),
115
+ ...optionalStr(a, 'apiVersion'),
116
+ };
117
+ }
118
+ throw new Error(`${where}.kind must be 'oauth' | 'apikey'`);
119
+ }
120
+ /**
121
+ * Validate one untrusted secret against the line-oriented `secrets.env`
122
+ * schema (no escaping): a {@link SECRET_NAME_RE} name outside the reserved
123
+ * `oauth.*` namespace and not ending in `_DOMAINS`, a single-line value, and
124
+ * at least one domain, each trimmed, non-blank, single-line and comma-free.
125
+ * node-server drops a secret with no domains, so `[]` is rejected here
126
+ * rather than shipped as a secret that silently never loads.
127
+ * @param {unknown} input
128
+ * @param {string} where error-message prefix, e.g. `cone-config: secrets[0]`
129
+ * @returns {SecretEntry}
130
+ */
131
+ export function validateSecret(input, where) {
132
+ if (input === null || typeof input !== 'object')
133
+ throw new Error(`${where} is not an object`);
134
+ const s = /** @type {Record<string, unknown>} */ (input);
135
+ if (!isStr(s.name) || !SECRET_NAME_RE.test(s.name)) {
136
+ throw new Error(`${where}: name must be an identifier matching ${SECRET_NAME_RE}`);
137
+ }
138
+ if (s.name.startsWith(RESERVED_PREFIX)) {
139
+ throw new Error(`${where} ${s.name}: the oauth.* namespace is reserved for OAuth replicas`);
140
+ }
141
+ if (s.name.endsWith(DOMAINS_SUFFIX)) {
142
+ throw new Error(`${where} ${s.name}: names ending in _DOMAINS are reserved for domain lines`);
143
+ }
144
+ if (!isStr(s.value) || hasNewline(s.value)) {
145
+ throw new Error(`${where} ${s.name}: value must be a single-line string`);
146
+ }
147
+ if (!Array.isArray(s.domains) || s.domains.length === 0 || !s.domains.every(isStr)) {
148
+ throw new Error(`${where} ${s.name}: domains must be a non-empty string[]`);
149
+ }
150
+ const domains = s.domains.map((d) => d.trim());
151
+ if (domains.some((d) => !d || hasNewline(d) || d.includes(','))) {
152
+ throw new Error(`${where} ${s.name}: domains must be non-blank, single-line and comma-free`);
153
+ }
154
+ return { name: s.name, value: s.value, domains };
155
+ }
156
+ /**
157
+ * Serialize validated secrets to the `NAME=value` / `NAME_DOMAINS=a,b` lines
158
+ * node-server's EnvSecretStore reads. Values are written verbatim, so callers
159
+ * pass entries that went through {@link validateSecret}.
160
+ * @param {readonly SecretEntry[]} secrets
161
+ * @returns {string}
162
+ */
163
+ export function serializeSecretsEnv(secrets) {
164
+ const lines = [];
165
+ for (const s of secrets) {
166
+ lines.push(`${s.name}=${s.value}`);
167
+ lines.push(`${s.name}${DOMAINS_SUFFIX}=${s.domains.join(',')}`);
168
+ }
169
+ return lines.length ? `${lines.join('\n')}\n` : '';
170
+ }
@@ -72,9 +72,8 @@ export declare function mergeConeConfig(base: ConeConfig, delta: ConeConfigDelta
72
72
  /**
73
73
  * Serialize flat secrets to the `NAME=value` / `NAME_DOMAINS=a,b` line format
74
74
  * that node-server's EnvSecretStore reads. Values are written verbatim (no
75
- * escaping — matching the existing parser), so secret names must be env-var
76
- * identifiers and values/domains must be single-line (no newlines, and values
77
- * must not break `NAME=value` parsing). Callers sanitize/validate inputs.
75
+ * escaping — matching the existing parser), so entries must have passed the
76
+ * bundle validators (single-line values, comma-free domains, safe names).
78
77
  */
79
78
  export declare function serializeSecretsEnv(secrets: SecretEntry[]): string;
80
79
  export declare function bundleToFiles(cfg: ConeConfig): {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cone-config/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cone-config/index.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,10 @@
1
1
  // Side-effect-free shared contract for cloud-cone configuration.
2
2
  // MUST NOT import e2b, node:*, or any runtime substrate — it is imported
3
3
  // by the browser webapp via the @slicc/cloud-core/cone-config subpath.
4
+ // Account and secret rules (including the secrets.env line-format constraints)
5
+ // live in the zero-dependency cone-config-rules.mjs, shared byte-for-byte with
6
+ // packages/github-workflow so both floats accept exactly the same bundles.
7
+ import { isEffortLevel, serializeSecretsEnv as serializeSecretLines, validateAccount, validateSecret, } from './cone-config-rules.mjs';
4
8
  /** Max serialized bundle size (bytes) accepted as a preboot env payload. */
5
9
  export const MAX_CONE_CONFIG_BYTES = 256 * 1024;
6
10
  /**
@@ -17,7 +21,6 @@ function isUntrustedObject(value) {
17
21
  function isStr(v) {
18
22
  return typeof v === 'string';
19
23
  }
20
- const VALID_EFFORT_LEVELS = new Set(['off', 'minimal', 'low', 'medium', 'high', 'xhigh']);
21
24
  export function validateConeConfig(input) {
22
25
  if (!isUntrustedObject(input))
23
26
  throw new Error('cone-config: not an object');
@@ -28,80 +31,17 @@ export function validateConeConfig(input) {
28
31
  throw new Error('cone-config: accounts must be an array');
29
32
  if (!Array.isArray(cfg.secrets))
30
33
  throw new Error('cone-config: secrets must be an array');
31
- const accounts = cfg.accounts.map((a) => validateAccount(a));
32
- const secrets = cfg.secrets.map((s) => validateSecret(s));
34
+ const accounts = cfg.accounts.map((a, i) => validateAccount(a, `cone-config: accounts[${i}]`));
35
+ const secrets = cfg.secrets.map((s, i) => validateSecret(s, `cone-config: secrets[${i}]`));
33
36
  const result = { model: cfg.model, accounts, secrets };
34
37
  if (cfg.effortLevel !== undefined) {
35
- if (!isStr(cfg.effortLevel) || !VALID_EFFORT_LEVELS.has(cfg.effortLevel)) {
38
+ if (!isEffortLevel(cfg.effortLevel)) {
36
39
  throw new Error('cone-config: effortLevel must be one of off|minimal|low|medium|high|xhigh');
37
40
  }
38
41
  result.effortLevel = cfg.effortLevel;
39
42
  }
40
43
  return result;
41
44
  }
42
- function validateAccount(a) {
43
- if (!isUntrustedObject(a))
44
- throw new Error('cone-config: account not an object');
45
- const acc = a;
46
- if (!isStr(acc.providerId))
47
- throw new Error('cone-config: account.providerId required');
48
- if (!isStr(acc.kind))
49
- throw new Error('cone-config: account.kind required');
50
- if (acc.kind === 'oauth') {
51
- if (!isStr(acc.accessToken))
52
- throw new Error('cone-config: oauth account requires accessToken');
53
- return {
54
- providerId: acc.providerId,
55
- kind: 'oauth',
56
- accessToken: acc.accessToken,
57
- ...(isStr(acc.refreshToken) ? { refreshToken: acc.refreshToken } : {}),
58
- ...(typeof acc.tokenExpiresAt === 'number' ? { tokenExpiresAt: acc.tokenExpiresAt } : {}),
59
- ...(isStr(acc.userName) ? { userName: acc.userName } : {}),
60
- ...(isStr(acc.baseUrl) ? { baseUrl: acc.baseUrl } : {}),
61
- };
62
- }
63
- if (acc.kind === 'apikey') {
64
- if (!isStr(acc.apiKey))
65
- throw new Error('cone-config: apikey account requires apiKey');
66
- return {
67
- providerId: acc.providerId,
68
- kind: 'apikey',
69
- apiKey: acc.apiKey,
70
- ...(isStr(acc.baseUrl) ? { baseUrl: acc.baseUrl } : {}),
71
- ...(isStr(acc.deployment) ? { deployment: acc.deployment } : {}),
72
- ...(isStr(acc.apiVersion) ? { apiVersion: acc.apiVersion } : {}),
73
- };
74
- }
75
- throw new Error(`cone-config: account.kind must be 'oauth' | 'apikey'`);
76
- }
77
- // secrets.env is line-based (NAME=value / NAME_DOMAINS=a,b) with no escaping,
78
- // so a newline/CR in a name or value would inject phantom lines on round-trip.
79
- // Names must be env-var identifiers; values and domains must be single-line.
80
- const ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
81
- function hasNewline(v) {
82
- return /[\r\n]/.test(v);
83
- }
84
- function validateSecret(s) {
85
- if (!isUntrustedObject(s))
86
- throw new Error('cone-config: secret not an object');
87
- const sec = s;
88
- if (!isStr(sec.name))
89
- throw new Error('cone-config: secret.name required');
90
- if (!ENV_NAME_RE.test(sec.name)) {
91
- throw new Error('cone-config: secret.name must be an env-var identifier ([A-Za-z_][A-Za-z0-9_]*)');
92
- }
93
- if (!isStr(sec.value))
94
- throw new Error('cone-config: secret.value required');
95
- if (hasNewline(sec.value))
96
- throw new Error('cone-config: secret.value must be single-line');
97
- if (!Array.isArray(sec.domains) || !sec.domains.every(isStr)) {
98
- throw new Error('cone-config: secret.domains must be string[]');
99
- }
100
- if (sec.domains.some((d) => hasNewline(d) || d.includes(','))) {
101
- throw new Error('cone-config: secret.domains entries must be single-line and comma-free');
102
- }
103
- return { name: sec.name, value: sec.value, domains: sec.domains };
104
- }
105
45
  /** Validate the `upsert` arm of a resume delta (accounts/secrets reuse the full-bundle validators). */
106
46
  function validateDeltaUpsert(input) {
107
47
  if (!isUntrustedObject(input)) {
@@ -113,13 +53,13 @@ function validateDeltaUpsert(input) {
113
53
  if (!Array.isArray(up.accounts)) {
114
54
  throw new Error('cone-config: delta.upsert.accounts must be an array');
115
55
  }
116
- upsert.accounts = up.accounts.map((a) => validateAccount(a));
56
+ upsert.accounts = up.accounts.map((a, i) => validateAccount(a, `cone-config: delta.upsert.accounts[${i}]`));
117
57
  }
118
58
  if (up.secrets !== undefined) {
119
59
  if (!Array.isArray(up.secrets)) {
120
60
  throw new Error('cone-config: delta.upsert.secrets must be an array');
121
61
  }
122
- upsert.secrets = up.secrets.map((s) => validateSecret(s));
62
+ upsert.secrets = up.secrets.map((s, i) => validateSecret(s, `cone-config: delta.upsert.secrets[${i}]`));
123
63
  }
124
64
  return upsert;
125
65
  }
@@ -164,7 +104,7 @@ export function validateConeConfigDelta(input) {
164
104
  if (d.effortLevel === null) {
165
105
  out.effortLevel = null;
166
106
  }
167
- else if (!isStr(d.effortLevel) || !VALID_EFFORT_LEVELS.has(d.effortLevel)) {
107
+ else if (!isEffortLevel(d.effortLevel)) {
168
108
  throw new Error('cone-config: delta.effortLevel must be one of off|minimal|low|medium|high|xhigh or null');
169
109
  }
170
110
  else {
@@ -204,17 +144,11 @@ export function mergeConeConfig(base, delta) {
204
144
  /**
205
145
  * Serialize flat secrets to the `NAME=value` / `NAME_DOMAINS=a,b` line format
206
146
  * that node-server's EnvSecretStore reads. Values are written verbatim (no
207
- * escaping — matching the existing parser), so secret names must be env-var
208
- * identifiers and values/domains must be single-line (no newlines, and values
209
- * must not break `NAME=value` parsing). Callers sanitize/validate inputs.
147
+ * escaping — matching the existing parser), so entries must have passed the
148
+ * bundle validators (single-line values, comma-free domains, safe names).
210
149
  */
211
150
  export function serializeSecretsEnv(secrets) {
212
- const lines = [];
213
- for (const s of secrets) {
214
- lines.push(`${s.name}=${s.value}`);
215
- lines.push(`${s.name}_DOMAINS=${s.domains.join(',')}`);
216
- }
217
- return lines.length ? lines.join('\n') + '\n' : '';
151
+ return serializeSecretLines(secrets);
218
152
  }
219
153
  export function bundleToFiles(cfg) {
220
154
  return {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bundle-cases.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-cases.test.d.ts","sourceRoot":"","sources":["../../../tests/cone-config/bundle-cases.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { bundleToFiles, validateConeConfig, validateConeConfigDelta, } from '../../src/cone-config/index.js';
3
+ import { ACCOUNT_CASES, INVALID_EFFORT_LEVELS, SECRET_CASES, VALID_EFFORT_LEVELS, } from '../fixtures/cone-config-cases.mjs';
4
+ // The same table runs against github-workflow's buildConeConfigFiles in
5
+ // packages/github-workflow/scripts/cone-config-rules.test.mjs (#4129).
6
+ const bundle = (extra) => ({ model: 'm', accounts: [], secrets: [], ...extra });
7
+ describe('shared cone-config cases: secrets', () => {
8
+ for (const c of SECRET_CASES) {
9
+ if (c.reject) {
10
+ it(`rejects ${c.id} (bundle and resume delta)`, () => {
11
+ const re = new RegExp(c.reject);
12
+ expect(() => validateConeConfig(bundle({ secrets: [c.secret] }))).toThrow(re);
13
+ expect(() => validateConeConfigDelta({ upsert: { secrets: [c.secret] } })).toThrow(re);
14
+ });
15
+ }
16
+ else {
17
+ it(`accepts ${c.id}`, () => {
18
+ const cfg = validateConeConfig(bundle({ secrets: [c.secret] }));
19
+ const { name, value } = c.secret;
20
+ expect(cfg.secrets).toEqual([{ name, value, domains: c.domains }]);
21
+ expect(bundleToFiles(cfg).secretsEnv).toBe(`${name}=${value}\n${name}_DOMAINS=${c.domains.join(',')}\n`);
22
+ expect(validateConeConfigDelta({ upsert: { secrets: [c.secret] } }).upsert?.secrets).toEqual(cfg.secrets);
23
+ });
24
+ }
25
+ }
26
+ });
27
+ describe('shared cone-config cases: accounts', () => {
28
+ for (const c of ACCOUNT_CASES) {
29
+ if (c.reject) {
30
+ it(`rejects ${c.id}`, () => {
31
+ const re = new RegExp(c.reject);
32
+ expect(() => validateConeConfig(bundle({ accounts: [c.account] }))).toThrow(re);
33
+ expect(() => validateConeConfigDelta({ upsert: { accounts: [c.account] } })).toThrow(re);
34
+ });
35
+ }
36
+ else {
37
+ it(`accepts ${c.id}`, () => {
38
+ const [account] = validateConeConfig(bundle({ accounts: [c.account] })).accounts;
39
+ const allowed = ['providerId', 'kind', 'baseUrl'].concat(account.kind === 'oauth'
40
+ ? ['accessToken', 'refreshToken', 'tokenExpiresAt', 'userName']
41
+ : ['apiKey', 'deployment', 'apiVersion']);
42
+ for (const key of Object.keys(account))
43
+ expect(allowed).toContain(key);
44
+ });
45
+ }
46
+ }
47
+ });
48
+ describe('shared cone-config cases: effort levels', () => {
49
+ it.each(VALID_EFFORT_LEVELS)('accepts %s', (level) => {
50
+ expect(validateConeConfig(bundle({ effortLevel: level })).effortLevel).toBe(level);
51
+ expect(validateConeConfigDelta({ effortLevel: level }).effortLevel).toBe(level);
52
+ });
53
+ it.each(INVALID_EFFORT_LEVELS)('rejects %s', (level) => {
54
+ expect(() => validateConeConfig(bundle({ effortLevel: level }))).toThrow(/effortLevel/);
55
+ expect(() => validateConeConfigDelta({ effortLevel: level })).toThrow(/effortLevel/);
56
+ });
57
+ });
@@ -44,13 +44,13 @@ describe('validateConeConfig', () => {
44
44
  expect(() => validateConeConfig({ ...base, secrets: [{ name: 'X', value: 'v', domains: 'a,b' }] })).toThrow(/domains/);
45
45
  });
46
46
  it('rejects an account with a missing/invalid kind', () => {
47
- expect(() => validateConeConfig({ ...base, accounts: [{ providerId: 'x' }] })).toThrow(/kind required/);
47
+ expect(() => validateConeConfig({ ...base, accounts: [{ providerId: 'x' }] })).toThrow(/kind must be/);
48
48
  });
49
- it('rejects a secret name that is not an env-var identifier', () => {
50
- expect(() => validateConeConfig({ ...base, secrets: [{ name: 'FOO=BAR', value: 'v', domains: [] }] })).toThrow(/identifier/);
49
+ it('rejects a secret name that is not an identifier', () => {
50
+ expect(() => validateConeConfig({ ...base, secrets: [{ name: 'FOO=BAR', value: 'v', domains: ['d'] }] })).toThrow(/identifier/);
51
51
  });
52
52
  it('rejects a secret value or domain with a newline (secrets.env is line-based)', () => {
53
- expect(() => validateConeConfig({ ...base, secrets: [{ name: 'X', value: 'a\nb', domains: [] }] })).toThrow(/single-line/);
53
+ expect(() => validateConeConfig({ ...base, secrets: [{ name: 'X', value: 'a\nb', domains: ['d'] }] })).toThrow(/single-line/);
54
54
  expect(() => validateConeConfig({ ...base, secrets: [{ name: 'X', value: 'v', domains: ['a,b'] }] })).toThrow(/comma-free/);
55
55
  });
56
56
  it('accepts a config with a valid effortLevel', () => {
@@ -80,7 +80,9 @@ describe('validateConeConfigDelta', () => {
80
80
  expect(() => validateConeConfigDelta({ upsert: { accounts: 'nope' } })).toThrow(/upsert.accounts must be an array/);
81
81
  });
82
82
  it('rejects a nested secret that would inject a newline', () => {
83
- expect(() => validateConeConfigDelta({ upsert: { secrets: [{ name: 'X', value: 'a\nb', domains: [] }] } })).toThrow(/single-line/);
83
+ expect(() => validateConeConfigDelta({
84
+ upsert: { secrets: [{ name: 'X', value: 'a\nb', domains: ['d'] }] },
85
+ })).toThrow(/single-line/);
84
86
  });
85
87
  it('rejects a non-string delete.secretNames entry', () => {
86
88
  expect(() => validateConeConfigDelta({ delete: { secretNames: [1] } })).toThrow(/secretNames must be string\[\]/);
@@ -0,0 +1,37 @@
1
+ export type SecretCase = {
2
+ id: string;
3
+ secret: unknown;
4
+ reject?: string;
5
+ domains?: string[];
6
+ changed?: Array<'cloud-core' | 'github-workflow'>;
7
+ };
8
+ /**
9
+ * @typedef {{
10
+ * id: string;
11
+ * secret: unknown;
12
+ * reject?: string;
13
+ * domains?: string[];
14
+ * changed?: Array<'cloud-core' | 'github-workflow'>;
15
+ * }} SecretCase
16
+ */
17
+ /** @type {SecretCase[]} */
18
+ export declare const SECRET_CASES: SecretCase[];
19
+ export type AccountCase = {
20
+ id: string;
21
+ account: unknown;
22
+ reject?: string;
23
+ changed?: Array<'cloud-core' | 'github-workflow'>;
24
+ };
25
+ /**
26
+ * @typedef {{
27
+ * id: string;
28
+ * account: unknown;
29
+ * reject?: string;
30
+ * changed?: Array<'cloud-core' | 'github-workflow'>;
31
+ * }} AccountCase
32
+ */
33
+ /** @type {AccountCase[]} */
34
+ export declare const ACCOUNT_CASES: AccountCase[];
35
+ export declare const VALID_EFFORT_LEVELS: string[];
36
+ export declare const INVALID_EFFORT_LEVELS: string[];
37
+ //# sourceMappingURL=cone-config-cases.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cone-config-cases.d.mts","sourceRoot":"","sources":["../../../tests/fixtures/cone-config-cases.mjs"],"names":[],"mappings":"AAWG,YAMG,UAAU,GANH;IACR,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,iBAAiB,CAAC,CAAC;CACnD,CAAY;AAPhB;;;;;;;;GAQG;AAEH,2BAA2B;AAC3B,eAAO,MAAM,YAAY,EADd,UAAU,EA0DpB,CAAC;AAGC,YAKG,WAAW,GALJ;IACR,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,KAAK,CAAC,YAAY,GAAG,iBAAiB,CAAC,CAAC;CACnD,CAAa;AANjB;;;;;;;GAOG;AAEH,4BAA4B;AAC5B,eAAO,MAAM,aAAa,EADf,WAAW,EAoDrB,CAAC;AAEF,eAAO,MAAM,mBAAmB,UAAuD,CAAC;AACxF,eAAO,MAAM,qBAAqB,UAA2B,CAAC"}