@try-works/dsh-model-as-tool 0.1.3 → 0.4.0

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 (260) hide show
  1. package/bin/dsh-tool-mode-credentials.mjs +20 -0
  2. package/bin/dsh-tool-mode.mjs +202 -0
  3. package/catalog/desert-ant-models.json +693 -693
  4. package/client/client.model-tools.js +614 -0
  5. package/client/index.js +1717 -0
  6. package/lib/adapters/index.d.ts.map +1 -1
  7. package/lib/adapters/index.js +4 -4
  8. package/lib/bindings.d.ts.map +1 -1
  9. package/lib/bindings.js +26 -25
  10. package/lib/capability.d.ts.map +1 -1
  11. package/lib/capability.js +17 -0
  12. package/lib/capture-path.d.ts +97 -0
  13. package/lib/capture-path.d.ts.map +1 -0
  14. package/lib/capture-path.js +152 -0
  15. package/lib/diagnostics.d.ts +166 -0
  16. package/lib/diagnostics.d.ts.map +1 -0
  17. package/lib/diagnostics.js +135 -0
  18. package/lib/extension-dependencies.d.ts +325 -0
  19. package/lib/extension-dependencies.d.ts.map +1 -0
  20. package/lib/extension-dependencies.js +858 -0
  21. package/lib/extension-dispatch.d.ts +117 -0
  22. package/lib/extension-dispatch.d.ts.map +1 -0
  23. package/lib/extension-dispatch.js +124 -0
  24. package/lib/extension-registrar.d.ts +100 -0
  25. package/lib/extension-registrar.d.ts.map +1 -0
  26. package/lib/extension-registrar.js +134 -0
  27. package/lib/extensions-api.d.ts +221 -0
  28. package/lib/extensions-api.d.ts.map +1 -0
  29. package/lib/extensions-api.js +17 -0
  30. package/lib/extensions-remote.d.ts +54 -0
  31. package/lib/extensions-remote.d.ts.map +1 -0
  32. package/lib/extensions-remote.js +66 -0
  33. package/lib/extensions-service.d.ts +367 -0
  34. package/lib/extensions-service.d.ts.map +1 -0
  35. package/lib/extensions-service.js +1527 -0
  36. package/lib/harness-llm.d.ts +138 -0
  37. package/lib/harness-llm.d.ts.map +1 -0
  38. package/lib/harness-llm.js +218 -0
  39. package/lib/harness-serving.d.ts +95 -0
  40. package/lib/harness-serving.d.ts.map +1 -0
  41. package/lib/harness-serving.js +157 -0
  42. package/lib/headless.d.ts +97 -0
  43. package/lib/headless.d.ts.map +1 -0
  44. package/lib/headless.js +349 -0
  45. package/lib/http-acquisition.d.ts +27 -0
  46. package/lib/http-acquisition.d.ts.map +1 -0
  47. package/lib/http-acquisition.js +136 -0
  48. package/lib/index.d.ts +271 -7
  49. package/lib/index.d.ts.map +1 -1
  50. package/lib/index.js +2644 -70
  51. package/lib/invocation-accounting.d.ts +169 -0
  52. package/lib/invocation-accounting.d.ts.map +1 -0
  53. package/lib/invocation-accounting.js +148 -0
  54. package/lib/legacy-migration.d.ts +95 -0
  55. package/lib/legacy-migration.d.ts.map +1 -0
  56. package/lib/legacy-migration.js +429 -0
  57. package/lib/managed-workers.d.ts +151 -0
  58. package/lib/managed-workers.d.ts.map +1 -0
  59. package/lib/managed-workers.js +249 -0
  60. package/lib/mcp/client-grant.d.ts +74 -0
  61. package/lib/mcp/client-grant.d.ts.map +1 -0
  62. package/lib/mcp/client-grant.js +60 -0
  63. package/lib/mcp/credential-cli.d.ts +38 -0
  64. package/lib/mcp/credential-cli.d.ts.map +1 -0
  65. package/lib/mcp/credential-cli.js +148 -0
  66. package/lib/mcp/credential-store.d.ts +143 -0
  67. package/lib/mcp/credential-store.d.ts.map +1 -0
  68. package/lib/mcp/credential-store.js +454 -0
  69. package/lib/mcp/host-binding.d.ts +25 -0
  70. package/lib/mcp/host-binding.d.ts.map +1 -1
  71. package/lib/mcp/host-binding.js +107 -14
  72. package/lib/mcp/http.d.ts +68 -18
  73. package/lib/mcp/http.d.ts.map +1 -1
  74. package/lib/mcp/http.js +390 -62
  75. package/lib/mcp/oauth.d.ts +149 -0
  76. package/lib/mcp/oauth.d.ts.map +1 -0
  77. package/lib/mcp/oauth.js +396 -0
  78. package/lib/mcp/protocol.d.ts +46 -7
  79. package/lib/mcp/protocol.d.ts.map +1 -1
  80. package/lib/mcp/protocol.js +63 -16
  81. package/lib/mcp/rate-limit.d.ts +68 -0
  82. package/lib/mcp/rate-limit.d.ts.map +1 -0
  83. package/lib/mcp/rate-limit.js +114 -0
  84. package/lib/mcp/sdk-v2.d.ts +17 -0
  85. package/lib/mcp/sdk-v2.d.ts.map +1 -0
  86. package/lib/mcp/sdk-v2.js +181 -0
  87. package/lib/mcp/server.d.ts +11 -1
  88. package/lib/mcp/server.d.ts.map +1 -1
  89. package/lib/mcp/server.js +80 -13
  90. package/lib/mcp/stdio.d.ts.map +1 -1
  91. package/lib/mcp/stdio.js +9 -1
  92. package/lib/mcp/subscriptions.d.ts +43 -1
  93. package/lib/mcp/subscriptions.d.ts.map +1 -1
  94. package/lib/mcp/subscriptions.js +90 -9
  95. package/lib/model-qualification.d.ts +192 -0
  96. package/lib/model-qualification.d.ts.map +1 -0
  97. package/lib/model-qualification.js +178 -0
  98. package/lib/planning.d.ts +246 -0
  99. package/lib/planning.d.ts.map +1 -0
  100. package/lib/planning.js +457 -0
  101. package/lib/prepared-assets.d.ts +178 -0
  102. package/lib/prepared-assets.d.ts.map +1 -0
  103. package/lib/prepared-assets.js +286 -0
  104. package/lib/provider-bridge.d.ts +37 -0
  105. package/lib/provider-bridge.d.ts.map +1 -1
  106. package/lib/provider-bridge.js +189 -12
  107. package/lib/ptc-authority.d.ts +140 -0
  108. package/lib/ptc-authority.d.ts.map +1 -0
  109. package/lib/ptc-authority.js +216 -0
  110. package/lib/ptc-runtime.d.ts +156 -0
  111. package/lib/ptc-runtime.d.ts.map +1 -0
  112. package/lib/ptc-runtime.js +191 -0
  113. package/lib/publication.d.ts +2 -1
  114. package/lib/publication.d.ts.map +1 -1
  115. package/lib/publication.js +13 -5
  116. package/lib/receipt.d.ts.map +1 -1
  117. package/lib/receipt.js +8 -0
  118. package/lib/title-proposal.d.ts +194 -0
  119. package/lib/title-proposal.d.ts.map +1 -0
  120. package/lib/title-proposal.js +244 -0
  121. package/lib/tool-mode-run.d.ts +235 -0
  122. package/lib/tool-mode-run.d.ts.map +1 -0
  123. package/lib/tool-mode-run.js +283 -0
  124. package/lib/types.d.ts +3 -1
  125. package/lib/types.d.ts.map +1 -1
  126. package/lib/update-surface.d.ts +79 -0
  127. package/lib/update-surface.d.ts.map +1 -0
  128. package/lib/update-surface.js +224 -0
  129. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/standard.d.ts +38 -0
  130. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/standard.d.ts.map +1 -0
  131. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/standard.js +445 -0
  132. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-embed.d.ts +14 -0
  133. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-embed.d.ts.map +1 -0
  134. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-embed.js +63 -0
  135. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-rerank.d.ts +14 -0
  136. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-rerank.d.ts.map +1 -0
  137. package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-rerank.js +76 -0
  138. package/node_modules/@try-works/tool-mode-contracts/lib/dsh.d.ts.map +1 -1
  139. package/node_modules/@try-works/tool-mode-contracts/lib/dsh.js +69 -55
  140. package/node_modules/@try-works/tool-mode-contracts/lib/index.d.ts +4 -1
  141. package/node_modules/@try-works/tool-mode-contracts/lib/index.d.ts.map +1 -1
  142. package/node_modules/@try-works/tool-mode-contracts/lib/index.js +26 -2
  143. package/node_modules/@try-works/tool-mode-contracts/lib/registry.d.ts +28 -2
  144. package/node_modules/@try-works/tool-mode-contracts/lib/registry.d.ts.map +1 -1
  145. package/node_modules/@try-works/tool-mode-contracts/lib/registry.js +93 -10
  146. package/node_modules/@try-works/tool-mode-contracts/package.json +0 -1
  147. package/node_modules/@try-works/tool-mode-extension-sdk/bin/dsh-tool-mode.mjs +20 -0
  148. package/node_modules/@try-works/tool-mode-extension-sdk/lib/cli.d.ts +80 -0
  149. package/node_modules/@try-works/tool-mode-extension-sdk/lib/cli.d.ts.map +1 -0
  150. package/node_modules/@try-works/tool-mode-extension-sdk/lib/cli.js +533 -0
  151. package/node_modules/@try-works/tool-mode-extension-sdk/lib/declarative-recipes.d.ts +83 -0
  152. package/node_modules/@try-works/tool-mode-extension-sdk/lib/declarative-recipes.d.ts.map +1 -0
  153. package/node_modules/@try-works/tool-mode-extension-sdk/lib/declarative-recipes.js +125 -0
  154. package/node_modules/@try-works/tool-mode-extension-sdk/lib/discovery.d.ts +70 -0
  155. package/node_modules/@try-works/tool-mode-extension-sdk/lib/discovery.d.ts.map +1 -0
  156. package/node_modules/@try-works/tool-mode-extension-sdk/lib/discovery.js +201 -0
  157. package/node_modules/@try-works/tool-mode-extension-sdk/lib/errors.d.ts +57 -0
  158. package/node_modules/@try-works/tool-mode-extension-sdk/lib/errors.d.ts.map +1 -0
  159. package/node_modules/@try-works/tool-mode-extension-sdk/lib/errors.js +83 -0
  160. package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.d.ts +32 -0
  161. package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.d.ts.map +1 -0
  162. package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.js +32 -0
  163. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.d.ts +86 -0
  164. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.d.ts.map +1 -0
  165. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.js +191 -0
  166. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/dependencies.d.ts +126 -0
  167. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/dependencies.d.ts.map +1 -0
  168. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/dependencies.js +297 -0
  169. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/lifecycle.d.ts +216 -0
  170. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/lifecycle.d.ts.map +1 -0
  171. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/lifecycle.js +800 -0
  172. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/migration.d.ts +210 -0
  173. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/migration.d.ts.map +1 -0
  174. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/migration.js +368 -0
  175. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/runtime-link.d.ts +63 -0
  176. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/runtime-link.d.ts.map +1 -0
  177. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/runtime-link.js +149 -0
  178. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/source-directory.d.ts +35 -0
  179. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/source-directory.d.ts.map +1 -0
  180. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/source-directory.js +179 -0
  181. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/staged.d.ts +179 -0
  182. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/staged.d.ts.map +1 -0
  183. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/staged.js +235 -0
  184. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/store.d.ts +367 -0
  185. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/store.d.ts.map +1 -0
  186. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/store.js +807 -0
  187. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/tar-gzip-source.d.ts +44 -0
  188. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/tar-gzip-source.d.ts.map +1 -0
  189. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/tar-gzip-source.js +243 -0
  190. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/update-flow.d.ts +185 -0
  191. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/update-flow.d.ts.map +1 -0
  192. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/update-flow.js +504 -0
  193. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/zip-source.d.ts +17 -0
  194. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/zip-source.d.ts.map +1 -0
  195. package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/zip-source.js +80 -0
  196. package/node_modules/@try-works/tool-mode-extension-sdk/lib/load.d.ts +52 -0
  197. package/node_modules/@try-works/tool-mode-extension-sdk/lib/load.d.ts.map +1 -0
  198. package/node_modules/@try-works/tool-mode-extension-sdk/lib/load.js +102 -0
  199. package/node_modules/@try-works/tool-mode-extension-sdk/lib/manifest.d.ts +171 -0
  200. package/node_modules/@try-works/tool-mode-extension-sdk/lib/manifest.d.ts.map +1 -0
  201. package/node_modules/@try-works/tool-mode-extension-sdk/lib/manifest.js +271 -0
  202. package/node_modules/@try-works/tool-mode-extension-sdk/lib/runtime.d.ts +242 -0
  203. package/node_modules/@try-works/tool-mode-extension-sdk/lib/runtime.d.ts.map +1 -0
  204. package/node_modules/@try-works/tool-mode-extension-sdk/lib/runtime.js +58 -0
  205. package/node_modules/@try-works/tool-mode-extension-sdk/lib/state.d.ts +118 -0
  206. package/node_modules/@try-works/tool-mode-extension-sdk/lib/state.d.ts.map +1 -0
  207. package/node_modules/@try-works/tool-mode-extension-sdk/lib/state.js +113 -0
  208. package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker/worker-child.d.ts +2 -0
  209. package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker/worker-child.d.ts.map +1 -0
  210. package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker/worker-child.js +351 -0
  211. package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker.d.ts +150 -0
  212. package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker.d.ts.map +1 -0
  213. package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker.js +670 -0
  214. package/node_modules/@try-works/tool-mode-extension-sdk/package.json +53 -0
  215. package/node_modules/@try-works/tool-mode-extension-sdk/schema/extension-manifest-1.1.0.schema.json +253 -0
  216. package/node_modules/@try-works/tool-mode-recipes/bin/tool-mode-recipe.mjs +15 -0
  217. package/node_modules/@try-works/tool-mode-recipes/lib/broker.d.ts +427 -0
  218. package/node_modules/@try-works/tool-mode-recipes/lib/broker.d.ts.map +1 -0
  219. package/node_modules/@try-works/tool-mode-recipes/lib/broker.js +592 -0
  220. package/node_modules/@try-works/tool-mode-recipes/lib/cli.d.ts +60 -0
  221. package/node_modules/@try-works/tool-mode-recipes/lib/cli.d.ts.map +1 -0
  222. package/node_modules/@try-works/tool-mode-recipes/lib/cli.js +936 -0
  223. package/node_modules/@try-works/tool-mode-recipes/lib/dsh-adapter.d.ts +237 -0
  224. package/node_modules/@try-works/tool-mode-recipes/lib/dsh-adapter.d.ts.map +1 -0
  225. package/node_modules/@try-works/tool-mode-recipes/lib/dsh-adapter.js +200 -0
  226. package/node_modules/@try-works/tool-mode-recipes/lib/fixture-provider.d.ts +85 -0
  227. package/node_modules/@try-works/tool-mode-recipes/lib/fixture-provider.d.ts.map +1 -0
  228. package/node_modules/@try-works/tool-mode-recipes/lib/fixture-provider.js +176 -0
  229. package/node_modules/@try-works/tool-mode-recipes/lib/images.d.ts +105 -0
  230. package/node_modules/@try-works/tool-mode-recipes/lib/images.d.ts.map +1 -0
  231. package/node_modules/@try-works/tool-mode-recipes/lib/images.js +129 -0
  232. package/node_modules/@try-works/tool-mode-recipes/lib/index.d.ts +25 -0
  233. package/node_modules/@try-works/tool-mode-recipes/lib/index.d.ts.map +1 -0
  234. package/node_modules/@try-works/tool-mode-recipes/lib/index.js +25 -0
  235. package/node_modules/@try-works/tool-mode-recipes/lib/recipe-format.d.ts +325 -0
  236. package/node_modules/@try-works/tool-mode-recipes/lib/recipe-format.d.ts.map +1 -0
  237. package/node_modules/@try-works/tool-mode-recipes/lib/recipe-format.js +1310 -0
  238. package/node_modules/@try-works/tool-mode-recipes/lib/templates.d.ts +51 -0
  239. package/node_modules/@try-works/tool-mode-recipes/lib/templates.d.ts.map +1 -0
  240. package/node_modules/@try-works/tool-mode-recipes/lib/templates.js +310 -0
  241. package/node_modules/@try-works/tool-mode-recipes/lib/titles.d.ts +227 -0
  242. package/node_modules/@try-works/tool-mode-recipes/lib/titles.d.ts.map +1 -0
  243. package/node_modules/@try-works/tool-mode-recipes/lib/titles.js +407 -0
  244. package/node_modules/@try-works/tool-mode-recipes/package.json +56 -0
  245. package/node_modules/@try-works/tool-mode-recipes/recipes/describe-image.json +38 -0
  246. package/node_modules/@try-works/tool-mode-recipes/recipes/text-title.json +45 -0
  247. package/node_modules/@try-works/tool-mode-recipes/schema/harness-model-recipe.schema.json +273 -0
  248. package/package.json +43 -15
  249. package/remote/spec.mjs +462 -0
  250. package/remote/typert.host.mjs +14 -0
  251. package/remote/typert.remote-client.mjs +16 -0
  252. package/lib/adapters/tongue.d.ts +0 -31
  253. package/lib/adapters/tongue.d.ts.map +0 -1
  254. package/lib/adapters/tongue.js +0 -93
  255. package/lib/adapters/voz.d.ts +0 -28
  256. package/lib/adapters/voz.d.ts.map +0 -1
  257. package/lib/adapters/voz.js +0 -102
  258. /package/{lib → node_modules/@try-works/tool-mode-extension-sdk/lib}/licensing.d.ts +0 -0
  259. /package/{lib → node_modules/@try-works/tool-mode-extension-sdk/lib}/licensing.d.ts.map +0 -0
  260. /package/{lib → node_modules/@try-works/tool-mode-extension-sdk/lib}/licensing.js +0 -0
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Archive defenses (EXT-11).
3
+ *
4
+ * An extension archive is attacker-controlled input. This module validates its
5
+ * ENTRY LIST before a single byte is extracted, because every defense here is
6
+ * cheaper and safer to apply to a list than to a filesystem: a traversal entry
7
+ * rejected here never reaches a path-join, and a symlink never exists to be
8
+ * followed.
9
+ *
10
+ * The rules are deliberately blunt where ambiguity helps an attacker:
11
+ *
12
+ * - Symlinks and hardlinks are REFUSED, not resolved. A link is the mechanism by
13
+ * which an in-package path reaches out of the package, and no legitimate
14
+ * extension needs one to ship code and schemas.
15
+ * - Duplicate and case-colliding entries are refused rather than last-write-wins.
16
+ * On a case-insensitive filesystem `A.js` and `a.js` are the same file, so an
17
+ * archive containing both extracts differently depending on the host — a
18
+ * discrepancy an attacker can use to make the validated bytes differ from the
19
+ * executed ones.
20
+ *
21
+ * @module @try-works/tool-mode-extension-sdk/install/archive
22
+ */
23
+ /** What one archive entry is. */
24
+ export type ArchiveEntryKind = 'file' | 'directory' | 'symlink' | 'hardlink';
25
+ /** One entry as reported by an archive reader, before extraction. */
26
+ export interface ArchiveEntry {
27
+ /** The path exactly as recorded in the archive, using `/` separators. */
28
+ readonly path: string;
29
+ /** Uncompressed size in bytes; 0 for directories and links. */
30
+ readonly size: number;
31
+ /** The entry type. Readers that cannot tell must report `file`. */
32
+ readonly kind: ArchiveEntryKind;
33
+ /** Compressed size when the reader knows it, for expansion-ratio checks. */
34
+ readonly compressedSize?: number;
35
+ }
36
+ /** Bounds applied to an archive before extraction (EXT-11). */
37
+ export interface ArchiveLimits {
38
+ /** Maximum number of entries. */
39
+ readonly maxEntries: number;
40
+ /** Maximum total uncompressed bytes. */
41
+ readonly maxTotalBytes: number;
42
+ /** Maximum uncompressed bytes for a single entry. */
43
+ readonly maxEntryBytes: number;
44
+ /**
45
+ * Maximum ratio of uncompressed to compressed across the archive.
46
+ *
47
+ * A compression bomb is small on the wire and enormous on disk, so the byte
48
+ * cap alone does not catch it before allocation.
49
+ */
50
+ readonly maxExpansionRatio: number;
51
+ }
52
+ /** Conservative defaults: generous for real extensions, hostile to bombs. */
53
+ export declare const DEFAULT_ARCHIVE_LIMITS: ArchiveLimits;
54
+ /**
55
+ * Validate an archive's entry list before extraction (EXT-11).
56
+ *
57
+ * @param entries - the entries as reported by the reader.
58
+ * @param limits - the bounds to apply.
59
+ * @returns the normalized entry paths, in archive order.
60
+ * @throws ManagementError when any entry, or the archive as a whole, is inadmissible.
61
+ */
62
+ export declare function validateArchiveEntries(entries: readonly ArchiveEntry[], limits?: ArchiveLimits): string[];
63
+ /**
64
+ * Locate the package root inside an archive.
65
+ *
66
+ * An archive may wrap everything in a single directory, which is normal for
67
+ * source archives. Anything else — zero roots, or files at the root alongside
68
+ * several directories — has no unambiguous package root and is refused.
69
+ * @param paths - the normalized entry paths.
70
+ * @returns the package root prefix, or '' when the package is at the archive root.
71
+ * @throws ManagementError when the root is ambiguous or the package.json is missing.
72
+ */
73
+ export declare function findPackageRoot(paths: readonly string[]): string;
74
+ /**
75
+ * Verify an archive against its declared integrity (EXT-08, EXT-12).
76
+ *
77
+ * Integrity is not trust: a matching digest says the bytes are the ones the
78
+ * operator approved, not that they are safe. It is still checked first, because a
79
+ * mismatch means nothing downstream is worth doing.
80
+ * @param bytes - the fetched archive bytes.
81
+ * @param expectedSha512 - the declared digest, lowercase hex or base64.
82
+ * @returns the computed digest, lowercase hex.
83
+ * @throws ManagementError with `INTEGRITY_MISMATCH`.
84
+ */
85
+ export declare function verifyIntegrity(bytes: Uint8Array, expectedSha512: string): string;
86
+ //# sourceMappingURL=archive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../src/install/archive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,iCAAiC;AACjC,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,CAAA;AAE5E,qEAAqE;AACrE,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,4EAA4E;IAC5E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CACjC;AAED,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,wCAAwC;IACxC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,qDAAqD;IACrD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;CACnC;AAED,6EAA6E;AAC7E,eAAO,MAAM,sBAAsB,EAAE,aAKpC,CAAA;AAiDD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,MAAM,GAAE,aAAsC,GAC7C,MAAM,EAAE,CA4FV;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAoBhE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAwBjF"}
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Archive defenses (EXT-11).
3
+ *
4
+ * An extension archive is attacker-controlled input. This module validates its
5
+ * ENTRY LIST before a single byte is extracted, because every defense here is
6
+ * cheaper and safer to apply to a list than to a filesystem: a traversal entry
7
+ * rejected here never reaches a path-join, and a symlink never exists to be
8
+ * followed.
9
+ *
10
+ * The rules are deliberately blunt where ambiguity helps an attacker:
11
+ *
12
+ * - Symlinks and hardlinks are REFUSED, not resolved. A link is the mechanism by
13
+ * which an in-package path reaches out of the package, and no legitimate
14
+ * extension needs one to ship code and schemas.
15
+ * - Duplicate and case-colliding entries are refused rather than last-write-wins.
16
+ * On a case-insensitive filesystem `A.js` and `a.js` are the same file, so an
17
+ * archive containing both extracts differently depending on the host — a
18
+ * discrepancy an attacker can use to make the validated bytes differ from the
19
+ * executed ones.
20
+ *
21
+ * @module @try-works/tool-mode-extension-sdk/install/archive
22
+ */
23
+ import { createHash } from 'node:crypto';
24
+ import { ManagementError } from "./../errors.js";
25
+ /** Conservative defaults: generous for real extensions, hostile to bombs. */
26
+ export const DEFAULT_ARCHIVE_LIMITS = {
27
+ maxEntries: 4096,
28
+ maxTotalBytes: 512 * 1024 * 1024,
29
+ maxEntryBytes: 128 * 1024 * 1024,
30
+ maxExpansionRatio: 200,
31
+ };
32
+ /** Windows device names, which resolve to hardware rather than to a file. */
33
+ const WINDOWS_RESERVED = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(?:\..*)?$/i;
34
+ /** A path segment that would escape its parent. */
35
+ function isTraversalSegment(segment) {
36
+ return segment === '..';
37
+ }
38
+ /**
39
+ * Normalize an archive entry path for comparison and containment, or reject it.
40
+ *
41
+ * @param entryPath - the path as recorded.
42
+ * @returns the normalized segments.
43
+ * @throws ManagementError when the path is inadmissible.
44
+ */
45
+ function normalizeEntryPath(entryPath) {
46
+ const fail = (why) => {
47
+ throw new ManagementError('INVALID_EXTENSION', 'install', `the archive entry ${JSON.stringify(entryPath)} is refused: ${why}`, 'Repack the extension so every entry is a package-relative path with no links.');
48
+ };
49
+ if (entryPath.length === 0)
50
+ fail('the path is empty');
51
+ if (entryPath.includes('\0'))
52
+ fail('the path contains a NUL byte');
53
+ // Checked before the absolute-path case: a UNC path also begins with a
54
+ // separator, and reporting it as merely "absolute" would understate what it is.
55
+ if (entryPath.startsWith('//'))
56
+ fail('the path is a UNC path');
57
+ // A backslash is a separator on Windows and a filename character elsewhere, so
58
+ // the same archive would extract to different trees. Refuse rather than guess.
59
+ if (entryPath.includes('\\'))
60
+ fail('the path contains a backslash, which extracts differently per platform');
61
+ if (entryPath.startsWith('/'))
62
+ fail('the path is absolute');
63
+ if (/^[A-Za-z]:/.test(entryPath))
64
+ fail('the path carries a drive letter');
65
+ const segments = entryPath.split('/').filter(segment => segment.length > 0 && segment !== '.');
66
+ for (const segment of segments) {
67
+ if (isTraversalSegment(segment))
68
+ fail('the path traverses out of the package');
69
+ if (WINDOWS_RESERVED.test(segment))
70
+ fail(`the segment ${JSON.stringify(segment)} is a reserved Windows device name`);
71
+ // A trailing dot or space is silently stripped by Windows, so `evil.` and
72
+ // `evil` collide there while remaining distinct elsewhere.
73
+ if (/[ .]$/.test(segment))
74
+ fail(`the segment ${JSON.stringify(segment)} ends in a dot or space`);
75
+ }
76
+ if (segments.length === 0)
77
+ fail('the path names nothing');
78
+ return segments;
79
+ }
80
+ /**
81
+ * Validate an archive's entry list before extraction (EXT-11).
82
+ *
83
+ * @param entries - the entries as reported by the reader.
84
+ * @param limits - the bounds to apply.
85
+ * @returns the normalized entry paths, in archive order.
86
+ * @throws ManagementError when any entry, or the archive as a whole, is inadmissible.
87
+ */
88
+ export function validateArchiveEntries(entries, limits = DEFAULT_ARCHIVE_LIMITS) {
89
+ if (entries.length > limits.maxEntries) {
90
+ throw new ManagementError('INVALID_EXTENSION', 'install', `the archive holds ${entries.length} entries, over the ${limits.maxEntries} limit`, 'Reduce the number of files, or raise the operator limit deliberately.');
91
+ }
92
+ const normalized = [];
93
+ // Two collision keys: exact, and case/separator-folded for Windows.
94
+ const exact = new Set();
95
+ const folded = new Map();
96
+ let totalBytes = 0;
97
+ let totalCompressed = 0;
98
+ for (const entry of entries) {
99
+ const segments = normalizeEntryPath(entry.path);
100
+ if (entry.kind === 'symlink' || entry.kind === 'hardlink') {
101
+ throw new ManagementError('INVALID_EXTENSION', 'install', `the archive entry ${JSON.stringify(entry.path)} is a ${entry.kind}; links are refused`, 'Ship real files. An extension does not need links to deliver code, schemas or assets.');
102
+ }
103
+ if (!Number.isFinite(entry.size) || entry.size < 0) {
104
+ throw new ManagementError('INVALID_EXTENSION', 'install', `the archive entry ${JSON.stringify(entry.path)} declares an invalid size`, 'Repack the archive.');
105
+ }
106
+ if (entry.size > limits.maxEntryBytes) {
107
+ throw new ManagementError('INVALID_EXTENSION', 'install', `the archive entry ${JSON.stringify(entry.path)} is ${entry.size} bytes, over the per-entry limit`, 'Split the asset, or raise the operator limit deliberately.');
108
+ }
109
+ const key = segments.join('/');
110
+ if (exact.has(key)) {
111
+ throw new ManagementError('INVALID_EXTENSION', 'install', `the archive declares ${JSON.stringify(key)} more than once`, 'Repack the archive with unique entries; last-write-wins is not admitted.');
112
+ }
113
+ exact.add(key);
114
+ const caseKey = key.toLowerCase();
115
+ const prior = folded.get(caseKey);
116
+ if (prior !== undefined && prior !== key) {
117
+ throw new ManagementError('INVALID_EXTENSION', 'install', `the archive entries ${JSON.stringify(prior)} and ${JSON.stringify(key)} collide on a case-insensitive filesystem`, 'Rename one of them; the archive would otherwise extract differently per host.');
118
+ }
119
+ folded.set(caseKey, key);
120
+ normalized.push(key);
121
+ totalBytes += entry.size;
122
+ totalCompressed += entry.compressedSize ?? 0;
123
+ }
124
+ if (totalBytes > limits.maxTotalBytes) {
125
+ throw new ManagementError('INVALID_EXTENSION', 'install', `the archive expands to ${totalBytes} bytes, over the ${limits.maxTotalBytes} limit`, 'Reduce the package contents, or raise the operator limit deliberately.');
126
+ }
127
+ // Only meaningful when the reader reports compressed sizes; without them the
128
+ // byte caps above still apply, so this cannot be used to bypass them.
129
+ if (totalCompressed > 0 && totalBytes / totalCompressed > limits.maxExpansionRatio) {
130
+ throw new ManagementError('INVALID_EXTENSION', 'install', `the archive expands ${(totalBytes / totalCompressed).toFixed(1)}x, over the ${limits.maxExpansionRatio}x ratio limit`, 'Repack without extreme compression; a high ratio is the signature of an expansion bomb.');
131
+ }
132
+ return normalized;
133
+ }
134
+ /**
135
+ * Locate the package root inside an archive.
136
+ *
137
+ * An archive may wrap everything in a single directory, which is normal for
138
+ * source archives. Anything else — zero roots, or files at the root alongside
139
+ * several directories — has no unambiguous package root and is refused.
140
+ * @param paths - the normalized entry paths.
141
+ * @returns the package root prefix, or '' when the package is at the archive root.
142
+ * @throws ManagementError when the root is ambiguous or the package.json is missing.
143
+ */
144
+ export function findPackageRoot(paths) {
145
+ const topLevel = new Set();
146
+ for (const path of paths) {
147
+ const [first] = path.split('/');
148
+ if (first !== undefined)
149
+ topLevel.add(first);
150
+ }
151
+ const hasRootPackageJson = paths.includes('package.json');
152
+ if (hasRootPackageJson)
153
+ return '';
154
+ const roots = [...topLevel].filter(candidate => paths.includes(`${candidate}/package.json`));
155
+ if (roots.length === 1)
156
+ return roots[0];
157
+ throw new ManagementError('INVALID_EXTENSION', 'install', roots.length === 0
158
+ ? 'the archive contains no package.json at its root or in a single top-level directory'
159
+ : `the archive contains ${roots.length} candidate package roots, which is ambiguous`, 'Pack the extension so package.json sits at the archive root or inside exactly one top-level directory.');
160
+ }
161
+ /**
162
+ * Verify an archive against its declared integrity (EXT-08, EXT-12).
163
+ *
164
+ * Integrity is not trust: a matching digest says the bytes are the ones the
165
+ * operator approved, not that they are safe. It is still checked first, because a
166
+ * mismatch means nothing downstream is worth doing.
167
+ * @param bytes - the fetched archive bytes.
168
+ * @param expectedSha512 - the declared digest, lowercase hex or base64.
169
+ * @returns the computed digest, lowercase hex.
170
+ * @throws ManagementError with `INTEGRITY_MISMATCH`.
171
+ */
172
+ export function verifyIntegrity(bytes, expectedSha512) {
173
+ const digest = createHash('sha512').update(bytes).digest('hex');
174
+ // Strip the optional SRI prefix and trim, but do NOT lowercase before the
175
+ // format decision: base64 is CASE-SENSITIVE (npm's dist.integrity is base64
176
+ // SRI), so lowercasing first corrupts a correct digest. npm's base64 SRI for
177
+ // a SHA-512 always carries '=' padding, which hex never does — that is the
178
+ // deterministic discriminator, and the hex arm is lowercased only after it
179
+ // is recognized as hex.
180
+ const stripped = expectedSha512.trim().replace(/^sha512-/, '');
181
+ const expectedHex = stripped.includes('=')
182
+ ? Buffer.from(stripped, 'base64').toString('hex')
183
+ : /^[0-9a-f]+$/i.test(stripped)
184
+ ? stripped.toLowerCase()
185
+ : Buffer.from(stripped, 'base64').toString('hex');
186
+ if (digest !== expectedHex) {
187
+ throw new ManagementError('INTEGRITY_MISMATCH', 'install', 'the fetched archive does not match its declared SHA-512', 'Do not retry blindly: re-fetch from the declared source and confirm the expected digest with the publisher.');
188
+ }
189
+ return digest;
190
+ }
191
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Installer-owned dependency graphs (EXT-09).
3
+ *
4
+ * An extension's runtime dependencies are resolved through the operator's
5
+ * registry EXACTLY ONCE (ranges lock to exact versions), fetched, verified
6
+ * against their registry-recorded SHA-512, and materialized into the
7
+ * extension's OWN immutable installation directory — never the host's
8
+ * node_modules, never the user's workspace. Lifecycle scripts are refused,
9
+ * never silently skipped or run: a dependency whose package declares
10
+ * `prepare`/`preinstall`/`install`/`postinstall` refuses the install with a
11
+ * named error. The resolved graph (name, exact version, integrity, requested
12
+ * spec) is recorded in the install record (EXT-12).
13
+ *
14
+ * The registry half is INJECTED, like the archive source: the SDK owns the
15
+ * graph discipline, the host supplies the configured registry and the tarball
16
+ * transport. An extension's runtime can only import what this installer
17
+ * materialized — undeclared resolution attempts fail at module load, because
18
+ * the runtime SDK link is the only bridge into the host tree.
19
+ *
20
+ * @module @try-works/tool-mode-extension-sdk/install/dependencies
21
+ */
22
+ import type { ArchiveSource, InstallSource } from './staged.ts';
23
+ /** One locked runtime dependency (EXT-12's dependency-lock record). */
24
+ export interface LockedDependency {
25
+ /** The package name, e.g. `@acme/lib`. */
26
+ readonly name: string;
27
+ /** The EXACT version the range resolved to. */
28
+ readonly version: string;
29
+ /**
30
+ * Registry arm: the registry-recorded SHA-512 that was verified.
31
+ * Preinstalled arm: the SHA-256 content digest of the EXACT bytes the
32
+ * installer copied into the extension's own tree (never a digest the
33
+ * resolver supplied, so the record covers what was actually materialized).
34
+ */
35
+ readonly integrity: string;
36
+ /** The requested spec, recorded verbatim for the audit trail. */
37
+ readonly resolvedFrom: string;
38
+ /**
39
+ * How the content arrived. ABSENT means the registry arm — existing locks
40
+ * and install records stay valid without this field.
41
+ *
42
+ * `'preinstalled'` IS the "scripts were not run by the installer" statement:
43
+ * the content arrived already materialized by a completed host install, so
44
+ * this installer ran NO lifecycle script on it — the package.json's scripts
45
+ * field is left untouched, never stripped and never executed (EXT-10's
46
+ * never-silently-skip rule is honored by provenance, not by editing bytes).
47
+ */
48
+ readonly provenance?: 'registry' | 'preinstalled';
49
+ /**
50
+ * Present exactly when `provenance` is `'preinstalled'`: the operator-supplied
51
+ * source directory the content was copied from, as the resolver returned it.
52
+ */
53
+ readonly preinstalledFrom?: string;
54
+ }
55
+ /** One dependency the resolver supplies: registry bytes or preinstalled content. */
56
+ export type DependencyContent = {
57
+ readonly name: string;
58
+ readonly version: string;
59
+ readonly tarball: InstallSource;
60
+ readonly integrity: string;
61
+ readonly provenance?: 'registry';
62
+ } | {
63
+ readonly name: string;
64
+ readonly version: string;
65
+ readonly dir: string;
66
+ readonly provenance: 'preinstalled';
67
+ };
68
+ /** The injected registry half: resolve a name/range to an exact dependency. */
69
+ export interface DependencyResolver {
70
+ /**
71
+ * Resolve a name and version spec ONCE to an exact version. The registry arm
72
+ * returns the tarball source and the registry-recorded integrity; the
73
+ * preinstalled arm returns an operator-approved materialized directory — the
74
+ * installer copies it and computes its own digest from the copied bytes.
75
+ * @param name - the package name.
76
+ * @param range - the declared spec (an exact version or a range).
77
+ */
78
+ resolve(name: string, range: string): Promise<DependencyContent>;
79
+ }
80
+ /** Bounds and providers for one dependency installation. */
81
+ export interface InstallDependencyGraph {
82
+ readonly resolver: DependencyResolver;
83
+ readonly archive: ArchiveSource;
84
+ readonly maxDepth?: number;
85
+ readonly maxPackages?: number;
86
+ /**
87
+ * The OPT-IN operator gate for preinstalled content. ABSENT (the default)
88
+ * means any preinstalled-armed resolve result REFUSES by name — a normal
89
+ * install of script-declaring registry bytes still refuses under EXT-10.
90
+ */
91
+ readonly allowPreinstalled?: boolean;
92
+ /**
93
+ * The operator-configured root every preinstalled directory must live
94
+ * under. REQUIRED when `allowPreinstalled` is true; the installer refuses a
95
+ * directory outside it (path-escape refusal) rather than copying.
96
+ */
97
+ readonly preinstalledRoot?: string;
98
+ /** One preinstalled copy's size bound in bytes. Default 512 MiB. */
99
+ readonly maxPreinstalledBytes?: number;
100
+ /** One preinstalled copy's file-count bound. Default 10 000. */
101
+ readonly maxPreinstalledFiles?: number;
102
+ }
103
+ /** Refuse a dependency whose package declares install-time lifecycle scripts. */
104
+ export declare function refuseInstallScripts(packageDir: string, name: string, version: string): void;
105
+ /**
106
+ * Resolve, fetch, verify and materialize one extension's dependency graph.
107
+ *
108
+ * Bounded BFS: ranges resolve exactly once, registry tarballs verify against
109
+ * their registry integrity, scripts are refused on the registry arm, and the
110
+ * graph is flattened into the extension's own `node_modules` (a private root —
111
+ * no hoisting into any other tree). Version conflicts within one graph are
112
+ * REFUSED rather than silently duplicated; the count and depth caps refuse
113
+ * runaway graphs by name.
114
+ *
115
+ * The PREINSTALLED arm is operator-gated: only when `allowPreinstalled` is set
116
+ * does a resolver-supplied directory get copied (bounded, path-escape-checked
117
+ * against `preinstalledRoot`, reparse-point-refused) into the extension's own
118
+ * tree, with the record's provenance stating that the installer ran no
119
+ * lifecycle script on it.
120
+ *
121
+ * @param packageDir - the extracted extension package directory.
122
+ * @param graph - the injected resolver/archive plus the bounds and the gate.
123
+ * @returns the locked dependency records, in materialization order.
124
+ */
125
+ export declare function installDependencyGraph(packageDir: string, graph: InstallDependencyGraph): Promise<readonly LockedDependency[]>;
126
+ //# sourceMappingURL=dependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../src/install/dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE/D,uEAAuE;AACvE,MAAM,WAAW,gBAAgB;IAC/B,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,cAAc,CAAA;IACjD;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CACnC;AAED,oFAAoF;AACpF,MAAM,MAAM,iBAAiB,GACzB;IACA,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CACjC,GACC;IACA,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAA;CACpC,CAAA;AAEH,+EAA+E;AAC/E,MAAM,WAAW,kBAAkB;IACjC;;;;;;;OAOG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;CACjE;AAED,4DAA4D;AAC5D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAA;IACrC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IACpC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,oEAAoE;IACpE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IACtC,gEAAgE;IAChE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;CACvC;AAkDD,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAyB5F;AAgFD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,SAAS,gBAAgB,EAAE,CAAC,CA0KtC"}