sliccy 6.225.0 → 6.226.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 (164) hide show
  1. package/dist/ui/.vite/manifest.json +186 -186
  2. package/dist/ui/assets/{SKILL-nuxIaHgr.js → SKILL-BKKGj_a4.js} +1 -1
  3. package/dist/ui/assets/{SKILL-CX_QtSBf.js → SKILL-DfQfFV0B.js} +1 -1
  4. package/dist/ui/assets/{SKILL-Crh4kwn1.js → SKILL-JUdJZkmv.js} +1 -1
  5. package/dist/ui/assets/{account-store-B9PzT8eI.js → account-store-BlJDP1-W.js} +1 -1
  6. package/dist/ui/assets/{account-store-3ywe8a2_.js → account-store-Dup-dSte.js} +1 -1
  7. package/dist/ui/assets/{adobe-D5BXlgVZ.js → adobe-BkQaujbn.js} +1 -1
  8. package/dist/ui/assets/{adobe-Dt3EgBjs.js → adobe-CQvTuyh_.js} +1 -1
  9. package/dist/ui/assets/{agent-panels-DmB_osCD.js → agent-panels-e39BAcGn.js} +1 -1
  10. package/dist/ui/assets/{almost-bash-shell-headless-79jPwhlW.js → almost-bash-shell-headless-DvTsKS1v.js} +331 -331
  11. package/dist/ui/assets/{apply-layout--4EHOd9d.js → apply-layout-COKznjFL.js} +1 -1
  12. package/dist/ui/assets/{apps-CLddWOLP.js → apps-BnILH4xd.js} +1 -1
  13. package/dist/ui/assets/{azure-openai-DXBzVlza.js → azure-openai-DSN7cshd.js} +1 -1
  14. package/dist/ui/assets/{azure-openai-CLJDkE6M.js → azure-openai-DtOuOPJB.js} +1 -1
  15. package/dist/ui/assets/{backend-hostfs-BoBHdukn.js → backend-hostfs-KLShl7sQ.js} +1 -1
  16. package/dist/ui/assets/{browser-DGwroBSO.js → browser-BhTdBqdp.js} +30 -30
  17. package/dist/ui/assets/{browser-CezNe0PF.js → browser-Jlk38XAj.js} +647 -647
  18. package/dist/ui/assets/{cdp-Dx2qqXfc.js → cdp-Dxgj-kkt.js} +1 -1
  19. package/dist/ui/assets/{cerebras-Buay3zRG.js → cerebras-DaTX2QuX.js} +1 -1
  20. package/dist/ui/assets/{cerebras-nPX7yCM3.js → cerebras-uY6Xy8za.js} +1 -1
  21. package/dist/ui/assets/{composer-speech-CgekTtlY.js → composer-speech-SCKDMr4i.js} +1 -1
  22. package/dist/ui/assets/{connect-surface-BZiroW1y.js → connect-surface-BzENdoiF.js} +1 -1
  23. package/dist/ui/assets/{cost-command-D0tJNxsl.js → cost-command-C_1fldSP.js} +1 -1
  24. package/dist/ui/assets/{directed-approval-BCjQhasX.js → directed-approval-B_DRdwpJ.js} +1 -1
  25. package/dist/ui/assets/{emscripten-vfs-hook-DJD9aM5A.js → emscripten-vfs-hook-Dce5ZWJb.js} +1 -1
  26. package/dist/ui/assets/{ensure-speech-assets-orXK0kOf.js → ensure-speech-assets-DUhEO7H0.js} +1 -1
  27. package/dist/ui/assets/{frozen-archive-writer-NfsOumcA.js → frozen-archive-writer-BGB_nYip.js} +1 -1
  28. package/dist/ui/assets/fs-DKTyXngI.js +2 -0
  29. package/dist/ui/assets/fs-DwHLmdxe.js +1 -0
  30. package/dist/ui/assets/{gelatiere-store-C5DwgxZd.js → gelatiere-store-DQIudjLw.js} +1 -1
  31. package/dist/ui/assets/{gelatiere-unit-CDr_F2sT.js → gelatiere-unit-CoeN1YRk.js} +1 -1
  32. package/dist/ui/assets/{github-DvwH50B1.js → github-C_sejJLD.js} +2 -2
  33. package/dist/ui/assets/{github-qgWF_XU8.js → github-Chwcb38q.js} +1 -1
  34. package/dist/ui/assets/{github-auth-HKErWCav.js → github-auth-CyLgcuwk.js} +1 -1
  35. package/dist/ui/assets/{github-copilot-By2ccujb.js → github-copilot-DNir8nPs.js} +1 -1
  36. package/dist/ui/assets/{github-copilot-D6tc7a6A.js → github-copilot-DSF4sN0A.js} +1 -1
  37. package/dist/ui/assets/{github-install-DNZljXVG.js → github-install-CypHkXWW.js} +1 -1
  38. package/dist/ui/assets/{github-zip-Df12ZywZ.js → github-zip-DvrCoKij.js} +1 -1
  39. package/dist/ui/assets/go-driver-CYR67gv1.js +25 -0
  40. package/dist/ui/assets/{hear-Cpm3nWHt.js → hear-BYApgyRp.js} +1 -1
  41. package/dist/ui/assets/{help-DXMagb-u.js → help-BSRIYdTr.js} +1 -1
  42. package/dist/ui/assets/{host-command-guuPK7VN.js → host-command-Dn-Z4AbC.js} +1 -1
  43. package/dist/ui/assets/{installer-X4bIJM1f.js → installer-DU0Ft-ta.js} +1 -1
  44. package/dist/ui/assets/{ipk-mamba-DqGVYttY.js → ipk-mamba-BhzmAVqX.js} +1 -1
  45. package/dist/ui/assets/{js-realm-worker-DtptcoUJ.js → js-realm-worker-CMoqILM7.js} +3 -3
  46. package/dist/ui/assets/{jsh-executor-BsY_Fyzv.js → jsh-executor-BSfT4Av-.js} +2 -2
  47. package/dist/ui/assets/{kernel-worker-CWXec_cl.js → kernel-worker-jFET0gP4.js} +10 -10
  48. package/dist/ui/assets/{lick-ws-bridge-C75psYB7.js → lick-ws-bridge-Bzqf-vDY.js} +1 -1
  49. package/dist/ui/assets/{lick-ws-bridge-CP0hY9cj.js → lick-ws-bridge-EXboAIWs.js} +1 -1
  50. package/dist/ui/assets/{live-session-curation-CQL7pI9d.js → live-session-curation-9JOZOk__.js} +1 -1
  51. package/dist/ui/assets/{live-session-snapshot-B5PoU89u.js → live-session-snapshot-lb3l3-2i.js} +1 -1
  52. package/dist/ui/assets/{local-llm-C7qZeRiv.js → local-llm-DPdTCBrf.js} +1 -1
  53. package/dist/ui/assets/{local-llm-FdvDyXqX.js → local-llm-DeEO_kWk.js} +1 -1
  54. package/dist/ui/assets/{main-BXY446OG.js → main-D4T6A3x0.js} +3 -3
  55. package/dist/ui/assets/{main-cherry-D3TvMfQh.js → main-cherry-CbSGyKQc.js} +1 -1
  56. package/dist/ui/assets/{memory-curation-seam-B9NMXo0s.js → memory-curation-seam-D86YzTcB.js} +1 -1
  57. package/dist/ui/assets/{memory-health-eJcGCD9X.js → memory-health-CRaGX9nB.js} +1 -1
  58. package/dist/ui/assets/{memory-write-execute-C0I3lkYQ.js → memory-write-execute-DWf8irl0.js} +1 -1
  59. package/dist/ui/assets/{merge-folded-cost-into-frozen-CZLnDZJE.js → merge-folded-cost-into-frozen-Bu65Q9Cg.js} +1 -1
  60. package/dist/ui/assets/{mount-BUS2m8lX.js → mount-D8OdNZ70.js} +1 -1
  61. package/dist/ui/assets/{mount-CAbmaXyj.js → mount-Dvq41z85.js} +3 -3
  62. package/dist/ui/assets/{new-session-DIBXrrZW.js → new-session-pIOo08ug.js} +2 -2
  63. package/dist/ui/assets/{oauth-bootstrap-HPCrY6da.js → oauth-bootstrap-hI54waCl.js} +2 -2
  64. package/dist/ui/assets/{onboarding-orchestrator-DYVgFzuM.js → onboarding-orchestrator-C7IPNkaS.js} +1 -1
  65. package/dist/ui/assets/{openai-codex-Do2Vyd81.js → openai-codex-4RG71-r1.js} +1 -1
  66. package/dist/ui/assets/{openai-codex-CWk5tY4u.js → openai-codex-Co8hzNYp.js} +1 -1
  67. package/dist/ui/assets/{openrouter-gjyR9WCp.js → openrouter-BQpYDJi3.js} +1 -1
  68. package/dist/ui/assets/{openrouter-DSzuA9mF.js → openrouter-Czqj8XpT.js} +1 -1
  69. package/dist/ui/assets/{openrouter-free-D7E3WMsO.js → openrouter-free-BEKVrg00.js} +1 -1
  70. package/dist/ui/assets/{openrouter-free-CQXsM-p7.js → openrouter-free-ZF0WQe1F.js} +1 -1
  71. package/dist/ui/assets/{openrouter-oauth-CGuS1tZQ.js → openrouter-oauth-BDLDVcec.js} +1 -1
  72. package/dist/ui/assets/{openrouter-oauth-BxtLREG-.js → openrouter-oauth-Bvj7wwNp.js} +1 -1
  73. package/dist/ui/assets/{opfs-mount-D3OJjsnE.js → opfs-mount-CkEPMeKd.js} +1 -1
  74. package/dist/ui/assets/{panel-rpc-handlers-Bofv8JhK.js → panel-rpc-handlers-BIaCpUWF.js} +2 -2
  75. package/dist/ui/assets/{panelize-shell-Cm2ojuvI.js → panelize-shell-ZDSWSUaz.js} +1 -1
  76. package/dist/ui/assets/{pi-edit-execution-D4s9pcHk.js → pi-edit-execution-Dxz6tqcr.js} +1 -1
  77. package/dist/ui/assets/{process-worker-CoJic0og.js → process-worker-COJhrHY2.js} +1 -1
  78. package/dist/ui/assets/{provider-BqAxwdti.js → provider-8d5bGvbc.js} +1 -1
  79. package/dist/ui/assets/{provider-DOJ85f1f.js → provider-C3R_g8Ig.js} +2 -2
  80. package/dist/ui/assets/{provider-settings-brukJESh.js → provider-settings-DUOh4hPx.js} +1 -1
  81. package/dist/ui/assets/provider-store-access-D4qzS4fC.js +1 -0
  82. package/dist/ui/assets/provider-store-access-DEvTyUN8.js +1 -0
  83. package/dist/ui/assets/{providers-jItvnenf.js → providers-CqM86e9A.js} +2 -2
  84. package/dist/ui/assets/{providers-ymrZXUAC.js → providers-fZ3KX8Lg.js} +1 -1
  85. package/dist/ui/assets/{quick-llm-Cz68lQP1.js → quick-llm-Do6-ghEG.js} +1 -1
  86. package/dist/ui/assets/{realm-inprocess-COgufIL2.js → realm-inprocess-BYC0jsGK.js} +3 -3
  87. package/dist/ui/assets/{realm-unhandled-rejections-CRza0ZaP.js → realm-unhandled-rejections-DGcjCfBE.js} +1 -1
  88. package/dist/ui/assets/{realm-unhandled-rejections-DErM2nJM.js → realm-unhandled-rejections-ZGmUnuk3.js} +1 -1
  89. package/dist/ui/assets/{recovery-screen-Bn1JfO8r.js → recovery-screen-J3LoIlFr.js} +1 -1
  90. package/dist/ui/assets/{remote-terminal-view-BtAyMABU.js → remote-terminal-view-_0YIhuqT.js} +3 -3
  91. package/dist/ui/assets/{restore-B5gjCx9g.js → restore-DHQi2wzK.js} +1 -1
  92. package/dist/ui/assets/{run-yUDNFMnf.js → run-B39tlo9Y.js} +1 -1
  93. package/dist/ui/assets/{run-DWH3xEl9.js → run-BUv3t71i.js} +1 -1
  94. package/dist/ui/assets/{run-Dei6hnFk.js → run-BhlaKL0o.js} +1 -1
  95. package/dist/ui/assets/{run-BB6jekYX.js → run-CB-l85sr.js} +2 -2
  96. package/dist/ui/assets/{run-C_B85hI0.js → run-CGZiR3xh.js} +1 -1
  97. package/dist/ui/assets/{run-D7KFxRYl.js → run-CT78CmeE.js} +1 -1
  98. package/dist/ui/assets/{run-C-wFOiGB.js → run-EPiuw1ru.js} +1 -1
  99. package/dist/ui/assets/{run-DhNCSo3v.js → run-_oGn-1AP.js} +1 -1
  100. package/dist/ui/assets/{run-BLIuToUE.js → run-aUbSngAa.js} +2 -2
  101. package/dist/ui/assets/{run-bkB7vq8y.js → run-uFO4egDg.js} +2 -2
  102. package/dist/ui/assets/{session-command-memory-NRdUnJyj.js → session-command-memory-n0b0bNTG.js} +2 -2
  103. package/dist/ui/assets/{session-jsonl-B6Ho_zgX.js → session-jsonl-BNQAPUiL.js} +1 -1
  104. package/dist/ui/assets/{session-jsonl-CjSE9LNe.js → session-jsonl-Dm2yw6F9.js} +1 -1
  105. package/dist/ui/assets/{session-search-index-CFeXumM6.js → session-search-index-DW9ma2yj.js} +1 -1
  106. package/dist/ui/assets/{setup-feature-flags-remote-DjrixOzh.js → setup-feature-flags-remote-D2waO-r4.js} +1 -1
  107. package/dist/ui/assets/{setup-model-catalog-B7eloJVP.js → setup-model-catalog-W9d0IwmJ.js} +1 -1
  108. package/dist/ui/assets/{signed-fetch-_L4sYbu4.js → signed-fetch-CIdxcCyT.js} +1 -1
  109. package/dist/ui/assets/{silent-renew-backoff-Bh6I1aDv.js → silent-renew-backoff-CKXdzlDo.js} +1 -1
  110. package/dist/ui/assets/slicc-version-fbt_Uj4l.js +1 -0
  111. package/dist/ui/assets/{snapshot-BGWKU3et.js → snapshot-KIIqV7oO.js} +1 -1
  112. package/dist/ui/assets/{snapshot-features-FhbQCRnw.js → snapshot-features-BLo8PAIz.js} +1 -1
  113. package/dist/ui/assets/{soundscape-BW5ut_iJ.js → soundscape-DzqywR3L.js} +1 -1
  114. package/dist/ui/assets/{speak-Bmu8NDTG.js → speak-Ck3_PA-W.js} +1 -1
  115. package/dist/ui/assets/{sprinkle-manager-DVk6M9Rk.js → sprinkle-manager-BeKUo2tm.js} +1 -1
  116. package/dist/ui/assets/{sprinkle-renderer-CHK6oQtb.js → sprinkle-renderer-CRyiQKjI.js} +1 -1
  117. package/dist/ui/assets/{ssh-CO09HVge.js → ssh-G5JZ2uyy.js} +1 -1
  118. package/dist/ui/assets/{state-y2e6wllb.js → state-BWDzjtHj.js} +1 -1
  119. package/dist/ui/assets/{store-DtAeQGIz.js → store-Czn1xbby.js} +1 -1
  120. package/dist/ui/assets/{store-CDeOYaBW.js → store-DNedyI8F.js} +1 -1
  121. package/dist/ui/assets/{sudo-CQLd4Bl9.js → sudo-qoInIpBO.js} +1 -1
  122. package/dist/ui/assets/{supervisor-DkKGobyK.js → supervisor-Jdju-S84.js} +1 -1
  123. package/dist/ui/assets/{sync-dialog-Bh1EodAD.js → sync-dialog-D7E1y2Ec.js} +1 -1
  124. package/dist/ui/assets/{transformers-env-DTWLfzlp.js → transformers-env-BWQg6iPs.js} +1 -1
  125. package/dist/ui/assets/{tray-leader--CfpbuW8.js → tray-leader-CGgHEzgP.js} +1 -1
  126. package/dist/ui/assets/{tray-leave-runtime-28mAhHhD.js → tray-leave-runtime-BBUcylR0.js} +1 -1
  127. package/dist/ui/assets/{tray-sidecar-p1yODGNz.js → tray-sidecar-B3vE5G1l.js} +1 -1
  128. package/dist/ui/assets/{upgrade-detection-Dmhf7Nhj.js → upgrade-detection-RbwMSxeX.js} +1 -1
  129. package/dist/ui/assets/{upskill-lick-skip-DQKYUQVD.js → upskill-lick-skip-C0iou2rp.js} +1 -1
  130. package/dist/ui/assets/{voice-reply-Bpj7QzL2.js → voice-reply-Bj1CpSf6.js} +1 -1
  131. package/dist/ui/assets/{wasi-runtime-D8RXmh55.js → wasi-runtime-CelptKxl.js} +3 -3
  132. package/dist/ui/assets/{wc-attach-CA28MRxX.js → wc-attach-B631REQc.js} +2 -2
  133. package/dist/ui/assets/{wc-browser-BZtbDGhF.js → wc-browser-KZbo8H3B.js} +1 -1
  134. package/dist/ui/assets/{wc-computers-DtzRlq6F.js → wc-computers-Deq0yXKO.js} +1 -1
  135. package/dist/ui/assets/{wc-detached-BRsCaIPp.js → wc-detached-9lhlXJPy.js} +1 -1
  136. package/dist/ui/assets/{wc-extension-D7fqQjyL.js → wc-extension-CKQerQPt.js} +2 -2
  137. package/dist/ui/assets/{wc-follower-DxV30XGh.js → wc-follower-DP10htl7.js} +3 -3
  138. package/dist/ui/assets/{wc-follower-oauth-C61uIB4e.js → wc-follower-oauth-ANEiGFkZ.js} +1 -1
  139. package/dist/ui/assets/{wc-gelatiere-mobAq65d.js → wc-gelatiere-DsVbjYHN.js} +1 -1
  140. package/dist/ui/assets/{wc-live-B3jtLLs9.js → wc-live-BWEChou-.js} +5 -5
  141. package/dist/ui/assets/{wc-nav-CGonUHTP.js → wc-nav-Bu0rCT1z.js} +2 -2
  142. package/dist/ui/assets/{wc-onboarding-BRxZeBkv.js → wc-onboarding-L8z2-1Ld.js} +2 -2
  143. package/dist/ui/assets/{wc-permissions-zTnYToAy.js → wc-permissions-Dz0I-zKu.js} +2 -2
  144. package/dist/ui/assets/{wc-placeholder-Cpnl-PaY.js → wc-placeholder-BTHzaZLv.js} +3 -3
  145. package/dist/ui/assets/{wc-secret-request-Cn3LZ0up.js → wc-secret-request-D6rDxI6g.js} +1 -1
  146. package/dist/ui/assets/{wc-settings-CSRgqHvg.js → wc-settings-DFhVBdll.js} +3 -3
  147. package/dist/ui/assets/{wc-shell-CxtTdVy3.js → wc-shell-Dh9k1nMd.js} +3 -3
  148. package/dist/ui/assets/{wc-shortcut-config-DdT46qXy.js → wc-shortcut-config-Bb94V6Av.js} +1 -1
  149. package/dist/ui/assets/{wc-sprinkles-PxjOzqYq.js → wc-sprinkles-BkAJcrnZ.js} +2 -2
  150. package/dist/ui/assets/{wc-transcript-export-D72PCnL5.js → wc-transcript-export-Bh3AZeXa.js} +2 -2
  151. package/dist/ui/assets/{wc-tray-CxWsACi9.js → wc-tray-DyBz3iBQ.js} +4 -4
  152. package/dist/ui/assets/welcome-detection-C4RN_MWp.js +1 -0
  153. package/dist/ui/assets/{whisper-session-CZwhv0Wc.js → whisper-session-DTRVaIcc.js} +2 -2
  154. package/dist/ui/assets/{xai-grok-CxuLkPqx.js → xai-grok-DEqHFn_v.js} +1 -1
  155. package/dist/ui/assets/{xai-grok-np6-cgG6.js → xai-grok-HD2wS7Sr.js} +1 -1
  156. package/dist/ui/index.html +3 -3
  157. package/dist/ui/packages/webapp/index.html +3 -3
  158. package/package.json +1 -1
  159. package/dist/ui/assets/fs-BsEI-Bub.js +0 -2
  160. package/dist/ui/assets/fs-mhrvMMpU.js +0 -1
  161. package/dist/ui/assets/provider-store-access-CT0Nt_Gs.js +0 -1
  162. package/dist/ui/assets/provider-store-access-Dat8JYid.js +0 -1
  163. package/dist/ui/assets/slicc-version-BMVEF0eF.js +0 -1
  164. package/dist/ui/assets/welcome-detection-DNl0QXNj.js +0 -1
