@pellux/goodvibes-sdk 0.25.10 → 0.25.12

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 (220) hide show
  1. package/dist/_internal/contracts/artifacts/operator-contract.json +178 -6
  2. package/dist/_internal/contracts/generated/foundation-client-types.d.ts +16 -1
  3. package/dist/_internal/contracts/generated/foundation-client-types.d.ts.map +1 -1
  4. package/dist/_internal/contracts/generated/foundation-metadata.d.ts +2 -2
  5. package/dist/_internal/contracts/generated/foundation-metadata.js +2 -2
  6. package/dist/_internal/contracts/generated/operator-contract.d.ts.map +1 -1
  7. package/dist/_internal/contracts/generated/operator-contract.js +178 -6
  8. package/dist/_internal/contracts/generated/operator-method-ids.d.ts +1 -1
  9. package/dist/_internal/contracts/generated/operator-method-ids.d.ts.map +1 -1
  10. package/dist/_internal/contracts/generated/operator-method-ids.js +1 -0
  11. package/dist/_internal/daemon/context.d.ts +1 -0
  12. package/dist/_internal/daemon/context.d.ts.map +1 -1
  13. package/dist/_internal/daemon/integration-route-types.d.ts +1 -0
  14. package/dist/_internal/daemon/integration-route-types.d.ts.map +1 -1
  15. package/dist/_internal/daemon/integration-routes.d.ts +1 -1
  16. package/dist/_internal/daemon/integration-routes.d.ts.map +1 -1
  17. package/dist/_internal/daemon/integration-routes.js +3 -0
  18. package/dist/_internal/daemon/operator.d.ts +1 -1
  19. package/dist/_internal/daemon/operator.d.ts.map +1 -1
  20. package/dist/_internal/daemon/operator.js +2 -0
  21. package/dist/_internal/daemon/runtime-route-types.d.ts +1 -1
  22. package/dist/_internal/daemon/runtime-route-types.d.ts.map +1 -1
  23. package/dist/_internal/platform/adapters/discord/index.d.ts.map +1 -1
  24. package/dist/_internal/platform/adapters/discord/index.js +4 -5
  25. package/dist/_internal/platform/adapters/github/index.d.ts.map +1 -1
  26. package/dist/_internal/platform/adapters/github/index.js +4 -5
  27. package/dist/_internal/platform/adapters/google-chat/index.d.ts.map +1 -1
  28. package/dist/_internal/platform/adapters/google-chat/index.js +7 -5
  29. package/dist/_internal/platform/adapters/helpers.d.ts +2 -1
  30. package/dist/_internal/platform/adapters/helpers.d.ts.map +1 -1
  31. package/dist/_internal/platform/adapters/helpers.js +3 -34
  32. package/dist/_internal/platform/adapters/homeassistant/index.d.ts +3 -0
  33. package/dist/_internal/platform/adapters/homeassistant/index.d.ts.map +1 -0
  34. package/dist/_internal/platform/adapters/homeassistant/index.js +185 -0
  35. package/dist/_internal/platform/adapters/index.d.ts +1 -0
  36. package/dist/_internal/platform/adapters/index.d.ts.map +1 -1
  37. package/dist/_internal/platform/adapters/index.js +1 -0
  38. package/dist/_internal/platform/adapters/mattermost/index.d.ts.map +1 -1
  39. package/dist/_internal/platform/adapters/mattermost/index.js +6 -2
  40. package/dist/_internal/platform/adapters/slack/index.d.ts.map +1 -1
  41. package/dist/_internal/platform/adapters/slack/index.js +4 -5
  42. package/dist/_internal/platform/adapters/telegram/index.d.ts.map +1 -1
  43. package/dist/_internal/platform/adapters/telegram/index.js +7 -5
  44. package/dist/_internal/platform/adapters/types.d.ts +1 -1
  45. package/dist/_internal/platform/adapters/types.d.ts.map +1 -1
  46. package/dist/_internal/platform/adapters/webhook/index.d.ts.map +1 -1
  47. package/dist/_internal/platform/adapters/webhook/index.js +4 -1
  48. package/dist/_internal/platform/automation/types.d.ts +1 -1
  49. package/dist/_internal/platform/automation/types.d.ts.map +1 -1
  50. package/dist/_internal/platform/channels/builtin/accounts.d.ts.map +1 -1
  51. package/dist/_internal/platform/channels/builtin/accounts.js +23 -0
  52. package/dist/_internal/platform/channels/builtin/contracts.d.ts.map +1 -1
  53. package/dist/_internal/platform/channels/builtin/contracts.js +9 -0
  54. package/dist/_internal/platform/channels/builtin/descriptors.d.ts.map +1 -1
  55. package/dist/_internal/platform/channels/builtin/descriptors.js +9 -2
  56. package/dist/_internal/platform/channels/builtin/homeassistant.d.ts +64 -0
  57. package/dist/_internal/platform/channels/builtin/homeassistant.d.ts.map +1 -0
  58. package/dist/_internal/platform/channels/builtin/homeassistant.js +391 -0
  59. package/dist/_internal/platform/channels/builtin/plugins.d.ts.map +1 -1
  60. package/dist/_internal/platform/channels/builtin/plugins.js +2 -1
  61. package/dist/_internal/platform/channels/builtin/presentation.d.ts.map +1 -1
  62. package/dist/_internal/platform/channels/builtin/presentation.js +4 -0
  63. package/dist/_internal/platform/channels/builtin/rendering.d.ts.map +1 -1
  64. package/dist/_internal/platform/channels/builtin/rendering.js +7 -0
  65. package/dist/_internal/platform/channels/builtin/setup-schema.d.ts.map +1 -1
  66. package/dist/_internal/platform/channels/builtin/setup-schema.js +53 -0
  67. package/dist/_internal/platform/channels/builtin/shared.d.ts +1 -1
  68. package/dist/_internal/platform/channels/builtin/shared.d.ts.map +1 -1
  69. package/dist/_internal/platform/channels/builtin/shared.js +2 -0
  70. package/dist/_internal/platform/channels/builtin/surfaces.d.ts.map +1 -1
  71. package/dist/_internal/platform/channels/builtin/surfaces.js +1 -0
  72. package/dist/_internal/platform/channels/builtin/targets.d.ts.map +1 -1
  73. package/dist/_internal/platform/channels/builtin/targets.js +24 -0
  74. package/dist/_internal/platform/channels/builtin-runtime.d.ts.map +1 -1
  75. package/dist/_internal/platform/channels/builtin-runtime.js +6 -0
  76. package/dist/_internal/platform/channels/delivery/strategies-core.d.ts +1 -0
  77. package/dist/_internal/platform/channels/delivery/strategies-core.d.ts.map +1 -1
  78. package/dist/_internal/platform/channels/delivery/strategies-core.js +60 -1
  79. package/dist/_internal/platform/channels/delivery/types.d.ts +2 -0
  80. package/dist/_internal/platform/channels/delivery/types.d.ts.map +1 -1
  81. package/dist/_internal/platform/channels/delivery-router.d.ts.map +1 -1
  82. package/dist/_internal/platform/channels/delivery-router.js +2 -1
  83. package/dist/_internal/platform/channels/reply-pipeline.d.ts.map +1 -1
  84. package/dist/_internal/platform/channels/reply-pipeline.js +9 -0
  85. package/dist/_internal/platform/channels/route-manager.d.ts.map +1 -1
  86. package/dist/_internal/platform/channels/route-manager.js +1 -0
  87. package/dist/_internal/platform/channels/surface-registry.d.ts.map +1 -1
  88. package/dist/_internal/platform/channels/surface-registry.js +4 -0
  89. package/dist/_internal/platform/channels/types.d.ts +1 -1
  90. package/dist/_internal/platform/channels/types.d.ts.map +1 -1
  91. package/dist/_internal/platform/cloudflare/manager.d.ts +1 -1
  92. package/dist/_internal/platform/cloudflare/manager.d.ts.map +1 -1
  93. package/dist/_internal/platform/cloudflare/manager.js +27 -24
  94. package/dist/_internal/platform/cloudflare/types.d.ts +5 -0
  95. package/dist/_internal/platform/cloudflare/types.d.ts.map +1 -1
  96. package/dist/_internal/platform/cloudflare/utils.d.ts.map +1 -1
  97. package/dist/_internal/platform/cloudflare/utils.js +4 -10
  98. package/dist/_internal/platform/companion/companion-chat-manager.d.ts +24 -4
  99. package/dist/_internal/platform/companion/companion-chat-manager.d.ts.map +1 -1
  100. package/dist/_internal/platform/companion/companion-chat-manager.js +128 -78
  101. package/dist/_internal/platform/config/schema-domain-surfaces.d.ts +12 -0
  102. package/dist/_internal/platform/config/schema-domain-surfaces.d.ts.map +1 -1
  103. package/dist/_internal/platform/config/schema-domain-surfaces.js +67 -0
  104. package/dist/_internal/platform/config/schema-types.d.ts +15 -2
  105. package/dist/_internal/platform/config/schema-types.d.ts.map +1 -1
  106. package/dist/_internal/platform/control-plane/gateway-utils.d.ts +37 -0
  107. package/dist/_internal/platform/control-plane/gateway-utils.d.ts.map +1 -0
  108. package/dist/_internal/platform/control-plane/gateway-utils.js +97 -0
  109. package/dist/_internal/platform/control-plane/gateway.d.ts +4 -9
  110. package/dist/_internal/platform/control-plane/gateway.d.ts.map +1 -1
  111. package/dist/_internal/platform/control-plane/gateway.js +26 -61
  112. package/dist/_internal/platform/control-plane/method-catalog-runtime.d.ts.map +1 -1
  113. package/dist/_internal/platform/control-plane/method-catalog-runtime.js +11 -1
  114. package/dist/_internal/platform/control-plane/operator-contract-schemas-admin.d.ts.map +1 -1
  115. package/dist/_internal/platform/control-plane/operator-contract-schemas-admin.js +3 -2
  116. package/dist/_internal/platform/control-plane/operator-contract-schemas-control.d.ts +1 -0
  117. package/dist/_internal/platform/control-plane/operator-contract-schemas-control.d.ts.map +1 -1
  118. package/dist/_internal/platform/control-plane/operator-contract-schemas-control.js +26 -0
  119. package/dist/_internal/platform/control-plane/routes/operator.d.ts +1 -1
  120. package/dist/_internal/platform/control-plane/routes/operator.d.ts.map +1 -1
  121. package/dist/_internal/platform/control-plane/routes/operator.js +2 -0
  122. package/dist/_internal/platform/control-plane/session-types.d.ts +2 -1
  123. package/dist/_internal/platform/control-plane/session-types.d.ts.map +1 -1
  124. package/dist/_internal/platform/control-plane/types.d.ts +1 -1
  125. package/dist/_internal/platform/control-plane/types.d.ts.map +1 -1
  126. package/dist/_internal/platform/daemon/control-plane.d.ts.map +1 -1
  127. package/dist/_internal/platform/daemon/control-plane.js +50 -6
  128. package/dist/_internal/platform/daemon/facade-composition.d.ts.map +1 -1
  129. package/dist/_internal/platform/daemon/facade-composition.js +30 -2
  130. package/dist/_internal/platform/daemon/facade-types.d.ts +1 -1
  131. package/dist/_internal/platform/daemon/facade-types.d.ts.map +1 -1
  132. package/dist/_internal/platform/daemon/http/homeassistant-routes.d.ts +40 -0
  133. package/dist/_internal/platform/daemon/http/homeassistant-routes.d.ts.map +1 -0
  134. package/dist/_internal/platform/daemon/http/homeassistant-routes.js +468 -0
  135. package/dist/_internal/platform/daemon/http/router.d.ts +4 -2
  136. package/dist/_internal/platform/daemon/http/router.d.ts.map +1 -1
  137. package/dist/_internal/platform/daemon/http/router.js +28 -16
  138. package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts +1 -1
  139. package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts.map +1 -1
  140. package/dist/_internal/platform/daemon/http-listener.d.ts.map +1 -1
  141. package/dist/_internal/platform/daemon/http-listener.js +4 -8
  142. package/dist/_internal/platform/daemon/surface-actions.d.ts +1 -1
  143. package/dist/_internal/platform/daemon/surface-actions.d.ts.map +1 -1
  144. package/dist/_internal/platform/daemon/surface-delivery.d.ts +1 -1
  145. package/dist/_internal/platform/daemon/surface-delivery.d.ts.map +1 -1
  146. package/dist/_internal/platform/daemon/surface-delivery.js +15 -0
  147. package/dist/_internal/platform/daemon/surface-policy.d.ts +1 -1
  148. package/dist/_internal/platform/daemon/surface-policy.d.ts.map +1 -1
  149. package/dist/_internal/platform/daemon/surface-policy.js +8 -0
  150. package/dist/_internal/platform/daemon/types.d.ts +3 -3
  151. package/dist/_internal/platform/daemon/types.d.ts.map +1 -1
  152. package/dist/_internal/platform/integrations/homeassistant.d.ts +62 -0
  153. package/dist/_internal/platform/integrations/homeassistant.d.ts.map +1 -0
  154. package/dist/_internal/platform/integrations/homeassistant.js +174 -0
  155. package/dist/_internal/platform/integrations/index.d.ts +2 -0
  156. package/dist/_internal/platform/integrations/index.d.ts.map +1 -1
  157. package/dist/_internal/platform/integrations/index.js +1 -0
  158. package/dist/_internal/platform/runtime/events/control-plane.d.ts +1 -1
  159. package/dist/_internal/platform/runtime/events/control-plane.d.ts.map +1 -1
  160. package/dist/_internal/platform/runtime/events/control-plane.js +1 -0
  161. package/dist/_internal/platform/runtime/events/routes.d.ts +1 -1
  162. package/dist/_internal/platform/runtime/events/routes.d.ts.map +1 -1
  163. package/dist/_internal/platform/runtime/events/routes.js +1 -0
  164. package/dist/_internal/platform/runtime/feature-flags/flags.d.ts.map +1 -1
  165. package/dist/_internal/platform/runtime/feature-flags/flags.js +9 -0
  166. package/dist/_internal/platform/runtime/feature-flags/gates.d.ts.map +1 -1
  167. package/dist/_internal/platform/runtime/feature-flags/gates.js +2 -0
  168. package/dist/_internal/platform/runtime/index.d.ts +2 -0
  169. package/dist/_internal/platform/runtime/index.d.ts.map +1 -1
  170. package/dist/_internal/platform/runtime/index.js +1 -0
  171. package/dist/_internal/platform/runtime/integration/helpers.d.ts +4 -0
  172. package/dist/_internal/platform/runtime/integration/helpers.d.ts.map +1 -1
  173. package/dist/_internal/platform/runtime/integration/helpers.js +4 -0
  174. package/dist/_internal/platform/runtime/security-settings.d.ts +19 -0
  175. package/dist/_internal/platform/runtime/security-settings.d.ts.map +1 -0
  176. package/dist/_internal/platform/runtime/security-settings.js +187 -0
  177. package/dist/_internal/platform/runtime/services.d.ts.map +1 -1
  178. package/dist/_internal/platform/runtime/services.js +1 -0
  179. package/dist/_internal/platform/security/user-auth.d.ts +1 -1
  180. package/dist/_internal/platform/security/user-auth.d.ts.map +1 -1
  181. package/dist/_internal/platform/security/user-auth.js +18 -3
  182. package/dist/_internal/platform/tools/edit/core.d.ts.map +1 -1
  183. package/dist/_internal/platform/tools/edit/core.js +4 -47
  184. package/dist/_internal/platform/tools/exec/runtime.d.ts.map +1 -1
  185. package/dist/_internal/platform/tools/exec/runtime.js +7 -1
  186. package/dist/_internal/platform/tools/exec/schema.d.ts +1 -0
  187. package/dist/_internal/platform/tools/exec/schema.d.ts.map +1 -1
  188. package/dist/_internal/platform/tools/exec/schema.js +1 -0
  189. package/dist/_internal/platform/tools/fetch/runtime.d.ts.map +1 -1
  190. package/dist/_internal/platform/tools/fetch/runtime.js +140 -19
  191. package/dist/_internal/platform/tools/fetch/schema.d.ts +1 -0
  192. package/dist/_internal/platform/tools/fetch/schema.d.ts.map +1 -1
  193. package/dist/_internal/platform/tools/fetch/schema.js +1 -0
  194. package/dist/_internal/platform/tools/find/executor.d.ts.map +1 -1
  195. package/dist/_internal/platform/tools/find/executor.js +7 -1
  196. package/dist/_internal/platform/tools/find/schema.d.ts.map +1 -1
  197. package/dist/_internal/platform/tools/find/schema.js +2 -0
  198. package/dist/_internal/platform/tools/read/index.d.ts.map +1 -1
  199. package/dist/_internal/platform/tools/read/index.js +7 -1
  200. package/dist/_internal/platform/tools/read/schema.d.ts +1 -0
  201. package/dist/_internal/platform/tools/read/schema.d.ts.map +1 -1
  202. package/dist/_internal/platform/tools/read/schema.js +1 -0
  203. package/dist/_internal/platform/tools/shared/process-manager.d.ts +2 -0
  204. package/dist/_internal/platform/tools/shared/process-manager.d.ts.map +1 -1
  205. package/dist/_internal/platform/tools/shared/process-manager.js +67 -5
  206. package/dist/_internal/platform/tools/write/index.d.ts.map +1 -1
  207. package/dist/_internal/platform/tools/write/index.js +3 -36
  208. package/dist/_internal/platform/utils/concurrency.d.ts +3 -0
  209. package/dist/_internal/platform/utils/concurrency.d.ts.map +1 -0
  210. package/dist/_internal/platform/utils/concurrency.js +17 -0
  211. package/dist/_internal/platform/utils/logger.d.ts.map +1 -1
  212. package/dist/_internal/platform/utils/logger.js +19 -1
  213. package/dist/_internal/platform/utils/request-body.d.ts +4 -0
  214. package/dist/_internal/platform/utils/request-body.d.ts.map +1 -0
  215. package/dist/_internal/platform/utils/request-body.js +45 -0
  216. package/dist/_internal/platform/version.js +1 -1
  217. package/dist/workers.d.ts +6 -0
  218. package/dist/workers.d.ts.map +1 -1
  219. package/dist/workers.js +55 -3
  220. package/package.json +1 -1
