@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.
Files changed (235) hide show
  1. package/README.en.md +122 -0
  2. package/README.md +3 -2
  3. package/THIRD_PARTY_NOTICES.md +4 -35
  4. package/lib/abort-B7izMMna.mjs +51 -0
  5. package/lib/abort-D1_Z5Ut5.mjs +51 -0
  6. package/lib/abort-dIkZBV7Q.mjs +51 -0
  7. package/lib/amazon-bedrock-B0nxT06F.mjs +917 -0
  8. package/lib/amazon-bedrock-D-shAr1X.mjs +917 -0
  9. package/lib/amazon-bedrock-WQhvjHYu.mjs +917 -0
  10. package/lib/anthropic-BWsZFzU8.mjs +262 -0
  11. package/lib/anthropic-CJCauvYz.mjs +3115 -0
  12. package/lib/anthropic-CMT1Qj1t.mjs +3115 -0
  13. package/lib/anthropic-CZghe_9U.mjs +3115 -0
  14. package/lib/anthropic-sCMH7JID.mjs +262 -0
  15. package/lib/anthropic-tTntD8BD.mjs +262 -0
  16. package/lib/api-key-login-BzqNdM2y.mjs +157 -0
  17. package/lib/api-key-login-CWVwvHT1.mjs +157 -0
  18. package/lib/api-key-login-CpzSezsi.mjs +157 -0
  19. package/lib/aws-credentials-8Mgn5MAy.mjs +867 -0
  20. package/lib/aws-credentials-CXryMobh.mjs +867 -0
  21. package/lib/aws-credentials-ChG79ey-.mjs +867 -0
  22. package/lib/azure-openai-responses-CNkHiLUh.mjs +274 -0
  23. package/lib/azure-openai-responses-Cgmc-rbL.mjs +274 -0
  24. package/lib/azure-openai-responses-DuukbD0F.mjs +274 -0
  25. package/lib/bun-shim.mjs +252 -12
  26. package/lib/bundled-references-CSuBco5p.mjs +55 -0
  27. package/lib/bundled-references-Cavaffah.mjs +55 -0
  28. package/lib/bundled-references-sLN0YdXU.mjs +55 -0
  29. package/lib/callback-server-BEFNf-jf.mjs +398 -0
  30. package/lib/callback-server-CQ5Jo8F-.mjs +398 -0
  31. package/lib/callback-server-DDSrZ6l_.mjs +398 -0
  32. package/lib/client.js +111 -41
  33. package/lib/cursor-B3zg7EHj.mjs +273 -0
  34. package/lib/cursor-B6TUEmgP.mjs +135 -0
  35. package/lib/cursor-BIQfBC6V.mjs +135 -0
  36. package/lib/cursor-D8gvtTL3.mjs +135 -0
  37. package/lib/cursor-DNk6eXDd.mjs +5470 -0
  38. package/lib/cursor-DkSX2h3H.mjs +5441 -0
  39. package/lib/cursor-MjSm74IJ.mjs +273 -0
  40. package/lib/cursor-aJrXeYCb.mjs +273 -0
  41. package/lib/cursor-mJQwUKXK.mjs +5441 -0
  42. package/lib/device-code-DBo3B5nh.mjs +51 -0
  43. package/lib/device-code-DIb0FU-H.mjs +51 -0
  44. package/lib/device-code-OI_tQcmc.mjs +51 -0
  45. package/lib/devin-BHZZyMhO.mjs +95 -0
  46. package/lib/devin-BK7DHeca.mjs +114 -0
  47. package/lib/devin-CfMp3cXS.mjs +95 -0
  48. package/lib/devin-CldyPD8K.mjs +95 -0
  49. package/lib/devin-CzRpTUOA.mjs +114 -0
  50. package/lib/devin-D9zR5B_R.mjs +542 -0
  51. package/lib/devin-DXOeNyU7.mjs +542 -0
  52. package/lib/devin-Q1yem3lp.mjs +114 -0
  53. package/lib/devin-vNZTNUON.mjs +542 -0
  54. package/lib/error-B3bevhrs.mjs +1449 -0
  55. package/lib/error-Dd8DIqs-.mjs +1449 -0
  56. package/lib/error-yCSG0mGC.mjs +1449 -0
  57. package/lib/event-stream-BDPi64mK.mjs +151 -0
  58. package/lib/event-stream-BbFZJy-z.mjs +151 -0
  59. package/lib/event-stream-loUa0s1T.mjs +151 -0
  60. package/lib/fs-promises-shim-Bx0fpxuk.mjs +57 -0
  61. package/lib/github-copilot-4GaMtQmg.mjs +208 -0
  62. package/lib/github-copilot-B1yiyVRh.mjs +104 -0
  63. package/lib/github-copilot-B2HGSIJK.mjs +104 -0
  64. package/lib/github-copilot-BWT3eAOF.mjs +208 -0
  65. package/lib/github-copilot-CYkjeTi3.mjs +208 -0
  66. package/lib/github-copilot-jscUZ8Hf.mjs +104 -0
  67. package/lib/gitlab-duo-CM7Ref1H.mjs +155 -0
  68. package/lib/gitlab-duo-akICyfeD.mjs +155 -0
  69. package/lib/gitlab-duo-gubO4FNw.mjs +155 -0
  70. package/lib/gitlab-duo-workflow-BGAF6JDw.mjs +91 -0
  71. package/lib/gitlab-duo-workflow-CSEgYk3N.mjs +91 -0
  72. package/lib/gitlab-duo-workflow-D78tdn8E.mjs +91 -0
  73. package/lib/google-BS4T25Pn.mjs +30 -0
  74. package/lib/google-TFe-7-of.mjs +30 -0
  75. package/lib/google-antigravity-DGmwC2KV.mjs +198 -0
  76. package/lib/google-antigravity-DNYhgTpA.mjs +198 -0
  77. package/lib/google-antigravity-Dlkdhahq.mjs +198 -0
  78. package/lib/google-auth-B6gjsZvg.mjs +232 -0
  79. package/lib/google-auth-De7_s3eo.mjs +232 -0
  80. package/lib/google-auth-DhqpOYrX.mjs +232 -0
  81. package/lib/google-gemini-cli-BG_LRdIV.mjs +850 -0
  82. package/lib/google-gemini-cli-CWu8HvXW.mjs +211 -0
  83. package/lib/google-gemini-cli-Cb97bzQc.mjs +850 -0
  84. package/lib/google-gemini-cli-Cqds_Q5T.mjs +850 -0
  85. package/lib/google-gemini-cli-Dsztq0N5.mjs +211 -0
  86. package/lib/google-gemini-cli-zJhiOcND.mjs +211 -0
  87. package/lib/google-oauth-shared-CuEHaDDj.mjs +147 -0
  88. package/lib/google-oauth-shared-CwNWYdmR.mjs +147 -0
  89. package/lib/google-oauth-shared-yqlyqPPC.mjs +147 -0
  90. package/lib/google-shared-CgKmmdO3.mjs +760 -0
  91. package/lib/google-shared-Dr-VG-ap.mjs +760 -0
  92. package/lib/google-shared-DzhCb9b0.mjs +760 -0
  93. package/lib/google-vertex-BDN2tLaD.mjs +99 -0
  94. package/lib/google-vertex-DopVOQOG.mjs +99 -0
  95. package/lib/google-vertex-kscbkyRb.mjs +99 -0
  96. package/lib/google-zyDOG9x7.mjs +30 -0
  97. package/lib/identity-Da1GPU9a.mjs +219 -0
  98. package/lib/identity-DnB63pS7.mjs +219 -0
  99. package/lib/identity-xRP7_eSR.mjs +219 -0
  100. package/lib/idle-iterator-Baoyn3Hp.mjs +366 -0
  101. package/lib/idle-iterator-C6XbWcuB.mjs +366 -0
  102. package/lib/idle-iterator-DUjKQEGT.mjs +366 -0
  103. package/lib/index.mjs +4608 -3935
  104. package/lib/kimi--wUOWER5.mjs +236 -0
  105. package/lib/kimi-DMVI-zrZ.mjs +236 -0
  106. package/lib/kimi-Dh0pv3WZ.mjs +236 -0
  107. package/lib/markit-BL3cH47U.mjs +1417 -0
  108. package/lib/markit-BNiNY6SE.mjs +1417 -0
  109. package/lib/markit-M0jhziqU.mjs +1417 -0
  110. package/lib/minimax-code-BK-3eBbz.mjs +53 -0
  111. package/lib/minimax-code-DCbuA6Yk.mjs +53 -0
  112. package/lib/minimax-code-Uq8Qu9LW.mjs +53 -0
  113. package/lib/models-CfT4coYT.mjs +104660 -0
  114. package/lib/models-D_XnT6ay.mjs +104660 -0
  115. package/lib/models-SGASygJ3.mjs +104660 -0
  116. package/lib/ollama-BQMGPxtV.mjs +589 -0
  117. package/lib/ollama-DPzBmq89.mjs +589 -0
  118. package/lib/ollama-DoBz5SFm.mjs +589 -0
  119. package/lib/openai-codex-Bi-4S4PX.mjs +255 -0
  120. package/lib/openai-codex-CQL_kvYL.mjs +255 -0
  121. package/lib/openai-codex-Ch8CkT3p.mjs +255 -0
  122. package/lib/openai-codex-responses-CvxL_FMF.mjs +3144 -0
  123. package/lib/openai-codex-responses-Cz-2qpC7.mjs +3144 -0
  124. package/lib/openai-codex-responses-pejZgdZo.mjs +3144 -0
  125. package/lib/openai-completions-CF8IyNtP.mjs +1360 -0
  126. package/lib/openai-completions-DIf361kF.mjs +1360 -0
  127. package/lib/openai-completions-i8doczAk.mjs +1360 -0
  128. package/lib/openai-reasoning-fallback-DGVVLgd1.mjs +286 -0
  129. package/lib/openai-reasoning-fallback-Nj6yB2rY.mjs +286 -0
  130. package/lib/openai-reasoning-fallback-OdJREP1o.mjs +286 -0
  131. package/lib/openai-responses-BqXJInHX.mjs +867 -0
  132. package/lib/openai-responses-DTkBiiy-.mjs +867 -0
  133. package/lib/openai-responses-Db_a-U4-.mjs +867 -0
  134. package/lib/opencode-DaJjcUbf.mjs +38 -0
  135. package/lib/opencode-DhMolSoB.mjs +38 -0
  136. package/lib/opencode-Rq_Q2vAO.mjs +38 -0
  137. package/lib/perplexity-9b-RQ0mV.mjs +194 -0
  138. package/lib/perplexity-C4iLVMUj.mjs +194 -0
  139. package/lib/perplexity-Uu7Jzg5b.mjs +194 -0
  140. package/lib/proxy-DDqrmjjC.mjs +190 -0
  141. package/lib/proxy-ZtUcl6r5.mjs +190 -0
  142. package/lib/proxy-pM_NIv-H.mjs +190 -0
  143. package/lib/request-debug-HJMoJncL.mjs +183 -0
  144. package/lib/sanitize-text-CfcXzw5X.mjs +33 -0
  145. package/lib/scrapers-BkFfcPHj.mjs +9198 -0
  146. package/lib/scrapers-CL-WgdU1.mjs +9198 -0
  147. package/lib/scrapers-CVptboMs.mjs +9198 -0
  148. package/lib/scrapers-CipyKyCH.mjs +9198 -0
  149. package/lib/scrapers-DGfrYhtw.mjs +9198 -0
  150. package/lib/scrapers-DSUPYoUF.mjs +9198 -0
  151. package/lib/scrapers-DZ2GXmp7.mjs +9198 -0
  152. package/lib/scrapers-nhQAvc8d.mjs +9198 -0
  153. package/lib/shell-snapshot-fn-env.sh +67 -43
  154. package/lib/src-BgpusnsB.mjs +5076 -0
  155. package/lib/src-DTid0g4K.mjs +5001 -0
  156. package/lib/src-lDmkSRbm.mjs +5006 -0
  157. package/lib/stream-BlldLkVq.mjs +10236 -0
  158. package/lib/stream-CRtexYLe.mjs +10236 -0
  159. package/lib/stream-C_RAoxJC.mjs +10236 -0
  160. package/lib/stream-markup-healing-2toHXWXM.mjs +491 -0
  161. package/lib/stream-markup-healing-DMsxBx1L.mjs +491 -0
  162. package/lib/stream-markup-healing-KMkiAA00.mjs +491 -0
  163. package/lib/turndown-DN7ByzEI.mjs +667 -0
  164. package/lib/types/client/locales.d.ts +1 -1
  165. package/lib/types/config/fields.d.ts +1 -1
  166. package/lib/types/config/settings.d.ts +25 -3
  167. package/lib/types/config/truncate.d.ts +9 -5
  168. package/lib/types/tools/bash/background.d.ts +1 -1
  169. package/lib/types/tools/bash/bash-executor.d.ts +4 -0
  170. package/lib/types/tools/bash/bash-interceptor.d.ts +10 -8
  171. package/lib/types/tools/bash/cd-workdir.d.ts +35 -0
  172. package/lib/types/tools/bash/non-interactive-env.d.ts +2 -0
  173. package/lib/types/tools/bash/render.d.ts +4 -3
  174. package/lib/types/tools/bash/sanitize-text.d.ts +5 -0
  175. package/lib/types/tools/bash/shell-snapshot.d.ts +4 -1
  176. package/lib/types/tools/bash/shell-tokenize.d.ts +60 -0
  177. package/lib/types/tools/bash/streaming-output.d.ts +12 -212
  178. package/lib/types/tools/bash/which.d.ts +20 -0
  179. package/lib/types/tools/bash/windows-shell.d.ts +31 -0
  180. package/lib/types/tools/edit/adapter/index.d.ts +25 -3
  181. package/lib/types/tools/edit/adapter/tools/auto-generated-guard.d.ts +7 -17
  182. package/lib/types/tools/glob/adapter/index.d.ts +27 -1
  183. package/lib/types/tools/grep/adapter/index.d.ts +29 -1
  184. package/lib/types/tools/omp/edit/dispatch.d.ts +43 -0
  185. package/lib/types/tools/omp/edit/hashline/noop-loop-guard.d.ts +3 -1
  186. package/lib/types/tools/omp/sdk.d.ts +6 -0
  187. package/lib/types/tools/omp/tools/auto-generated-guard.d.ts +20 -0
  188. package/lib/types/tools/omp/tools/fetch.d.ts +2 -0
  189. package/lib/types/tools/omp/tools/read.d.ts +2 -8
  190. package/lib/types/tools/omp/tools/write.d.ts +4 -4
  191. package/lib/types/tools/omp/utils/image-loading.d.ts +10 -36
  192. package/lib/types/tools/read/adapter/index.d.ts +4 -1
  193. package/lib/types/tools/read-image/index.d.ts +4 -0
  194. package/lib/types/tools/shared/auto-generated-guard.dsh.d.ts +16 -4
  195. package/lib/types/tools/shared/bun-shim.d.ts +39 -3
  196. package/lib/types/tools/shared/fs-promises-shim.d.ts +3 -1
  197. package/lib/types/tools/shared/image-bridge.d.ts +98 -0
  198. package/lib/types/tools/shared/omp-prompt.d.ts +17 -9
  199. package/lib/types/tools/shared/session-state.d.ts +9 -3
  200. package/lib/utils-2Wq2eATG.mjs +8119 -0
  201. package/lib/utils-BnX8O3vi.mjs +12303 -0
  202. package/lib/utils-Bw139LTz.mjs +8119 -0
  203. package/lib/utils-CE8N8P4Q.mjs +12315 -0
  204. package/lib/utils-CZw4tVZQ.mjs +12315 -0
  205. package/lib/utils-C_MrQ_0z.mjs +12301 -0
  206. package/lib/utils-CiGN7OHR.mjs +12315 -0
  207. package/lib/utils-Cp76gCyk.mjs +8119 -0
  208. package/lib/utils-D0GRDgAr.mjs +12315 -0
  209. package/lib/utils-D0Z1fyoO.mjs +12299 -0
  210. package/lib/utils-D2YknRk4.mjs +51 -0
  211. package/lib/utils-DppGHXQB.mjs +51 -0
  212. package/lib/utils-DzXZDfYc.mjs +51 -0
  213. package/lib/utils-W8WdSBpX.mjs +12315 -0
  214. package/lib/vision-guard-01qSwFpf.mjs +92 -0
  215. package/lib/vision-guard-BDD4OrKo.mjs +92 -0
  216. package/lib/vision-guard-DzZGaOga.mjs +92 -0
  217. package/lib/wafer-CgtPHerf.mjs +17 -0
  218. package/lib/wafer-DRU0EjZX.mjs +17 -0
  219. package/lib/wafer-cBtrn6q9.mjs +17 -0
  220. package/lib/xai-oauth-Buk8XVvM.mjs +446 -0
  221. package/lib/xai-oauth-CMal8l1O.mjs +446 -0
  222. package/lib/xai-oauth-DPHDXKD7.mjs +446 -0
  223. package/lib/xiaomi-CZgwvX2G.mjs +157 -0
  224. package/lib/xiaomi-D2qT5cAC.mjs +157 -0
  225. package/lib/xiaomi-Dd87KSg5.mjs +157 -0
  226. package/lib/zai-7DWMkEqM.mjs +203 -0
  227. package/lib/zai-C59YnomG.mjs +203 -0
  228. package/lib/zai-CFeOt-53.mjs +203 -0
  229. package/lib/zip-Cg9ANN_U.mjs +1316 -0
  230. package/lib/zip-D36ZKsP8.mjs +1316 -0
  231. package/lib/zip-D6QXpvaJ.mjs +1316 -0
  232. package/package.json +14 -10
  233. package/presets/package.json +1 -1
  234. package/presets/tool-plus-ptc/preset.yml +1 -1
  235. package/presets/tool-plus-standard/preset.yml +1 -1
