@cortexkit/aft-bridge 0.30.2 → 0.30.3

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/index.d.ts CHANGED
@@ -15,13 +15,12 @@ export type { Logger, LogMeta } from "./logger.js";
15
15
  export type { MigrationHarness, MigrationOptions, MigrationStatus } from "./migration.js";
16
16
  export { ensureStorageMigrated, getMigrationStatus, resolveCortexKitStorageRoot, resolveLegacyStorageRoot, } from "./migration.js";
17
17
  export { __test__ as __onnxTest__, cleanupOnnxRuntime, ensureOnnxRuntime, getManualInstallHint, isOrtAutoDownloadSupported, } from "./onnx-runtime.js";
18
- export { repairRootScopedStorageFile, resolveHarnessStoragePath } from "./paths.js";
18
+ export { markAnnouncementSeen, repairRootScopedStorageFile, resolveHarnessStoragePath, shouldShowAnnouncement, } from "./paths.js";
19
19
  export { PLATFORM_ARCH_MAP, PLATFORM_ASSET_MAP } from "./platform.js";
20
20
  export type { PoolOptions } from "./pool.js";
21
21
  export { BridgePool, HomeProjectRootError, isHomeDirectoryRoot } from "./pool.js";
22
22
  export type { AftErrorResponse, AftPushFrame, AftRequestEnvelope, AftResponse, AftSuccessResponse, BashCompletedFrame, BgCompletion, ConfigureWarningFrame, PermissionAskFrame, ProgressFrame, StatusCompression, StatusCompressionAggregate, StatusResponse, } from "./protocol.js";
23
23
  export { findBinary, findBinarySync, platformKey } from "./resolver.js";
24
- export { _isPrivateIpv4, cleanupUrlCache, fetchUrlToTempFile } from "./url-fetch.js";
25
24
  export type { ZoomResponseLike } from "./zoom-format.js";
26
25
  export { formatZoomText } from "./zoom-format.js";
27
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEzE,OAAO,EACL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,EACX,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1E,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAE1F,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,QAAQ,IAAI,YAAY,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,2BAA2B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAEpF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACtE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAElF,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,0BAA0B,EAC1B,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAErF,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EACV,oBAAoB,EACpB,sBAAsB,EACtB,aAAa,EACb,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,GACf,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEzE,OAAO,EACL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,EACX,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1E,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACnD,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAE1F,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,QAAQ,IAAI,YAAY,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACtE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAElF,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,0BAA0B,EAC1B,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAExE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -18,12 +18,10 @@ export { compressionSavingsPercent, formatTokenCount } from "./format.js";
18
18
  export { ensureStorageMigrated, getMigrationStatus, resolveCortexKitStorageRoot, resolveLegacyStorageRoot, } from "./migration.js";
19
19
  // --- ONNX runtime ---
20
20
  export { __test__ as __onnxTest__, cleanupOnnxRuntime, ensureOnnxRuntime, getManualInstallHint, isOrtAutoDownloadSupported, } from "./onnx-runtime.js";
21
- export { repairRootScopedStorageFile, resolveHarnessStoragePath } from "./paths.js";
21
+ export { markAnnouncementSeen, repairRootScopedStorageFile, resolveHarnessStoragePath, shouldShowAnnouncement, } from "./paths.js";
22
22
  // --- platform helpers ---
23
23
  export { PLATFORM_ARCH_MAP, PLATFORM_ASSET_MAP } from "./platform.js";
24
24
  export { BridgePool, HomeProjectRootError, isHomeDirectoryRoot } from "./pool.js";
25
25
  export { findBinary, findBinarySync, platformKey } from "./resolver.js";
26
- // --- URL fetch (shared by aft_outline / aft_zoom URL targets) ---
27
- export { _isPrivateIpv4, cleanupUrlCache, fetchUrlToTempFile } from "./url-fetch.js";
28
26
  export { formatZoomText } from "./zoom-format.js";
29
27
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0BAA0B;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUrD,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzE,4BAA4B;AAC5B,OAAO,EACL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,EACX,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,gCAAgC;AAChC,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG1E,4BAA4B;AAC5B,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,uBAAuB;AACvB,OAAO,EACL,QAAQ,IAAI,YAAY,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,2BAA2B,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AACpF,2BAA2B;AAC3B,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEtE,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAiBlF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACxE,mEAAmE;AACnE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGrF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0BAA0B;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAUrD,oBAAoB;AACpB,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACzE,4BAA4B;AAC5B,OAAO,EACL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,EACX,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,gCAAgC;AAChC,OAAO,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG1E,4BAA4B;AAC5B,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,uBAAuB;AACvB,OAAO,EACL,QAAQ,IAAI,YAAY,EACxB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,2BAA2B;AAC3B,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEtE,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAiBlF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGxE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/paths.d.ts CHANGED
@@ -1,4 +1,41 @@
1
1
  import type { MigrationHarness } from "./migration.js";
2
2
  export declare function resolveHarnessStoragePath(storageRoot: string, harness: MigrationHarness, ...segments: string[]): string;
3
3
  export declare function repairRootScopedStorageFile(storageRoot: string, harness: MigrationHarness, fileName: string): string;