@@ -119,6 +119,7 @@ export const EXEC_TOOL_SCHEMA = {
119
119
  // cmd or cmd_base64 required — validated at runtime
120
120
  },
121
121
  minItems: 1,
122
+ maxItems: 10,
122
123
  },
123
124
  parallel: {
124
125
  type: 'boolean',
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/fetch/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAsF,MAAM,aAAa,CAAC;AAClI,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAUxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAK/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,GAAG,IAAI,CAAC;IACvE,QAAQ,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC;CACtE;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAMD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;IAC/D,OAAO,CAAC,eAAe,CAAK;IAE5B,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAOtE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAiBxC,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;CA8DpF;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC,CAE5G;AA+UD,wBAAgB,eAAe,CAC7B,IAAI,GAAE,gBAAqB,EAC3B,OAAO,sBAA4B,GAClC,IAAI,CAiCN"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/fetch/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAsF,MAAM,aAAa,CAAC;AAClI,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAUxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAM/E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,GAAG,IAAI,CAAC;IACvE,QAAQ,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC;CACtE;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AASD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;IAC/D,OAAO,CAAC,eAAe,CAAK;IAE5B,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAOtE,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAiBxC,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;CAkFpF;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC,CAE5G;AA8dD,wBAAgB,eAAe,CAC7B,IAAI,GAAE,gBAAqB,EAC3B,OAAO,sBAA4B,GAClC,IAAI,CAiCN"}
@@ -6,7 +6,11 @@ import { applyExtract, sniffContentType } from './extract.js';
6
6
  import { summarizeError } from '../../utils/error-display.js';