@@ -1 +1 @@
1
- var e='---\nname: mount\ndescription: |\n Use this whenever the user asks to mount anything — local folders, S3\n buckets, S3-compatible services (Cloudflare R2, MinIO), or Adobe da.live\n / AEM Document Authoring repos. Read this skill BEFORE deciding which\n backend to use; do NOT default to a local file picker when the user\n names a remote service. Covers credential setup with profile-namespaced\n `secret set` keys (e.g. `s3.aws.access_key_id`) or the extension Options\n page, the right `mount --source` invocation per intent, `mount info` for\n probed case/Unicode/exec-bit semantics, and common errors (EACCES on\n missing credentials, EBUSY on concurrent edits, EFBIG on oversized files).\nallowed-tools: bash, read_file, write_file, edit\n---\n\n# Mount\n\nThe `mount` shell command bridges remote storage into the VFS. After mounting, `read_file`, `write_file`, `edit`, and `bash` (with `cat`, `ls`, etc.) all work against the remote source as if it were a local directory. Four backends the command itself mounts, plus host folders the launcher already mounted:\n\n| Backend | Source URI | Auth |\n| ------- | ----------------------------- | ------------------------------------------------------ |\n| Local | (no `--source`) | OS file picker — cone-only, fails in scoops |\n| Host | (launcher mount table) | Already mounted — do not picker-mount over it |\n| S3 | `s3://<bucket>[/<prefix>]` | Profile-namespaced secrets (`s3.<profile>.*`) |\n| DA | `da://<org>/<repo>[/<path>]` | Adobe IMS bearer (reuses the Adobe LLM provider login) |\n| AEM | `aem://<org>/<site>[/<path>]` | Adobe IMS bearer (same login as DA) |\n\nA launcher mount-table entry (`--mount` / Sliccstart Settings → Mounts) is already at its target when the cone starts. `mount list` shows it as `hostfs://<os-path>`. Do not `mount <that-path>` over it. A picker mount on a table target is replaced by the host folder; picker mounts at other paths stay.\n\n## Choosing a backend from user intent\n\nWhen the user asks to "mount X", read the request literally before defaulting to local:\n\n| User says | Use this backend |\n| -------------------------------------------------- | ------------------------------------------------------- |\n| "mount my Documents folder" / "mount /tmp" | Local — `mount /mnt/documents` |\n| "mount this S3 bucket: s3://my-bucket/foo" | S3 — `mount --source s3://my-bucket/foo /mnt/s3` |\n| "mount this R2 bucket" | S3 with a custom-endpoint profile (R2 is S3-compatible) |\n| "mount the AEM DA repo for org/site" | DA — `mount --source da://<org>/<site> /mnt/da` |\n| "mount this Adobe DA project" / "mount da.live" | DA |\n| "mount this Helix 6 site" / "mount the Source Bus" | AEM — `mount --source aem://<org>/<site> /mnt/aem` |\n| "mount this S3-compatible storage" (MinIO, etc.) | S3 with a custom-endpoint profile |\n\nIf the URL scheme is `s3://`, `da://`, or `aem://`, the choice is unambiguous — don\'t ask. If the user gives a hostname or describes a service without a URL, ask one specific clarifying question (e.g. "Is this the AEM Document Authoring service at da.live, or a different system?") rather than offering a menu of generic options.\n\n**Don\'t default to local when the user mentions a remote service name.**\n\n### DA or AEM? You don\'t have to know — but read the mount output\n\nA site upgraded to the Helix 6 architecture keeps its `da.live` authoring UI and its `<org>/<site>` name, but its content moves to the Source Bus on `api.aem.live`. `da://` handles this for you: it probes the site config before mounting and re-routes to the Source Bus when that is where the content lives, printing a note on stderr. So `mount --source da://<org>/<site>` is always safe to reach for.\n\nTwo things follow:\n\n- **Read the stderr note.** `mount: <org>/<site> is on Helix 6 …` means the mount landed on `aem://` — that is correct, not a warning to work around.\n- **A `da://` mount can now fail with `could not determine the content source`.** That means the site config was unreadable (usually: no Adobe login), not that the site is missing. Fix the login, or pass `--backend da` / `--backend aem` if you already know which store holds the content. Don\'t retry the same command hoping for a different answer.\n\n## Setting up credentials before the first mount\n\n### S3 / R2 / MinIO\n\nS3 mounts read credentials from profile-namespaced secrets. Set them via the `secret` command before mounting. The agent never sees real secret values; only the server-side sign-and-forward handler does.\n\n```bash\n# AWS S3 (default profile)\nsecret set s3.default.access_key_id AKIA... --domain "*.amazonaws.com"\nsecret set s3.default.secret_access_key ... --domain "*.amazonaws.com"\nsecret set s3.default.region us-east-1 --domain "*.amazonaws.com"\n\n# Cloudflare R2 (uses a custom endpoint, requires path-style addressing for some setups)\nsecret set s3.r2.access_key_id ... --domain "*.r2.cloudflarestorage.com"\nsecret set s3.r2.secret_access_key ... --domain "*.r2.cloudflarestorage.com"\nsecret set s3.r2.endpoint https://<account>.r2.cloudflarestorage.com --domain "*.r2.cloudflarestorage.com"\n# Optional — only set this if R2 returns "Bucket name was not in expected format" at first read:\nsecret set s3.r2.path_style true --domain "*.r2.cloudflarestorage.com"\n```\n\nPer-profile keys: `access_key_id` and `secret_access_key` are required; `region` (default `us-east-1`), `endpoint` (custom host for R2/MinIO), `session_token` (for STS), and `path_style` (`"true"` for path-style addressing) are optional.\n\nIn **CLI / Electron mode** secrets live in `~/.slicc/secrets.env` (or macOS Keychain via swift-server). In **extension mode** they live in `chrome.storage.local` and the `secret` command writes to it directly.\n\n### Adobe da.live and AEM Source Bus\n\nDA and AEM mounts both use the Adobe IMS bearer token from the existing Adobe LLM provider — there are no DA-specific secrets to set. **If the user has not logged into the Adobe LLM provider yet, the first mount will fail with `EACCES`. Tell them to log in via Settings → Providers → Adobe (or run `oauth-token adobe`) first.**\n\n## Mounting\n\n```bash\n# Local (interactive picker, cone only)\nmount /mnt/local\n\n# S3 — bucket + optional prefix\nmount --source s3://my-bucket /mnt/s3\nmount --source s3://my-bucket/site --profile aws /mnt/aws\n\n# Cloudflare R2 — same s3:// scheme, different profile (custom endpoint)\nmount --source s3://my-r2-bucket/path --profile r2 /mnt/r2\n\n# Adobe da.live — org + repo (probes the site config, re-routes if Helix 6)\nmount --source da://my-org/my-repo /mnt/da\n\n# AEM Helix 6 Source Bus — org + site, no probe needed\nmount --source aem://my-org/my-site /mnt/aem\n```\n\nUseful flags:\n\n- `--profile <name>` — selects which `s3.<profile>.*` keys to use (S3 only). Defaults to `default`.\n- `--backend <da|aem>` — force the Adobe backend instead of probing the site config. Reach for it only when the probe fails or you know it is wrong.\n- `--no-probe` — skip the mount-time `HEAD bucket` / `GET /list` probe. Use when you want the mount to land even if the source is temporarily unreachable; first read/write will surface any auth errors instead. It does **not** skip the `da://` content-source probe.\n- `--max-body-mb <n>` — override the per-mount body-size limit. Defaults: S3 25 MB, DA/AEM 5 MB. Files exceeding this throw `EFBIG` before bytes flow.\n\n## Lifecycle\n\n```bash\nmount list # show all active mounts\nmount --list # same as `mount list` (`-l` also works)\nmount info /tmp # probe case / Unicode / exec-bit / name semantics\nmount info --json /mnt/kb # same report as JSON (the programmatic form)\nmount unmount /mnt/r2 # tear down (cache stays for next mount within TTL)\numount /mnt/r2 # alias for `mount unmount` (same flags, same exit codes)\nmount unmount --clear-cache /mnt/r2 # tear down + drop cached listings/bodies\nmount refresh /mnt/r2 # re-walk the source and diff against cache\nmount refresh --bodies /mnt/r2 # also conditionally re-fetch changed bodies\n```\n\n`umount <path>` is a plain alias for `mount unmount <path>` — same parser, same `--clear-cache`, same exit codes; only the error prefix says `umount:`. Use whichever spelling the user typed. Unmounting a path that is not mounted is a no-op (not an error) under both.\n\n### `mount info` — ask before assuming names are unique\n\nTwo mounts in one runtime can disagree about identity. MEASURED: `/tmp` is case-sensitive and byte-exact; a macOS APFS hostfs mount (`/mnt/kb`) is case- **and** Unicode-normalization-insensitive. `ls` / `exists` / `read_file` will resolve `SLICC.md` to `Slicc.md` on the latter, and an NFC spelling of an NFD-stored name. **Do not discover this by renaming.** A rename between two names the volume considers equal has truncated files (#3107). Ask instead:\n\n```bash\nmount info --json /mnt/kb\n```\n\nThe report is probed (scratch file, stat back, always cleaned up), not declared from `diskutil`. Fields: `caseSensitivity`, `unicodeNormalization` (`byte-exact` vs `insensitive`), `unicodeStorage` (`nfc` / `nfd` / `as-written`), `executableBit`, `namesRoundTripByteExact`, `maxFilenameLength`, `writable`, `hostBacked`. If `unicodeNormalization` is `insensitive` or `caseSensitivity` is `insensitive`, compare names by folding case and NFC — do not treat a case/Unicode mismatch as a missing file, and do not rename one spelling onto the other.\n\nBuilt-in VFS paths such as `/tmp` support executable bits through `chmod`.\nMounted sources report the capability their bridge implements; the host disk\'s\ncapabilities alone do not imply that the mounted metadata operation is supported.\n\n`mount refresh` prints a structured summary: `Refreshed /mnt/r2: +2 -1 ~3 (47 unchanged, 0 errors)`. Use it after you know the remote changed externally and you want the local view to catch up before the 30 s TTL expires. On hostfs the same form applies: a populated idle tree reports a non-zero `unchanged` count of files checked (not `0 unchanged`), so exit 0 plus counts is evidence the walk ran.\n\n## Index state and bounds (`mount list`)\n\nEach mount is indexed in the background for fast file discovery and listings; `mount list` shows each mount\'s index state. The walk is bounded — defaults (raised 10×): max directory depth **400**, max total entries **2,000,000**. Two env vars override them: `SLICC_MOUNT_INDEX_MAX_DEPTH` and `SLICC_MOUNT_INDEX_MAX_ENTRIES` (an invalid value falls back to the default with a warning).\n\nWhen a bound is hit the index is **skipped** (reads still work via the slow fallback) and `mount list` shows a distinct cause, so advise the right remedy:\n\n- `directory nesting exceeded the depth limit` → raise `SLICC_MOUNT_INDEX_MAX_DEPTH` or unmount.\n- `mounted tree is too large` → raise `SLICC_MOUNT_INDEX_MAX_ENTRIES` or unmount (this is **not** a cycle).\n- `self-referential mount cycle detected` → a real, confirmed cycle; unmount it.\n- `index error: <message>` → any other indexing failure.\n\nDon\'t call a large or deep mount "cyclic" — only `self-referential mount cycle detected` means a true self-reference.\n\n## Reading and writing once mounted\n\nTreat the mount path like any other VFS directory:\n\n```bash\nls /mnt/da\nread_file /mnt/da/index.html\nwrite_file /mnt/da/new-page.html "<html>..."\nedit /mnt/da/index.html # via the standard edit tool\nrm /mnt/da/old.html\n```\n\nReads and writes use TTL + ETag caching (30 s default). Reads are zero-RTT within TTL. Writes use `If-Match` / `If-None-Match: *` for conflict detection.\n\nOn an AEM (Source Bus) mount there are no ETags — the API exposes only `last-modified` — so conflict detection uses modification time and only covers files you read first. A blind `write_file` to a path you never read will overwrite whatever is there. Read before you write on `aem://` mounts.\n\n## Common error patterns\n\n| Error | What it means |\n| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `mount: probe failed for s3://… — profile \'aws\' missing required field \'access_key_id\'.` | The user hasn\'t set credentials yet. Walk them through `secret set s3.<profile>.*`. |\n| `EACCES: s3 access denied` | Wrong credentials, wrong region, or the bucket policy denies the user. |\n| `EACCES: da access denied` / `EACCES: aem access denied` | IMS token expired or user not authed against the Adobe provider. |\n| `mount: could not determine the content source for da://…` | The site config probe failed — usually no Adobe login. Fix the login, or pass `--backend da` / `--backend aem`. Don\'t just retry. |\n| `EBUSY: remote modified since last read — re-read and retry` | Concurrent writer changed the file. Re-read with `read_file` and retry the edit. |\n| `EFBIG: body exceeds maxBodyBytes` | File is over the per-mount size limit (S3 25 MB, DA/AEM 5 MB). Use shell tools (`aws s3 cp`) for very large files instead, or pass `--max-body-mb <n>` at mount time. |\n| `mount: cannot mount local directories from a scoop (no UI).` | Local mounts need a user gesture. Either ask the cone to mount, or use S3/DA which work in scoops. |\n| `EXDEV: cannot create a symlink across a mount boundary` | `ln -s /mnt/… <vfs-path>` cannot create a real link (mount backends have no symlink inode). Use the mount path, or copy. Do not retry — it will not become a link. |\n\n## When asked to "explore" a mounted DA or S3 source\n\nAfter mounting, prefer `bash: ls` over `read_file` for navigation — it\'s instant within the TTL window because the listing is cached. Only `read_file` files you actually intend to read; every read is a network round-trip on the first call.\n\nFor DA specifically: the `/list` endpoint doesn\'t include file sizes, so `ls -l` triggers one HEAD per file the first time, then caches. Subsequent `ls -l` within 30 s is free.\n\nFor AEM: listings _do_ carry size and mtime, so `ls -l` costs one listing and no per-file round-trips. The size shown is the stored (compressed) size until the file has been read, so it can be well under what `read_file` returns. Empty folders don\'t exist on the Source Bus — a directory disappears when its last file is deleted.\n\n## Don\'t\n\n- Don\'t suggest the user install a separate AWS CLI / da.live SDK — `mount` is the integration point.\n- Don\'t try to `cd` into a remote mount before mounting; `bash`\'s working directory is independent of mount setup.\n- Don\'t ask "do you have credentials" if the user has already named a service — try the mount first, surface the actionable error from the probe, and walk them through the specific `secret set` commands.\n- Don\'t work around a `could not determine the content source` failure by switching to `--no-probe` — that flag doesn\'t skip the content-source probe, and the failure is telling you the login is missing.\n- Don\'t fall back to a local mount if the user mentioned a remote service. Default to clarifying which remote backend, not which directory to pick.\n- Don\'t rename a file to change only case or Unicode form until `mount info` says the volume is byte-exact. On an insensitive mount that is the #3107 truncate.\n- Don\'t `ln -s` a mounted path onto `/tmp`, `/shared`, or any other VFS path to alias it. That is `EXDEV` (#3311); use the mount path or copy.\n- Don\'t `mount` a path that `mount list` already shows as `hostfs://`. The launcher mount table owns that target.\n';export{e as default};
1
+ var e='---\nname: mount\ndescription: |\n Use this whenever the user asks to mount anything — local folders, S3\n buckets, S3-compatible services (Cloudflare R2, MinIO), or Adobe da.live\n / AEM Document Authoring repos. Read this skill BEFORE deciding which\n backend to use; do NOT default to a local file picker when the user\n names a remote service. Covers credential setup with profile-namespaced\n `secret set` keys (e.g. `s3.aws.access_key_id`) or the extension Options\n page, the right `mount --source` invocation per intent, `mount info` for\n probed case/Unicode/exec-bit semantics, and common errors (EACCES on\n missing credentials, EBUSY on concurrent edits, EFBIG on oversized files).\nallowed-tools: bash, read_file, write_file, edit\n---\n\n# Mount\n\nThe `mount` shell command bridges remote storage into the VFS. After mounting, `read_file`, `write_file`, `edit`, and `bash` (with `cat`, `ls`, etc.) all work against the remote source as if it were a local directory. Four backends the command itself mounts, plus host folders the launcher already mounted:\n\n| Backend | Source URI | Auth |\n| ------- | ----------------------------- | ------------------------------------------------------ |\n| Local | (no `--source`) | OS file picker — cone-only, fails in scoops |\n| Host | (launcher mount table) | Already mounted — do not picker-mount over it |\n| S3 | `s3://<bucket>[/<prefix>]` | Profile-namespaced secrets (`s3.<profile>.*`) |\n| DA | `da://<org>/<repo>[/<path>]` | Adobe IMS bearer (reuses the Adobe LLM provider login) |\n| AEM | `aem://<org>/<site>[/<path>]` | Adobe IMS bearer (same login as DA) |\n\nA launcher mount-table entry (`--mount` / Sliccstart Settings → Mounts) is already at its target when the cone starts. `mount list` shows it as `hostfs://<os-path>`. Do not `mount <that-path>` over it. A picker mount on a table target is replaced by the host folder; picker mounts at other paths stay.\n\n## Choosing a backend from user intent\n\nWhen the user asks to "mount X", read the request literally before defaulting to local:\n\n| User says | Use this backend |\n| -------------------------------------------------- | ------------------------------------------------------- |\n| "mount my Documents folder" / "mount /tmp" | Local — `mount /mnt/documents` |\n| "mount this S3 bucket: s3://my-bucket/foo" | S3 — `mount --source s3://my-bucket/foo /mnt/s3` |\n| "mount this R2 bucket" | S3 with a custom-endpoint profile (R2 is S3-compatible) |\n| "mount the AEM DA repo for org/site" | DA — `mount --source da://<org>/<site> /mnt/da` |\n| "mount this Adobe DA project" / "mount da.live" | DA |\n| "mount this Helix 6 site" / "mount the Source Bus" | AEM — `mount --source aem://<org>/<site> /mnt/aem` |\n| "mount this S3-compatible storage" (MinIO, etc.) | S3 with a custom-endpoint profile |\n\nIf the URL scheme is `s3://`, `da://`, or `aem://`, the choice is unambiguous — don\'t ask. If the user gives a hostname or describes a service without a URL, ask one specific clarifying question (e.g. "Is this the AEM Document Authoring service at da.live, or a different system?") rather than offering a menu of generic options.\n\n**Don\'t default to local when the user mentions a remote service name.**\n\n### DA or AEM? You don\'t have to know — but read the mount output\n\nA site upgraded to the Helix 6 architecture keeps its `da.live` authoring UI and its `<org>/<site>` name, but its content moves to the Source Bus on `api.aem.live`. `da://` handles this for you: it probes the site config before mounting and re-routes to the Source Bus when that is where the content lives, printing a note on stderr. So `mount --source da://<org>/<site>` is always safe to reach for.\n\nTwo things follow:\n\n- **Read the stderr note.** `mount: <org>/<site> is on Helix 6 …` means the mount landed on `aem://` — that is correct, not a warning to work around.\n- **A `da://` mount can now fail with `could not determine the content source`.** That means the site config was unreadable (usually: no Adobe login), not that the site is missing. Fix the login, or pass `--backend da` / `--backend aem` if you already know which store holds the content. Don\'t retry the same command hoping for a different answer.\n\n## Setting up credentials before the first mount\n\n### S3 / R2 / MinIO\n\nS3 mounts read credentials from profile-namespaced secrets. Set them via the `secret` command before mounting. The agent never sees real secret values; only the server-side sign-and-forward handler does.\n\n```bash\n# AWS S3 (default profile)\nsecret set s3.default.access_key_id AKIA... --domain "*.amazonaws.com"\nsecret set s3.default.secret_access_key ... --domain "*.amazonaws.com"\nsecret set s3.default.region us-east-1 --domain "*.amazonaws.com"\n\n# Cloudflare R2 (uses a custom endpoint, requires path-style addressing for some setups)\nsecret set s3.r2.access_key_id ... --domain "*.r2.cloudflarestorage.com"\nsecret set s3.r2.secret_access_key ... --domain "*.r2.cloudflarestorage.com"\nsecret set s3.r2.endpoint https://<account>.r2.cloudflarestorage.com --domain "*.r2.cloudflarestorage.com"\n# Optional — only set this if R2 returns "Bucket name was not in expected format" at first read:\nsecret set s3.r2.path_style true --domain "*.r2.cloudflarestorage.com"\n```\n\nPer-profile keys: `access_key_id` and `secret_access_key` are required; `region` (default `us-east-1`), `endpoint` (custom host for R2/MinIO), `session_token` (for STS), and `path_style` (`"true"` for path-style addressing) are optional.\n\nIn **CLI / Electron mode** secrets live in `~/.slicc/secrets.env` (or macOS Keychain via swift-server). In **extension mode** they live in `chrome.storage.local` and the `secret` command writes to it directly.\n\n### Adobe da.live and AEM Source Bus\n\nDA and AEM mounts both use the Adobe IMS bearer token from the existing Adobe LLM provider — there are no DA-specific secrets to set. **If the user has not logged into the Adobe LLM provider yet, the first mount will fail with `EACCES`. Tell them to log in via Settings → Providers → Adobe (or run `oauth-token adobe`) first.**\n\n## Mounting\n\n```bash\n# Local (interactive picker, cone only)\nmount /mnt/local\n\n# S3 — bucket + optional prefix\nmount --source s3://my-bucket /mnt/s3\nmount --source s3://my-bucket/site --profile aws /mnt/aws\n\n# Cloudflare R2 — same s3:// scheme, different profile (custom endpoint)\nmount --source s3://my-r2-bucket/path --profile r2 /mnt/r2\n\n# Adobe da.live — org + repo (probes the site config, re-routes if Helix 6)\nmount --source da://my-org/my-repo /mnt/da\n\n# AEM Helix 6 Source Bus — org + site, no probe needed\nmount --source aem://my-org/my-site /mnt/aem\n```\n\nUseful flags:\n\n- `--profile <name>` — selects which `s3.<profile>.*` keys to use (S3 only). Defaults to `default`.\n- `--backend <da|aem>` — force the Adobe backend instead of probing the site config. Reach for it only when the probe fails or you know it is wrong.\n- `--no-probe` — skip the mount-time `HEAD bucket` / `GET /list` probe. Use when you want the mount to land even if the source is temporarily unreachable; first read/write will surface any auth errors instead. It does **not** skip the `da://` content-source probe.\n- `--max-body-mb <n>` — override the per-mount body-size limit. Defaults: S3 25 MB, DA/AEM 5 MB. Files exceeding this throw `EFBIG` before bytes flow.\n\n## Lifecycle\n\n```bash\nmount list # show all active mounts\nmount --list # same as `mount list` (`-l` also works)\nmount info /tmp # probe case / Unicode / exec-bit / name semantics\nmount info --json /mnt/kb # same report as JSON (the programmatic form)\nmount unmount /mnt/r2 # tear down (cache stays for next mount within TTL)\numount /mnt/r2 # alias for `mount unmount` (same flags, same exit codes)\nmount unmount --clear-cache /mnt/r2 # tear down + drop cached listings/bodies\nmount refresh /mnt/r2 # re-walk the source and diff against cache\nmount refresh --bodies /mnt/r2 # also conditionally re-fetch changed bodies\n```\n\n`umount <path>` is a plain alias for `mount unmount <path>` — same parser, same `--clear-cache`, same exit codes; only the error prefix says `umount:`. Use whichever spelling the user typed. Unmounting a path that is not mounted is a no-op (not an error) under both.\n\n### `mount info` — ask before assuming names are unique\n\nTwo mounts in one runtime can disagree about identity. MEASURED: `/tmp` is case-sensitive and byte-exact; a macOS APFS hostfs mount (`/mnt/kb`) is case- **and** Unicode-normalization-insensitive. `ls` / `exists` / `read_file` will resolve `SLICC.md` to `Slicc.md` on the latter, and an NFC spelling of an NFD-stored name. **Do not discover this by renaming.** A rename between two names the volume considers equal has truncated files (#3107). Ask instead:\n\n```bash\nmount info --json /mnt/kb\n```\n\nThe report is probed (scratch file, stat back, always cleaned up), not declared from `diskutil`. Fields: `caseSensitivity`, `unicodeNormalization` (`byte-exact` vs `insensitive`), `unicodeStorage` (`nfc` / `nfd` / `as-written`), `executableBit`, `namesRoundTripByteExact`, `maxFilenameLength`, `writable`, `hostBacked`. If `unicodeNormalization` is `insensitive` or `caseSensitivity` is `insensitive`, compare names by folding case and NFC — do not treat a case/Unicode mismatch as a missing file, and do not rename one spelling onto the other.\n\nBuilt-in VFS paths such as `/tmp` support executable bits through `chmod`.\nMounted sources report the capability their bridge implements; the host disk\'s\ncapabilities alone do not imply that the mounted metadata operation is supported.\n\n`mount refresh` prints a structured summary: `Refreshed /mnt/r2: +2 -1 ~3 (47 unchanged, 0 errors)`. Use it after you know the remote changed externally and you want the local view to catch up before the 30 s TTL expires. On hostfs the same form applies: a populated idle tree reports a non-zero `unchanged` count of files checked (not `0 unchanged`), so exit 0 plus counts is evidence the walk ran.\n\n## Index state and bounds (`mount list`)\n\nEach mount is indexed in the background for fast file discovery and listings; `mount list` shows each mount\'s index state. The walk is bounded — defaults (raised 10×): max directory depth **400**, max total entries **2,000,000**. Two env vars override them: `SLICC_MOUNT_INDEX_MAX_DEPTH` and `SLICC_MOUNT_INDEX_MAX_ENTRIES` (an invalid value falls back to the default with a warning).\n\nWhen a bound is hit the index is **skipped** (reads still work via the slow fallback) and `mount list` shows a distinct cause, so advise the right remedy:\n\n- `directory nesting exceeded the depth limit` → raise `SLICC_MOUNT_INDEX_MAX_DEPTH` or unmount.\n- `mounted tree is too large` → raise `SLICC_MOUNT_INDEX_MAX_ENTRIES` or unmount (this is **not** a cycle).\n- `self-referential mount cycle detected` → a real, confirmed cycle; unmount it.\n- `index error: <message>` → any other indexing failure.\n\nDon\'t call a large or deep mount "cyclic" — only `self-referential mount cycle detected` means a true self-reference.\n\n## Reading and writing once mounted\n\nTreat the mount path like any other VFS directory:\n\n```bash\nls /mnt/da\nread_file /mnt/da/index.html\nwrite_file /mnt/da/new-page.html "<html>..."\nedit /mnt/da/index.html # via the standard edit tool\nrm /mnt/da/old.html\n```\n\nReads and writes use TTL + ETag caching (30 s default). Reads are zero-RTT within TTL. Writes use `If-Match` / `If-None-Match: *` for conflict detection.\n\nOn an AEM (Source Bus) mount there are no ETags — the API exposes only `last-modified` — so conflict detection uses modification time and only covers files you read first. A blind `write_file` to a path you never read will overwrite whatever is there. Read before you write on `aem://` mounts.\n\n## Common error patterns\n\n| Error | What it means |\n| ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `mount: probe failed for s3://… — profile \'aws\' missing required field \'access_key_id\'.` | The user hasn\'t set credentials yet. Walk them through `secret set s3.<profile>.*`. |\n| `EACCES: s3 access denied` | Wrong credentials, wrong region, or the bucket policy denies the user. |\n| `EACCES: da access denied` / `EACCES: aem access denied` | IMS token expired or user not authed against the Adobe provider. |\n| `mount: could not determine the content source for da://…` | The site config probe failed — usually no Adobe login. Fix the login, or pass `--backend da` / `--backend aem`. Don\'t just retry. |\n| `EBUSY: remote modified since last read — re-read and retry` | Concurrent writer changed the file. Re-read with `read_file` and retry the edit. |\n| `EFBIG: body exceeds maxBodyBytes` | File is over the per-mount size limit (S3 25 MB, DA/AEM 5 MB). Use shell tools (`aws s3 cp`) for very large files instead, or pass `--max-body-mb <n>` at mount time. |\n| `mount: cannot mount local directories from a scoop (no UI).` | Local mounts need a user gesture. Either ask the cone to mount, or use S3/DA which work in scoops. |\n| `EINVAL: symlinks not supported on mounted filesystems` | `ln -s … /mnt/<path>` tried to put the link on the mount (backends have no symlink inode). Put the link on VFS instead: `ln -s /mnt/… /shared/x` works. |\n\n## When asked to "explore" a mounted DA or S3 source\n\nAfter mounting, prefer `bash: ls` over `read_file` for navigation — it\'s instant within the TTL window because the listing is cached. Only `read_file` files you actually intend to read; every read is a network round-trip on the first call.\n\nFor DA specifically: the `/list` endpoint doesn\'t include file sizes, so `ls -l` triggers one HEAD per file the first time, then caches. Subsequent `ls -l` within 30 s is free.\n\nFor AEM: listings _do_ carry size and mtime, so `ls -l` costs one listing and no per-file round-trips. The size shown is the stored (compressed) size until the file has been read, so it can be well under what `read_file` returns. Empty folders don\'t exist on the Source Bus — a directory disappears when its last file is deleted.\n\n## Don\'t\n\n- Don\'t suggest the user install a separate AWS CLI / da.live SDK — `mount` is the integration point.\n- Don\'t try to `cd` into a remote mount before mounting; `bash`\'s working directory is independent of mount setup.\n- Don\'t ask "do you have credentials" if the user has already named a service — try the mount first, surface the actionable error from the probe, and walk them through the specific `secret set` commands.\n- Don\'t work around a `could not determine the content source` failure by switching to `--no-probe` — that flag doesn\'t skip the content-source probe, and the failure is telling you the login is missing.\n- Don\'t fall back to a local mount if the user mentioned a remote service. Default to clarifying which remote backend, not which directory to pick.\n- Don\'t rename a file to change only case or Unicode form until `mount info` says the volume is byte-exact. On an insensitive mount that is the #3107 truncate.\n- Don\'t create a symlink _on_ a mount (`ln -s x /mnt/kb/link`): that is `EINVAL`. A link on VFS pointing at a mounted path is fine (`ln -s /mnt/kb /shared/kb`).\n- Don\'t `mount` a path that `mount list` already shows as `hostfs://`. The launcher mount table owns that target.\n';export{e as default};
@@ -1 +1 @@
1
- var e="---\nname: skill-authoring\ndescription: |\n Use this when the user wants to write a new skill, edit an existing one, or\n understand SLICC's skill system. Covers SKILL.md frontmatter (name,\n description, allowed-tools), how to write a description that triggers\n reliably, native `/workspace/skills/` vs compatibility `.agents/` /\n `.claude/skills/` discovery, and when to ship companion files like `.jsh`\n scripts or `.bsh` browser hooks.\nallowed-tools: bash, read_file, write_file, edit\n---\n\n# Skill authoring\n\nA skill is a folder with a `SKILL.md` (and optional companion files) that loads into the agent's system prompt when the description matches the user's intent. This skill is about authoring those folders well.\n\n## Discovery\n\nSLICC discovers five kinds of skill roots:\n\n| Root | Source | Mutability |\n| ------------------------------------------------------------ | -------------------------------------------- | ----------------------------------- |\n| `/workspace/skills/<name>/SKILL.md` | Bundled or installed via `upskill` | Install-managed; you can edit them |\n| `.agents/skills/<name>/SKILL.md` (anywhere) | Compatibility (Cursor / SuperClaude) | Read-only (discovered, not managed) |\n| `.claude/skills/<name>/SKILL.md` (anywhere) | Compatibility (Claude Code) | Read-only (discovered, not managed) |\n| `<mount>/.claude-plugin/marketplace.json` → plugin `skills/` | Claude Code marketplace (mounted repos) | Read-only (discovered, not managed) |\n| `<plugin-root>/skills/<name>/SKILL.md` | Agent Plugins installed via `plugin install` | Read-only (discovered, not managed) |\n\nSkills under `/workspace/skills/` installed with `upskill` carry a `.upskill` provenance record (source, ref, commit, file list) that `upskill list --outdated` consults and `upskill update [--dry-run]` uses to refresh them. `upskill` never modifies or deletes a **dotfile** in a skill directory, so that is where a skill should keep its credentials and local state (`scripts/.config`) — everything else is replaced on update.\n\nThe marketplace root is auto-discovered: when a mounted directory contains `.claude-plugin/marketplace.json`, SLICC reads the manifest, resolves each plugin's `source` path, and discovers skills at `<plugin-source>/skills/<name>/SKILL.md`. No install step needed — mount the repo and the skills are live immediately. Agent Plugins (agent-plugins.org packages with a `plugin.json` manifest) require an explicit `plugin install <path|repo>` — `<repo>` may be a local directory or a GitHub reference (`owner/repo`, `owner/repo@branch`, or a `https://github.com/owner/repo[/tree/branch[/dir]]` URL, downloaded into `/workspace/.plugins/sources/`); their skills then surface automatically. Precedence: native > agents > claude > marketplace > plugin.\n\nWhen you create a new skill **for SLICC**, put it in `/workspace/skills/<name>/`. The `.agents/`, `.claude/`, and marketplace paths exist so SLICC can pick up skills authored for other agents without modification — don't create new skills there.\n\n## SKILL.md structure\n\n```markdown\n---\nname: <slug>\ndescription: |\n Use this when ...\n ... (1–3 sentences explaining trigger conditions, what's covered, and what's\n NOT covered if there's a sibling skill that handles related topics.)\nallowed-tools: bash, read_file, write_file, edit\n---\n\n# Title (matches `name`)\n\n... body ...\n```\n\n### Frontmatter fields\n\n- **`name`** — lowercase, kebab-case. Must match the folder name. This is what `skill list` shows.\n- **`description`** — the trigger string. The agent uses this to decide whether to load the skill. Get this right; everything else is secondary.\n- **`allowed-tools`** — comma-separated list of tools the skill needs. Without this, the agent may load the skill but find it can't execute the steps. Common values:\n - `bash` — almost every skill.\n - `read_file, write_file, edit` — for skills that author files (sprinkles, config edits, three-way merges).\n - Omit only for purely informational skills.\n\n### Writing a good description\n\nThe description is a trigger, not a summary. It runs through the agent at every turn — too vague and the skill loads when irrelevant; too narrow and it doesn't load when needed.\n\n**Pattern that works**: \"Use this when \\<user-facing trigger\\>. Covers \\<topics\\>. \\[For \\<adjacent topic\\> use \\<sibling skill\\>.\\]\"\n\nCompare:\n\n- ❌ `description: Licks, webhooks, cron tasks, viewing pages/images, screencapture, onboarding`\n Keyword soup. The agent has to guess what \"licks\" or \"screencapture\" mean for this user.\n- ✅ `description: Use this when setting up event-driven automation in SLICC — webhooks, cron tasks, or filesystem watchers that route events to scoops. Covers webhook, crontask, and fswatch. Read this BEFORE wiring anything that should fire on a schedule, an HTTP call, or a VFS change.`\n Names the user intent (\"setting up event-driven automation\"), names the commands the agent will reach for, and tells the agent when to load it.\n\nRules of thumb:\n\n- Lead with **\"Use this when...\"** or **\"Use this whenever...\"**.\n- Name the **user-facing trigger** (what the user said), not just the implementation.\n- If there's a closely-named sibling skill (dips vs sprinkles, mount vs other storage), say which is which inside the description so the agent doesn't load both.\n- Multi-line YAML scalars are fine for longer descriptions — use the `|` block style.\n\n## Body conventions\n\n- Lead with one sentence stating what the skill is. No preamble.\n- Use tables for option matrices (commands × flags, tradeoffs, etc.).\n- Code blocks are bash unless otherwise needed.\n- Include a \"Don't\" or \"Common errors\" section near the end if the skill is failure-prone — the agent will read it before acting.\n- If the skill is large (> ~150 lines), split a reference table or example gallery into a companion `<topic>.md` and have the SKILL.md `read_file` it on demand. The `sprinkles/` skill (style-guide.md) and `dips/` skill (patterns.md) follow this pattern.\n\n## Companion files\n\n### `.jsh` — JavaScript shell scripts\n\n`.jsh` files on the shell's `$PATH` search roots are auto-discovered as shell commands. **Full reference: `./jsh-runtime-extensions.md`.**\n\n- **Auto-discovery**: registered as callable commands by filename (without the extension), from the `$PATH` roots — `/workspace/skills`, `/workspace/.mcp/aliases`, `/workspace/bin`, `/shared/bin` by default. A skill can ship its own commands by including a `.jsh` next to `SKILL.md`. Earlier PATH roots win basename collisions, so `/workspace/skills/` beats `/workspace/bin`. Two skills under the same root that ship the same command are not silent: a `.upskill` provenance record wins over a bundled copy, a newer `installed` timestamp wins among provenanced skills, otherwise the first scan hit wins — and `skill list` / `which` name the loser. For commands elsewhere, add their dir to the PATH: `echo 'export PATH=\"$PATH:/my/tools\"' >> ~/.profile`.\n- **Direct execution**: run any script by path with `jsh /tmp/tool.jsh [args…]`. `jsh` is an alias for the Node shim, including `sliccy:` module resolution and argument passthrough; `process.argv[0]` remains `node` for Node compatibility.\n- **Dual-mode**: works in both the CLI server and the Chrome extension (sandbox iframe). Don't rely on CLI-only Node modules.\n- **Top-level `await`**: scripts are wrapped in `AsyncFunction`, so `await` at the top level works. Prefer it — errors surface instead of becoming unhandled rejections. Fire-and-forget `.then()`, unawaited `main()`, `setTimeout`, and `await fetch(…).json()` / `.text()` also keep the realm alive: like Node, the process stays up while I/O (fs/exec/fetch, including reading the response body) or timers are outstanding, and `process.exit()` skips the rest. A Promise with no handle (`new Promise(() => {})`) does **not** keep it alive. `node --check` / `-c` syntax-checks without executing (top-level `await` and ESM `import`/`export` are valid — the same entry transpile `node file.mjs` uses). `node --input-type=module` treats `-e` / stdin / `.js` as ESM.\n\n#### Runtime surface (use these — don't reinvent)\n\nNode-standard bare globals:\n\n| Global | Use for |\n| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `process` | `argv`, `env`, `cwd()`, `exit(code)`, `exitCode` (deferred status; honoured after the event-loop drain), `stdout.write`, `stderr.write`; `stdin` is one-shot buffered (no streaming) — `read()`, events, or async iterator, drain once |\n| `console` | `log`/`info`/`debug`/`dirxml`/`table`/`dir` → stdout; `warn`/`error`/`assert`/`trace` → stderr (`assert` does not throw); `group*` indent; `time*`/`count*` labeled; `clear` no-op |\n| `fetch` | Standard `fetch` routed through SLICC's proxied transport (cookies + CORS handled). |\n| `require(p)` | Synchronous CJS `require`. Use `require('sliccy:<name>')` for capability bridges and `require('fs')` for the VFS bridge (see below). |\n| `__dirname` / `__filename` | CJS scope vars — the script's own directory and absolute path. |\n\nCapability bridges via `require('sliccy:<name>')` (full reference: `./jsh-runtime-extensions.md`):\n\n| `require('sliccy:<name>')` | Use for |\n| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `sliccy:exec` | Callable `exec(cmd)` + `.spawn(argv[])`. Composes with any supplemental command or `.jsh` script. |\n| `sliccy:agent` | Callable `agent(prompt, opts?)` → sub-scoop final text (parsed when `schema` set) + `.spawn(...)` → `{ finalText, exitCode, stderr }`. `opts`: `model`, `thinking`, `cwd`, `allowedCommands`, `readOnly`, `schema`. |\n| `sliccy:skill` | `dir` / `root` / `refs` / `assets` / `config()` / `token(providerId)` — skill-root `references/` and `assets/`, script-dir `.config`, provider tokens. |\n| `sliccy:http` | `http.client({ baseUrl, token, headers, retry, timeoutMs })` — standard API-client builder. |\n| `sliccy:browser` | `findTab`, `ensureTab`, `openWindow`, `windowBounds`, `setWindowBounds`, `eval`, `evalAsync`, `cookie`, `localStorage`, `fetch`, `websocket.on(...)`. |\n| `sliccy:usb` / `sliccy:serial` / `sliccy:hid` | `list()` / `request()` + device methods. Chromium-only. |\n| `sliccy:computer` | `register(handlers)` — jsh-hosted computer backend (screenshot/input over `computer-call`; keep-alive). |\n| `sliccy:cli` | `die(msg, opts?)`, `out(value)`, `warn(msg, opts?)`, `help(text)`. |\n| `sliccy:color` | ANSI helpers (`green`, `red`, `bold`, `dim`, …) auto-disabled on non-TTY / `NO_COLOR`. |\n| `sliccy:time` | `parseDuration`, `ago`, `range`, `future`, `gmailDate`. |\n| `sliccy:fmt` | `trunc`, `col`, `table`, `date`. |\n| `sliccy:pool` | `pool(n, items, fn)` — bounded concurrency runner. |\n\nVFS bridge:\n\n| `require('fs')` / `require('node:fs')` | `readFile`, `writeFile`, `readFileBinary`, `writeFileBinary`, `appendFile`, `readDir`, `exists`, `stat`, `mkdir`, `rm`, `fetchToFile` — all paths are VFS, async. There is no bare `fs` global. |\n| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n\n#### Runtime extensions (live — prefer these over hand-rolled equivalents)\n\nReach these via `require('sliccy:<name>')`. Full reference: `./jsh-runtime-extensions.md`. Use them instead of reimplementing the cross-skill patterns they replace.\n\n- **`process.argv.parseFlags()`** — returns `{ positional, flags, subcommand }`. Replaces the per-skill `--flag=val` / `--flag val` parsing loop.\n- **`require('sliccy:browser')`** — `findTab({ domain | urlMatch })`, `ensureTab(url)`, `openWindow(url, opts?)` (frame-sized window), `windowBounds(tab)`, `setWindowBounds(tab, bounds)` (returns achieved bounds), `eval(tab, fn)`, `evalAsync(tab, fn)`, `cookie(tab, name)`, `localStorage(tab, key)`. Replaces shelling out to `playwright-cli tab-list` and regex-parsing its output.\n- **`browser.fetch(tab, url, opts)`** — page-context fetch (runs inside the tab's origin, so cookies + same-origin headers are automatic). Replaces the `eval-file` temp-file + double-JSON-unwrap dance.\n- **`browser.websocket.on(tab, …).filter({…}).forward({ sink })`** — declarative WebSocket observer with a closed sink set (`webhook` / `scoop` / `vfs` / `log`). **Required** for any new WS-watch use case; do not author page-context `WebSocket.prototype` patches in skill code.\n- **`require('sliccy:http').client({ baseUrl, token, headers, retry })`** — `get`/`post`/`put`/`delete` with merged headers, lazy token resolution, and Retry-After-aware backoff for `retry.on` statuses.\n- **`require('sliccy:skill')`** — `dir` / `root` / `refs` / `assets` / `config()` / `token(providerId)`: replace the per-skill `process.argv[1]` dirname math, ad-hoc `.config` JSON readers, and bespoke `oauth-token` shell-outs. `refs`/`assets` resolve from the skill root (parent of the `scripts/` path segment, including nested helpers).\n- **`require('sliccy:computer')`** — `register(handlers)` for a jsh-hosted computer backend. `register()` keeps a `jshd` unit alive via `computer-call` events. Drive it with the `computer` shell command.\n\nShip a `.jsh` when the skill needs deterministic, parameterizable behavior the agent shouldn't have to re-derive each time (e.g. a `slicc-handoff` helper, a custom diff formatter, a domain-specific lint).\n\n### `.bsh` — browser shell scripts\n\n`.bsh` files auto-execute when the browser navigates to a matching URL:\n\n- **Filename = hostname pattern**: `-.okta.com.bsh` matches `*.okta.com`.\n- **`// @match` directive**: restrict to specific URL patterns in the first 10 lines.\n- Same execution engine as `.jsh`.\n\nUse `.bsh` for site-specific automations — auto-fillers, lick-emitters, or page transforms that should run whenever the user lands on a particular host.\n\n## Filesystem at a glance\n\nThe VFS is stored in IndexedDB; it survives tab closes and refreshes. The `mount` shell command bridges remote storage (local folders, S3-compatible, Adobe DA) into VFS paths — see `/workspace/skills/mount/SKILL.md`.\n\nThe VFS supports symbolic links transparently:\n\n```bash\nln -s /workspace/skills /workspace/skill-link # Create symlink\nreadlink /workspace/skill-link # Read link target\nls -la /workspace/ # Shows symlinks with -> target\n```\n\n`cat`, `read_file`, `write_file` etc. follow symlinks automatically.\n\n**Mount points must be empty.** Mounting over existing files is blocked so built-in skills and scripts stay discoverable. Do not `ln -s` a `/mnt/…` path onto VFS — mount backends cannot host a real symlink, and the call fails with `EXDEV`. Use the mount path directly, or copy.\n\n## Don't\n\n- Don't ship a skill without a description that starts with \"Use this when...\" — the trigger field IS the skill from the agent's perspective.\n- Don't put `name:` in Title Case. Lowercase kebab-case. Match the folder.\n- Don't dump shell-command catalogs into a SKILL.md just because they're related — `commands` already lists them. Skills are for **patterns and policy**, not reference material.\n- Don't author skills under `.agents/skills/` or `.claude/skills/`. Those roots are for compatibility discovery from other agents.\n";export{e as default};
1
+ var e="---\nname: skill-authoring\ndescription: |\n Use this when the user wants to write a new skill, edit an existing one, or\n understand SLICC's skill system. Covers SKILL.md frontmatter (name,\n description, allowed-tools), how to write a description that triggers\n reliably, native `/workspace/skills/` vs compatibility `.agents/` /\n `.claude/skills/` discovery, and when to ship companion files like `.jsh`\n scripts or `.bsh` browser hooks.\nallowed-tools: bash, read_file, write_file, edit\n---\n\n# Skill authoring\n\nA skill is a folder with a `SKILL.md` (and optional companion files) that loads into the agent's system prompt when the description matches the user's intent. This skill is about authoring those folders well.\n\n## Discovery\n\nSLICC discovers five kinds of skill roots:\n\n| Root | Source | Mutability |\n| ------------------------------------------------------------ | -------------------------------------------- | ----------------------------------- |\n| `/workspace/skills/<name>/SKILL.md` | Bundled or installed via `upskill` | Install-managed; you can edit them |\n| `.agents/skills/<name>/SKILL.md` (anywhere) | Compatibility (Cursor / SuperClaude) | Read-only (discovered, not managed) |\n| `.claude/skills/<name>/SKILL.md` (anywhere) | Compatibility (Claude Code) | Read-only (discovered, not managed) |\n| `<mount>/.claude-plugin/marketplace.json` → plugin `skills/` | Claude Code marketplace (mounted repos) | Read-only (discovered, not managed) |\n| `<plugin-root>/skills/<name>/SKILL.md` | Agent Plugins installed via `plugin install` | Read-only (discovered, not managed) |\n\nSkills under `/workspace/skills/` installed with `upskill` carry a `.upskill` provenance record (source, ref, commit, file list) that `upskill list --outdated` consults and `upskill update [--dry-run]` uses to refresh them. `upskill` never modifies or deletes a **dotfile** in a skill directory, so that is where a skill should keep its credentials and local state (`scripts/.config`) — everything else is replaced on update.\n\nThe marketplace root is auto-discovered: when a mounted directory contains `.claude-plugin/marketplace.json`, SLICC reads the manifest, resolves each plugin's `source` path, and discovers skills at `<plugin-source>/skills/<name>/SKILL.md`. No install step needed — mount the repo and the skills are live immediately. Agent Plugins (agent-plugins.org packages with a `plugin.json` manifest) require an explicit `plugin install <path|repo>` — `<repo>` may be a local directory or a GitHub reference (`owner/repo`, `owner/repo@branch`, or a `https://github.com/owner/repo[/tree/branch[/dir]]` URL, downloaded into `/workspace/.plugins/sources/`); their skills then surface automatically. Precedence: native > agents > claude > marketplace > plugin.\n\nWhen you create a new skill **for SLICC**, put it in `/workspace/skills/<name>/`. The `.agents/`, `.claude/`, and marketplace paths exist so SLICC can pick up skills authored for other agents without modification — don't create new skills there.\n\n## SKILL.md structure\n\n```markdown\n---\nname: <slug>\ndescription: |\n Use this when ...\n ... (1–3 sentences explaining trigger conditions, what's covered, and what's\n NOT covered if there's a sibling skill that handles related topics.)\nallowed-tools: bash, read_file, write_file, edit\n---\n\n# Title (matches `name`)\n\n... body ...\n```\n\n### Frontmatter fields\n\n- **`name`** — lowercase, kebab-case. Must match the folder name. This is what `skill list` shows.\n- **`description`** — the trigger string. The agent uses this to decide whether to load the skill. Get this right; everything else is secondary.\n- **`allowed-tools`** — comma-separated list of tools the skill needs. Without this, the agent may load the skill but find it can't execute the steps. Common values:\n - `bash` — almost every skill.\n - `read_file, write_file, edit` — for skills that author files (sprinkles, config edits, three-way merges).\n - Omit only for purely informational skills.\n\n### Writing a good description\n\nThe description is a trigger, not a summary. It runs through the agent at every turn — too vague and the skill loads when irrelevant; too narrow and it doesn't load when needed.\n\n**Pattern that works**: \"Use this when \\<user-facing trigger\\>. Covers \\<topics\\>. \\[For \\<adjacent topic\\> use \\<sibling skill\\>.\\]\"\n\nCompare:\n\n- ❌ `description: Licks, webhooks, cron tasks, viewing pages/images, screencapture, onboarding`\n Keyword soup. The agent has to guess what \"licks\" or \"screencapture\" mean for this user.\n- ✅ `description: Use this when setting up event-driven automation in SLICC — webhooks, cron tasks, or filesystem watchers that route events to scoops. Covers webhook, crontask, and fswatch. Read this BEFORE wiring anything that should fire on a schedule, an HTTP call, or a VFS change.`\n Names the user intent (\"setting up event-driven automation\"), names the commands the agent will reach for, and tells the agent when to load it.\n\nRules of thumb:\n\n- Lead with **\"Use this when...\"** or **\"Use this whenever...\"**.\n- Name the **user-facing trigger** (what the user said), not just the implementation.\n- If there's a closely-named sibling skill (dips vs sprinkles, mount vs other storage), say which is which inside the description so the agent doesn't load both.\n- Multi-line YAML scalars are fine for longer descriptions — use the `|` block style.\n\n## Body conventions\n\n- Lead with one sentence stating what the skill is. No preamble.\n- Use tables for option matrices (commands × flags, tradeoffs, etc.).\n- Code blocks are bash unless otherwise needed.\n- Include a \"Don't\" or \"Common errors\" section near the end if the skill is failure-prone — the agent will read it before acting.\n- If the skill is large (> ~150 lines), split a reference table or example gallery into a companion `<topic>.md` and have the SKILL.md `read_file` it on demand. The `sprinkles/` skill (style-guide.md) and `dips/` skill (patterns.md) follow this pattern.\n\n## Companion files\n\n### `.jsh` — JavaScript shell scripts\n\n`.jsh` files on the shell's `$PATH` search roots are auto-discovered as shell commands. **Full reference: `./jsh-runtime-extensions.md`.**\n\n- **Auto-discovery**: registered as callable commands by filename (without the extension), from the `$PATH` roots — `/workspace/skills`, `/workspace/.mcp/aliases`, `/workspace/bin`, `/shared/bin` by default. A skill can ship its own commands by including a `.jsh` next to `SKILL.md`. Earlier PATH roots win basename collisions, so `/workspace/skills/` beats `/workspace/bin`. Two skills under the same root that ship the same command are not silent: a `.upskill` provenance record wins over a bundled copy, a newer `installed` timestamp wins among provenanced skills, otherwise the first scan hit wins — and `skill list` / `which` name the loser. For commands elsewhere, add their dir to the PATH: `echo 'export PATH=\"$PATH:/my/tools\"' >> ~/.profile`.\n- **Direct execution**: run any script by path with `jsh /tmp/tool.jsh [args…]`. `jsh` is an alias for the Node shim, including `sliccy:` module resolution and argument passthrough; `process.argv[0]` remains `node` for Node compatibility.\n- **Dual-mode**: works in both the CLI server and the Chrome extension (sandbox iframe). Don't rely on CLI-only Node modules.\n- **Top-level `await`**: scripts are wrapped in `AsyncFunction`, so `await` at the top level works. Prefer it — errors surface instead of becoming unhandled rejections. Fire-and-forget `.then()`, unawaited `main()`, `setTimeout`, and `await fetch(…).json()` / `.text()` also keep the realm alive: like Node, the process stays up while I/O (fs/exec/fetch, including reading the response body) or timers are outstanding, and `process.exit()` skips the rest. A Promise with no handle (`new Promise(() => {})`) does **not** keep it alive. `node --check` / `-c` syntax-checks without executing (top-level `await` and ESM `import`/`export` are valid — the same entry transpile `node file.mjs` uses). `node --input-type=module` treats `-e` / stdin / `.js` as ESM.\n\n#### Runtime surface (use these — don't reinvent)\n\nNode-standard bare globals:\n\n| Global | Use for |\n| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `process` | `argv`, `env`, `cwd()`, `exit(code)`, `exitCode` (deferred status; honoured after the event-loop drain), `stdout.write`, `stderr.write`; `stdin` is one-shot buffered (no streaming) — `read()`, events, or async iterator, drain once |\n| `console` | `log`/`info`/`debug`/`dirxml`/`table`/`dir` → stdout; `warn`/`error`/`assert`/`trace` → stderr (`assert` does not throw); `group*` indent; `time*`/`count*` labeled; `clear` no-op |\n| `fetch` | Standard `fetch` routed through SLICC's proxied transport (cookies + CORS handled). |\n| `require(p)` | Synchronous CJS `require`. Use `require('sliccy:<name>')` for capability bridges and `require('fs')` for the VFS bridge (see below). |\n| `__dirname` / `__filename` | CJS scope vars — the script's own directory and absolute path. |\n\nCapability bridges via `require('sliccy:<name>')` (full reference: `./jsh-runtime-extensions.md`):\n\n| `require('sliccy:<name>')` | Use for |\n| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `sliccy:exec` | Callable `exec(cmd)` + `.spawn(argv[])`. Composes with any supplemental command or `.jsh` script. |\n| `sliccy:agent` | Callable `agent(prompt, opts?)` → sub-scoop final text (parsed when `schema` set) + `.spawn(...)` → `{ finalText, exitCode, stderr }`. `opts`: `model`, `thinking`, `cwd`, `allowedCommands`, `readOnly`, `schema`. |\n| `sliccy:skill` | `dir` / `root` / `refs` / `assets` / `config()` / `token(providerId)` — skill-root `references/` and `assets/`, script-dir `.config`, provider tokens. |\n| `sliccy:http` | `http.client({ baseUrl, token, headers, retry, timeoutMs })` — standard API-client builder. |\n| `sliccy:browser` | `findTab`, `ensureTab`, `openWindow`, `windowBounds`, `setWindowBounds`, `eval`, `evalAsync`, `cookie`, `localStorage`, `fetch`, `websocket.on(...)`. |\n| `sliccy:usb` / `sliccy:serial` / `sliccy:hid` | `list()` / `request()` + device methods. Chromium-only. |\n| `sliccy:computer` | `register(handlers)` — jsh-hosted computer backend (screenshot/input over `computer-call`; keep-alive). |\n| `sliccy:cli` | `die(msg, opts?)`, `out(value)`, `warn(msg, opts?)`, `help(text)`. |\n| `sliccy:color` | ANSI helpers (`green`, `red`, `bold`, `dim`, …) auto-disabled on non-TTY / `NO_COLOR`. |\n| `sliccy:time` | `parseDuration`, `ago`, `range`, `future`, `gmailDate`. |\n| `sliccy:fmt` | `trunc`, `col`, `table`, `date`. |\n| `sliccy:pool` | `pool(n, items, fn)` — bounded concurrency runner. |\n\nVFS bridge:\n\n| `require('fs')` / `require('node:fs')` | `readFile`, `writeFile`, `readFileBinary`, `writeFileBinary`, `appendFile`, `readDir`, `exists`, `stat`, `mkdir`, `rm`, `fetchToFile` — all paths are VFS, async. There is no bare `fs` global. |\n| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n\n#### Runtime extensions (live — prefer these over hand-rolled equivalents)\n\nReach these via `require('sliccy:<name>')`. Full reference: `./jsh-runtime-extensions.md`. Use them instead of reimplementing the cross-skill patterns they replace.\n\n- **`process.argv.parseFlags()`** — returns `{ positional, flags, subcommand }`. Replaces the per-skill `--flag=val` / `--flag val` parsing loop.\n- **`require('sliccy:browser')`** — `findTab({ domain | urlMatch })`, `ensureTab(url)`, `openWindow(url, opts?)` (frame-sized window), `windowBounds(tab)`, `setWindowBounds(tab, bounds)` (returns achieved bounds), `eval(tab, fn)`, `evalAsync(tab, fn)`, `cookie(tab, name)`, `localStorage(tab, key)`. Replaces shelling out to `playwright-cli tab-list` and regex-parsing its output.\n- **`browser.fetch(tab, url, opts)`** — page-context fetch (runs inside the tab's origin, so cookies + same-origin headers are automatic). Replaces the `eval-file` temp-file + double-JSON-unwrap dance.\n- **`browser.websocket.on(tab, …).filter({…}).forward({ sink })`** — declarative WebSocket observer with a closed sink set (`webhook` / `scoop` / `vfs` / `log`). **Required** for any new WS-watch use case; do not author page-context `WebSocket.prototype` patches in skill code.\n- **`require('sliccy:http').client({ baseUrl, token, headers, retry })`** — `get`/`post`/`put`/`delete` with merged headers, lazy token resolution, and Retry-After-aware backoff for `retry.on` statuses.\n- **`require('sliccy:skill')`** — `dir` / `root` / `refs` / `assets` / `config()` / `token(providerId)`: replace the per-skill `process.argv[1]` dirname math, ad-hoc `.config` JSON readers, and bespoke `oauth-token` shell-outs. `refs`/`assets` resolve from the skill root (parent of the `scripts/` path segment, including nested helpers).\n- **`require('sliccy:computer')`** — `register(handlers)` for a jsh-hosted computer backend. `register()` keeps a `jshd` unit alive via `computer-call` events. Drive it with the `computer` shell command.\n\nShip a `.jsh` when the skill needs deterministic, parameterizable behavior the agent shouldn't have to re-derive each time (e.g. a `slicc-handoff` helper, a custom diff formatter, a domain-specific lint).\n\n### `.bsh` — browser shell scripts\n\n`.bsh` files auto-execute when the browser navigates to a matching URL:\n\n- **Filename = hostname pattern**: `-.okta.com.bsh` matches `*.okta.com`.\n- **`// @match` directive**: restrict to specific URL patterns in the first 10 lines.\n- Same execution engine as `.jsh`.\n\nUse `.bsh` for site-specific automations — auto-fillers, lick-emitters, or page transforms that should run whenever the user lands on a particular host.\n\n## Filesystem at a glance\n\nThe VFS is stored in IndexedDB; it survives tab closes and refreshes. The `mount` shell command bridges remote storage (local folders, S3-compatible, Adobe DA) into VFS paths — see `/workspace/skills/mount/SKILL.md`.\n\nThe VFS supports symbolic links transparently:\n\n```bash\nln -s /workspace/skills /workspace/skill-link # Create symlink\nreadlink /workspace/skill-link # Read link target\nls -la /workspace/ # Shows symlinks with -> target\n```\n\n`cat`, `read_file`, `write_file` etc. follow symlinks automatically.\n\n**Mount points must be empty.** Mounting over existing files is blocked so built-in skills and scripts stay discoverable. `ln -s /mnt/… /shared/x` works: the link lives on VFS, and everything through it reaches the mount. A link cannot live _on_ a mount, though (`EINVAL`): mount backends have no symlink inode.\n\n## Don't\n\n- Don't ship a skill without a description that starts with \"Use this when...\" — the trigger field IS the skill from the agent's perspective.\n- Don't put `name:` in Title Case. Lowercase kebab-case. Match the folder.\n- Don't dump shell-command catalogs into a SKILL.md just because they're related — `commands` already lists them. Skills are for **patterns and policy**, not reference material.\n- Don't author skills under `.agents/skills/` or `.claude/skills/`. Those roots are for compatibility discovery from other agents.\n";export{e as default};
@@ -1 +1 @@
1
- var e="---\nname: package-execution\ndescription: |\n Use this when the user asks to run or install a JavaScript/npm package with\n `npx` or `ipx`, or to run a `package.json` script with `npm run`. Covers\n built-in hints, any required `ipk add` bootstrap, the `--force` bypass, and\n how script bodies resolve installed bins.\nallowed-tools: bash\n---\n\n# JavaScript package execution\n\n`ipx` runs package bins from the nearest installed `node_modules`; `npx` is an alias with the same behavior. If no local bin or installed package resolves, it normally installs the requested package and runs its bin.\n\nBefore that network install, mapped package names that duplicate SLICC built-ins redirect to the built-in instead. The command exits non-zero and prints an actionable stderr hint naming the built-in and suggesting an invocation with the original arguments. The hint may also include an exact `ipk add` bootstrap; run that bootstrap first when present, then use the suggested built-in.\n\nPrefer the built-in. To deliberately preserve install-and-run behavior for the npm package, put `--force` before its name:\n\n```bash\nnpx --force <package> [args...]\nipx --force <package> [args...]\n```\n\nAlready-installed packages, locally resolved bins, and unmapped package names keep their normal behavior. Use `commands` to discover available built-ins instead of maintaining a package mapping here.\n\n## Installing and removing packages\n\n`ipk install <pkg>` (also `npm install`, `npm i`, `ipk add`) installs into `<cwd>/node_modules` and records the package in the nearest `package.json` — in the section it already occupies, or in `dependencies` if it is new. `ipk install -D <pkg>` / `npm install --save-dev <pkg>` records new packages in `devDependencies`. A bare name that is already declared is resolved against that existing range, not latest. Versions are picked as pnpm picks them: a range takes the `latest` dist-tag whenever `latest` satisfies it (`*` always takes `latest`), and deprecated versions are passed over unless nothing else fits. Unknown install flags fail instead of being ignored. `ipk install` with no package names installs declared `dependencies`, `devDependencies` and `optionalDependencies` without rewriting `package.json`. `ipk install -g <pkg>` installs into the shared global prefix at `/shared/lib/node_modules`, records direct dependencies in `/shared/lib/package.json`, and publishes PATH-visible `.jsh` delegators under `/shared/bin` for package bins. Every downloaded tarball is checked against the registry's published hash before it is extracted. An `EINTEGRITY` error means that package's bytes did not match and it was not extracted, but packages installed before it may already be on disk and `package.json` was not updated. Check the state with `ipk list`, then retry the install; don't work around it. Installed files keep the package's executable bits (as npm sets them: 0755 for anything the tarball marks executable, 0644 otherwise), and `bin` targets are always executable, so a package's scripts and helpers (e.g. `git submodule` from `@ai-ecoverse/wasm-git`) run without `chmod +x`. A tree installed before this is repaired the next time you install into it. Platform-specific optional dependencies are skipped unless they are built for wasm (`cpu: wasm32`); the `skipping optional dependency … (unsupported platform)` notes are expected, not errors. For a napi-rs package that doesn't list its wasm binding, add `<pkg>-wasm32-wasi` (e.g. `@oxc-parser/binding-wasm32-wasi`) yourself.\n\n```bash\nipk install lodash # local project install\nipk install -D eslint # record in devDependencies\nnpm install --save-dev eslint@8.57.1\nipk install -g typescript # global install (shared prefix + PATH bin)\nnpm uninstall -g typescript # remove from global manifest and reconcile tree\nnpm list -g # list direct global dependencies\nnpm root -g # print /shared/lib/node_modules\n```\n\nGlobal bins installed with `-g` are on the default `$PATH` via `/shared/bin/<name>.jsh` delegators — invoke them by bare name from any cwd (delegators run `ipx --global <bin>` so a same-named local package does not shadow the global install). Local uninstall/list/root work without `-g` against the cwd `package.json`.\n\n## Wasm programs (`wasm`)\n\nA global package that ships wasm-realm programs (a `slicc.commands` manifest in its `package.json`, or an `@ai-ecoverse/wasm-*` package with `bin/<x>` + `bin/<x>.wasm`; `\"abi\": \"wasi\"` marks WASI programs built from Zig, Go or Rust, which have no glue) makes each program a command: `ipk add -g @ai-ecoverse/wasm-<tool>`, then run it by name. `wasm --list` lists them; `which <name>` shows the package. A built-in of the same name (`sed`, `grep`, `cat`, …) still wins, so run the program with `wasm <name> ARGS...`. `wasm -t <name>` runs it interactively on the panel terminal (a TTY: `wasm -t bash` is a real bash prompt, with job control — ^Z, `jobs`, `fg`, `bg`); the agent's own `bash` tool has no terminal to lend. Installing `@ai-ecoverse/wasm-bash` also moves your own `bash` tool onto GNU bash (real pipes, `trap`, `select`, arrays, bash's exact semantics; `cd` and exports carry between calls, shell functions do not). A WASI module you have as a file runs directly too: `wasm ./tool.wasm ARGS` (or `./tool.wasm` in GNU bash); it sees the VFS with relative paths from your working directory, pipes like any program, and WASIX builds (Wasmer's registry: bash, coreutils, python with `subprocess` and `threading`) run with fork, exec and pipes; threaded builds (`wasm32-wasip1-threads`, pthreads) run a worker per thread, at most 64 per process (`SLICC_WASM_THREADS=N` for fewer). A WASI server gets its socket from `wasm --listen PORT ./server.wasm` (the fd is in `$SLICC_LISTEN_FDS`; Go's `net.FileListener(os.NewFile(fd, \"\"))` serves on it), reachable from your other programs at `127.0.0.1:PORT`. Supplemental commands work as before. The terminal panel then opens in GNU bash too (`wasm --login` starts it; `exit` returns to the slicc prompt, and `wasm --login` starts it again). `export SLICC_SHELL=just-bash` switches both back. Wasm programs built with socket support talk over a private loopback network: a server listening on `127.0.0.1:PORT` in one of your wasm programs is reachable from your other wasm programs while it runs (the terminal panel and each scoop have networks of their own), and a program reaches the outside over HTTP through your network's proxy: `http_proxy` / `https_proxy` point at `127.0.0.1:3128` by default (`no_proxy` keeps `localhost` direct), so `curl http://…` works the way the shell's `curl` does, masked secrets included. HTTPS works too: the proxy terminates TLS with a certificate from your network's own CA, which `SSL_CERT_FILE` / `CURL_CA_BUNDLE` / `GIT_SSL_CAINFO` point programs at (`$HOME/.config/slicc/realm-ca-*.pem`; `-k` is never needed). A redirect reaches the program as it would any HTTP client (`curl -L` follows it), except on Sliccstart, whose fetch path follows redirects itself. No other traffic leaves: only `localhost` / `127.0.0.1` resolve. Once a native CPython is installed, `python3` in GNU bash is native Python, and `pyodide` stays SLICC's Pyodide under its own name. Installed Python packages are on its path by themselves. Once `@ai-ecoverse/wasm-git` is installed, `git` in GNU bash is native git (in just-bash it stays SLICC's built-in; `wasm git …` reaches native git there). Native git authenticates by itself: its default credential helper, `git-credential-slicc`, hands it your GitHub login (or `$GH_TOKEN` / `$GITHUB_TOKEN`, or a `*_TOKEN` secret scoped to the host) masked, so `git clone` / `git push` over HTTPS to a private repo just work, and it commits as SLICC's git identity. Don't put tokens in remote URLs; your `~/.gitconfig` overrides both (`$HOME/.config/slicc/gitconfig` is the realm's system config, rewritten each run).\n\n## Conda / emscripten-forge (`ipk mamba`)\n\n`ipk mamba install <pkg>[=<version>]` installs emscripten-wasm32 packages from emscripten-forge / conda-forge into `/shared/lib/conda` (not `node_modules`). Executable files (shared objects, scripts) keep their executable bit. Prefer this for **forge C/WASM libraries** (for example `zlib`, `libpng`) that provide headers, `.a`, and SIDE_MODULE `.so` under that prefix.\n\nKeep using `ipk install` / `ipk add -g` for the **npm** packages that power these built-ins — forge names are not drop-in replacements today:\n\n- `convert` → `ipk add -g @imagemagick/magick-wasm@…` (forge `imagemagick` has no runnable `convert.wasm`)\n- `ffmpeg` → `ipk add -g @ffmpeg/core@…` (forge `ffmpeg` is libav `.a` only)\n- `python` → `ipk add pyodide@…` (no forge `pyodide`)\n\n```bash\nipk mamba install zlib # newest indexed build → /shared/lib/conda\nipk mamba install zlib=1.3.1 # exact version\nipk mamba list # conda-meta inventory\nipk mamba uninstall zlib\nipk mamba --help # channels, prefix, and thin-installer limits\n```\n\n## Running package.json scripts\n\n`npm run <script>` (also `ipk run`, `npm run-script`, and the `npm test` / `start` / `stop` / `restart` shortcuts) runs a `scripts` entry from the nearest `package.json`, in that package's directory. `npm run` with no script name lists what is available — read that list instead of guessing a script name.\n\n```bash\nnpm run # list scripts\nnpm run build # run build, with prebuild/postbuild around it\nnpm run build -- --watch # pass extra args to the script body\nnpm run build --silent # no banner, script output only (either side of the name)\nnpm run lint -- --help # --help after -- goes to the script, not to npm\n```\n\n`--silent`/`-s` and `--if-present` are npm's own flags anywhere before `--`; everything after `--` reaches the script untouched. Missing `start` falls back to `node server.js` when the package has one, and missing `restart` to `npm stop --if-present && npm start`.\n\nA bare bin word in a script body (`vitest run`) is rewritten to `ipx vitest run` when that package is installed, because `$PATH` does not cover `node_modules/.bin` shims. This also applies after keywords like `if`/`then`/`do`. A SLICC built-in with the same name wins, and an unknown word is not installed implicitly — install it with `ipk add <pkg>` first.\n";export{e as default};
1
+ var e="---\nname: package-execution\ndescription: |\n Use this when the user asks to run or install a JavaScript/npm package with\n `npx` or `ipx`, or to run a `package.json` script with `npm run`. Covers\n built-in hints, any required `ipk add` bootstrap, the `--force` bypass, and\n how script bodies resolve installed bins.\nallowed-tools: bash\n---\n\n# JavaScript package execution\n\n`ipx` runs package bins from the nearest installed `node_modules`; `npx` is an alias with the same behavior. If no local bin or installed package resolves, it normally installs the requested package and runs its bin.\n\nBefore that network install, mapped package names that duplicate SLICC built-ins redirect to the built-in instead. The command exits non-zero and prints an actionable stderr hint naming the built-in and suggesting an invocation with the original arguments. The hint may also include an exact `ipk add` bootstrap; run that bootstrap first when present, then use the suggested built-in.\n\nPrefer the built-in. To deliberately preserve install-and-run behavior for the npm package, put `--force` before its name:\n\n```bash\nnpx --force <package> [args...]\nipx --force <package> [args...]\n```\n\nAlready-installed packages, locally resolved bins, and unmapped package names keep their normal behavior. Use `commands` to discover available built-ins instead of maintaining a package mapping here.\n\n## Installing and removing packages\n\n`ipk install <pkg>` (also `npm install`, `npm i`, `ipk add`) installs into `<cwd>/node_modules` and records the package in the nearest `package.json` — in the section it already occupies, or in `dependencies` if it is new. `ipk install -D <pkg>` / `npm install --save-dev <pkg>` records new packages in `devDependencies`. A bare name that is already declared is resolved against that existing range, not latest. Versions are picked as pnpm picks them: a range takes the `latest` dist-tag whenever `latest` satisfies it (`*` always takes `latest`), and deprecated versions are passed over unless nothing else fits. Unknown install flags fail instead of being ignored. `ipk install` with no package names installs declared `dependencies`, `devDependencies` and `optionalDependencies` without rewriting `package.json`. `ipk install -g <pkg>` installs into the shared global prefix at `/shared/lib/node_modules`, records direct dependencies in `/shared/lib/package.json`, and publishes PATH-visible `.jsh` delegators under `/shared/bin` for package bins. Every downloaded tarball is checked against the registry's published hash before it is extracted. An `EINTEGRITY` error means that package's bytes did not match and it was not extracted, but packages installed before it may already be on disk and `package.json` was not updated. Check the state with `ipk list`, then retry the install; don't work around it. Installed files keep the package's executable bits (as npm sets them: 0755 for anything the tarball marks executable, 0644 otherwise), and `bin` targets are always executable, so a package's scripts and helpers (e.g. `git submodule` from `@ai-ecoverse/wasm-git`) run without `chmod +x`. A tree installed before this is repaired the next time you install into it. Platform-specific optional dependencies are skipped unless they are built for wasm (`cpu: wasm32`); the `skipping optional dependency … (unsupported platform)` notes are expected, not errors. For a napi-rs package that doesn't list its wasm binding, add `<pkg>-wasm32-wasi` (e.g. `@oxc-parser/binding-wasm32-wasi`) yourself.\n\n```bash\nipk install lodash # local project install\nipk install -D eslint # record in devDependencies\nnpm install --save-dev eslint@8.57.1\nipk install -g typescript # global install (shared prefix + PATH bin)\nnpm uninstall -g typescript # remove from global manifest and reconcile tree\nnpm list -g # list direct global dependencies\nnpm root -g # print /shared/lib/node_modules\n```\n\nGlobal bins installed with `-g` are on the default `$PATH` via `/shared/bin/<name>.jsh` delegators — invoke them by bare name from any cwd (delegators run `ipx --global <bin>` so a same-named local package does not shadow the global install). Local uninstall/list/root work without `-g` against the cwd `package.json`.\n\n## Wasm programs (`wasm`)\n\nA global package that ships wasm-realm programs (a `slicc.commands` manifest in its `package.json`, or an `@ai-ecoverse/wasm-*` package with `bin/<x>` + `bin/<x>.wasm`; `\"abi\": \"wasi\"` marks WASI programs built from Zig, Go or Rust, which have no glue) makes each program a command: `ipk add -g @ai-ecoverse/wasm-<tool>`, then run it by name. `wasm --list` lists them; `which <name>` shows the package. A built-in of the same name (`sed`, `grep`, `cat`, …) still wins, so run the program with `wasm <name> ARGS...`. `wasm -t <name>` runs it interactively on the panel terminal (a TTY: `wasm -t bash` is a real bash prompt, with job control — ^Z, `jobs`, `fg`, `bg`); the agent's own `bash` tool has no terminal to lend. Installing `@ai-ecoverse/wasm-bash` also moves your own `bash` tool onto GNU bash (real pipes, `trap`, `select`, arrays, bash's exact semantics; `cd` and exports carry between calls, shell functions do not). A WASI module you have as a file runs directly too: `wasm ./tool.wasm ARGS` (or `./tool.wasm` in GNU bash); it sees the VFS with relative paths from your working directory, pipes like any program, and WASIX builds (Wasmer's registry: bash, coreutils, python with `subprocess` and `threading`) run with fork, exec and pipes; threaded builds (`wasm32-wasip1-threads`, pthreads) run a worker per thread, at most 64 per process (`SLICC_WASM_THREADS=N` for fewer). A WASI server gets its socket from `wasm --listen PORT ./server.wasm` (the fd is in `$SLICC_LISTEN_FDS`; Go's `net.FileListener(os.NewFile(fd, \"\"))` serves on it), reachable from your other programs at `127.0.0.1:PORT`. Supplemental commands work as before. The terminal panel then opens in GNU bash too (`wasm --login` starts it; `exit` returns to the slicc prompt, and `wasm --login` starts it again). `export SLICC_SHELL=just-bash` switches both back. Wasm programs built with socket support talk over a private loopback network: a server listening on `127.0.0.1:PORT` in one of your wasm programs is reachable from your other wasm programs while it runs (the terminal panel and each scoop have networks of their own), and a program reaches the outside over HTTP through your network's proxy: `http_proxy` / `https_proxy` point at `127.0.0.1:3128` by default (`no_proxy` keeps `localhost` direct), so `curl http://…` works the way the shell's `curl` does, masked secrets included. HTTPS works too: the proxy terminates TLS with a certificate from your network's own CA, which `SSL_CERT_FILE` / `CURL_CA_BUNDLE` / `GIT_SSL_CAINFO` point programs at (`$HOME/.config/slicc/realm-ca-*.pem`; `-k` is never needed). A redirect reaches the program as it would any HTTP client (`curl -L` follows it), except on Sliccstart, whose fetch path follows redirects itself. No other traffic leaves: only `localhost` / `127.0.0.1` resolve. Once a Go toolchain package is installed, `go build` / `go run` build Go programs here (`go` is SLICC's driver; the output is a wasip1 program you run as `./prog`, or any `GOOS`/`GOARCH` whose standard library is installed; the standard library and your module's own packages only: no cgo, `//go:embed` or module downloads yet). Once a native CPython is installed, `python3` in GNU bash is native Python, and `pyodide` stays SLICC's Pyodide under its own name. Installed Python packages are on its path by themselves. Once `@ai-ecoverse/wasm-git` is installed, `git` in GNU bash is native git (in just-bash it stays SLICC's built-in; `wasm git …` reaches native git there). Native git authenticates by itself: its default credential helper, `git-credential-slicc`, hands it your GitHub login (or `$GH_TOKEN` / `$GITHUB_TOKEN`, or a `*_TOKEN` secret scoped to the host) masked, so `git clone` / `git push` over HTTPS to a private repo just work, and it commits as SLICC's git identity. Don't put tokens in remote URLs; your `~/.gitconfig` overrides both (`$HOME/.config/slicc/gitconfig` is the realm's system config, rewritten each run).\n\n## Conda / emscripten-forge (`ipk mamba`)\n\n`ipk mamba install <pkg>[=<version>]` installs emscripten-wasm32 packages from emscripten-forge / conda-forge into `/shared/lib/conda` (not `node_modules`). Executable files (shared objects, scripts) keep their executable bit. Prefer this for **forge C/WASM libraries** (for example `zlib`, `libpng`) that provide headers, `.a`, and SIDE_MODULE `.so` under that prefix.\n\nKeep using `ipk install` / `ipk add -g` for the **npm** packages that power these built-ins — forge names are not drop-in replacements today:\n\n- `convert` → `ipk add -g @imagemagick/magick-wasm@…` (forge `imagemagick` has no runnable `convert.wasm`)\n- `ffmpeg` → `ipk add -g @ffmpeg/core@…` (forge `ffmpeg` is libav `.a` only)\n- `python` → `ipk add pyodide@…` (no forge `pyodide`)\n\n```bash\nipk mamba install zlib # newest indexed build → /shared/lib/conda\nipk mamba install zlib=1.3.1 # exact version\nipk mamba list # conda-meta inventory\nipk mamba uninstall zlib\nipk mamba --help # channels, prefix, and thin-installer limits\n```\n\n## Running package.json scripts\n\n`npm run <script>` (also `ipk run`, `npm run-script`, and the `npm test` / `start` / `stop` / `restart` shortcuts) runs a `scripts` entry from the nearest `package.json`, in that package's directory. `npm run` with no script name lists what is available — read that list instead of guessing a script name.\n\n```bash\nnpm run # list scripts\nnpm run build # run build, with prebuild/postbuild around it\nnpm run build -- --watch # pass extra args to the script body\nnpm run build --silent # no banner, script output only (either side of the name)\nnpm run lint -- --help # --help after -- goes to the script, not to npm\n```\n\n`--silent`/`-s` and `--if-present` are npm's own flags anywhere before `--`; everything after `--` reaches the script untouched. Missing `start` falls back to `node server.js` when the package has one, and missing `restart` to `npm stop --if-present && npm start`.\n\nA bare bin word in a script body (`vitest run`) is rewritten to `ipx vitest run` when that package is installed, because `$PATH` does not cover `node_modules/.bin` shims. This also applies after keywords like `if`/`then`/`do`. A SLICC built-in with the same name wins, and an unknown word is not installed implicitly — install it with `ipk add <pkg>` first.\n";export{e as default};
@@ -1 +1 @@
1
- import{n as e}from"./rolldown-runtime-Dd_uD5pT.js";import{t}from"./logger-LESFN7Hj.js";import"./proxied-fetch-CoZ8jHud.js";import{i as n,r}from"./panel-rpc-DW7W4w6_.js";import{n as i,o as a,t as o}from"./providers-ymrZXUAC.js";import{s,t as c}from"./api-endpoint-D8lUKmPu.js";import{a as l,c as u,o as ee,s as d}from"./core-E6pC-3NP.js";import{t as f}from"./secrets-bridge-client-EgBSROu5.js";import{a as te,c as ne,i as re,l as ie}from"./bedrock-camp-compat-ByR2ly4i.js";import{r as ae,t as oe}from"./bedrock-camp-extra-models-DIuCBjcJ.js";import{s as se}from"./claude-model-version-ceOteQ2f.js";const ce=`slicc_oauth_extra_domains`;function p(e){try{let t=e.getItem(ce);if(!t)return{};let n=JSON.parse(t);if(typeof n!=`object`||!n||Array.isArray(n))return{};let r={};for(let[e,t]of Object.entries(n)){if(typeof e!=`string`||!Array.isArray(t))continue;let n=t.filter(e=>typeof e==`string`&&e.length>0);n.length>0&&(r[e]=n)}return r}catch{return{}}}function le(e,t){try{e.setItem(ce,JSON.stringify(t))}catch(e){throw Error(`Failed to persist OAuth extras (localStorage quota exceeded?): ${e instanceof Error?e.message:String(e)}`)}}function m(e,t){let n={input:0,output:0,cacheRead:0,cacheWrite:0},r=se(e);if(!r)return n;let i;for(let e of t.values()){let t=se(e.id);!t||t.family!==r.family||(!i||t.major>i.major||t.major===i.major&&t.minor>i.minor)&&(i={major:t.major,minor:t.minor,cost:e.cost})}return i?.cost??n}const ue=t(`model-policy`),h=`/etc/models`;function g(){return{sections:{}}}function de(e){let t=e.indexOf(`#`);return(t===-1?e:e.slice(0,t)).trim()}function fe(e){let t=g();if(typeof e!=`string`)return t;let n=null;for(let r of e.split(/\r?\n/)){let e=de(r);if(!e)continue;let i=/^\[([^\]]+)\]$/.exec(e);if(i){n=i[1].trim(),t.sections[n]??=[];continue}if(n===null){ue.warn(`model policy entry before any [provider] section — ignored`,{entry:e});continue}let a=e.startsWith(`-`),o=a?e.slice(1).trim():e,s=o.indexOf(`:`);if(s<=0||s===o.length-1){ue.warn(`model policy entry is not provider:model — ignored`,{entry:e});continue}t.sections[n].push({providerId:o.slice(0,s).trim(),modelId:o.slice(s+1).trim(),deny:a})}return t}function _(e,t,n){return e.providerId===t?e.modelId===`*`||e.modelId===n:!1}function pe(e,t){return e.sections[t]??[]}function me(e,t,n,r){return pe(e,t).some(e=>e.deny&&_(e,n,r))}function he(e,t,n,r){let i=pe(e,t);return i.some(e=>e.deny&&_(e,n,r))?!1:n===t||i.some(e=>!e.deny&&_(e,n,r))}let v=g();function ge(e){v=e}function _e(){return v}function ve(e,t,n){return`add \`${t}:${n}\` (or \`${t}:*\`) under \`[${e}]\` in ${h}`}var ye=e({ACCOUNTS_KEY:()=>x,__test__:()=>Te,addAccount:()=>I,applyProviderDefaults:()=>ke,clearAllSettings:()=>ft,clearApiKey:()=>st,clearBaseUrl:()=>ut,clearSelectedProvider:()=>it,ensureOAuthMaskReplica:()=>Xe,exportProviders:()=>dt,getAccounts:()=>P,getAllAvailableModels:()=>Me,getAllExtraOAuthDomains:()=>Le,getAlternativeModelProviders:()=>Ne,getApiKey:()=>at,getApiKeyForProvider:()=>V,getApiVersionForProvider:()=>et,getAvailableProviders:()=>T,getBaseUrl:()=>ct,getBaseUrlForProvider:()=>H,getDeploymentForProvider:()=>$e,getExtraOAuthDomains:()=>Pe,getModelCatalogProviderIds:()=>mt,getOAuthAccountInfo:()=>A,getProviderConfig:()=>D,getProviderModels:()=>k,getRawApiKeyForProvider:()=>B,getSelectedModelId:()=>U,getSelectedProvider:()=>W,isModelHiddenFromPicker:()=>M,isUsableOAuthMaskReplica:()=>R,logoutOAuthAccount:()=>Be,maskOAuthTokenWithRetry:()=>Ve,migrateLegacyAuthOnlySelection:()=>Ce,modelRunsOnProvider:()=>vt,persistOAuthMaskViaServiceWorker:()=>z,policyVisible:()=>N,providerOffersLlmModels:()=>E,removeAccount:()=>L,resolveCurrentModel:()=>J,resolveModelById:()=>q,resolveModelByShorthand:()=>yt,resolveModelIdForScoop:()=>Dt,resolveModelSelectionForScoop:()=>Q,saveOAuthAccount:()=>Qe,setApiKey:()=>ot,setBaseUrl:()=>lt,setExtraOAuthDomains:()=>Fe,setExtraOAuthDomainsAsync:()=>Ie,setSelectedModelId:()=>tt,setSelectedProvider:()=>rt});const y=ee,b=d,x=`slicc_accounts`,S=`selected-model`,be=[`slicc_provider`,`slicc_api_key`,`slicc_base_url`,`anthropic_api_key`,`api_provider`,`azure_resource`,`bedrock_region`],xe=new Set([`github`]);function C(e){let t;try{t=u()}catch{return!1}return t.includes(e)&&!a(e)}let w=!1;function Se(){if(!w){w=!0;for(let e of be)try{localStorage.removeItem(e)}catch{}Ce()}}function Ce(){try{let e=localStorage.getItem(S);if(e){let t=e.indexOf(`:`);if(t>0){let n=e.slice(0,t);(xe.has(n)||C(n))&&localStorage.removeItem(S)}}}catch{}try{let e=localStorage.getItem(x);if(!e)return;let t=JSON.parse(e);if(!Array.isArray(t))return;let n=t.filter(e=>!(typeof e==`object`&&e&&typeof e.providerId==`string`&&C(e.providerId)));n.length!==t.length&&localStorage.setItem(x,JSON.stringify(n))}catch{}}function we(){w=!1}const Te={_resetLegacyCleanup:we};function T(){let e=u().filter(a),t=i();return[...new Set([...e,...t])].filter(e=>!o(e)?.hidden)}function E(e){try{if(k(e).length>0)return!0}catch{}try{if(d(e).length>0)return!0}catch{}let t=o(e);return!!(t?.modelOverrides&&Object.keys(t.modelOverrides).length>0)}function Ee(e,t){try{if(k(e).some(e=>e.id===t))return!0}catch{}try{if(d(e).some(e=>e.id===t))return!0}catch{}let n=o(e);return!!(n?.modelOverrides&&Object.hasOwn(n.modelOverrides,t))}function D(e){return o(e)||{id:e,name:e.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),description:`${e} provider`,requiresApiKey:!0,requiresBaseUrl:!1}}function O(e,t){t.context_window!==void 0&&(e.contextWindow=t.context_window),t.max_tokens!==void 0&&(e.maxTokens=t.max_tokens),t.reasoning!==void 0&&(e.reasoning=t.reasoning),t.input!==void 0&&(e.input=t.input),t.cost!==void 0&&(e.cost=t.cost,e.inputCost=t.cost.input,e.outputCost=t.cost.output,e.cacheReadCost=t.cost.cacheRead,e.cacheWriteCost=t.cost.cacheWrite),t.compat!==void 0&&(e.compat={...e.compat??{},...t.compat}),t.thinkingLevelMap!==void 0&&(e.thinkingLevelMap={...e.thinkingLevelMap??{},...t.thinkingLevelMap})}function De(e){let t=re(e);return{...e,api:`bedrock-camp-converse`,provider:`bedrock-camp`,reasoning:e.reasoning===!0&&(ne(e)||t!==null),...t?{thinkingLevelMap:{...t}}:{}}}function k(e){try{if(e===`bedrock-camp`){let e=te(H(`bedrock-camp`));return ae(b(`amazon-bedrock`),oe).filter(t=>ie(t,e)).map(De)}let t=D(e);if(t.getModelIds){let n;try{n=t.getModelIds()}catch(t){return j.error(`Provider getModelIds callback failed`,{providerId:e,error:t instanceof Error?t.message:String(t)}),[]}let r=new Map;for(let e of u())try{for(let t of b(e))r.set(t.id,t)}catch{}return n.map(n=>{let i=n.api===`openai`?`openai`:`anthropic`,a=`${e}-${i}`,o=r.get(n.id),s;if(o)s={...o,api:a,provider:e};else if(s=G(e,n.id,``,a),n.name&&(s.name=n.name),i===`anthropic`){let e=m(n.id,r);s.cost=e,s.inputCost=e.input,s.outputCost=e.output,s.cacheReadCost=e.cacheRead,s.cacheWriteCost=e.cacheWrite}let c=t.modelOverrides?.[n.id];return c&&O(s,c),O(s,n),s})}if(t.isOAuth){let n=b(`anthropic`),r=`${e}-anthropic`;return n.map(n=>{let i={...n,api:r,provider:e},a=t.modelOverrides?.[n.id];return a&&O(i,a),i})}return b(e===`azure-ai-foundry`?`anthropic`:e)}catch(t){return j.error(`Failed to load models`,{providerId:e,error:t instanceof Error?t.message:String(t)}),[]}}function A(e){let t=P().find(t=>t.providerId===e);if(!t?.accessToken)return null;let n=!!t.tokenExpiresAt&&Date.now()>t.tokenExpiresAt-6e4;return{token:t.accessToken,maskedValue:t.maskedValue,expiresAt:t.tokenExpiresAt,userName:t.userName,userAvatar:t.userAvatar,scopes:t.scopes,expired:n}}const Oe=Object.assign({})[`/packages/webapp/providers.json`]??[],j=t(`provider-settings`);function ke(e=Oe){if(e.length===0||P().length>0)return;let t=new Set(T());for(let n of e)if(!(!n.providerId||!n.apiKey)){if(!t.has(n.providerId)){j.warn(`Unknown provider "${n.providerId}" in providers.json — skipping`);continue}I(n.providerId,n.apiKey,n.baseUrl)}let n=e.find(e=>e.providerId&&e.apiKey&&t.has(e.providerId));n?.model&&!localStorage.getItem(S)&&localStorage.setItem(S,`${n.providerId}:${n.model}`)}const Ae=[/haiku/i];function M(e){return Ae.some(t=>t.test(e))}function je(e){return e.filter(e=>!M(e.id))}function N(e,t){let n=$();if(n===null)return e;let r=_e();return e.filter(e=>!me(r,n,t,e.id))}function Me(){let e=P();if(e.length===0)return[];let t=new Map;for(let n of e){if(t.has(n.providerId))continue;let e=D(n.providerId);if(e.hidden||C(n.providerId))continue;let r=N(je(k(n.providerId)),n.providerId);if(r.length===0)continue;let i={providerId:n.providerId,providerName:e.name,models:r};t.set(n.providerId,i)}return[...t.values()]}function Ne(e){return Me().map(e=>e.providerId).filter(t=>t!==e)}function P(){Se();let e=localStorage.getItem(x);if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`object`&&!!e&&typeof e.providerId==`string`&&typeof e.apiKey==`string`):[]}catch{return[]}}function Pe(e){return p(localStorage)[e]??[]}function Fe(e,t){let n=p(localStorage),r=t.map(e=>e.trim()).filter(e=>e.length>0);r.length===0?delete n[e]:n[e]=r,le(localStorage,n)}async function Ie(e,t){if(n()){Fe(e,t);return}let i=r();if(!i)throw Error(`setExtraOAuthDomainsAsync: no DOM and no panel-rpc client — cannot persist to page localStorage`);let{storeAfter:a}=await i.call(`oauth-extras-set`,{providerId:e,domains:t});try{le(localStorage,a)}catch(t){j.warn(`worker-shim mirror failed after successful page write — reload to refresh`,{providerId:e,error:t instanceof Error?t.message:String(t)})}}function Le(){return p(localStorage)}function Re(e){localStorage.setItem(x,JSON.stringify(e))}async function F(e){if(n()){Re(e);return}let t=r();if(!t)throw Error(`saveAccountsAsync: no DOM and no panel-rpc client — cannot persist to page localStorage`);let i=JSON.stringify(e),{storedJson:a}=await t.call(`save-oauth-accounts`,{accountsJson:i});try{localStorage.setItem(x,a)}catch(e){j.warn(`worker-shim mirror failed after successful page write — reload to refresh`,{error:e instanceof Error?e.message:String(e)})}}function I(e,t,n,r,i){let a=P().filter(t=>t.providerId!==e),o={providerId:e,apiKey:t};n&&(o.baseUrl=n),r&&(o.deployment=r),i&&(o.apiVersion=i),a.push(o),Re(a)}async function ze(e){let t=l();try{if(t===`extension-direct`){let t=await new Promise(t=>{chrome.runtime.sendMessage({type:`secrets.delete`,name:`oauth.${e}.token`},n=>{chrome.runtime.lastError&&j.error(`SW secrets.delete transport failed`,{providerId:e,error:chrome.runtime.lastError.message}),t(n??{})})});t.error&&j.error(`SW secrets.delete returned error`,{providerId:e,error:t.error})}else if(t===`extension-delegate`){let t=await f(`secrets.delete`,{name:`oauth.${e}.token`});t?.error&&j.error(`Bridge secrets.delete returned error`,{providerId:e,error:t.error})}else if(t!==`connect`){let t=await fetch(s(`/api/secrets/oauth/${e}`),{method:`DELETE`,headers:c()});!t.ok&&t.status!==404&&j.warn(`OAuth replica DELETE non-ok`,{providerId:e,status:t.status})}}catch(n){j.error(`OAuth replica removal failed`,{providerId:e,topology:t,error:n instanceof Error?n.message:String(n)})}}async function L(e){let t=P().find(t=>t.providerId===e),n=D(e);t&&n?.isOAuth&&await Be(e),await ze(e),await F(P().filter(t=>t.providerId!==e));let r=localStorage.getItem(S)??``,i=r.indexOf(`:`);i>0&&r.slice(0,i)===e&&localStorage.removeItem(S)}async function Be(e){let t=P().find(t=>t.providerId===e);if(!t)return;let n=D(e);if(n?.isOAuth){if(n.onOAuthLogout)try{await n.onOAuthLogout()}catch(t){j.warn(`onOAuthLogout failed`,{providerId:e,error:t instanceof Error?t.message:String(t)})}if(n.getOAuthLogoutUrl){let r=n.getOAuthLogoutUrl(t);if(r){let{openIdpLogoutUrl:t}=await import(`./oauth-service-Bx_Dy3GC.js`);await t(r).catch(t=>{j.warn(`IdP logout popup failed`,{providerId:e,error:t instanceof Error?t.message:String(t)})})}}await F(P().map(t=>t.providerId===e?{providerId:t.providerId,apiKey:``,baseUrl:t.baseUrl,userName:t.userName,userAvatar:t.userAvatar,loggedOut:!0}:t)),await ze(e)}}async function Ve(e,t={}){let n=Math.max(1,t.attempts??3),r=t.delayMs??150,i=t.sleep??(e=>new Promise(t=>setTimeout(t,e))),a;for(let t=0;t<n;t++){let o=await e();if(o.maskedValue)return{maskedValue:o.maskedValue};o.error&&(a=o.error),t<n-1&&await i(r)}return{lastError:a}}const He=`access token rotated during mask write`;function Ue(e,t,n,r){let i=r.find(t=>t.providerId===e);return i?.accessToken?i.accessToken===t?(i.maskedValue=n,{maskedValue:n}):(j.warn(`OAuth mask write raced with token rotation; discarding replica`,{providerId:e}),{error:He}):{error:`account gone after mask write`}}function R(e,t){return!!e&&e!==t}async function z(e,t,n){let r={providerId:e.providerId,accessToken:e.accessToken,domains:e.domains.join(`,`)},{maskedValue:i,lastError:a}=await Ve(()=>t.sendMaskRequest(r),n);if(!R(i,e.accessToken)){let t=i?`mask replica equals the access token`:a??`no error reported (cold SW or empty reply)`;return j.error(`OAuth mask give-up: no masked value after retries`,{providerId:e.providerId,reason:t}),{error:t}}let o=t.getAccounts(),s=Ue(e.providerId,e.accessToken,i,o);return s.maskedValue&&await t.saveAccounts(o),s}function We(e){let t=D(e).oauthTokenDomains??[],n=Pe(e),r=new Set,i=[];for(let e of[...t,...n]){let t=e.toLowerCase();r.has(t)||(r.add(t),i.push(e))}return i}function Ge(e){return new Promise(t=>{chrome.runtime.sendMessage({type:`secrets.mask-oauth-token`,...e},n=>{chrome.runtime.lastError&&j.error(`SW mask-oauth-token transport failed`,{providerId:e.providerId,error:chrome.runtime.lastError.message});let r=typeof n==`object`&&n?n:void 0;r?.error&&j.warn(`SW mask-oauth-token returned error`,{providerId:e.providerId,error:r.error}),t(r??{})})})}function Ke(e){return f(`secrets.mask-oauth-token`,e).then(t=>(t?.error&&j.warn(`Bridge mask-oauth-token returned error`,{providerId:e.providerId,error:t.error}),t??{})).catch(t=>(j.error(`Bridge mask-oauth-token transport failed`,{providerId:e.providerId,error:t instanceof Error?t.message:String(t)}),{}))}async function qe(e,t,n){let r=s(`/api/secrets/oauth-update`),i=await fetch(r,{method:`POST`,headers:c({"Content-Type":`application/json`}),body:JSON.stringify({providerId:e,accessToken:t,domains:n})});if(!i.ok)return j.warn(`OAuth replica POST non-ok`,{providerId:e,status:i.status,url:r}),{error:`OAuth replica POST HTTP ${i.status}`};let a=await i.json();if(typeof a.maskedValue!=`string`)return j.warn(`OAuth replica POST ok but missing maskedValue`,{providerId:e,url:r}),{error:`OAuth replica POST ok but missing maskedValue`};if(!R(a.maskedValue,t))return j.error(`OAuth mask replica equals the access token; refusing to persist`,{providerId:e}),{error:`mask replica equals the access token`};let o=P(),l=Ue(e,t,a.maskedValue,o);return l.maskedValue&&await F(o),l}async function Je(e,t){let n=await Ye(e,t);if(n.error!==He)return n;let r=P().find(t=>t.providerId===e)?.accessToken;return!r||r===t?n:Ye(e,r)}async function Ye(e,t){let n=We(e);if(n.length===0)return{error:`no oauth token domains configured`};let r=l();try{return r===`extension-direct`?z({providerId:e,accessToken:t,domains:n},{sendMaskRequest:Ge,getAccounts:P,saveAccounts:F}):r===`extension-delegate`?z({providerId:e,accessToken:t,domains:n},{sendMaskRequest:Ke,getAccounts:P,saveAccounts:F}):r===`connect`?{error:`no replica store in connect mode`}:await qe(e,t,n)}catch(t){let n=t instanceof Error?t.message:String(t);return j.error(`OAuth replica sync failed`,{providerId:e,topology:r,error:n}),{error:n}}}async function Xe(e){let t=P().find(t=>t.providerId===e);return t?.accessToken?R(t.maskedValue,t.accessToken)?{maskedValue:t.maskedValue}:Je(e,t.accessToken):{error:`no access token held`}}function Ze(e,t){if(e.accessToken)return`scopes`in e?e.scopes:t?.scopes}async function Qe(e){let t=P().find(t=>t.providerId===e.providerId),n=P().filter(t=>t.providerId!==e.providerId);n.push({providerId:e.providerId,apiKey:``,accessToken:e.accessToken,refreshToken:e.refreshToken,tokenExpiresAt:e.tokenExpiresAt,userName:e.userName,userAvatar:e.userAvatar,baseUrl:e.baseUrl??t?.baseUrl,scopes:Ze(e,t)}),await F(n),await Je(e.providerId,e.accessToken)}function B(e){let t=P().find(t=>t.providerId===e);return t&&(t.accessToken||t.apiKey)||null}function V(e){let t=P().find(t=>t.providerId===e);return t?t.accessToken||t.apiKey||(D(e).optionalApiKey?`local`:null):null}function H(e){return P().find(t=>t.providerId===e)?.baseUrl??null}function $e(e){return P().find(t=>t.providerId===e)?.deployment??null}function et(e){return P().find(t=>t.providerId===e)?.apiVersion??null}function U(){let e=localStorage.getItem(S)||``,t=e.indexOf(`:`);return t>=0?e.slice(t+1):e}function tt(e){let t=e.indexOf(`:`);if(t>0){let n=e.slice(0,t),r=new Set([...i(),...T()]),a=n.includes(`.`);if(r.has(n)||!a){localStorage.setItem(S,e);return}}let n=W();localStorage.setItem(S,`${n}:${e}`)}function nt(){return localStorage.getItem(S)||``}function W(){let e=nt(),t=e.indexOf(`:`);if(t>0)return e.slice(0,t);let n=P(),r=U();if(r){let e=n.find(e=>E(e.providerId)&&Ee(e.providerId,r));if(e)return e.providerId}let i=n.find(e=>E(e.providerId));return i?i.providerId:n.length>0?n[0].providerId:`anthropic`}function rt(e){let t=U();localStorage.setItem(S,`${e}:${t}`)}function it(){let e=U();localStorage.setItem(S,e)}function at(){return V(W())}function ot(e){let t=W();I(t,e,H(t)??void 0)}async function st(){await L(W())}function ct(){return H(W())}function lt(e){let t=W(),n=B(t);n&&I(t,n,e||void 0)}function ut(){let e=W(),t=B(e);t&&I(e,t)}function dt(){let e=P(),t=W(),n=U();return e.map(e=>{let r={providerId:e.providerId,apiKey:e.apiKey};return e.baseUrl&&(r.baseUrl=e.baseUrl),e.providerId===t&&n&&(r.model=n),r})}async function ft(){let e=P();await Promise.allSettled(e.map(e=>L(e.providerId))),localStorage.removeItem(x),localStorage.removeItem(S);for(let e of be)localStorage.removeItem(e)}function pt(e){return/^(?:gpt[-.]?|o[0-9]|chatgpt)/i.test(e)?`openai`:`anthropic`}function G(e,t,n,r){return{id:t,name:t,provider:e,api:r??`${e}-${pt(t)}`,baseUrl:n??``,contextWindow:2e5,maxTokens:16384,input:[`text`,`image`],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},reasoning:!0}}function K(e,t){return t.isOAuth||e===`azure-ai-foundry`?`anthropic`:e===`bedrock-camp`?`amazon-bedrock`:e}function mt(){let e=new Set;for(let t of P())t.loggedOut||(e.add(t.providerId),e.add(K(t.providerId,D(t.providerId))));return[...e]}function ht(e,t,n){let r=k(e).find(e=>e.id===t);return r?n?{...r,baseUrl:n}:r:null}function gt(e,t,n,r){return n.isOAuth?k(t).find(e=>e.id===r)||{...e,api:`${t}-anthropic`,provider:t}:t===`bedrock-camp`?{...e,api:`bedrock-camp-converse`,provider:`bedrock-camp`}:e}function _t(e,t,n,r,i){let a=ht(e,n,r);if(a)return a;if(t.isOAuth)return G(e,n,r);if(i)throw Error(`Model ${n} is not available from provider ${e}`);return J()}function q(e,t){if(!e)return J();let n=t??W(),r=H(n),i=D(n);if(t!==void 0){let t=ht(n,e,r);if(t)return t}try{let t=K(n,i),a=y(t,e);if(!a?.id)throw Error(`Model ${e} not found`);let o=gt(a,n,i,e);return r?{...o,baseUrl:r}:o}catch(a){return j.debug(`resolveModelById: pi-ai lookup miss, using provider fallback`,{providerId:n,modelId:e,error:a instanceof Error?a.message:String(a)}),_t(n,i,e,r,t!==void 0)}}function vt(e,t){return e.provider===t||e.provider===K(t,D(t))}function J(){let e=W(),t=U(),n=H(e),r=k(e),i=D(e),a=i.defaultModelId?r.find(e=>e.id.toLowerCase().includes(i.defaultModelId.toLowerCase()))?.id:void 0,o=t||a||r[0]?.id||`claude-sonnet-4-6`;try{let t=K(e,i),a=y(t,o);if(!a?.id)throw Error(`Model ${o} not found in ${t} registry`);let s=a;return i.isOAuth?s=r.find(e=>e.id===o)||{...s,api:`${e}-anthropic`,provider:e}:e===`bedrock-camp`&&(s={...s,api:`bedrock-camp-converse`,provider:`bedrock-camp`}),n&&(s={...s,baseUrl:n}),s}catch(t){j.debug(`resolveCurrentModel: pi-ai lookup miss, using provider fallback`,{providerId:e,effectiveModelId:o,error:t instanceof Error?t.message:String(t)});let a=r.find(e=>e.id===o);return a?n?{...a,baseUrl:n}:a:i.isOAuth?G(e,o,n):y(`anthropic`,`claude-sonnet-4-0`)}}function yt(e){let t=e.toLowerCase();if(!t)return null;let n=null;try{n=W()}catch{}if(n!==null){let e=Y(t,[n]);if(e!==null)return e}return Y(t,P().map(e=>e.providerId))}function Y(e,t){let n=null,r=-1;for(let i of t)for(let t of k(i)){let i=t.id.toLowerCase(),a=(t.name??``).toLowerCase();if(!i.includes(e)&&!a.includes(e))continue;let o=t.contextWindow??0;(o>r||o===r&&Ot(t.id,n??``)>0)&&(r=o,n=t.id)}return n}function X(){let e=[];try{for(let t of P())e.includes(t.providerId)||e.push(t.providerId)}catch{}try{let t=W();e.includes(t)||e.push(t)}catch{}return e}function bt(e){let t=e.indexOf(`:`);if(t<=0||t===e.length-1)return null;let n=e.slice(0,t),r=e.slice(t+1),i=X().includes(n);if(i)return{providerId:n,modelId:r,configured:i};let a=!1;try{a=T().includes(n)}catch{}return a?{providerId:n,modelId:r,configured:!1}:null}function Z(e,t,n=!0){let r=[e],i=n?Y(e.toLowerCase(),[t]):null;i!==null&&i!==e&&r.push(i);let a=[];try{a=k(t)}catch{}for(let n of r)if(!(a.length>0&&!a.some(e=>e.id===n)))try{if(q(n,t).id===n)return{modelId:n,providerId:t}}catch(r){j.debug(`selectModelFromProvider: candidate did not resolve`,{input:e,candidate:n,providerId:t,error:r instanceof Error?r.message:String(r)})}return null}function xt(e){return e.map(e=>`${e.providerId}:${e.modelId}`).join(`, `)}function Q(e){if(!e)return{ok:!1,error:`unknown model: (empty)`};let t=bt(e);if(t)return Tt(e,t);let n=null;try{n=W()}catch{}if(n!==null){let t=Z(e,n);if(t)return wt(t)}return Et(e,n)}function $(){try{return W()}catch{return null}}function St(e){let t=$();return t===null||he(_e(),t,e.providerId,e.modelId)}function Ct(e){let t=$()??`<none>`;return{ok:!1,error:`model not allowed: ${`${e.providerId}:${e.modelId}`} is blocked by ${h} while "${t}" is selected — ${ve(t,e.providerId,e.modelId)}`}}function wt(e){return St(e)?{ok:!0,selection:e}:Ct(e)}function Tt(e,t){if(!t.configured){let n=X();return{ok:!1,error:`unknown model: ${e} (provider "${t.providerId}" is not configured${n.length>0?`; configured: ${n.join(`, `)}`:``})`}}let n=Z(t.modelId,t.providerId);return n?wt(n):{ok:!1,error:`unknown model: ${e} (provider "${t.providerId}" does not offer "${t.modelId}")`}}function Et(e,t){let n=X().filter(e=>e!==t);for(let t of[`exact`,`shorthand`]){let r=[];for(let i of n){let n=t===`exact`?e:Y(e.toLowerCase(),[i]);if(n===null)continue;let a=Z(n,i,!1);a&&r.push(a)}let i=r.filter(St);if(i.length===0&&r.length>0)return Ct(r[0]);if(i.length===1)return{ok:!0,selection:i[0]};if(i.length>1)return{ok:!1,error:`ambiguous model: ${e} matches ${xt(i)} — qualify it as provider:model`}}return{ok:!1,error:`unknown model: ${e}`}}function Dt(e){let t=Q(e);return t.ok?t.selection.modelId:null}function Ot(e,t){let n=e.match(/\d+/g)?.map(Number)??[],r=t.match(/\d+/g)?.map(Number)??[],i=Math.max(n.length,r.length);for(let e=0;e<i;e++){let t=(n[e]??0)-(r[e]??0);if(t!==0)return t}return 0}export{p as C,m as S,Qe as _,V as a,fe as b,$e as c,U as d,W as f,Q as g,q as h,at as i,A as l,J as m,Xe as n,et as o,vt as p,P as r,H as s,ye as t,k as u,h as v,ge as x,g as y};
1
+ import{n as e}from"./rolldown-runtime-Dd_uD5pT.js";import{t}from"./logger-LESFN7Hj.js";import"./proxied-fetch-CoZ8jHud.js";import{i as n,r}from"./panel-rpc-DW7W4w6_.js";import{n as i,o as a,t as o}from"./providers-fZ3KX8Lg.js";import{s,t as c}from"./api-endpoint-D8lUKmPu.js";import{a as l,c as u,o as ee,s as d}from"./core-E6pC-3NP.js";import{t as f}from"./secrets-bridge-client-EgBSROu5.js";import{a as te,c as ne,i as re,l as ie}from"./bedrock-camp-compat-ByR2ly4i.js";import{r as ae,t as oe}from"./bedrock-camp-extra-models-DIuCBjcJ.js";import{s as se}from"./claude-model-version-ceOteQ2f.js";const ce=`slicc_oauth_extra_domains`;function p(e){try{let t=e.getItem(ce);if(!t)return{};let n=JSON.parse(t);if(typeof n!=`object`||!n||Array.isArray(n))return{};let r={};for(let[e,t]of Object.entries(n)){if(typeof e!=`string`||!Array.isArray(t))continue;let n=t.filter(e=>typeof e==`string`&&e.length>0);n.length>0&&(r[e]=n)}return r}catch{return{}}}function le(e,t){try{e.setItem(ce,JSON.stringify(t))}catch(e){throw Error(`Failed to persist OAuth extras (localStorage quota exceeded?): ${e instanceof Error?e.message:String(e)}`)}}function m(e,t){let n={input:0,output:0,cacheRead:0,cacheWrite:0},r=se(e);if(!r)return n;let i;for(let e of t.values()){let t=se(e.id);!t||t.family!==r.family||(!i||t.major>i.major||t.major===i.major&&t.minor>i.minor)&&(i={major:t.major,minor:t.minor,cost:e.cost})}return i?.cost??n}const ue=t(`model-policy`),h=`/etc/models`;function g(){return{sections:{}}}function de(e){let t=e.indexOf(`#`);return(t===-1?e:e.slice(0,t)).trim()}function fe(e){let t=g();if(typeof e!=`string`)return t;let n=null;for(let r of e.split(/\r?\n/)){let e=de(r);if(!e)continue;let i=/^\[([^\]]+)\]$/.exec(e);if(i){n=i[1].trim(),t.sections[n]??=[];continue}if(n===null){ue.warn(`model policy entry before any [provider] section — ignored`,{entry:e});continue}let a=e.startsWith(`-`),o=a?e.slice(1).trim():e,s=o.indexOf(`:`);if(s<=0||s===o.length-1){ue.warn(`model policy entry is not provider:model — ignored`,{entry:e});continue}t.sections[n].push({providerId:o.slice(0,s).trim(),modelId:o.slice(s+1).trim(),deny:a})}return t}function _(e,t,n){return e.providerId===t?e.modelId===`*`||e.modelId===n:!1}function pe(e,t){return e.sections[t]??[]}function me(e,t,n,r){return pe(e,t).some(e=>e.deny&&_(e,n,r))}function he(e,t,n,r){let i=pe(e,t);return i.some(e=>e.deny&&_(e,n,r))?!1:n===t||i.some(e=>!e.deny&&_(e,n,r))}let v=g();function ge(e){v=e}function _e(){return v}function ve(e,t,n){return`add \`${t}:${n}\` (or \`${t}:*\`) under \`[${e}]\` in ${h}`}var ye=e({ACCOUNTS_KEY:()=>x,__test__:()=>Te,addAccount:()=>I,applyProviderDefaults:()=>ke,clearAllSettings:()=>ft,clearApiKey:()=>st,clearBaseUrl:()=>ut,clearSelectedProvider:()=>it,ensureOAuthMaskReplica:()=>Xe,exportProviders:()=>dt,getAccounts:()=>P,getAllAvailableModels:()=>Me,getAllExtraOAuthDomains:()=>Le,getAlternativeModelProviders:()=>Ne,getApiKey:()=>at,getApiKeyForProvider:()=>V,getApiVersionForProvider:()=>et,getAvailableProviders:()=>T,getBaseUrl:()=>ct,getBaseUrlForProvider:()=>H,getDeploymentForProvider:()=>$e,getExtraOAuthDomains:()=>Pe,getModelCatalogProviderIds:()=>mt,getOAuthAccountInfo:()=>A,getProviderConfig:()=>D,getProviderModels:()=>k,getRawApiKeyForProvider:()=>B,getSelectedModelId:()=>U,getSelectedProvider:()=>W,isModelHiddenFromPicker:()=>M,isUsableOAuthMaskReplica:()=>R,logoutOAuthAccount:()=>Be,maskOAuthTokenWithRetry:()=>Ve,migrateLegacyAuthOnlySelection:()=>Ce,modelRunsOnProvider:()=>vt,persistOAuthMaskViaServiceWorker:()=>z,policyVisible:()=>N,providerOffersLlmModels:()=>E,removeAccount:()=>L,resolveCurrentModel:()=>J,resolveModelById:()=>q,resolveModelByShorthand:()=>yt,resolveModelIdForScoop:()=>Dt,resolveModelSelectionForScoop:()=>Q,saveOAuthAccount:()=>Qe,setApiKey:()=>ot,setBaseUrl:()=>lt,setExtraOAuthDomains:()=>Fe,setExtraOAuthDomainsAsync:()=>Ie,setSelectedModelId:()=>tt,setSelectedProvider:()=>rt});const y=ee,b=d,x=`slicc_accounts`,S=`selected-model`,be=[`slicc_provider`,`slicc_api_key`,`slicc_base_url`,`anthropic_api_key`,`api_provider`,`azure_resource`,`bedrock_region`],xe=new Set([`github`]);function C(e){let t;try{t=u()}catch{return!1}return t.includes(e)&&!a(e)}let w=!1;function Se(){if(!w){w=!0;for(let e of be)try{localStorage.removeItem(e)}catch{}Ce()}}function Ce(){try{let e=localStorage.getItem(S);if(e){let t=e.indexOf(`:`);if(t>0){let n=e.slice(0,t);(xe.has(n)||C(n))&&localStorage.removeItem(S)}}}catch{}try{let e=localStorage.getItem(x);if(!e)return;let t=JSON.parse(e);if(!Array.isArray(t))return;let n=t.filter(e=>!(typeof e==`object`&&e&&typeof e.providerId==`string`&&C(e.providerId)));n.length!==t.length&&localStorage.setItem(x,JSON.stringify(n))}catch{}}function we(){w=!1}const Te={_resetLegacyCleanup:we};function T(){let e=u().filter(a),t=i();return[...new Set([...e,...t])].filter(e=>!o(e)?.hidden)}function E(e){try{if(k(e).length>0)return!0}catch{}try{if(d(e).length>0)return!0}catch{}let t=o(e);return!!(t?.modelOverrides&&Object.keys(t.modelOverrides).length>0)}function Ee(e,t){try{if(k(e).some(e=>e.id===t))return!0}catch{}try{if(d(e).some(e=>e.id===t))return!0}catch{}let n=o(e);return!!(n?.modelOverrides&&Object.hasOwn(n.modelOverrides,t))}function D(e){return o(e)||{id:e,name:e.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),description:`${e} provider`,requiresApiKey:!0,requiresBaseUrl:!1}}function O(e,t){t.context_window!==void 0&&(e.contextWindow=t.context_window),t.max_tokens!==void 0&&(e.maxTokens=t.max_tokens),t.reasoning!==void 0&&(e.reasoning=t.reasoning),t.input!==void 0&&(e.input=t.input),t.cost!==void 0&&(e.cost=t.cost,e.inputCost=t.cost.input,e.outputCost=t.cost.output,e.cacheReadCost=t.cost.cacheRead,e.cacheWriteCost=t.cost.cacheWrite),t.compat!==void 0&&(e.compat={...e.compat??{},...t.compat}),t.thinkingLevelMap!==void 0&&(e.thinkingLevelMap={...e.thinkingLevelMap??{},...t.thinkingLevelMap})}function De(e){let t=re(e);return{...e,api:`bedrock-camp-converse`,provider:`bedrock-camp`,reasoning:e.reasoning===!0&&(ne(e)||t!==null),...t?{thinkingLevelMap:{...t}}:{}}}function k(e){try{if(e===`bedrock-camp`){let e=te(H(`bedrock-camp`));return ae(b(`amazon-bedrock`),oe).filter(t=>ie(t,e)).map(De)}let t=D(e);if(t.getModelIds){let n;try{n=t.getModelIds()}catch(t){return j.error(`Provider getModelIds callback failed`,{providerId:e,error:t instanceof Error?t.message:String(t)}),[]}let r=new Map;for(let e of u())try{for(let t of b(e))r.set(t.id,t)}catch{}return n.map(n=>{let i=n.api===`openai`?`openai`:`anthropic`,a=`${e}-${i}`,o=r.get(n.id),s;if(o)s={...o,api:a,provider:e};else if(s=G(e,n.id,``,a),n.name&&(s.name=n.name),i===`anthropic`){let e=m(n.id,r);s.cost=e,s.inputCost=e.input,s.outputCost=e.output,s.cacheReadCost=e.cacheRead,s.cacheWriteCost=e.cacheWrite}let c=t.modelOverrides?.[n.id];return c&&O(s,c),O(s,n),s})}if(t.isOAuth){let n=b(`anthropic`),r=`${e}-anthropic`;return n.map(n=>{let i={...n,api:r,provider:e},a=t.modelOverrides?.[n.id];return a&&O(i,a),i})}return b(e===`azure-ai-foundry`?`anthropic`:e)}catch(t){return j.error(`Failed to load models`,{providerId:e,error:t instanceof Error?t.message:String(t)}),[]}}function A(e){let t=P().find(t=>t.providerId===e);if(!t?.accessToken)return null;let n=!!t.tokenExpiresAt&&Date.now()>t.tokenExpiresAt-6e4;return{token:t.accessToken,maskedValue:t.maskedValue,expiresAt:t.tokenExpiresAt,userName:t.userName,userAvatar:t.userAvatar,scopes:t.scopes,expired:n}}const Oe=Object.assign({})[`/packages/webapp/providers.json`]??[],j=t(`provider-settings`);function ke(e=Oe){if(e.length===0||P().length>0)return;let t=new Set(T());for(let n of e)if(!(!n.providerId||!n.apiKey)){if(!t.has(n.providerId)){j.warn(`Unknown provider "${n.providerId}" in providers.json — skipping`);continue}I(n.providerId,n.apiKey,n.baseUrl)}let n=e.find(e=>e.providerId&&e.apiKey&&t.has(e.providerId));n?.model&&!localStorage.getItem(S)&&localStorage.setItem(S,`${n.providerId}:${n.model}`)}const Ae=[/haiku/i];function M(e){return Ae.some(t=>t.test(e))}function je(e){return e.filter(e=>!M(e.id))}function N(e,t){let n=$();if(n===null)return e;let r=_e();return e.filter(e=>!me(r,n,t,e.id))}function Me(){let e=P();if(e.length===0)return[];let t=new Map;for(let n of e){if(t.has(n.providerId))continue;let e=D(n.providerId);if(e.hidden||C(n.providerId))continue;let r=N(je(k(n.providerId)),n.providerId);if(r.length===0)continue;let i={providerId:n.providerId,providerName:e.name,models:r};t.set(n.providerId,i)}return[...t.values()]}function Ne(e){return Me().map(e=>e.providerId).filter(t=>t!==e)}function P(){Se();let e=localStorage.getItem(x);if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`object`&&!!e&&typeof e.providerId==`string`&&typeof e.apiKey==`string`):[]}catch{return[]}}function Pe(e){return p(localStorage)[e]??[]}function Fe(e,t){let n=p(localStorage),r=t.map(e=>e.trim()).filter(e=>e.length>0);r.length===0?delete n[e]:n[e]=r,le(localStorage,n)}async function Ie(e,t){if(n()){Fe(e,t);return}let i=r();if(!i)throw Error(`setExtraOAuthDomainsAsync: no DOM and no panel-rpc client — cannot persist to page localStorage`);let{storeAfter:a}=await i.call(`oauth-extras-set`,{providerId:e,domains:t});try{le(localStorage,a)}catch(t){j.warn(`worker-shim mirror failed after successful page write — reload to refresh`,{providerId:e,error:t instanceof Error?t.message:String(t)})}}function Le(){return p(localStorage)}function Re(e){localStorage.setItem(x,JSON.stringify(e))}async function F(e){if(n()){Re(e);return}let t=r();if(!t)throw Error(`saveAccountsAsync: no DOM and no panel-rpc client — cannot persist to page localStorage`);let i=JSON.stringify(e),{storedJson:a}=await t.call(`save-oauth-accounts`,{accountsJson:i});try{localStorage.setItem(x,a)}catch(e){j.warn(`worker-shim mirror failed after successful page write — reload to refresh`,{error:e instanceof Error?e.message:String(e)})}}function I(e,t,n,r,i){let a=P().filter(t=>t.providerId!==e),o={providerId:e,apiKey:t};n&&(o.baseUrl=n),r&&(o.deployment=r),i&&(o.apiVersion=i),a.push(o),Re(a)}async function ze(e){let t=l();try{if(t===`extension-direct`){let t=await new Promise(t=>{chrome.runtime.sendMessage({type:`secrets.delete`,name:`oauth.${e}.token`},n=>{chrome.runtime.lastError&&j.error(`SW secrets.delete transport failed`,{providerId:e,error:chrome.runtime.lastError.message}),t(n??{})})});t.error&&j.error(`SW secrets.delete returned error`,{providerId:e,error:t.error})}else if(t===`extension-delegate`){let t=await f(`secrets.delete`,{name:`oauth.${e}.token`});t?.error&&j.error(`Bridge secrets.delete returned error`,{providerId:e,error:t.error})}else if(t!==`connect`){let t=await fetch(s(`/api/secrets/oauth/${e}`),{method:`DELETE`,headers:c()});!t.ok&&t.status!==404&&j.warn(`OAuth replica DELETE non-ok`,{providerId:e,status:t.status})}}catch(n){j.error(`OAuth replica removal failed`,{providerId:e,topology:t,error:n instanceof Error?n.message:String(n)})}}async function L(e){let t=P().find(t=>t.providerId===e),n=D(e);t&&n?.isOAuth&&await Be(e),await ze(e),await F(P().filter(t=>t.providerId!==e));let r=localStorage.getItem(S)??``,i=r.indexOf(`:`);i>0&&r.slice(0,i)===e&&localStorage.removeItem(S)}async function Be(e){let t=P().find(t=>t.providerId===e);if(!t)return;let n=D(e);if(n?.isOAuth){if(n.onOAuthLogout)try{await n.onOAuthLogout()}catch(t){j.warn(`onOAuthLogout failed`,{providerId:e,error:t instanceof Error?t.message:String(t)})}if(n.getOAuthLogoutUrl){let r=n.getOAuthLogoutUrl(t);if(r){let{openIdpLogoutUrl:t}=await import(`./oauth-service-Bx_Dy3GC.js`);await t(r).catch(t=>{j.warn(`IdP logout popup failed`,{providerId:e,error:t instanceof Error?t.message:String(t)})})}}await F(P().map(t=>t.providerId===e?{providerId:t.providerId,apiKey:``,baseUrl:t.baseUrl,userName:t.userName,userAvatar:t.userAvatar,loggedOut:!0}:t)),await ze(e)}}async function Ve(e,t={}){let n=Math.max(1,t.attempts??3),r=t.delayMs??150,i=t.sleep??(e=>new Promise(t=>setTimeout(t,e))),a;for(let t=0;t<n;t++){let o=await e();if(o.maskedValue)return{maskedValue:o.maskedValue};o.error&&(a=o.error),t<n-1&&await i(r)}return{lastError:a}}const He=`access token rotated during mask write`;function Ue(e,t,n,r){let i=r.find(t=>t.providerId===e);return i?.accessToken?i.accessToken===t?(i.maskedValue=n,{maskedValue:n}):(j.warn(`OAuth mask write raced with token rotation; discarding replica`,{providerId:e}),{error:He}):{error:`account gone after mask write`}}function R(e,t){return!!e&&e!==t}async function z(e,t,n){let r={providerId:e.providerId,accessToken:e.accessToken,domains:e.domains.join(`,`)},{maskedValue:i,lastError:a}=await Ve(()=>t.sendMaskRequest(r),n);if(!R(i,e.accessToken)){let t=i?`mask replica equals the access token`:a??`no error reported (cold SW or empty reply)`;return j.error(`OAuth mask give-up: no masked value after retries`,{providerId:e.providerId,reason:t}),{error:t}}let o=t.getAccounts(),s=Ue(e.providerId,e.accessToken,i,o);return s.maskedValue&&await t.saveAccounts(o),s}function We(e){let t=D(e).oauthTokenDomains??[],n=Pe(e),r=new Set,i=[];for(let e of[...t,...n]){let t=e.toLowerCase();r.has(t)||(r.add(t),i.push(e))}return i}function Ge(e){return new Promise(t=>{chrome.runtime.sendMessage({type:`secrets.mask-oauth-token`,...e},n=>{chrome.runtime.lastError&&j.error(`SW mask-oauth-token transport failed`,{providerId:e.providerId,error:chrome.runtime.lastError.message});let r=typeof n==`object`&&n?n:void 0;r?.error&&j.warn(`SW mask-oauth-token returned error`,{providerId:e.providerId,error:r.error}),t(r??{})})})}function Ke(e){return f(`secrets.mask-oauth-token`,e).then(t=>(t?.error&&j.warn(`Bridge mask-oauth-token returned error`,{providerId:e.providerId,error:t.error}),t??{})).catch(t=>(j.error(`Bridge mask-oauth-token transport failed`,{providerId:e.providerId,error:t instanceof Error?t.message:String(t)}),{}))}async function qe(e,t,n){let r=s(`/api/secrets/oauth-update`),i=await fetch(r,{method:`POST`,headers:c({"Content-Type":`application/json`}),body:JSON.stringify({providerId:e,accessToken:t,domains:n})});if(!i.ok)return j.warn(`OAuth replica POST non-ok`,{providerId:e,status:i.status,url:r}),{error:`OAuth replica POST HTTP ${i.status}`};let a=await i.json();if(typeof a.maskedValue!=`string`)return j.warn(`OAuth replica POST ok but missing maskedValue`,{providerId:e,url:r}),{error:`OAuth replica POST ok but missing maskedValue`};if(!R(a.maskedValue,t))return j.error(`OAuth mask replica equals the access token; refusing to persist`,{providerId:e}),{error:`mask replica equals the access token`};let o=P(),l=Ue(e,t,a.maskedValue,o);return l.maskedValue&&await F(o),l}async function Je(e,t){let n=await Ye(e,t);if(n.error!==He)return n;let r=P().find(t=>t.providerId===e)?.accessToken;return!r||r===t?n:Ye(e,r)}async function Ye(e,t){let n=We(e);if(n.length===0)return{error:`no oauth token domains configured`};let r=l();try{return r===`extension-direct`?z({providerId:e,accessToken:t,domains:n},{sendMaskRequest:Ge,getAccounts:P,saveAccounts:F}):r===`extension-delegate`?z({providerId:e,accessToken:t,domains:n},{sendMaskRequest:Ke,getAccounts:P,saveAccounts:F}):r===`connect`?{error:`no replica store in connect mode`}:await qe(e,t,n)}catch(t){let n=t instanceof Error?t.message:String(t);return j.error(`OAuth replica sync failed`,{providerId:e,topology:r,error:n}),{error:n}}}async function Xe(e){let t=P().find(t=>t.providerId===e);return t?.accessToken?R(t.maskedValue,t.accessToken)?{maskedValue:t.maskedValue}:Je(e,t.accessToken):{error:`no access token held`}}function Ze(e,t){if(e.accessToken)return`scopes`in e?e.scopes:t?.scopes}async function Qe(e){let t=P().find(t=>t.providerId===e.providerId),n=P().filter(t=>t.providerId!==e.providerId);n.push({providerId:e.providerId,apiKey:``,accessToken:e.accessToken,refreshToken:e.refreshToken,tokenExpiresAt:e.tokenExpiresAt,userName:e.userName,userAvatar:e.userAvatar,baseUrl:e.baseUrl??t?.baseUrl,scopes:Ze(e,t)}),await F(n),await Je(e.providerId,e.accessToken)}function B(e){let t=P().find(t=>t.providerId===e);return t&&(t.accessToken||t.apiKey)||null}function V(e){let t=P().find(t=>t.providerId===e);return t?t.accessToken||t.apiKey||(D(e).optionalApiKey?`local`:null):null}function H(e){return P().find(t=>t.providerId===e)?.baseUrl??null}function $e(e){return P().find(t=>t.providerId===e)?.deployment??null}function et(e){return P().find(t=>t.providerId===e)?.apiVersion??null}function U(){let e=localStorage.getItem(S)||``,t=e.indexOf(`:`);return t>=0?e.slice(t+1):e}function tt(e){let t=e.indexOf(`:`);if(t>0){let n=e.slice(0,t),r=new Set([...i(),...T()]),a=n.includes(`.`);if(r.has(n)||!a){localStorage.setItem(S,e);return}}let n=W();localStorage.setItem(S,`${n}:${e}`)}function nt(){return localStorage.getItem(S)||``}function W(){let e=nt(),t=e.indexOf(`:`);if(t>0)return e.slice(0,t);let n=P(),r=U();if(r){let e=n.find(e=>E(e.providerId)&&Ee(e.providerId,r));if(e)return e.providerId}let i=n.find(e=>E(e.providerId));return i?i.providerId:n.length>0?n[0].providerId:`anthropic`}function rt(e){let t=U();localStorage.setItem(S,`${e}:${t}`)}function it(){let e=U();localStorage.setItem(S,e)}function at(){return V(W())}function ot(e){let t=W();I(t,e,H(t)??void 0)}async function st(){await L(W())}function ct(){return H(W())}function lt(e){let t=W(),n=B(t);n&&I(t,n,e||void 0)}function ut(){let e=W(),t=B(e);t&&I(e,t)}function dt(){let e=P(),t=W(),n=U();return e.map(e=>{let r={providerId:e.providerId,apiKey:e.apiKey};return e.baseUrl&&(r.baseUrl=e.baseUrl),e.providerId===t&&n&&(r.model=n),r})}async function ft(){let e=P();await Promise.allSettled(e.map(e=>L(e.providerId))),localStorage.removeItem(x),localStorage.removeItem(S);for(let e of be)localStorage.removeItem(e)}function pt(e){return/^(?:gpt[-.]?|o[0-9]|chatgpt)/i.test(e)?`openai`:`anthropic`}function G(e,t,n,r){return{id:t,name:t,provider:e,api:r??`${e}-${pt(t)}`,baseUrl:n??``,contextWindow:2e5,maxTokens:16384,input:[`text`,`image`],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},reasoning:!0}}function K(e,t){return t.isOAuth||e===`azure-ai-foundry`?`anthropic`:e===`bedrock-camp`?`amazon-bedrock`:e}function mt(){let e=new Set;for(let t of P())t.loggedOut||(e.add(t.providerId),e.add(K(t.providerId,D(t.providerId))));return[...e]}function ht(e,t,n){let r=k(e).find(e=>e.id===t);return r?n?{...r,baseUrl:n}:r:null}function gt(e,t,n,r){return n.isOAuth?k(t).find(e=>e.id===r)||{...e,api:`${t}-anthropic`,provider:t}:t===`bedrock-camp`?{...e,api:`bedrock-camp-converse`,provider:`bedrock-camp`}:e}function _t(e,t,n,r,i){let a=ht(e,n,r);if(a)return a;if(t.isOAuth)return G(e,n,r);if(i)throw Error(`Model ${n} is not available from provider ${e}`);return J()}function q(e,t){if(!e)return J();let n=t??W(),r=H(n),i=D(n);if(t!==void 0){let t=ht(n,e,r);if(t)return t}try{let t=K(n,i),a=y(t,e);if(!a?.id)throw Error(`Model ${e} not found`);let o=gt(a,n,i,e);return r?{...o,baseUrl:r}:o}catch(a){return j.debug(`resolveModelById: pi-ai lookup miss, using provider fallback`,{providerId:n,modelId:e,error:a instanceof Error?a.message:String(a)}),_t(n,i,e,r,t!==void 0)}}function vt(e,t){return e.provider===t||e.provider===K(t,D(t))}function J(){let e=W(),t=U(),n=H(e),r=k(e),i=D(e),a=i.defaultModelId?r.find(e=>e.id.toLowerCase().includes(i.defaultModelId.toLowerCase()))?.id:void 0,o=t||a||r[0]?.id||`claude-sonnet-4-6`;try{let t=K(e,i),a=y(t,o);if(!a?.id)throw Error(`Model ${o} not found in ${t} registry`);let s=a;return i.isOAuth?s=r.find(e=>e.id===o)||{...s,api:`${e}-anthropic`,provider:e}:e===`bedrock-camp`&&(s={...s,api:`bedrock-camp-converse`,provider:`bedrock-camp`}),n&&(s={...s,baseUrl:n}),s}catch(t){j.debug(`resolveCurrentModel: pi-ai lookup miss, using provider fallback`,{providerId:e,effectiveModelId:o,error:t instanceof Error?t.message:String(t)});let a=r.find(e=>e.id===o);return a?n?{...a,baseUrl:n}:a:i.isOAuth?G(e,o,n):y(`anthropic`,`claude-sonnet-4-0`)}}function yt(e){let t=e.toLowerCase();if(!t)return null;let n=null;try{n=W()}catch{}if(n!==null){let e=Y(t,[n]);if(e!==null)return e}return Y(t,P().map(e=>e.providerId))}function Y(e,t){let n=null,r=-1;for(let i of t)for(let t of k(i)){let i=t.id.toLowerCase(),a=(t.name??``).toLowerCase();if(!i.includes(e)&&!a.includes(e))continue;let o=t.contextWindow??0;(o>r||o===r&&Ot(t.id,n??``)>0)&&(r=o,n=t.id)}return n}function X(){let e=[];try{for(let t of P())e.includes(t.providerId)||e.push(t.providerId)}catch{}try{let t=W();e.includes(t)||e.push(t)}catch{}return e}function bt(e){let t=e.indexOf(`:`);if(t<=0||t===e.length-1)return null;let n=e.slice(0,t),r=e.slice(t+1),i=X().includes(n);if(i)return{providerId:n,modelId:r,configured:i};let a=!1;try{a=T().includes(n)}catch{}return a?{providerId:n,modelId:r,configured:!1}:null}function Z(e,t,n=!0){let r=[e],i=n?Y(e.toLowerCase(),[t]):null;i!==null&&i!==e&&r.push(i);let a=[];try{a=k(t)}catch{}for(let n of r)if(!(a.length>0&&!a.some(e=>e.id===n)))try{if(q(n,t).id===n)return{modelId:n,providerId:t}}catch(r){j.debug(`selectModelFromProvider: candidate did not resolve`,{input:e,candidate:n,providerId:t,error:r instanceof Error?r.message:String(r)})}return null}function xt(e){return e.map(e=>`${e.providerId}:${e.modelId}`).join(`, `)}function Q(e){if(!e)return{ok:!1,error:`unknown model: (empty)`};let t=bt(e);if(t)return Tt(e,t);let n=null;try{n=W()}catch{}if(n!==null){let t=Z(e,n);if(t)return wt(t)}return Et(e,n)}function $(){try{return W()}catch{return null}}function St(e){let t=$();return t===null||he(_e(),t,e.providerId,e.modelId)}function Ct(e){let t=$()??`<none>`;return{ok:!1,error:`model not allowed: ${`${e.providerId}:${e.modelId}`} is blocked by ${h} while "${t}" is selected — ${ve(t,e.providerId,e.modelId)}`}}function wt(e){return St(e)?{ok:!0,selection:e}:Ct(e)}function Tt(e,t){if(!t.configured){let n=X();return{ok:!1,error:`unknown model: ${e} (provider "${t.providerId}" is not configured${n.length>0?`; configured: ${n.join(`, `)}`:``})`}}let n=Z(t.modelId,t.providerId);return n?wt(n):{ok:!1,error:`unknown model: ${e} (provider "${t.providerId}" does not offer "${t.modelId}")`}}function Et(e,t){let n=X().filter(e=>e!==t);for(let t of[`exact`,`shorthand`]){let r=[];for(let i of n){let n=t===`exact`?e:Y(e.toLowerCase(),[i]);if(n===null)continue;let a=Z(n,i,!1);a&&r.push(a)}let i=r.filter(St);if(i.length===0&&r.length>0)return Ct(r[0]);if(i.length===1)return{ok:!0,selection:i[0]};if(i.length>1)return{ok:!1,error:`ambiguous model: ${e} matches ${xt(i)} — qualify it as provider:model`}}return{ok:!1,error:`unknown model: ${e}`}}function Dt(e){let t=Q(e);return t.ok?t.selection.modelId:null}function Ot(e,t){let n=e.match(/\d+/g)?.map(Number)??[],r=t.match(/\d+/g)?.map(Number)??[],i=Math.max(n.length,r.length);for(let e=0;e<i;e++){let t=(n[e]??0)-(r[e]??0);if(t!==0)return t}return 0}export{p as C,m as S,Qe as _,V as a,fe as b,$e as c,U as d,W as f,Q as g,q as h,at as i,A as l,J as m,Xe as n,et as o,vt as p,P as r,H as s,ye as t,k as u,h as v,ge as x,g as y};
@@ -1,2 +1,2 @@
1
1
  const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/oauth-service-B-vKfxAF.js","assets/preload-helper-Czpn1I53.js","assets/proxied-fetch-Cplb-Tee.js","assets/rolldown-runtime-Dd_uD5pT.js","assets/base64-ELzoYfwP.js","assets/proxy-error-BSFYY7jj.js","assets/api-endpoint-DuEQRZ4g.js","assets/runtime-env-Dlaokqg1.js","assets/panel-rpc-D3EPRnmw.js","assets/permissions-surface-registry-CilCRwhh.js"])))=>i.map(i=>d[i]);