4
+ /**
5
+ * Decides whether to surface the version-specific announcement dialog/toast.
6
+ *
7
+ * Three cases, all driven off the persisted `last_announced_version` file:
8
+ *
9
+ * 1. **Existing user, same version** — file matches `currentVersion`. Skip.
10
+ *
11
+ * 2. **Existing user, upgrade** — file holds a *different* non-empty version.
12
+ * Show the dialog so the user sees what's new in their upgrade. After the
13
+ * dialog is dismissed, the host calls `markAnnouncementSeen` to record
14
+ * `currentVersion`.
15
+ *
16
+ * 3. **Fresh install or ephemeral sandbox** — file does not exist OR holds
17
+ * only whitespace. We deliberately do NOT show changelog bullets to a
18
+ * first-time user (no context to interpret them), AND we don't pester
19
+ * Docker/CI/disposable-VM users whose storage gets wiped every boot.
20
+ * Instead we silently **seed** the file with `currentVersion` so the very
21
+ * next launch behaves like case 1. Future upgrades still trigger case 2.
22
+ *
23
+ * Failures to read/write the marker file are non-fatal: we never let a
24
+ * filesystem hiccup spam an announcement. On any I/O error the function
25
+ * returns `false` and the host treats this turn as already-announced.
26
+ *
27
+ * Returns:
28
+ * - `true` → the caller should render the announcement and then call
29
+ * `markAnnouncementSeen(...)` once the user has seen it.
30
+ * - `false` → skip rendering. (File was already up-to-date, OR this was a
31
+ * fresh-install seed and the file has now been written so the
32
+ * next launch will also skip.)
33
+ */
34
+ export declare function shouldShowAnnouncement(storageRoot: string, harness: MigrationHarness, currentVersion: string): boolean;
35
+ /**
36
+ * Records that the user has seen `currentVersion`'s announcement. Best-effort
37
+ * filesystem write — failures are silently swallowed because the worst case
38
+ * is repeating the announcement once, not a broken plugin.
39
+ */
40
+ export declare function markAnnouncementSeen(storageRoot: string, harness: MigrationHarness, currentVersion: string): void;
4
41
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,EACzB,GAAG,QAAQ,EAAE,MAAM,EAAE,GACpB,MAAM,CAER;AAED,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,MAAM,GACf,MAAM,CAeR"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,EACzB,GAAG,QAAQ,EAAE,MAAM,EAAE,GACpB,MAAM,CAER;AAED,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,MAAM,GACf,MAAM,CAeR;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,EACzB,cAAc,EAAE,MAAM,GACrB,OAAO,CAkCT;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,gBAAgB,EACzB,cAAc,EAAE,MAAM,GACrB,IAAI,CAWN"}
package/dist/paths.js CHANGED
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, renameSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  export function resolveHarnessStoragePath(storageRoot, harness, ...segments) {
4
4
  return join(storageRoot, harness, ...segments);
@@ -18,4 +18,85 @@ export function repairRootScopedStorageFile(storageRoot, harness, fileName) {
18
18
  }
19
19
  return harnessPath;
20
20
  }
21
+ /**
22
+ * Decides whether to surface the version-specific announcement dialog/toast.
23
+ *
24
+ * Three cases, all driven off the persisted `last_announced_version` file:
25
+ *
26
+ * 1. **Existing user, same version** — file matches `currentVersion`. Skip.
27
+ *
28
+ * 2. **Existing user, upgrade** — file holds a *different* non-empty version.
29
+ * Show the dialog so the user sees what's new in their upgrade. After the
30
+ * dialog is dismissed, the host calls `markAnnouncementSeen` to record
31
+ * `currentVersion`.
32
+ *
33
+ * 3. **Fresh install or ephemeral sandbox** — file does not exist OR holds
34
+ * only whitespace. We deliberately do NOT show changelog bullets to a
35
+ * first-time user (no context to interpret them), AND we don't pester
36
+ * Docker/CI/disposable-VM users whose storage gets wiped every boot.
37
+ * Instead we silently **seed** the file with `currentVersion` so the very
38
+ * next launch behaves like case 1. Future upgrades still trigger case 2.
39
+ *
40
+ * Failures to read/write the marker file are non-fatal: we never let a
41
+ * filesystem hiccup spam an announcement. On any I/O error the function
42
+ * returns `false` and the host treats this turn as already-announced.
43
+ *
44
+ * Returns:
45
+ * - `true` → the caller should render the announcement and then call
46
+ * `markAnnouncementSeen(...)` once the user has seen it.
47
+ * - `false` → skip rendering. (File was already up-to-date, OR this was a
48
+ * fresh-install seed and the file has now been written so the
49
+ * next launch will also skip.)
50
+ */
51
+ export function shouldShowAnnouncement(storageRoot, harness, currentVersion) {
52
+ if (!currentVersion)
53
+ return false;
54
+ const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
55
+ let lastVersion = "";
56
+ try {
57
+ if (existsSync(versionFile)) {
58
+ lastVersion = readFileSync(versionFile, "utf-8").trim();
59
+ }
60
+ }
61
+ catch {
62
+ // Read failed — be conservative and skip the announcement so a flaky
63
+ // filesystem can't repeatedly flash a dialog.
64
+ return false;
65
+ }
66
+ if (lastVersion === currentVersion)
67
+ return false;
68
+ if (!lastVersion) {
69
+ // Fresh install or sandbox: silently mark as seen. The next launch sees
70
+ // case 1 (file matches) and stays quiet. Real upgrades from a persisted
71
+ // older version still hit the `lastVersion !== currentVersion` path
72
+ // above and surface the dialog.
73
+ try {
74
+ mkdirSync(dirname(versionFile), { recursive: true });
75
+ writeFileSync(versionFile, currentVersion);
76
+ }
77
+ catch {
78
+ // Best-effort. If we couldn't seed the file we still skip this turn so
79
+ // the user isn't pestered; we'll just try to seed again next launch.
80
+ }
81
+ return false;
82
+ }
83
+ return true;
84
+ }
85
+ /**
86
+ * Records that the user has seen `currentVersion`'s announcement. Best-effort
87
+ * filesystem write — failures are silently swallowed because the worst case
88
+ * is repeating the announcement once, not a broken plugin.
89
+ */
90
+ export function markAnnouncementSeen(storageRoot, harness, currentVersion) {
91
+ if (!currentVersion)
92
+ return;
93
+ const versionFile = repairRootScopedStorageFile(storageRoot, harness, "last_announced_version");
94
+ try {
95
+ mkdirSync(dirname(versionFile), { recursive: true });
96
+ writeFileSync(versionFile, currentVersion);
97
+ }
98
+ catch {
99
+ // Best-effort.
100
+ }
101
+ }
21
102
  //# sourceMappingURL=paths.js.map