7
7
  import { instrumentedFetch } from '../../utils/fetch-with-timeout.js';
8
8
  import { toRecord } from '../../utils/record-coerce.js';
9
+ import { mapWithConcurrency } from '../../utils/concurrency.js';
9
10
  const MAX_CACHE_SIZE = 500;
11
+ const MAX_FETCH_URLS = 20;
12
+ const MAX_PARALLEL_FETCHES = 5;
13
+ const MAX_REDIRECTS = 10;
10
14
  const DEFAULT_TIMEOUT_MS = 30_000;
11
15
  export class FetchRuntimeService {
12
16
  responseCache = new Map();
@@ -43,6 +47,21 @@ export class FetchRuntimeService {
43
47
  const cacheTtlSeconds = input.cache_ttl_seconds ?? 0;
44
48
  const rateLimitMs = input.rate_limit_ms ?? 0;
45
49
  const maxContentLength = input.max_content_length;
50
+ if (input.urls.length > MAX_FETCH_URLS) {
51
+ return {
52
+ success: false,
53
+ summary: {
54
+ total: input.urls.length,
55
+ succeeded: 0,
56
+ failed: input.urls.length,
57
+ total_ms: 0,
58
+ },
59
+ results: [{
60
+ url: input.urls[0]?.url ?? '',
61
+ error: `Too many URLs: maximum ${MAX_FETCH_URLS} per fetch call`,
62
+ }],
63
+ };
64
+ }
46
65
  const sanitizeMode = resolveSanitizeMode(input.sanitize_mode);
47
66
  const trustTierConfig = {
48
67
  trustedHosts: input.trusted_hosts,
@@ -63,7 +82,7 @@ export class FetchRuntimeService {
63
82
  if (rateLimitMs > 0) {
64
83
  logger.debug('fetch tool: rate_limit_ms is ignored in parallel mode; set parallel: false to enforce rate limiting');
65
84
  }
66
- results = await Promise.all(input.urls.map((urlInput) => fetchOne(urlInput, fetchOpts, this)));
85
+ results = await mapWithConcurrency(input.urls, MAX_PARALLEL_FETCHES, (urlInput) => fetchOne(urlInput, fetchOpts, this));
67
86
  }
68
87
  else {
69
88
  results = [];
@@ -149,16 +168,25 @@ function encodeFormBodyData(bodyData) {
149
168
  }
150
169
  return params.toString();
151
170
  }
152
- async function fetchOneRaw(urlInput, headers, method, body, effectiveUrl) {
171
+ async function fetchOneRaw(urlInput, headers, method, body, effectiveUrl, trustTierConfig, sanitizationEnabled) {
153
172
  const controller = new AbortController();
154
173
  const timer = setTimeout(() => controller.abort(), urlInput.timeout_ms ?? DEFAULT_TIMEOUT_MS);
155
174
  try {
156
- const response = await instrumentedFetch(effectiveUrl, {
157
- method,
158
- headers: Object.keys(headers).length > 0 ? headers : undefined,
159
- body,
160
- signal: controller.signal,
161
- });
175
+ const response = sanitizationEnabled
176
+ ? await fetchWithValidatedRedirects({
177
+ url: effectiveUrl,
178
+ method,
179
+ headers,
180
+ body,
181
+ signal: controller.signal,
182
+ trustTierConfig,
183
+ })
184
+ : await instrumentedFetch(effectiveUrl, {
185
+ method,
186
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
187
+ body,
188
+ signal: controller.signal,
189
+ });
162
190
  clearTimeout(timer);
163
191
  return response;
164
192
  }
@@ -167,6 +195,69 @@ async function fetchOneRaw(urlInput, headers, method, body, effectiveUrl) {
167
195
  throw err;
168
196
  }
169
197
  }
198
+ async function fetchWithValidatedRedirects(input) {
199
+ let currentUrl = input.url;
200
+ let currentMethod = input.method;
201
+ let currentBody = input.body;
202
+ let currentHeaders = { ...input.headers };
203
+ for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount++) {
204
+ const response = await instrumentedFetch(currentUrl, {
205
+ method: currentMethod,
206
+ headers: Object.keys(currentHeaders).length > 0 ? currentHeaders : undefined,
207
+ body: currentBody,
208
+ signal: input.signal,
209
+ redirect: 'manual',
210
+ });
211
+ if (!isRedirectStatus(response.status))
212
+ return response;
213
+ const location = response.headers.get('location');
214
+ if (!location)
215
+ return response;
216
+ if (redirectCount === MAX_REDIRECTS) {
217
+ throw new Error(`Too many redirects after ${MAX_REDIRECTS} hops`);
218
+ }
219
+ const nextUrl = new URL(location, currentUrl).toString();
220
+ const nextHost = extractHostname(nextUrl);
221
+ if (nextHost !== null) {
222
+ const trustResult = classifyHostTrustTier(nextHost, input.trustTierConfig);
223
+ emitHostTrustTier(nextHost, nextUrl, trustResult);
224
+ if (trustResult.tier === 'blocked') {
225
+ if (trustResult.isSsrf)
226
+ emitSsrfDeny(nextHost, nextUrl, trustResult.reason);
227
+ throw new Error(`Redirect blocked: ${trustResult.reason}`);
228
+ }
229
+ }
230
+ if (shouldRewriteRedirectToGet(response.status, currentMethod)) {
231
+ currentMethod = 'GET';
232
+ currentBody = undefined;
233
+ currentHeaders = removeContentHeaders(currentHeaders);
234
+ }
235
+ if (new URL(nextUrl).origin !== new URL(currentUrl).origin) {
236
+ currentHeaders = removeCredentialHeaders(currentHeaders);
237
+ }
238
+ currentUrl = nextUrl;
239
+ }
240
+ throw new Error(`Too many redirects after ${MAX_REDIRECTS} hops`);
241
+ }
242
+ function isRedirectStatus(status) {
243
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
244
+ }
245
+ function shouldRewriteRedirectToGet(status, method) {
246
+ const upper = method.toUpperCase();
247
+ return status === 303 || ((status === 301 || status === 302) && upper === 'POST');
248
+ }
249
+ function removeContentHeaders(headers) {
250
+ return Object.fromEntries(Object.entries(headers).filter(([key]) => {
251
+ const normalized = key.toLowerCase();
252
+ return normalized !== 'content-type' && normalized !== 'content-length';
253
+ }));
254
+ }
255
+ function removeCredentialHeaders(headers) {
256
+ return Object.fromEntries(Object.entries(headers).filter(([key]) => {
257
+ const normalized = key.toLowerCase();
258
+ return normalized !== 'authorization' && normalized !== 'cookie' && normalized !== 'proxy-authorization';
259
+ }));
260
+ }
170
261
  function prepareFetchHeaders(urlInput) {
171
262
  const headers = { ...(urlInput.headers ?? {}) };
172
263
  if (urlInput.auth) {
@@ -269,28 +360,22 @@ async function fetchOne(urlInput, opts, runtime) {
269
360
  const { headers, body: requestBody } = await prepareFetchRequest(urlInput, deps);
270
361
  const startTime = performance.now();
271
362
  try {
272
- let response = await fetchOneRaw(urlInput, headers, method, requestBody, effectiveUrl);
363
+ let response = await fetchOneRaw(urlInput, headers, method, requestBody, effectiveUrl, trustTierConfig, sanitizationEnabled);
273
364
  const retryOnAuth = urlInput.retry_on_auth ?? (urlInput.service !== undefined);
274
365
  if (response.status === 401 && retryOnAuth && urlInput.service && !(requestBody instanceof FormData)) {
275
366
  const refreshedHeaders = await deps.serviceRegistry?.resolveAuth(urlInput.service);
276
367
  if (refreshedHeaders) {
277
368
  const retryHeaders = { ...headers };
278
369
  Object.assign(retryHeaders, refreshedHeaders);
279
- response = await fetchOneRaw(urlInput, retryHeaders, method, requestBody, effectiveUrl);
370
+ response = await fetchOneRaw(urlInput, retryHeaders, method, requestBody, effectiveUrl, trustTierConfig, sanitizationEnabled);
280
371
  }
281
372
  }
282
373
  const durationMs = Math.round(performance.now() - startTime);
283
374
  let contentType = response.headers.get('content-type') ?? '';
284
- let rawBody = await response.text();
375
+ const bodyResult = await readResponseText(response, effectiveMaxContent);
376
+ let rawBody = bodyResult.text;
285
377
  contentType = sniffContentType(contentType, rawBody);
286
- let truncated = false;
287
- if (effectiveMaxContent !== undefined) {
288
- const buf = Buffer.from(rawBody, 'utf-8');
289
- if (buf.length > effectiveMaxContent) {
290
- rawBody = buf.subarray(0, effectiveMaxContent).toString('utf-8');
291
- truncated = true;
292
- }
293
- }
378
+ const truncated = bodyResult.truncated;
294
379
  const byteSize = Buffer.byteLength(rawBody, 'utf-8');
295
380
  const result = buildFetchResultBase(urlInput, response, durationMs);
296
381
  if (verbosity === 'count_only') {
@@ -358,6 +443,42 @@ async function fetchOne(urlInput, opts, runtime) {
358
443
  return { url: urlInput.url, error: message, duration_ms: durationMs };
359
444
  }
360
445
  }
446
+ async function readResponseText(response, maxBytes) {
447
+ if (maxBytes === undefined || maxBytes <= 0 || !response.body) {
448
+ return { text: await response.text(), truncated: false };
449
+ }
450
+ const reader = response.body.getReader();
451
+ const decoder = new TextDecoder();
452
+ let total = 0;
453
+ let text = '';
454
+ let truncated = false;
455
+ try {
456
+ for (;;) {
457
+ const { done, value } = await reader.read();
458
+ if (done)
459
+ break;
460
+ const remaining = maxBytes - total;
461
+ if (remaining <= 0) {
462
+ truncated = true;
463
+ await reader.cancel('Response body limit reached').catch(() => { });
464
+ break;
465
+ }
466
+ const chunk = value.byteLength > remaining ? value.subarray(0, remaining) : value;
467
+ text += decoder.decode(chunk, { stream: true });
468
+ total += chunk.byteLength;
469
+ if (value.byteLength > remaining) {
470
+ truncated = true;
471
+ await reader.cancel('Response body limit reached').catch(() => { });
472
+ break;
473
+ }
474
+ }
475
+ text += decoder.decode();
476
+ return { text, truncated };
477
+ }
478
+ finally {
479
+ reader.releaseLock();
480
+ }
481
+ }
361
482
  function cacheSuccessfulGet(runtime, cacheTtlSeconds, method, key, result) {
362
483
  if (cacheTtlSeconds > 0 && method === 'GET') {
363
484
  runtime.cacheSet(key, { data: result, timestamp: Date.now(), ttl: cacheTtlSeconds });
@@ -122,6 +122,7 @@ export declare const FETCH_TOOL_SCHEMA: {
122
122
  readonly required: readonly ["url"];
123
123
  };
124
124
  readonly minItems: 1;
125
+ readonly maxItems: 20;
125
126
  };
126
127
  readonly extract: {
127
128
  readonly type: "string";
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/fetch/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/fetch/schema.ts"],"names":[],"mappings":"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"}
@@ -113,6 +113,7 @@ export const FETCH_TOOL_SCHEMA = {
113
113
  required: ['url'],
114
114
  },
115
115
  minItems: 1,
116
+ maxItems: 20,
116
117
  },
117
118
  extract: {
118
119
  type: 'string',
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/find/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AASjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,IAAI,EAC3D,OAAO,qBAA2B,GACjC,IAAI,CAuEN"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/find/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AASjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAOjD,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,IAAI,EAC3D,OAAO,qBAA2B,GACjC,IAAI,CA0EN"}
@@ -7,6 +7,9 @@ import { executeStructuralQuery } from './structural.js';
7
7
  import { executeSymbolsQuery } from './symbols.js';
8
8
  import { FindRuntimeService } from './shared.js';
9
9
  import { summarizeError } from '../../utils/error-display.js';
10
+ import { mapWithConcurrency } from '../../utils/concurrency.js';
11
+ const MAX_FIND_QUERIES = 20;
12
+ const MAX_PARALLEL_FIND_QUERIES = 5;
10
13
  export function createFindTool(projectRoot, featureFlags, runtime = new FindRuntimeService()) {
11
14
  if (typeof projectRoot !== 'string' || projectRoot.trim().length === 0) {
12
15
  throw new Error('createFindTool requires projectRoot');
@@ -18,6 +21,9 @@ export function createFindTool(projectRoot, featureFlags, runtime = new FindRunt
18
21
  if (!Array.isArray(args.queries) || args.queries.length === 0) {
19
22
  return { success: false, error: 'Missing or empty "queries" array' };
20
23
  }
24
+ if (args.queries.length > MAX_FIND_QUERIES) {
25
+ return { success: false, error: `Too many queries: maximum ${MAX_FIND_QUERIES} per find call` };
26
+ }
21
27
  const input = args;
22
28
  const output = input.output ?? {};
23
29
  const parallel = input.parallel !== false;
@@ -48,7 +54,7 @@ export function createFindTool(projectRoot, featureFlags, runtime = new FindRunt
48
54
  };
49
55
  let pairs;
50
56
  if (parallel) {
51
- pairs = await Promise.all(input.queries.map(runQuery));
57
+ pairs = await mapWithConcurrency(input.queries, MAX_PARALLEL_FIND_QUERIES, runQuery);
52
58
  }
53
59
  else {
54
60
  pairs = [];
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/find/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,cAwQxB,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/find/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,cA0QxB,CAAC"}
@@ -186,6 +186,8 @@ export const findSchema = {
186
186
  },
187
187
  },
188
188
  },
189
+ minItems: 1,
190
+ maxItems: 20,
189
191
  },
190
192
  output: {
191
193
  type: 'object',
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/read/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAIjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAUhE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpE,qBAAa,QAAS,YAAW,IAAI;IACnC,QAAQ,CAAC,UAAU,EAAE,cAAc,CASjC;IAEF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsD;gBAGrF,YAAY,EAAE,YAAY,EAC1B,SAAS,CAAC,EAAE,cAAc,EAC1B,gBAAgB,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,YAAY,CAAC;IAOlE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;YAa9F,QAAQ;CAuHvB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/read/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAIjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAWhE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKpE,qBAAa,QAAS,YAAW,IAAI;IACnC,QAAQ,CAAC,UAAU,EAAE,cAAc,CASjC;IAEF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsD;gBAGrF,YAAY,EAAE,YAAY,EAC1B,SAAS,CAAC,EAAE,cAAc,EAC1B,gBAAgB,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,YAAY,CAAC;IAOlE,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;YAgB9F,QAAQ;CAwHvB"}
@@ -6,6 +6,9 @@ import { CodeIntelligence } from '../../intelligence/facade.js';
6
6
  import { logger } from '../../utils/logger.js';
7
7
  import { summarizeError } from '../../utils/error-display.js';
8
8
  import { paginateFiles, readOneFile, } from './file-readers.js';
9
+ import { mapWithConcurrency } from '../../utils/concurrency.js';
10
+ const MAX_READ_FILES = 50;
11
+ const MAX_PARALLEL_READ_FILES = 8;
9
12
  export class ReadTool {
10
13
  definition = {
11
14
  name: 'read',
@@ -28,6 +31,9 @@ export class ReadTool {
28
31
  if (!Array.isArray(args.files) || args.files.length === 0) {
29
32
  return { success: false, error: 'Missing or empty "files" array' };
30
33
  }
34
+ if (args.files.length > MAX_READ_FILES) {
35
+ return { success: false, error: `Too many files: maximum ${MAX_READ_FILES} per read call` };
36
+ }
31
37
  try {
32
38
  return await this._execute(args);
33
39
  }
@@ -63,7 +69,7 @@ export class ReadTool {
63
69
  .map(({ f }) => f.path);
64
70
  paginationInfo = { page, total_pages: totalPages, pending_files: pendingFiles };
65
71
  }
66
- const results = await Promise.all(filesToProcess.map((f) => readOneFile(f, globalExtract, format, includeLineNumbers, maxPerItem, this.fileCache, this.projectIndex, globalImageMode, globalMaxImageSize, this.codeIntelligence)));
72
+ const results = await mapWithConcurrency(filesToProcess, MAX_PARALLEL_READ_FILES, (f) => readOneFile(f, globalExtract, format, includeLineNumbers, maxPerItem, this.fileCache, this.projectIndex, globalImageMode, globalMaxImageSize, this.codeIntelligence));
67
73
  if (maxTokens !== undefined) {
68
74
  let usedTokens = 0;
69
75
  for (const r of results) {
@@ -55,6 +55,7 @@ export declare const READ_TOOL_SCHEMA: {
55
55
  readonly required: readonly ["path"];
56
56
  };
57
57
  readonly minItems: 1;
58
+ readonly maxItems: 50;
58
59
  };
59
60
  readonly extract: {
60
61
  readonly type: "string";
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/read/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkHnB,CAAC;AAEX,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,KAAK,GAAG,OAAO,CAAC;AAE9E,+BAA+B;AAC/B,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAE7E,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED,0CAA0C;AAC1C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,YAAY,CAAC;QACtB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/read/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmHnB,CAAC;AAEX,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,KAAK,GAAG,OAAO,CAAC;AAE9E,+BAA+B;AAC/B,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAAC;AAE7E,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED,0CAA0C;AAC1C,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,YAAY,CAAC;QACtB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB"}
@@ -53,6 +53,7 @@ export const READ_TOOL_SCHEMA = {
53
53
  required: ['path'],
54
54
  },
55
55
  minItems: 1,
56
+ maxItems: 50,
56
57
  },
57
58
  extract: {
58
59
  type: 'string',
@@ -19,6 +19,7 @@ export interface BackgroundProcess {
19
19
  * Null if the process completed normally or SIGKILL was never scheduled.
20
20
  */
21
21
  killDeadline: number | null;
22
+ completedAt?: number;
22
23
  }
23
24
  export interface SpawnOptions {
24
25
  /** Abort the process if it hasn't completed within this many ms. Default: 60000. */
@@ -76,5 +77,6 @@ export declare class ProcessManager {
76
77
  * Returns a BgCommandResult if the command was handled, null otherwise.
77
78
  */
78
79
  handleCommand(cmd: string): BgCommandResult | null;
80
+ private pruneCompletedProcesses;
79
81
  }
80
82
  //# sourceMappingURL=process-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/shared/process-manager.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF;;;;;GAKG;AAIH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAID,MAAM,WAAW,YAAY;IAC3B,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAID,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAID,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,UAAU,CAAwC;IAC1D,OAAO,CAAC,MAAM,CAAmD;IAIjE,OAAO,CAAC,KAAK;IAMb;;;;;;;;;;OAUG;IACG,KAAK,CACT,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACvC,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,eAAe,CAAC;IA2F3B,iFAAiF;IACjF,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIpD,kEAAkE;IAClE,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IASrE;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAczB,yEAAyE;IACzE,IAAI,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IASvE;;;OAGG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;CAmDnD"}
1
+ {"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/shared/process-manager.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAErF;;;;;GAKG;AAIH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAQD,MAAM,WAAW,YAAY;IAC3B,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kFAAkF;IAClF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAID,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAID,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,UAAU,CAAwC;IAC1D,OAAO,CAAC,MAAM,CAAmD;IAIjE,OAAO,CAAC,KAAK;IAMb;;;;;;;;;;OAUG;IACG,KAAK,CACT,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACvC,IAAI,CAAC,EAAE,YAAY,GAClB,OAAO,CAAC,eAAe,CAAC;IAkG3B,iFAAiF;IACjF,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAKpD,kEAAkE;IAClE,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IAUrE;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAczB,yEAAyE;IACzE,IAAI,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAUvE;;;OAGG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAqDlD,OAAO,CAAC,uBAAuB;CAWhC"}
@@ -1,4 +1,7 @@
1
1
  /** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
2
+ const MAX_PROCESS_OUTPUT_BYTES = 256 * 1024;
3
+ const MAX_COMPLETED_PROCESSES = 100;
4
+ const COMPLETED_PROCESS_TTL_MS = 30 * 60 * 1000;
2
5
  // ─── ProcessManager ───────────────────────────────────────────────────────────
3
6
  export class ProcessManager {
4
7
  _counter = 0;
@@ -35,6 +38,7 @@ export class ProcessManager {
35
38
  done: false,
36
39
  killDeadline: null,
37
40
  };
41
+ this.pruneCompletedProcesses();
38
42
  this._processes.set(id, entry);
39
43
  const cleanEnv = Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== undefined));
40
44
  const mergedEnv = { ...cleanEnv, ...env };
@@ -58,15 +62,18 @@ export class ProcessManager {
58
62
  // Cast stdout/stderr to ReadableStream — Bun guarantees these are ReadableStream
59
63
  // when stdout/stderr is set to 'pipe', but the return type is a union.
60
64
  const collectionPromise = (async () => {
61
- const [stdoutText, stderrText] = await Promise.all([
62
- new Response(proc.stdout).text(),
63
- new Response(proc.stderr).text(),
65
+ const [stdoutText, stderrText, exitCode] = await Promise.all([
66
+ readProcessStream(proc.stdout),
67
+ readProcessStream(proc.stderr),
68
+ proc.exited,
64
69
  ]);
65
70
  entry.stdout.push(stdoutText);
66
71
  entry.stderr.push(stderrText);
67
- entry.exitCode = await proc.exited;
72
+ entry.exitCode = exitCode;
68
73
  entry.done = true;
74
+ entry.completedAt = Date.now();
69
75
  this._procs.delete(id);
76
+ this.pruneCompletedProcesses();
70
77
  })();
71
78
  // Timeout watchdog: SIGTERM → wait grace → SIGKILL
72
79
  const timeoutHandle = setTimeout(async () => {
@@ -77,7 +84,7 @@ export class ProcessManager {
77
84
  }
78
85
  catch { /* already exited */ }
79
86
  entry.killDeadline = Date.now() + sigtermGraceMs;
80
- await new Promise((r) => setTimeout(r, sigtermGraceMs));
87
+ await sleep(sigtermGraceMs);
81
88
  if (!entry.done) {
82
89
  try {
83
90
  proc.kill('SIGKILL');
@@ -85,13 +92,16 @@ export class ProcessManager {
85
92
  catch { /* already exited */ }
86
93
  }
87
94
  }, timeoutMs);
95
+ timeoutHandle.unref?.();
88
96
  // Reject the spawn promise if the process errors immediately (ENOENT/EACCES
89
97
  // on the child process level) — the outer try/catch handles Bun.spawn throws;
90
98
  // this handles async failures surfaced via proc.exited rejecting.
91
99
  void collectionPromise.catch(() => {
92
100
  clearTimeout(timeoutHandle);
93
101
  entry.done = true;
102
+ entry.completedAt = Date.now();
94
103
  this._procs.delete(id);
104
+ this.pruneCompletedProcesses();
95
105
  });
96
106
  // Clear the timeout watchdog once the process completes naturally
97
107
  void collectionPromise.then(() => {
@@ -109,10 +119,12 @@ export class ProcessManager {
109
119
  }
110
120
  /** Get the status record for a background process, or undefined if not found. */
111
121
  getStatus(id) {
122
+ this.pruneCompletedProcesses();
112
123
  return this._processes.get(id);
113
124
  }
114
125
  /** Get the accumulated stdout/stderr for a background process. */
115
126
  getOutput(id) {
127
+ this.pruneCompletedProcesses();
116
128
  const entry = this._processes.get(id);
117
129
  if (!entry)
118
130
  return undefined;
@@ -143,6 +155,7 @@ export class ProcessManager {
143
155
  }
144
156
  /** List all tracked background processes with their status summaries. */
145
157
  list() {
158
+ this.pruneCompletedProcesses();
146
159
  return Array.from(this._processes.values()).map((e) => ({
147
160
  id: e.id,
148
161
  pid: e.pid,
@@ -155,6 +168,7 @@ export class ProcessManager {
155
168
  * Returns a BgCommandResult if the command was handled, null otherwise.
156
169
  */
157
170
  handleCommand(cmd) {
171
+ this.pruneCompletedProcesses();
158
172
  // bg_status <id>
159
173
  const statusMatch = cmd.match(/^bg_status\s+(\S+)$/);
160
174
  if (statusMatch) {
@@ -201,4 +215,52 @@ export class ProcessManager {
201
215
  }
202
216
  return null;
203
217
  }
218
+ pruneCompletedProcesses(now = Date.now()) {
219
+ const completed = [...this._processes.values()]
220
+ .filter((entry) => entry.done)
221
+ .sort((a, b) => (b.completedAt ?? b.startTime) - (a.completedAt ?? a.startTime));
222
+ for (let i = 0; i < completed.length; i++) {
223
+ const entry = completed[i];
224
+ const completedAt = entry.completedAt ?? entry.startTime;
225
+ if (now - completedAt <= COMPLETED_PROCESS_TTL_MS && i < MAX_COMPLETED_PROCESSES)
226
+ continue;
227
+ this._processes.delete(entry.id);
228
+ }
229
+ }
230
+ }
231
+ async function readProcessStream(stream) {
232
+ const reader = stream.getReader();
233
+ const decoder = new TextDecoder();
234
+ let total = 0;
235
+ let output = '';
236
+ let truncated = false;
237
+ try {
238
+ for (;;) {
239
+ const { done, value } = await reader.read();
240
+ if (done)
241
+ break;
242
+ const remaining = MAX_PROCESS_OUTPUT_BYTES - total;
243
+ if (remaining > 0) {
244
+ const chunk = value.byteLength > remaining ? value.subarray(0, remaining) : value;
245
+ output += decoder.decode(chunk, { stream: true });
246
+ total += chunk.byteLength;
247
+ }
248
+ if (value.byteLength > remaining) {
249
+ truncated = true;
250
+ }
251
+ }
252
+ output += decoder.decode();
253
+ return truncated
254
+ ? `${output}\n[goodvibes: output truncated after ${MAX_PROCESS_OUTPUT_BYTES} bytes]\n`
255
+ : output;
256
+ }
257
+ finally {
258
+ reader.releaseLock();
259
+ }
260
+ }
261
+ function sleep(ms) {
262
+ return new Promise((resolve) => {
263
+ const timer = setTimeout(resolve, ms);
264
+ timer.unref?.();
265
+ });
204
266
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/write/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAGjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAIxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAkV7E,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,aAAa,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IAC3C,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChC,aAAa,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,cAAc,CAAC,CAAC;CAC5D,GAAG,IAAI,CAmPP"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/write/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAGjE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAIxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AA+S7E,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,aAAa,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IAC3C,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAChC,aAAa,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,cAAc,CAAC,CAAC;CAC5D,GAAG,IAAI,CAmPP"}
@@ -1,5 +1,5 @@
1
- import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, copyFileSync, unlinkSync, realpathSync } from 'node:fs';
2
- import { dirname, extname, join, relative, resolve } from 'node:path';
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, copyFileSync, unlinkSync } from 'node:fs';
2
+ import { dirname, extname, join, relative } from 'node:path';
3
3
  import { randomBytes } from 'node:crypto';
4
4
  import { WRITE_SCHEMA } from './schema.js';
5
5
  import { runValidators, formatValidatorFailure } from '../shared/validators.js';
@@ -10,6 +10,7 @@ import { AutoHealer } from '../shared/auto-heal.js';
10
10
  import { isNotebookFile } from '../../utils/notebook.js';
11
11
  import { logger } from '../../utils/logger.js';
12
12
  import { summarizeError } from '../../utils/error-display.js';
13
+ import { resolveAndValidatePath } from '../../utils/path-safety.js';
13
14
  // ---------------------------------------------------------------------------
14
15
  // Helpers
15
16
  // ---------------------------------------------------------------------------
@@ -31,40 +32,6 @@ function buildBackupPath(resolvedPath, projectRoot) {
31
32
  const rel = relative(projectRoot, resolvedPath);
32
33
  return join(projectRoot, '.goodvibes', '.backups', `${rel}.${Date.now()}`);
33
34
  }
34
- function nearestExistingPath(path) {
35
- let current = path;
36
- while (!existsSync(current)) {
37
- const parent = dirname(current);
38
- if (parent === current)
39
- return current;
40
- current = parent;
41
- }
42
- return current;
43
- }
44
- function isInsideRoot(root, candidate) {
45
- const rel = relative(root, candidate);
46
- return rel === '' || (!rel.startsWith('..') && !rel.includes('/..') && !rel.startsWith('/'));
47
- }
48
- function resolveAndValidatePath(inputPath, projectRoot) {
49
- const root = realpathSync(resolve(projectRoot));
50
- const resolved = resolve(root, inputPath);
51
- const rel = relative(root, resolved);
52
- if (rel.startsWith('..') || rel.includes('/..')) {
53
- throw new Error(`Path '${inputPath}' is outside the project root`);
54
- }
55
- const existingPath = nearestExistingPath(resolved);
56
- const realExistingPath = realpathSync(existingPath);
57
- if (!isInsideRoot(root, realExistingPath)) {
58
- throw new Error(`Path '${inputPath}' is outside the project root`);
59
- }
60
- if (existsSync(resolved)) {
61
- const realTargetPath = realpathSync(resolved);
62
- if (!isInsideRoot(root, realTargetPath)) {
63
- throw new Error(`Path '${inputPath}' is outside the project root`);
64
- }
65
- }
66
- return resolved;
67
- }
68
35
  /** Module-level constant — avoids re-allocating the Set on every validation call. */
69
36
  const VALID_CELL_TYPES = new Set(['code', 'markdown', 'raw']);
70
37
  /**
@@ -0,0 +1,3 @@
1
+ /** Run async work with a fixed concurrency cap while preserving input order. */
2
+ export declare function mapWithConcurrency<T, R>(items: readonly T[], limit: number, worker: (item: T, index: number) => Promise<R>): Promise<R[]>;
3
+ //# sourceMappingURL=concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/utils/concurrency.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAC3C,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,CAAC,EAAE,CAAC,CAmBd"}
@@ -0,0 +1,17 @@
1
+ /** Run async work with a fixed concurrency cap while preserving input order. */
2
+ export async function mapWithConcurrency(items, limit, worker) {
3
+ const concurrency = Math.max(1, Math.floor(limit));
4
+ const results = new Array(items.length);
5
+ let nextIndex = 0;
6
+ async function runWorker() {
7
+ for (;;) {
8
+ const index = nextIndex++;
9
+ if (index >= items.length)
10
+ return;
11
+ results[index] = await worker(items[index], index);
12
+ }
13
+ }
14
+ const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => runWorker());
15
+ await Promise.all(workers);
16
+ return results;
17
+ }