@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.
- package/dist/_internal/contracts/artifacts/operator-contract.json +178 -6
- package/dist/_internal/contracts/generated/foundation-client-types.d.ts +16 -1
- package/dist/_internal/contracts/generated/foundation-client-types.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/foundation-metadata.d.ts +2 -2
- package/dist/_internal/contracts/generated/foundation-metadata.js +2 -2
- package/dist/_internal/contracts/generated/operator-contract.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/operator-contract.js +178 -6
- package/dist/_internal/contracts/generated/operator-method-ids.d.ts +1 -1
- package/dist/_internal/contracts/generated/operator-method-ids.d.ts.map +1 -1
- package/dist/_internal/contracts/generated/operator-method-ids.js +1 -0
- package/dist/_internal/daemon/context.d.ts +1 -0
- package/dist/_internal/daemon/context.d.ts.map +1 -1
- package/dist/_internal/daemon/integration-route-types.d.ts +1 -0
- package/dist/_internal/daemon/integration-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/integration-routes.d.ts +1 -1
- package/dist/_internal/daemon/integration-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/integration-routes.js +3 -0
- package/dist/_internal/daemon/operator.d.ts +1 -1
- package/dist/_internal/daemon/operator.d.ts.map +1 -1
- package/dist/_internal/daemon/operator.js +2 -0
- package/dist/_internal/daemon/runtime-route-types.d.ts +1 -1
- package/dist/_internal/daemon/runtime-route-types.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/discord/index.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/discord/index.js +4 -5
- package/dist/_internal/platform/adapters/github/index.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/github/index.js +4 -5
- package/dist/_internal/platform/adapters/google-chat/index.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/google-chat/index.js +7 -5
- package/dist/_internal/platform/adapters/helpers.d.ts +2 -1
- package/dist/_internal/platform/adapters/helpers.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/helpers.js +3 -34
- package/dist/_internal/platform/adapters/homeassistant/index.d.ts +3 -0
- package/dist/_internal/platform/adapters/homeassistant/index.d.ts.map +1 -0
- package/dist/_internal/platform/adapters/homeassistant/index.js +185 -0
- package/dist/_internal/platform/adapters/index.d.ts +1 -0
- package/dist/_internal/platform/adapters/index.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/index.js +1 -0
- package/dist/_internal/platform/adapters/mattermost/index.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/mattermost/index.js +6 -2
- package/dist/_internal/platform/adapters/slack/index.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/slack/index.js +4 -5
- package/dist/_internal/platform/adapters/telegram/index.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/telegram/index.js +7 -5
- package/dist/_internal/platform/adapters/types.d.ts +1 -1
- package/dist/_internal/platform/adapters/types.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/webhook/index.d.ts.map +1 -1
- package/dist/_internal/platform/adapters/webhook/index.js +4 -1
- package/dist/_internal/platform/automation/types.d.ts +1 -1
- package/dist/_internal/platform/automation/types.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/accounts.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/accounts.js +23 -0
- package/dist/_internal/platform/channels/builtin/contracts.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/contracts.js +9 -0
- package/dist/_internal/platform/channels/builtin/descriptors.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/descriptors.js +9 -2
- package/dist/_internal/platform/channels/builtin/homeassistant.d.ts +64 -0
- package/dist/_internal/platform/channels/builtin/homeassistant.d.ts.map +1 -0
- package/dist/_internal/platform/channels/builtin/homeassistant.js +391 -0
- package/dist/_internal/platform/channels/builtin/plugins.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/plugins.js +2 -1
- package/dist/_internal/platform/channels/builtin/presentation.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/presentation.js +4 -0
- package/dist/_internal/platform/channels/builtin/rendering.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/rendering.js +7 -0
- package/dist/_internal/platform/channels/builtin/setup-schema.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/setup-schema.js +53 -0
- package/dist/_internal/platform/channels/builtin/shared.d.ts +1 -1
- package/dist/_internal/platform/channels/builtin/shared.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/shared.js +2 -0
- package/dist/_internal/platform/channels/builtin/surfaces.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/surfaces.js +1 -0
- package/dist/_internal/platform/channels/builtin/targets.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin/targets.js +24 -0
- package/dist/_internal/platform/channels/builtin-runtime.d.ts.map +1 -1
- package/dist/_internal/platform/channels/builtin-runtime.js +6 -0
- package/dist/_internal/platform/channels/delivery/strategies-core.d.ts +1 -0
- package/dist/_internal/platform/channels/delivery/strategies-core.d.ts.map +1 -1
- package/dist/_internal/platform/channels/delivery/strategies-core.js +60 -1
- package/dist/_internal/platform/channels/delivery/types.d.ts +2 -0
- package/dist/_internal/platform/channels/delivery/types.d.ts.map +1 -1
- package/dist/_internal/platform/channels/delivery-router.d.ts.map +1 -1
- package/dist/_internal/platform/channels/delivery-router.js +2 -1
- package/dist/_internal/platform/channels/reply-pipeline.d.ts.map +1 -1
- package/dist/_internal/platform/channels/reply-pipeline.js +9 -0
- package/dist/_internal/platform/channels/route-manager.d.ts.map +1 -1
- package/dist/_internal/platform/channels/route-manager.js +1 -0
- package/dist/_internal/platform/channels/surface-registry.d.ts.map +1 -1
- package/dist/_internal/platform/channels/surface-registry.js +4 -0
- package/dist/_internal/platform/channels/types.d.ts +1 -1
- package/dist/_internal/platform/channels/types.d.ts.map +1 -1
- package/dist/_internal/platform/cloudflare/manager.d.ts +1 -1
- package/dist/_internal/platform/cloudflare/manager.d.ts.map +1 -1
- package/dist/_internal/platform/cloudflare/manager.js +27 -24
- package/dist/_internal/platform/cloudflare/types.d.ts +5 -0
- package/dist/_internal/platform/cloudflare/types.d.ts.map +1 -1
- package/dist/_internal/platform/cloudflare/utils.d.ts.map +1 -1
- package/dist/_internal/platform/cloudflare/utils.js +4 -10
- package/dist/_internal/platform/companion/companion-chat-manager.d.ts +24 -4
- package/dist/_internal/platform/companion/companion-chat-manager.d.ts.map +1 -1
- package/dist/_internal/platform/companion/companion-chat-manager.js +128 -78
- package/dist/_internal/platform/config/schema-domain-surfaces.d.ts +12 -0
- package/dist/_internal/platform/config/schema-domain-surfaces.d.ts.map +1 -1
- package/dist/_internal/platform/config/schema-domain-surfaces.js +67 -0
- package/dist/_internal/platform/config/schema-types.d.ts +15 -2
- package/dist/_internal/platform/config/schema-types.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/gateway-utils.d.ts +37 -0
- package/dist/_internal/platform/control-plane/gateway-utils.d.ts.map +1 -0
- package/dist/_internal/platform/control-plane/gateway-utils.js +97 -0
- package/dist/_internal/platform/control-plane/gateway.d.ts +4 -9
- package/dist/_internal/platform/control-plane/gateway.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/gateway.js +26 -61
- package/dist/_internal/platform/control-plane/method-catalog-runtime.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/method-catalog-runtime.js +11 -1
- package/dist/_internal/platform/control-plane/operator-contract-schemas-admin.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/operator-contract-schemas-admin.js +3 -2
- package/dist/_internal/platform/control-plane/operator-contract-schemas-control.d.ts +1 -0
- package/dist/_internal/platform/control-plane/operator-contract-schemas-control.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/operator-contract-schemas-control.js +26 -0
- package/dist/_internal/platform/control-plane/routes/operator.d.ts +1 -1
- package/dist/_internal/platform/control-plane/routes/operator.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/routes/operator.js +2 -0
- package/dist/_internal/platform/control-plane/session-types.d.ts +2 -1
- package/dist/_internal/platform/control-plane/session-types.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/types.d.ts +1 -1
- package/dist/_internal/platform/control-plane/types.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/control-plane.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/control-plane.js +50 -6
- package/dist/_internal/platform/daemon/facade-composition.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/facade-composition.js +30 -2
- package/dist/_internal/platform/daemon/facade-types.d.ts +1 -1
- package/dist/_internal/platform/daemon/facade-types.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http/homeassistant-routes.d.ts +40 -0
- package/dist/_internal/platform/daemon/http/homeassistant-routes.d.ts.map +1 -0
- package/dist/_internal/platform/daemon/http/homeassistant-routes.js +468 -0
- package/dist/_internal/platform/daemon/http/router.d.ts +4 -2
- package/dist/_internal/platform/daemon/http/router.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http/router.js +28 -16
- package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts +1 -1
- package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http-listener.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http-listener.js +4 -8
- package/dist/_internal/platform/daemon/surface-actions.d.ts +1 -1
- package/dist/_internal/platform/daemon/surface-actions.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/surface-delivery.d.ts +1 -1
- package/dist/_internal/platform/daemon/surface-delivery.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/surface-delivery.js +15 -0
- package/dist/_internal/platform/daemon/surface-policy.d.ts +1 -1
- package/dist/_internal/platform/daemon/surface-policy.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/surface-policy.js +8 -0
- package/dist/_internal/platform/daemon/types.d.ts +3 -3
- package/dist/_internal/platform/daemon/types.d.ts.map +1 -1
- package/dist/_internal/platform/integrations/homeassistant.d.ts +62 -0
- package/dist/_internal/platform/integrations/homeassistant.d.ts.map +1 -0
- package/dist/_internal/platform/integrations/homeassistant.js +174 -0
- package/dist/_internal/platform/integrations/index.d.ts +2 -0
- package/dist/_internal/platform/integrations/index.d.ts.map +1 -1
- package/dist/_internal/platform/integrations/index.js +1 -0
- package/dist/_internal/platform/runtime/events/control-plane.d.ts +1 -1
- package/dist/_internal/platform/runtime/events/control-plane.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/events/control-plane.js +1 -0
- package/dist/_internal/platform/runtime/events/routes.d.ts +1 -1
- package/dist/_internal/platform/runtime/events/routes.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/events/routes.js +1 -0
- package/dist/_internal/platform/runtime/feature-flags/flags.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/feature-flags/flags.js +9 -0
- package/dist/_internal/platform/runtime/feature-flags/gates.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/feature-flags/gates.js +2 -0
- package/dist/_internal/platform/runtime/index.d.ts +2 -0
- package/dist/_internal/platform/runtime/index.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/index.js +1 -0
- package/dist/_internal/platform/runtime/integration/helpers.d.ts +4 -0
- package/dist/_internal/platform/runtime/integration/helpers.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/integration/helpers.js +4 -0
- package/dist/_internal/platform/runtime/security-settings.d.ts +19 -0
- package/dist/_internal/platform/runtime/security-settings.d.ts.map +1 -0
- package/dist/_internal/platform/runtime/security-settings.js +187 -0
- package/dist/_internal/platform/runtime/services.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/services.js +1 -0
- package/dist/_internal/platform/security/user-auth.d.ts +1 -1
- package/dist/_internal/platform/security/user-auth.d.ts.map +1 -1
- package/dist/_internal/platform/security/user-auth.js +18 -3
- package/dist/_internal/platform/tools/edit/core.d.ts.map +1 -1
- package/dist/_internal/platform/tools/edit/core.js +4 -47
- package/dist/_internal/platform/tools/exec/runtime.d.ts.map +1 -1
- package/dist/_internal/platform/tools/exec/runtime.js +7 -1
- package/dist/_internal/platform/tools/exec/schema.d.ts +1 -0
- package/dist/_internal/platform/tools/exec/schema.d.ts.map +1 -1
- package/dist/_internal/platform/tools/exec/schema.js +1 -0
- package/dist/_internal/platform/tools/fetch/runtime.d.ts.map +1 -1
- package/dist/_internal/platform/tools/fetch/runtime.js +140 -19
- package/dist/_internal/platform/tools/fetch/schema.d.ts +1 -0
- package/dist/_internal/platform/tools/fetch/schema.d.ts.map +1 -1
- package/dist/_internal/platform/tools/fetch/schema.js +1 -0
- package/dist/_internal/platform/tools/find/executor.d.ts.map +1 -1
- package/dist/_internal/platform/tools/find/executor.js +7 -1
- package/dist/_internal/platform/tools/find/schema.d.ts.map +1 -1
- package/dist/_internal/platform/tools/find/schema.js +2 -0
- package/dist/_internal/platform/tools/read/index.d.ts.map +1 -1
- package/dist/_internal/platform/tools/read/index.js +7 -1
- package/dist/_internal/platform/tools/read/schema.d.ts +1 -0
- package/dist/_internal/platform/tools/read/schema.d.ts.map +1 -1
- package/dist/_internal/platform/tools/read/schema.js +1 -0
- package/dist/_internal/platform/tools/shared/process-manager.d.ts +2 -0
- package/dist/_internal/platform/tools/shared/process-manager.d.ts.map +1 -1
- package/dist/_internal/platform/tools/shared/process-manager.js +67 -5
- package/dist/_internal/platform/tools/write/index.d.ts.map +1 -1
- package/dist/_internal/platform/tools/write/index.js +3 -36
- package/dist/_internal/platform/utils/concurrency.d.ts +3 -0
- package/dist/_internal/platform/utils/concurrency.d.ts.map +1 -0
- package/dist/_internal/platform/utils/concurrency.js +17 -0
- package/dist/_internal/platform/utils/logger.d.ts.map +1 -1
- package/dist/_internal/platform/utils/logger.js +19 -1
- package/dist/_internal/platform/utils/request-body.d.ts +4 -0
- package/dist/_internal/platform/utils/request-body.d.ts.map +1 -0
- package/dist/_internal/platform/utils/request-body.js +45 -0
- package/dist/_internal/platform/version.js +1 -1
- package/dist/workers.d.ts +6 -0
- package/dist/workers.d.ts.map +1 -1
- package/dist/workers.js +55 -3
- package/package.json +1 -1
|
@@ -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;
|
|
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
|
|
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 =
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
375
|
+
const bodyResult = await readResponseText(response, effectiveMaxContent);
|
|
376
|
+
let rawBody = bodyResult.text;
|
|
285
377
|
contentType = sniffContentType(contentType, rawBody);
|
|
286
|
-
|
|
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 });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/fetch/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../../../src/_internal/platform/tools/fetch/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;
|
|
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
|
|
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,
|
|
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"}
|
|
@@ -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;
|
|
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
|
|
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) {
|
|
@@ -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
|
|
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"}
|
|
@@ -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;
|
|
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
|
-
|
|
63
|
-
|
|
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 =
|
|
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
|
|
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;
|
|
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
|
|
2
|
-
import { dirname, extname, join, relative
|
|
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 @@
|
|
|
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
|
+
}
|