package/dist/paths.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,MAAM,UAAU,yBAAyB,CACvC,WAAmB,EACnB,OAAyB,EACzB,GAAG,QAAkB;IAErB,OAAO,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,WAAmB,EACnB,OAAyB,EACzB,QAAgB;IAEhB,MAAM,WAAW,GAAG,yBAAyB,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAE7C,IAAI,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IAEzE,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,UAAU,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,oDAAoD;IACtD,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG1C,MAAM,UAAU,yBAAyB,CACvC,WAAmB,EACnB,OAAyB,EACzB,GAAG,QAAkB;IAErB,OAAO,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,WAAmB,EACnB,OAAyB,EACzB,QAAgB;IAEhB,MAAM,WAAW,GAAG,yBAAyB,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAE7C,IAAI,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IAEzE,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,UAAU,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,oDAAoD;IACtD,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,sBAAsB,CACpC,WAAmB,EACnB,OAAyB,EACzB,cAAsB;IAEtB,IAAI,CAAC,cAAc;QAAE,OAAO,KAAK,CAAC;IAElC,MAAM,WAAW,GAAG,2BAA2B,CAAC,WAAW,EAAE,OAAO,EAAE,wBAAwB,CAAC,CAAC;IAEhG,IAAI,WAAW,GAAG,EAAE,CAAC;IACrB,IAAI,CAAC;QACH,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,WAAW,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1D,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;QACrE,8CAA8C;QAC9C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,WAAW,KAAK,cAAc;QAAE,OAAO,KAAK,CAAC;IAEjD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,wEAAwE;QACxE,wEAAwE;QACxE,oEAAoE;QACpE,gCAAgC;QAChC,IAAI,CAAC;YACH,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACrD,aAAa,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;YACvE,qEAAqE;QACvE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAAmB,EACnB,OAAyB,EACzB,cAAsB;IAEtB,IAAI,CAAC,cAAc;QAAE,OAAO;IAE5B,MAAM,WAAW,GAAG,2BAA2B,CAAC,WAAW,EAAE,OAAO,EAAE,wBAAwB,CAAC,CAAC;IAEhG,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,aAAa,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/aft-bridge",
3
- "version": "0.30.2",
3
+ "version": "0.30.3",
4
4
  "type": "module",
5
5
  "description": "Shared NDJSON bridge transport, binary resolution, and ONNX runtime helpers for AFT agent-host plugins (OpenCode, Pi)",
6
6
  "license": "MIT",
