@try-works/dsh-model-as-tool 0.1.2 → 0.3.6
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/bin/dsh-tool-mode-credentials.mjs +20 -0
- package/bin/dsh-tool-mode.mjs +202 -0
- package/catalog/desert-ant-models.json +693 -693
- package/client/client.model-tools.js +592 -0
- package/client/index.js +1679 -0
- package/lib/adapters/index.d.ts.map +1 -1
- package/lib/adapters/index.js +4 -4
- package/lib/bindings.d.ts.map +1 -1
- package/lib/bindings.js +26 -25
- package/lib/capability.d.ts.map +1 -1
- package/lib/capability.js +17 -0
- package/lib/capture-path.d.ts +97 -0
- package/lib/capture-path.d.ts.map +1 -0
- package/lib/capture-path.js +152 -0
- package/lib/diagnostics.d.ts +166 -0
- package/lib/diagnostics.d.ts.map +1 -0
- package/lib/diagnostics.js +135 -0
- package/lib/extension-dependencies.d.ts +197 -0
- package/lib/extension-dependencies.d.ts.map +1 -0
- package/lib/extension-dependencies.js +369 -0
- package/lib/extension-dispatch.d.ts +117 -0
- package/lib/extension-dispatch.d.ts.map +1 -0
- package/lib/extension-dispatch.js +124 -0
- package/lib/extension-registrar.d.ts +100 -0
- package/lib/extension-registrar.d.ts.map +1 -0
- package/lib/extension-registrar.js +134 -0
- package/lib/extensions-api.d.ts +217 -0
- package/lib/extensions-api.d.ts.map +1 -0
- package/lib/extensions-api.js +17 -0
- package/lib/extensions-remote.d.ts +54 -0
- package/lib/extensions-remote.d.ts.map +1 -0
- package/lib/extensions-remote.js +66 -0
- package/lib/extensions-service.d.ts +334 -0
- package/lib/extensions-service.d.ts.map +1 -0
- package/lib/extensions-service.js +1351 -0
- package/lib/harness-llm.d.ts +138 -0
- package/lib/harness-llm.d.ts.map +1 -0
- package/lib/harness-llm.js +218 -0
- package/lib/harness-serving.d.ts +95 -0
- package/lib/harness-serving.d.ts.map +1 -0
- package/lib/harness-serving.js +157 -0
- package/lib/headless.d.ts +97 -0
- package/lib/headless.d.ts.map +1 -0
- package/lib/headless.js +349 -0
- package/lib/http-acquisition.d.ts +27 -0
- package/lib/http-acquisition.d.ts.map +1 -0
- package/lib/http-acquisition.js +136 -0
- package/lib/index.d.ts +250 -7
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2625 -70
- package/lib/invocation-accounting.d.ts +169 -0
- package/lib/invocation-accounting.d.ts.map +1 -0
- package/lib/invocation-accounting.js +148 -0
- package/lib/legacy-migration.d.ts +95 -0
- package/lib/legacy-migration.d.ts.map +1 -0
- package/lib/legacy-migration.js +429 -0
- package/lib/managed-workers.d.ts +151 -0
- package/lib/managed-workers.d.ts.map +1 -0
- package/lib/managed-workers.js +249 -0
- package/lib/mcp/client-grant.d.ts +74 -0
- package/lib/mcp/client-grant.d.ts.map +1 -0
- package/lib/mcp/client-grant.js +60 -0
- package/lib/mcp/credential-cli.d.ts +38 -0
- package/lib/mcp/credential-cli.d.ts.map +1 -0
- package/lib/mcp/credential-cli.js +148 -0
- package/lib/mcp/credential-store.d.ts +143 -0
- package/lib/mcp/credential-store.d.ts.map +1 -0
- package/lib/mcp/credential-store.js +454 -0
- package/lib/mcp/host-binding.d.ts +25 -0
- package/lib/mcp/host-binding.d.ts.map +1 -1
- package/lib/mcp/host-binding.js +107 -14
- package/lib/mcp/http.d.ts +68 -18
- package/lib/mcp/http.d.ts.map +1 -1
- package/lib/mcp/http.js +390 -62
- package/lib/mcp/oauth.d.ts +149 -0
- package/lib/mcp/oauth.d.ts.map +1 -0
- package/lib/mcp/oauth.js +396 -0
- package/lib/mcp/protocol.d.ts +46 -7
- package/lib/mcp/protocol.d.ts.map +1 -1
- package/lib/mcp/protocol.js +63 -16
- package/lib/mcp/rate-limit.d.ts +68 -0
- package/lib/mcp/rate-limit.d.ts.map +1 -0
- package/lib/mcp/rate-limit.js +114 -0
- package/lib/mcp/sdk-v2.d.ts +17 -0
- package/lib/mcp/sdk-v2.d.ts.map +1 -0
- package/lib/mcp/sdk-v2.js +181 -0
- package/lib/mcp/server.d.ts +11 -1
- package/lib/mcp/server.d.ts.map +1 -1
- package/lib/mcp/server.js +80 -13
- package/lib/mcp/stdio.d.ts.map +1 -1
- package/lib/mcp/stdio.js +9 -1
- package/lib/mcp/subscriptions.d.ts +43 -1
- package/lib/mcp/subscriptions.d.ts.map +1 -1
- package/lib/mcp/subscriptions.js +90 -9
- package/lib/model-qualification.d.ts +192 -0
- package/lib/model-qualification.d.ts.map +1 -0
- package/lib/model-qualification.js +178 -0
- package/lib/planning.d.ts +246 -0
- package/lib/planning.d.ts.map +1 -0
- package/lib/planning.js +457 -0
- package/lib/prepared-assets.d.ts +178 -0
- package/lib/prepared-assets.d.ts.map +1 -0
- package/lib/prepared-assets.js +286 -0
- package/lib/provider-bridge.d.ts +37 -0
- package/lib/provider-bridge.d.ts.map +1 -1
- package/lib/provider-bridge.js +189 -12
- package/lib/ptc-authority.d.ts +140 -0
- package/lib/ptc-authority.d.ts.map +1 -0
- package/lib/ptc-authority.js +216 -0
- package/lib/ptc-runtime.d.ts +156 -0
- package/lib/ptc-runtime.d.ts.map +1 -0
- package/lib/ptc-runtime.js +191 -0
- package/lib/publication.d.ts +2 -1
- package/lib/publication.d.ts.map +1 -1
- package/lib/publication.js +13 -5
- package/lib/receipt.d.ts.map +1 -1
- package/lib/receipt.js +8 -0
- package/lib/title-proposal.d.ts +194 -0
- package/lib/title-proposal.d.ts.map +1 -0
- package/lib/title-proposal.js +244 -0
- package/lib/tool-mode-run.d.ts +235 -0
- package/lib/tool-mode-run.d.ts.map +1 -0
- package/lib/tool-mode-run.js +283 -0
- package/lib/types.d.ts +3 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/update-surface.d.ts +79 -0
- package/lib/update-surface.d.ts.map +1 -0
- package/lib/update-surface.js +224 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/lang-detect.d.ts +16 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/lang-detect.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/lang-detect.js +85 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/standard.d.ts +38 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/standard.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/standard.js +445 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/stt-transcribe.d.ts +20 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/stt-transcribe.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/stt-transcribe.js +112 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-embed.d.ts +14 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-embed.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-embed.js +63 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-rerank.d.ts +14 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-rerank.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/contracts/text-rerank.js +76 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/dsh.d.ts +82 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/dsh.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/dsh.js +274 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/index.d.ts +26 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/index.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/index.js +48 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/meta.d.ts +104 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/meta.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/meta.js +55 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/registry.d.ts +107 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/registry.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-contracts/lib/registry.js +246 -0
- package/node_modules/@try-works/tool-mode-contracts/package.json +34 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/bin/dsh-tool-mode.mjs +20 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/cli.d.ts +80 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/cli.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/cli.js +533 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/declarative-recipes.d.ts +83 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/declarative-recipes.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/declarative-recipes.js +125 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/discovery.d.ts +70 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/discovery.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/discovery.js +201 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/errors.d.ts +57 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/errors.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/errors.js +83 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.d.ts +31 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/index.js +31 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.d.ts +86 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/archive.js +185 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/dependencies.d.ts +126 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/dependencies.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/dependencies.js +297 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/lifecycle.d.ts +216 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/lifecycle.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/lifecycle.js +800 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/migration.d.ts +210 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/migration.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/migration.js +368 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/runtime-link.d.ts +63 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/runtime-link.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/runtime-link.js +149 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/source-directory.d.ts +35 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/source-directory.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/source-directory.js +179 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/staged.d.ts +179 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/staged.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/staged.js +235 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/store.d.ts +367 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/store.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/store.js +807 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/update-flow.d.ts +185 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/update-flow.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/update-flow.js +504 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/zip-source.d.ts +17 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/zip-source.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/install/zip-source.js +80 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/load.d.ts +52 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/load.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/load.js +102 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/manifest.d.ts +171 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/manifest.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/manifest.js +271 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/runtime.d.ts +242 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/runtime.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/runtime.js +58 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/state.d.ts +118 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/state.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/state.js +113 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker/worker-child.d.ts +2 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker/worker-child.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker/worker-child.js +351 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker.d.ts +150 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/lib/worker.js +670 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/package.json +53 -0
- package/node_modules/@try-works/tool-mode-extension-sdk/schema/extension-manifest-1.1.0.schema.json +253 -0
- package/node_modules/@try-works/tool-mode-recipes/bin/tool-mode-recipe.mjs +15 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/broker.d.ts +427 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/broker.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/broker.js +592 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/cli.d.ts +60 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/cli.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/cli.js +936 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/dsh-adapter.d.ts +237 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/dsh-adapter.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/dsh-adapter.js +200 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/fixture-provider.d.ts +85 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/fixture-provider.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/fixture-provider.js +176 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/images.d.ts +105 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/images.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/images.js +129 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/index.d.ts +25 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/index.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/index.js +25 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/recipe-format.d.ts +325 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/recipe-format.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/recipe-format.js +1310 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/templates.d.ts +51 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/templates.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/templates.js +310 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/titles.d.ts +227 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/titles.d.ts.map +1 -0
- package/node_modules/@try-works/tool-mode-recipes/lib/titles.js +407 -0
- package/node_modules/@try-works/tool-mode-recipes/package.json +56 -0
- package/node_modules/@try-works/tool-mode-recipes/recipes/describe-image.json +38 -0
- package/node_modules/@try-works/tool-mode-recipes/recipes/text-title.json +45 -0
- package/node_modules/@try-works/tool-mode-recipes/schema/harness-model-recipe.schema.json +273 -0
- package/package.json +50 -17
- package/remote/spec.mjs +439 -0
- package/remote/typert.host.mjs +14 -0
- package/remote/typert.remote-client.mjs +16 -0
- package/lib/adapters/tongue.d.ts +0 -31
- package/lib/adapters/tongue.d.ts.map +0 -1
- package/lib/adapters/tongue.js +0 -93
- package/lib/adapters/voz.d.ts +0 -28
- package/lib/adapters/voz.d.ts.map +0 -1
- package/lib/adapters/voz.js +0 -102
- /package/{lib → node_modules/@try-works/tool-mode-extension-sdk/lib}/licensing.d.ts +0 -0
- /package/{lib → node_modules/@try-works/tool-mode-extension-sdk/lib}/licensing.d.ts.map +0 -0
- /package/{lib → node_modules/@try-works/tool-mode-extension-sdk/lib}/licensing.js +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolving a DECLARATIVE implementation's recipe (EXT-13, RCP-01, slice 3).
|
|
3
|
+
*
|
|
4
|
+
* THE CONVENTION THIS ESTABLISHES, and why it has to exist. The pinned manifest schema's
|
|
5
|
+
* `implementations` items permit only `id`, `contractId`, `contractVersion`, `modelId` and
|
|
6
|
+
* `recipeVersion`, with `additionalProperties: false` — so **a manifest cannot name its
|
|
7
|
+
* recipe files**. There is no path field to read.
|
|
8
|
+
*
|
|
9
|
+
* What a manifest declares is a recipe VERSION. The ARTEFACT is therefore located by a
|
|
10
|
+
* convention, and until now no convention existed because nothing had ever consumed a
|
|
11
|
+
* declarative manifest: every package in this repository was `kind: "module"` and reached its
|
|
12
|
+
* behaviour through a module entry.
|
|
13
|
+
*
|
|
14
|
+
* The convention, stated once so it is not re-invented at each call site:
|
|
15
|
+
*
|
|
16
|
+
* <package>/recipes/<implementation-id>.json
|
|
17
|
+
*
|
|
18
|
+
* Chosen because the implementation id is already unique within the package, already matches
|
|
19
|
+
* `^[a-z][a-z0-9-]*$` by schema, and therefore needs no escaping or normalisation to become a
|
|
20
|
+
* file name. The alternative — keying on the contract id — would need path-mapping for the
|
|
21
|
+
* `tool-mode/` namespace and would collide when one contract has several implementations,
|
|
22
|
+
* which is exactly what `implementations` is an ARRAY to allow.
|
|
23
|
+
*
|
|
24
|
+
* @module @try-works/tool-mode-extension-sdk/declarative-recipes
|
|
25
|
+
*/
|
|
26
|
+
/** The directory the convention looks in. */
|
|
27
|
+
export declare const RECIPE_DIRECTORY = "recipes";
|
|
28
|
+
/** A resolved recipe, or the reason it could not be resolved. */
|
|
29
|
+
export type RecipeResolution = {
|
|
30
|
+
readonly ok: true;
|
|
31
|
+
readonly recipe: unknown;
|
|
32
|
+
readonly path: string;
|
|
33
|
+
} | {
|
|
34
|
+
readonly ok: false;
|
|
35
|
+
readonly reason: 'missing' | 'unreadable' | 'invalid-json';
|
|
36
|
+
readonly path: string;
|
|
37
|
+
readonly detail: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Resolve one implementation's recipe by the convention.
|
|
41
|
+
*
|
|
42
|
+
* @param packageDir - the installed package root.
|
|
43
|
+
* @param implementationId - the manifest implementation id, which names the file.
|
|
44
|
+
* @returns the parsed recipe, or an honest failure.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveDeclarativeRecipe(packageDir: string, implementationId: string): RecipeResolution;
|
|
47
|
+
/**
|
|
48
|
+
* Resolve every implementation a declarative manifest declares.
|
|
49
|
+
*
|
|
50
|
+
* All-or-nothing on purpose: a package that could satisfy HALF its declarations would be
|
|
51
|
+
* activated in a state its manifest does not describe, and a caller would have no way to
|
|
52
|
+
* learn which half. Refusing names what is missing instead.
|
|
53
|
+
*
|
|
54
|
+
* @param packageDir - the installed package root.
|
|
55
|
+
* @param implementations - the manifest's declaration list.
|
|
56
|
+
* @returns every resolved recipe, or the first failure.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveDeclarativeImplementations(packageDir: string, implementations: readonly {
|
|
59
|
+
readonly id: string;
|
|
60
|
+
readonly contractId: string;
|
|
61
|
+
readonly recipeVersion: string;
|
|
62
|
+
}[]): {
|
|
63
|
+
readonly ok: true;
|
|
64
|
+
readonly resolved: readonly {
|
|
65
|
+
readonly id: string;
|
|
66
|
+
readonly contractId: string;
|
|
67
|
+
readonly recipeVersion: string;
|
|
68
|
+
readonly recipe: unknown;
|
|
69
|
+
readonly path: string;
|
|
70
|
+
}[];
|
|
71
|
+
} | {
|
|
72
|
+
readonly ok: false;
|
|
73
|
+
readonly id: string;
|
|
74
|
+
readonly detail: string;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Whether an installed package is declarative, and what it declares.
|
|
78
|
+
*
|
|
79
|
+
* @param packageDir - the installed package root.
|
|
80
|
+
* @returns the declared recipe names when the package is declarative, else undefined.
|
|
81
|
+
*/
|
|
82
|
+
export declare function declaredRecipeNames(packageDir: string): readonly string[] | undefined;
|
|
83
|
+
//# sourceMappingURL=declarative-recipes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declarative-recipes.d.ts","sourceRoot":"","sources":["../src/declarative-recipes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,6CAA6C;AAC7C,eAAO,MAAM,gBAAgB,YAAY,CAAA;AAEzC,iEAAiE;AACjE,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,YAAY,GAAG,cAAc,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtI;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,CA6CvG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,SAAS;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAAE,EAAE,GAC/G;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,GACzL;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAcvE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAQrF"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolving a DECLARATIVE implementation's recipe (EXT-13, RCP-01, slice 3).
|
|
3
|
+
*
|
|
4
|
+
* THE CONVENTION THIS ESTABLISHES, and why it has to exist. The pinned manifest schema's
|
|
5
|
+
* `implementations` items permit only `id`, `contractId`, `contractVersion`, `modelId` and
|
|
6
|
+
* `recipeVersion`, with `additionalProperties: false` — so **a manifest cannot name its
|
|
7
|
+
* recipe files**. There is no path field to read.
|
|
8
|
+
*
|
|
9
|
+
* What a manifest declares is a recipe VERSION. The ARTEFACT is therefore located by a
|
|
10
|
+
* convention, and until now no convention existed because nothing had ever consumed a
|
|
11
|
+
* declarative manifest: every package in this repository was `kind: "module"` and reached its
|
|
12
|
+
* behaviour through a module entry.
|
|
13
|
+
*
|
|
14
|
+
* The convention, stated once so it is not re-invented at each call site:
|
|
15
|
+
*
|
|
16
|
+
* <package>/recipes/<implementation-id>.json
|
|
17
|
+
*
|
|
18
|
+
* Chosen because the implementation id is already unique within the package, already matches
|
|
19
|
+
* `^[a-z][a-z0-9-]*$` by schema, and therefore needs no escaping or normalisation to become a
|
|
20
|
+
* file name. The alternative — keying on the contract id — would need path-mapping for the
|
|
21
|
+
* `tool-mode/` namespace and would collide when one contract has several implementations,
|
|
22
|
+
* which is exactly what `implementations` is an ARRAY to allow.
|
|
23
|
+
*
|
|
24
|
+
* @module @try-works/tool-mode-extension-sdk/declarative-recipes
|
|
25
|
+
*/
|
|
26
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
27
|
+
import { join } from 'node:path';
|
|
28
|
+
/** The directory the convention looks in. */
|
|
29
|
+
export const RECIPE_DIRECTORY = 'recipes';
|
|
30
|
+
/**
|
|
31
|
+
* Resolve one implementation's recipe by the convention.
|
|
32
|
+
*
|
|
33
|
+
* @param packageDir - the installed package root.
|
|
34
|
+
* @param implementationId - the manifest implementation id, which names the file.
|
|
35
|
+
* @returns the parsed recipe, or an honest failure.
|
|
36
|
+
*/
|
|
37
|
+
export function resolveDeclarativeRecipe(packageDir, implementationId) {
|
|
38
|
+
const path = join(packageDir, RECIPE_DIRECTORY, `${implementationId}.json`);
|
|
39
|
+
/**
|
|
40
|
+
* The id is re-checked HERE rather than trusted from the manifest.
|
|
41
|
+
*
|
|
42
|
+
* The schema constrains it to `^[a-z][a-z0-9-]*$`, but this function builds a PATH from it,
|
|
43
|
+
* and a path built from an unvalidated string is a traversal. Re-checking costs nothing and
|
|
44
|
+
* means the resolver is safe even if a caller passes an id from somewhere the schema never
|
|
45
|
+
* saw — a hand-written manifest, a future protocol version, or a test.
|
|
46
|
+
*/
|
|
47
|
+
if (!/^[a-z][a-z0-9-]*$/.test(implementationId)) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
reason: 'missing',
|
|
51
|
+
path,
|
|
52
|
+
detail: `the implementation id ${JSON.stringify(implementationId)} is not a legal recipe name`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
let text;
|
|
56
|
+
try {
|
|
57
|
+
text = readFileSync(path, 'utf8');
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
reason: 'missing',
|
|
63
|
+
path,
|
|
64
|
+
// The convention is NAMED in the failure, because a package author who put the file
|
|
65
|
+
// elsewhere can only fix it if they are told where it was looked for.
|
|
66
|
+
detail: `no recipe at ${RECIPE_DIRECTORY}/${implementationId}.json: `
|
|
67
|
+
+ `${error instanceof Error ? error.message : String(error)}`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
return { ok: true, recipe: JSON.parse(text), path };
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return {
|
|
75
|
+
ok: false,
|
|
76
|
+
reason: 'invalid-json',
|
|
77
|
+
path,
|
|
78
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve every implementation a declarative manifest declares.
|
|
84
|
+
*
|
|
85
|
+
* All-or-nothing on purpose: a package that could satisfy HALF its declarations would be
|
|
86
|
+
* activated in a state its manifest does not describe, and a caller would have no way to
|
|
87
|
+
* learn which half. Refusing names what is missing instead.
|
|
88
|
+
*
|
|
89
|
+
* @param packageDir - the installed package root.
|
|
90
|
+
* @param implementations - the manifest's declaration list.
|
|
91
|
+
* @returns every resolved recipe, or the first failure.
|
|
92
|
+
*/
|
|
93
|
+
export function resolveDeclarativeImplementations(packageDir, implementations) {
|
|
94
|
+
const resolved = [];
|
|
95
|
+
for (const implementation of implementations) {
|
|
96
|
+
const outcome = resolveDeclarativeRecipe(packageDir, implementation.id);
|
|
97
|
+
if (!outcome.ok)
|
|
98
|
+
return { ok: false, id: implementation.id, detail: outcome.detail };
|
|
99
|
+
resolved.push({
|
|
100
|
+
id: implementation.id,
|
|
101
|
+
contractId: implementation.contractId,
|
|
102
|
+
recipeVersion: implementation.recipeVersion,
|
|
103
|
+
recipe: outcome.recipe,
|
|
104
|
+
path: outcome.path,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return { ok: true, resolved };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Whether an installed package is declarative, and what it declares.
|
|
111
|
+
*
|
|
112
|
+
* @param packageDir - the installed package root.
|
|
113
|
+
* @returns the declared recipe names when the package is declarative, else undefined.
|
|
114
|
+
*/
|
|
115
|
+
export function declaredRecipeNames(packageDir) {
|
|
116
|
+
try {
|
|
117
|
+
const entries = readdirSync(join(packageDir, RECIPE_DIRECTORY));
|
|
118
|
+
return entries.filter(name => name.endsWith('.json')).map(name => name.slice(0, -'.json'.length)).sort();
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// A package with no recipes directory is not declarative by this convention.
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=declarative-recipes.js.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded static discovery (EXT-13).
|
|
3
|
+
*
|
|
4
|
+
* Discovery reads a package as DATA and never imports it. That ordering is the
|
|
5
|
+
* security property, not an optimization: installation must not execute the
|
|
6
|
+
* package, so the host inspects `package.json` and the manifest, decides whether
|
|
7
|
+
* the package is acceptable, and only then considers running anything.
|
|
8
|
+
*
|
|
9
|
+
* Every read is bounded by a byte limit and every path is confined to the package
|
|
10
|
+
* directory, so a hostile package cannot make discovery read an arbitrary file or
|
|
11
|
+
* allocate without limit.
|
|
12
|
+
*
|
|
13
|
+
* @module @try-works/tool-mode-extension-sdk/discovery
|
|
14
|
+
*/
|
|
15
|
+
import { type LicenseLayer, type NoNetworkVerdict, type ResolvedLicenseRecord } from './licensing.ts';
|
|
16
|
+
import { type ExtensionManifest } from './manifest.ts';
|
|
17
|
+
/** Largest `package.json` accepted, in bytes. */
|
|
18
|
+
export declare const MAX_PACKAGE_JSON_BYTES: number;
|
|
19
|
+
/** What discovery learns about a package without running any of it. */
|
|
20
|
+
export interface ExtensionDiscovery {
|
|
21
|
+
/** The package name from `package.json`. */
|
|
22
|
+
readonly packageName: string;
|
|
23
|
+
/** The package version from `package.json`. */
|
|
24
|
+
readonly packageVersion: string;
|
|
25
|
+
/** Absolute path of the unpacked package directory. */
|
|
26
|
+
readonly packageDir: string;
|
|
27
|
+
/** Absolute path of the manifest the `toolMode.manifest` field names. */
|
|
28
|
+
readonly manifestPath: string;
|
|
29
|
+
/**
|
|
30
|
+
* Absolute path of the public `./tool-mode` entry, resolved from the package's
|
|
31
|
+
* own `exports` map. Undefined for a declarative package, which has no module
|
|
32
|
+
* entry to import.
|
|
33
|
+
*/
|
|
34
|
+
readonly entryPath?: string;
|
|
35
|
+
/** The validated manifest. */
|
|
36
|
+
readonly manifest: ExtensionManifest;
|
|
37
|
+
/**
|
|
38
|
+
* The resolved per-layer licence record (LIC-01).
|
|
39
|
+
*
|
|
40
|
+
* Produced by discovery rather than left to a consumer, so every caller resolves
|
|
41
|
+
* the same way and a package that declares no licences gets the same explicit gap
|
|
42
|
+
* report as one that declares an incomplete set.
|
|
43
|
+
*/
|
|
44
|
+
readonly licenses: ResolvedLicenseRecord;
|
|
45
|
+
/** The layers the package did NOT declare, which are gaps rather than defaults. */
|
|
46
|
+
readonly licenseGaps: readonly LicenseLayer[];
|
|
47
|
+
/**
|
|
48
|
+
* Whether the package is eligible for a strict no-network deployment (LIC-04).
|
|
49
|
+
*
|
|
50
|
+
* Derived from the declaration, and a package that declares nothing is NOT
|
|
51
|
+
* eligible: silence about telemetry cannot be read as an absence of telemetry.
|
|
52
|
+
*/
|
|
53
|
+
readonly noNetwork: NoNetworkVerdict;
|
|
54
|
+
/** How the package may truthfully describe its network behaviour. */
|
|
55
|
+
readonly networkDescription: string;
|
|
56
|
+
/** The declared public exports, which discovery requires to be explicit. */
|
|
57
|
+
readonly exports: readonly string[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Discover an extension package without importing it.
|
|
61
|
+
*
|
|
62
|
+
* Enforces the EXT-13 package requirements: a `package.json` declaring `name`,
|
|
63
|
+
* `version`, `type: "module"`, an explicit `exports` map, and a `toolMode.manifest`
|
|
64
|
+
* field pointing at a manifest inside the package.
|
|
65
|
+
* @param packageDir - absolute path of the unpacked package.
|
|
66
|
+
* @returns the discovery result.
|
|
67
|
+
* @throws ManagementError with `INVALID_EXTENSION` for any violated requirement.
|
|
68
|
+
*/
|
|
69
|
+
export declare function discoverExtension(packageDir: string): ExtensionDiscovery;
|
|
70
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAoE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAExH,iDAAiD;AACjD,eAAO,MAAM,sBAAsB,QAAa,CAAA;AAEhD,uEAAuE;AACvE,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,uDAAuD;IACvD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,8BAA8B;IAC9B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;IACpC;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAA;IACxC,mFAAmF;IACnF,QAAQ,CAAC,WAAW,EAAE,SAAS,YAAY,EAAE,CAAA;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAA;IACpC,qEAAqE;IACrE,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AA0ED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,CAwJxE"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded static discovery (EXT-13).
|
|
3
|
+
*
|
|
4
|
+
* Discovery reads a package as DATA and never imports it. That ordering is the
|
|
5
|
+
* security property, not an optimization: installation must not execute the
|
|
6
|
+
* package, so the host inspects `package.json` and the manifest, decides whether
|
|
7
|
+
* the package is acceptable, and only then considers running anything.
|
|
8
|
+
*
|
|
9
|
+
* Every read is bounded by a byte limit and every path is confined to the package
|
|
10
|
+
* directory, so a hostile package cannot make discovery read an arbitrary file or
|
|
11
|
+
* allocate without limit.
|
|
12
|
+
*
|
|
13
|
+
* @module @try-works/tool-mode-extension-sdk/discovery
|
|
14
|
+
*/
|
|
15
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
16
|
+
import { join, resolve, sep } from 'node:path';
|
|
17
|
+
import { ManagementError } from "./errors.js";
|
|
18
|
+
import { describeNetwork, noNetworkEligibility, resolveLicenses, } from "./licensing.js";
|
|
19
|
+
import { MAX_MANIFEST_BYTES, validateManifest, validateLockQualifications } from "./manifest.js";
|
|
20
|
+
/** Largest `package.json` accepted, in bytes. */
|
|
21
|
+
export const MAX_PACKAGE_JSON_BYTES = 256 * 1024;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a `./tool-mode` export target to a path.
|
|
24
|
+
*
|
|
25
|
+
* An export value is either a string or a conditions object, and both appear in
|
|
26
|
+
* real packages. The entry is read from the declaration rather than guessed from
|
|
27
|
+
* a convention, so a package that points its entry elsewhere still loads.
|
|
28
|
+
* @param value - the export value.
|
|
29
|
+
* @returns the relative target, or undefined when there is none.
|
|
30
|
+
*/
|
|
31
|
+
function exportTarget(value) {
|
|
32
|
+
if (typeof value === 'string')
|
|
33
|
+
return value;
|
|
34
|
+
if (typeof value === 'object' && value !== null) {
|
|
35
|
+
const conditions = value;
|
|
36
|
+
// `default` is the condition Node itself falls back to.
|
|
37
|
+
const target = conditions.default ?? conditions.import ?? conditions.node;
|
|
38
|
+
if (typeof target === 'string')
|
|
39
|
+
return target;
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Read one bounded JSON file inside a package.
|
|
45
|
+
*
|
|
46
|
+
* @param path - absolute path to read.
|
|
47
|
+
* @param maxBytes - the size bound.
|
|
48
|
+
* @param what - a label for error messages.
|
|
49
|
+
* @returns the decoded value.
|
|
50
|
+
* @throws ManagementError when the file is missing, oversized, or not JSON.
|
|
51
|
+
*/
|
|
52
|
+
function readBoundedJson(path, maxBytes, what) {
|
|
53
|
+
let size;
|
|
54
|
+
try {
|
|
55
|
+
size = statSync(path).size;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', `the package does not ship ${what}`, `Add ${what} to the published package.`);
|
|
59
|
+
}
|
|
60
|
+
if (size > maxBytes) {
|
|
61
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', `${what} is ${size} bytes, over the ${maxBytes}-byte limit`, `Reduce ${what}; discovery reads it as bounded data before importing any code.`);
|
|
62
|
+
}
|
|
63
|
+
let text;
|
|
64
|
+
try {
|
|
65
|
+
text = readFileSync(path, 'utf8');
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', `${what} could not be read`, 'Check that the file is present and readable by the installing account.');
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(text);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', `${what} is not valid JSON`, `Correct the JSON syntax in ${what}.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Discover an extension package without importing it.
|
|
79
|
+
*
|
|
80
|
+
* Enforces the EXT-13 package requirements: a `package.json` declaring `name`,
|
|
81
|
+
* `version`, `type: "module"`, an explicit `exports` map, and a `toolMode.manifest`
|
|
82
|
+
* field pointing at a manifest inside the package.
|
|
83
|
+
* @param packageDir - absolute path of the unpacked package.
|
|
84
|
+
* @returns the discovery result.
|
|
85
|
+
* @throws ManagementError with `INVALID_EXTENSION` for any violated requirement.
|
|
86
|
+
*/
|
|
87
|
+
export function discoverExtension(packageDir) {
|
|
88
|
+
const root = resolve(packageDir);
|
|
89
|
+
const manifest = readBoundedJson(join(root, 'package.json'), MAX_PACKAGE_JSON_BYTES, 'package.json');
|
|
90
|
+
if (typeof manifest !== 'object' || manifest === null || Array.isArray(manifest)) {
|
|
91
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', 'package.json is not an object', 'Ship a valid package.json.');
|
|
92
|
+
}
|
|
93
|
+
const pkg = manifest;
|
|
94
|
+
const packageName = pkg.name;
|
|
95
|
+
const packageVersion = pkg.version;
|
|
96
|
+
if (typeof packageName !== 'string' || packageName.length === 0) {
|
|
97
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', 'package.json declares no name', 'Declare a name.');
|
|
98
|
+
}
|
|
99
|
+
if (typeof packageVersion !== 'string' || packageVersion.length === 0) {
|
|
100
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', 'package.json declares no version', 'Declare a semantic version.');
|
|
101
|
+
}
|
|
102
|
+
if (pkg.type !== 'module') {
|
|
103
|
+
// ESM-only keeps the loading path single and avoids a CJS interop surface the
|
|
104
|
+
// host would otherwise have to reason about before importing anything.
|
|
105
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', 'package.json must declare "type": "module"', 'Publish the extension as an ES module.');
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The `exports` map is required of a MODULE package and NOT of a declarative one.
|
|
109
|
+
*
|
|
110
|
+
* This check used to run here, unconditionally, and it made a declarative package
|
|
111
|
+
* UNDISCOVERABLE: such a package ships no code, so it has no entry points to export, and
|
|
112
|
+
* demanding an `exports` map asked it to declare something it does not have. The failure
|
|
113
|
+
* read "package.json must declare an explicit \"exports\" map" — advice a package with no
|
|
114
|
+
* module cannot act on.
|
|
115
|
+
*
|
|
116
|
+
* The requirement is now applied AFTER the manifest is read, where the execution kind is
|
|
117
|
+
* known. `exportsField` is still read here so the shape check happens in one place.
|
|
118
|
+
*/
|
|
119
|
+
const exportsField = pkg.exports;
|
|
120
|
+
const toolMode = pkg.toolMode;
|
|
121
|
+
if (typeof toolMode !== 'object' || toolMode === null || typeof toolMode.manifest !== 'string') {
|
|
122
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', 'package.json must declare "toolMode": { "manifest": "./…" }', 'Add the toolMode discovery field naming the extension manifest.');
|
|
123
|
+
}
|
|
124
|
+
const declared = toolMode.manifest;
|
|
125
|
+
const manifestPath = resolve(root, declared);
|
|
126
|
+
if (!manifestPath.startsWith(root + sep)) {
|
|
127
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', 'the declared manifest path escapes the package directory', 'Reference the manifest by a package-relative path.');
|
|
128
|
+
}
|
|
129
|
+
const raw = readBoundedJson(manifestPath, MAX_MANIFEST_BYTES, 'the extension manifest');
|
|
130
|
+
/** A declarative package has no exports map at all, so there is no entry to look for. */
|
|
131
|
+
const entry = typeof exportsField === 'object' && exportsField !== null
|
|
132
|
+
? exportTarget(exportsField['./tool-mode'])
|
|
133
|
+
: undefined;
|
|
134
|
+
const entryPath = entry === undefined ? undefined : resolve(root, entry);
|
|
135
|
+
if (entryPath !== undefined && !entryPath.startsWith(root + sep)) {
|
|
136
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', 'the ./tool-mode export points outside the package directory', 'Point the export at a file inside the package.');
|
|
137
|
+
}
|
|
138
|
+
// Named alidated because manifest already holds the parsed package.json above.
|
|
139
|
+
const validated = validateManifest(raw, { packageName, packageVersion, packageDir: root });
|
|
140
|
+
// The declared asset locks' qualification records are validated too (MODEL-05):
|
|
141
|
+
// a record that claims a qualified path must actually carry every field.
|
|
142
|
+
validateLockQualifications(validated, root);
|
|
143
|
+
/**
|
|
144
|
+
* The `exports` requirement, applied where the execution KIND is known.
|
|
145
|
+
*
|
|
146
|
+
* A module package must declare its public entry points, because the host resolves one in
|
|
147
|
+
* order to load it, and implicit resolution is not admitted. A DECLARATIVE package has no
|
|
148
|
+
* module to load: its behaviour is a set of recipe files resolved by the
|
|
149
|
+
* `recipes/<implementation-id>.json` convention instead. Requiring an `exports` map of it
|
|
150
|
+
* demanded a declaration it cannot meaningfully make, and rejected every declarative
|
|
151
|
+
* package before its kind could even be read.
|
|
152
|
+
*/
|
|
153
|
+
const declarative = validated.execution.kind === 'declarative';
|
|
154
|
+
if (!declarative
|
|
155
|
+
&& (typeof exportsField !== 'object' || exportsField === null || Object.keys(exportsField).length === 0)) {
|
|
156
|
+
throw new ManagementError('INVALID_EXTENSION', 'discover', 'package.json must declare an explicit "exports" map', 'Declare the public entry points; implicit resolution is not admitted.');
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Licence resolution happens HERE rather than being left to each consumer.
|
|
160
|
+
*
|
|
161
|
+
* Every caller then resolves the same way, and a package that declares nothing gets
|
|
162
|
+
* the same explicit gap report as one that declares an incomplete set — rather than
|
|
163
|
+
* one consumer treating silence as permission and another not.
|
|
164
|
+
*/
|
|
165
|
+
const { record: licenses, gaps: licenseGaps } = resolveLicenses(packageName, (validated.licenses ?? []).map((entry) => ({
|
|
166
|
+
layer: entry.layer,
|
|
167
|
+
name: entry.name,
|
|
168
|
+
url: entry.url,
|
|
169
|
+
openSource: entry.openSource,
|
|
170
|
+
redistribution: entry.redistribution,
|
|
171
|
+
attributionRequired: entry.attributionRequired,
|
|
172
|
+
...entry.attributionText === undefined ? {} : { attributionText: entry.attributionText },
|
|
173
|
+
obligations: entry.obligations ?? [],
|
|
174
|
+
})));
|
|
175
|
+
/**
|
|
176
|
+
* Network behaviour is TAKEN FROM THE DECLARATION, and a package that declares
|
|
177
|
+
* nothing is treated as telemetry-bearing rather than telemetry-free: silence about
|
|
178
|
+
* telemetry cannot be read as an absence of telemetry (LIC-04).
|
|
179
|
+
*/
|
|
180
|
+
const declaredNetwork = validated.network ?? { requiredTelemetry: true, otherNetworkUse: true };
|
|
181
|
+
const networkBehaviour = {
|
|
182
|
+
extensionId: packageName,
|
|
183
|
+
requiredTelemetry: declaredNetwork.requiredTelemetry,
|
|
184
|
+
otherNetworkUse: declaredNetwork.otherNetworkUse,
|
|
185
|
+
...declaredNetwork.telemetryContent === undefined ? {} : { telemetryContent: declaredNetwork.telemetryContent },
|
|
186
|
+
};
|
|
187
|
+
return {
|
|
188
|
+
packageName,
|
|
189
|
+
packageVersion,
|
|
190
|
+
packageDir: root,
|
|
191
|
+
manifestPath,
|
|
192
|
+
...entryPath === undefined ? {} : { entryPath },
|
|
193
|
+
manifest: validated,
|
|
194
|
+
exports: typeof exportsField === 'object' && exportsField !== null ? Object.keys(exportsField) : [],
|
|
195
|
+
licenses,
|
|
196
|
+
licenseGaps,
|
|
197
|
+
noNetwork: noNetworkEligibility(networkBehaviour),
|
|
198
|
+
networkDescription: describeNetwork(networkBehaviour),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The machine-readable management error vocabulary (EXT-34).
|
|
3
|
+
*
|
|
4
|
+
* Every management failure carries a stable code, the operation that failed, and
|
|
5
|
+
* safe recovery advice. Recovery text is authored to be safe to show: it never
|
|
6
|
+
* contains a credential, a token, or an absolute path from the operator's disk,
|
|
7
|
+
* because these errors surface in logs and operator UIs.
|
|
8
|
+
*
|
|
9
|
+
* @module @try-works/tool-mode-extension-sdk/errors
|
|
10
|
+
*/
|
|
11
|
+
/** Every management error code the protocol defines (EXT-34). */
|
|
12
|
+
export declare const MANAGEMENT_ERROR_CODES: readonly ["INVALID_EXTENSION", "INCOMPATIBLE_PROTOCOL", "UNSUPPORTED_PLATFORM", "INTEGRITY_MISMATCH", "PERMISSION_REQUIRED", "DEPENDENCY_UNSATISFIED", "TOOL_NAME_CONFLICT", "CONTRACT_MISMATCH", "EXTENSION_INACTIVE", "EXTENSION_IN_USE", "BUILTIN_PROTECTED", "EXTENSION_REVOKED", "EXTENSION_FAULT", "UPGRADE_FAILED", "CLEANUP_PENDING"];
|
|
13
|
+
/** One management error code. */
|
|
14
|
+
export type ManagementErrorCode = (typeof MANAGEMENT_ERROR_CODES)[number];
|
|
15
|
+
/** The management operations an error can be attributed to. */
|
|
16
|
+
export type ManagementOperation = 'discover' | 'install' | 'activate' | 'deactivate' | 'update' | 'uninstall' | 'prepare' | 'invoke';
|
|
17
|
+
/** A structured management failure. */
|
|
18
|
+
export interface ManagementErrorShape {
|
|
19
|
+
/** Stable machine-readable code. */
|
|
20
|
+
readonly code: ManagementErrorCode;
|
|
21
|
+
/** The operation that failed. */
|
|
22
|
+
readonly operation: ManagementOperation;
|
|
23
|
+
/** Human-readable description, safe to log. */
|
|
24
|
+
readonly message: string;
|
|
25
|
+
/** Safe recovery advice. Never contains credentials or operator paths. */
|
|
26
|
+
readonly recovery: string;
|
|
27
|
+
/** Whether retrying the same operation could succeed. */
|
|
28
|
+
readonly retryable: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* A management failure raised by discovery, installation or lifecycle code.
|
|
32
|
+
*
|
|
33
|
+
* `retryable` is derived from the code rather than passed in, so a caller cannot
|
|
34
|
+
* accidentally mark a permission refusal as a transient fault the agent should
|
|
35
|
+
* retry in a loop.
|
|
36
|
+
*/
|
|
37
|
+
export declare class ManagementError extends Error {
|
|
38
|
+
readonly name = "ManagementError";
|
|
39
|
+
readonly code: ManagementErrorCode;
|
|
40
|
+
readonly operation: ManagementOperation;
|
|
41
|
+
readonly recovery: string;
|
|
42
|
+
readonly retryable: boolean;
|
|
43
|
+
constructor(code: ManagementErrorCode, operation: ManagementOperation, message: string, recovery: string);
|
|
44
|
+
/** Render the structured shape, for receipts and management surfaces. */
|
|
45
|
+
toShape(): ManagementErrorShape;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Strip anything credential-shaped from recovery advice.
|
|
49
|
+
*
|
|
50
|
+
* EXT-34 requires that recovery text never carries raw credentials. Advice is
|
|
51
|
+
* authored rather than interpolated, so this is a guard against a future edit
|
|
52
|
+
* that interpolates a path or a value by accident.
|
|
53
|
+
* @param text - the authored advice.
|
|
54
|
+
* @returns the advice with path- and credential-shaped spans removed.
|
|
55
|
+
*/
|
|
56
|
+
export declare function sanitizeRecovery(text: string): string;
|
|
57
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,iEAAiE;AACjE,eAAO,MAAM,sBAAsB,+UAgBzB,CAAA;AAEV,iCAAiC;AACjC,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAA;AAEzE,+DAA+D;AAC/D,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,SAAS,GACT,UAAU,GACV,YAAY,GACZ,QAAQ,GACR,WAAW,GACX,SAAS,GACT,QAAQ,CAAA;AAQZ,uCAAuC;AACvC,MAAM,WAAW,oBAAoB;IACnC,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAA;IAClC,iCAAiC;IACjC,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAA;IACvC,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,yDAAyD;IACzD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;GAMG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAkB,IAAI,qBAAoB;IAC1C,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAA;IAClC,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAA;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;gBAGzB,IAAI,EAAE,mBAAmB,EACzB,SAAS,EAAE,mBAAmB,EAC9B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM;IASlB,yEAAyE;IACzE,OAAO,IAAI,oBAAoB;CAShC;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQrD"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The machine-readable management error vocabulary (EXT-34).
|
|
3
|
+
*
|
|
4
|
+
* Every management failure carries a stable code, the operation that failed, and
|
|
5
|
+
* safe recovery advice. Recovery text is authored to be safe to show: it never
|
|
6
|
+
* contains a credential, a token, or an absolute path from the operator's disk,
|
|
7
|
+
* because these errors surface in logs and operator UIs.
|
|
8
|
+
*
|
|
9
|
+
* @module @try-works/tool-mode-extension-sdk/errors
|
|
10
|
+
*/
|
|
11
|
+
/** Every management error code the protocol defines (EXT-34). */
|
|
12
|
+
export const MANAGEMENT_ERROR_CODES = [
|
|
13
|
+
'INVALID_EXTENSION',
|
|
14
|
+
'INCOMPATIBLE_PROTOCOL',
|
|
15
|
+
'UNSUPPORTED_PLATFORM',
|
|
16
|
+
'INTEGRITY_MISMATCH',
|
|
17
|
+
'PERMISSION_REQUIRED',
|
|
18
|
+
'DEPENDENCY_UNSATISFIED',
|
|
19
|
+
'TOOL_NAME_CONFLICT',
|
|
20
|
+
'CONTRACT_MISMATCH',
|
|
21
|
+
'EXTENSION_INACTIVE',
|
|
22
|
+
'EXTENSION_IN_USE',
|
|
23
|
+
'BUILTIN_PROTECTED',
|
|
24
|
+
'EXTENSION_REVOKED',
|
|
25
|
+
'EXTENSION_FAULT',
|
|
26
|
+
'UPGRADE_FAILED',
|
|
27
|
+
'CLEANUP_PENDING',
|
|
28
|
+
];
|
|
29
|
+
/** Whether a code's condition is worth retrying unchanged. */
|
|
30
|
+
const RETRYABLE = new Set([
|
|
31
|
+
'EXTENSION_FAULT',
|
|
32
|
+
'CLEANUP_PENDING',
|
|
33
|
+
]);
|
|
34
|
+
/**
|
|
35
|
+
* A management failure raised by discovery, installation or lifecycle code.
|
|
36
|
+
*
|
|
37
|
+
* `retryable` is derived from the code rather than passed in, so a caller cannot
|
|
38
|
+
* accidentally mark a permission refusal as a transient fault the agent should
|
|
39
|
+
* retry in a loop.
|
|
40
|
+
*/
|
|
41
|
+
export class ManagementError extends Error {
|
|
42
|
+
name = 'ManagementError';
|
|
43
|
+
code;
|
|
44
|
+
operation;
|
|
45
|
+
recovery;
|
|
46
|
+
retryable;
|
|
47
|
+
constructor(code, operation, message, recovery) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.code = code;
|
|
50
|
+
this.operation = operation;
|
|
51
|
+
this.recovery = recovery;
|
|
52
|
+
this.retryable = RETRYABLE.has(code);
|
|
53
|
+
}
|
|
54
|
+
/** Render the structured shape, for receipts and management surfaces. */
|
|
55
|
+
toShape() {
|
|
56
|
+
return {
|
|
57
|
+
code: this.code,
|
|
58
|
+
operation: this.operation,
|
|
59
|
+
message: this.message,
|
|
60
|
+
recovery: this.recovery,
|
|
61
|
+
retryable: this.retryable,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Strip anything credential-shaped from recovery advice.
|
|
67
|
+
*
|
|
68
|
+
* EXT-34 requires that recovery text never carries raw credentials. Advice is
|
|
69
|
+
* authored rather than interpolated, so this is a guard against a future edit
|
|
70
|
+
* that interpolates a path or a value by accident.
|
|
71
|
+
* @param text - the authored advice.
|
|
72
|
+
* @returns the advice with path- and credential-shaped spans removed.
|
|
73
|
+
*/
|
|
74
|
+
export function sanitizeRecovery(text) {
|
|
75
|
+
return text
|
|
76
|
+
// Windows and POSIX absolute paths.
|
|
77
|
+
.replace(/[A-Za-z]:\\[^\s"']*/g, '<path>')
|
|
78
|
+
.replace(/(?<![\w.])\/(?:[\w.-]+\/)+[\w.-]+/g, '<path>')
|
|
79
|
+
// Token-shaped spans.
|
|
80
|
+
.replace(/\b(?:npm_|ghp_|gho_|sk-)[A-Za-z0-9_-]{8,}/g, '<redacted>')
|
|
81
|
+
.replace(/\b[A-Fa-f0-9]{32,}\b/g, '<redacted>');
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=errors.js.map
|