@xiaoso/dsh-tool-plus 0.1.0-beta.2 → 0.1.0-beta.4
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.
- package/README.en.md +122 -0
- package/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +4 -35
- package/lib/abort-B7izMMna.mjs +51 -0
- package/lib/abort-D1_Z5Ut5.mjs +51 -0
- package/lib/abort-dIkZBV7Q.mjs +51 -0
- package/lib/amazon-bedrock-B0nxT06F.mjs +917 -0
- package/lib/amazon-bedrock-D-shAr1X.mjs +917 -0
- package/lib/amazon-bedrock-WQhvjHYu.mjs +917 -0
- package/lib/anthropic-BWsZFzU8.mjs +262 -0
- package/lib/anthropic-CJCauvYz.mjs +3115 -0
- package/lib/anthropic-CMT1Qj1t.mjs +3115 -0
- package/lib/anthropic-CZghe_9U.mjs +3115 -0
- package/lib/anthropic-sCMH7JID.mjs +262 -0
- package/lib/anthropic-tTntD8BD.mjs +262 -0
- package/lib/api-key-login-BzqNdM2y.mjs +157 -0
- package/lib/api-key-login-CWVwvHT1.mjs +157 -0
- package/lib/api-key-login-CpzSezsi.mjs +157 -0
- package/lib/aws-credentials-8Mgn5MAy.mjs +867 -0
- package/lib/aws-credentials-CXryMobh.mjs +867 -0
- package/lib/aws-credentials-ChG79ey-.mjs +867 -0
- package/lib/azure-openai-responses-CNkHiLUh.mjs +274 -0
- package/lib/azure-openai-responses-Cgmc-rbL.mjs +274 -0
- package/lib/azure-openai-responses-DuukbD0F.mjs +274 -0
- package/lib/bun-shim.mjs +252 -12
- package/lib/bundled-references-CSuBco5p.mjs +55 -0
- package/lib/bundled-references-Cavaffah.mjs +55 -0
- package/lib/bundled-references-sLN0YdXU.mjs +55 -0
- package/lib/callback-server-BEFNf-jf.mjs +398 -0
- package/lib/callback-server-CQ5Jo8F-.mjs +398 -0
- package/lib/callback-server-DDSrZ6l_.mjs +398 -0
- package/lib/client.js +111 -41
- package/lib/cursor-B3zg7EHj.mjs +273 -0
- package/lib/cursor-B6TUEmgP.mjs +135 -0
- package/lib/cursor-BIQfBC6V.mjs +135 -0
- package/lib/cursor-D8gvtTL3.mjs +135 -0
- package/lib/cursor-DNk6eXDd.mjs +5470 -0
- package/lib/cursor-DkSX2h3H.mjs +5441 -0
- package/lib/cursor-MjSm74IJ.mjs +273 -0
- package/lib/cursor-aJrXeYCb.mjs +273 -0
- package/lib/cursor-mJQwUKXK.mjs +5441 -0
- package/lib/device-code-DBo3B5nh.mjs +51 -0
- package/lib/device-code-DIb0FU-H.mjs +51 -0
- package/lib/device-code-OI_tQcmc.mjs +51 -0
- package/lib/devin-BHZZyMhO.mjs +95 -0
- package/lib/devin-BK7DHeca.mjs +114 -0
- package/lib/devin-CfMp3cXS.mjs +95 -0
- package/lib/devin-CldyPD8K.mjs +95 -0
- package/lib/devin-CzRpTUOA.mjs +114 -0
- package/lib/devin-D9zR5B_R.mjs +542 -0
- package/lib/devin-DXOeNyU7.mjs +542 -0
- package/lib/devin-Q1yem3lp.mjs +114 -0
- package/lib/devin-vNZTNUON.mjs +542 -0
- package/lib/error-B3bevhrs.mjs +1449 -0
- package/lib/error-Dd8DIqs-.mjs +1449 -0
- package/lib/error-yCSG0mGC.mjs +1449 -0
- package/lib/event-stream-BDPi64mK.mjs +151 -0
- package/lib/event-stream-BbFZJy-z.mjs +151 -0
- package/lib/event-stream-loUa0s1T.mjs +151 -0
- package/lib/fs-promises-shim-Bx0fpxuk.mjs +57 -0
- package/lib/github-copilot-4GaMtQmg.mjs +208 -0
- package/lib/github-copilot-B1yiyVRh.mjs +104 -0
- package/lib/github-copilot-B2HGSIJK.mjs +104 -0
- package/lib/github-copilot-BWT3eAOF.mjs +208 -0
- package/lib/github-copilot-CYkjeTi3.mjs +208 -0
- package/lib/github-copilot-jscUZ8Hf.mjs +104 -0
- package/lib/gitlab-duo-CM7Ref1H.mjs +155 -0
- package/lib/gitlab-duo-akICyfeD.mjs +155 -0
- package/lib/gitlab-duo-gubO4FNw.mjs +155 -0
- package/lib/gitlab-duo-workflow-BGAF6JDw.mjs +91 -0
- package/lib/gitlab-duo-workflow-CSEgYk3N.mjs +91 -0
- package/lib/gitlab-duo-workflow-D78tdn8E.mjs +91 -0
- package/lib/google-BS4T25Pn.mjs +30 -0
- package/lib/google-TFe-7-of.mjs +30 -0
- package/lib/google-antigravity-DGmwC2KV.mjs +198 -0
- package/lib/google-antigravity-DNYhgTpA.mjs +198 -0
- package/lib/google-antigravity-Dlkdhahq.mjs +198 -0
- package/lib/google-auth-B6gjsZvg.mjs +232 -0
- package/lib/google-auth-De7_s3eo.mjs +232 -0
- package/lib/google-auth-DhqpOYrX.mjs +232 -0
- package/lib/google-gemini-cli-BG_LRdIV.mjs +850 -0
- package/lib/google-gemini-cli-CWu8HvXW.mjs +211 -0
- package/lib/google-gemini-cli-Cb97bzQc.mjs +850 -0
- package/lib/google-gemini-cli-Cqds_Q5T.mjs +850 -0
- package/lib/google-gemini-cli-Dsztq0N5.mjs +211 -0
- package/lib/google-gemini-cli-zJhiOcND.mjs +211 -0
- package/lib/google-oauth-shared-CuEHaDDj.mjs +147 -0
- package/lib/google-oauth-shared-CwNWYdmR.mjs +147 -0
- package/lib/google-oauth-shared-yqlyqPPC.mjs +147 -0
- package/lib/google-shared-CgKmmdO3.mjs +760 -0
- package/lib/google-shared-Dr-VG-ap.mjs +760 -0
- package/lib/google-shared-DzhCb9b0.mjs +760 -0
- package/lib/google-vertex-BDN2tLaD.mjs +99 -0
- package/lib/google-vertex-DopVOQOG.mjs +99 -0
- package/lib/google-vertex-kscbkyRb.mjs +99 -0
- package/lib/google-zyDOG9x7.mjs +30 -0
- package/lib/identity-Da1GPU9a.mjs +219 -0
- package/lib/identity-DnB63pS7.mjs +219 -0
- package/lib/identity-xRP7_eSR.mjs +219 -0
- package/lib/idle-iterator-Baoyn3Hp.mjs +366 -0
- package/lib/idle-iterator-C6XbWcuB.mjs +366 -0
- package/lib/idle-iterator-DUjKQEGT.mjs +366 -0
- package/lib/index.mjs +4608 -3935
- package/lib/kimi--wUOWER5.mjs +236 -0
- package/lib/kimi-DMVI-zrZ.mjs +236 -0
- package/lib/kimi-Dh0pv3WZ.mjs +236 -0
- package/lib/markit-BL3cH47U.mjs +1417 -0
- package/lib/markit-BNiNY6SE.mjs +1417 -0
- package/lib/markit-M0jhziqU.mjs +1417 -0
- package/lib/minimax-code-BK-3eBbz.mjs +53 -0
- package/lib/minimax-code-DCbuA6Yk.mjs +53 -0
- package/lib/minimax-code-Uq8Qu9LW.mjs +53 -0
- package/lib/models-CfT4coYT.mjs +104660 -0
- package/lib/models-D_XnT6ay.mjs +104660 -0
- package/lib/models-SGASygJ3.mjs +104660 -0
- package/lib/ollama-BQMGPxtV.mjs +589 -0
- package/lib/ollama-DPzBmq89.mjs +589 -0
- package/lib/ollama-DoBz5SFm.mjs +589 -0
- package/lib/openai-codex-Bi-4S4PX.mjs +255 -0
- package/lib/openai-codex-CQL_kvYL.mjs +255 -0
- package/lib/openai-codex-Ch8CkT3p.mjs +255 -0
- package/lib/openai-codex-responses-CvxL_FMF.mjs +3144 -0
- package/lib/openai-codex-responses-Cz-2qpC7.mjs +3144 -0
- package/lib/openai-codex-responses-pejZgdZo.mjs +3144 -0
- package/lib/openai-completions-CF8IyNtP.mjs +1360 -0
- package/lib/openai-completions-DIf361kF.mjs +1360 -0
- package/lib/openai-completions-i8doczAk.mjs +1360 -0
- package/lib/openai-reasoning-fallback-DGVVLgd1.mjs +286 -0
- package/lib/openai-reasoning-fallback-Nj6yB2rY.mjs +286 -0
- package/lib/openai-reasoning-fallback-OdJREP1o.mjs +286 -0
- package/lib/openai-responses-BqXJInHX.mjs +867 -0
- package/lib/openai-responses-DTkBiiy-.mjs +867 -0
- package/lib/openai-responses-Db_a-U4-.mjs +867 -0
- package/lib/opencode-DaJjcUbf.mjs +38 -0
- package/lib/opencode-DhMolSoB.mjs +38 -0
- package/lib/opencode-Rq_Q2vAO.mjs +38 -0
- package/lib/perplexity-9b-RQ0mV.mjs +194 -0
- package/lib/perplexity-C4iLVMUj.mjs +194 -0
- package/lib/perplexity-Uu7Jzg5b.mjs +194 -0
- package/lib/proxy-DDqrmjjC.mjs +190 -0
- package/lib/proxy-ZtUcl6r5.mjs +190 -0
- package/lib/proxy-pM_NIv-H.mjs +190 -0
- package/lib/request-debug-HJMoJncL.mjs +183 -0
- package/lib/sanitize-text-CfcXzw5X.mjs +33 -0
- package/lib/scrapers-BkFfcPHj.mjs +9198 -0
- package/lib/scrapers-CL-WgdU1.mjs +9198 -0
- package/lib/scrapers-CVptboMs.mjs +9198 -0
- package/lib/scrapers-CipyKyCH.mjs +9198 -0
- package/lib/scrapers-DGfrYhtw.mjs +9198 -0
- package/lib/scrapers-DSUPYoUF.mjs +9198 -0
- package/lib/scrapers-DZ2GXmp7.mjs +9198 -0
- package/lib/scrapers-nhQAvc8d.mjs +9198 -0
- package/lib/shell-snapshot-fn-env.sh +67 -43
- package/lib/src-BgpusnsB.mjs +5076 -0
- package/lib/src-DTid0g4K.mjs +5001 -0
- package/lib/src-lDmkSRbm.mjs +5006 -0
- package/lib/stream-BlldLkVq.mjs +10236 -0
- package/lib/stream-CRtexYLe.mjs +10236 -0
- package/lib/stream-C_RAoxJC.mjs +10236 -0
- package/lib/stream-markup-healing-2toHXWXM.mjs +491 -0
- package/lib/stream-markup-healing-DMsxBx1L.mjs +491 -0
- package/lib/stream-markup-healing-KMkiAA00.mjs +491 -0
- package/lib/turndown-DN7ByzEI.mjs +667 -0
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/config/fields.d.ts +1 -1
- package/lib/types/config/settings.d.ts +25 -3
- package/lib/types/config/truncate.d.ts +9 -5
- package/lib/types/tools/bash/background.d.ts +1 -1
- package/lib/types/tools/bash/bash-executor.d.ts +4 -0
- package/lib/types/tools/bash/bash-interceptor.d.ts +10 -8
- package/lib/types/tools/bash/cd-workdir.d.ts +35 -0
- package/lib/types/tools/bash/non-interactive-env.d.ts +2 -0
- package/lib/types/tools/bash/render.d.ts +4 -3
- package/lib/types/tools/bash/sanitize-text.d.ts +5 -0
- package/lib/types/tools/bash/shell-snapshot.d.ts +4 -1
- package/lib/types/tools/bash/shell-tokenize.d.ts +60 -0
- package/lib/types/tools/bash/streaming-output.d.ts +12 -212
- package/lib/types/tools/bash/which.d.ts +20 -0
- package/lib/types/tools/bash/windows-shell.d.ts +31 -0
- package/lib/types/tools/edit/adapter/index.d.ts +25 -3
- package/lib/types/tools/edit/adapter/tools/auto-generated-guard.d.ts +7 -17
- package/lib/types/tools/glob/adapter/index.d.ts +27 -1
- package/lib/types/tools/grep/adapter/index.d.ts +29 -1
- package/lib/types/tools/omp/edit/dispatch.d.ts +43 -0
- package/lib/types/tools/omp/edit/hashline/noop-loop-guard.d.ts +3 -1
- package/lib/types/tools/omp/sdk.d.ts +6 -0
- package/lib/types/tools/omp/tools/auto-generated-guard.d.ts +20 -0
- package/lib/types/tools/omp/tools/fetch.d.ts +2 -0
- package/lib/types/tools/omp/tools/read.d.ts +2 -8
- package/lib/types/tools/omp/tools/write.d.ts +4 -4
- package/lib/types/tools/omp/utils/image-loading.d.ts +10 -36
- package/lib/types/tools/read/adapter/index.d.ts +4 -1
- package/lib/types/tools/read-image/index.d.ts +4 -0
- package/lib/types/tools/shared/auto-generated-guard.dsh.d.ts +16 -4
- package/lib/types/tools/shared/bun-shim.d.ts +39 -3
- package/lib/types/tools/shared/fs-promises-shim.d.ts +3 -1
- package/lib/types/tools/shared/image-bridge.d.ts +98 -0
- package/lib/types/tools/shared/omp-prompt.d.ts +17 -9
- package/lib/types/tools/shared/session-state.d.ts +9 -3
- package/lib/utils-2Wq2eATG.mjs +8119 -0
- package/lib/utils-BnX8O3vi.mjs +12303 -0
- package/lib/utils-Bw139LTz.mjs +8119 -0
- package/lib/utils-CE8N8P4Q.mjs +12315 -0
- package/lib/utils-CZw4tVZQ.mjs +12315 -0
- package/lib/utils-C_MrQ_0z.mjs +12301 -0
- package/lib/utils-CiGN7OHR.mjs +12315 -0
- package/lib/utils-Cp76gCyk.mjs +8119 -0
- package/lib/utils-D0GRDgAr.mjs +12315 -0
- package/lib/utils-D0Z1fyoO.mjs +12299 -0
- package/lib/utils-D2YknRk4.mjs +51 -0
- package/lib/utils-DppGHXQB.mjs +51 -0
- package/lib/utils-DzXZDfYc.mjs +51 -0
- package/lib/utils-W8WdSBpX.mjs +12315 -0
- package/lib/vision-guard-01qSwFpf.mjs +92 -0
- package/lib/vision-guard-BDD4OrKo.mjs +92 -0
- package/lib/vision-guard-DzZGaOga.mjs +92 -0
- package/lib/wafer-CgtPHerf.mjs +17 -0
- package/lib/wafer-DRU0EjZX.mjs +17 -0
- package/lib/wafer-cBtrn6q9.mjs +17 -0
- package/lib/xai-oauth-Buk8XVvM.mjs +446 -0
- package/lib/xai-oauth-CMal8l1O.mjs +446 -0
- package/lib/xai-oauth-DPHDXKD7.mjs +446 -0
- package/lib/xiaomi-CZgwvX2G.mjs +157 -0
- package/lib/xiaomi-D2qT5cAC.mjs +157 -0
- package/lib/xiaomi-Dd87KSg5.mjs +157 -0
- package/lib/zai-7DWMkEqM.mjs +203 -0
- package/lib/zai-C59YnomG.mjs +203 -0
- package/lib/zai-CFeOt-53.mjs +203 -0
- package/lib/zip-Cg9ANN_U.mjs +1316 -0
- package/lib/zip-D36ZKsP8.mjs +1316 -0
- package/lib/zip-D6QXpvaJ.mjs +1316 -0
- package/package.json +14 -10
- package/presets/package.json +1 -1
- package/presets/tool-plus-ptc/preset.yml +1 -1
- package/presets/tool-plus-standard/preset.yml +1 -1
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { installBunShim as __installBunShim } from "./bun-shim.mjs";
|
|
2
|
+
__installBunShim();
|
|
3
|
+
import { c as OAuthError, h as LoginCancelledError, t as ConfigurationError } from "./error-yCSG0mGC.mjs";
|
|
4
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/registry/oauth/oauth.html
|
|
5
|
+
var oauth_default = "<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n <title>oh my pi · authentication</title>\n <style>\n :root {\n /* dark, slightly purple-tinted neutrals — never #000 */\n --ink-0: oklch(0.135 0.018 295);\n --ink-1: oklch(0.172 0.022 295);\n --ink-2: oklch(0.21 0.024 295);\n --ink-4: oklch(0.36 0.024 295);\n --ink-5: oklch(0.5 0.022 290);\n --ink-6: oklch(0.66 0.018 290);\n --ink-7: oklch(0.82 0.014 285);\n --ink-9: oklch(0.97 0.008 90);\n\n /* brand: magenta lead, cyan reply */\n --magenta: oklch(0.7 0.24 340);\n --iris: oklch(0.62 0.21 295);\n --cyan: oklch(0.81 0.14 200);\n\n /* signal */\n --success: oklch(0.78 0.16 150);\n --error: oklch(0.66 0.22 25);\n\n --bg: var(--ink-0);\n --fg: var(--ink-9);\n --fg-dim: var(--ink-7);\n --fg-faint: var(--ink-5);\n --rule: oklch(1 0 0 / 0.07);\n --rule-strong: oklch(1 0 0 / 0.14);\n --accent: var(--magenta);\n --accent-2: var(--cyan);\n\n color-scheme: dark;\n }\n\n * {\n box-sizing: border-box;\n }\n\n body {\n font-family: \"Geist\", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n background:\n radial-gradient(ellipse 80vw 60vh at 18% -10%, oklch(0.7 0.24 340 / 0.13), transparent 60%),\n radial-gradient(ellipse 70vw 70vh at 110% 30%, oklch(0.81 0.14 200 / 0.09), transparent 60%),\n var(--bg);\n color: var(--fg);\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n margin: 0;\n padding: 1.5rem;\n -webkit-font-smoothing: antialiased;\n text-rendering: optimizeLegibility;\n overflow-x: clip;\n }\n\n /* ascii grid backdrop */\n .grid-bg {\n position: fixed;\n inset: 0;\n background-image:\n linear-gradient(to right, oklch(1 0 0 / 0.025) 1px, transparent 1px),\n linear-gradient(to bottom, oklch(1 0 0 / 0.025) 1px, transparent 1px);\n background-size: 56px 56px;\n background-position: -1px -1px;\n mask-image: radial-gradient(ellipse at 50% 30%, #000 30%, transparent 75%);\n pointer-events: none;\n z-index: 0;\n }\n\n .container {\n position: relative;\n z-index: 1;\n background: oklch(0.172 0.022 295 / 0.72);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n border: 1px solid var(--rule);\n border-radius: 16px;\n padding: 2.5rem 2.5rem 2rem;\n width: 100%;\n max-width: 420px;\n text-align: center;\n box-shadow:\n 0 24px 48px -12px oklch(0 0 0 / 0.55),\n 0 0 0 1px oklch(1 0 0 / 0.03) inset;\n opacity: 0;\n transform: translateY(10px);\n animation: rise 0.6s cubic-bezier(0.16, 1, 0.3, 1) forwards;\n }\n @keyframes rise {\n to {\n opacity: 1;\n transform: none;\n }\n }\n\n /* brand header */\n .brand {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n margin-bottom: 2rem;\n }\n .brand svg {\n width: 22px;\n height: 22px;\n }\n .brand .wordmark {\n font-size: 13px;\n font-weight: 500;\n letter-spacing: -0.01em;\n color: var(--fg);\n }\n\n /* status mark */\n .mark-wrap {\n position: relative;\n width: 72px;\n height: 72px;\n margin: 0 auto 1.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .mark-wrap::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: 50%;\n background: oklch(1 0 0 / 0.05);\n z-index: 0;\n }\n .mark {\n width: 40px;\n height: 40px;\n z-index: 2;\n }\n .timer-svg {\n position: absolute;\n top: -2px;\n left: -2px;\n width: 76px;\n height: 76px;\n transform: rotate(-90deg);\n z-index: 1;\n pointer-events: none;\n }\n .timer-circle {\n fill: none;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-dasharray: 226;\n stroke-dashoffset: 0;\n }\n .countdown .timer-circle {\n animation: countdown 3s linear forwards;\n }\n @keyframes countdown {\n to {\n stroke-dashoffset: 226;\n }\n }\n\n h1 {\n font-family: \"Fraunces\", \"Iowan Old Style\", Georgia, serif;\n font-size: 1.6rem;\n font-weight: 500;\n letter-spacing: -0.022em;\n line-height: 1.15;\n margin: 0 0 0.75rem;\n text-wrap: balance;\n }\n p {\n color: var(--fg-dim);\n line-height: 1.6;\n margin: 0 0 1.75rem;\n font-size: 0.95rem;\n }\n\n .btn {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n background: var(--fg);\n color: var(--bg);\n font-family: inherit;\n font-weight: 500;\n padding: 0.65rem 1.4rem;\n border-radius: 8px;\n text-decoration: none;\n font-size: 0.9rem;\n transition: opacity 0.2s, transform 0.2s;\n cursor: pointer;\n border: none;\n }\n .btn:hover {\n opacity: 0.88;\n transform: translateY(-1px);\n }\n .btn:active {\n transform: translateY(0);\n }\n\n /* State: success */\n .success .mark-wrap::before {\n background: oklch(0.78 0.16 150 / 0.12);\n }\n .success .mark {\n color: var(--success);\n }\n .success .timer-circle {\n stroke: var(--success);\n }\n .success .icon-error {\n display: none;\n }\n\n /* State: error */\n .error .mark-wrap::before {\n background: oklch(0.66 0.22 25 / 0.12);\n }\n .error .mark {\n color: var(--error);\n }\n .error .timer-circle {\n stroke: var(--error);\n }\n .error .icon-success,\n .error .timer-svg {\n display: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .container,\n .countdown .timer-circle {\n animation: none;\n }\n .container {\n opacity: 1;\n transform: none;\n }\n }\n </style>\n </head>\n <body>\n <span aria-hidden=\"true\" class=\"grid-bg\"></span>\n <div id=\"app\" class=\"container\">\n <div class=\"brand\">\n <svg viewBox=\"0 0 64 64\" aria-hidden=\"true\">\n <defs>\n <linearGradient id=\"pi-grad\" x1=\"0\" y1=\"0\" x2=\"1\" y2=\"1\">\n <stop offset=\"0\" stop-color=\"oklch(0.7 0.24 340)\" />\n <stop offset=\".5\" stop-color=\"oklch(0.62 0.21 295)\" />\n <stop offset=\"1\" stop-color=\"oklch(0.81 0.14 200)\" />\n </linearGradient>\n </defs>\n <path fill=\"url(#pi-grad)\" d=\"M10 14h44v9H43v33h-9V23h-9v22h-9V23H10z\" />\n </svg>\n <span class=\"wordmark\">oh my pi</span>\n </div>\n\n <div class=\"mark-wrap\">\n <svg class=\"timer-svg\" viewBox=\"0 0 76 76\">\n <circle class=\"timer-circle\" cx=\"38\" cy=\"38\" r=\"36\"></circle>\n </svg>\n <svg class=\"mark icon-success\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n <svg class=\"mark icon-error\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </div>\n\n <h1 id=\"title\">Authentication</h1>\n <p id=\"message\"></p>\n <button onclick=\"window.close()\" class=\"btn\">Close Window</button>\n </div>\n\n <script id=\"server-state\" type=\"application/json\">\n __OAUTH_STATE__\n <\/script>\n\n <script>\n let serverState;\n try {\n serverState = JSON.parse(document.getElementById(\"server-state\").textContent);\n } catch {\n const params = new URLSearchParams(window.location.search);\n serverState = {\n ok: params.get(\"ok\") === \"1\",\n error: params.get(\"error\") || \"Authentication failed\",\n };\n }\n\n const app = document.getElementById(\"app\");\n const title = document.getElementById(\"title\");\n const message = document.getElementById(\"message\");\n\n if (serverState.ok) {\n app.classList.add(\"success\", \"countdown\");\n title.textContent = \"Authentication Successful\";\n message.innerHTML = \"You have successfully logged in.<br>You can now close this tab.\";\n setTimeout(() => window.close(), 3000);\n } else {\n app.classList.add(\"error\");\n title.textContent = \"Authentication Failed\";\n message.textContent = serverState.error || \"An error occurred\";\n }\n <\/script>\n </body>\n</html>\n";
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/registry/oauth/callback-server.ts
|
|
8
|
+
/**
|
|
9
|
+
* Abstract base class for OAuth flows with local callback servers.
|
|
10
|
+
*
|
|
11
|
+
* Handles:
|
|
12
|
+
* - Port allocation (tries expected port, falls back to random)
|
|
13
|
+
* - Callback server setup and request handling
|
|
14
|
+
* - Common OAuth flow logic
|
|
15
|
+
*
|
|
16
|
+
* Providers extend this and implement:
|
|
17
|
+
* - generateAuthUrl(): Build provider-specific authorization URL
|
|
18
|
+
* - exchangeToken(): Exchange authorization code for tokens
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_TIMEOUT = 3e5;
|
|
21
|
+
const DEFAULT_HOSTNAME = "localhost";
|
|
22
|
+
const CALLBACK_PATH = "/callback";
|
|
23
|
+
const IPV4_LOOPBACK = "127.0.0.1";
|
|
24
|
+
const IPV6_LOOPBACK = "::1";
|
|
25
|
+
/**
|
|
26
|
+
* How many times a random-port bind may be redrawn when the ephemeral port it
|
|
27
|
+
* landed on is already held on {@link IPV6_LOOPBACK} by that exact address.
|
|
28
|
+
* Small on purpose: each redraw picks a fresh port, so a repeat collision is
|
|
29
|
+
* vanishingly unlikely.
|
|
30
|
+
*/
|
|
31
|
+
const IPV6_COMPANION_ATTEMPTS = 4;
|
|
32
|
+
/**
|
|
33
|
+
* Path served by {@link OAuthCallbackFlow} that 302-redirects to the pending
|
|
34
|
+
* authorization URL. Kept out of {@link OAuthCallbackFlowOptions} because it
|
|
35
|
+
* lives on the loopback callback server alongside {@link CALLBACK_PATH} and
|
|
36
|
+
* must never clash with a provider-registered redirect URI (all known
|
|
37
|
+
* providers register `/callback`-shaped paths).
|
|
38
|
+
*/
|
|
39
|
+
const LAUNCH_PATH = "/launch";
|
|
40
|
+
/**
|
|
41
|
+
* Whether a failed bind means "another process already holds this port".
|
|
42
|
+
* Bun surfaces `EADDRINUSE` on the error's `code` where the platform reports
|
|
43
|
+
* it, and otherwise only in the message, so both are checked.
|
|
44
|
+
*/
|
|
45
|
+
function isAddressInUse(error) {
|
|
46
|
+
const code = error?.code;
|
|
47
|
+
if (typeof code === "string") return code === "EADDRINUSE";
|
|
48
|
+
return error instanceof Error && /EADDRINUSE|in use/i.test(error.message);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Abstract base class for OAuth flows with local callback servers.
|
|
52
|
+
*/
|
|
53
|
+
var OAuthCallbackFlow = class {
|
|
54
|
+
ctrl;
|
|
55
|
+
preferredPort;
|
|
56
|
+
callbackPath;
|
|
57
|
+
callbackHostname;
|
|
58
|
+
redirectUri;
|
|
59
|
+
allowPortFallback;
|
|
60
|
+
#manualInputOnly;
|
|
61
|
+
#callbackResolve;
|
|
62
|
+
#callbackReject;
|
|
63
|
+
/**
|
|
64
|
+
* Authorization URL the `/launch` route currently redirects to. Set by
|
|
65
|
+
* {@link login} after {@link generateAuthUrl} and before {@link OAuthController.onAuth}
|
|
66
|
+
* fires, cleared when the server stops. `undefined` before the flow reaches
|
|
67
|
+
* that point and after it finishes, so `/launch` returns 503 rather than
|
|
68
|
+
* a stale URL.
|
|
69
|
+
*/
|
|
70
|
+
#pendingAuthUrl;
|
|
71
|
+
constructor(ctrl, preferredPortOrOptions, callbackPath = CALLBACK_PATH) {
|
|
72
|
+
this.ctrl = ctrl;
|
|
73
|
+
if (typeof preferredPortOrOptions === "number") {
|
|
74
|
+
this.preferredPort = preferredPortOrOptions;
|
|
75
|
+
this.callbackPath = callbackPath;
|
|
76
|
+
this.callbackHostname = DEFAULT_HOSTNAME;
|
|
77
|
+
this.allowPortFallback = true;
|
|
78
|
+
this.#manualInputOnly = false;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.preferredPort = preferredPortOrOptions.preferredPort;
|
|
82
|
+
this.callbackPath = preferredPortOrOptions.callbackPath ?? CALLBACK_PATH;
|
|
83
|
+
this.callbackHostname = preferredPortOrOptions.callbackHostname ?? DEFAULT_HOSTNAME;
|
|
84
|
+
this.redirectUri = preferredPortOrOptions.redirectUri;
|
|
85
|
+
this.allowPortFallback = preferredPortOrOptions.allowPortFallback ?? true;
|
|
86
|
+
this.#manualInputOnly = preferredPortOrOptions.manualInputOnly ?? false;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Generate CSRF state token. Override if provider needs custom state generation.
|
|
90
|
+
*/
|
|
91
|
+
generateState() {
|
|
92
|
+
const bytes = /* @__PURE__ */ new Uint8Array(16);
|
|
93
|
+
crypto.getRandomValues(bytes);
|
|
94
|
+
return Array.from(bytes).map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
95
|
+
}
|
|
96
|
+
#loginCancelledError() {
|
|
97
|
+
return new LoginCancelledError(`OAuth callback cancelled: ${this.ctrl.signal?.reason}`);
|
|
98
|
+
}
|
|
99
|
+
#throwIfCancelled() {
|
|
100
|
+
if (this.ctrl.signal?.aborted) throw this.#loginCancelledError();
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Execute the OAuth login flow.
|
|
104
|
+
*/
|
|
105
|
+
async login() {
|
|
106
|
+
const state = this.generateState();
|
|
107
|
+
this.#throwIfCancelled();
|
|
108
|
+
const { server, redirectUri, launchUrl } = this.#manualInputOnly ? {
|
|
109
|
+
server: void 0,
|
|
110
|
+
redirectUri: this.#buildRedirectUri(),
|
|
111
|
+
launchUrl: void 0
|
|
112
|
+
} : await this.#startCallbackServer(state);
|
|
113
|
+
try {
|
|
114
|
+
this.#throwIfCancelled();
|
|
115
|
+
const { url: authUrl, instructions } = await this.generateAuthUrl(state, redirectUri);
|
|
116
|
+
this.#throwIfCancelled();
|
|
117
|
+
this.#pendingAuthUrl = authUrl;
|
|
118
|
+
this.ctrl.onAuth?.({
|
|
119
|
+
url: authUrl,
|
|
120
|
+
launchUrl,
|
|
121
|
+
instructions
|
|
122
|
+
});
|
|
123
|
+
this.ctrl.onProgress?.(this.#manualInputOnly ? "Waiting for pasted authorization code..." : "Waiting for browser authentication...");
|
|
124
|
+
const { code } = await this.#waitForCallback(state);
|
|
125
|
+
this.#throwIfCancelled();
|
|
126
|
+
this.ctrl.onProgress?.("Exchanging authorization code for tokens...");
|
|
127
|
+
return await this.exchangeToken(code, state, redirectUri);
|
|
128
|
+
} finally {
|
|
129
|
+
this.#pendingAuthUrl = void 0;
|
|
130
|
+
server?.stop();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
#buildRedirectUri() {
|
|
134
|
+
return this.redirectUri ?? `http://${this.callbackHostname}:${this.preferredPort}${this.callbackPath}`;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Start callback server, trying preferred port first, falling back to random.
|
|
138
|
+
* `launchUrl` is `undefined` when the caller configured `callbackPath` to
|
|
139
|
+
* collide with {@link LAUNCH_PATH} — the callback handler resolves the real
|
|
140
|
+
* callback in that case, so advertising a self-redirecting URL would be
|
|
141
|
+
* incorrect.
|
|
142
|
+
*/
|
|
143
|
+
async #startCallbackServer(expectedState) {
|
|
144
|
+
try {
|
|
145
|
+
const server = this.#createServer(this.preferredPort, expectedState);
|
|
146
|
+
const actualPort = this.#resolveServerPort(server);
|
|
147
|
+
const launchUrl = this.#launchUrlIfSafe(actualPort);
|
|
148
|
+
if (this.redirectUri) return {
|
|
149
|
+
server,
|
|
150
|
+
redirectUri: this.redirectUri,
|
|
151
|
+
launchUrl
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
server,
|
|
155
|
+
redirectUri: `http://${this.callbackHostname}:${actualPort}${this.callbackPath}`,
|
|
156
|
+
launchUrl
|
|
157
|
+
};
|
|
158
|
+
} catch (cause) {
|
|
159
|
+
if (this.redirectUri) throw new ConfigurationError(`OAuth callback port ${this.preferredPort} is in use, but oauth.redirectUri (${this.redirectUri}) requires this exact port. Free port ${this.preferredPort} (e.g. stop the process bound to it) and retry, or change oauth.redirectUri to point at an available port.`, { cause });
|
|
160
|
+
if (!this.allowPortFallback) throw new ConfigurationError(`OAuth callback port ${this.preferredPort} is in use. The OAuth provider validates redirect URIs against its registered callback, so falling back to a random port would be rejected. Free port ${this.preferredPort} (e.g. stop the process bound to it) and retry, or set oauth.callbackPort/oauth.redirectUri to a port the provider has registered.`, { cause });
|
|
161
|
+
const server = this.#createServer(0, expectedState);
|
|
162
|
+
const actualPort = this.#resolveServerPort(server);
|
|
163
|
+
const redirectUri = `http://${this.callbackHostname}:${actualPort}${this.callbackPath}`;
|
|
164
|
+
const launchUrl = this.#launchUrlIfSafe(actualPort);
|
|
165
|
+
this.ctrl.onProgress?.(`Preferred port ${this.preferredPort} unavailable, using port ${actualPort}`);
|
|
166
|
+
return {
|
|
167
|
+
server,
|
|
168
|
+
redirectUri,
|
|
169
|
+
launchUrl
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Read the numeric port a callback server bound to. `Bun.Server.port` is
|
|
175
|
+
* declared `number | undefined` because Unix-socket servers have no port,
|
|
176
|
+
* but every callback flow uses TCP; a missing port here indicates a
|
|
177
|
+
* configuration error rather than a fallback case.
|
|
178
|
+
*/
|
|
179
|
+
#resolveServerPort(server) {
|
|
180
|
+
const port = server.port;
|
|
181
|
+
if (typeof port !== "number") throw new ConfigurationError("OAuth callback server bound to a non-TCP endpoint; expected a numeric port. Check `oauth.callbackPort`/`oauth.redirectUri`.");
|
|
182
|
+
return port;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Build the `/launch` URL served by the callback server bound to `port`, or
|
|
186
|
+
* `undefined` when it must not be advertised:
|
|
187
|
+
* - the configured `callbackPath` (or a `redirectUri` whose pathname
|
|
188
|
+
* resolves to {@link LAUNCH_PATH}) would collide with the launch route;
|
|
189
|
+
* - the flow's `redirectUri` never returns to this loopback server: fixed
|
|
190
|
+
* non-loopback hosts, or custom schemes like GitLab Duo's `vscode://`
|
|
191
|
+
* URI — which `new URL` parses without complaint, so a scheme/host check
|
|
192
|
+
* is required, not just the parse failure path. Advertising a localhost
|
|
193
|
+
* `/launch` target for such flows misrepresents the callback endpoint
|
|
194
|
+
* and hands remote users a URL that resolves nowhere.
|
|
195
|
+
* Kept short (~30 chars) so UIs can advertise it as a
|
|
196
|
+
* viewport-truncation-safe copy target for the full authorization URL.
|
|
197
|
+
*/
|
|
198
|
+
#launchUrlIfSafe(port) {
|
|
199
|
+
if (this.callbackPath === LAUNCH_PATH) return void 0;
|
|
200
|
+
if (this.redirectUri) try {
|
|
201
|
+
const parsed = new URL(this.redirectUri);
|
|
202
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
|
|
203
|
+
if (parsed.hostname !== "localhost" && parsed.hostname !== "127.0.0.1" && parsed.hostname !== "[::1]") return;
|
|
204
|
+
if (parsed.pathname === LAUNCH_PATH) return void 0;
|
|
205
|
+
} catch {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
return `http://${this.callbackHostname}:${port}${LAUNCH_PATH}`;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Create the HTTP listener(s) for the OAuth callback.
|
|
212
|
+
*
|
|
213
|
+
* `localhost` is not a single endpoint: it resolves to both
|
|
214
|
+
* {@link IPV4_LOOPBACK} and {@link IPV6_LOOPBACK}, and clients commonly try
|
|
215
|
+
* `::1` first. Binding only the IPv4 literal hands the authorization code to
|
|
216
|
+
* whatever holds the IPv6 loopback on the same port — a dev server on
|
|
217
|
+
* `*:3000` is the common case — which answers from its own routes while this
|
|
218
|
+
* flow waits out the full {@link DEFAULT_TIMEOUT}. Nothing detects it either:
|
|
219
|
+
* a specific-address bind coexists with another process's wildcard bind, so
|
|
220
|
+
* `Bun.serve` reports the port as free and the random-port fallback in
|
|
221
|
+
* {@link #startCallbackServer} never runs.
|
|
222
|
+
*
|
|
223
|
+
* Binding both loopback literals fixes the delivery rather than dodging it:
|
|
224
|
+
* the kernel routes a connection to the most specific matching bind, so our
|
|
225
|
+
* `::1` listener receives `localhost` traffic that would otherwise reach a
|
|
226
|
+
* process bound to the `::` wildcard. Both listeners answer the same routes,
|
|
227
|
+
* so which family the client resolves stops mattering.
|
|
228
|
+
*
|
|
229
|
+
* A genuine collision — another process on exactly this loopback address and
|
|
230
|
+
* port — still raises EADDRINUSE and reaches the caller's in-use policy. A
|
|
231
|
+
* host that cannot bind `::1` at all (IPv6 disabled, address unavailable) is
|
|
232
|
+
* not a collision: the IPv4 listener is the only reachable endpoint there, so
|
|
233
|
+
* it serves alone.
|
|
234
|
+
*/
|
|
235
|
+
#createServer(port, expectedState) {
|
|
236
|
+
if (this.callbackHostname !== DEFAULT_HOSTNAME) return this.#serve(this.callbackHostname, port, expectedState);
|
|
237
|
+
for (let attempt = 0;; attempt++) {
|
|
238
|
+
const primary = this.#serve(IPV4_LOOPBACK, port, expectedState);
|
|
239
|
+
const boundPort = primary.port;
|
|
240
|
+
if (typeof boundPort !== "number") return primary;
|
|
241
|
+
let companion;
|
|
242
|
+
try {
|
|
243
|
+
companion = this.#serve(IPV6_LOOPBACK, boundPort, expectedState);
|
|
244
|
+
} catch (cause) {
|
|
245
|
+
if (!isAddressInUse(cause)) return primary;
|
|
246
|
+
primary.stop(true);
|
|
247
|
+
if (port !== 0 || attempt >= IPV6_COMPANION_ATTEMPTS) throw cause;
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
get port() {
|
|
252
|
+
return primary.port;
|
|
253
|
+
},
|
|
254
|
+
stop: (closeActiveConnections) => {
|
|
255
|
+
companion.stop(closeActiveConnections);
|
|
256
|
+
return primary.stop(closeActiveConnections);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/** Bind one loopback listener serving the callback and launch routes. */
|
|
262
|
+
#serve(hostname, port, expectedState) {
|
|
263
|
+
return Bun.serve({
|
|
264
|
+
hostname,
|
|
265
|
+
port,
|
|
266
|
+
reusePort: false,
|
|
267
|
+
fetch: (req) => this.#handleCallback(req, expectedState)
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Handle OAuth callback HTTP request. Two routes on the same loopback server:
|
|
272
|
+
* - `callbackPath` (default `/callback`) — the provider redirect target.
|
|
273
|
+
* - {@link LAUNCH_PATH} (`/launch`) — 302 to the pending authorization URL so
|
|
274
|
+
* viewport-safe copy targets can survive TUI truncation.
|
|
275
|
+
*
|
|
276
|
+
* `callbackPath` wins any collision: an OMP config that pins the provider
|
|
277
|
+
* redirect at `/launch` (via `oauth.callbackPath` or a loopback
|
|
278
|
+
* `oauth.redirectUri`) must resolve the callback normally rather than
|
|
279
|
+
* self-redirect. `#startCallbackServer` also suppresses `launchUrl` in that
|
|
280
|
+
* case, so the launch route is never advertised when it would collide.
|
|
281
|
+
*/
|
|
282
|
+
#handleCallback(req, expectedState) {
|
|
283
|
+
const url = new URL(req.url);
|
|
284
|
+
if (url.pathname !== this.callbackPath) {
|
|
285
|
+
if (url.pathname === LAUNCH_PATH) {
|
|
286
|
+
const pending = this.#pendingAuthUrl;
|
|
287
|
+
if (!pending) return new Response("OAuth launch URL is no longer active", { status: 503 });
|
|
288
|
+
return Response.redirect(pending, 302);
|
|
289
|
+
}
|
|
290
|
+
return new Response("Not Found", { status: 404 });
|
|
291
|
+
}
|
|
292
|
+
const code = url.searchParams.get("code");
|
|
293
|
+
const state = url.searchParams.get("state") || "";
|
|
294
|
+
const error = url.searchParams.get("error") || "";
|
|
295
|
+
const errorDescription = url.searchParams.get("error_description") || error;
|
|
296
|
+
let resultState;
|
|
297
|
+
if (error) resultState = {
|
|
298
|
+
ok: false,
|
|
299
|
+
error: `Authorization failed: ${errorDescription}`
|
|
300
|
+
};
|
|
301
|
+
else if (!code) resultState = {
|
|
302
|
+
ok: false,
|
|
303
|
+
error: "Missing authorization code"
|
|
304
|
+
};
|
|
305
|
+
else if (expectedState && state !== expectedState) resultState = {
|
|
306
|
+
ok: false,
|
|
307
|
+
error: "State mismatch - possible CSRF attack"
|
|
308
|
+
};
|
|
309
|
+
else resultState = {
|
|
310
|
+
ok: true,
|
|
311
|
+
code,
|
|
312
|
+
state
|
|
313
|
+
};
|
|
314
|
+
if (resultState.ok) {
|
|
315
|
+
const resolve = this.#callbackResolve;
|
|
316
|
+
queueMicrotask(() => {
|
|
317
|
+
resolve?.({
|
|
318
|
+
code: resultState.code,
|
|
319
|
+
state: resultState.state
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
} else if (error && (!expectedState || state === expectedState)) {
|
|
323
|
+
const reject = this.#callbackReject;
|
|
324
|
+
const message = resultState.error ?? `Authorization failed: ${errorDescription}`;
|
|
325
|
+
queueMicrotask(() => {
|
|
326
|
+
reject?.(new OAuthError(message, { kind: "device-auth" }));
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
return new Response(oauth_default.replaceAll("__OAUTH_STATE__", JSON.stringify(resultState)), {
|
|
330
|
+
status: resultState.ok ? 200 : 500,
|
|
331
|
+
headers: { "Content-Type": "text/html" }
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Wait for OAuth callback or manual input (whichever comes first).
|
|
336
|
+
*/
|
|
337
|
+
#waitForCallback(expectedState) {
|
|
338
|
+
const timeoutSignal = AbortSignal.timeout(DEFAULT_TIMEOUT);
|
|
339
|
+
const signal = this.ctrl.signal ? AbortSignal.any([this.ctrl.signal, timeoutSignal]) : timeoutSignal;
|
|
340
|
+
if (signal.aborted) return Promise.reject(this.#loginCancelledError());
|
|
341
|
+
const callback = Promise.withResolvers();
|
|
342
|
+
this.#callbackResolve = callback.resolve;
|
|
343
|
+
this.#callbackReject = callback.reject;
|
|
344
|
+
signal.addEventListener("abort", () => {
|
|
345
|
+
this.#callbackResolve = void 0;
|
|
346
|
+
this.#callbackReject = void 0;
|
|
347
|
+
callback.reject(new LoginCancelledError(`OAuth callback cancelled: ${signal.reason}`));
|
|
348
|
+
});
|
|
349
|
+
const callbackPromise = callback.promise;
|
|
350
|
+
if (this.ctrl.onManualCodeInput) {
|
|
351
|
+
const requestManualInput = this.ctrl.onManualCodeInput;
|
|
352
|
+
const manualPromise = (async () => {
|
|
353
|
+
while (true) {
|
|
354
|
+
const result = await Promise.race([callbackPromise, requestManualInput().then((input) => {
|
|
355
|
+
const parsed = parseCallbackInput(input);
|
|
356
|
+
if (!parsed.code) return null;
|
|
357
|
+
if (expectedState && parsed.state && parsed.state !== expectedState) return null;
|
|
358
|
+
return {
|
|
359
|
+
code: parsed.code,
|
|
360
|
+
state: parsed.state ?? ""
|
|
361
|
+
};
|
|
362
|
+
}).catch(() => null)]);
|
|
363
|
+
if (result) return result;
|
|
364
|
+
}
|
|
365
|
+
})();
|
|
366
|
+
return Promise.race([callbackPromise, manualPromise]);
|
|
367
|
+
}
|
|
368
|
+
return callbackPromise;
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
/**
|
|
372
|
+
* Parse a redirect URL or code string to extract code and state.
|
|
373
|
+
*/
|
|
374
|
+
function parseCallbackInput(input) {
|
|
375
|
+
const value = input.trim();
|
|
376
|
+
if (!value) return {};
|
|
377
|
+
try {
|
|
378
|
+
const url = new URL(value);
|
|
379
|
+
return {
|
|
380
|
+
code: url.searchParams.get("code") ?? void 0,
|
|
381
|
+
state: url.searchParams.get("state") ?? void 0
|
|
382
|
+
};
|
|
383
|
+
} catch {}
|
|
384
|
+
if (value.includes("code=")) {
|
|
385
|
+
const params = new URLSearchParams(value.replace(/^[?#]/, ""));
|
|
386
|
+
return {
|
|
387
|
+
code: params.get("code") ?? void 0,
|
|
388
|
+
state: params.get("state") ?? void 0
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
const [code, state] = value.split("#", 2);
|
|
392
|
+
return {
|
|
393
|
+
code,
|
|
394
|
+
state
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
//#endregion
|
|
398
|
+
export { OAuthCallbackFlow as t };
|
package/lib/client.js
CHANGED
|
@@ -50,7 +50,7 @@ window.__ModuleLoader__.load({
|
|
|
50
50
|
{
|
|
51
51
|
name: "interceptorEnabled",
|
|
52
52
|
kind: "boolean",
|
|
53
|
-
default:
|
|
53
|
+
default: true,
|
|
54
54
|
labelKey: "interceptorEnabled",
|
|
55
55
|
hintKey: "interceptorEnabledHint",
|
|
56
56
|
group: "behavior",
|
|
@@ -345,6 +345,15 @@ window.__ModuleLoader__.load({
|
|
|
345
345
|
group: "reading",
|
|
346
346
|
tool: "read"
|
|
347
347
|
},
|
|
348
|
+
{
|
|
349
|
+
name: "readConcurrentSafe",
|
|
350
|
+
kind: "boolean",
|
|
351
|
+
default: true,
|
|
352
|
+
labelKey: "readConcurrentSafe",
|
|
353
|
+
hintKey: "readConcurrentSafeHint",
|
|
354
|
+
group: "reading",
|
|
355
|
+
tool: "read"
|
|
356
|
+
},
|
|
348
357
|
{
|
|
349
358
|
name: "readSummarizeEnabled",
|
|
350
359
|
kind: "boolean",
|
|
@@ -433,6 +442,15 @@ window.__ModuleLoader__.load({
|
|
|
433
442
|
tool: "read",
|
|
434
443
|
visibility: { requiresEnabled: "fetchEnabled" }
|
|
435
444
|
},
|
|
445
|
+
{
|
|
446
|
+
name: "imagesBlockImages",
|
|
447
|
+
kind: "boolean",
|
|
448
|
+
default: false,
|
|
449
|
+
labelKey: "imagesBlockImages",
|
|
450
|
+
hintKey: "imagesBlockImagesHint",
|
|
451
|
+
group: "images",
|
|
452
|
+
tool: "read"
|
|
453
|
+
},
|
|
436
454
|
{
|
|
437
455
|
name: "imagesAutoResize",
|
|
438
456
|
kind: "boolean",
|
|
@@ -443,27 +461,62 @@ window.__ModuleLoader__.load({
|
|
|
443
461
|
tool: "read"
|
|
444
462
|
},
|
|
445
463
|
{
|
|
446
|
-
name: "
|
|
447
|
-
kind: "
|
|
448
|
-
default:
|
|
449
|
-
labelKey: "
|
|
450
|
-
hintKey: "
|
|
464
|
+
name: "imagesResizeMaxSide",
|
|
465
|
+
kind: "number",
|
|
466
|
+
default: 1568,
|
|
467
|
+
labelKey: "imagesResizeMaxSide",
|
|
468
|
+
hintKey: "imagesResizeMaxSideHint",
|
|
451
469
|
group: "images",
|
|
452
470
|
tool: "read",
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
471
|
+
visibility: { requiresEnabled: "imagesAutoResize" }
|
|
472
|
+
},
|
|
473
|
+
{
|
|
474
|
+
name: "imagesResizeMaxBytes",
|
|
475
|
+
kind: "number",
|
|
476
|
+
default: 512e3,
|
|
477
|
+
labelKey: "imagesResizeMaxBytes",
|
|
478
|
+
hintKey: "imagesResizeMaxBytesHint",
|
|
479
|
+
group: "images",
|
|
480
|
+
tool: "read",
|
|
481
|
+
visibility: { requiresEnabled: "imagesAutoResize" }
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
name: "imagesResizeMinSide",
|
|
485
|
+
kind: "number",
|
|
486
|
+
default: 200,
|
|
487
|
+
labelKey: "imagesResizeMinSide",
|
|
488
|
+
hintKey: "imagesResizeMinSideHint",
|
|
489
|
+
group: "images",
|
|
490
|
+
tool: "read",
|
|
491
|
+
visibility: { requiresEnabled: "imagesAutoResize" }
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
name: "imagesResizeJpegQuality",
|
|
495
|
+
kind: "number",
|
|
496
|
+
default: 80,
|
|
497
|
+
labelKey: "imagesResizeJpegQuality",
|
|
498
|
+
hintKey: "imagesResizeJpegQualityHint",
|
|
499
|
+
group: "images",
|
|
500
|
+
tool: "read",
|
|
501
|
+
visibility: { requiresEnabled: "imagesAutoResize" }
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
name: "imagesExcludeWebp",
|
|
505
|
+
kind: "boolean",
|
|
506
|
+
default: false,
|
|
507
|
+
labelKey: "imagesExcludeWebp",
|
|
508
|
+
hintKey: "imagesExcludeWebpHint",
|
|
509
|
+
group: "images",
|
|
510
|
+
tool: "read"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
name: "imagesInputMaxBytes",
|
|
514
|
+
kind: "number",
|
|
515
|
+
default: 20971520,
|
|
516
|
+
labelKey: "imagesInputMaxBytes",
|
|
517
|
+
hintKey: "imagesInputMaxBytesHint",
|
|
518
|
+
group: "images",
|
|
519
|
+
tool: "read"
|
|
467
520
|
},
|
|
468
521
|
{
|
|
469
522
|
name: "editMode",
|
|
@@ -601,11 +654,6 @@ window.__ModuleLoader__.load({
|
|
|
601
654
|
id: "astEdit",
|
|
602
655
|
labelKey: "tabAstEdit",
|
|
603
656
|
fields: TOOL_PLUS_FIELDS.filter((f) => f.tool === "astEdit").map((f) => f.name)
|
|
604
|
-
},
|
|
605
|
-
{
|
|
606
|
-
id: "readImage",
|
|
607
|
-
labelKey: "tabReadImage",
|
|
608
|
-
fields: []
|
|
609
657
|
}
|
|
610
658
|
];
|
|
611
659
|
/** Look up one field definition by its schema key. */
|
|
@@ -2030,7 +2078,6 @@ window.__ModuleLoader__.load({
|
|
|
2030
2078
|
groupBehavior: "行为",
|
|
2031
2079
|
groupReading: "读取",
|
|
2032
2080
|
groupSummary: "代码摘要",
|
|
2033
|
-
groupImages: "图片",
|
|
2034
2081
|
groupEditMode: "编辑模式",
|
|
2035
2082
|
groupGuard: "文件守卫",
|
|
2036
2083
|
noConfigTitle: "该工具无全局配置项",
|
|
@@ -2057,15 +2104,28 @@ window.__ModuleLoader__.load({
|
|
|
2057
2104
|
fetchEnabledHint: "read 处理 http(s) URL(网页转 Markdown 供模型阅读)时是否启用抓取。",
|
|
2058
2105
|
fetchMaxTimeoutSeconds: "抓取超时(秒)",
|
|
2059
2106
|
fetchMaxTimeoutSecondsHint: "URL 抓取超时上限;0 表示使用默认的 30 秒。",
|
|
2060
|
-
imagesAutoResize: "图片自动缩放",
|
|
2061
|
-
imagesAutoResizeHint: "read 读取图片时自动缩放到可展示尺寸。",
|
|
2062
|
-
inspectImageMode: "图片检查模式",
|
|
2063
|
-
inspectImageModeHint: "读图工具的行为模式:auto/on/off。",
|
|
2064
2107
|
groupFetch: "抓取",
|
|
2065
|
-
|
|
2066
|
-
|
|
2108
|
+
groupImages: "图片",
|
|
2109
|
+
imagesAutoResize: "图片自动缩放",
|
|
2110
|
+
imagesAutoResizeHint: "read 读取图片时自动缩放到可展示尺寸(关则原图入库,由宿主归一化)。",
|
|
2111
|
+
imagesBlockImages: "禁用图片读取",
|
|
2112
|
+
imagesBlockImagesHint: "开启后 read 与 URL 抓取遇到图片一律只回文字提示,不展示图片(省 token,或规避敏感图外发)。",
|
|
2113
|
+
imagesResizeMaxSide: "缩放目标最长边",
|
|
2114
|
+
imagesResizeMaxSideHint: "自动缩放时把图片长边压到该像素以内(默认 1568,主流视觉模型的实际处理上限)。",
|
|
2115
|
+
imagesResizeMaxBytes: "缩放目标字节数",
|
|
2116
|
+
imagesResizeMaxBytesHint: "自动缩放的压缩预算(默认 512000 即 500KB);已小于预算四分之一的图跳过重编码。",
|
|
2117
|
+
imagesResizeMinSide: "缩放尺寸下限",
|
|
2118
|
+
imagesResizeMinSideHint: "过小的图会被放大到该边长(默认 200 像素)——多数视觉模型拒收退化小图。",
|
|
2119
|
+
imagesResizeJpegQuality: "首次编码质量",
|
|
2120
|
+
imagesResizeJpegQualityHint: "缩放后首次有损编码的质量参数,1-100(默认 80);超出字节预算时仍会自动降质降尺寸。",
|
|
2121
|
+
imagesExcludeWebp: "禁用 WebP 输出",
|
|
2122
|
+
imagesExcludeWebpHint: "部分本地推理后端(llama.cpp/Ollama 系)不能解码 WebP,命中名单的模型已自动规避;此开关对名单外的网关模型强制改出 PNG/JPEG。",
|
|
2123
|
+
imagesInputMaxBytes: "图片输入大小上限",
|
|
2124
|
+
imagesInputMaxBytesHint: "超过该大小的图片文件直接拒读(默认 20971520 即 20MB;实际还与宿主附件限额取小)。",
|
|
2067
2125
|
readRenderMarkdown: "渲染 Markdown",
|
|
2068
2126
|
readRenderMarkdownHint: "读取 .md 文件时按 Markdown 渲染输出。",
|
|
2127
|
+
readConcurrentSafe: "并发安全读取",
|
|
2128
|
+
readConcurrentSafeHint: "声明 read 可并发执行(宿主并行调度多个 read 调用,含图片读取);关闭后宿主串行执行。默认开启,改动即时生效。",
|
|
2069
2129
|
editMode: "编辑模式",
|
|
2070
2130
|
editModeHint: "edit 工具的输入解释模式:replace=字面量替换;patch=unified diff;hashline=行锚点补丁;apply_patch=Codex 信封。默认 replace。",
|
|
2071
2131
|
editFuzzyMatch: "模糊匹配",
|
|
@@ -2084,7 +2144,6 @@ window.__ModuleLoader__.load({
|
|
|
2084
2144
|
astEditEnabledHint: "启用 ast_edit 工具做结构化 AST 重写(默认开启)。",
|
|
2085
2145
|
groupGrep: "匹配上下文",
|
|
2086
2146
|
groupAst: "AST 工具",
|
|
2087
|
-
optAuto: "auto(自动)",
|
|
2088
2147
|
optReplace: "replace(字面量替换)",
|
|
2089
2148
|
optPatch: "patch(unified diff)",
|
|
2090
2149
|
optHashline: "hashline(行锚点)",
|
|
@@ -2173,7 +2232,6 @@ window.__ModuleLoader__.load({
|
|
|
2173
2232
|
groupBehavior: "Behavior",
|
|
2174
2233
|
groupReading: "Reading",
|
|
2175
2234
|
groupSummary: "Code summary",
|
|
2176
|
-
groupImages: "Images",
|
|
2177
2235
|
groupEditMode: "Edit mode",
|
|
2178
2236
|
groupGuard: "File guard",
|
|
2179
2237
|
noConfigTitle: "No global settings for this tool",
|
|
@@ -2200,15 +2258,28 @@ window.__ModuleLoader__.load({
|
|
|
2200
2258
|
fetchEnabledHint: "Whether fetching is enabled when read handles http(s) URLs.",
|
|
2201
2259
|
fetchMaxTimeoutSeconds: "Fetch timeout (s)",
|
|
2202
2260
|
fetchMaxTimeoutSecondsHint: "URL fetch timeout cap; 0 = default 30s.",
|
|
2203
|
-
imagesAutoResize: "Auto-resize images",
|
|
2204
|
-
imagesAutoResizeHint: "Auto-resize images to a displayable size when reading.",
|
|
2205
|
-
inspectImageMode: "Image inspection mode",
|
|
2206
|
-
inspectImageModeHint: "Behavior mode for inspecting images: auto/on/off.",
|
|
2207
2261
|
groupFetch: "Fetching",
|
|
2208
|
-
|
|
2209
|
-
|
|
2262
|
+
groupImages: "Images",
|
|
2263
|
+
imagesAutoResize: "Auto-resize images",
|
|
2264
|
+
imagesAutoResizeHint: "Downscale images to a displayable size when reading (off: store originals and let the host normalize).",
|
|
2265
|
+
imagesBlockImages: "Disable image reading",
|
|
2266
|
+
imagesBlockImagesHint: "When on, read and URL fetches return a text note for images instead of showing them (saves tokens; keeps sensitive pictures out of requests).",
|
|
2267
|
+
imagesResizeMaxSide: "Resize target longest edge",
|
|
2268
|
+
imagesResizeMaxSideHint: "Auto-resize downscales the longest edge to at most this many pixels (default 1568, the effective vision-processing ceiling of mainstream models).",
|
|
2269
|
+
imagesResizeMaxBytes: "Resize target bytes",
|
|
2270
|
+
imagesResizeMaxBytesHint: "Compression budget for auto-resize (default 512000 = 500KB); images already below a quarter of it skip re-encoding.",
|
|
2271
|
+
imagesResizeMinSide: "Resize minimum edge",
|
|
2272
|
+
imagesResizeMinSideHint: "Undersized images are upscaled to this edge length (default 200px) — most vision backends reject degenerate tiny images.",
|
|
2273
|
+
imagesResizeJpegQuality: "First-pass encode quality",
|
|
2274
|
+
imagesResizeJpegQualityHint: "Quality (1-100, default 80) for the first lossy encode after resizing; the pipeline still walks down quality/scale when over budget.",
|
|
2275
|
+
imagesExcludeWebp: "Never encode WebP",
|
|
2276
|
+
imagesExcludeWebpHint: "Some local inference backends (llama.cpp/Ollama family) cannot decode WebP; detected models are already auto-excluded. This forces PNG/JPEG output for off-list gateway models.",
|
|
2277
|
+
imagesInputMaxBytes: "Image input size cap",
|
|
2278
|
+
imagesInputMaxBytesHint: "Image files above this size are rejected outright (default 20971520 = 20MB; also capped by the host attachment limits).",
|
|
2210
2279
|
readRenderMarkdown: "Render Markdown",
|
|
2211
2280
|
readRenderMarkdownHint: "Render .md files as Markdown when reading.",
|
|
2281
|
+
readConcurrentSafe: "Concurrency-safe reads",
|
|
2282
|
+
readConcurrentSafeHint: "Declare read as concurrency-safe so the host may dispatch multiple read calls (including image reads) in parallel; disable to force serial execution. Default on; changes apply immediately.",
|
|
2212
2283
|
editMode: "Edit mode",
|
|
2213
2284
|
editModeHint: "How edit interprets its input: replace / patch / hashline / apply_patch. Default: replace.",
|
|
2214
2285
|
editFuzzyMatch: "Fuzzy matching",
|
|
@@ -2227,7 +2298,6 @@ window.__ModuleLoader__.load({
|
|
|
2227
2298
|
astEditEnabledHint: "Enable the ast_edit tool for structural AST rewrites (on by default).",
|
|
2228
2299
|
groupGrep: "Match context",
|
|
2229
2300
|
groupAst: "AST tools",
|
|
2230
|
-
optAuto: "auto",
|
|
2231
2301
|
optReplace: "replace (literal)",
|
|
2232
2302
|
optPatch: "patch (unified diff)",
|
|
2233
2303
|
optHashline: "hashline (line anchors)",
|