@@ -0,0 +1,867 @@
1
+ import { installBunShim as __installBunShim } from "./bun-shim.mjs";
2
+ __installBunShim();
3
+ import { I as $flag, P as $env, S as debug, y as isEnoent } from "./src-BgpusnsB.mjs";
4
+ import { H as AwsCredentialsError } from "./error-Dd8DIqs-.mjs";
5
+ import { n as raceWithSignal } from "./abort-dIkZBV7Q.mjs";
6
+ import { i as isLocalOrMetadataHost } from "./proxy-pM_NIv-H.mjs";
7
+ import * as path from "node:path";
8
+ import * as fs from "node:fs";
9
+ import * as os from "node:os";
10
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/utils/aws-profile.ts
11
+ function parseAwsIni(text) {
12
+ const out = {};
13
+ let current = null;
14
+ for (const rawLine of text.split(/\r?\n/)) {
15
+ const line = rawLine.trim();
16
+ if (!line || line.startsWith("#") || line.startsWith(";")) continue;
17
+ if (line.startsWith("[") && line.endsWith("]")) {
18
+ let name = line.slice(1, -1).trim();
19
+ if (name.startsWith("profile ")) name = name.slice(8).trim();
20
+ if (name.startsWith("sso-session ")) name = `sso-session:${name.slice(12).trim()}`;
21
+ let section = out[name];
22
+ if (!section) {
23
+ section = {};
24
+ out[name] = section;
25
+ }
26
+ current = section;
27
+ continue;
28
+ }
29
+ if (!current) continue;
30
+ const eq = line.indexOf("=");
31
+ if (eq === -1) continue;
32
+ current[line.slice(0, eq).trim()] = line.slice(eq + 1).trim();
33
+ }
34
+ return out;
35
+ }
36
+ function readAwsIniSync(filePath) {
37
+ try {
38
+ return parseAwsIni(fs.readFileSync(filePath, "utf8"));
39
+ } catch {
40
+ return;
41
+ }
42
+ }
43
+ /** Resolve the selected shared-credentials profile. */
44
+ function resolveAwsProfile(profile) {
45
+ return profile || $env.AWS_PROFILE || "default";
46
+ }
47
+ /**
48
+ * Whether the shared config file participates in profile/region resolution.
49
+ * Explicit profile selection enables it; the implicit default profile follows
50
+ * the AWS SDK's `AWS_SDK_LOAD_CONFIG` opt-in.
51
+ */
52
+ function shouldLoadAwsSharedConfig(profile) {
53
+ if (profile || $env.AWS_PROFILE) return true;
54
+ const value = $env.AWS_SDK_LOAD_CONFIG?.toLowerCase();
55
+ return value === "1" || value === "true";
56
+ }
57
+ function resolveAwsProfileRegion(profile) {
58
+ if (!shouldLoadAwsSharedConfig(profile)) return void 0;
59
+ return readAwsIniSync($env.AWS_CONFIG_FILE || path.join(os.homedir(), ".aws", "config"))?.[resolveAwsProfile(profile)]?.region;
60
+ }
61
+ /** Region selected by the environment or active shared-config profile. */
62
+ function resolveAwsAmbientRegion(profile) {
63
+ return $env.AWS_REGION || $env.AWS_DEFAULT_REGION || resolveAwsProfileRegion(profile);
64
+ }
65
+ /** Resolve the region precedence shared by AWS transports and credential exchanges. */
66
+ function resolveAwsRegion(explicitRegion, profile) {
67
+ return explicitRegion || resolveAwsAmbientRegion(profile) || "us-east-1";
68
+ }
69
+ function hasConfiguredAwsProfile(profile) {
70
+ const selectedProfile = resolveAwsProfile(profile);
71
+ const credentialsPath = $env.AWS_SHARED_CREDENTIALS_FILE || path.join(os.homedir(), ".aws", "credentials");
72
+ const configPath = $env.AWS_CONFIG_FILE || path.join(os.homedir(), ".aws", "config");
73
+ return profileHasCredentialSource(selectedProfile, readAwsIniSync(credentialsPath), shouldLoadAwsSharedConfig(profile) ? readAwsIniSync(configPath) : void 0, /* @__PURE__ */ new Set());
74
+ }
75
+ /**
76
+ * Whether a profile terminates in a usable credential source. Mirrors the
77
+ * resolver's per-profile dispatch (static keys, SSO, `credential_process`,
78
+ * `role_arn` chaining) so the availability probe never diverges from what
79
+ * `resolveAwsCredentials` can actually resolve. `role_arn` chains follow
80
+ * `source_profile` recursively (cycle-guarded by `seen`); MFA-gated roles are
81
+ * treated as unusable because non-interactive resolution cannot supply a token.
82
+ */
83
+ function profileHasCredentialSource(profile, credentialsIni, configIni, seen) {
84
+ if (seen.has(profile)) return false;
85
+ seen.add(profile);
86
+ const merged = {
87
+ ...configIni?.[profile] ?? {},
88
+ ...credentialsIni?.[profile] ?? {}
89
+ };
90
+ if (merged.role_arn) {
91
+ if (merged.web_identity_token_file) return true;
92
+ if (merged.mfa_serial) return false;
93
+ if (merged.credential_source) switch (merged.credential_source) {
94
+ case "Environment": return !!($env.AWS_ACCESS_KEY_ID && $env.AWS_SECRET_ACCESS_KEY);
95
+ case "EcsContainer": return !!($env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI || $env.AWS_CONTAINER_CREDENTIALS_FULL_URI);
96
+ case "Ec2InstanceMetadata": return $env.AWS_EC2_METADATA_DISABLED?.toLowerCase() !== "true";
97
+ default: return false;
98
+ }
99
+ if (merged.source_profile) return profileHasCredentialSource(merged.source_profile, credentialsIni, configIni, seen);
100
+ return false;
101
+ }
102
+ if (merged.aws_access_key_id && merged.aws_secret_access_key) return true;
103
+ if (merged.credential_process) return true;
104
+ if (!merged.sso_account_id || !merged.sso_role_name) return false;
105
+ if (merged.sso_start_url && merged.sso_region) return true;
106
+ const session = merged.sso_session ? configIni?.[`sso-session:${merged.sso_session}`] : void 0;
107
+ return !!(session?.sso_start_url && session.sso_region);
108
+ }
109
+ //#endregion
110
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/registry/types.ts
111
+ /** Credentials are resolved by the provider transport rather than used as a bearer string. */
112
+ const AUTHENTICATED_SENTINEL = "<authenticated>";
113
+ //#endregion
114
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/registry/aws.ts
115
+ function isEc2Host() {
116
+ const checks = [
117
+ ["/sys/hypervisor/uuid", (v) => v.startsWith("ec2")],
118
+ ["/sys/devices/virtual/dmi/id/product_uuid", (v) => v.startsWith("ec2")],
119
+ ["/sys/devices/virtual/dmi/id/board_asset_tag", (v) => v.startsWith("ec2") || v.startsWith("i-")],
120
+ ["/sys/devices/virtual/dmi/id/sys_vendor", (v) => v.includes("amazon ec2")],
121
+ ["/sys/devices/virtual/dmi/id/bios_vendor", (v) => v.includes("amazon ec2")]
122
+ ];
123
+ for (const [candidate, matches] of checks) try {
124
+ if (matches(fs.readFileSync(candidate, "utf8").trim().toLowerCase())) return true;
125
+ } catch {}
126
+ return false;
127
+ }
128
+ function hasAwsCredentialSource() {
129
+ const hasEcsCredentials = !!$env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI || !!$env.AWS_CONTAINER_CREDENTIALS_FULL_URI;
130
+ const hasWebIdentity = !!$env.AWS_WEB_IDENTITY_TOKEN_FILE && !!$env.AWS_ROLE_ARN;
131
+ const hasProfile = hasConfiguredAwsProfile();
132
+ const hasInstanceRole = $env.AWS_EC2_METADATA_DISABLED?.toLowerCase() !== "true" && (!!$env.AWS_EC2_METADATA_SERVICE_ENDPOINT || isEc2Host());
133
+ return !!($env.AWS_ACCESS_KEY_ID && $env.AWS_SECRET_ACCESS_KEY || $env.AWS_BEARER_TOKEN_BEDROCK || hasWebIdentity || hasProfile || hasEcsCredentials || hasInstanceRole);
134
+ }
135
+ /** Registry key marker for AWS transports that resolve their own bearer/IAM credentials. */
136
+ function resolveAwsRegistryApiKey(options) {
137
+ if (options?.allowSkipAuth && $flag("AWS_BEDROCK_SKIP_AUTH")) return AUTHENTICATED_SENTINEL;
138
+ return hasAwsCredentialSource() ? AUTHENTICATED_SENTINEL : void 0;
139
+ }
140
+ /** Resolve a real AWS bearer token while filtering the registry's auth marker. */
141
+ function resolveAwsBearerToken(apiKey, bearerToken) {
142
+ return bearerToken || (apiKey === "<authenticated>" ? void 0 : apiKey) || $env.AWS_BEARER_TOKEN_BEDROCK;
143
+ }
144
+ //#endregion
145
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/aws-sigv4.ts
146
+ const ALGORITHM = "AWS4-HMAC-SHA256";
147
+ const KEY_TYPE = "aws4_request";
148
+ const UNSIGNABLE = {
149
+ authorization: true,
150
+ "cache-control": true,
151
+ connection: true,
152
+ expect: true,
153
+ from: true,
154
+ "keep-alive": true,
155
+ "max-forwards": true,
156
+ pragma: true,
157
+ referer: true,
158
+ te: true,
159
+ trailer: true,
160
+ "transfer-encoding": true,
161
+ upgrade: true,
162
+ "user-agent": true,
163
+ "x-amzn-trace-id": true
164
+ };
165
+ /** Coerce a possibly-ArrayBufferLike-backed `Uint8Array` into one over a fresh
166
+ * `ArrayBuffer`, which is what `crypto.subtle.{digest,sign,importKey}` requires
167
+ * under the strict TS DOM typings. No-op when already strict.
168
+ */
169
+ function asStrict(bytes) {
170
+ if (bytes.buffer instanceof ArrayBuffer && bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength) return bytes;
171
+ const copy = new Uint8Array(bytes.byteLength);
172
+ copy.set(bytes);
173
+ return copy;
174
+ }
175
+ const subtle = globalThis.crypto.subtle;
176
+ const HEX = "0123456789abcdef";
177
+ function toHex(bytes) {
178
+ let out = "";
179
+ for (let i = 0; i < bytes.length; i++) {
180
+ const b = bytes[i];
181
+ out += HEX[b >> 4] + HEX[b & 15];
182
+ }
183
+ return out;
184
+ }
185
+ async function sha256(data) {
186
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : asStrict(data);
187
+ const digest = await subtle.digest("SHA-256", bytes);
188
+ return new Uint8Array(digest);
189
+ }
190
+ async function sha256Hex(data) {
191
+ return toHex(await sha256(data));
192
+ }
193
+ async function hmac(key, data) {
194
+ const cryptoKey = await subtle.importKey("raw", asStrict(key), {
195
+ name: "HMAC",
196
+ hash: "SHA-256"
197
+ }, false, ["sign"]);
198
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : asStrict(data);
199
+ const sig = await subtle.sign("HMAC", cryptoKey, bytes);
200
+ return new Uint8Array(sig);
201
+ }
202
+ /**
203
+ * Derive a signing key: HMAC chain `kSecret → kDate → kRegion → kService → kSigning`.
204
+ */
205
+ async function getSigningKey(secretAccessKey, shortDate, region, service) {
206
+ return hmac(await hmac(await hmac(await hmac(new TextEncoder().encode(`AWS4${secretAccessKey}`), shortDate), region), service), KEY_TYPE);
207
+ }
208
+ /** `YYYYMMDDTHHMMSSZ` + 8-char `YYYYMMDD`. */
209
+ function formatAmzDate(d) {
210
+ const iso = d.toISOString();
211
+ const longDate = `${iso.slice(0, 4)}${iso.slice(5, 7)}${iso.slice(8, 10)}T${iso.slice(11, 13)}${iso.slice(14, 16)}${iso.slice(17, 19)}Z`;
212
+ return {
213
+ longDate,
214
+ shortDate: longDate.slice(0, 8)
215
+ };
216
+ }
217
+ /**
218
+ * Canonicalize a request path per RFC 3986: each segment is %-encoded but `/`
219
+ * stays literal. Matches the smithy default (`uriEscapePath: true`, then revert
220
+ * the double-encoding of `/`). Bedrock paths use no reserved characters in
221
+ * practice, but model IDs can include `:` and `.`.
222
+ */
223
+ function canonicalPath(path) {
224
+ return path.split("/").map((seg) => seg.length === 0 ? "" : encodeRfc3986(seg)).join("/");
225
+ }
226
+ function encodeRfc3986(str) {
227
+ return encodeURIComponent(str).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
228
+ }
229
+ function canonicalQuery(query) {
230
+ if (!query) return "";
231
+ const pairs = [];
232
+ for (const part of query.split("&")) {
233
+ if (!part) continue;
234
+ const eq = part.indexOf("=");
235
+ const k = eq === -1 ? part : part.slice(0, eq);
236
+ const v = eq === -1 ? "" : part.slice(eq + 1);
237
+ pairs.push([decodeURIComponent(k), decodeURIComponent(v)]);
238
+ }
239
+ pairs.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0);
240
+ return pairs.map(([k, v]) => `${encodeRfc3986(k)}=${encodeRfc3986(v)}`).join("&");
241
+ }
242
+ async function signRequest(params) {
243
+ const { method, host, path, query, body, region, service, credentials } = params;
244
+ const { longDate, shortDate } = formatAmzDate(params.date ?? /* @__PURE__ */ new Date());
245
+ const payloadHash = await sha256Hex(body);
246
+ const signed = {
247
+ host,
248
+ "x-amz-date": longDate,
249
+ "x-amz-content-sha256": payloadHash
250
+ };
251
+ if (credentials.sessionToken) signed["x-amz-security-token"] = credentials.sessionToken;
252
+ const extraHeaders = params.headers;
253
+ if (extraHeaders) for (const k in extraHeaders) {
254
+ const lk = k.toLowerCase();
255
+ if (UNSIGNABLE[lk]) continue;
256
+ if (lk.startsWith("proxy-") || lk.startsWith("sec-")) continue;
257
+ signed[lk] = extraHeaders[k].trim().replace(/\s+/g, " ");
258
+ }
259
+ const sortedNames = Object.keys(signed).sort();
260
+ const canonicalHeaders = `${sortedNames.map((n) => `${n}:${signed[n]}`).join("\n")}\n`;
261
+ const signedHeadersStr = sortedNames.join(";");
262
+ const canonicalRequest = [
263
+ method.toUpperCase(),
264
+ canonicalPath(path),
265
+ canonicalQuery(query),
266
+ canonicalHeaders,
267
+ signedHeadersStr,
268
+ payloadHash
269
+ ].join("\n");
270
+ const scope = `${shortDate}/${region}/${service}/${KEY_TYPE}`;
271
+ const stringToSign = [
272
+ ALGORITHM,
273
+ longDate,
274
+ scope,
275
+ await sha256Hex(canonicalRequest)
276
+ ].join("\n");
277
+ const signature = toHex(await hmac(await getSigningKey(credentials.secretAccessKey, shortDate, region, service), stringToSign));
278
+ const out = {
279
+ host,
280
+ "x-amz-date": longDate,
281
+ "x-amz-content-sha256": payloadHash,
282
+ authorization: `${ALGORITHM} Credential=${credentials.accessKeyId}/${scope}, SignedHeaders=${signedHeadersStr}, Signature=${signature}`
283
+ };
284
+ if (credentials.sessionToken) out["x-amz-security-token"] = credentials.sessionToken;
285
+ return out;
286
+ }
287
+ //#endregion
288
+ //#region node_modules/.pnpm/@oh-my-pi+pi-ai@17.3.5/node_modules/@oh-my-pi/pi-ai/src/providers/aws-credentials.ts
289
+ /**
290
+ * AWS credential resolution for the Bedrock provider.
291
+ *
292
+ * Chain (first hit wins):
293
+ * 1. Static credentials from the environment
294
+ * (`AWS_ACCESS_KEY_ID` + `AWS_SECRET_ACCESS_KEY` [+ `AWS_SESSION_TOKEN`]).
295
+ * 2. Web identity (`AWS_WEB_IDENTITY_TOKEN_FILE` + `AWS_ROLE_ARN`).
296
+ * 3. Profile in `~/.aws/credentials` (and `~/.aws/config` for SSO/roles):
297
+ * - static keys, SSO, `credential_process`, or `role_arn` role chaining
298
+ * (`source_profile` recursion, `web_identity_token_file`, `credential_source`).
299
+ * 4. ECS/container credentials from `AWS_CONTAINER_CREDENTIALS_*`.
300
+ * 5. EC2 IMDSv2 when metadata is enabled.
301
+ *
302
+ * Resolved credentials are cached process-wide per profile and refreshed
303
+ * 60 s before `Expiration` to absorb clock skew.
304
+ */
305
+ const REFRESH_SKEW_MS = 6e4;
306
+ /**
307
+ * TTL for file-sourced credentials that carry a session token but no expiry.
308
+ * Tools like aws-vault/saml2aws rewrite ~/.aws/credentials with short-lived STS
309
+ * session keys; caching them forever serves stale creds after rotation.
310
+ */
311
+ const FILE_SESSION_CREDS_TTL_MS = 3e5;
312
+ /**
313
+ * Bound for the detached (signal-free) shared resolution: a hung
314
+ * credential_process/SSO/IMDS fetch must not pin the inflight slot forever.
315
+ */
316
+ const SHARED_RESOLVE_TIMEOUT_MS = 3e4;
317
+ function requireDynamicCredentialExpiration(value, source, kind) {
318
+ const expiresAt = value ? Date.parse(value) : NaN;
319
+ if (Number.isFinite(expiresAt)) return expiresAt;
320
+ throw new AwsCredentialsError(`${source} response has a missing or invalid Expiration.`, kind);
321
+ }
322
+ /** Credential-process expiry is optional; missing/malformed values disable caching. */
323
+ function dynamicCredentialExpiration(value) {
324
+ if (!value) return Date.now();
325
+ const expiresAt = Date.parse(value);
326
+ return Number.isFinite(expiresAt) ? expiresAt : Date.now();
327
+ }
328
+ const cache = /* @__PURE__ */ new Map();
329
+ const inflight = /* @__PURE__ */ new Map();
330
+ function credentialCacheKey(profile, region, loadSharedConfig) {
331
+ return `${profile}\x00${region}\x00${loadSharedConfig ? "config" : "credentials"}`;
332
+ }
333
+ async function resolveAwsCredentials(opts = {}) {
334
+ const profile = resolveAwsProfile(opts.profile);
335
+ const region = resolveAwsRegion(opts.region, opts.profile);
336
+ const loadSharedConfig = shouldLoadAwsSharedConfig(opts.profile);
337
+ const cacheKey = credentialCacheKey(profile, region, loadSharedConfig);
338
+ const hit = cache.get(cacheKey);
339
+ if (hit && hit.expiresAt - REFRESH_SKEW_MS > Date.now()) return hit.creds;
340
+ const existing = inflight.get(cacheKey);
341
+ if (existing) return raceWithSignal(existing, opts.signal);
342
+ const fetchImpl = opts.fetch ?? globalThis.fetch;
343
+ const promise = (async () => {
344
+ try {
345
+ const creds = await resolveFresh(profile, region, loadSharedConfig, AbortSignal.timeout(SHARED_RESOLVE_TIMEOUT_MS), fetchImpl);
346
+ cache.set(cacheKey, {
347
+ creds,
348
+ expiresAt: creds.expiresAt ?? Number.POSITIVE_INFINITY
349
+ });
350
+ return creds;
351
+ } finally {
352
+ inflight.delete(cacheKey);
353
+ }
354
+ })();
355
+ inflight.set(cacheKey, promise);
356
+ return raceWithSignal(promise, opts.signal);
357
+ }
358
+ async function resolveFresh(profile, region, loadSharedConfig, signal, fetchImpl = globalThis.fetch) {
359
+ const envCreds = readEnvCredentials();
360
+ if (envCreds) return envCreds;
361
+ const webIdentityCreds = await readWebIdentityCredentials(region, signal, fetchImpl);
362
+ if (webIdentityCreds) return webIdentityCreds;
363
+ const profileCreds = await readProfileCredentials(profile, region, loadSharedConfig, signal, fetchImpl);
364
+ if (profileCreds) return profileCreds;
365
+ const containerCreds = await readContainerCredentials(signal, fetchImpl);
366
+ if (containerCreds) return containerCreds;
367
+ if ($env.AWS_EC2_METADATA_DISABLED?.toLowerCase() !== "true") {
368
+ const imdsCreds = await readImdsCredentials(signal, fetchImpl);
369
+ if (imdsCreds) return imdsCreds;
370
+ }
371
+ throw new AwsCredentialsError("Unable to resolve AWS credentials. Configure static environment keys, web identity, an AWS profile, ECS credentials, or an EC2 instance role.", "resolution");
372
+ }
373
+ function readEnvCredentials() {
374
+ const ak = $env.AWS_ACCESS_KEY_ID;
375
+ const sk = $env.AWS_SECRET_ACCESS_KEY;
376
+ if (!ak || !sk) return void 0;
377
+ const token = $env.AWS_SESSION_TOKEN;
378
+ return token ? {
379
+ accessKeyId: ak,
380
+ secretAccessKey: sk,
381
+ sessionToken: token
382
+ } : {
383
+ accessKeyId: ak,
384
+ secretAccessKey: sk
385
+ };
386
+ }
387
+ async function readIniFile(p) {
388
+ try {
389
+ return parseAwsIni(await fs.promises.readFile(p, "utf8"));
390
+ } catch (err) {
391
+ if (isEnoent(err)) return void 0;
392
+ throw err;
393
+ }
394
+ }
395
+ async function readProfileCredentials(profile, region, loadSharedConfig, signal, fetchImpl) {
396
+ const home = os.homedir();
397
+ const credentialsPath = $env.AWS_SHARED_CREDENTIALS_FILE || path.join(home, ".aws", "credentials");
398
+ const configPath = $env.AWS_CONFIG_FILE || path.join(home, ".aws", "config");
399
+ return resolveProfileChain(profile, {
400
+ credentialsIni: await readIniFile(credentialsPath),
401
+ configIni: loadSharedConfig ? await readIniFile(configPath) : void 0,
402
+ region,
403
+ signal,
404
+ fetchImpl
405
+ }, /* @__PURE__ */ new Set());
406
+ }
407
+ /**
408
+ * Resolve one profile, following `role_arn` chains. A `role_arn` profile derives
409
+ * base credentials from `source_profile` (recursive), `web_identity_token_file`,
410
+ * or `credential_source`, then exchanges them via STS. Non-role profiles resolve
411
+ * directly from static keys, SSO, or `credential_process`. `seen` guards against
412
+ * `source_profile` cycles.
413
+ */
414
+ async function resolveProfileChain(profile, ctx, seen) {
415
+ if (seen.has(profile)) throw new AwsCredentialsError(`AWS profile role chain contains a cycle at '${profile}'.`, "profile");
416
+ seen.add(profile);
417
+ const merged = {
418
+ ...ctx.configIni?.[profile] ?? {},
419
+ ...ctx.credentialsIni?.[profile] ?? {}
420
+ };
421
+ if (Object.keys(merged).length === 0) return void 0;
422
+ if (merged.role_arn) return assumeRoleFromProfile(profile, merged, ctx, seen);
423
+ if (merged.aws_access_key_id && merged.aws_secret_access_key) {
424
+ const out = {
425
+ accessKeyId: merged.aws_access_key_id,
426
+ secretAccessKey: merged.aws_secret_access_key
427
+ };
428
+ if (merged.aws_session_token) {
429
+ out.sessionToken = merged.aws_session_token;
430
+ out.expiresAt = Date.now() + FILE_SESSION_CREDS_TTL_MS;
431
+ }
432
+ return out;
433
+ }
434
+ if (merged.sso_account_id && merged.sso_role_name) return readSsoCredentials(merged, ctx.configIni, ctx.region, ctx.signal, ctx.fetchImpl);
435
+ if (merged.credential_process) return readCredentialProcess(profile, merged.credential_process, ctx.signal);
436
+ }
437
+ /**
438
+ * Resolve base credentials for a `role_arn` profile and exchange them for the
439
+ * target role. `web_identity_token_file` is a self-contained
440
+ * AssumeRoleWithWebIdentity; otherwise the base comes from `source_profile`
441
+ * (recursive) or `credential_source`, followed by an STS `AssumeRole`.
442
+ */
443
+ async function assumeRoleFromProfile(profile, merged, ctx, seen) {
444
+ const roleArn = merged.role_arn;
445
+ const region = ctx.region;
446
+ if (merged.web_identity_token_file) return assumeRoleWithWebIdentity({
447
+ roleArn,
448
+ tokenFile: merged.web_identity_token_file,
449
+ sessionName: merged.role_session_name
450
+ }, region, ctx.signal, ctx.fetchImpl);
451
+ if (merged.mfa_serial) throw new AwsCredentialsError(`AWS profile '${profile}' requires MFA (mfa_serial), which is not supported for non-interactive credential resolution.`, "profile");
452
+ let base;
453
+ if (merged.source_profile) {
454
+ base = await resolveProfileChain(merged.source_profile, ctx, seen);
455
+ if (!base) throw new AwsCredentialsError(`AWS profile '${profile}' references source_profile '${merged.source_profile}', which has no usable credentials.`, "profile");
456
+ } else if (merged.credential_source) {
457
+ base = await resolveCredentialSource(merged.credential_source, region, ctx.signal, ctx.fetchImpl);
458
+ if (!base) throw new AwsCredentialsError(`AWS profile '${profile}' credential_source '${merged.credential_source}' produced no credentials.`, "profile");
459
+ } else throw new AwsCredentialsError(`AWS profile '${profile}' sets role_arn without source_profile, credential_source, or web_identity_token_file.`, "profile");
460
+ return stsAssumeRole(base, roleArn, region, {
461
+ sessionName: merged.role_session_name,
462
+ durationSeconds: merged.duration_seconds,
463
+ externalId: merged.external_id
464
+ }, ctx.signal, ctx.fetchImpl);
465
+ }
466
+ /** Resolve the base credentials named by a profile `credential_source` directive. */
467
+ async function resolveCredentialSource(source, _region, signal, fetchImpl) {
468
+ switch (source) {
469
+ case "Environment": return readEnvCredentials();
470
+ case "Ec2InstanceMetadata": return $env.AWS_EC2_METADATA_DISABLED?.toLowerCase() === "true" ? void 0 : readImdsCredentials(signal, fetchImpl);
471
+ case "EcsContainer": return readContainerCredentials(signal, fetchImpl);
472
+ default: throw new AwsCredentialsError(`Unsupported AWS credential_source '${source}'.`, "profile");
473
+ }
474
+ }
475
+ /**
476
+ * Exchange base credentials for a target role via STS `AssumeRole`. The request
477
+ * is SigV4-signed with the base credentials.
478
+ */
479
+ async function stsAssumeRole(base, roleArn, region, opts, signal, fetchImpl) {
480
+ const body = new URLSearchParams({
481
+ Action: "AssumeRole",
482
+ Version: "2011-06-15",
483
+ RoleArn: roleArn,
484
+ RoleSessionName: opts.sessionName || `omp-${process.pid}`
485
+ });
486
+ if (opts.durationSeconds) body.set("DurationSeconds", opts.durationSeconds);
487
+ if (opts.externalId) body.set("ExternalId", opts.externalId);
488
+ const payload = new TextEncoder().encode(body.toString());
489
+ const endpoint = new URL(stsEndpoint(region));
490
+ const contentType = "application/x-www-form-urlencoded";
491
+ const response = await fetchImpl(endpoint, {
492
+ method: "POST",
493
+ headers: {
494
+ ...await signRequest({
495
+ method: "POST",
496
+ host: endpoint.host,
497
+ path: endpoint.pathname,
498
+ body: payload,
499
+ region,
500
+ service: "sts",
501
+ credentials: base,
502
+ headers: { "content-type": contentType }
503
+ }),
504
+ "content-type": contentType
505
+ },
506
+ body: payload,
507
+ signal
508
+ });
509
+ const xml = await response.text();
510
+ if (!response.ok) throw new AwsCredentialsError(`AWS AssumeRole failed: ${response.status} ${xmlTag(xml, "Message") ?? xml.slice(0, 200)}`, "assume-role");
511
+ return parseStsCredentials(xml, "AWS AssumeRole", "assume-role");
512
+ }
513
+ async function readSsoCredentials(profileCfg, configIni, defaultRegion, signal, fetchImpl) {
514
+ let startUrl = profileCfg.sso_start_url;
515
+ let ssoRegion = profileCfg.sso_region;
516
+ const sessionName = profileCfg.sso_session;
517
+ if (sessionName && configIni) {
518
+ const session = configIni[`sso-session:${sessionName}`];
519
+ if (session) {
520
+ startUrl = startUrl || session.sso_start_url;
521
+ ssoRegion = ssoRegion || session.sso_region;
522
+ }
523
+ }
524
+ if (!startUrl || !ssoRegion) return void 0;
525
+ const token = await loadSsoCachedToken(startUrl, sessionName);
526
+ if (!token?.accessToken) throw new AwsCredentialsError(`AWS SSO token for ${startUrl} not found in ~/.aws/sso/cache. Run 'aws sso login' first.`, "sso-token-missing");
527
+ const expiresAt = token.expiresAt ? Date.parse(token.expiresAt) : Number.POSITIVE_INFINITY;
528
+ if (Number.isFinite(expiresAt) && expiresAt <= Date.now()) throw new AwsCredentialsError(`AWS SSO token for ${startUrl} has expired. Run 'aws sso login' to refresh.`, "sso-token-expired");
529
+ const response = await fetchImpl(`https://portal.sso.${ssoRegion}.amazonaws.com/federation/credentials?account_id=${encodeURIComponent(profileCfg.sso_account_id)}&role_name=${encodeURIComponent(profileCfg.sso_role_name)}`, {
530
+ method: "GET",
531
+ headers: { "x-amz-sso_bearer_token": token.accessToken },
532
+ signal
533
+ });
534
+ if (!response.ok) {
535
+ const body = await response.text().catch(() => "");
536
+ throw new AwsCredentialsError(`AWS SSO GetRoleCredentials failed: ${response.status} ${body.slice(0, 200)}`, "sso-role");
537
+ }
538
+ const role = (await response.json()).roleCredentials;
539
+ if (!role) throw new AwsCredentialsError("AWS SSO GetRoleCredentials: missing roleCredentials in response", "sso-role");
540
+ return {
541
+ accessKeyId: role.accessKeyId,
542
+ secretAccessKey: role.secretAccessKey,
543
+ sessionToken: role.sessionToken,
544
+ expiresAt: role.expiration
545
+ };
546
+ }
547
+ async function loadSsoCachedToken(startUrl, sessionName) {
548
+ const cacheDir = path.join(os.homedir(), ".aws", "sso", "cache");
549
+ let entries;
550
+ try {
551
+ entries = await fs.promises.readdir(cacheDir);
552
+ } catch (err) {
553
+ if (isEnoent(err)) return void 0;
554
+ throw err;
555
+ }
556
+ const candidates = [];
557
+ const hash = await sha1Hex(sessionName || startUrl);
558
+ candidates.push(`${hash}.json`);
559
+ for (const entry of entries) if (entry.endsWith(".json") && !candidates.includes(entry)) candidates.push(entry);
560
+ for (const file of candidates) {
561
+ if (!entries.includes(file)) continue;
562
+ try {
563
+ const text = await fs.promises.readFile(path.join(cacheDir, file), "utf8");
564
+ const parsed = JSON.parse(text);
565
+ if (parsed.startUrl === startUrl || sessionName && file === `${hash}.json`) return parsed;
566
+ } catch (err) {
567
+ debug("aws-credentials: failed to read SSO cache", {
568
+ file,
569
+ err: String(err)
570
+ });
571
+ }
572
+ }
573
+ }
574
+ async function sha1Hex(input) {
575
+ const digest = await globalThis.crypto.subtle.digest("SHA-1", new TextEncoder().encode(input));
576
+ const bytes = new Uint8Array(digest);
577
+ let out = "";
578
+ for (let i = 0; i < bytes.length; i++) out += bytes[i].toString(16).padStart(2, "0");
579
+ return out;
580
+ }
581
+ async function readCredentialProcess(profile, command, signal) {
582
+ const argv = buildCredentialProcessArgv(profile, command);
583
+ const child = Bun.spawn(argv, {
584
+ stdin: "ignore",
585
+ stdout: "pipe",
586
+ stderr: "pipe",
587
+ windowsHide: true,
588
+ signal
589
+ });
590
+ const [stdout, stderr, exitCode] = await Promise.all([
591
+ new Response(child.stdout).text(),
592
+ new Response(child.stderr).text(),
593
+ child.exited
594
+ ]);
595
+ if (exitCode !== 0) {
596
+ const tail = stderr.trim().slice(-512) || stdout.trim().slice(-512) || "(no output)";
597
+ throw new AwsCredentialsError(`AWS credential_process for profile '${profile}' exited ${exitCode}: ${tail}`, "credential-process");
598
+ }
599
+ let parsed;
600
+ try {
601
+ parsed = JSON.parse(stdout);
602
+ } catch (err) {
603
+ throw new AwsCredentialsError(`AWS credential_process for profile '${profile}' did not emit valid JSON: ${String(err)}`, "credential-process", { cause: err });
604
+ }
605
+ if (parsed.Version !== 1) throw new AwsCredentialsError(`AWS credential_process for profile '${profile}' returned unsupported Version ${parsed.Version ?? "<missing>"}; expected 1.`, "credential-process");
606
+ if (!parsed.AccessKeyId || !parsed.SecretAccessKey) throw new AwsCredentialsError(`AWS credential_process for profile '${profile}' returned envelope without AccessKeyId/SecretAccessKey.`, "credential-process");
607
+ const out = {
608
+ accessKeyId: parsed.AccessKeyId,
609
+ secretAccessKey: parsed.SecretAccessKey
610
+ };
611
+ if (parsed.SessionToken) {
612
+ out.sessionToken = parsed.SessionToken;
613
+ out.expiresAt = dynamicCredentialExpiration(parsed.Expiration);
614
+ } else if (parsed.Expiration) out.expiresAt = dynamicCredentialExpiration(parsed.Expiration);
615
+ return out;
616
+ }
617
+ /** Resolve the argv for `Bun.spawn`. On Windows we route `.cmd`/`.bat` helpers
618
+ * through `cmd.exe /c` because direct execution refuses batch files (mirrors
619
+ * Node's `execFile` policy and avoids surprise no-ops). */
620
+ function buildCredentialProcessArgv(profile, command) {
621
+ const tokens = tokenizeCredentialProcessCommand(command);
622
+ if (tokens.length === 0) throw new AwsCredentialsError(`AWS credential_process for profile '${profile}' is empty.`, "credential-process");
623
+ if (process.platform === "win32" && isBatchScript(tokens[0])) return [
624
+ "cmd.exe",
625
+ "/d",
626
+ "/s",
627
+ "/c",
628
+ command
629
+ ];
630
+ return tokens;
631
+ }
632
+ function isBatchScript(executable) {
633
+ const lower = executable.toLowerCase();
634
+ return lower.endsWith(".cmd") || lower.endsWith(".bat");
635
+ }
636
+ /** POSIX-shell-style tokenizer used by the AWS CLI for `credential_process`.
637
+ *
638
+ * Outside quotes a backslash escapes the next character. Inside single quotes
639
+ * everything is literal (no escapes, cannot contain `'`). Inside double quotes
640
+ * a backslash only escapes `$`, `` ` ``, `"`, and `\` — every other backslash
641
+ * is preserved verbatim, which is what makes Windows paths like
642
+ * `"C:\Program Files\tool\auth.exe"` survive tokenization. */
643
+ function tokenizeCredentialProcessCommand(cmd) {
644
+ const tokens = [];
645
+ let current = "";
646
+ let hasToken = false;
647
+ let mode = "normal";
648
+ for (let i = 0; i < cmd.length; i++) {
649
+ const ch = cmd[i];
650
+ if (mode === "normal") {
651
+ if (ch === "'") {
652
+ mode = "single";
653
+ hasToken = true;
654
+ continue;
655
+ }
656
+ if (ch === "\"") {
657
+ mode = "double";
658
+ hasToken = true;
659
+ continue;
660
+ }
661
+ if (ch === "\\" && i + 1 < cmd.length) {
662
+ current += cmd[++i];
663
+ hasToken = true;
664
+ continue;
665
+ }
666
+ if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
667
+ if (hasToken) {
668
+ tokens.push(current);
669
+ current = "";
670
+ hasToken = false;
671
+ }
672
+ continue;
673
+ }
674
+ current += ch;
675
+ hasToken = true;
676
+ continue;
677
+ }
678
+ if (mode === "single") {
679
+ if (ch === "'") {
680
+ mode = "normal";
681
+ continue;
682
+ }
683
+ current += ch;
684
+ continue;
685
+ }
686
+ if (ch === "\"") {
687
+ mode = "normal";
688
+ continue;
689
+ }
690
+ if (ch === "\\" && i + 1 < cmd.length) {
691
+ const next = cmd[i + 1];
692
+ if (next === "$" || next === "`" || next === "\"" || next === "\\") {
693
+ current += next;
694
+ i++;
695
+ continue;
696
+ }
697
+ current += ch;
698
+ continue;
699
+ }
700
+ current += ch;
701
+ }
702
+ if (mode !== "normal") throw new AwsCredentialsError("AWS credential_process command has an unterminated quote.", "credential-process");
703
+ if (hasToken) tokens.push(current);
704
+ return tokens;
705
+ }
706
+ function xmlTag(xml, tag) {
707
+ const value = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`).exec(xml)?.[1];
708
+ if (!value) return void 0;
709
+ return value.replaceAll("&amp;", "&").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&quot;", "\"").replaceAll("&apos;", "'");
710
+ }
711
+ function stsEndpoint(region) {
712
+ return `https://sts.${region}.${region.startsWith("cn-") ? "amazonaws.com.cn" : "amazonaws.com"}/`;
713
+ }
714
+ /** Parse `<Credentials>` from an STS AssumeRole/WithWebIdentity XML response. */
715
+ function parseStsCredentials(xml, source, kind) {
716
+ const accessKeyId = xmlTag(xml, "AccessKeyId");
717
+ const secretAccessKey = xmlTag(xml, "SecretAccessKey");
718
+ const sessionToken = xmlTag(xml, "SessionToken");
719
+ if (!accessKeyId || !secretAccessKey || !sessionToken) throw new AwsCredentialsError(`${source} response is missing credentials.`, kind);
720
+ return {
721
+ accessKeyId,
722
+ secretAccessKey,
723
+ sessionToken,
724
+ expiresAt: requireDynamicCredentialExpiration(xmlTag(xml, "Expiration"), source, kind)
725
+ };
726
+ }
727
+ async function readWebIdentityCredentials(region, signal, fetchImpl) {
728
+ const tokenFile = $env.AWS_WEB_IDENTITY_TOKEN_FILE;
729
+ const roleArn = $env.AWS_ROLE_ARN;
730
+ if (!tokenFile || !roleArn) return void 0;
731
+ return assumeRoleWithWebIdentity({
732
+ roleArn,
733
+ tokenFile,
734
+ sessionName: $env.AWS_ROLE_SESSION_NAME
735
+ }, region, signal, fetchImpl);
736
+ }
737
+ /**
738
+ * Exchange a web-identity token file for role credentials via STS
739
+ * `AssumeRoleWithWebIdentity`. Used by the env chain (`AWS_WEB_IDENTITY_TOKEN_FILE`)
740
+ * and by `role_arn` + `web_identity_token_file` profiles.
741
+ */
742
+ async function assumeRoleWithWebIdentity(params, region, signal, fetchImpl) {
743
+ let token;
744
+ try {
745
+ token = (await Bun.file(params.tokenFile).text()).trim();
746
+ } catch (err) {
747
+ throw new AwsCredentialsError(`Unable to read AWS web identity token file: ${String(err)}`, "web-identity", { cause: err });
748
+ }
749
+ if (!token) throw new AwsCredentialsError("AWS web identity token file is empty.", "web-identity");
750
+ const body = new URLSearchParams({
751
+ Action: "AssumeRoleWithWebIdentity",
752
+ Version: "2011-06-15",
753
+ RoleArn: params.roleArn,
754
+ RoleSessionName: params.sessionName || `omp-${process.pid}`,
755
+ WebIdentityToken: token
756
+ });
757
+ const response = await fetchImpl(stsEndpoint(region), {
758
+ method: "POST",
759
+ headers: { "content-type": "application/x-www-form-urlencoded" },
760
+ body: body.toString(),
761
+ signal
762
+ });
763
+ const xml = await response.text();
764
+ if (!response.ok) throw new AwsCredentialsError(`AWS AssumeRoleWithWebIdentity failed: ${response.status} ${xmlTag(xml, "Message") ?? xml.slice(0, 200)}`, "web-identity");
765
+ return parseStsCredentials(xml, "AWS web identity", "web-identity");
766
+ }
767
+ const ECS_TASK_CREDENTIALS_BASE_URL = new URL("http://169.254.170.2/");
768
+ async function readContainerCredentials(signal, fetchImpl) {
769
+ const relativeUri = $env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI;
770
+ const fullUri = $env.AWS_CONTAINER_CREDENTIALS_FULL_URI;
771
+ if (!relativeUri && !fullUri) return void 0;
772
+ let endpoint;
773
+ if (relativeUri) {
774
+ if (!relativeUri.startsWith("/") || relativeUri.startsWith("//")) throw new AwsCredentialsError("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI must be a single-host absolute path.", "container");
775
+ endpoint = new URL(relativeUri.slice(1), ECS_TASK_CREDENTIALS_BASE_URL);
776
+ } else {
777
+ try {
778
+ endpoint = new URL(fullUri);
779
+ } catch (err) {
780
+ throw new AwsCredentialsError(`AWS_CONTAINER_CREDENTIALS_FULL_URI is invalid: ${String(err)}`, "container", { cause: err });
781
+ }
782
+ if (endpoint.protocol !== "https:" && !isLocalOrMetadataHost(endpoint.hostname)) throw new AwsCredentialsError("AWS_CONTAINER_CREDENTIALS_FULL_URI must use HTTPS or a local metadata host.", "container");
783
+ }
784
+ let authorization = $env.AWS_CONTAINER_AUTHORIZATION_TOKEN;
785
+ const authorizationTokenFile = $env.AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE;
786
+ if (!authorization && authorizationTokenFile) try {
787
+ authorization = (await Bun.file(authorizationTokenFile).text()).trim();
788
+ } catch (err) {
789
+ throw new AwsCredentialsError(`Unable to read AWS container authorization token file: ${String(err)}`, "container", { cause: err });
790
+ }
791
+ const response = await fetchImpl(endpoint, {
792
+ headers: authorization ? { authorization } : void 0,
793
+ signal
794
+ });
795
+ if (!response.ok) {
796
+ const body = await response.text().catch(() => "");
797
+ throw new AwsCredentialsError(`AWS container credential endpoint failed: ${response.status} ${body.slice(0, 200)}`, "container");
798
+ }
799
+ const body = await response.json();
800
+ if (!body.AccessKeyId || !body.SecretAccessKey || !body.Token) throw new AwsCredentialsError("AWS container credential response is missing AccessKeyId/SecretAccessKey/Token.", "container");
801
+ return {
802
+ accessKeyId: body.AccessKeyId,
803
+ secretAccessKey: body.SecretAccessKey,
804
+ sessionToken: body.Token,
805
+ expiresAt: requireDynamicCredentialExpiration(body.Expiration, "AWS container credential", "container")
806
+ };
807
+ }
808
+ const IMDS_IPV4_BASE_URL = "http://169.254.169.254/";
809
+ const IMDS_IPV6_BASE_URL = "http://[fd00:ec2::254]/";
810
+ const IMDS_TIMEOUT_MS = 1e3;
811
+ function imdsRequestSignal(parentSignal) {
812
+ const timeout = AbortSignal.timeout(IMDS_TIMEOUT_MS);
813
+ return parentSignal ? AbortSignal.any([parentSignal, timeout]) : timeout;
814
+ }
815
+ function imdsBaseUrl() {
816
+ const fallback = $env.AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE?.toLowerCase() === "ipv6" ? IMDS_IPV6_BASE_URL : IMDS_IPV4_BASE_URL;
817
+ const endpoint = new URL($env.AWS_EC2_METADATA_SERVICE_ENDPOINT || fallback);
818
+ if (!endpoint.pathname.endsWith("/")) endpoint.pathname += "/";
819
+ return endpoint;
820
+ }
821
+ async function readImdsCredentials(parentSignal, fetchImpl) {
822
+ try {
823
+ const endpoint = imdsBaseUrl();
824
+ const tokenRes = await fetchImpl(new URL("latest/api/token", endpoint), {
825
+ method: "PUT",
826
+ headers: { "x-aws-ec2-metadata-token-ttl-seconds": "21600" },
827
+ signal: imdsRequestSignal(parentSignal)
828
+ });
829
+ if (!tokenRes.ok) return void 0;
830
+ const token = await tokenRes.text();
831
+ const roleRes = await fetchImpl(new URL("latest/meta-data/iam/security-credentials/", endpoint), {
832
+ headers: { "x-aws-ec2-metadata-token": token },
833
+ signal: imdsRequestSignal(parentSignal)
834
+ });
835
+ if (!roleRes.ok) return void 0;
836
+ const role = (await roleRes.text()).trim();
837
+ if (!role) return void 0;
838
+ const credsRes = await fetchImpl(new URL(`latest/meta-data/iam/security-credentials/${encodeURIComponent(role)}`, endpoint), {
839
+ headers: { "x-aws-ec2-metadata-token": token },
840
+ signal: imdsRequestSignal(parentSignal)
841
+ });
842
+ if (!credsRes.ok) return void 0;
843
+ const body = await credsRes.json();
844
+ if (!body.AccessKeyId || !body.SecretAccessKey || !body.Token || !body.Expiration) return void 0;
845
+ const expiresAt = Date.parse(body.Expiration);
846
+ if (!Number.isFinite(expiresAt)) return void 0;
847
+ return {
848
+ accessKeyId: body.AccessKeyId,
849
+ secretAccessKey: body.SecretAccessKey,
850
+ sessionToken: body.Token,
851
+ expiresAt
852
+ };
853
+ } catch {
854
+ return;
855
+ }
856
+ }
857
+ /**
858
+ * Drop the cache entry for one profile/region. Called by the Bedrock provider on
859
+ * 401/403 responses so stale credentials are re-resolved instead of served until restart.
860
+ */
861
+ function invalidateAwsCredentialCache(opts = {}) {
862
+ const profile = resolveAwsProfile(opts.profile);
863
+ const region = resolveAwsRegion(opts.region, opts.profile);
864
+ cache.delete(credentialCacheKey(profile, region, shouldLoadAwsSharedConfig(opts.profile)));
865
+ }
866
+ //#endregion
867
+ export { resolveAwsRegistryApiKey as a, resolveAwsRegion as c, resolveAwsBearerToken as i, resolveAwsCredentials as n, AUTHENTICATED_SENTINEL as o, signRequest as r, resolveAwsAmbientRegion as s, invalidateAwsCredentialCache as t };