2
- import{n as e}from"./rolldown-runtime-Dd_uD5pT.js";import{a as t,i as n,o as r}from"./core-DXD5e-Tl.js";import{t as i}from"./preload-helper-Czpn1I53.js";import{t as a}from"./logger-DDBAeTLF.js";import"./proxied-fetch-Cplb-Tee.js";import{s as o,t as s}from"./api-endpoint-DuEQRZ4g.js";import{n as c}from"./float-topology-C9GjBEv-.js";import"./secret-topology-Dm_PZRZx.js";import{n as l}from"./secrets-bridge-client-CWv2_nw7.js";import{n as ee,o as u,t as d}from"./providers-jItvnenf.js";import{n as te,t as ne}from"./panel-rpc-D3EPRnmw.js";import{a as re,c as ie,i as ae,l as oe}from"./bedrock-camp-compat-B1oHsbyo.js";import{r as se,t as ce}from"./bedrock-camp-extra-models-BYrxX19D.js";import{o as le}from"./claude-model-version-DZmbk9E2.js";var ue=`slicc_oauth_extra_domains`;function f(e){try{let t=e.getItem(ue);if(!t)return{};let n=JSON.parse(t);if(typeof n!=`object`||!n||Array.isArray(n))return{};let r={};for(let[e,t]of Object.entries(n)){if(typeof e!=`string`||!Array.isArray(t))continue;let n=t.filter(e=>typeof e==`string`&&e.length>0);n.length>0&&(r[e]=n)}return r}catch{return{}}}function de(e,t){try{e.setItem(ue,JSON.stringify(t))}catch(e){throw Error(`Failed to persist OAuth extras (localStorage quota exceeded?): ${e instanceof Error?e.message:String(e)}`)}}function fe(e,t){let n={input:0,output:0,cacheRead:0,cacheWrite:0},r=le(e);if(!r)return n;let i;for(let e of t.values()){let t=le(e.id);!t||t.family!==r.family||(!i||t.major>i.major||t.major===i.major&&t.minor>i.minor)&&(i={major:t.major,minor:t.minor,cost:e.cost})}return i?.cost??n}a(`model-policy`);var pe=`/etc/models`;function me(){return{sections:{}}}function p(e,t,n){return e.providerId===t?e.modelId===`*`||e.modelId===n:!1}function he(e,t){return e.sections[t]??[]}function ge(e,t,n,r){return he(e,t).some(e=>e.deny&&p(e,n,r))}function _e(e,t,n,r){let i=he(e,t);return i.some(e=>e.deny&&p(e,n,r))?!1:n===t||i.some(e=>!e.deny&&p(e,n,r))}var ve=me();function ye(){return ve}function be(e,t,n){return`add \`${t}:${n}\` (or \`${t}:*\`) under \`[${e}]\` in ${pe}`}var xe=e({ACCOUNTS_KEY:()=>g,__test__:()=>Ee,addAccount:()=>P,applyProviderDefaults:()=>je,clearAllSettings:()=>ut,clearApiKey:()=>at,clearBaseUrl:()=>ct,clearSelectedProvider:()=>nt,ensureOAuthMaskReplica:()=>qe,exportProviders:()=>lt,getAccounts:()=>A,getAllAvailableModels:()=>k,getAllExtraOAuthDomains:()=>Ie,getAlternativeModelProviders:()=>Pe,getApiKey:()=>rt,getApiKeyForProvider:()=>V,getApiVersionForProvider:()=>Qe,getAvailableProviders:()=>x,getBaseUrl:()=>ot,getBaseUrlForProvider:()=>H,getDeploymentForProvider:()=>Ze,getExtraOAuthDomains:()=>j,getModelCatalogProviderIds:()=>ft,getOAuthAccountInfo:()=>ke,getProviderConfig:()=>C,getProviderModels:()=>T,getRawApiKeyForProvider:()=>B,getSelectedModelId:()=>U,getSelectedProvider:()=>W,isModelHiddenFromPicker:()=>D,isUsableOAuthMaskReplica:()=>R,logoutOAuthAccount:()=>I,maskOAuthTokenWithRetry:()=>L,migrateLegacyAuthOnlySelection:()=>b,modelRunsOnProvider:()=>gt,persistOAuthMaskViaServiceWorker:()=>z,policyVisible:()=>O,providerOffersLlmModels:()=>S,removeAccount:()=>F,resolveCurrentModel:()=>J,resolveModelById:()=>q,resolveModelByShorthand:()=>_t,resolveModelIdForScoop:()=>Tt,resolveModelSelectionForScoop:()=>Q,saveOAuthAccount:()=>Ye,setApiKey:()=>it,setBaseUrl:()=>st,setExtraOAuthDomains:()=>M,setExtraOAuthDomainsAsync:()=>Fe,setSelectedModelId:()=>$e,setSelectedProvider:()=>tt}),m=n,h=t,g=`slicc_accounts`,_=`selected-model`,Se=[`slicc_provider`,`slicc_api_key`,`slicc_base_url`,`anthropic_api_key`,`api_provider`,`azure_resource`,`bedrock_region`],Ce=new Set([`github`]);function v(e){let t;try{t=r()}catch{return!1}return t.includes(e)&&!u(e)}var y=!1;function we(){if(!y){y=!0;for(let e of Se)try{localStorage.removeItem(e)}catch{}b()}}function b(){try{let e=localStorage.getItem(_);if(e){let t=e.indexOf(`:`);if(t>0){let n=e.slice(0,t);(Ce.has(n)||v(n))&&localStorage.removeItem(_)}}}catch{}try{let e=localStorage.getItem(g);if(!e)return;let t=JSON.parse(e);if(!Array.isArray(t))return;let n=t.filter(e=>!(typeof e==`object`&&e&&typeof e.providerId==`string`&&v(e.providerId)));n.length!==t.length&&localStorage.setItem(g,JSON.stringify(n))}catch{}}function Te(){y=!1}var Ee={_resetLegacyCleanup:Te};function x(){let e=r().filter(u),t=ee();return[...new Set([...e,...t])].filter(e=>!d(e)?.hidden)}function S(e){try{if(T(e).length>0)return!0}catch{}try{if(t(e).length>0)return!0}catch{}let n=d(e);return!!(n?.modelOverrides&&Object.keys(n.modelOverrides).length>0)}function De(e,n){try{if(T(e).some(e=>e.id===n))return!0}catch{}try{if(t(e).some(e=>e.id===n))return!0}catch{}let r=d(e);return!!(r?.modelOverrides&&Object.hasOwn(r.modelOverrides,n))}function C(e){return d(e)||{id:e,name:e.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),description:`${e} provider`,requiresApiKey:!0,requiresBaseUrl:!1}}function w(e,t){t.context_window!==void 0&&(e.contextWindow=t.context_window),t.max_tokens!==void 0&&(e.maxTokens=t.max_tokens),t.reasoning!==void 0&&(e.reasoning=t.reasoning),t.input!==void 0&&(e.input=t.input),t.cost!==void 0&&(e.cost=t.cost,e.inputCost=t.cost.input,e.outputCost=t.cost.output,e.cacheReadCost=t.cost.cacheRead,e.cacheWriteCost=t.cost.cacheWrite),t.compat!==void 0&&(e.compat={...e.compat??{},...t.compat}),t.thinkingLevelMap!==void 0&&(e.thinkingLevelMap={...e.thinkingLevelMap??{},...t.thinkingLevelMap})}function Oe(e){let t=ae(e);return{...e,api:`bedrock-camp-converse`,provider:`bedrock-camp`,reasoning:e.reasoning===!0&&(ie(e)||t!==null),...t?{thinkingLevelMap:{...t}}:{}}}function T(e){try{if(e===`bedrock-camp`){let e=re(H(`bedrock-camp`));return se(h(`amazon-bedrock`),ce).filter(t=>oe(t,e)).map(Oe)}let t=C(e);if(t.getModelIds){let n;try{n=t.getModelIds()}catch(t){return E.error(`Provider getModelIds callback failed`,{providerId:e,error:t instanceof Error?t.message:String(t)}),[]}let i=new Map;for(let e of r())try{for(let t of h(e))i.set(t.id,t)}catch{}return n.map(n=>{let r=n.api===`openai`?`openai`:`anthropic`,a=`${e}-${r}`,o=i.get(n.id),s;if(o)s={...o,api:a,provider:e};else if(s=G(e,n.id,``,a),n.name&&(s.name=n.name),r===`anthropic`){let e=fe(n.id,i);s.cost=e,s.inputCost=e.input,s.outputCost=e.output,s.cacheReadCost=e.cacheRead,s.cacheWriteCost=e.cacheWrite}let c=t.modelOverrides?.[n.id];return c&&w(s,c),w(s,n),s})}if(t.isOAuth){let n=h(`anthropic`),r=`${e}-anthropic`;return n.map(n=>{let i={...n,api:r,provider:e},a=t.modelOverrides?.[n.id];return a&&w(i,a),i})}return h(e===`azure-ai-foundry`?`anthropic`:e)}catch(t){return E.error(`Failed to load models`,{providerId:e,error:t instanceof Error?t.message:String(t)}),[]}}function ke(e){let t=A().find(t=>t.providerId===e);if(!t?.accessToken)return null;let n=!!t.tokenExpiresAt&&Date.now()>t.tokenExpiresAt-6e4;return{token:t.accessToken,maskedValue:t.maskedValue,expiresAt:t.tokenExpiresAt,userName:t.userName,userAvatar:t.userAvatar,scopes:t.scopes,expired:n}}var Ae=Object.assign({})[`/packages/webapp/providers.json`]??[],E=a(`provider-settings`);function je(e=Ae){if(e.length===0||A().length>0)return;let t=new Set(x());for(let n of e)if(!(!n.providerId||!n.apiKey)){if(!t.has(n.providerId)){E.warn(`Unknown provider "${n.providerId}" in providers.json — skipping`);continue}P(n.providerId,n.apiKey,n.baseUrl)}let n=e.find(e=>e.providerId&&e.apiKey&&t.has(e.providerId));n?.model&&!localStorage.getItem(_)&&localStorage.setItem(_,`${n.providerId}:${n.model}`)}var Me=[/haiku/i];function D(e){return Me.some(t=>t.test(e))}function Ne(e){return e.filter(e=>!D(e.id))}function O(e,t){let n=$();if(n===null)return e;let r=ye();return e.filter(e=>!ge(r,n,t,e.id))}function k(){let e=A();if(e.length===0)return[];let t=new Map;for(let n of e){if(t.has(n.providerId))continue;let e=C(n.providerId);if(e.hidden||v(n.providerId))continue;let r=O(Ne(T(n.providerId)),n.providerId);if(r.length===0)continue;let i={providerId:n.providerId,providerName:e.name,models:r};t.set(n.providerId,i)}return[...t.values()]}function Pe(e){return k().map(e=>e.providerId).filter(t=>t!==e)}function A(){we();let e=localStorage.getItem(g);if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`object`&&!!e&&typeof e.providerId==`string`&&typeof e.apiKey==`string`):[]}catch{return[]}}function j(e){return f(localStorage)[e]??[]}function M(e,t){let n=f(localStorage),r=t.map(e=>e.trim()).filter(e=>e.length>0);r.length===0?delete n[e]:n[e]=r,de(localStorage,n)}async function Fe(e,t){if(te()){M(e,t);return}let n=ne();if(!n)throw Error(`setExtraOAuthDomainsAsync: no DOM and no panel-rpc client — cannot persist to page localStorage`);let{storeAfter:r}=await n.call(`oauth-extras-set`,{providerId:e,domains:t});try{de(localStorage,r)}catch(t){E.warn(`worker-shim mirror failed after successful page write — reload to refresh`,{providerId:e,error:t instanceof Error?t.message:String(t)})}}function Ie(){return f(localStorage)}function Le(e){localStorage.setItem(g,JSON.stringify(e))}async function N(e){if(te()){Le(e);return}let t=ne();if(!t)throw Error(`saveAccountsAsync: no DOM and no panel-rpc client — cannot persist to page localStorage`);let n=JSON.stringify(e),{storedJson:r}=await t.call(`save-oauth-accounts`,{accountsJson:n});try{localStorage.setItem(g,r)}catch(e){E.warn(`worker-shim mirror failed after successful page write — reload to refresh`,{error:e instanceof Error?e.message:String(e)})}}function P(e,t,n,r,i){let a=A().filter(t=>t.providerId!==e),o={providerId:e,apiKey:t};n&&(o.baseUrl=n),r&&(o.deployment=r),i&&(o.apiVersion=i),a.push(o),Le(a)}async function Re(e){let t=c();try{if(t===`extension-direct`){let t=await new Promise(t=>{chrome.runtime.sendMessage({type:`secrets.delete`,name:`oauth.${e}.token`},n=>{chrome.runtime.lastError&&E.error(`SW secrets.delete transport failed`,{providerId:e,error:chrome.runtime.lastError.message}),t(n??{})})});t.error&&E.error(`SW secrets.delete returned error`,{providerId:e,error:t.error})}else if(t===`extension-delegate`){let t=await l(`secrets.delete`,{name:`oauth.${e}.token`});t?.error&&E.error(`Bridge secrets.delete returned error`,{providerId:e,error:t.error})}else if(t!==`connect`){let t=await fetch(o(`/api/secrets/oauth/${e}`),{method:`DELETE`,headers:s()});!t.ok&&t.status!==404&&E.warn(`OAuth replica DELETE non-ok`,{providerId:e,status:t.status})}}catch(n){E.error(`OAuth replica removal failed`,{providerId:e,topology:t,error:n instanceof Error?n.message:String(n)})}}async function F(e){let t=A().find(t=>t.providerId===e),n=C(e);t&&n?.isOAuth&&await I(e),await Re(e),await N(A().filter(t=>t.providerId!==e));let r=localStorage.getItem(_)??``,i=r.indexOf(`:`);i>0&&r.slice(0,i)===e&&localStorage.removeItem(_)}async function I(e){let t=A().find(t=>t.providerId===e);if(!t)return;let n=C(e);if(n?.isOAuth){if(n.onOAuthLogout)try{await n.onOAuthLogout()}catch(t){E.warn(`onOAuthLogout failed`,{providerId:e,error:t instanceof Error?t.message:String(t)})}if(n.getOAuthLogoutUrl){let r=n.getOAuthLogoutUrl(t);if(r){let{openIdpLogoutUrl:t}=await i(async()=>{let{openIdpLogoutUrl:e}=await import(`./oauth-service-B-vKfxAF.js`);return{openIdpLogoutUrl:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]));await t(r).catch(t=>{E.warn(`IdP logout popup failed`,{providerId:e,error:t instanceof Error?t.message:String(t)})})}}await N(A().map(t=>t.providerId===e?{providerId:t.providerId,apiKey:``,baseUrl:t.baseUrl,userName:t.userName,userAvatar:t.userAvatar,loggedOut:!0}:t)),await Re(e)}}async function L(e,t={}){let n=Math.max(1,t.attempts??3),r=t.delayMs??150,i=t.sleep??(e=>new Promise(t=>setTimeout(t,e))),a;for(let t=0;t<n;t++){let o=await e();if(o.maskedValue)return{maskedValue:o.maskedValue};o.error&&(a=o.error),t<n-1&&await i(r)}return{lastError:a}}var ze=`access token rotated during mask write`;function Be(e,t,n,r){let i=r.find(t=>t.providerId===e);return i?.accessToken?i.accessToken===t?(i.maskedValue=n,{maskedValue:n}):(E.warn(`OAuth mask write raced with token rotation; discarding replica`,{providerId:e}),{error:ze}):{error:`account gone after mask write`}}function R(e,t){return!!e&&e!==t}async function z(e,t,n){let r={providerId:e.providerId,accessToken:e.accessToken,domains:e.domains.join(`,`)},{maskedValue:i,lastError:a}=await L(()=>t.sendMaskRequest(r),n);if(!R(i,e.accessToken)){let t=i?`mask replica equals the access token`:a??`no error reported (cold SW or empty reply)`;return E.error(`OAuth mask give-up: no masked value after retries`,{providerId:e.providerId,reason:t}),{error:t}}let o=t.getAccounts(),s=Be(e.providerId,e.accessToken,i,o);return s.maskedValue&&await t.saveAccounts(o),s}function Ve(e){let t=C(e).oauthTokenDomains??[],n=j(e),r=new Set,i=[];for(let e of[...t,...n]){let t=e.toLowerCase();r.has(t)||(r.add(t),i.push(e))}return i}function He(e){return new Promise(t=>{chrome.runtime.sendMessage({type:`secrets.mask-oauth-token`,...e},n=>{chrome.runtime.lastError&&E.error(`SW mask-oauth-token transport failed`,{providerId:e.providerId,error:chrome.runtime.lastError.message});let r=typeof n==`object`&&n?n:void 0;r?.error&&E.warn(`SW mask-oauth-token returned error`,{providerId:e.providerId,error:r.error}),t(r??{})})})}function Ue(e){return l(`secrets.mask-oauth-token`,e).then(t=>(t?.error&&E.warn(`Bridge mask-oauth-token returned error`,{providerId:e.providerId,error:t.error}),t??{})).catch(t=>(E.error(`Bridge mask-oauth-token transport failed`,{providerId:e.providerId,error:t instanceof Error?t.message:String(t)}),{}))}async function We(e,t,n){let r=o(`/api/secrets/oauth-update`),i=await fetch(r,{method:`POST`,headers:s({"Content-Type":`application/json`}),body:JSON.stringify({providerId:e,accessToken:t,domains:n})});if(!i.ok)return E.warn(`OAuth replica POST non-ok`,{providerId:e,status:i.status,url:r}),{error:`OAuth replica POST HTTP ${i.status}`};let a=await i.json();if(typeof a.maskedValue!=`string`)return E.warn(`OAuth replica POST ok but missing maskedValue`,{providerId:e,url:r}),{error:`OAuth replica POST ok but missing maskedValue`};if(!R(a.maskedValue,t))return E.error(`OAuth mask replica equals the access token; refusing to persist`,{providerId:e}),{error:`mask replica equals the access token`};let c=A(),l=Be(e,t,a.maskedValue,c);return l.maskedValue&&await N(c),l}async function Ge(e,t){let n=await Ke(e,t);if(n.error!==ze)return n;let r=A().find(t=>t.providerId===e)?.accessToken;return!r||r===t?n:Ke(e,r)}async function Ke(e,t){let n=Ve(e);if(n.length===0)return{error:`no oauth token domains configured`};let r=c();try{return r===`extension-direct`?z({providerId:e,accessToken:t,domains:n},{sendMaskRequest:He,getAccounts:A,saveAccounts:N}):r===`extension-delegate`?z({providerId:e,accessToken:t,domains:n},{sendMaskRequest:Ue,getAccounts:A,saveAccounts:N}):r===`connect`?{error:`no replica store in connect mode`}:await We(e,t,n)}catch(t){let n=t instanceof Error?t.message:String(t);return E.error(`OAuth replica sync failed`,{providerId:e,topology:r,error:n}),{error:n}}}async function qe(e){let t=A().find(t=>t.providerId===e);return t?.accessToken?R(t.maskedValue,t.accessToken)?{maskedValue:t.maskedValue}:Ge(e,t.accessToken):{error:`no access token held`}}function Je(e,t){if(e.accessToken)return`scopes`in e?e.scopes:t?.scopes}async function Ye(e){let t=A().find(t=>t.providerId===e.providerId),n=A().filter(t=>t.providerId!==e.providerId);n.push({providerId:e.providerId,apiKey:``,accessToken:e.accessToken,refreshToken:e.refreshToken,tokenExpiresAt:e.tokenExpiresAt,userName:e.userName,userAvatar:e.userAvatar,baseUrl:e.baseUrl??t?.baseUrl,scopes:Je(e,t)}),await N(n),await Ge(e.providerId,e.accessToken)}var Xe=`local`;function B(e){let t=A().find(t=>t.providerId===e);return t&&(t.accessToken||t.apiKey)||null}function V(e){let t=A().find(t=>t.providerId===e);return t?t.accessToken||t.apiKey||(C(e).optionalApiKey?Xe:null):null}function H(e){return A().find(t=>t.providerId===e)?.baseUrl??null}function Ze(e){return A().find(t=>t.providerId===e)?.deployment??null}function Qe(e){return A().find(t=>t.providerId===e)?.apiVersion??null}function U(){let e=localStorage.getItem(_)||``,t=e.indexOf(`:`);return t>=0?e.slice(t+1):e}function $e(e){let t=e.indexOf(`:`);if(t>0){let n=e.slice(0,t),r=new Set([...ee(),...x()]),i=n.includes(`.`);if(r.has(n)||!i){localStorage.setItem(_,e);return}}let n=W();localStorage.setItem(_,`${n}:${e}`)}function et(){return localStorage.getItem(_)||``}function W(){let e=et(),t=e.indexOf(`:`);if(t>0)return e.slice(0,t);let n=A(),r=U();if(r){let e=n.find(e=>S(e.providerId)&&De(e.providerId,r));if(e)return e.providerId}let i=n.find(e=>S(e.providerId));return i?i.providerId:n.length>0?n[0].providerId:`anthropic`}function tt(e){let t=U();localStorage.setItem(_,`${e}:${t}`)}function nt(){let e=U();localStorage.setItem(_,e)}function rt(){return V(W())}function it(e){let t=W();P(t,e,H(t)??void 0)}async function at(){await F(W())}function ot(){return H(W())}function st(e){let t=W(),n=B(t);n&&P(t,n,e||void 0)}function ct(){let e=W(),t=B(e);t&&P(e,t)}function lt(){let e=A(),t=W(),n=U();return e.map(e=>{let r={providerId:e.providerId,apiKey:e.apiKey};return e.baseUrl&&(r.baseUrl=e.baseUrl),e.providerId===t&&n&&(r.model=n),r})}async function ut(){let e=A();await Promise.allSettled(e.map(e=>F(e.providerId))),localStorage.removeItem(g),localStorage.removeItem(_);for(let e of Se)localStorage.removeItem(e)}function dt(e){return/^(?:gpt[-.]?|o[0-9]|chatgpt)/i.test(e)?`openai`:`anthropic`}function G(e,t,n,r){return{id:t,name:t,provider:e,api:r??`${e}-${dt(t)}`,baseUrl:n??``,contextWindow:2e5,maxTokens:16384,input:[`text`,`image`],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},reasoning:!0}}function K(e,t){return t.isOAuth||e===`azure-ai-foundry`?`anthropic`:e===`bedrock-camp`?`amazon-bedrock`:e}function ft(){let e=new Set;for(let t of A())t.loggedOut||(e.add(t.providerId),e.add(K(t.providerId,C(t.providerId))));return[...e]}function pt(e,t,n){let r=T(e).find(e=>e.id===t);return r?n?{...r,baseUrl:n}:r:null}function mt(e,t,n,r){return n.isOAuth?T(t).find(e=>e.id===r)||{...e,api:`${t}-anthropic`,provider:t}:t===`bedrock-camp`?{...e,api:`bedrock-camp-converse`,provider:`bedrock-camp`}:e}function ht(e,t,n,r,i){let a=pt(e,n,r);if(a)return a;if(t.isOAuth)return G(e,n,r);if(i)throw Error(`Model ${n} is not available from provider ${e}`);return J()}function q(e,t){if(!e)return J();let n=t??W(),r=H(n),i=C(n);if(t!==void 0){let t=pt(n,e,r);if(t)return t}try{let t=m(K(n,i),e);if(!t?.id)throw Error(`Model ${e} not found`);let a=mt(t,n,i,e);return r?{...a,baseUrl:r}:a}catch(a){return E.debug(`resolveModelById: pi-ai lookup miss, using provider fallback`,{providerId:n,modelId:e,error:a instanceof Error?a.message:String(a)}),ht(n,i,e,r,t!==void 0)}}function gt(e,t){return e.provider===t||e.provider===K(t,C(t))}function J(){let e=W(),t=U(),n=H(e),r=T(e),i=C(e),a=i.defaultModelId?r.find(e=>e.id.toLowerCase().includes(i.defaultModelId.toLowerCase()))?.id:void 0,o=t||a||r[0]?.id||`claude-sonnet-4-6`;try{let t=K(e,i),a=m(t,o);if(!a?.id)throw Error(`Model ${o} not found in ${t} registry`);let s=a;return i.isOAuth?s=r.find(e=>e.id===o)||{...s,api:`${e}-anthropic`,provider:e}:e===`bedrock-camp`&&(s={...s,api:`bedrock-camp-converse`,provider:`bedrock-camp`}),n&&(s={...s,baseUrl:n}),s}catch(t){E.debug(`resolveCurrentModel: pi-ai lookup miss, using provider fallback`,{providerId:e,effectiveModelId:o,error:t instanceof Error?t.message:String(t)});let a=r.find(e=>e.id===o);return a?n?{...a,baseUrl:n}:a:i.isOAuth?G(e,o,n):m(`anthropic`,`claude-sonnet-4-0`)}}function _t(e){let t=e.toLowerCase();if(!t)return null;let n=null;try{n=W()}catch{}if(n!==null){let e=Y(t,[n]);if(e!==null)return e}return Y(t,A().map(e=>e.providerId))}function Y(e,t){let n=null,r=-1;for(let i of t)for(let t of T(i)){let i=t.id.toLowerCase(),a=(t.name??``).toLowerCase();if(!i.includes(e)&&!a.includes(e))continue;let o=t.contextWindow??0;(o>r||o===r&&Et(t.id,n??``)>0)&&(r=o,n=t.id)}return n}function X(){let e=[];try{for(let t of A())e.includes(t.providerId)||e.push(t.providerId)}catch{}try{let t=W();e.includes(t)||e.push(t)}catch{}return e}function vt(e){let t=e.indexOf(`:`);if(t<=0||t===e.length-1)return null;let n=e.slice(0,t),r=e.slice(t+1),i=X().includes(n);if(i)return{providerId:n,modelId:r,configured:i};let a=!1;try{a=x().includes(n)}catch{}return a?{providerId:n,modelId:r,configured:!1}:null}function Z(e,t,n=!0){let r=[e],i=n?Y(e.toLowerCase(),[t]):null;i!==null&&i!==e&&r.push(i);let a=[];try{a=T(t)}catch{}for(let n of r)if(!(a.length>0&&!a.some(e=>e.id===n)))try{if(q(n,t).id===n)return{modelId:n,providerId:t}}catch(r){E.debug(`selectModelFromProvider: candidate did not resolve`,{input:e,candidate:n,providerId:t,error:r instanceof Error?r.message:String(r)})}return null}function yt(e){return e.map(e=>`${e.providerId}:${e.modelId}`).join(`, `)}function Q(e){if(!e)return{ok:!1,error:`unknown model: (empty)`};let t=vt(e);if(t)return Ct(e,t);let n=null;try{n=W()}catch{}if(n!==null){let t=Z(e,n);if(t)return St(t)}return wt(e,n)}function $(){try{return W()}catch{return null}}function bt(e){let t=$();return t===null||_e(ye(),t,e.providerId,e.modelId)}function xt(e){let t=$()??`<none>`;return{ok:!1,error:`model not allowed: ${`${e.providerId}:${e.modelId}`} is blocked by ${pe} while "${t}" is selected — ${be(t,e.providerId,e.modelId)}`}}function St(e){return bt(e)?{ok:!0,selection:e}:xt(e)}function Ct(e,t){if(!t.configured){let n=X();return{ok:!1,error:`unknown model: ${e} (provider "${t.providerId}" is not configured${n.length>0?`; configured: ${n.join(`, `)}`:``})`}}let n=Z(t.modelId,t.providerId);return n?St(n):{ok:!1,error:`unknown model: ${e} (provider "${t.providerId}" does not offer "${t.modelId}")`}}function wt(e,t){let n=X().filter(e=>e!==t);for(let t of[`exact`,`shorthand`]){let r=[];for(let i of n){let n=t===`exact`?e:Y(e.toLowerCase(),[i]);if(n===null)continue;let a=Z(n,i,!1);a&&r.push(a)}let i=r.filter(bt);if(i.length===0&&r.length>0)return xt(r[0]);if(i.length===1)return{ok:!0,selection:i[0]};if(i.length>1)return{ok:!1,error:`ambiguous model: ${e} matches ${yt(i)} — qualify it as provider:model`}}return{ok:!1,error:`unknown model: ${e}`}}function Tt(e){let t=Q(e);return t.ok?t.selection.modelId:null}function Et(e,t){let n=e.match(/\d+/g)?.map(Number)??[],r=t.match(/\d+/g)?.map(Number)??[],i=Math.max(n.length,r.length);for(let e=0;e<i;e++){let t=(n[e]??0)-(r[e]??0);if(t!==0)return t}return 0}export{fe as $,W as A,F as B,j as C,T as D,C as E,b as F,Q as G,q as H,gt as I,st as J,Ye as K,z as L,R as M,I as N,B as O,L as P,tt as Q,O as R,Ze as S,ke as T,_t as U,J as V,Tt as W,Fe as X,M as Y,$e as Z,V as _,je as a,ot as b,ct as c,lt as d,A as f,rt as g,Pe as h,P as i,D as j,U as k,nt as l,Ie as m,Ee as n,ut as o,k as p,it as q,xe as r,at as s,g as t,qe as u,Qe as v,ft as w,H as x,x as y,S as z};
2
+ import{n as e}from"./rolldown-runtime-Dd_uD5pT.js";import{a as t,i as n,o as r}from"./core-DXD5e-Tl.js";import{t as i}from"./preload-helper-Czpn1I53.js";import{t as a}from"./logger-DDBAeTLF.js";import"./proxied-fetch-Cplb-Tee.js";import{s as o,t as s}from"./api-endpoint-DuEQRZ4g.js";import{n as c}from"./float-topology-C9GjBEv-.js";import"./secret-topology-Dm_PZRZx.js";import{n as l}from"./secrets-bridge-client-CWv2_nw7.js";import{n as ee,o as u,t as d}from"./providers-CqM86e9A.js";import{n as te,t as ne}from"./panel-rpc-D3EPRnmw.js";import{a as re,c as ie,i as ae,l as oe}from"./bedrock-camp-compat-B1oHsbyo.js";import{r as se,t as ce}from"./bedrock-camp-extra-models-BYrxX19D.js";import{o as le}from"./claude-model-version-DZmbk9E2.js";var ue=`slicc_oauth_extra_domains`;function f(e){try{let t=e.getItem(ue);if(!t)return{};let n=JSON.parse(t);if(typeof n!=`object`||!n||Array.isArray(n))return{};let r={};for(let[e,t]of Object.entries(n)){if(typeof e!=`string`||!Array.isArray(t))continue;let n=t.filter(e=>typeof e==`string`&&e.length>0);n.length>0&&(r[e]=n)}return r}catch{return{}}}function de(e,t){try{e.setItem(ue,JSON.stringify(t))}catch(e){throw Error(`Failed to persist OAuth extras (localStorage quota exceeded?): ${e instanceof Error?e.message:String(e)}`)}}function fe(e,t){let n={input:0,output:0,cacheRead:0,cacheWrite:0},r=le(e);if(!r)return n;let i;for(let e of t.values()){let t=le(e.id);!t||t.family!==r.family||(!i||t.major>i.major||t.major===i.major&&t.minor>i.minor)&&(i={major:t.major,minor:t.minor,cost:e.cost})}return i?.cost??n}a(`model-policy`);var pe=`/etc/models`;function me(){return{sections:{}}}function p(e,t,n){return e.providerId===t?e.modelId===`*`||e.modelId===n:!1}function he(e,t){return e.sections[t]??[]}function ge(e,t,n,r){return he(e,t).some(e=>e.deny&&p(e,n,r))}function _e(e,t,n,r){let i=he(e,t);return i.some(e=>e.deny&&p(e,n,r))?!1:n===t||i.some(e=>!e.deny&&p(e,n,r))}var ve=me();function ye(){return ve}function be(e,t,n){return`add \`${t}:${n}\` (or \`${t}:*\`) under \`[${e}]\` in ${pe}`}var xe=e({ACCOUNTS_KEY:()=>g,__test__:()=>Ee,addAccount:()=>P,applyProviderDefaults:()=>je,clearAllSettings:()=>ut,clearApiKey:()=>at,clearBaseUrl:()=>ct,clearSelectedProvider:()=>nt,ensureOAuthMaskReplica:()=>qe,exportProviders:()=>lt,getAccounts:()=>A,getAllAvailableModels:()=>k,getAllExtraOAuthDomains:()=>Ie,getAlternativeModelProviders:()=>Pe,getApiKey:()=>rt,getApiKeyForProvider:()=>V,getApiVersionForProvider:()=>Qe,getAvailableProviders:()=>x,getBaseUrl:()=>ot,getBaseUrlForProvider:()=>H,getDeploymentForProvider:()=>Ze,getExtraOAuthDomains:()=>j,getModelCatalogProviderIds:()=>ft,getOAuthAccountInfo:()=>ke,getProviderConfig:()=>C,getProviderModels:()=>T,getRawApiKeyForProvider:()=>B,getSelectedModelId:()=>U,getSelectedProvider:()=>W,isModelHiddenFromPicker:()=>D,isUsableOAuthMaskReplica:()=>R,logoutOAuthAccount:()=>I,maskOAuthTokenWithRetry:()=>L,migrateLegacyAuthOnlySelection:()=>b,modelRunsOnProvider:()=>gt,persistOAuthMaskViaServiceWorker:()=>z,policyVisible:()=>O,providerOffersLlmModels:()=>S,removeAccount:()=>F,resolveCurrentModel:()=>J,resolveModelById:()=>q,resolveModelByShorthand:()=>_t,resolveModelIdForScoop:()=>Tt,resolveModelSelectionForScoop:()=>Q,saveOAuthAccount:()=>Ye,setApiKey:()=>it,setBaseUrl:()=>st,setExtraOAuthDomains:()=>M,setExtraOAuthDomainsAsync:()=>Fe,setSelectedModelId:()=>$e,setSelectedProvider:()=>tt}),m=n,h=t,g=`slicc_accounts`,_=`selected-model`,Se=[`slicc_provider`,`slicc_api_key`,`slicc_base_url`,`anthropic_api_key`,`api_provider`,`azure_resource`,`bedrock_region`],Ce=new Set([`github`]);function v(e){let t;try{t=r()}catch{return!1}return t.includes(e)&&!u(e)}var y=!1;function we(){if(!y){y=!0;for(let e of Se)try{localStorage.removeItem(e)}catch{}b()}}function b(){try{let e=localStorage.getItem(_);if(e){let t=e.indexOf(`:`);if(t>0){let n=e.slice(0,t);(Ce.has(n)||v(n))&&localStorage.removeItem(_)}}}catch{}try{let e=localStorage.getItem(g);if(!e)return;let t=JSON.parse(e);if(!Array.isArray(t))return;let n=t.filter(e=>!(typeof e==`object`&&e&&typeof e.providerId==`string`&&v(e.providerId)));n.length!==t.length&&localStorage.setItem(g,JSON.stringify(n))}catch{}}function Te(){y=!1}var Ee={_resetLegacyCleanup:Te};function x(){let e=r().filter(u),t=ee();return[...new Set([...e,...t])].filter(e=>!d(e)?.hidden)}function S(e){try{if(T(e).length>0)return!0}catch{}try{if(t(e).length>0)return!0}catch{}let n=d(e);return!!(n?.modelOverrides&&Object.keys(n.modelOverrides).length>0)}function De(e,n){try{if(T(e).some(e=>e.id===n))return!0}catch{}try{if(t(e).some(e=>e.id===n))return!0}catch{}let r=d(e);return!!(r?.modelOverrides&&Object.hasOwn(r.modelOverrides,n))}function C(e){return d(e)||{id:e,name:e.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),description:`${e} provider`,requiresApiKey:!0,requiresBaseUrl:!1}}function w(e,t){t.context_window!==void 0&&(e.contextWindow=t.context_window),t.max_tokens!==void 0&&(e.maxTokens=t.max_tokens),t.reasoning!==void 0&&(e.reasoning=t.reasoning),t.input!==void 0&&(e.input=t.input),t.cost!==void 0&&(e.cost=t.cost,e.inputCost=t.cost.input,e.outputCost=t.cost.output,e.cacheReadCost=t.cost.cacheRead,e.cacheWriteCost=t.cost.cacheWrite),t.compat!==void 0&&(e.compat={...e.compat??{},...t.compat}),t.thinkingLevelMap!==void 0&&(e.thinkingLevelMap={...e.thinkingLevelMap??{},...t.thinkingLevelMap})}function Oe(e){let t=ae(e);return{...e,api:`bedrock-camp-converse`,provider:`bedrock-camp`,reasoning:e.reasoning===!0&&(ie(e)||t!==null),...t?{thinkingLevelMap:{...t}}:{}}}function T(e){try{if(e===`bedrock-camp`){let e=re(H(`bedrock-camp`));return se(h(`amazon-bedrock`),ce).filter(t=>oe(t,e)).map(Oe)}let t=C(e);if(t.getModelIds){let n;try{n=t.getModelIds()}catch(t){return E.error(`Provider getModelIds callback failed`,{providerId:e,error:t instanceof Error?t.message:String(t)}),[]}let i=new Map;for(let e of r())try{for(let t of h(e))i.set(t.id,t)}catch{}return n.map(n=>{let r=n.api===`openai`?`openai`:`anthropic`,a=`${e}-${r}`,o=i.get(n.id),s;if(o)s={...o,api:a,provider:e};else if(s=G(e,n.id,``,a),n.name&&(s.name=n.name),r===`anthropic`){let e=fe(n.id,i);s.cost=e,s.inputCost=e.input,s.outputCost=e.output,s.cacheReadCost=e.cacheRead,s.cacheWriteCost=e.cacheWrite}let c=t.modelOverrides?.[n.id];return c&&w(s,c),w(s,n),s})}if(t.isOAuth){let n=h(`anthropic`),r=`${e}-anthropic`;return n.map(n=>{let i={...n,api:r,provider:e},a=t.modelOverrides?.[n.id];return a&&w(i,a),i})}return h(e===`azure-ai-foundry`?`anthropic`:e)}catch(t){return E.error(`Failed to load models`,{providerId:e,error:t instanceof Error?t.message:String(t)}),[]}}function ke(e){let t=A().find(t=>t.providerId===e);if(!t?.accessToken)return null;let n=!!t.tokenExpiresAt&&Date.now()>t.tokenExpiresAt-6e4;return{token:t.accessToken,maskedValue:t.maskedValue,expiresAt:t.tokenExpiresAt,userName:t.userName,userAvatar:t.userAvatar,scopes:t.scopes,expired:n}}var Ae=Object.assign({})[`/packages/webapp/providers.json`]??[],E=a(`provider-settings`);function je(e=Ae){if(e.length===0||A().length>0)return;let t=new Set(x());for(let n of e)if(!(!n.providerId||!n.apiKey)){if(!t.has(n.providerId)){E.warn(`Unknown provider "${n.providerId}" in providers.json — skipping`);continue}P(n.providerId,n.apiKey,n.baseUrl)}let n=e.find(e=>e.providerId&&e.apiKey&&t.has(e.providerId));n?.model&&!localStorage.getItem(_)&&localStorage.setItem(_,`${n.providerId}:${n.model}`)}var Me=[/haiku/i];function D(e){return Me.some(t=>t.test(e))}function Ne(e){return e.filter(e=>!D(e.id))}function O(e,t){let n=$();if(n===null)return e;let r=ye();return e.filter(e=>!ge(r,n,t,e.id))}function k(){let e=A();if(e.length===0)return[];let t=new Map;for(let n of e){if(t.has(n.providerId))continue;let e=C(n.providerId);if(e.hidden||v(n.providerId))continue;let r=O(Ne(T(n.providerId)),n.providerId);if(r.length===0)continue;let i={providerId:n.providerId,providerName:e.name,models:r};t.set(n.providerId,i)}return[...t.values()]}function Pe(e){return k().map(e=>e.providerId).filter(t=>t!==e)}function A(){we();let e=localStorage.getItem(g);if(!e)return[];try{let t=JSON.parse(e);return Array.isArray(t)?t.filter(e=>typeof e==`object`&&!!e&&typeof e.providerId==`string`&&typeof e.apiKey==`string`):[]}catch{return[]}}function j(e){return f(localStorage)[e]??[]}function M(e,t){let n=f(localStorage),r=t.map(e=>e.trim()).filter(e=>e.length>0);r.length===0?delete n[e]:n[e]=r,de(localStorage,n)}async function Fe(e,t){if(te()){M(e,t);return}let n=ne();if(!n)throw Error(`setExtraOAuthDomainsAsync: no DOM and no panel-rpc client — cannot persist to page localStorage`);let{storeAfter:r}=await n.call(`oauth-extras-set`,{providerId:e,domains:t});try{de(localStorage,r)}catch(t){E.warn(`worker-shim mirror failed after successful page write — reload to refresh`,{providerId:e,error:t instanceof Error?t.message:String(t)})}}function Ie(){return f(localStorage)}function Le(e){localStorage.setItem(g,JSON.stringify(e))}async function N(e){if(te()){Le(e);return}let t=ne();if(!t)throw Error(`saveAccountsAsync: no DOM and no panel-rpc client — cannot persist to page localStorage`);let n=JSON.stringify(e),{storedJson:r}=await t.call(`save-oauth-accounts`,{accountsJson:n});try{localStorage.setItem(g,r)}catch(e){E.warn(`worker-shim mirror failed after successful page write — reload to refresh`,{error:e instanceof Error?e.message:String(e)})}}function P(e,t,n,r,i){let a=A().filter(t=>t.providerId!==e),o={providerId:e,apiKey:t};n&&(o.baseUrl=n),r&&(o.deployment=r),i&&(o.apiVersion=i),a.push(o),Le(a)}async function Re(e){let t=c();try{if(t===`extension-direct`){let t=await new Promise(t=>{chrome.runtime.sendMessage({type:`secrets.delete`,name:`oauth.${e}.token`},n=>{chrome.runtime.lastError&&E.error(`SW secrets.delete transport failed`,{providerId:e,error:chrome.runtime.lastError.message}),t(n??{})})});t.error&&E.error(`SW secrets.delete returned error`,{providerId:e,error:t.error})}else if(t===`extension-delegate`){let t=await l(`secrets.delete`,{name:`oauth.${e}.token`});t?.error&&E.error(`Bridge secrets.delete returned error`,{providerId:e,error:t.error})}else if(t!==`connect`){let t=await fetch(o(`/api/secrets/oauth/${e}`),{method:`DELETE`,headers:s()});!t.ok&&t.status!==404&&E.warn(`OAuth replica DELETE non-ok`,{providerId:e,status:t.status})}}catch(n){E.error(`OAuth replica removal failed`,{providerId:e,topology:t,error:n instanceof Error?n.message:String(n)})}}async function F(e){let t=A().find(t=>t.providerId===e),n=C(e);t&&n?.isOAuth&&await I(e),await Re(e),await N(A().filter(t=>t.providerId!==e));let r=localStorage.getItem(_)??``,i=r.indexOf(`:`);i>0&&r.slice(0,i)===e&&localStorage.removeItem(_)}async function I(e){let t=A().find(t=>t.providerId===e);if(!t)return;let n=C(e);if(n?.isOAuth){if(n.onOAuthLogout)try{await n.onOAuthLogout()}catch(t){E.warn(`onOAuthLogout failed`,{providerId:e,error:t instanceof Error?t.message:String(t)})}if(n.getOAuthLogoutUrl){let r=n.getOAuthLogoutUrl(t);if(r){let{openIdpLogoutUrl:t}=await i(async()=>{let{openIdpLogoutUrl:e}=await import(`./oauth-service-B-vKfxAF.js`);return{openIdpLogoutUrl:e}},__vite__mapDeps([0,1,2,3,4,5,6,7,8,9]));await t(r).catch(t=>{E.warn(`IdP logout popup failed`,{providerId:e,error:t instanceof Error?t.message:String(t)})})}}await N(A().map(t=>t.providerId===e?{providerId:t.providerId,apiKey:``,baseUrl:t.baseUrl,userName:t.userName,userAvatar:t.userAvatar,loggedOut:!0}:t)),await Re(e)}}async function L(e,t={}){let n=Math.max(1,t.attempts??3),r=t.delayMs??150,i=t.sleep??(e=>new Promise(t=>setTimeout(t,e))),a;for(let t=0;t<n;t++){let o=await e();if(o.maskedValue)return{maskedValue:o.maskedValue};o.error&&(a=o.error),t<n-1&&await i(r)}return{lastError:a}}var ze=`access token rotated during mask write`;function Be(e,t,n,r){let i=r.find(t=>t.providerId===e);return i?.accessToken?i.accessToken===t?(i.maskedValue=n,{maskedValue:n}):(E.warn(`OAuth mask write raced with token rotation; discarding replica`,{providerId:e}),{error:ze}):{error:`account gone after mask write`}}function R(e,t){return!!e&&e!==t}async function z(e,t,n){let r={providerId:e.providerId,accessToken:e.accessToken,domains:e.domains.join(`,`)},{maskedValue:i,lastError:a}=await L(()=>t.sendMaskRequest(r),n);if(!R(i,e.accessToken)){let t=i?`mask replica equals the access token`:a??`no error reported (cold SW or empty reply)`;return E.error(`OAuth mask give-up: no masked value after retries`,{providerId:e.providerId,reason:t}),{error:t}}let o=t.getAccounts(),s=Be(e.providerId,e.accessToken,i,o);return s.maskedValue&&await t.saveAccounts(o),s}function Ve(e){let t=C(e).oauthTokenDomains??[],n=j(e),r=new Set,i=[];for(let e of[...t,...n]){let t=e.toLowerCase();r.has(t)||(r.add(t),i.push(e))}return i}function He(e){return new Promise(t=>{chrome.runtime.sendMessage({type:`secrets.mask-oauth-token`,...e},n=>{chrome.runtime.lastError&&E.error(`SW mask-oauth-token transport failed`,{providerId:e.providerId,error:chrome.runtime.lastError.message});let r=typeof n==`object`&&n?n:void 0;r?.error&&E.warn(`SW mask-oauth-token returned error`,{providerId:e.providerId,error:r.error}),t(r??{})})})}function Ue(e){return l(`secrets.mask-oauth-token`,e).then(t=>(t?.error&&E.warn(`Bridge mask-oauth-token returned error`,{providerId:e.providerId,error:t.error}),t??{})).catch(t=>(E.error(`Bridge mask-oauth-token transport failed`,{providerId:e.providerId,error:t instanceof Error?t.message:String(t)}),{}))}async function We(e,t,n){let r=o(`/api/secrets/oauth-update`),i=await fetch(r,{method:`POST`,headers:s({"Content-Type":`application/json`}),body:JSON.stringify({providerId:e,accessToken:t,domains:n})});if(!i.ok)return E.warn(`OAuth replica POST non-ok`,{providerId:e,status:i.status,url:r}),{error:`OAuth replica POST HTTP ${i.status}`};let a=await i.json();if(typeof a.maskedValue!=`string`)return E.warn(`OAuth replica POST ok but missing maskedValue`,{providerId:e,url:r}),{error:`OAuth replica POST ok but missing maskedValue`};if(!R(a.maskedValue,t))return E.error(`OAuth mask replica equals the access token; refusing to persist`,{providerId:e}),{error:`mask replica equals the access token`};let c=A(),l=Be(e,t,a.maskedValue,c);return l.maskedValue&&await N(c),l}async function Ge(e,t){let n=await Ke(e,t);if(n.error!==ze)return n;let r=A().find(t=>t.providerId===e)?.accessToken;return!r||r===t?n:Ke(e,r)}async function Ke(e,t){let n=Ve(e);if(n.length===0)return{error:`no oauth token domains configured`};let r=c();try{return r===`extension-direct`?z({providerId:e,accessToken:t,domains:n},{sendMaskRequest:He,getAccounts:A,saveAccounts:N}):r===`extension-delegate`?z({providerId:e,accessToken:t,domains:n},{sendMaskRequest:Ue,getAccounts:A,saveAccounts:N}):r===`connect`?{error:`no replica store in connect mode`}:await We(e,t,n)}catch(t){let n=t instanceof Error?t.message:String(t);return E.error(`OAuth replica sync failed`,{providerId:e,topology:r,error:n}),{error:n}}}async function qe(e){let t=A().find(t=>t.providerId===e);return t?.accessToken?R(t.maskedValue,t.accessToken)?{maskedValue:t.maskedValue}:Ge(e,t.accessToken):{error:`no access token held`}}function Je(e,t){if(e.accessToken)return`scopes`in e?e.scopes:t?.scopes}async function Ye(e){let t=A().find(t=>t.providerId===e.providerId),n=A().filter(t=>t.providerId!==e.providerId);n.push({providerId:e.providerId,apiKey:``,accessToken:e.accessToken,refreshToken:e.refreshToken,tokenExpiresAt:e.tokenExpiresAt,userName:e.userName,userAvatar:e.userAvatar,baseUrl:e.baseUrl??t?.baseUrl,scopes:Je(e,t)}),await N(n),await Ge(e.providerId,e.accessToken)}var Xe=`local`;function B(e){let t=A().find(t=>t.providerId===e);return t&&(t.accessToken||t.apiKey)||null}function V(e){let t=A().find(t=>t.providerId===e);return t?t.accessToken||t.apiKey||(C(e).optionalApiKey?Xe:null):null}function H(e){return A().find(t=>t.providerId===e)?.baseUrl??null}function Ze(e){return A().find(t=>t.providerId===e)?.deployment??null}function Qe(e){return A().find(t=>t.providerId===e)?.apiVersion??null}function U(){let e=localStorage.getItem(_)||``,t=e.indexOf(`:`);return t>=0?e.slice(t+1):e}function $e(e){let t=e.indexOf(`:`);if(t>0){let n=e.slice(0,t),r=new Set([...ee(),...x()]),i=n.includes(`.`);if(r.has(n)||!i){localStorage.setItem(_,e);return}}let n=W();localStorage.setItem(_,`${n}:${e}`)}function et(){return localStorage.getItem(_)||``}function W(){let e=et(),t=e.indexOf(`:`);if(t>0)return e.slice(0,t);let n=A(),r=U();if(r){let e=n.find(e=>S(e.providerId)&&De(e.providerId,r));if(e)return e.providerId}let i=n.find(e=>S(e.providerId));return i?i.providerId:n.length>0?n[0].providerId:`anthropic`}function tt(e){let t=U();localStorage.setItem(_,`${e}:${t}`)}function nt(){let e=U();localStorage.setItem(_,e)}function rt(){return V(W())}function it(e){let t=W();P(t,e,H(t)??void 0)}async function at(){await F(W())}function ot(){return H(W())}function st(e){let t=W(),n=B(t);n&&P(t,n,e||void 0)}function ct(){let e=W(),t=B(e);t&&P(e,t)}function lt(){let e=A(),t=W(),n=U();return e.map(e=>{let r={providerId:e.providerId,apiKey:e.apiKey};return e.baseUrl&&(r.baseUrl=e.baseUrl),e.providerId===t&&n&&(r.model=n),r})}async function ut(){let e=A();await Promise.allSettled(e.map(e=>F(e.providerId))),localStorage.removeItem(g),localStorage.removeItem(_);for(let e of Se)localStorage.removeItem(e)}function dt(e){return/^(?:gpt[-.]?|o[0-9]|chatgpt)/i.test(e)?`openai`:`anthropic`}function G(e,t,n,r){return{id:t,name:t,provider:e,api:r??`${e}-${dt(t)}`,baseUrl:n??``,contextWindow:2e5,maxTokens:16384,input:[`text`,`image`],cost:{input:0,output:0,cacheRead:0,cacheWrite:0},reasoning:!0}}function K(e,t){return t.isOAuth||e===`azure-ai-foundry`?`anthropic`:e===`bedrock-camp`?`amazon-bedrock`:e}function ft(){let e=new Set;for(let t of A())t.loggedOut||(e.add(t.providerId),e.add(K(t.providerId,C(t.providerId))));return[...e]}function pt(e,t,n){let r=T(e).find(e=>e.id===t);return r?n?{...r,baseUrl:n}:r:null}function mt(e,t,n,r){return n.isOAuth?T(t).find(e=>e.id===r)||{...e,api:`${t}-anthropic`,provider:t}:t===`bedrock-camp`?{...e,api:`bedrock-camp-converse`,provider:`bedrock-camp`}:e}function ht(e,t,n,r,i){let a=pt(e,n,r);if(a)return a;if(t.isOAuth)return G(e,n,r);if(i)throw Error(`Model ${n} is not available from provider ${e}`);return J()}function q(e,t){if(!e)return J();let n=t??W(),r=H(n),i=C(n);if(t!==void 0){let t=pt(n,e,r);if(t)return t}try{let t=m(K(n,i),e);if(!t?.id)throw Error(`Model ${e} not found`);let a=mt(t,n,i,e);return r?{...a,baseUrl:r}:a}catch(a){return E.debug(`resolveModelById: pi-ai lookup miss, using provider fallback`,{providerId:n,modelId:e,error:a instanceof Error?a.message:String(a)}),ht(n,i,e,r,t!==void 0)}}function gt(e,t){return e.provider===t||e.provider===K(t,C(t))}function J(){let e=W(),t=U(),n=H(e),r=T(e),i=C(e),a=i.defaultModelId?r.find(e=>e.id.toLowerCase().includes(i.defaultModelId.toLowerCase()))?.id:void 0,o=t||a||r[0]?.id||`claude-sonnet-4-6`;try{let t=K(e,i),a=m(t,o);if(!a?.id)throw Error(`Model ${o} not found in ${t} registry`);let s=a;return i.isOAuth?s=r.find(e=>e.id===o)||{...s,api:`${e}-anthropic`,provider:e}:e===`bedrock-camp`&&(s={...s,api:`bedrock-camp-converse`,provider:`bedrock-camp`}),n&&(s={...s,baseUrl:n}),s}catch(t){E.debug(`resolveCurrentModel: pi-ai lookup miss, using provider fallback`,{providerId:e,effectiveModelId:o,error:t instanceof Error?t.message:String(t)});let a=r.find(e=>e.id===o);return a?n?{...a,baseUrl:n}:a:i.isOAuth?G(e,o,n):m(`anthropic`,`claude-sonnet-4-0`)}}function _t(e){let t=e.toLowerCase();if(!t)return null;let n=null;try{n=W()}catch{}if(n!==null){let e=Y(t,[n]);if(e!==null)return e}return Y(t,A().map(e=>e.providerId))}function Y(e,t){let n=null,r=-1;for(let i of t)for(let t of T(i)){let i=t.id.toLowerCase(),a=(t.name??``).toLowerCase();if(!i.includes(e)&&!a.includes(e))continue;let o=t.contextWindow??0;(o>r||o===r&&Et(t.id,n??``)>0)&&(r=o,n=t.id)}return n}function X(){let e=[];try{for(let t of A())e.includes(t.providerId)||e.push(t.providerId)}catch{}try{let t=W();e.includes(t)||e.push(t)}catch{}return e}function vt(e){let t=e.indexOf(`:`);if(t<=0||t===e.length-1)return null;let n=e.slice(0,t),r=e.slice(t+1),i=X().includes(n);if(i)return{providerId:n,modelId:r,configured:i};let a=!1;try{a=x().includes(n)}catch{}return a?{providerId:n,modelId:r,configured:!1}:null}function Z(e,t,n=!0){let r=[e],i=n?Y(e.toLowerCase(),[t]):null;i!==null&&i!==e&&r.push(i);let a=[];try{a=T(t)}catch{}for(let n of r)if(!(a.length>0&&!a.some(e=>e.id===n)))try{if(q(n,t).id===n)return{modelId:n,providerId:t}}catch(r){E.debug(`selectModelFromProvider: candidate did not resolve`,{input:e,candidate:n,providerId:t,error:r instanceof Error?r.message:String(r)})}return null}function yt(e){return e.map(e=>`${e.providerId}:${e.modelId}`).join(`, `)}function Q(e){if(!e)return{ok:!1,error:`unknown model: (empty)`};let t=vt(e);if(t)return Ct(e,t);let n=null;try{n=W()}catch{}if(n!==null){let t=Z(e,n);if(t)return St(t)}return wt(e,n)}function $(){try{return W()}catch{return null}}function bt(e){let t=$();return t===null||_e(ye(),t,e.providerId,e.modelId)}function xt(e){let t=$()??`<none>`;return{ok:!1,error:`model not allowed: ${`${e.providerId}:${e.modelId}`} is blocked by ${pe} while "${t}" is selected — ${be(t,e.providerId,e.modelId)}`}}function St(e){return bt(e)?{ok:!0,selection:e}:xt(e)}function Ct(e,t){if(!t.configured){let n=X();return{ok:!1,error:`unknown model: ${e} (provider "${t.providerId}" is not configured${n.length>0?`; configured: ${n.join(`, `)}`:``})`}}let n=Z(t.modelId,t.providerId);return n?St(n):{ok:!1,error:`unknown model: ${e} (provider "${t.providerId}" does not offer "${t.modelId}")`}}function wt(e,t){let n=X().filter(e=>e!==t);for(let t of[`exact`,`shorthand`]){let r=[];for(let i of n){let n=t===`exact`?e:Y(e.toLowerCase(),[i]);if(n===null)continue;let a=Z(n,i,!1);a&&r.push(a)}let i=r.filter(bt);if(i.length===0&&r.length>0)return xt(r[0]);if(i.length===1)return{ok:!0,selection:i[0]};if(i.length>1)return{ok:!1,error:`ambiguous model: ${e} matches ${yt(i)} — qualify it as provider:model`}}return{ok:!1,error:`unknown model: ${e}`}}function Tt(e){let t=Q(e);return t.ok?t.selection.modelId:null}function Et(e,t){let n=e.match(/\d+/g)?.map(Number)??[],r=t.match(/\d+/g)?.map(Number)??[],i=Math.max(n.length,r.length);for(let e=0;e<i;e++){let t=(n[e]??0)-(r[e]??0);if(t!==0)return t}return 0}export{fe as $,W as A,F as B,j as C,T as D,C as E,b as F,Q as G,q as H,gt as I,st as J,Ye as K,z as L,R as M,I as N,B as O,L as P,tt as Q,O as R,Ze as S,ke as T,_t as U,J as V,Tt as W,Fe as X,M as Y,$e as Z,V as _,je as a,ot as b,ct as c,lt as d,A as f,rt as g,Pe as h,P as i,D as j,U as k,nt as l,Ie as m,Ee as n,ut as o,k as p,it as q,xe as r,at as s,g as t,qe as u,Qe as v,ft as w,H as x,x as y,S as z};
@@ -1 +1 @@
1
- import{S as e,_ as t,r as n,s as r}from"./account-store-B9PzT8eI.js";import{r as i}from"./panel-rpc-DW7W4w6_.js";import{a}from"./diagnostics-Cag7MsZI.js";import{a as o}from"./compat-CGK4SwF8.js";import{c as s,s as c}from"./core-E6pC-3NP.js";import{a as l,r as u,s as d,t as f}from"./legacy-api-aliases-DvlNmb0H.js";import{a as p,i as m,r as h}from"./claude-model-version-ceOteQ2f.js";import{r as g}from"./provider-budget-DbHWq3j6.js";import{n as _}from"./llm-session-id-BZyXP_j2.js";import{n as v}from"./pi-transcript-context-4pjVPiVC.js";import{y}from"./kernel-worker-CWXec_cl.js";import{n as b,t as ee}from"./silent-renew-backoff-Dmz3DJHb.js";import{getOAuthPageOrigin as te}from"./oauth-service-Bx_Dy3GC.js";import{n as x}from"./temperature-support-0nztUM0u.js";import"./provider-settings-brukJESh.js";var ne={proxyEndpoint:`https://adobe-llm-proxy.paolo-moz.workers.dev`,redirectUri:`https://www.sliccy.ai/auth/callback`,extensionRedirectUri:`https://akjjllgokmbgpbdbmafpiefnhidlmbgf.chromiumapp.org/adobe`};function re(e,t){return h(e,t)}function S(e,t,n){return e!==`xhigh`||!t?e:p(t,n)?`xhigh`:m(t,n)?`max`:`high`}function ie(e,t){let n=e?t?.thinkingLevelMap?.[e]:void 0;return S((()=>{if(typeof n==`string`)return n;switch(e){case`minimal`:case`low`:return`low`;case`medium`:return`medium`;case`xhigh`:return`xhigh`;default:return`high`}})(),t?.id,t?.name)}function ae(e,t){return async(n,r)=>{let i=t?await t(n,r)??n:n,a=i.thinking;return a&&a.type===`enabled`&&(i.thinking={type:`adaptive`,...a.display===void 0?{}:{display:a.display}},i.output_config={...i.output_config??{},effort:e}),i}}function C(e,t){if(!re(e.id,e.name))return t;let n=t,r=S(n.effort??ie(n.reasoning,e),e.id,e.name);return{...t,onPayload:ae(r,n.onPayload)}}function oe(e,t){let n={id:e.id,name:e.name??e.id},r=t?.api??e.api,i=t?.context_window??e.context_window,a=t?.max_tokens??e.max_tokens,o=t?.reasoning??e.reasoning,s=t?.input??e.input;r&&(n.api=r),i!==void 0&&(n.context_window=i),a!==void 0&&(n.max_tokens=a),o!==void 0&&(n.reasoning=o),s&&(n.input=s);let c=t?.cost??e.cost;return c&&(n.cost=c),/haiku/i.test(e.id)&&(n.compat={supportsEagerToolInputStreaming:!1}),/sonnet-5\b/i.test(e.id)&&!n.thinkingLevelMap&&(n.thinkingLevelMap={xhigh:`xhigh`}),n}async function se(e,t,n,r={}){let i=typeof AbortController==`function`?new AbortController:null,a=i?setTimeout(()=>i.abort(),r.timeoutMs??8e3):null;try{let a=await n(`${e.replace(/\/$/,``)}/v1/usage`,{headers:{...r.headers,Authorization:`Bearer ${t}`},...i?{signal:i.signal}:{}});if(a.status===404||a.status===501)return null;if(!a.ok)throw Error(`Adobe /v1/usage returned ${a.status}`);return g(await a.json())}finally{a&&clearTimeout(a)}}const w=Object.assign({"/packages/webapp/providers/adobe-config.json":ne})[`/packages/webapp/providers/adobe-config.json`]??{clientId:``,proxyEndpoint:``,scopes:`openid,profile,email`};function T(){let e=r(`adobe`);if(e)return e.replace(/\/$/,``);if(w.proxyEndpoint)return w.proxyEndpoint.replace(/\/$/,``);throw Error(`Adobe proxy endpoint not configured — set it in Settings or adobe-config.json`)}const E=new Map,ce=new Map,le=`slicc-adobe-models`;function ue(e){try{localStorage.setItem(le,JSON.stringify(e))}catch{}}async function D(e){try{let t=await fetch(`${e}/v1/config`,{headers:{[W]:`6.225.0`}});return t.ok?await t.json():(console.warn(`[adobe] Proxy /v1/config returned ${t.status}`),null)}catch(e){return console.warn(`[adobe] Failed to fetch proxy config:`,e instanceof Error?e.message:String(e)),null}}async function O(e){let t=E.get(e);if(t)return t;let n=await D(e);return n||=(await new Promise(e=>setTimeout(e,600)),await D(e)),n?(E.set(e,n),n):{}}function k(e){let t=e.clientId||w.clientId;if(!t)throw Error(`Could not determine IMS client ID — proxy /v1/config did not return one and adobe-config.json is empty`);return t}function A(e){return e.scopes||w.scopes}function j(e){return e.imsEnvironment||w.imsEnvironment||`prod`}const M={prod:`https://ims-na1.adobelogin.com`,stg1:`https://ims-na1-stg1.adobelogin.com`};function N(e){return M[e??w.imsEnvironment??`prod`]??M.prod}async function P(){let e;try{e=T()}catch{return{}}return E.get(e)||new Promise(t=>{let n=setTimeout(()=>t({}),5e3),r=e=>{clearTimeout(n),t(e)};O(e).then(r,()=>r({}))})}function F(e){try{let t=e.split(`.`)[1];if(!t)return;let n=t.replace(/-/g,`+`).replace(/_/g,`/`),r=atob(n+`=`.repeat((4-n.length%4)%4)),i=JSON.parse(r);return typeof i.client_id==`string`?i.client_id:void 0}catch{return}}const I=typeof chrome<`u`&&!!chrome?.runtime?.id;function L(){return n().find(e=>e.providerId===`adobe`)}const de=[`/ims/profile/v1`,`/ims/userinfo/v2`];async function fe(e,t){try{let n=await fetch(e,{headers:{Authorization:`Bearer ${t}`}});if(!n.ok){console.warn(`[adobe] Profile fetch ${e} returned ${n.status}`);return}let r=await n.json(),i=r.displayName||r.name||r.email;return i?{name:i,avatar:r.picture||r.avatar_url}:void 0}catch(t){console.warn(`[adobe] Profile fetch ${e} failed:`,t instanceof Error?t.message:String(t));return}}async function pe(e,t){for(let n of de){let r=await fe(`${N(t)}${n}`,e);if(r)return r}return console.warn(`[adobe] No IMS profile endpoint named the user; account will have no display name`),{}}async function me(){let e=L(),t=e?.accessToken;if(!t)return{status:`unknown`,detail:`no stored token`};let n=await P(),r=F(t)||n.clientId||w.clientId||``;if(!r)return{status:`unknown`,detail:`no IMS client ID available`};let i=N(j(n));try{let n=await fetch(`${i}/ims/validate_token/v1`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({client_id:r,token:t,type:`access_token`}),signal:AbortSignal.timeout(1e4)});if(!n.ok)return{status:`unknown`,detail:`HTTP ${n.status}${n.statusText?` ${n.statusText}`:``}`};let a=await n.json();return a.valid===!0?{status:`accepted`,userName:e?.userName}:a.valid===!1?{status:`rejected`,detail:`IMS reported the token invalid (${typeof a.reason==`string`?a.reason:`no reason given`})`}:{status:`unknown`,detail:"IMS answered 200 without a boolean `valid` verdict"}}catch(e){return{status:`unknown`,detail:e instanceof Error?e.message:String(e)}}}function R(e){let t=e.indexOf(`#`);if(t<0)return null;let n=new URLSearchParams(e.slice(t+1)),r=n.get(`access_token`);return r?{accessToken:r,expiresIn:parseInt(n.get(`expires_in`)??`86400`,10),scope:n.get(`scope`)??void 0}:null}const z={id:`adobe`,name:`Adobe`,description:`Claude via Adobe — login with your Adobe ID`,requiresApiKey:!1,requiresBaseUrl:!w.proxyEndpoint,baseUrlPlaceholder:`https://your-proxy.example.com`,baseUrlDescription:`Anthropic-compatible proxy endpoint`,isOAuth:!0,defaultModelId:`sonnet`,oauthTokenDomains:[`ims-na1.adobelogin.com`,`ims-na1-stg1.adobelogin.com`,`*.adobelogin.com`,`*.adobe.io`,`firefall.adobe.io`,`admin.hlx.page`,`admin.hlx.live`,`admin.aem.page`,`admin.aem.live`,`api.aem.live`],getBudgetUsage:ge,getModelIds:()=>{let e=e=>oe(e,ce.get(e.id));for(let t of Q.values())if(t.length){let n=t.map(t=>e({id:t.id,name:t.name??t.id,reasoning:t.reasoning,input:t.input,cost:t.cost}));return ue(n),n}for(let t of E.values())if(t.models?.length)return t.models.map(t=>e(t));try{let e=localStorage.getItem(le);if(e){let t=JSON.parse(e);if(t.length)return t}}catch{}return[{id:`claude-sonnet-4-6`,name:`Claude Sonnet 4.6`}]},onOAuthLogin:async(e,n,r)=>{let i=T(),a=await O(i),o=k(a),s=A(a),c=j(a),l=I?null:await te(),u=I?null:b({pageHref:l.href,pageOrigin:l.origin,configuredRedirectUri:w.redirectUri},()=>crypto.randomUUID()),d=I?w.extensionRedirectUri??`https://${chrome.runtime.id}.chromiumapp.org/`:u.redirectUri,f=u?.oauthState,p=u?.expectedNonce??null,m=new URLSearchParams({client_id:o,scope:s,response_type:`token`,redirect_uri:d});f&&m.set(`state`,f),r?.forceReauth&&m.set(`prompt`,`login`);let h=await e(`${N(c)}/ims/authorize/v2?${m}`);if(!h)return;if(p&&h)try{if(new URL(h).searchParams.get(`nonce`)!==p){console.error(`[adobe] OAuth nonce mismatch — possible CSRF`);return}}catch(e){console.warn(`[adobe] Nonce check skipped (URL parse failed):`,e instanceof Error?e.message:String(e))}let g=R(h);if(!g){console.error(`[adobe] Could not extract token from redirect URL`);return}let _=await pe(g.accessToken,c);await t({providerId:`adobe`,accessToken:g.accessToken,tokenExpiresAt:Date.now()+g.expiresIn*1e3,userName:_.name,userAvatar:_.avatar,scopes:g.scope,baseUrl:w.proxyEndpoint?void 0:i}),y(),await $().catch(e=>console.warn(`[adobe] Failed to fetch models after login:`,e instanceof Error?e.message:String(e))),n()},onOAuthLogout:async()=>{let e=L();if(e?.accessToken)try{let t=await P(),n=F(e.accessToken)||t.clientId||w.clientId,r=j(t);if(n){let t=await fetch(`${N(r)}/ims/revoke`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({token:e.accessToken,token_type_hint:`access_token`,client_id:n})});t.ok||console.warn(`[adobe] Token revocation returned ${t.status}, token may still be valid server-side`)}}catch(e){console.warn(`[adobe] Failed to revoke token:`,e instanceof Error?e.message:String(e))}await t({providerId:`adobe`,accessToken:``}),y()},onSilentRenew:async()=>L()?.accessToken?U():null,onValidateToken:me,refreshModels:async e=>{await $(e);let t=z.getModelIds?.();t?.length&&ue(t)}};let B=null;const he=ee();async function V(){let e=L();if(!e?.accessToken)throw Error(`Not logged in to Adobe — please log in first`);if((e.tokenExpiresAt??0)-Date.now()>6e4)return e.accessToken;console.log(`[adobe] Token expired or expiring soon, attempting silent renewal...`);let t=await he.run(()=>U());if(t)return t;let n=L();if((n?.tokenExpiresAt??0)-Date.now()>0&&n?.accessToken)return n.accessToken;throw Error(`Adobe session expired — please log in again`)}async function ge(){let e;try{e=T()}catch{return null}let t=L();if(!t?.accessToken||H())throw Error(`Adobe budget: not signed in`);return se(e,t.accessToken,fetch,{headers:{"X-Session-Id":_(xe)}})}function H(){let e=L();return!e?.tokenExpiresAt||Date.now()>e.tokenExpiresAt-6e4}async function U(){if(typeof window>`u`){let e=i();if(!e)return null;try{let{accessToken:t}=await e.call(`silent-renew`,{providerId:`adobe`},{timeoutMs:13e4});return t}catch(e){return console.warn(`[adobe] worker→page silent-renew bridge failed:`,e instanceof Error?e.message:String(e)),null}}return B===null&&(B=be().finally(()=>{B=null})),B}function _e(e,t){let n=k(t),r=A(t),i=j(t),a=I?null:b({pageHref:window.location.href,pageOrigin:window.location.origin,configuredRedirectUri:w.redirectUri},()=>crypto.randomUUID()),o=I?w.extensionRedirectUri??`https://${chrome.runtime.id}.chromiumapp.org/`:a.redirectUri,s=a?.oauthState,c=a?.expectedNonce??null,l=new URLSearchParams({client_id:n,scope:r,response_type:`token`,redirect_uri:o,prompt:`none`});return s&&l.set(`state`,s),{authorizeUrl:`${N(i)}/ims/authorize/v2?${l}`,expectedNonce:c,proxyEndpoint:e}}function ve(e,t){if(!t)return!0;try{if(new URL(e).searchParams.get(`nonce`)!==t)return console.error(`[adobe] OAuth nonce mismatch — possible CSRF`),!1}catch(e){console.warn(`[adobe] Nonce check skipped (URL parse failed):`,e instanceof Error?e.message:String(e))}return!0}async function ye(e,n){let r=L();await t({providerId:`adobe`,accessToken:e.accessToken,tokenExpiresAt:Date.now()+e.expiresIn*1e3,userName:r?.userName,userAvatar:r?.userAvatar,scopes:e.scope,baseUrl:w.proxyEndpoint?void 0:n})}async function be(){try{let e=T(),{authorizeUrl:t,expectedNonce:n}=_e(e,await O(e)),{createOAuthLauncher:r}=await import(`./oauth-service-Bx_Dy3GC.js`),i=await r()(t,{interactive:!1});if(!i||!ve(i,n))return null;let a=R(i);return a?(await ye(a,e),console.log(`[adobe] Token renewed silently`),await $().catch(e=>console.warn(`[adobe] Failed to refresh models after silent renewal:`,e instanceof Error?e.message:String(e))),a.accessToken):null}catch(e){return console.warn(`[adobe] Silent renewal error:`,e instanceof Error?e.message:String(e)),null}}const W=`X-Slicc-Version`;function G(e){let t={};if(e.headers)for(let[n,r]of Object.entries(e.headers))n.toLowerCase()!==`x-slicc-version`&&(t[n]=r);return t[W]=`6.225.0`,{...e,headers:t}}const xe=`adobe-usage-probe`,K=new Set;function q(e,t){if(e.headers){for(let[t,n]of Object.entries(e.headers))if(t.toLowerCase()===`x-session-id`&&n!=null)return e}return K.has(t)||(K.add(t),console.warn(`[adobe] Missing X-Session-Id from ${t} — using daily fallback. Attach an X-Session-Id header at the call site (see scoop-context.ts streamWithSessionId or docs/pitfalls.md).`)),{...e,headers:{...e.headers??{},"X-Session-Id":_(`adobe-provider-fallback`)}}}function Se(){K.clear()}function J(e,t){return{type:`error`,reason:`error`,error:{role:`assistant`,content:[],api:`adobe-anthropic`,provider:`adobe`,model:e.id,usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:`error`,errorMessage:t instanceof Error?t.message:String(t),timestamp:Date.now()}}}function Y(e){console.error(`[adobe] Stream error:`,e instanceof Error?e.message:String(e))}const X=(e,t,n={})=>{let r=a();return Ce(r,e,t,n).catch(Y),r};async function Ce(e,t,n,r){try{let i=await V();if(String(t.api).includes(`openai`)){let a={...t,baseUrl:`${T()}/v1`,api:`openai-completions`,compat:{...t.compat,supportsStore:!1,supportsDeveloperRole:!1}},o=u(a,v(n),G(q({...r,apiKey:i},`streamAdobe[openai]`)));for await(let t of o)e.push(t)}else{let a={...t,baseUrl:T(),api:`anthropic-messages`},o=f(a,v(n),G(q(C(t,x(t.id,t.name,{...r,apiKey:i})),`streamAdobe[anthropic]`)));for await(let t of o)e.push(t)}e.end()}catch(n){Y(n),e.push(J(t,n)),e.end()}}const Z=(e,t,n)=>{let r=a();return we(r,e,t,n).catch(Y),r};async function we(e,t,n,r){try{let i=await V();if(String(t.api).includes(`openai`)){let a={...t,baseUrl:`${T()}/v1`,api:`openai-completions`,compat:{...t.compat,supportsStore:!1,supportsDeveloperRole:!1}},o=d(a,v(n),G(q({...r,apiKey:i},`streamSimpleAdobe[openai]`)));for await(let t of o)e.push(t)}else{let a={...t,baseUrl:T(),api:`anthropic-messages`},o=l(a,v(n),G(q(C(t,x(t.id,t.name,{...r,apiKey:i})),`streamSimpleAdobe[anthropic]`)));for await(let t of o)e.push(t)}e.end()}catch(n){Y(n),e.push(J(t,n)),e.end()}}function Te(e){let t={id:e.id,name:e.name};return e.api!==void 0&&(t.api=e.api),e.context_window!==void 0&&(t.context_window=e.context_window),e.max_tokens!==void 0&&(t.max_tokens=e.max_tokens),e.reasoning!==void 0&&(t.reasoning=e.reasoning),e.input!==void 0&&(t.input=e.input),t}function Ee(){let e=new Map;for(let t of s())try{let n=c(t);for(let t of n)e.set(t.id,t)}catch{}return e}function De(t,n,r){let i=`adobe-${t.api===`openai`?`openai`:`anthropic`}`,a=r.get(t.id);if(a)return{...a,provider:`adobe`,api:i};let o=e(t.id,r);return{id:t.id,name:t.name??t.id,provider:`adobe`,api:i,baseUrl:n,contextWindow:2e5,maxTokens:16384,input:[`text`,`image`],cost:o,inputCost:o.input,outputCost:o.output,cacheReadCost:o.cacheRead,cacheWriteCost:o.cacheWrite,reasoning:!0}}function Oe(e,t){for(let t of e)ce.set(t.id,Te(t));let n=Ee();return e.map(e=>De(e,t,n))}async function ke(e){try{let t=e??await V(),n=T(),r=await fetch(`${n}/v1/models`,{headers:{Authorization:`Bearer ${t}`,[W]:`6.225.0`}});if(!r.ok)console.warn(`[adobe] Proxy /v1/models returned ${r.status}, falling back to Anthropic models`);else{let e=await r.json();if(e.data?.length)return Oe(e.data,n)}}catch(e){console.warn(`[adobe] Failed to fetch proxy models:`,e instanceof Error?e.message:String(e))}return null}const Q=new Map;function Ae(){return c(`anthropic`).map(e=>({...e,provider:`adobe`,api:`adobe-anthropic`}))}async function $(e){let t=T(),n=Q.get(t);if(n)return n;let r=await ke(e);return r?(Q.set(t,r),r):Ae()}function je(){o({api:`adobe-anthropic`,stream:X,streamSimple:Z}),o({api:`adobe-openai`,stream:X,streamSimple:Z})}export{Se as __resetAdobeSessionIdWarningCacheForTests,z as config,R as extractTokenFromUrl,$ as getAdobeModels,V as getValidAccessToken,H as isTokenExpired,je as register};
1
+ import{S as e,_ as t,r as n,s as r}from"./account-store-BlJDP1-W.js";import{r as i}from"./panel-rpc-DW7W4w6_.js";import{a}from"./diagnostics-Cag7MsZI.js";import{a as o}from"./compat-CGK4SwF8.js";import{c as s,s as c}from"./core-E6pC-3NP.js";import{a as l,r as u,s as d,t as f}from"./legacy-api-aliases-DvlNmb0H.js";import{a as p,i as m,r as h}from"./claude-model-version-ceOteQ2f.js";import{r as g}from"./provider-budget-DbHWq3j6.js";import{n as _}from"./llm-session-id-BZyXP_j2.js";import{n as v}from"./pi-transcript-context-4pjVPiVC.js";import{y}from"./kernel-worker-jFET0gP4.js";import{n as b,t as ee}from"./silent-renew-backoff-Dmz3DJHb.js";import{getOAuthPageOrigin as te}from"./oauth-service-Bx_Dy3GC.js";import{n as x}from"./temperature-support-0nztUM0u.js";import"./provider-settings-DUOh4hPx.js";var ne={proxyEndpoint:`https://adobe-llm-proxy.paolo-moz.workers.dev`,redirectUri:`https://www.sliccy.ai/auth/callback`,extensionRedirectUri:`https://akjjllgokmbgpbdbmafpiefnhidlmbgf.chromiumapp.org/adobe`};function re(e,t){return h(e,t)}function S(e,t,n){return e!==`xhigh`||!t?e:p(t,n)?`xhigh`:m(t,n)?`max`:`high`}function ie(e,t){let n=e?t?.thinkingLevelMap?.[e]:void 0;return S((()=>{if(typeof n==`string`)return n;switch(e){case`minimal`:case`low`:return`low`;case`medium`:return`medium`;case`xhigh`:return`xhigh`;default:return`high`}})(),t?.id,t?.name)}function ae(e,t){return async(n,r)=>{let i=t?await t(n,r)??n:n,a=i.thinking;return a&&a.type===`enabled`&&(i.thinking={type:`adaptive`,...a.display===void 0?{}:{display:a.display}},i.output_config={...i.output_config??{},effort:e}),i}}function C(e,t){if(!re(e.id,e.name))return t;let n=t,r=S(n.effort??ie(n.reasoning,e),e.id,e.name);return{...t,onPayload:ae(r,n.onPayload)}}function oe(e,t){let n={id:e.id,name:e.name??e.id},r=t?.api??e.api,i=t?.context_window??e.context_window,a=t?.max_tokens??e.max_tokens,o=t?.reasoning??e.reasoning,s=t?.input??e.input;r&&(n.api=r),i!==void 0&&(n.context_window=i),a!==void 0&&(n.max_tokens=a),o!==void 0&&(n.reasoning=o),s&&(n.input=s);let c=t?.cost??e.cost;return c&&(n.cost=c),/haiku/i.test(e.id)&&(n.compat={supportsEagerToolInputStreaming:!1}),/sonnet-5\b/i.test(e.id)&&!n.thinkingLevelMap&&(n.thinkingLevelMap={xhigh:`xhigh`}),n}async function se(e,t,n,r={}){let i=typeof AbortController==`function`?new AbortController:null,a=i?setTimeout(()=>i.abort(),r.timeoutMs??8e3):null;try{let a=await n(`${e.replace(/\/$/,``)}/v1/usage`,{headers:{...r.headers,Authorization:`Bearer ${t}`},...i?{signal:i.signal}:{}});if(a.status===404||a.status===501)return null;if(!a.ok)throw Error(`Adobe /v1/usage returned ${a.status}`);return g(await a.json())}finally{a&&clearTimeout(a)}}const w=Object.assign({"/packages/webapp/providers/adobe-config.json":ne})[`/packages/webapp/providers/adobe-config.json`]??{clientId:``,proxyEndpoint:``,scopes:`openid,profile,email`};function T(){let e=r(`adobe`);if(e)return e.replace(/\/$/,``);if(w.proxyEndpoint)return w.proxyEndpoint.replace(/\/$/,``);throw Error(`Adobe proxy endpoint not configured — set it in Settings or adobe-config.json`)}const E=new Map,ce=new Map,le=`slicc-adobe-models`;function ue(e){try{localStorage.setItem(le,JSON.stringify(e))}catch{}}async function D(e){try{let t=await fetch(`${e}/v1/config`,{headers:{[W]:`6.226.1`}});return t.ok?await t.json():(console.warn(`[adobe] Proxy /v1/config returned ${t.status}`),null)}catch(e){return console.warn(`[adobe] Failed to fetch proxy config:`,e instanceof Error?e.message:String(e)),null}}async function O(e){let t=E.get(e);if(t)return t;let n=await D(e);return n||=(await new Promise(e=>setTimeout(e,600)),await D(e)),n?(E.set(e,n),n):{}}function k(e){let t=e.clientId||w.clientId;if(!t)throw Error(`Could not determine IMS client ID — proxy /v1/config did not return one and adobe-config.json is empty`);return t}function A(e){return e.scopes||w.scopes}function j(e){return e.imsEnvironment||w.imsEnvironment||`prod`}const M={prod:`https://ims-na1.adobelogin.com`,stg1:`https://ims-na1-stg1.adobelogin.com`};function N(e){return M[e??w.imsEnvironment??`prod`]??M.prod}async function P(){let e;try{e=T()}catch{return{}}return E.get(e)||new Promise(t=>{let n=setTimeout(()=>t({}),5e3),r=e=>{clearTimeout(n),t(e)};O(e).then(r,()=>r({}))})}function F(e){try{let t=e.split(`.`)[1];if(!t)return;let n=t.replace(/-/g,`+`).replace(/_/g,`/`),r=atob(n+`=`.repeat((4-n.length%4)%4)),i=JSON.parse(r);return typeof i.client_id==`string`?i.client_id:void 0}catch{return}}const I=typeof chrome<`u`&&!!chrome?.runtime?.id;function L(){return n().find(e=>e.providerId===`adobe`)}const de=[`/ims/profile/v1`,`/ims/userinfo/v2`];async function fe(e,t){try{let n=await fetch(e,{headers:{Authorization:`Bearer ${t}`}});if(!n.ok){console.warn(`[adobe] Profile fetch ${e} returned ${n.status}`);return}let r=await n.json(),i=r.displayName||r.name||r.email;return i?{name:i,avatar:r.picture||r.avatar_url}:void 0}catch(t){console.warn(`[adobe] Profile fetch ${e} failed:`,t instanceof Error?t.message:String(t));return}}async function pe(e,t){for(let n of de){let r=await fe(`${N(t)}${n}`,e);if(r)return r}return console.warn(`[adobe] No IMS profile endpoint named the user; account will have no display name`),{}}async function me(){let e=L(),t=e?.accessToken;if(!t)return{status:`unknown`,detail:`no stored token`};let n=await P(),r=F(t)||n.clientId||w.clientId||``;if(!r)return{status:`unknown`,detail:`no IMS client ID available`};let i=N(j(n));try{let n=await fetch(`${i}/ims/validate_token/v1`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({client_id:r,token:t,type:`access_token`}),signal:AbortSignal.timeout(1e4)});if(!n.ok)return{status:`unknown`,detail:`HTTP ${n.status}${n.statusText?` ${n.statusText}`:``}`};let a=await n.json();return a.valid===!0?{status:`accepted`,userName:e?.userName}:a.valid===!1?{status:`rejected`,detail:`IMS reported the token invalid (${typeof a.reason==`string`?a.reason:`no reason given`})`}:{status:`unknown`,detail:"IMS answered 200 without a boolean `valid` verdict"}}catch(e){return{status:`unknown`,detail:e instanceof Error?e.message:String(e)}}}function R(e){let t=e.indexOf(`#`);if(t<0)return null;let n=new URLSearchParams(e.slice(t+1)),r=n.get(`access_token`);return r?{accessToken:r,expiresIn:parseInt(n.get(`expires_in`)??`86400`,10),scope:n.get(`scope`)??void 0}:null}const z={id:`adobe`,name:`Adobe`,description:`Claude via Adobe — login with your Adobe ID`,requiresApiKey:!1,requiresBaseUrl:!w.proxyEndpoint,baseUrlPlaceholder:`https://your-proxy.example.com`,baseUrlDescription:`Anthropic-compatible proxy endpoint`,isOAuth:!0,defaultModelId:`sonnet`,oauthTokenDomains:[`ims-na1.adobelogin.com`,`ims-na1-stg1.adobelogin.com`,`*.adobelogin.com`,`*.adobe.io`,`firefall.adobe.io`,`admin.hlx.page`,`admin.hlx.live`,`admin.aem.page`,`admin.aem.live`,`api.aem.live`],getBudgetUsage:ge,getModelIds:()=>{let e=e=>oe(e,ce.get(e.id));for(let t of Q.values())if(t.length){let n=t.map(t=>e({id:t.id,name:t.name??t.id,reasoning:t.reasoning,input:t.input,cost:t.cost}));return ue(n),n}for(let t of E.values())if(t.models?.length)return t.models.map(t=>e(t));try{let e=localStorage.getItem(le);if(e){let t=JSON.parse(e);if(t.length)return t}}catch{}return[{id:`claude-sonnet-4-6`,name:`Claude Sonnet 4.6`}]},onOAuthLogin:async(e,n,r)=>{let i=T(),a=await O(i),o=k(a),s=A(a),c=j(a),l=I?null:await te(),u=I?null:b({pageHref:l.href,pageOrigin:l.origin,configuredRedirectUri:w.redirectUri},()=>crypto.randomUUID()),d=I?w.extensionRedirectUri??`https://${chrome.runtime.id}.chromiumapp.org/`:u.redirectUri,f=u?.oauthState,p=u?.expectedNonce??null,m=new URLSearchParams({client_id:o,scope:s,response_type:`token`,redirect_uri:d});f&&m.set(`state`,f),r?.forceReauth&&m.set(`prompt`,`login`);let h=await e(`${N(c)}/ims/authorize/v2?${m}`);if(!h)return;if(p&&h)try{if(new URL(h).searchParams.get(`nonce`)!==p){console.error(`[adobe] OAuth nonce mismatch — possible CSRF`);return}}catch(e){console.warn(`[adobe] Nonce check skipped (URL parse failed):`,e instanceof Error?e.message:String(e))}let g=R(h);if(!g){console.error(`[adobe] Could not extract token from redirect URL`);return}let _=await pe(g.accessToken,c);await t({providerId:`adobe`,accessToken:g.accessToken,tokenExpiresAt:Date.now()+g.expiresIn*1e3,userName:_.name,userAvatar:_.avatar,scopes:g.scope,baseUrl:w.proxyEndpoint?void 0:i}),y(),await $().catch(e=>console.warn(`[adobe] Failed to fetch models after login:`,e instanceof Error?e.message:String(e))),n()},onOAuthLogout:async()=>{let e=L();if(e?.accessToken)try{let t=await P(),n=F(e.accessToken)||t.clientId||w.clientId,r=j(t);if(n){let t=await fetch(`${N(r)}/ims/revoke`,{method:`POST`,headers:{"Content-Type":`application/x-www-form-urlencoded`},body:new URLSearchParams({token:e.accessToken,token_type_hint:`access_token`,client_id:n})});t.ok||console.warn(`[adobe] Token revocation returned ${t.status}, token may still be valid server-side`)}}catch(e){console.warn(`[adobe] Failed to revoke token:`,e instanceof Error?e.message:String(e))}await t({providerId:`adobe`,accessToken:``}),y()},onSilentRenew:async()=>L()?.accessToken?U():null,onValidateToken:me,refreshModels:async e=>{await $(e);let t=z.getModelIds?.();t?.length&&ue(t)}};let B=null;const he=ee();async function V(){let e=L();if(!e?.accessToken)throw Error(`Not logged in to Adobe — please log in first`);if((e.tokenExpiresAt??0)-Date.now()>6e4)return e.accessToken;console.log(`[adobe] Token expired or expiring soon, attempting silent renewal...`);let t=await he.run(()=>U());if(t)return t;let n=L();if((n?.tokenExpiresAt??0)-Date.now()>0&&n?.accessToken)return n.accessToken;throw Error(`Adobe session expired — please log in again`)}async function ge(){let e;try{e=T()}catch{return null}let t=L();if(!t?.accessToken||H())throw Error(`Adobe budget: not signed in`);return se(e,t.accessToken,fetch,{headers:{"X-Session-Id":_(xe)}})}function H(){let e=L();return!e?.tokenExpiresAt||Date.now()>e.tokenExpiresAt-6e4}async function U(){if(typeof window>`u`){let e=i();if(!e)return null;try{let{accessToken:t}=await e.call(`silent-renew`,{providerId:`adobe`},{timeoutMs:13e4});return t}catch(e){return console.warn(`[adobe] worker→page silent-renew bridge failed:`,e instanceof Error?e.message:String(e)),null}}return B===null&&(B=be().finally(()=>{B=null})),B}function _e(e,t){let n=k(t),r=A(t),i=j(t),a=I?null:b({pageHref:window.location.href,pageOrigin:window.location.origin,configuredRedirectUri:w.redirectUri},()=>crypto.randomUUID()),o=I?w.extensionRedirectUri??`https://${chrome.runtime.id}.chromiumapp.org/`:a.redirectUri,s=a?.oauthState,c=a?.expectedNonce??null,l=new URLSearchParams({client_id:n,scope:r,response_type:`token`,redirect_uri:o,prompt:`none`});return s&&l.set(`state`,s),{authorizeUrl:`${N(i)}/ims/authorize/v2?${l}`,expectedNonce:c,proxyEndpoint:e}}function ve(e,t){if(!t)return!0;try{if(new URL(e).searchParams.get(`nonce`)!==t)return console.error(`[adobe] OAuth nonce mismatch — possible CSRF`),!1}catch(e){console.warn(`[adobe] Nonce check skipped (URL parse failed):`,e instanceof Error?e.message:String(e))}return!0}async function ye(e,n){let r=L();await t({providerId:`adobe`,accessToken:e.accessToken,tokenExpiresAt:Date.now()+e.expiresIn*1e3,userName:r?.userName,userAvatar:r?.userAvatar,scopes:e.scope,baseUrl:w.proxyEndpoint?void 0:n})}async function be(){try{let e=T(),{authorizeUrl:t,expectedNonce:n}=_e(e,await O(e)),{createOAuthLauncher:r}=await import(`./oauth-service-Bx_Dy3GC.js`),i=await r()(t,{interactive:!1});if(!i||!ve(i,n))return null;let a=R(i);return a?(await ye(a,e),console.log(`[adobe] Token renewed silently`),await $().catch(e=>console.warn(`[adobe] Failed to refresh models after silent renewal:`,e instanceof Error?e.message:String(e))),a.accessToken):null}catch(e){return console.warn(`[adobe] Silent renewal error:`,e instanceof Error?e.message:String(e)),null}}const W=`X-Slicc-Version`;function G(e){let t={};if(e.headers)for(let[n,r]of Object.entries(e.headers))n.toLowerCase()!==`x-slicc-version`&&(t[n]=r);return t[W]=`6.226.1`,{...e,headers:t}}const xe=`adobe-usage-probe`,K=new Set;function q(e,t){if(e.headers){for(let[t,n]of Object.entries(e.headers))if(t.toLowerCase()===`x-session-id`&&n!=null)return e}return K.has(t)||(K.add(t),console.warn(`[adobe] Missing X-Session-Id from ${t} — using daily fallback. Attach an X-Session-Id header at the call site (see scoop-context.ts streamWithSessionId or docs/pitfalls.md).`)),{...e,headers:{...e.headers??{},"X-Session-Id":_(`adobe-provider-fallback`)}}}function Se(){K.clear()}function J(e,t){return{type:`error`,reason:`error`,error:{role:`assistant`,content:[],api:`adobe-anthropic`,provider:`adobe`,model:e.id,usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:`error`,errorMessage:t instanceof Error?t.message:String(t),timestamp:Date.now()}}}function Y(e){console.error(`[adobe] Stream error:`,e instanceof Error?e.message:String(e))}const X=(e,t,n={})=>{let r=a();return Ce(r,e,t,n).catch(Y),r};async function Ce(e,t,n,r){try{let i=await V();if(String(t.api).includes(`openai`)){let a={...t,baseUrl:`${T()}/v1`,api:`openai-completions`,compat:{...t.compat,supportsStore:!1,supportsDeveloperRole:!1}},o=u(a,v(n),G(q({...r,apiKey:i},`streamAdobe[openai]`)));for await(let t of o)e.push(t)}else{let a={...t,baseUrl:T(),api:`anthropic-messages`},o=f(a,v(n),G(q(C(t,x(t.id,t.name,{...r,apiKey:i})),`streamAdobe[anthropic]`)));for await(let t of o)e.push(t)}e.end()}catch(n){Y(n),e.push(J(t,n)),e.end()}}const Z=(e,t,n)=>{let r=a();return we(r,e,t,n).catch(Y),r};async function we(e,t,n,r){try{let i=await V();if(String(t.api).includes(`openai`)){let a={...t,baseUrl:`${T()}/v1`,api:`openai-completions`,compat:{...t.compat,supportsStore:!1,supportsDeveloperRole:!1}},o=d(a,v(n),G(q({...r,apiKey:i},`streamSimpleAdobe[openai]`)));for await(let t of o)e.push(t)}else{let a={...t,baseUrl:T(),api:`anthropic-messages`},o=l(a,v(n),G(q(C(t,x(t.id,t.name,{...r,apiKey:i})),`streamSimpleAdobe[anthropic]`)));for await(let t of o)e.push(t)}e.end()}catch(n){Y(n),e.push(J(t,n)),e.end()}}function Te(e){let t={id:e.id,name:e.name};return e.api!==void 0&&(t.api=e.api),e.context_window!==void 0&&(t.context_window=e.context_window),e.max_tokens!==void 0&&(t.max_tokens=e.max_tokens),e.reasoning!==void 0&&(t.reasoning=e.reasoning),e.input!==void 0&&(t.input=e.input),t}function Ee(){let e=new Map;for(let t of s())try{let n=c(t);for(let t of n)e.set(t.id,t)}catch{}return e}function De(t,n,r){let i=`adobe-${t.api===`openai`?`openai`:`anthropic`}`,a=r.get(t.id);if(a)return{...a,provider:`adobe`,api:i};let o=e(t.id,r);return{id:t.id,name:t.name??t.id,provider:`adobe`,api:i,baseUrl:n,contextWindow:2e5,maxTokens:16384,input:[`text`,`image`],cost:o,inputCost:o.input,outputCost:o.output,cacheReadCost:o.cacheRead,cacheWriteCost:o.cacheWrite,reasoning:!0}}function Oe(e,t){for(let t of e)ce.set(t.id,Te(t));let n=Ee();return e.map(e=>De(e,t,n))}async function ke(e){try{let t=e??await V(),n=T(),r=await fetch(`${n}/v1/models`,{headers:{Authorization:`Bearer ${t}`,[W]:`6.226.1`}});if(!r.ok)console.warn(`[adobe] Proxy /v1/models returned ${r.status}, falling back to Anthropic models`);else{let e=await r.json();if(e.data?.length)return Oe(e.data,n)}}catch(e){console.warn(`[adobe] Failed to fetch proxy models:`,e instanceof Error?e.message:String(e))}return null}const Q=new Map;function Ae(){return c(`anthropic`).map(e=>({...e,provider:`adobe`,api:`adobe-anthropic`}))}async function $(e){let t=T(),n=Q.get(t);if(n)return n;let r=await ke(e);return r?(Q.set(t,r),r):Ae()}function je(){o({api:`adobe-anthropic`,stream:X,streamSimple:Z}),o({api:`adobe-openai`,stream:X,streamSimple:Z})}export{Se as __resetAdobeSessionIdWarningCacheForTests,z as config,R as extractTokenFromUrl,$ as getAdobeModels,V as getValidAccessToken,H as isTokenExpired,je as register};