@@ -1,33 +0,0 @@
1
- import { lookup } from "node:dns/promises";
2
- import { type Dispatcher } from "undici";
3
- interface FetchUrlOptions {
4
- allowPrivate?: boolean;
5
- /** Test-only injection point. Production fetches use undici with DNS pinning. */
6
- fetchImpl?: FetchImpl;
7
- /** Test-only injection point. Production DNS resolution uses node:dns/promises.lookup. */
8
- lookup?: LookupFn;
9
- /** Test-only injection point for observing the DNS-pinned dispatcher. */
10
- dispatcherFactory?: (validatedIp: string) => Dispatcher;
11
- }
12
- type LookupFn = typeof lookup;
13
- interface FetchInit {
14
- signal?: AbortSignal;
15
- redirect?: "manual";
16
- dispatcher?: Dispatcher;
17
- headers?: Record<string, string>;
18
- }
19
- type FetchImpl = (input: string, init: FetchInit) => Promise<Response>;
20
- /** Exported for unit tests. */
21
- export declare function _isPrivateIpv4(address: string): boolean;
22
- /**
23
- * Fetch a URL to a cached temp file. Uses disk cache with 1-day TTL.
24
- * Returns the cached file path the Rust outline/zoom command can read.
25
- * Throws on errors (invalid URL, network failure, unsupported content type, oversized body).
26
- */
27
- export declare function fetchUrlToTempFile(url: string, storageDir: string, options?: FetchUrlOptions): Promise<string>;
28
- /**
29
- * Remove cache entries older than TTL. Called periodically at plugin startup.
30
- */
31
- export declare function cleanupUrlCache(storageDir: string): void;
32
- export {};
33
- //# sourceMappingURL=url-fetch.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"url-fetch.d.ts","sourceRoot":"","sources":["../src/url-fetch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAW3C,OAAO,EAAS,KAAK,UAAU,EAAwB,MAAM,QAAQ,CAAC;AAoBtE,UAAU,eAAe;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iFAAiF;IACjF,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,0FAA0F;IAC1F,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,UAAU,CAAC;CACzD;AAED,KAAK,QAAQ,GAAG,OAAO,MAAM,CAAC;AAC9B,UAAU,SAAS;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,KAAK,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAyBvE,+BAA+B;AAC/B,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAavD;AAqVD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAuIjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAkCxD"}
package/dist/url-fetch.js DELETED
@@ -1,526 +0,0 @@
1
- import { createHash, randomBytes } from "node:crypto";
2
- import { lookup } from "node:dns/promises";
3
- import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync, } from "node:fs";
4
- import { isIP } from "node:net";
5
- import { join } from "node:path";
6
- import { Agent, fetch as undiciFetch } from "undici";
7
- import { log, warn } from "./active-logger.js";
8
- /** Max response body size (10 MB) */
9
- const MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
10
- /** Cache TTL: 1 day */
11
- const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
12
- /** Fetch timeout: 30 seconds — covers initial connect + headers */
13
- const FETCH_TIMEOUT_MS = 30_000;
14
- /**
15
- * Per-chunk body read timeout: 15 seconds. Resets after every successful
16
- * chunk so legitimate large/slow downloads still complete, but a stalled
17
- * mid-body stream (e.g. CDN edge drops the connection without closing the
18
- * socket cleanly) is aborted within this window. Without this guard the
19
- * body loop blocks indefinitely because Node's `AbortController` from
20
- * `fetch()` only covers the connect+headers phase, not body streaming.
21
- */
22
- const BODY_CHUNK_TIMEOUT_MS = 15_000;
23
- const MAX_REDIRECTS = 5;
24
- function cacheDir(storageDir) {
25
- return join(storageDir, "url_cache");
26
- }
27
- function hashUrl(url) {
28
- return createHash("sha256").update(url).digest("hex").slice(0, 16);
29
- }
30
- function metaPath(storageDir, hash) {
31
- return join(cacheDir(storageDir), `${hash}.meta.json`);
32
- }
33
- function contentPath(storageDir, hash, extension) {
34
- return join(cacheDir(storageDir), `${hash}${extension}`);
35
- }
36
- /** Exported for unit tests. */
37
- export function _isPrivateIpv4(address) {
38
- const parts = address.split(".").map((part) => Number.parseInt(part, 10));
39
- if (parts.length !== 4 || parts.some((part) => !Number.isInteger(part)))
40
- return true;
41
- const [a, b] = parts;
42
- return (a === 0 || // 0.0.0.0/8 — wildcard, blocked to prevent local-host bypass
43
- a === 10 ||
44
- a === 127 ||
45
- (a === 172 && b >= 16 && b <= 31) ||
46
- (a === 192 && b === 168) ||
47
- (a === 169 && b === 254) ||
48
- a >= 224 // multicast (224/4) and reserved (240/4)
49
- );
50
- }
51
- /**
52
- * Expand a possibly-compressed IPv6 address to 8 hextets (numbers).
53
- * Returns null on parse failure.
54
- */
55
- function expandIpv6(addr) {
56
- if (addr === "::")
57
- return [0, 0, 0, 0, 0, 0, 0, 0];
58
- // Reject more than one "::"
59
- const dcMatches = addr.match(/::/g);
60
- if (dcMatches && dcMatches.length > 1)
61
- return null;
62
- // Handle dotted-quad tail by converting to two hextets.
63
- let normalized = addr;
64
- const lastColon = normalized.lastIndexOf(":");
65
- if (lastColon !== -1) {
66
- const tail = normalized.slice(lastColon + 1);
67
- if (tail.includes(".")) {
68
- const octets = tail.split(".").map((p) => Number.parseInt(p, 10));
69
- if (octets.length !== 4 || octets.some((o) => Number.isNaN(o) || o < 0 || o > 255)) {
70
- return null;
71
- }
72
- const h1 = ((octets[0] << 8) | octets[1]).toString(16);
73
- const h2 = ((octets[2] << 8) | octets[3]).toString(16);
74
- normalized = `${normalized.slice(0, lastColon)}:${h1}:${h2}`;
75
- }
76
- }
77
- let parts;
78
- if (normalized.includes("::")) {
79
- const [left, right] = normalized.split("::");
80
- const leftParts = left ? left.split(":") : [];
81
- const rightParts = right ? right.split(":") : [];
82
- const fill = 8 - leftParts.length - rightParts.length;
83
- if (fill < 0)
84
- return null;
85
- parts = [...leftParts, ...Array(fill).fill("0"), ...rightParts];
86
- }
87
- else {
88
- parts = normalized.split(":");
89
- }
90
- if (parts.length !== 8)
91
- return null;
92
- const hextets = parts.map((p) => {
93
- const n = Number.parseInt(p, 16);
94
- return Number.isNaN(n) || n < 0 || n > 0xffff ? -1 : n;
95
- });
96
- if (hextets.some((h) => h === -1))
97
- return null;
98
- return hextets;
99
- }
100
- function isPrivateIp(address) {
101
- if (!address.includes(":")) {
102
- return _isPrivateIpv4(address);
103
- }
104
- const lower = address.toLowerCase();
105
- // Strip optional zone identifier (fe80::1%eth0 → fe80::1).
106
- const noZone = lower.split("%")[0];
107
- // Expand to 8 hextets so we can reliably detect IPv4-mapped/compatible
108
- // forms even after URL canonicalization (e.g. [::ffff:127.0.0.1] →
109
- // [::ffff:7f00:1]).
110
- const hextets = expandIpv6(noZone);
111
- if (hextets) {
112
- // IPv4-mapped (::ffff:X.X.X.X) and IPv4-compatible (::X.X.X.X) — extract
113
- // the embedded IPv4 from the last two hextets and check against IPv4 ranges.
114
- const top6Zero = hextets.slice(0, 6).every((h) => h === 0);
115
- const isMapped = hextets[0] === 0 &&
116
- hextets[1] === 0 &&
117
- hextets[2] === 0 &&
118
- hextets[3] === 0 &&
119
- hextets[4] === 0 &&
120
- hextets[5] === 0xffff;
121
- if (isMapped || top6Zero) {
122
- const a = (hextets[6] >> 8) & 0xff;
123
- const b = hextets[6] & 0xff;
124
- const c = (hextets[7] >> 8) & 0xff;
125
- const d = hextets[7] & 0xff;
126
- const ipv4 = `${a}.${b}.${c}.${d}`;
127
- // ::1 (loopback) and :: (unspecified) both fall into top6Zero and last
128
- // hextet 0 or 1 — _isPrivateIpv4 already blocks 0.0.0.0 and 127/8.
129
- if (top6Zero && hextets[6] === 0 && hextets[7] <= 1) {
130
- return true;
131
- }
132
- return _isPrivateIpv4(ipv4);
133
- }
134
- const firstHextet = hextets[0];
135
- return (
136
- // fe80::/10 link-local
137
- (firstHextet >= 0xfe80 && firstHextet <= 0xfebf) ||
138
- // fc00::/7 unique local
139
- (firstHextet >= 0xfc00 && firstHextet <= 0xfdff) ||
140
- // ff00::/8 multicast
141
- firstHextet >= 0xff00);
142
- }
143
- // Could not expand — be conservative and block.
144
- return true;
145
- }
146
- async function assertPublicUrl(url, allowPrivate, dnsLookup = lookup) {
147
- if (url.protocol !== "http:" && url.protocol !== "https:") {
148
- throw new Error(`Only http:// and https:// URLs are supported, got: ${url.protocol}`);
149
- }
150
- if (allowPrivate)
151
- return undefined;
152
- // URL.hostname returns IPv6 literals wrapped in brackets ("[::1]") per WHATWG.
153
- // Strip them before checking the address.
154
- const hostname = url.hostname.replace(/^\[|\]$/g, "");
155
- // If the hostname is already a literal IP, check it directly — skip DNS so we
156
- // also catch malformed IPv6 forms (::127.0.0.1, ::ffff:127.0.0.1) that some
157
- // resolvers reject as "not found" instead of returning the embedded IPv4.
158
- if (isIP(hostname) || hostname.includes(":")) {
159
- if (isPrivateIp(hostname)) {
160
- throw new Error(`Blocked private URL host ${url.hostname} (${hostname})`);
161
- }
162
- return hostname;
163
- }
164
- const addresses = await dnsLookup(hostname, { all: true, verbatim: true });
165
- for (const { address } of addresses) {
166
- if (isPrivateIp(address)) {
167
- throw new Error(`Blocked private URL host ${url.hostname} (${address})`);
168
- }
169
- }
170
- if (addresses.length === 0) {
171
- throw new Error(`Failed to resolve URL host ${url.hostname}`);
172
- }
173
- // Prefer IPv4 when available. AAAA can come first on many resolvers, but
174
- // many user networks (corporate, home, mobile) don't have IPv6 transit, so
175
- // pinning to AAAA causes EHOSTUNREACH / connect timeouts that surface as a
176
- // bare `fetch failed`. Falls back to whatever DNS gave us if no IPv4 record.
177
- // `family` is documented as numeric (4/6) but be defensive — some runtimes
178
- // have surfaced it as the string "IPv4"/"IPv6" historically.
179
- const ipv4 = addresses.find((entry) => entry.family === 4 ||
180
- entry.family === "IPv4" ||
181
- (typeof entry.address === "string" && isIP(entry.address) === 4));
182
- const chosen = ipv4 ?? addresses[0];
183
- if (!chosen || typeof chosen.address !== "string" || chosen.address.length === 0) {
184
- // Should be unreachable given the length>0 check above, but the bare
185
- // `Invalid IP address: undefined` failure surfaced by undici when an
186
- // empty/undefined IP slips into connect.lookup is opaque enough that
187
- // we want a clear, structured failure instead.
188
- throw new Error(`DNS lookup for ${url.hostname} returned no usable address (got: ${JSON.stringify(addresses)})`);
189
- }
190
- return chosen.address;
191
- }
192
- function createPinnedDispatcher(validatedIp) {
193
- const family = validatedIp.includes(":") ? 6 : 4;
194
- // Node 18+ calls the lookup with `opts.all: true` (especially via TLS /
195
- // happy-eyeballs paths). When `all` is true the callback expects an *array*
196
- // of `{address, family}` objects, not the legacy `(err, address, family)`
197
- // 3-arg shape. Calling the legacy form there causes Node to surface
198
- // `TypeError [ERR_INVALID_IP_ADDRESS]: Invalid IP address: undefined` from
199
- // net:emitLookup, wrapped by undici as a bare `fetch failed`. Honor
200
- // whichever shape `opts.all` requested.
201
- // (Cast to `any` because undici's `LookupFunction` type only models the
202
- // single-address callback overload, not the `all: true` variadic.)
203
- // biome-ignore lint/suspicious/noExplicitAny: dual-overload lookup callback
204
- const pinnedLookup = (_hostname, opts,
205
- // biome-ignore lint/suspicious/noExplicitAny: dual-overload lookup callback
206
- callback) => {
207
- if (opts?.all) {
208
- callback(null, [{ address: validatedIp, family }]);
209
- }
210
- else {
211
- callback(null, validatedIp, family);
212
- }
213
- };
214
- return new Agent({
215
- connect: { lookup: pinnedLookup },
216
- });
217
- }
218
- function resolveRedirectUrl(currentUrl, location) {
219
- if (!location) {
220
- throw new Error(`Redirect from ${currentUrl.href} missing Location header`);
221
- }
222
- return new URL(location, currentUrl);
223
- }
224
- // Detect Bun runtime. When undici is bundled into a Bun-targeted bundle
225
- // (opencode-plugin builds with `bun build --target node`), the bundled undici
226
- // fetch + bundled stream classes can stall on body reads against many real
227
- // hosts (github.com, registry.npmjs.org, unpkg.com, api.github.com). This is a
228
- // known interaction between bundled undici streams and Bun's runtime — the
229
- // same undici code works fine when loaded via Node `require()` directly.
230
- //
231
- // When running under Bun, fall back to the runtime's native global fetch (Bun
232
- // has its own performant fetch impl). SSRF protection is still active via
233
- // `assertPublicUrl`; we just skip the per-connection DNS pinning since Bun's
234
- // native fetch doesn't accept an undici dispatcher. The window for DNS
235
- // rebinding is small (one DNS lookup → one TCP connect) and the URL fetch
236
- // surface in AFT is opt-in tooling, not an untrusted server-side request path.
237
- //
238
- // biome-ignore lint/suspicious/noExplicitAny: detect Bun runtime
239
- const isBunRuntime = typeof globalThis.Bun !== "undefined";
240
- async function fetchWithRedirects(startUrl, allowPrivate, deps = {}) {
241
- let currentUrl = startUrl;
242
- // Honor explicit fetchImpl override (tests). Otherwise: Bun gets native fetch,
243
- // Node gets undici with pinned dispatcher.
244
- const fetchImpl = deps.fetchImpl ?? (isBunRuntime ? globalThis.fetch : undiciFetch);
245
- const dnsLookup = deps.lookup ?? lookup;
246
- for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount++) {
247
- const validatedIp = await assertPublicUrl(currentUrl, allowPrivate, dnsLookup);
248
- // Pinned dispatcher only works with undici (Node path). Bun's native fetch
249
- // doesn't accept a dispatcher arg, so skip pinning there. An explicit
250
- // `dispatcherFactory` (test injection) always wins over runtime detection
251
- // so unit tests can keep asserting the pin behavior without spinning up
252
- // a real Node process.
253
- let dispatcher;
254
- if (validatedIp) {
255
- if (deps.dispatcherFactory) {
256
- dispatcher = deps.dispatcherFactory(validatedIp);
257
- }
258
- else if (!isBunRuntime) {
259
- dispatcher = createPinnedDispatcher(validatedIp);
260
- }
261
- }
262
- const controller = new AbortController();
263
- const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
264
- let response;
265
- try {
266
- response = await fetchImpl(currentUrl.href, {
267
- signal: controller.signal,
268
- redirect: "manual",
269
- dispatcher,
270
- headers: {
271
- "user-agent": "aft-opencode-plugin",
272
- // Prioritize markdown for content-negotiating servers (GitHub API, many docs sites).
273
- // `application/vnd.github.raw` is GitHub's custom type — returns raw markdown from
274
- // repo file and readme endpoints. Falls back to HTML if markdown is not available.
275
- accept: "application/vnd.github.raw, text/markdown, text/x-markdown, text/html;q=0.9, application/json;q=0.8, text/plain;q=0.5",
276
- },
277
- });
278
- }
279
- catch (err) {
280
- // undici wraps the underlying network error (ECONNREFUSED / ETIMEDOUT /
281
- // EHOSTUNREACH / ENOTFOUND / cert errors) inside `.cause` and exposes a
282
- // bare "fetch failed" on the outer Error. Surfacing the cause's `code`
283
- // and message turns an unactionable failure into something the agent
284
- // (and the user) can actually triage.
285
- const error = err;
286
- const cause = error.cause;
287
- const causeCode = cause?.code ?? error.code;
288
- const causeMsg = cause?.message ?? "";
289
- const detail = causeCode
290
- ? causeMsg
291
- ? `${causeCode}: ${causeMsg}`
292
- : causeCode
293
- : (error.message ?? "unknown error");
294
- // Log the full chain so triage doesn't depend on the agent surface
295
- // forwarding the wrapped error message.
296
- warn(`URL fetch failed: ${currentUrl.href} — ${detail}`, {
297
- outerMessage: error.message,
298
- causeName: cause?.name,
299
- causeCode,
300
- causeErrno: cause?.errno,
301
- causeSyscall: cause?.syscall,
302
- });
303
- throw new Error(`Failed to fetch ${currentUrl.href}: ${detail}`);
304
- }
305
- finally {
306
- clearTimeout(timer);
307
- }
308
- if (response.status < 300 || response.status >= 400) {
309
- return response;
310
- }
311
- if (redirectCount === MAX_REDIRECTS) {
312
- throw new Error(`Too many redirects fetching ${startUrl.href}`);
313
- }
314
- currentUrl = resolveRedirectUrl(currentUrl, response.headers.get("location"));
315
- }
316
- throw new Error(`Too many redirects fetching ${startUrl.href}`);
317
- }
318
- /**
319
- * Map a Content-Type header to a file extension AFT can parse.
320
- * Returns null for unsupported types.
321
- */
322
- function resolveExtension(contentType) {
323
- // Normalize: strip parameters (after `;`) AND pick the first value if the server
324
- // echoed back a comma-separated list (GitHub API does this for /readme endpoints).
325
- const lower = contentType.toLowerCase().split(";")[0].split(",")[0].trim();
326
- if (lower === "text/html" ||
327
- lower === "application/xhtml+xml" ||
328
- lower === "application/vnd.github.html" ||
329
- lower === "application/vnd.github+html") {
330
- return ".html";
331
- }
332
- if (lower === "text/markdown" ||
333
- lower === "text/x-markdown" ||
334
- lower === "application/markdown" ||
335
- // GitHub API raw content type — returns raw markdown for README endpoints
336
- lower === "application/vnd.github.raw" ||
337
- lower === "application/vnd.github+raw" ||
338
- lower === "application/vnd.github.v3.raw") {
339
- return ".md";
340
- }
341
- if (lower === "text/plain") {
342
- // treat plain text as markdown so aft_outline can show headings if present
343
- return ".md";
344
- }
345
- if (lower === "application/json" || lower === "application/ld+json" || lower.endsWith("+json")) {
346
- // JSON is parseable by aft_outline (top-level keys become symbols).
347
- // Covers npm registry, unpkg package.json, OpenAPI specs, etc.
348
- return ".json";
349
- }
350
- return null;
351
- }
352
- /**
353
- * Fetch a URL to a cached temp file. Uses disk cache with 1-day TTL.
354
- * Returns the cached file path the Rust outline/zoom command can read.
355
- * Throws on errors (invalid URL, network failure, unsupported content type, oversized body).
356
- */
357
- export async function fetchUrlToTempFile(url, storageDir, options = {}) {
358
- let parsed;
359
- try {
360
- parsed = new URL(url);
361
- }
362
- catch {
363
- throw new Error(`Invalid URL: ${url}`);
364
- }
365
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
366
- throw new Error(`Only http:// and https:// URLs are supported, got: ${parsed.protocol}`);
367
- }
368
- const allowPrivate = options.allowPrivate === true;
369
- // Enforce the caller's current SSRF policy before consulting the disk cache.
370
- // Otherwise a URL previously cached with allowPrivate=true could be replayed
371
- // by a later allowPrivate=false call without re-validating the host.
372
- await assertPublicUrl(parsed, allowPrivate, options.lookup);
373
- const dir = cacheDir(storageDir);
374
- mkdirSync(dir, { recursive: true });
375
- const hash = hashUrl(url);
376
- const metaFile = metaPath(storageDir, hash);
377
- // Check cache
378
- if (existsSync(metaFile)) {
379
- try {
380
- const meta = JSON.parse(readFileSync(metaFile, "utf8"));
381
- const age = Date.now() - meta.fetchedAt;
382
- const cached = contentPath(storageDir, hash, meta.extension);
383
- if (age < CACHE_TTL_MS && existsSync(cached)) {
384
- log(`URL cache hit: ${url} (${Math.round(age / 1000)}s old)`);
385
- return cached;
386
- }
387
- }
388
- catch {
389
- // corrupted meta, re-fetch
390
- }
391
- }
392
- log(`Fetching URL: ${url}`);
393
- const response = await fetchWithRedirects(parsed, allowPrivate, options);
394
- if (!response.ok) {
395
- throw new Error(`HTTP ${response.status} ${response.statusText} fetching ${url}`);
396
- }
397
- const contentType = response.headers.get("content-type") || "text/plain";
398
- const extension = resolveExtension(contentType);
399
- if (!extension) {
400
- throw new Error(`Unsupported content type '${contentType}' for ${url}. Supported: text/html, text/markdown, text/plain`);
401
- }
402
- const lengthHeader = response.headers.get("content-length");
403
- if (lengthHeader) {
404
- const length = Number.parseInt(lengthHeader, 10);
405
- if (Number.isFinite(length) && length > MAX_RESPONSE_BYTES) {
406
- throw new Error(`Response too large: ${length} bytes (max ${MAX_RESPONSE_BYTES})`);
407
- }
408
- }
409
- // Stream with size cap and per-chunk timeout. The AbortController used for
410
- // the initial fetch() only covers connect + headers — once we hold a
411
- // ReadableStream reader, `reader.read()` has no built-in timeout, so a
412
- // server that sends headers and then stalls mid-body (CDN edge drops the
413
- // socket, partial response, rate limit hold) blocks this loop forever.
414
- // The per-chunk timer is reset after every successful read, so legitimate
415
- // large/slow downloads still complete cleanly.
416
- const reader = response.body?.getReader();
417
- if (!reader) {
418
- throw new Error(`Failed to read response body for ${url}`);
419
- }
420
- const chunks = [];
421
- let total = 0;
422
- try {
423
- while (true) {
424
- let chunkTimer;
425
- const stallSymbol = Symbol("body-stall");
426
- const stallPromise = new Promise((resolve) => {
427
- chunkTimer = setTimeout(() => resolve(stallSymbol), BODY_CHUNK_TIMEOUT_MS);
428
- });
429
- let result;
430
- try {
431
- result = await Promise.race([reader.read(), stallPromise]);
432
- }
433
- finally {
434
- if (chunkTimer)
435
- clearTimeout(chunkTimer);
436
- }
437
- if (result === stallSymbol) {
438
- reader.cancel().catch(() => { });
439
- throw new Error(`Body read stalled (no data for ${BODY_CHUNK_TIMEOUT_MS}ms) fetching ${url}`);
440
- }
441
- const { done, value } = result;
442
- if (done)
443
- break;
444
- if (value) {
445
- total += value.length;
446
- if (total > MAX_RESPONSE_BYTES) {
447
- reader.cancel().catch(() => { });
448
- throw new Error(`Response exceeded ${MAX_RESPONSE_BYTES} bytes, aborted`);
449
- }
450
- chunks.push(value);
451
- }
452
- }
453
- }
454
- finally {
455
- // Defensive: release any held lock so the underlying stream can be GCed
456
- // even if a throw skipped the loop's normal exit. `releaseLock` is a no-op
457
- // if the reader was already cancelled.
458
- try {
459
- reader.releaseLock();
460
- }
461
- catch { }
462
- }
463
- // Write content and meta atomically
464
- const body = Buffer.concat(chunks);
465
- const contentFile = contentPath(storageDir, hash, extension);
466
- const nonce = randomBytes(8).toString("hex");
467
- const tmpContent = `${contentFile}.tmp-${process.pid}-${nonce}`;
468
- writeFileSync(tmpContent, body);
469
- const { renameSync } = await import("node:fs");
470
- renameSync(tmpContent, contentFile);
471
- const meta = {
472
- url,
473
- contentType,
474
- extension,
475
- fetchedAt: Date.now(),
476
- };
477
- const tmpMeta = `${metaFile}.tmp-${process.pid}-${nonce}`;
478
- writeFileSync(tmpMeta, JSON.stringify(meta));
479
- renameSync(tmpMeta, metaFile);
480
- log(`URL cached (${total} bytes): ${url}`);
481
- return contentFile;
482
- }
483
- /**
484
- * Remove cache entries older than TTL. Called periodically at plugin startup.
485
- */
486
- export function cleanupUrlCache(storageDir) {
487
- const dir = cacheDir(storageDir);
488
- if (!existsSync(dir))
489
- return;
490
- let removed = 0;
491
- try {
492
- for (const entry of readdirSync(dir)) {
493
- if (!entry.endsWith(".meta.json"))
494
- continue;
495
- const metaFile = join(dir, entry);
496
- try {
497
- const meta = JSON.parse(readFileSync(metaFile, "utf8"));
498
- const age = Date.now() - meta.fetchedAt;
499
- if (age > CACHE_TTL_MS) {
500
- const hash = entry.slice(0, -".meta.json".length);
501
- const content = contentPath(storageDir, hash, meta.extension);
502
- if (existsSync(content))
503
- unlinkSync(content);
504
- unlinkSync(metaFile);
505
- removed++;
506
- }
507
- }
508
- catch {
509
- // corrupted meta, remove it too
510
- try {
511
- unlinkSync(metaFile);
512
- removed++;
513
- }
514
- catch { }
515
- }
516
- }
517
- }
518
- catch (err) {
519
- warn(`URL cache cleanup failed: ${err.message}`);
520
- return;
521
- }
522
- if (removed > 0) {
523
- log(`URL cache cleanup: removed ${removed} stale entries`);
524
- }
525
- }
526
- //# sourceMappingURL=url-fetch.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"url-fetch.js","sourceRoot":"","sources":["../src/url-fetch.ts"],"names":[],"mappings":"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"}