@try-works/dsh-model-as-tool 0.4.1 → 0.4.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/client/client.model-tools.js +4 -0
- package/lib/extension-dependencies.d.ts +15 -2
- package/lib/extension-dependencies.d.ts.map +1 -1
- package/lib/extension-dependencies.js +54 -18
- package/lib/extensions-api.d.ts +3 -1
- package/lib/extensions-api.d.ts.map +1 -1
- package/lib/extensions-service.d.ts +24 -0
- package/lib/extensions-service.d.ts.map +1 -1
- package/lib/extensions-service.js +346 -8
- package/lib/index.d.ts +13 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +107 -1
- package/package.json +1 -1
- package/remote/spec.mjs +1 -0
|
@@ -252,8 +252,17 @@ export interface RegistrySessionOptions {
|
|
|
252
252
|
readonly archiveFactory: (fetcher: (source: InstallSource) => Promise<Uint8Array>) => ArchiveSource;
|
|
253
253
|
/** Hard cap on one downloaded package tarball; defaults to the SDK archive bound. */
|
|
254
254
|
readonly maxTarballBytes?: number;
|
|
255
|
-
/**
|
|
256
|
-
readonly
|
|
255
|
+
/** Packument/metadata request timeout (wall clock); default 30 s. */
|
|
256
|
+
readonly metadataTimeoutMs?: number;
|
|
257
|
+
/**
|
|
258
|
+
* Tarball IDLE timeout: abort only after this long with NO bytes arriving.
|
|
259
|
+
*
|
|
260
|
+
* A large dependency (onnxruntime-node is hundreds of MB) must not be aborted
|
|
261
|
+
* by the short metadata budget; the sha512 is verified after the transfer, so
|
|
262
|
+
* the byte cap is the real bound and a slow-but-moving stream is fine.
|
|
263
|
+
* Default 10 minutes.
|
|
264
|
+
*/
|
|
265
|
+
readonly tarballTimeoutMs?: number;
|
|
257
266
|
/** Injected fetch, for tests. Defaults to the global fetch. */
|
|
258
267
|
readonly fetchImpl?: typeof fetch;
|
|
259
268
|
}
|
|
@@ -279,6 +288,10 @@ export interface RegistrySession {
|
|
|
279
288
|
*/
|
|
280
289
|
download(source: InstallSource, signal?: AbortSignal): Promise<Uint8Array>;
|
|
281
290
|
}
|
|
291
|
+
/** The default packument timeout: metadata is small and must answer promptly. */
|
|
292
|
+
export declare const DEFAULT_REGISTRY_METADATA_TIMEOUT_MS = 30000;
|
|
293
|
+
/** The default tarball IDLE timeout: a large dependency may transfer for minutes. */
|
|
294
|
+
export declare const DEFAULT_REGISTRY_TARBALL_TIMEOUT_MS: number;
|
|
282
295
|
/**
|
|
283
296
|
* Whether one published version satisfies a semver range.
|
|
284
297
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension-dependencies.d.ts","sourceRoot":"","sources":["../src/extension-dependencies.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"extension-dependencies.d.ts","sourceRoot":"","sources":["../src/extension-dependencies.ts"],"names":[],"mappings":"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"}
|
|
@@ -401,30 +401,48 @@ function encodePackageName(name) {
|
|
|
401
401
|
// npm encodes scoped names' slash as %2f and leaves the leading @ readable.
|
|
402
402
|
return name.startsWith('@') ? name.replace('/', '%2f') : encodeURIComponent(name);
|
|
403
403
|
}
|
|
404
|
-
/**
|
|
405
|
-
|
|
404
|
+
/** The default packument timeout: metadata is small and must answer promptly. */
|
|
405
|
+
export const DEFAULT_REGISTRY_METADATA_TIMEOUT_MS = 30_000;
|
|
406
|
+
/** The default tarball IDLE timeout: a large dependency may transfer for minutes. */
|
|
407
|
+
export const DEFAULT_REGISTRY_TARBALL_TIMEOUT_MS = 10 * 60_000;
|
|
408
|
+
/** Read a response body with a hard byte cap and an optional IDLE timeout. */
|
|
409
|
+
async function readBoundedBody(response, maxBytes, options) {
|
|
410
|
+
const tooLarge = (declared) => new RegistryError('registry-tarball-too-large', options?.tooLargeMessage?.(declared) ?? `the response is over the ${maxBytes}-byte cap`);
|
|
406
411
|
const declared = Number(response.headers.get('content-length') ?? Number.NaN);
|
|
407
412
|
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
408
413
|
await response.body?.cancel();
|
|
409
|
-
throw
|
|
414
|
+
throw tooLarge(declared);
|
|
410
415
|
}
|
|
411
416
|
if (response.body === null) {
|
|
412
417
|
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
413
418
|
if (buffer.byteLength > maxBytes)
|
|
414
|
-
throw
|
|
419
|
+
throw tooLarge(buffer.byteLength);
|
|
415
420
|
return buffer;
|
|
416
421
|
}
|
|
417
422
|
const reader = response.body.getReader();
|
|
418
423
|
const chunks = [];
|
|
419
424
|
let total = 0;
|
|
420
425
|
for (;;) {
|
|
421
|
-
const
|
|
426
|
+
const idleTimeoutMs = options?.idleTimeoutMs;
|
|
427
|
+
const idleMessage = options?.idleMessage;
|
|
428
|
+
const { done, value } = idleTimeoutMs === undefined
|
|
429
|
+
? await reader.read()
|
|
430
|
+
: await new Promise((resolve, reject) => {
|
|
431
|
+
const timer = setTimeout(() => {
|
|
432
|
+
// Abort the transfer, then name WHY in the caller's vocabulary.
|
|
433
|
+
void reader.cancel(new Error('registry tarball idle timeout')).catch(() => { });
|
|
434
|
+
reject(new RegistryError('registry-tarball-fetch-failed', idleMessage?.() ?? `no bytes arrived for ${idleTimeoutMs} ms (idle timeout)`));
|
|
435
|
+
}, idleTimeoutMs);
|
|
436
|
+
reader.read().then(result => { clearTimeout(timer); resolve(result); }, error => { clearTimeout(timer); reject(error); });
|
|
437
|
+
});
|
|
422
438
|
if (done)
|
|
423
439
|
break;
|
|
440
|
+
if (value === undefined)
|
|
441
|
+
continue;
|
|
424
442
|
total += value.byteLength;
|
|
425
443
|
if (total > maxBytes) {
|
|
426
444
|
await reader.cancel();
|
|
427
|
-
throw
|
|
445
|
+
throw tooLarge(total);
|
|
428
446
|
}
|
|
429
447
|
chunks.push(value);
|
|
430
448
|
}
|
|
@@ -737,13 +755,14 @@ function selectPublishedVersion(name, spec, packument) {
|
|
|
737
755
|
export function createRegistrySession(options) {
|
|
738
756
|
const registryUrl = normalizeRegistryUrl(options.registryUrl);
|
|
739
757
|
const maxTarballBytes = options.maxTarballBytes ?? MAX_DEPENDENCY_ARCHIVE_BYTES;
|
|
740
|
-
const
|
|
758
|
+
const metadataTimeoutMs = options.metadataTimeoutMs ?? DEFAULT_REGISTRY_METADATA_TIMEOUT_MS;
|
|
759
|
+
const tarballTimeoutMs = options.tarballTimeoutMs ?? DEFAULT_REGISTRY_TARBALL_TIMEOUT_MS;
|
|
741
760
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
742
761
|
/** tarball URL per `name@version` key, registered by resolve(). */
|
|
743
762
|
const tarballs = new Map();
|
|
744
|
-
const
|
|
745
|
-
? AbortSignal.timeout(
|
|
746
|
-
: AbortSignal.any([signal, AbortSignal.timeout(
|
|
763
|
+
const timedMetadata = (signal) => signal === undefined
|
|
764
|
+
? AbortSignal.timeout(metadataTimeoutMs)
|
|
765
|
+
: AbortSignal.any([signal, AbortSignal.timeout(metadataTimeoutMs)]);
|
|
747
766
|
const requireRegistry = () => {
|
|
748
767
|
if (registryUrl === '') {
|
|
749
768
|
throw new RegistryError('registry-not-configured', 'no npm registry is configured (config.extensionRegistry)');
|
|
@@ -761,11 +780,11 @@ export function createRegistrySession(options) {
|
|
|
761
780
|
try {
|
|
762
781
|
response = await fetchImpl(url, {
|
|
763
782
|
headers: { accept: 'application/vnd.npm.install-v1+json, application/json' },
|
|
764
|
-
signal:
|
|
783
|
+
signal: timedMetadata(signal),
|
|
765
784
|
});
|
|
766
785
|
}
|
|
767
786
|
catch (error) {
|
|
768
|
-
throw new RegistryError('registry-unavailable', `the npm registry ${base} could not be reached: ${messageOf(error)}`, { cause: error, transport: true });
|
|
787
|
+
throw new RegistryError('registry-unavailable', `the npm registry ${base} could not be reached for ${name} within ${metadataTimeoutMs} ms (metadata timeout): ${messageOf(error)}`, { cause: error, transport: true });
|
|
769
788
|
}
|
|
770
789
|
if (!response.ok) {
|
|
771
790
|
await response.body?.cancel();
|
|
@@ -777,7 +796,9 @@ export function createRegistrySession(options) {
|
|
|
777
796
|
}
|
|
778
797
|
throw new RegistryError('registry-invalid-metadata', `the npm registry ${base} refused ${name} with HTTP ${response.status}`);
|
|
779
798
|
}
|
|
780
|
-
const metadata = await readBoundedBody(response, MAX_REGISTRY_METADATA_BYTES
|
|
799
|
+
const metadata = await readBoundedBody(response, MAX_REGISTRY_METADATA_BYTES, {
|
|
800
|
+
tooLargeMessage: declared => `the registry metadata for ${name} is over the ${MAX_REGISTRY_METADATA_BYTES}-byte cap${declared === undefined ? '' : ` (declared ${declared})`}`,
|
|
801
|
+
});
|
|
781
802
|
let parsed;
|
|
782
803
|
try {
|
|
783
804
|
parsed = JSON.parse(new TextDecoder().decode(metadata));
|
|
@@ -806,24 +827,39 @@ export function createRegistrySession(options) {
|
|
|
806
827
|
// resolve-then-fetch, so this is a programming error, not a package refusal.
|
|
807
828
|
throw new RegistryError('registry-invalid-metadata', `the registry tarball ${source.requested} was not resolved by this session`);
|
|
808
829
|
}
|
|
830
|
+
let host = 'unknown host';
|
|
831
|
+
try {
|
|
832
|
+
host = new URL(url).host;
|
|
833
|
+
}
|
|
834
|
+
catch {
|
|
835
|
+
// A tarball URL is validated as http(s) at resolve time; keep a safe label.
|
|
836
|
+
}
|
|
837
|
+
const label = `${source.requested} from ${host}`;
|
|
809
838
|
let response;
|
|
810
839
|
try {
|
|
811
|
-
|
|
840
|
+
// NO wall-clock deadline here: the bytes are digest-verified, so a large
|
|
841
|
+
// dependency may transfer for minutes. Only the caller's signal and the
|
|
842
|
+
// IDLE timeout below can abort it.
|
|
843
|
+
response = await fetchImpl(url, signal === undefined ? {} : { signal });
|
|
812
844
|
}
|
|
813
845
|
catch (error) {
|
|
814
|
-
throw new RegistryError('registry-tarball-fetch-failed', `the tarball for ${
|
|
846
|
+
throw new RegistryError('registry-tarball-fetch-failed', `the tarball for ${label} could not be downloaded (timeout or transport, not the size cap; the cap is ${maxTarballBytes} bytes): ${messageOf(error)}`, { cause: error });
|
|
815
847
|
}
|
|
816
848
|
if (!response.ok) {
|
|
817
849
|
await response.body?.cancel();
|
|
818
|
-
throw new RegistryError('registry-tarball-fetch-failed', `the tarball for ${
|
|
850
|
+
throw new RegistryError('registry-tarball-fetch-failed', `the tarball for ${label} answered HTTP ${response.status} (not the size cap)`);
|
|
819
851
|
}
|
|
820
852
|
try {
|
|
821
|
-
return await readBoundedBody(response, maxTarballBytes
|
|
853
|
+
return await readBoundedBody(response, maxTarballBytes, {
|
|
854
|
+
idleTimeoutMs: tarballTimeoutMs,
|
|
855
|
+
tooLargeMessage: declared => `the tarball for ${label} is over the ${maxTarballBytes}-byte cap${declared === undefined ? '' : ` (${declared} bytes)`}`,
|
|
856
|
+
idleMessage: () => `the tarball for ${label} timed out: no bytes arrived for ${tarballTimeoutMs} ms (timeout, not the ${maxTarballBytes}-byte cap)`,
|
|
857
|
+
});
|
|
822
858
|
}
|
|
823
859
|
catch (error) {
|
|
824
860
|
if (error instanceof RegistryError)
|
|
825
861
|
throw error;
|
|
826
|
-
throw new RegistryError('registry-tarball-fetch-failed', `the tarball for ${
|
|
862
|
+
throw new RegistryError('registry-tarball-fetch-failed', `the tarball for ${label} could not be read (timeout or transport, not the size cap): ${messageOf(error)}`, { cause: error });
|
|
827
863
|
}
|
|
828
864
|
},
|
|
829
865
|
};
|
package/lib/extensions-api.d.ts
CHANGED
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
*/
|
|
16
16
|
/** One extension, as the UI needs it. */
|
|
17
17
|
/** What kind of prerequisite an extension (or a model it serves) has. */
|
|
18
|
-
export type ExtensionRequirementKind = 'store' | 'source' | 'dependencies'
|
|
18
|
+
export type ExtensionRequirementKind = 'store' | 'source' | 'dependencies'
|
|
19
|
+
/** Optional tool-runtime packages (optionalDependencies) the extension's tools load. */
|
|
20
|
+
| 'runtime' | 'assets' | 'executable' | 'harness-model' | 'platform' | 'integrity' | 'activation';
|
|
19
21
|
/** The action that clears an unmet requirement, when the deployment supports it. */
|
|
20
22
|
export type ExtensionRequirementAction = 'install' | 'prepare' | 'enable' | 'config' | 'none';
|
|
21
23
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions-api.d.ts","sourceRoot":"","sources":["../src/extensions-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,yCAAyC;AACzC,yEAAyE;AACzE,MAAM,MAAM,wBAAwB,GAChC,OAAO,GACP,QAAQ,GACR,cAAc,
|
|
1
|
+
{"version":3,"file":"extensions-api.d.ts","sourceRoot":"","sources":["../src/extensions-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -52,6 +52,14 @@ import { stagedInstallFromDirectory, type ExtensionLifecycle, type InstallDepend
|
|
|
52
52
|
import type { ExtensionInstallResult, ExtensionPrepareResult, ExtensionToggleResult, ExtensionsDescribeResult, ModelToolsRemote } from './extensions-api.ts';
|
|
53
53
|
import type { AcquisitionSource } from './asset-acquisition.ts';
|
|
54
54
|
import type { PrepareAssetsSurface } from './prepared-assets.ts';
|
|
55
|
+
/**
|
|
56
|
+
* The default dependency-graph depth bound for registry installs (task-116).
|
|
57
|
+
*
|
|
58
|
+
* The SDK default (3) is too shallow for real trees; onnxruntime-node reaches
|
|
59
|
+
* `define-data-property` at depth 4. Preinstalled packages are leaves, so this
|
|
60
|
+
* only bounds registry-resolved graphs.
|
|
61
|
+
*/
|
|
62
|
+
export declare const DEFAULT_REGISTRY_DEPENDENCY_DEPTH = 12;
|
|
55
63
|
/** What the host can report about the shared harness model provider (declarative extensions). */
|
|
56
64
|
export interface HarnessProviderStatus {
|
|
57
65
|
/** Whether a provider is composed and able to serve declarative extensions. */
|
|
@@ -112,6 +120,8 @@ export type ExtensionsServiceErrorCode =
|
|
|
112
120
|
| 'extension-preparation-failed'
|
|
113
121
|
/** A prerequisite the deployment cannot satisfy blocks activation before any lifecycle call. */
|
|
114
122
|
| 'extension-requirement-unmet'
|
|
123
|
+
/** The extension's optional tool runtime is not installed, so its tools cannot load. */
|
|
124
|
+
| 'extension-runtime-unavailable'
|
|
115
125
|
/** Registry mode was selected but no registry URL is configured. */
|
|
116
126
|
| 'extension-registry-unconfigured'
|
|
117
127
|
/** The registry has no such package, version, or dist-tag (HTTP 404 / no matching version). */
|
|
@@ -190,6 +200,20 @@ export interface ExtensionsServiceOptions {
|
|
|
190
200
|
readonly registryUrl?: string;
|
|
191
201
|
/** Hard cap on one registry package tarball; defaults to the SDK archive bound (256 MiB). */
|
|
192
202
|
readonly registryTarballMaxBytes?: number;
|
|
203
|
+
/**
|
|
204
|
+
* IDLE timeout for one registry tarball download, in ms; defaults to 10 minutes.
|
|
205
|
+
*
|
|
206
|
+
* Separate from the short metadata timeout: onnxruntime-node is hundreds of MB,
|
|
207
|
+
* and a moving transfer must not be aborted by the packument budget. Aborts only
|
|
208
|
+
* when NO bytes arrive for this long; the byte cap remains the real bound.
|
|
209
|
+
*/
|
|
210
|
+
readonly registryTarballTimeoutMs?: number;
|
|
211
|
+
/**
|
|
212
|
+
* Dependency-graph depth bound for registry installs; defaults to
|
|
213
|
+
* {@link DEFAULT_REGISTRY_DEPENDENCY_DEPTH} (12). Configurable because real
|
|
214
|
+
* dependency trees vary; a refusal names the level and the package.
|
|
215
|
+
*/
|
|
216
|
+
readonly registryDependencyDepth?: number;
|
|
193
217
|
/** INTERNAL TEST SEAM: the directory installer, defaulting to the SDK's staged path. */
|
|
194
218
|
readonly installDirectory?: DirectoryInstaller;
|
|
195
219
|
/** INTERNAL TEST SEAM: the content digest, defaulting to the SDK's installed-content digest. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions-service.d.ts","sourceRoot":"","sources":["../src/extensions-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;
|
|
1
|
+
{"version":3,"file":"extensions-service.d.ts","sourceRoot":"","sources":["../src/extensions-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,11 +48,20 @@
|
|
|
48
48
|
*
|
|
49
49
|
* @module @try-works/dsh-model-as-tool/extensions-service
|
|
50
50
|
*/
|
|
51
|
-
import { accessSync, constants, existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
51
|
+
import { accessSync, constants, cpSync, existsSync, mkdtempSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
52
|
+
import { tmpdir } from 'node:os';
|
|
52
53
|
import { dirname, join, resolve } from 'node:path';
|
|
53
|
-
import { createTarGzipArchiveSource, digestInstalledContent, discoverExtension, ExtensionStore, ManagementError, stagedInstall, stagedInstallFromDirectory, } from '@try-works/tool-mode-extension-sdk';
|
|
54
|
-
import { createFirstPartyDependencyGraph, createRegistryDependencyGraph, createRegistrySession, DEFAULT_REGISTRY_URL, MAX_DEPENDENCY_ARCHIVE_BYTES, RegistryError, resolveFirstPartyDependency, } from "./extension-dependencies.js";
|
|
54
|
+
import { createTarGzipArchiveSource, digestInstalledContent, discoverExtension, ExtensionStore, installDependencyGraph, ManagementError, stagedInstall, stagedInstallFromDirectory, } from '@try-works/tool-mode-extension-sdk';
|
|
55
|
+
import { createFirstPartyDependencyGraph, createRegistryDependencyGraph, createRegistrySession, DEFAULT_REGISTRY_URL, MAX_DEPENDENCY_ARCHIVE_BYTES, RegistryError, resolveFirstPartyDependency, satisfiesRegistryRange, } from "./extension-dependencies.js";
|
|
55
56
|
import { createHttpSource } from "./http-acquisition.js";
|
|
57
|
+
/**
|
|
58
|
+
* The default dependency-graph depth bound for registry installs (task-116).
|
|
59
|
+
*
|
|
60
|
+
* The SDK default (3) is too shallow for real trees; onnxruntime-node reaches
|
|
61
|
+
* `define-data-property` at depth 4. Preinstalled packages are leaves, so this
|
|
62
|
+
* only bounds registry-resolved graphs.
|
|
63
|
+
*/
|
|
64
|
+
export const DEFAULT_REGISTRY_DEPENDENCY_DEPTH = 12;
|
|
56
65
|
/**
|
|
57
66
|
* The readiness values that permit activation (the SDK's callable set).
|
|
58
67
|
*
|
|
@@ -77,6 +86,7 @@ const REQUIREMENT_PRIORITY = [
|
|
|
77
86
|
'integrity',
|
|
78
87
|
'platform',
|
|
79
88
|
'dependencies',
|
|
89
|
+
'runtime',
|
|
80
90
|
'harness-model',
|
|
81
91
|
'executable',
|
|
82
92
|
'assets',
|
|
@@ -105,7 +115,8 @@ function blocksRow(installed, requirement) {
|
|
|
105
115
|
|| requirement.kind === 'source'
|
|
106
116
|
|| requirement.kind === 'dependencies'
|
|
107
117
|
|| requirement.kind === 'platform'
|
|
108
|
-
|| requirement.kind === 'harness-model'
|
|
118
|
+
|| requirement.kind === 'harness-model'
|
|
119
|
+
|| requirement.kind === 'runtime';
|
|
109
120
|
}
|
|
110
121
|
/** Build one requirement value. */
|
|
111
122
|
function requirement(kind, satisfied, reason, action = 'none') {
|
|
@@ -178,10 +189,11 @@ const EMPTY_FACTS = {
|
|
|
178
189
|
executionKind: undefined,
|
|
179
190
|
platforms: [],
|
|
180
191
|
dependencies: [],
|
|
192
|
+
optionalDependencies: [],
|
|
181
193
|
problem: null,
|
|
182
194
|
};
|
|
183
|
-
/** Read
|
|
184
|
-
function readDeclaredDependencies(packageDir) {
|
|
195
|
+
/** Read one package.json dependency field as name→range pairs; empty when unreadable. */
|
|
196
|
+
function readDeclaredDependencies(packageDir, field = 'dependencies') {
|
|
185
197
|
if (packageDir === null)
|
|
186
198
|
return [];
|
|
187
199
|
try {
|
|
@@ -191,7 +203,7 @@ function readDeclaredDependencies(packageDir) {
|
|
|
191
203
|
// SAFETY: the value came from JSON.parse and the object guard above; only
|
|
192
204
|
// string-valued dependency specs are kept, so an unexpected shape yields an
|
|
193
205
|
// empty declaration rather than a trusted one.
|
|
194
|
-
const dependencies = parsed
|
|
206
|
+
const dependencies = parsed[field];
|
|
195
207
|
if (typeof dependencies !== 'object' || dependencies === null || Array.isArray(dependencies))
|
|
196
208
|
return [];
|
|
197
209
|
const declared = [];
|
|
@@ -214,6 +226,7 @@ function readDeclaredDependencies(packageDir) {
|
|
|
214
226
|
*/
|
|
215
227
|
function readExtensionFacts(packageDir) {
|
|
216
228
|
const dependencies = readDeclaredDependencies(packageDir);
|
|
229
|
+
const optionalDependencies = readDeclaredDependencies(packageDir, 'optionalDependencies');
|
|
217
230
|
try {
|
|
218
231
|
const discovery = discoverExtension(packageDir);
|
|
219
232
|
const manifest = discovery.manifest;
|
|
@@ -226,6 +239,7 @@ function readExtensionFacts(packageDir) {
|
|
|
226
239
|
executionKind: manifest.execution.kind,
|
|
227
240
|
platforms: manifest.models.flatMap(model => model.platforms),
|
|
228
241
|
dependencies,
|
|
242
|
+
optionalDependencies,
|
|
229
243
|
problem: null,
|
|
230
244
|
};
|
|
231
245
|
}
|
|
@@ -236,6 +250,7 @@ function readExtensionFacts(packageDir) {
|
|
|
236
250
|
packageVersion: null,
|
|
237
251
|
packageDir,
|
|
238
252
|
dependencies,
|
|
253
|
+
optionalDependencies,
|
|
239
254
|
problem: `the package at ${packageDir} is not a usable extension: ${messageOf(error)}`,
|
|
240
255
|
};
|
|
241
256
|
}
|
|
@@ -252,6 +267,146 @@ function platformLabel(platform) {
|
|
|
252
267
|
function hostPlatformMatches(platforms) {
|
|
253
268
|
return platforms.some(platform => platform.os === process.platform && platform.arch === process.arch);
|
|
254
269
|
}
|
|
270
|
+
/** The sidecar filename inside the extension store (host-owned, never inside a package). */
|
|
271
|
+
const RUNTIME_DEPENDENCY_FILE = 'runtime-dependencies.json';
|
|
272
|
+
/** Read the store's runtime-dependency sidecar; a missing/corrupt document is empty. */
|
|
273
|
+
function readRuntimeDependencyDocument(storeDir) {
|
|
274
|
+
try {
|
|
275
|
+
const parsed = JSON.parse(readFileSync(join(storeDir, RUNTIME_DEPENDENCY_FILE), 'utf8'));
|
|
276
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
277
|
+
return { updatedAt: '', extensions: {} };
|
|
278
|
+
const extensions = parsed.extensions;
|
|
279
|
+
if (typeof extensions !== 'object' || extensions === null || Array.isArray(extensions)) {
|
|
280
|
+
return { updatedAt: '', extensions: {} };
|
|
281
|
+
}
|
|
282
|
+
// SAFETY: the container was checked to be a non-array object; each entry is
|
|
283
|
+
// read defensively by the requirement model, and a malformed entry is ignored.
|
|
284
|
+
return { updatedAt: '', extensions: extensions };
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
return { updatedAt: '', extensions: {} };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/** Merge one extension's runtime attempts into the store sidecar (atomic replace). */
|
|
291
|
+
function writeRuntimeDependencyDocument(storeDir, extensionId, version, optional) {
|
|
292
|
+
try {
|
|
293
|
+
const current = readRuntimeDependencyDocument(storeDir);
|
|
294
|
+
const document = {
|
|
295
|
+
updatedAt: new Date().toISOString(),
|
|
296
|
+
extensions: {
|
|
297
|
+
...current.extensions,
|
|
298
|
+
[extensionId]: { version, optional },
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
const target = join(storeDir, RUNTIME_DEPENDENCY_FILE);
|
|
302
|
+
const temporary = `${target}.${process.pid}.${Date.now().toString(36)}.tmp`;
|
|
303
|
+
writeFileSync(temporary, `${JSON.stringify(document, null, 2)}\n`, 'utf8');
|
|
304
|
+
rmSync(target, { force: true });
|
|
305
|
+
cpSync(temporary, target);
|
|
306
|
+
rmSync(temporary, { force: true });
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
// Diagnostics only: failing to record an optional-runtime attempt must never
|
|
310
|
+
// turn a successful install into a failure. The requirement probes the tree.
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
/** Read one installed dependency's package.json version, or undefined. */
|
|
314
|
+
function readInstalledDependencyVersion(installPath, name) {
|
|
315
|
+
try {
|
|
316
|
+
const parsed = JSON.parse(readFileSync(join(installPath, 'node_modules', ...name.split('/'), 'package.json'), 'utf8'));
|
|
317
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
318
|
+
return undefined;
|
|
319
|
+
const version = parsed.version;
|
|
320
|
+
return typeof version === 'string' ? version : undefined;
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
return undefined;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Atomically REPLACE one installed record in the store lock.
|
|
328
|
+
*
|
|
329
|
+
* The SDK's `recordInstall` deliberately refuses an already-recorded identity
|
|
330
|
+
* (upgrade protection), and it exposes no update call. The host legitimately
|
|
331
|
+
* changes an installed copy AFTER activation-free materialization (optional tool
|
|
332
|
+
* runtimes): the recorded content digest must match the bytes the operator now
|
|
333
|
+
* has, and the lock is the host-owned document that carries it. The replacement is
|
|
334
|
+
* a same-file atomic rename, so a crash leaves either the old or the new record.
|
|
335
|
+
* @param storeDir - the configured store.
|
|
336
|
+
* @param updated - the record to store, keyed by identity and version.
|
|
337
|
+
* @returns whether the record was found and replaced.
|
|
338
|
+
*/
|
|
339
|
+
function replaceInstalledRecord(storeDir, updated) {
|
|
340
|
+
try {
|
|
341
|
+
const store = new ExtensionStore(storeDir);
|
|
342
|
+
const lock = store.readLock();
|
|
343
|
+
if (lock.corrupt)
|
|
344
|
+
return false;
|
|
345
|
+
const index = lock.value.extensions.findIndex(candidate => candidate.extensionId === updated.extensionId && candidate.version === updated.version);
|
|
346
|
+
if (index === -1)
|
|
347
|
+
return false;
|
|
348
|
+
const extensions = [...lock.value.extensions];
|
|
349
|
+
extensions[index] = updated;
|
|
350
|
+
const target = store.lockPath;
|
|
351
|
+
const temporary = `${target}.${process.pid}.${Date.now().toString(36)}.tmp`;
|
|
352
|
+
writeFileSync(temporary, `${JSON.stringify({ lockVersion: 1, extensions }, null, 2)}\n`, 'utf8');
|
|
353
|
+
renameSync(temporary, target);
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Directories to search for OPERATOR-PREINSTALLED packages, deepest-nested first.
|
|
362
|
+
*
|
|
363
|
+
* A preinstalled package is a LEAF: its transitive dependencies already sit in its
|
|
364
|
+
* OWN `node_modules` (npm nests them when versions conflict), so root-level lookup
|
|
365
|
+
* alone misses e.g. `@huggingface/transformers/node_modules/onnxruntime-web`. This
|
|
366
|
+
* enumerates the preinstalled root, each top-level package directory, and (bounded)
|
|
367
|
+
* their nested package directories; the resolver tries each in order.
|
|
368
|
+
* @param root - the operator-configured preinstalled root (its `node_modules` is searched).
|
|
369
|
+
* @param depth - how many nested package levels to enumerate (bounded).
|
|
370
|
+
* @returns candidate package roots, root first.
|
|
371
|
+
*/
|
|
372
|
+
function preinstalledSearchRoots(root, depth = 3) {
|
|
373
|
+
const candidates = [root];
|
|
374
|
+
const visit = (nodeModules, remaining) => {
|
|
375
|
+
if (remaining <= 0)
|
|
376
|
+
return;
|
|
377
|
+
let entries;
|
|
378
|
+
try {
|
|
379
|
+
entries = readdirSync(nodeModules);
|
|
380
|
+
}
|
|
381
|
+
catch {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
for (const entry of entries) {
|
|
385
|
+
if (entry.startsWith('.'))
|
|
386
|
+
continue;
|
|
387
|
+
const entryPath = join(nodeModules, entry);
|
|
388
|
+
if (entry.startsWith('@')) {
|
|
389
|
+
let scoped;
|
|
390
|
+
try {
|
|
391
|
+
scoped = readdirSync(entryPath);
|
|
392
|
+
}
|
|
393
|
+
catch {
|
|
394
|
+
continue;
|
|
395
|
+
}
|
|
396
|
+
for (const name of scoped) {
|
|
397
|
+
const packageDir = join(entryPath, name);
|
|
398
|
+
candidates.push(packageDir);
|
|
399
|
+
visit(join(packageDir, 'node_modules'), remaining - 1);
|
|
400
|
+
}
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
candidates.push(entryPath);
|
|
404
|
+
visit(join(entryPath, 'node_modules'), remaining - 1);
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
visit(join(root, 'node_modules'), depth);
|
|
408
|
+
return candidates;
|
|
409
|
+
}
|
|
255
410
|
/**
|
|
256
411
|
* Every declared deployment whose recorded readiness does not permit activation.
|
|
257
412
|
*
|
|
@@ -707,6 +862,9 @@ export class ExtensionsService {
|
|
|
707
862
|
else {
|
|
708
863
|
requirements.push(requirement('integrity', false, input.integrityReason ?? `the installed content's integrity is ${input.integrity}`, 'install'));
|
|
709
864
|
}
|
|
865
|
+
// RUNTIME: optional tool-runtime packages must be materialized, or the
|
|
866
|
+
// extension's tools load and fail at call time — which is not activation.
|
|
867
|
+
requirements.push(this.#runtimeRequirement(input));
|
|
710
868
|
// HARNESS MODEL: only declarative packages are served by the host broker.
|
|
711
869
|
if (input.facts.executionKind === 'declarative') {
|
|
712
870
|
requirements.push(this.#harnessModelRequirement());
|
|
@@ -795,6 +953,45 @@ export class ExtensionsService {
|
|
|
795
953
|
? requirement('dependencies', true, `all ${count} declared runtime dependenc${count === 1 ? 'y resolves' : 'ies resolve'} in the host's installed tree`)
|
|
796
954
|
: requirement('dependencies', false, `the host's tree is missing ${missing.length} declared runtime dependenc${missing.length === 1 ? 'y' : 'ies'}: ${missing.join(', ')}; install the dependency for the host first`, 'none');
|
|
797
955
|
}
|
|
956
|
+
/**
|
|
957
|
+
* The OPTIONAL tool-runtime requirement.
|
|
958
|
+
*
|
|
959
|
+
* Module extensions declare the packages their tools `require()` at call time as
|
|
960
|
+
* optionalDependencies (e.g. tongue's `@desert-ant-labs/tongue`). If one is absent
|
|
961
|
+
* the extension still activates and its tools fail at call time, so this
|
|
962
|
+
* requirement BLOCKS activation instead: a tool that cannot load is not served.
|
|
963
|
+
* The sidecar records why a materialization attempt failed (the lock cannot).
|
|
964
|
+
*/
|
|
965
|
+
#runtimeRequirement(input) {
|
|
966
|
+
const declared = input.facts.optionalDependencies;
|
|
967
|
+
if (declared.length === 0) {
|
|
968
|
+
return requirement('runtime', true, 'the package declares no optional tool runtime');
|
|
969
|
+
}
|
|
970
|
+
if (!input.installed || input.record === undefined) {
|
|
971
|
+
return requirement('runtime', true, 'not installed yet; optional tool runtimes are materialized and verified at install time');
|
|
972
|
+
}
|
|
973
|
+
const recorded = readRuntimeDependencyDocument(input.storeDir).extensions[input.id];
|
|
974
|
+
const unresolved = [];
|
|
975
|
+
const resolved = [];
|
|
976
|
+
for (const dependency of declared) {
|
|
977
|
+
const installedVersion = readInstalledDependencyVersion(input.record.installPath, dependency.name);
|
|
978
|
+
if (installedVersion === undefined) {
|
|
979
|
+
const attempt = recorded?.optional.find(entry => entry.name === dependency.name && !entry.satisfied);
|
|
980
|
+
unresolved.push(`${dependency.name} ${dependency.range} is not installed inside the extension`
|
|
981
|
+
+ (attempt?.error === undefined ? '' : `: ${attempt.error}`));
|
|
982
|
+
}
|
|
983
|
+
else if (!satisfiesRegistryRange(installedVersion, dependency.range)) {
|
|
984
|
+
unresolved.push(`${dependency.name} is installed at ${installedVersion}, which does not satisfy ${dependency.range}`);
|
|
985
|
+
}
|
|
986
|
+
else {
|
|
987
|
+
resolved.push(`${dependency.name}@${installedVersion}`);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (unresolved.length === 0) {
|
|
991
|
+
return requirement('runtime', true, `the optional tool runtime${resolved.length === 1 ? ' is' : 's are'} materialized (${resolved.join(', ')})`);
|
|
992
|
+
}
|
|
993
|
+
return requirement('runtime', false, `the extension's tools cannot load: ${unresolved.join('; ')}`, 'install');
|
|
994
|
+
}
|
|
798
995
|
/** The harness-model requirement for a declarative package. */
|
|
799
996
|
#harnessModelRequirement() {
|
|
800
997
|
const status = this.#options.harnessProviderStatus?.();
|
|
@@ -1119,6 +1316,9 @@ export class ExtensionsService {
|
|
|
1119
1316
|
registryUrl,
|
|
1120
1317
|
archiveFactory: createTarGzipArchiveSource,
|
|
1121
1318
|
maxTarballBytes: this.#options.registryTarballMaxBytes ?? MAX_DEPENDENCY_ARCHIVE_BYTES,
|
|
1319
|
+
...this.#options.registryTarballTimeoutMs === undefined
|
|
1320
|
+
? {}
|
|
1321
|
+
: { tarballTimeoutMs: this.#options.registryTarballTimeoutMs },
|
|
1122
1322
|
});
|
|
1123
1323
|
let resolved;
|
|
1124
1324
|
try {
|
|
@@ -1141,7 +1341,7 @@ export class ExtensionsService {
|
|
|
1141
1341
|
// Registry metadata recorded AS DATA, never as trust: the bytes are
|
|
1142
1342
|
// verified against the same sha512 before anything is extracted.
|
|
1143
1343
|
provenance: { registryIntegrity: resolved.integrity },
|
|
1144
|
-
dependencies:
|
|
1344
|
+
dependencies: this.#installGraph(session),
|
|
1145
1345
|
});
|
|
1146
1346
|
}
|
|
1147
1347
|
catch (error) {
|
|
@@ -1164,6 +1364,10 @@ export class ExtensionsService {
|
|
|
1164
1364
|
if (installed.archiveDigest.trim().length === 0) {
|
|
1165
1365
|
throw new ExtensionsServiceError('extension-digest-unavailable', `${installed.extensionId}@${installed.version} was installed without a content digest, so it cannot be verified before activation`);
|
|
1166
1366
|
}
|
|
1367
|
+
// Optional tool runtimes are materialized AFTER the package install and are
|
|
1368
|
+
// NOT allowed to fail it: tongue/voz tools `require()` an optional package at
|
|
1369
|
+
// call time, and the requirement model blocks activation if it is absent.
|
|
1370
|
+
await this.#materializeOptionalRuntimes(storeDir, installed, session, signal);
|
|
1167
1371
|
return {
|
|
1168
1372
|
id: installed.extensionId,
|
|
1169
1373
|
version: installed.version,
|
|
@@ -1172,6 +1376,136 @@ export class ExtensionsService {
|
|
|
1172
1376
|
resolvedVersion: resolved.version,
|
|
1173
1377
|
};
|
|
1174
1378
|
}
|
|
1379
|
+
/**
|
|
1380
|
+
* The dependency graph used on the REGISTRY install path (regular AND optional).
|
|
1381
|
+
*
|
|
1382
|
+
* PRECEDENCE: when the operator's preinstalled gate is ON and the host's own
|
|
1383
|
+
* tree holds a package satisfying the range, that operator-completed content is
|
|
1384
|
+
* preferred. The SDK copies it with provenance `preinstalled` and records that
|
|
1385
|
+
* no lifecycle script was run. Anything NOT preinstalled falls to the registry
|
|
1386
|
+
* arm, where EXT-10 still refuses script-declaring packages.
|
|
1387
|
+
*
|
|
1388
|
+
* DEPTH: preinstalled packages are LEAVES for graph purposes — their transitive
|
|
1389
|
+
* tree travels with them — but real registry trees (onnxruntime-node) exceed the
|
|
1390
|
+
* SDK's default 3-level bound, so the host raises the default to
|
|
1391
|
+
* {@link DEFAULT_REGISTRY_DEPENDENCY_DEPTH} and makes it configurable.
|
|
1392
|
+
* @param session - the registry session.
|
|
1393
|
+
* @returns the graph.
|
|
1394
|
+
*/
|
|
1395
|
+
#installGraph(session) {
|
|
1396
|
+
const depth = this.#options.registryDependencyDepth ?? DEFAULT_REGISTRY_DEPENDENCY_DEPTH;
|
|
1397
|
+
const registryGraph = { ...createRegistryDependencyGraph(session), maxDepth: depth };
|
|
1398
|
+
const preinstalledRoot = this.#options.preinstalledDependenciesRoot ?? '';
|
|
1399
|
+
const allowPreinstalled = this.#options.allowPreinstalledDependencies === true && preinstalledRoot !== '';
|
|
1400
|
+
if (!allowPreinstalled)
|
|
1401
|
+
return registryGraph;
|
|
1402
|
+
const preinstalledRoots = preinstalledSearchRoots(preinstalledRoot);
|
|
1403
|
+
return {
|
|
1404
|
+
resolver: {
|
|
1405
|
+
async resolve(name, range) {
|
|
1406
|
+
// Prefer operator-completed content, root first and then nested package
|
|
1407
|
+
// trees: a preinstalled package's transitive deps live in ITS OWN
|
|
1408
|
+
// node_modules, so root-level lookup alone would fall through to the
|
|
1409
|
+
// registry and refuse a script-declaring leaf under EXT-10.
|
|
1410
|
+
for (const candidateRoot of preinstalledRoots) {
|
|
1411
|
+
try {
|
|
1412
|
+
const found = resolveFirstPartyDependency({ sourcePackageDir: candidateRoot }, name, range);
|
|
1413
|
+
return { name: found.name, version: found.version, dir: found.directory, provenance: 'preinstalled' };
|
|
1414
|
+
}
|
|
1415
|
+
catch {
|
|
1416
|
+
continue;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
return registryGraph.resolver.resolve(name, range);
|
|
1420
|
+
},
|
|
1421
|
+
},
|
|
1422
|
+
archive: registryGraph.archive,
|
|
1423
|
+
allowPreinstalled: true,
|
|
1424
|
+
preinstalledRoot,
|
|
1425
|
+
maxDepth: depth,
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* Materialize the extension's optionalDependencies without failing the install.
|
|
1430
|
+
*
|
|
1431
|
+
* Each declaration is resolved and materialized through the SAME SDK dependency
|
|
1432
|
+
* graph discipline as regular dependencies (bounded fetch, sha512 verification,
|
|
1433
|
+
* EXT-10 script refusal) into a scratch package, then merged into the
|
|
1434
|
+
* extension's own node_modules. A failure is RECORDED (store sidecar) and the
|
|
1435
|
+
* requirement model blocks activation instead; the package install stands.
|
|
1436
|
+
*
|
|
1437
|
+
* The store record's content digest is recomputed after a successful merge,
|
|
1438
|
+
* because the installed bytes legitimately changed; the archive digest (the
|
|
1439
|
+
* tarball identity) is untouched.
|
|
1440
|
+
* @param storeDir - the configured store.
|
|
1441
|
+
* @param installed - the just-installed package.
|
|
1442
|
+
* @param session - the registry session used for the install.
|
|
1443
|
+
* @param signal - cancellation.
|
|
1444
|
+
*/
|
|
1445
|
+
async #materializeOptionalRuntimes(storeDir, installed, session, signal) {
|
|
1446
|
+
const optional = readDeclaredDependencies(installed.installPath, 'optionalDependencies');
|
|
1447
|
+
if (optional.length === 0)
|
|
1448
|
+
return;
|
|
1449
|
+
const attempts = [];
|
|
1450
|
+
const locked = [];
|
|
1451
|
+
for (const dependency of optional) {
|
|
1452
|
+
signal?.throwIfAborted();
|
|
1453
|
+
const scratch = mkdtempSync(join(tmpdir(), 'dsh-optional-runtime-'));
|
|
1454
|
+
try {
|
|
1455
|
+
writeFileSync(join(scratch, 'package.json'), `${JSON.stringify({ name: 'dsh-optional-runtime-host', version: '0.0.0', dependencies: { [dependency.name]: dependency.range } }, null, 2)}\n`, 'utf8');
|
|
1456
|
+
const materialized = await installDependencyGraph(scratch, this.#installGraph(session));
|
|
1457
|
+
const sourceNodeModules = join(scratch, 'node_modules');
|
|
1458
|
+
const targetNodeModules = join(installed.installPath, 'node_modules');
|
|
1459
|
+
if (existsSync(sourceNodeModules)) {
|
|
1460
|
+
for (const name of readdirSync(sourceNodeModules)) {
|
|
1461
|
+
const from = join(sourceNodeModules, name);
|
|
1462
|
+
const to = join(targetNodeModules, name);
|
|
1463
|
+
if (existsSync(to)) {
|
|
1464
|
+
const kept = readInstalledDependencyVersion(installed.installPath, name);
|
|
1465
|
+
const wanted = materialized.find(entry => entry.name === name);
|
|
1466
|
+
if (kept !== undefined && wanted !== undefined && kept !== wanted.version) {
|
|
1467
|
+
throw new Error(`${name} is already installed at ${kept}, but the optional runtime needs ${wanted.version}`);
|
|
1468
|
+
}
|
|
1469
|
+
continue;
|
|
1470
|
+
}
|
|
1471
|
+
cpSync(from, to, { recursive: true });
|
|
1472
|
+
}
|
|
1473
|
+
locked.push(...materialized);
|
|
1474
|
+
}
|
|
1475
|
+
const own = materialized.find(entry => entry.name === dependency.name);
|
|
1476
|
+
attempts.push({
|
|
1477
|
+
name: dependency.name,
|
|
1478
|
+
range: dependency.range,
|
|
1479
|
+
satisfied: true,
|
|
1480
|
+
...own === undefined ? {} : { version: own.version },
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
catch (error) {
|
|
1484
|
+
if (signal?.aborted === true)
|
|
1485
|
+
throw error;
|
|
1486
|
+
attempts.push({ name: dependency.name, range: dependency.range, satisfied: false, error: messageOf(error) });
|
|
1487
|
+
}
|
|
1488
|
+
finally {
|
|
1489
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
writeRuntimeDependencyDocument(storeDir, installed.extensionId, installed.version, attempts);
|
|
1493
|
+
if (locked.length === 0)
|
|
1494
|
+
return;
|
|
1495
|
+
const store = new ExtensionStore(storeDir);
|
|
1496
|
+
const record = store.listInstalled().value.find(candidate => candidate.extensionId === installed.extensionId && candidate.version === installed.version);
|
|
1497
|
+
if (record === undefined)
|
|
1498
|
+
return;
|
|
1499
|
+
const existing = new Set((record.dependencies ?? []).map(entry => entry.name));
|
|
1500
|
+
const additions = locked.filter(entry => !existing.has(entry.name));
|
|
1501
|
+
if (additions.length === 0)
|
|
1502
|
+
return;
|
|
1503
|
+
replaceInstalledRecord(storeDir, {
|
|
1504
|
+
...record,
|
|
1505
|
+
contentDigest: digestInstalledContent(installed.installPath),
|
|
1506
|
+
dependencies: [...(record.dependencies ?? []), ...additions],
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1175
1509
|
/**
|
|
1176
1510
|
* Install one extension from a local source directory (EXT-06 developer mode).
|
|
1177
1511
|
*
|
|
@@ -1319,6 +1653,10 @@ export class ExtensionsService {
|
|
|
1319
1653
|
// that classification while refusing before the lifecycle call.
|
|
1320
1654
|
throw new ExtensionsServiceError('extension-activation-failed', `[INTEGRITY_MISMATCH] ${unmet.reason}`);
|
|
1321
1655
|
}
|
|
1656
|
+
if (unmet.kind === 'runtime') {
|
|
1657
|
+
// Activation that cannot serve the extension's tools is not activation.
|
|
1658
|
+
throw new ExtensionsServiceError('extension-runtime-unavailable', unmet.reason);
|
|
1659
|
+
}
|
|
1322
1660
|
throw new ExtensionsServiceError('extension-requirement-unmet', unmet.reason);
|
|
1323
1661
|
}
|
|
1324
1662
|
const ownedHere = current?.observedActivation === 'active'
|
package/lib/index.d.ts
CHANGED
|
@@ -153,6 +153,19 @@ export interface Config {
|
|
|
153
153
|
extensionRegistry?: string;
|
|
154
154
|
/** Hard cap on one registry package tarball download. Default 256 MiB. */
|
|
155
155
|
extensionTarballMaxBytes?: number;
|
|
156
|
+
/**
|
|
157
|
+
* IDLE timeout for one registry tarball download, in ms. Default 10 minutes.
|
|
158
|
+
* Applies only when NO bytes arrive; a slow large download is not aborted.
|
|
159
|
+
*/
|
|
160
|
+
extensionTarballTimeoutMs?: number;
|
|
161
|
+
/**
|
|
162
|
+
* Dependency-graph depth bound for registry installs. Default 12.
|
|
163
|
+
*
|
|
164
|
+
* Preinstalled dependencies are leaves (their own tree travels with them);
|
|
165
|
+
* registry-resolved graphs are bounded by this, and a refusal names the level
|
|
166
|
+
* and the package.
|
|
167
|
+
*/
|
|
168
|
+
extensionDependencyDepth?: number;
|
|
156
169
|
/**
|
|
157
170
|
* Operator gate: allow dependency content that arrived already materialized.
|
|
158
171
|
*
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAMxC,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAavE,OAAO,EAAoH,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC5K,OAAO,EAAe,KAAK,WAAW,EAAuB,MAAM,8BAA8B,CAAA;AAuCjG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAuB/D,eAAO,MAAM,IAAI,gBAAgB,CAAA;AACjC,eAAO,MAAM,MAAM,UAAY,CAAA;AAE/B;;;GAGG;AACH,eACA,MAAM,qBAAqB,MAAM,CAAA;AAajC,4BAA4B;AAC5B,MAAM,WAAW,MAAM;IACrB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,2DAA2D;IAC3D,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,gEAAgE;IAChE,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,GAAG,CAAC,EAAE;QACJ,0EAA0E;QAC1E,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,0DAA0D;QAC1D,OAAO,CAAC,EAAE,MAAM,CAAA;KACjB,CAAA;IACD;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE;QACP,mEAAmE;QACnE,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,gDAAgD;QAChD,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;IACD;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;;;;;;OAaG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;;;;;;;;;;OAWG;IACH,sBAAsB,CAAC,EAAE,UAAU,GAAG,WAAW,GAAG,MAAM,CAAA;IAC1D;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,0EAA0E;IAC1E,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC;;;;;;;;;;OAUG;IACH,6BAA6B,CAAC,EAAE,OAAO,CAAA;IACvC;;;;;;;OAOG;IACH,4BAA4B,CAAC,EAAE,MAAM,CAAA;IACrC;;;;;;;;;;;;;OAaG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC;;;6DAGyD;IACzD,kBAAkB,CAAC,EAAE,MAAM,iBAAiB,CAAA;IAC5C,mFAAmF;IACnF,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE;QACX,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,kBAAkB,CAAC,EAAE,OAAO,CAAA;QAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAA;QAC5B,sBAAsB,CAAC,EAAE,OAAO,CAAA;QAChC,gBAAgB,CAAC,EAAE,OAAO,CAAA;QAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAA;KAC5B,CAAA;IACD,KAAK,CAAC,EAAE;QACN,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;QAC3B,mBAAmB,CAAC,EAAE,OAAO,CAAA;QAC7B,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;QACzB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;QACtB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,IAAI,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,0BAA0B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,CAAA;KACrE,CAAA;IACD,aAAa,CAAC,EAAE;QACd,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,qBAAqB,CAAC,EAAE,MAAM,CAAA;QAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAA;KAC9B,CAAA;IACD,YAAY,CAAC,EAAE;QACb,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,uBAAuB,CAAC,EAAE,OAAO,CAAA;KAClC,CAAA;IACD,iBAAiB,CAAC,EAAE;QAClB,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,sBAAsB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAA;QAC9C,kBAAkB,CAAC,EAAE,MAAM,CAAA;QAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAA;QAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAA;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAA;QACzB,mBAAmB,CAAC,EAAE,OAAO,CAAA;QAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAA;KAC9B,CAAA;IACD,SAAS,CAAC,EAAE;QACV,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,mBAAmB,CAAC,EAAE,OAAO,CAAA;QAC7B,mBAAmB,CAAC,EAAE,OAAO,CAAA;QAC7B,wBAAwB,CAAC,EAAE,OAAO,CAAA;KACnC,CAAA;IACD,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAA;IAC/C,SAAS,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,OAAO,CAAA;QAChB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,mBAAmB,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,OAAO,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KACpE,CAAA;IACD;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAClC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+DAA+D;IAC/D,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;OAOG;IACH,cAAc,CAAC,EAAE,UAAU,GAAG,eAAe,CAAA;IAC7C;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,WAAW,CAAA;IAC7B;;;;;;;;;;OAUG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAA;IACjC;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC7B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC/B,iEAAiE;IACjE,MAAM,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CACvF;AAkBD,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -103,6 +103,14 @@ export const Config = z.object({
|
|
|
103
103
|
extensionRegistry: z.string().default('https://registry.npmjs.org/'),
|
|
104
104
|
/** Hard cap on one registry tarball download, in bytes. Default 256 MiB. */
|
|
105
105
|
extensionTarballMaxBytes: z.number().min(1).default(256 * 1024 * 1024),
|
|
106
|
+
/**
|
|
107
|
+
* IDLE timeout for one registry tarball download, in ms. Default 10 minutes.
|
|
108
|
+
* Aborts only when NO bytes arrive for this long; a large dependency streaming
|
|
109
|
+
* slowly is not aborted by the short package-metadata timeout.
|
|
110
|
+
*/
|
|
111
|
+
extensionTarballTimeoutMs: z.number().min(1000).default(10 * 60_000),
|
|
112
|
+
/** Depth bound for registry dependency graphs. Default 12 (SDK default is 3). */
|
|
113
|
+
extensionDependencyDepth: z.number().min(1).max(64).default(12),
|
|
106
114
|
allowPreinstalledDependencies: z.boolean().default(false),
|
|
107
115
|
preinstalledDependenciesRoot: z.string().default(''),
|
|
108
116
|
/**
|
|
@@ -337,6 +345,44 @@ export async function apply(ctx, config = {}) {
|
|
|
337
345
|
* install loop; the extension-store block assigns it.
|
|
338
346
|
*/
|
|
339
347
|
let extensionLifecycle;
|
|
348
|
+
/**
|
|
349
|
+
* TASK-117: the catalogue-vs-extension tool-name reconciliation.
|
|
350
|
+
*
|
|
351
|
+
* OWNERSHIP RULE: an INSTALLED extension that declares a tool with a given
|
|
352
|
+
* name OWNS that name — its activation registers the tool, so the catalogue
|
|
353
|
+
* must SKIP its own registration for a contract-backed entry with the same
|
|
354
|
+
* tool name (the live EXTENSION_FAULT was the catalogue winning the race at
|
|
355
|
+
* boot). The skip is recorded; when the owning extension deactivates, the
|
|
356
|
+
* catalogue registration is RESTORED. Deterministic in both orders: the
|
|
357
|
+
* probe reads the durable store, not an in-flight registry.
|
|
358
|
+
*/
|
|
359
|
+
const extensionStore = config.extensionStore !== undefined && config.extensionStore.length > 0
|
|
360
|
+
? new ExtensionStore(config.extensionStore)
|
|
361
|
+
: undefined;
|
|
362
|
+
const catalogueDeferred = new Set();
|
|
363
|
+
const extensionOwnsToolName = (toolName) => {
|
|
364
|
+
if (extensionStore === undefined)
|
|
365
|
+
return false;
|
|
366
|
+
try {
|
|
367
|
+
// Only an ACTIVE extension owns a name at runtime: a disabled (or
|
|
368
|
+
// failed) installation must not keep the catalogue from serving it.
|
|
369
|
+
const active = new Set(extensionStore.readProfileState('default').value
|
|
370
|
+
.filter(entry => entry.desiredActivation === 'active' && entry.observedActivation === 'active')
|
|
371
|
+
.map(entry => entry.extensionId));
|
|
372
|
+
for (const record of extensionStore.listInstalled().value) {
|
|
373
|
+
if (!active.has(record.extensionId))
|
|
374
|
+
continue;
|
|
375
|
+
const discovery = discoverExtension(record.installPath);
|
|
376
|
+
if (discovery.manifest.tools.some(tool => tool.name === toolName))
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
// A broken package cannot own a tool name; the catalogue keeps it.
|
|
382
|
+
return false;
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
};
|
|
340
386
|
/**
|
|
341
387
|
* The extensions the contribution registrar currently admits.
|
|
342
388
|
*
|
|
@@ -373,6 +419,8 @@ export async function apply(ctx, config = {}) {
|
|
|
373
419
|
installSource: config.extensionInstallSource ?? 'auto',
|
|
374
420
|
registryUrl: config.extensionRegistry ?? 'https://registry.npmjs.org/',
|
|
375
421
|
registryTarballMaxBytes: config.extensionTarballMaxBytes ?? 256 * 1024 * 1024,
|
|
422
|
+
registryTarballTimeoutMs: config.extensionTarballTimeoutMs ?? 10 * 60_000,
|
|
423
|
+
registryDependencyDepth: config.extensionDependencyDepth ?? 12,
|
|
376
424
|
/**
|
|
377
425
|
* The operator gate for already-materialized dependencies. OFF by default:
|
|
378
426
|
* a dependency whose package.json declares install-time scripts still
|
|
@@ -411,11 +459,28 @@ export async function apply(ctx, config = {}) {
|
|
|
411
459
|
onActivationChange: (extensionId, active) => {
|
|
412
460
|
if (active) {
|
|
413
461
|
activatedExtensions.add(extensionId);
|
|
462
|
+
// TASK-117: the extension now owns its tool names — withdraw the
|
|
463
|
+
// catalogue registrations for those names BEFORE the lifecycle
|
|
464
|
+
// publishes (the hook runs before activate), so the activation cannot
|
|
465
|
+
// collide with a catalogue tool. The names are deferred, not lost.
|
|
466
|
+
for (const item of resolved.filter(candidate => candidate.entry.contract !== null)) {
|
|
467
|
+
if (!extensionOwnsToolName(item.entry.tool.name))
|
|
468
|
+
continue;
|
|
469
|
+
if (!installed.has(item.entry.id))
|
|
470
|
+
continue;
|
|
471
|
+
uninstall(item.entry.id);
|
|
472
|
+
catalogueDeferred.add(item.entry.id);
|
|
473
|
+
ctx.logger.info(`model-tools: ${item.entry.name}'s tool ${item.entry.tool.name} is taken over by ${extensionId}; `
|
|
474
|
+
+ 'the catalogue registration is withdrawn and deferred');
|
|
475
|
+
}
|
|
414
476
|
return;
|
|
415
477
|
}
|
|
416
478
|
if (extensionLifecycle?.stateOf(extensionId)?.observedActivation !== 'active') {
|
|
417
479
|
activatedExtensions.delete(extensionId);
|
|
418
480
|
}
|
|
481
|
+
// TASK-117: the extension released its tool names — restore every
|
|
482
|
+
// deferred catalogue registration the release freed.
|
|
483
|
+
void restoreDeferredCatalogue();
|
|
419
484
|
},
|
|
420
485
|
/**
|
|
421
486
|
* The harness-model provider status seam (task-93): the thunk evaluates the
|
|
@@ -1110,6 +1175,18 @@ export async function apply(ctx, config = {}) {
|
|
|
1110
1175
|
toolName = existing.toolName;
|
|
1111
1176
|
dispose = () => { };
|
|
1112
1177
|
}
|
|
1178
|
+
else if (extensionOwnsToolName(entry.tool.name)) {
|
|
1179
|
+
/**
|
|
1180
|
+
* TASK-117: an installed extension OWNS this tool name — its
|
|
1181
|
+
* activation registers it, so the catalogue registration is SKIPPED
|
|
1182
|
+
* rather than racing it (the live EXTENSION_FAULT). The deferral is
|
|
1183
|
+
* recorded; the extension's deactivation restores the catalogue tool.
|
|
1184
|
+
*/
|
|
1185
|
+
catalogueDeferred.add(entry.id);
|
|
1186
|
+
ctx.logger.info(`model-tools: ${entry.name}'s tool ${entry.tool.name} is owned by an installed extension; `
|
|
1187
|
+
+ 'the catalogue registration is deferred until the extension releases the name');
|
|
1188
|
+
return false;
|
|
1189
|
+
}
|
|
1113
1190
|
else {
|
|
1114
1191
|
const registered = registerContractTool(ctx, binding, host);
|
|
1115
1192
|
registeredContracts.set(entry.contract, registered);
|
|
@@ -1211,6 +1288,33 @@ export async function apply(ctx, config = {}) {
|
|
|
1211
1288
|
const configuredIds = resolved
|
|
1212
1289
|
.filter(item => (wanted === undefined || wanted.has(item.entry.id)) && !excluded.has(item.entry.id))
|
|
1213
1290
|
.map(item => item.entry.id);
|
|
1291
|
+
/**
|
|
1292
|
+
* TASK-117: the deferred catalogue registrations, restored when the owning
|
|
1293
|
+
* extension releases a tool name (deactivation). Runs after `install` and
|
|
1294
|
+
* `resolved` exist; the onActivationChange hook fires it asynchronously.
|
|
1295
|
+
*/
|
|
1296
|
+
const restoreDeferredCatalogue = async () => {
|
|
1297
|
+
for (const modelId of [...catalogueDeferred]) {
|
|
1298
|
+
const item = resolved.find(candidate => candidate.entry.id === modelId);
|
|
1299
|
+
if (item === undefined) {
|
|
1300
|
+
catalogueDeferred.delete(modelId);
|
|
1301
|
+
continue;
|
|
1302
|
+
}
|
|
1303
|
+
if (extensionOwnsToolName(item.entry.tool.name))
|
|
1304
|
+
continue;
|
|
1305
|
+
catalogueDeferred.delete(modelId);
|
|
1306
|
+
ctx.logger.info(`model-tools: ${item.entry.name}'s tool ${item.entry.tool.name} is released; restoring the catalogue registration`);
|
|
1307
|
+
try {
|
|
1308
|
+
await install(item);
|
|
1309
|
+
}
|
|
1310
|
+
catch (error) {
|
|
1311
|
+
// A failed restore is reported, never swallowed silently: the operator
|
|
1312
|
+
// must see why the catalogue tool did not come back.
|
|
1313
|
+
ctx.logger.warn(`model-tools: could not restore the catalogue registration for ${item.entry.name}: `
|
|
1314
|
+
+ `${error instanceof Error ? error.message : String(error)}`);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1214
1318
|
for (const item of resolved) {
|
|
1215
1319
|
const { install: selection, disabled } = resolveSelection(configuredIds, persisted);
|
|
1216
1320
|
if (!selection.has(item.entry.id)) {
|
|
@@ -2353,7 +2457,9 @@ export async function apply(ctx, config = {}) {
|
|
|
2353
2457
|
*/
|
|
2354
2458
|
const extensionStoreDir = config.extensionStore ?? '';
|
|
2355
2459
|
if (extensionStoreDir.length > 0) {
|
|
2356
|
-
|
|
2460
|
+
// TASK-117: the store is the HOISTED instance (constructed at the apply
|
|
2461
|
+
// top so the catalogue-install loop can probe extension tool ownership).
|
|
2462
|
+
const store = extensionStore;
|
|
2357
2463
|
/**
|
|
2358
2464
|
* How dispatch reaches an ACTIVATED extension.
|
|
2359
2465
|
*
|
package/package.json
CHANGED