@agentxm/extension-resolution 0.28.14-preview.1789139351.5cd4595aa
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/LICENSE +110 -0
- package/README.md +56 -0
- package/dist/src/accepted-pack-dependency-resolver.d.ts +23 -0
- package/dist/src/accepted-pack-dependency-resolver.js +31 -0
- package/dist/src/accepted-pack-hydration.d.ts +33 -0
- package/dist/src/accepted-pack-hydration.js +93 -0
- package/dist/src/axm-skill-candidate.d.ts +16 -0
- package/dist/src/axm-skill-candidate.js +80 -0
- package/dist/src/axm-skill-compatibility.d.ts +87 -0
- package/dist/src/axm-skill-compatibility.js +248 -0
- package/dist/src/axm-skill-workspace-compatibility.d.ts +23 -0
- package/dist/src/axm-skill-workspace-compatibility.js +110 -0
- package/dist/src/configured-entry-resolution.d.ts +118 -0
- package/dist/src/configured-entry-resolution.js +735 -0
- package/dist/src/configured-entry.d.ts +38 -0
- package/dist/src/configured-entry.js +8 -0
- package/dist/src/errors.d.ts +113 -0
- package/dist/src/errors.js +71 -0
- package/dist/src/index.d.ts +34 -0
- package/dist/src/index.js +45 -0
- package/dist/src/live.d.ts +25 -0
- package/dist/src/live.js +47 -0
- package/dist/src/named-registry-resolution.d.ts +26 -0
- package/dist/src/named-registry-resolution.js +110 -0
- package/dist/src/pack-dependency-resolution.d.ts +73 -0
- package/dist/src/pack-dependency-resolution.js +422 -0
- package/dist/src/publisher-binding.d.ts +66 -0
- package/dist/src/publisher-binding.js +75 -0
- package/dist/src/release-age-policy.d.ts +55 -0
- package/dist/src/release-age-policy.js +115 -0
- package/dist/src/release-age-posture.d.ts +23 -0
- package/dist/src/release-age-posture.js +15 -0
- package/dist/src/resolution-timeout.d.ts +11 -0
- package/dist/src/resolution-timeout.js +17 -0
- package/dist/src/resolved-pack-dependency.d.ts +32 -0
- package/dist/src/resolved-pack-dependency.js +28 -0
- package/dist/src/source-authority.d.ts +60 -0
- package/dist/src/source-authority.js +70 -0
- package/dist/src/testing.d.ts +40 -0
- package/dist/src/testing.js +40 -0
- package/dist/src/update/constraint-precedence.d.ts +75 -0
- package/dist/src/update/constraint-precedence.js +99 -0
- package/dist/src/update/targeted-update-context.d.ts +101 -0
- package/dist/src/update/targeted-update-context.js +217 -0
- package/dist/src/version-resolution.d.ts +39 -0
- package/dist/src/version-resolution.js +76 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, MIT Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-MIT
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2025-2026 AgentXM, Inc.
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the MIT license that is effective on the second anniversary of the date we make
|
|
91
|
+
the Software available. On or after that date, you may use the Software under
|
|
92
|
+
the MIT license, in which case the following will apply:
|
|
93
|
+
|
|
94
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
95
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
96
|
+
the Software without restriction, including without limitation the rights to
|
|
97
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
98
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
99
|
+
so, subject to the following conditions:
|
|
100
|
+
|
|
101
|
+
The above copyright notice and this permission notice shall be included in all
|
|
102
|
+
copies or substantial portions of the Software.
|
|
103
|
+
|
|
104
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
105
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
106
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
107
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
108
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
109
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
110
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# @agentxm/extension-resolution
|
|
2
|
+
|
|
3
|
+
Extension resolution policy for the AXM client: what a configured or requested
|
|
4
|
+
extension resolves to, and whether that resolution may be accepted.
|
|
5
|
+
|
|
6
|
+
- **Minimum release age** — `parseMinimumReleaseAge`,
|
|
7
|
+
`isVersionEntryEligibleAt`, `releaseAgeEvidence`, exemption and holdback
|
|
8
|
+
records, and the operator's per-invocation `ReleaseAgePosture`.
|
|
9
|
+
- **Version selection under that policy** — `resolveVersionEntryWithReleaseAge`,
|
|
10
|
+
`resolveVersionEntryForReleaseAge`, and the named Registry target decisions
|
|
11
|
+
`decideNamedRegistryVersion` and `namedRegistryCandidates`.
|
|
12
|
+
- **Configured-entry resolution** — `resolveConfiguredSkill` and its six
|
|
13
|
+
siblings, `resolveConfiguredRegistryEntry`, and the
|
|
14
|
+
`ResolvedConfiguredEntry` vocabulary the lockfile and plans carry.
|
|
15
|
+
- **Pack dependency resolution** — `resolvePackDependencies`,
|
|
16
|
+
`resolvePackDependenciesWithReleaseAge`, the resolved-dependency map schema,
|
|
17
|
+
and `acceptedPackDependencyResolver` for deterministic recovery.
|
|
18
|
+
- **Source authority** — `evaluateSourceAuthority`: whether a requested source
|
|
19
|
+
may replace the configured one for the same target.
|
|
20
|
+
- **Publisher-binding trust** — `classifyPublisherBindingTransition` and the
|
|
21
|
+
proposal vocabulary. Shaping the resulting plan risk condition belongs to
|
|
22
|
+
the feature that owns the plan, not here.
|
|
23
|
+
- **Official AXM skill compatibility** — `evaluateAxmSkillCompatibility`,
|
|
24
|
+
`evaluateAxmSkillCandidate`, `readAxmSkillWorkspaceCompatibility`.
|
|
25
|
+
|
|
26
|
+
Exports `.` and `./live`.
|
|
27
|
+
|
|
28
|
+
Dependency budget: `@agentxm/extension-model`, `@agentxm/registry-protocol`,
|
|
29
|
+
`@agentxm/extension-content`, `@agentxm/extension-sources`, and
|
|
30
|
+
`@agentxm/workspace-state`. Deciding what a configured entry resolves to needs
|
|
31
|
+
workspace facts and source acquisition, so this package sits **above**
|
|
32
|
+
`@agentxm/workspace-state`: state must never depend on it.
|
|
33
|
+
|
|
34
|
+
## Provider contract
|
|
35
|
+
|
|
36
|
+
`@agentxm/extension-sources` (an integration) fetches the Registry index, maps
|
|
37
|
+
entries to refs, and probes archives, but it may not import this core package.
|
|
38
|
+
It therefore declares ports whose vocabulary lives in
|
|
39
|
+
`@agentxm/extension-model/unstable/sources/source-host-provider`:
|
|
40
|
+
|
|
41
|
+
- `RegistryResolutionPolicy` — implemented structurally by this package's
|
|
42
|
+
decision functions and bound by the application composition root
|
|
43
|
+
(`apps/cli/src/cli-runtime/registry-resolution-policy-live.ts`).
|
|
44
|
+
- `AxmSkillCandidateGate` — implemented by `AxmSkillCandidateGateLive` in this
|
|
45
|
+
package's `./live`.
|
|
46
|
+
- `WorkspaceCatalog` — implemented by `@agentxm/workspace-projection`, which
|
|
47
|
+
owns the agent-selection facts the catalog reports.
|
|
48
|
+
|
|
49
|
+
Selection semantics that the Registry itself defines (`selectVersion`,
|
|
50
|
+
`resolveVersionEntry`: yanked handling and range maxima) stay in
|
|
51
|
+
`@agentxm/registry-protocol/unstable/registry/version-selection`, which both
|
|
52
|
+
the client integration and this package consume.
|
|
53
|
+
|
|
54
|
+
Unstable and unsupported — use the [axm.sh](https://axm.sh) CLI.
|
|
55
|
+
|
|
56
|
+
FSL-1.1-MIT © 2025-2026 AgentXM, Inc.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pack member resolution from already accepted state.
|
|
3
|
+
*
|
|
4
|
+
* Recovering an accepted Pack must not re-select its members: every member
|
|
5
|
+
* ref comes from the accepted resolution recorded for that member's
|
|
6
|
+
* configured name, and a member without one is a conflict rather than a new
|
|
7
|
+
* selection. That is resolution authority, so the resolver is built here and
|
|
8
|
+
* the application only chooses when to use it.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import type * as FileSystem from "effect/FileSystem";
|
|
13
|
+
import type * as Path from "effect/Path";
|
|
14
|
+
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
15
|
+
import type { AcceptedCanonicalRefError } from "@agentxm/workspace-state";
|
|
16
|
+
import { ExtensionResolutionFailed } from "./errors.js";
|
|
17
|
+
import type { PackDependencyRefResolver } from "./pack-dependency-resolution.js";
|
|
18
|
+
/**
|
|
19
|
+
* Resolve every Pack member from the accepted resolution recorded for its
|
|
20
|
+
* configured name, refusing the recovery when a member has none.
|
|
21
|
+
*/
|
|
22
|
+
export declare const acceptedPackDependencyResolver: () => PackDependencyRefResolver<AcceptedCanonicalRefError | ExtensionResolutionFailed, WorkspaceMutations | FileSystem.FileSystem | Path.Path>;
|
|
23
|
+
//# sourceMappingURL=accepted-pack-dependency-resolver.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pack member resolution from already accepted state.
|
|
3
|
+
*
|
|
4
|
+
* Recovering an accepted Pack must not re-select its members: every member
|
|
5
|
+
* ref comes from the accepted resolution recorded for that member's
|
|
6
|
+
* configured name, and a member without one is a conflict rather than a new
|
|
7
|
+
* selection. That is resolution authority, so the resolver is built here and
|
|
8
|
+
* the application only chooses when to use it.
|
|
9
|
+
*
|
|
10
|
+
* @experimental This API is unstable and may change without notice.
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Option from "effect/Option";
|
|
14
|
+
import { acceptedLockedResolutionRef, WorkspaceMutations } from "@agentxm/workspace-state";
|
|
15
|
+
import { ExtensionResolutionFailed } from "./errors.js";
|
|
16
|
+
/**
|
|
17
|
+
* Resolve every Pack member from the accepted resolution recorded for its
|
|
18
|
+
* configured name, refusing the recovery when a member has none.
|
|
19
|
+
*/
|
|
20
|
+
export const acceptedPackDependencyResolver = () => ({ owner, type, name, root }) => Effect.gen(function* () {
|
|
21
|
+
const workspace = yield* WorkspaceMutations;
|
|
22
|
+
const accepted = yield* acceptedLockedResolutionRef({ workspace, type, name });
|
|
23
|
+
if (Option.isNone(accepted)) {
|
|
24
|
+
return yield* new ExtensionResolutionFailed({
|
|
25
|
+
category: "conflict",
|
|
26
|
+
detail: `Accepted Pack recovery for ${root} has no accepted ${type} resolution for ${owner}/${name}`,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return accepted.value;
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=accepted-pack-dependency-resolver.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovering the accepted Pack reference a lock entry records.
|
|
3
|
+
*
|
|
4
|
+
* A lock row carries the accepted version and its manifest content identity,
|
|
5
|
+
* but not the member constraints the manifest declares, so a reference rebuilt
|
|
6
|
+
* from the lock alone would expand to an empty closure and record the wrong
|
|
7
|
+
* content identity. Fetching the accepted archive and decoding its manifest is
|
|
8
|
+
* the only way to recover those constraints without re-resolving — and
|
|
9
|
+
* re-resolving is exactly what an operation restoring accepted state must not
|
|
10
|
+
* do.
|
|
11
|
+
*
|
|
12
|
+
* This lives with resolution rather than with either feature because both the
|
|
13
|
+
* configured install closure and the reconciliation sweep's Pack recovery
|
|
14
|
+
* restore from the same accepted authority.
|
|
15
|
+
*
|
|
16
|
+
* @experimental This API is unstable and may change without notice.
|
|
17
|
+
*/
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as FileSystem from "effect/FileSystem";
|
|
20
|
+
import * as Path from "effect/Path";
|
|
21
|
+
import type { PackRef } from "@agentxm/extension-model/unstable/extensions/refs/pack";
|
|
22
|
+
import { SourceHostProviders } from "@agentxm/extension-sources";
|
|
23
|
+
import { WorkspaceMutations } from "@agentxm/workspace-state";
|
|
24
|
+
import { ExtensionResolutionFailed } from "./errors.js";
|
|
25
|
+
/**
|
|
26
|
+
* Complete an accepted Pack reference with the member constraints its accepted
|
|
27
|
+
* archive declares. The archive is fetched, its manifest decoded, and its
|
|
28
|
+
* identity and content checked against the lock before any member resolves
|
|
29
|
+
* from it, so a divergent archive refuses instead of silently reshaping the
|
|
30
|
+
* closure.
|
|
31
|
+
*/
|
|
32
|
+
export declare const hydrateAcceptedPackRef: (name: string, ref: PackRef) => Effect.Effect<PackRef, ExtensionResolutionFailed, WorkspaceMutations | SourceHostProviders | FileSystem.FileSystem | Path.Path>;
|
|
33
|
+
//# sourceMappingURL=accepted-pack-hydration.d.ts.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovering the accepted Pack reference a lock entry records.
|
|
3
|
+
*
|
|
4
|
+
* A lock row carries the accepted version and its manifest content identity,
|
|
5
|
+
* but not the member constraints the manifest declares, so a reference rebuilt
|
|
6
|
+
* from the lock alone would expand to an empty closure and record the wrong
|
|
7
|
+
* content identity. Fetching the accepted archive and decoding its manifest is
|
|
8
|
+
* the only way to recover those constraints without re-resolving — and
|
|
9
|
+
* re-resolving is exactly what an operation restoring accepted state must not
|
|
10
|
+
* do.
|
|
11
|
+
*
|
|
12
|
+
* This lives with resolution rather than with either feature because both the
|
|
13
|
+
* configured install closure and the reconciliation sweep's Pack recovery
|
|
14
|
+
* restore from the same accepted authority.
|
|
15
|
+
*
|
|
16
|
+
* @experimental This API is unstable and may change without notice.
|
|
17
|
+
*/
|
|
18
|
+
import * as Effect from "effect/Effect";
|
|
19
|
+
import * as FileSystem from "effect/FileSystem";
|
|
20
|
+
import * as Option from "effect/Option";
|
|
21
|
+
import * as Path from "effect/Path";
|
|
22
|
+
import * as Schema from "effect/Schema";
|
|
23
|
+
import { PACK_MANIFEST_FILENAME, PackManifestSchema, } from "@agentxm/extension-model/unstable/packs/manifest-schema";
|
|
24
|
+
import { SourceHostProviders } from "@agentxm/extension-sources";
|
|
25
|
+
import { WorkspaceMutations, computePackManifestContentIdentity } from "@agentxm/workspace-state";
|
|
26
|
+
import { ExtensionResolutionFailed } from "./errors.js";
|
|
27
|
+
const refused = (fields) => new ExtensionResolutionFailed({
|
|
28
|
+
category: fields.category,
|
|
29
|
+
detail: fields.detail,
|
|
30
|
+
...(fields.cause === undefined ? {} : { cause: fields.cause }),
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Complete an accepted Pack reference with the member constraints its accepted
|
|
34
|
+
* archive declares. The archive is fetched, its manifest decoded, and its
|
|
35
|
+
* identity and content checked against the lock before any member resolves
|
|
36
|
+
* from it, so a divergent archive refuses instead of silently reshaping the
|
|
37
|
+
* closure.
|
|
38
|
+
*/
|
|
39
|
+
export const hydrateAcceptedPackRef = Effect.fn("ExtensionResolution.hydrateAcceptedPackRef")(function* (name, ref) {
|
|
40
|
+
const ws = yield* WorkspaceMutations;
|
|
41
|
+
const sources = yield* SourceHostProviders;
|
|
42
|
+
const fs = yield* FileSystem.FileSystem;
|
|
43
|
+
const path = yield* Path.Path;
|
|
44
|
+
const locked = yield* ws.getLockedPack(name).pipe(Effect.mapError((cause) => refused({
|
|
45
|
+
category: "internal",
|
|
46
|
+
detail: `Accepted Pack lock for ${name} could not be read`,
|
|
47
|
+
cause,
|
|
48
|
+
})));
|
|
49
|
+
if (Option.isNone(locked)) {
|
|
50
|
+
return yield* refused({
|
|
51
|
+
category: "conflict",
|
|
52
|
+
detail: `Accepted Pack recovery has no lock authority for ${name}`,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const manifest = yield* Effect.scoped(Effect.gen(function* () {
|
|
56
|
+
const fetched = yield* sources.fetch(ref).pipe(Effect.mapError((cause) => refused({
|
|
57
|
+
category: "network",
|
|
58
|
+
detail: `Failed to fetch accepted Pack ${ref.owner}/packs/${ref.name}@${ref.version}`,
|
|
59
|
+
cause,
|
|
60
|
+
})));
|
|
61
|
+
const manifestPath = path.join(fetched.directory, PACK_MANIFEST_FILENAME);
|
|
62
|
+
const manifestText = yield* fs.readFileString(manifestPath).pipe(Effect.mapError((cause) => refused({
|
|
63
|
+
category: "validation",
|
|
64
|
+
detail: `Accepted Pack archive has no readable manifest at ${manifestPath}`,
|
|
65
|
+
cause,
|
|
66
|
+
})));
|
|
67
|
+
const manifestJson = yield* Effect.try({
|
|
68
|
+
try: () => JSON.parse(manifestText),
|
|
69
|
+
catch: (cause) => refused({
|
|
70
|
+
category: "validation",
|
|
71
|
+
detail: `Accepted Pack archive manifest is not valid JSON: ${manifestPath}`,
|
|
72
|
+
cause,
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
75
|
+
return yield* Schema.decodeUnknownEffect(PackManifestSchema)(manifestJson).pipe(Effect.mapError((cause) => refused({
|
|
76
|
+
category: "validation",
|
|
77
|
+
detail: `Accepted Pack archive manifest is invalid: ${manifestPath}`,
|
|
78
|
+
cause,
|
|
79
|
+
})));
|
|
80
|
+
}));
|
|
81
|
+
const observedContentIdentity = computePackManifestContentIdentity(manifest);
|
|
82
|
+
if (manifest.owner !== ref.owner ||
|
|
83
|
+
manifest.name !== ref.name ||
|
|
84
|
+
manifest.version !== ref.version ||
|
|
85
|
+
observedContentIdentity !== locked.value.manifestContentIdentity) {
|
|
86
|
+
return yield* refused({
|
|
87
|
+
category: "conflict",
|
|
88
|
+
detail: `Accepted Pack ${ref.owner}/packs/${ref.name}@${ref.version} content ${locked.value.manifestContentIdentity} does not match fetched archive ${manifest.owner}/packs/${manifest.name}@${manifest.version} content ${observedContentIdentity}`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return { ...ref, pack: { name: ref.pack.name, dependencies: manifest.dependencies } };
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=accepted-pack-hydration.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as FileSystem from "effect/FileSystem";
|
|
3
|
+
import * as Path from "effect/Path";
|
|
4
|
+
import { AxmSkillCompatibilityUnavailable, AxmSkillIncompatible } from "./errors.js";
|
|
5
|
+
import { type AxmSkillCompatibility } from "./axm-skill-compatibility.js";
|
|
6
|
+
import type { SkillExtensionRef } from "@agentxm/extension-model/unstable/extensions/refs/skill";
|
|
7
|
+
export interface ValidateAxmSkillCandidateArgs {
|
|
8
|
+
readonly ref: SkillExtensionRef;
|
|
9
|
+
readonly packageRoot: string;
|
|
10
|
+
readonly skillSourcePath: string;
|
|
11
|
+
}
|
|
12
|
+
/** Inspect candidate bytes and evaluate official AXM skill compatibility. */
|
|
13
|
+
export declare const evaluateAxmSkillCandidate: (args: ValidateAxmSkillCandidateArgs) => Effect.Effect<AxmSkillCompatibility | null, AxmSkillCompatibilityUnavailable, FileSystem.FileSystem | Path.Path>;
|
|
14
|
+
/** Validate official AXM skill bytes before any workspace state is changed. */
|
|
15
|
+
export declare const validateAxmSkillCandidate: (args: ValidateAxmSkillCandidateArgs) => Effect.Effect<AxmSkillCompatibility | null, AxmSkillCompatibilityUnavailable | AxmSkillIncompatible, FileSystem.FileSystem | Path.Path>;
|
|
16
|
+
//# sourceMappingURL=axm-skill-candidate.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as FileSystem from "effect/FileSystem";
|
|
3
|
+
import * as Option from "effect/Option";
|
|
4
|
+
import * as Path from "effect/Path";
|
|
5
|
+
import { AxmSkillCompatibilityUnavailable, AxmSkillIncompatible } from "./errors.js";
|
|
6
|
+
import { AXM_SKILL_FQN, AxmSkillCompatibilityPolicy, evaluateAxmSkillCompatibility, } from "./axm-skill-compatibility.js";
|
|
7
|
+
import { parseSkillMd } from "@agentxm/extension-content";
|
|
8
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9
|
+
const parseManifest = (content) => Option.match(content, {
|
|
10
|
+
onNone: () => ({ official: false, version: null }),
|
|
11
|
+
onSome: (text) => {
|
|
12
|
+
try {
|
|
13
|
+
const value = JSON.parse(text);
|
|
14
|
+
if (!isRecord(value))
|
|
15
|
+
return { official: false, version: null };
|
|
16
|
+
return {
|
|
17
|
+
official: value["owner"] === "@agentxm" && value["type"] === "skill" && value["name"] === "axm",
|
|
18
|
+
version: typeof value["version"] === "string" ? value["version"] : null,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return { official: false, version: null };
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
const isKnownOfficialRef = (ref) => (ref.refType === "registry" || ref.refType === "workspace") &&
|
|
27
|
+
ref.owner === "@agentxm" &&
|
|
28
|
+
ref.name === "axm";
|
|
29
|
+
const sourceForRef = (ref) => {
|
|
30
|
+
switch (ref.refType) {
|
|
31
|
+
case "registry":
|
|
32
|
+
return `${ref.owner}/skills/${ref.name}@${ref.version}`;
|
|
33
|
+
case "workspace":
|
|
34
|
+
return `workspace:${ref.owner}/skills/${ref.name}`;
|
|
35
|
+
case "git-hosted":
|
|
36
|
+
case "local":
|
|
37
|
+
return ref.location;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/** Inspect candidate bytes and evaluate official AXM skill compatibility. */
|
|
41
|
+
export const evaluateAxmSkillCandidate = (args) => Effect.gen(function* () {
|
|
42
|
+
const fs = yield* FileSystem.FileSystem;
|
|
43
|
+
const path = yield* Path.Path;
|
|
44
|
+
const [manifestContent, skillContent] = yield* Effect.all([
|
|
45
|
+
fs.readFileString(path.join(args.packageRoot, "skill.json")).pipe(Effect.option),
|
|
46
|
+
fs.readFileString(path.join(args.skillSourcePath, "SKILL.md")).pipe(Effect.option),
|
|
47
|
+
]);
|
|
48
|
+
const manifest = parseManifest(manifestContent);
|
|
49
|
+
if (!isKnownOfficialRef(args.ref) && !manifest.official)
|
|
50
|
+
return null;
|
|
51
|
+
const parsedSkill = Option.flatMap(skillContent, (content) => parseSkillMd(content, "axm"));
|
|
52
|
+
const candidate = {
|
|
53
|
+
manifestVersion: manifest.version,
|
|
54
|
+
metadata: Option.match(parsedSkill, {
|
|
55
|
+
onNone: () => null,
|
|
56
|
+
onSome: (skill) => Option.getOrNull(skill.metadata),
|
|
57
|
+
}),
|
|
58
|
+
source: sourceForRef(args.ref),
|
|
59
|
+
};
|
|
60
|
+
const policy = yield* Effect.serviceOption(AxmSkillCompatibilityPolicy);
|
|
61
|
+
const result = Option.match(policy, {
|
|
62
|
+
onNone: () => evaluateAxmSkillCompatibility({ cliVersion: null, skill: candidate }),
|
|
63
|
+
onSome: (service) => service.evaluate({ fqn: AXM_SKILL_FQN, candidate }),
|
|
64
|
+
});
|
|
65
|
+
if (result === null) {
|
|
66
|
+
return yield* new AxmSkillCompatibilityUnavailable();
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
});
|
|
70
|
+
/** Validate official AXM skill bytes before any workspace state is changed. */
|
|
71
|
+
export const validateAxmSkillCandidate = (args) => Effect.gen(function* () {
|
|
72
|
+
const result = yield* evaluateAxmSkillCandidate(args);
|
|
73
|
+
if (result === null)
|
|
74
|
+
return null;
|
|
75
|
+
if (result.status === "incompatible") {
|
|
76
|
+
return yield* new AxmSkillIncompatible({ compatibility: result });
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=axm-skill-candidate.js.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as Layer from "effect/Layer";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import * as ServiceMap from "effect/Context";
|
|
4
|
+
export declare const AXM_SKILL_FQN = "@agentxm/skills/axm";
|
|
5
|
+
export declare const AXM_SKILL_CLI_VERSION_METADATA_KEY = "axm.sh/cli-version";
|
|
6
|
+
export declare const AXM_SKILL_CLI_VERSION_RANGE_METADATA_KEY = "axm.sh/cli-version-range";
|
|
7
|
+
export declare const AXM_SKILL_BUNDLED_PREVIEW_COMMAND = "axm skills install @agentxm/skills/axm --bundled --preview";
|
|
8
|
+
export declare const AXM_SKILL_BUNDLED_APPLY_COMMAND = "axm skills install @agentxm/skills/axm --bundled";
|
|
9
|
+
export declare const AXM_SKILL_REGISTRY_PREVIEW_COMMAND = "axm skills update --name axm --preview";
|
|
10
|
+
export declare const AXM_SKILL_REGISTRY_APPLY_COMMAND = "axm skills update --name axm";
|
|
11
|
+
export declare const AxmSkillCompatibilityReasonSchema: Schema.Literals<readonly ["cli-version-unavailable", "axm-skill-missing", "axm-skill-manifest-invalid", "compatibility-metadata-missing", "compatibility-metadata-malformed", "skill-release-mismatch", "skill-release-range-mismatch", "cli-version-incompatible"]>;
|
|
12
|
+
export type AxmSkillCompatibilityReason = typeof AxmSkillCompatibilityReasonSchema.Type;
|
|
13
|
+
export declare const AxmSkillCompatibilityRecoveryActionSchema: Schema.Literals<readonly ["none", "inspect-cli", "upgrade-cli", "update-registry-skill", "install-bundled-skill", "preserve-authored-skill"]>;
|
|
14
|
+
export type AxmSkillCompatibilityRecoveryAction = typeof AxmSkillCompatibilityRecoveryActionSchema.Type;
|
|
15
|
+
export declare const AxmSkillCompatibilityRecoveryStepSchema: Schema.Struct<{
|
|
16
|
+
readonly boundary: Schema.Literals<readonly ["executable", "workspace", "verification"]>;
|
|
17
|
+
readonly command: Schema.String;
|
|
18
|
+
readonly preview: Schema.Boolean;
|
|
19
|
+
}>;
|
|
20
|
+
export type AxmSkillCompatibilityRecoveryStep = typeof AxmSkillCompatibilityRecoveryStepSchema.Type;
|
|
21
|
+
export declare const AxmSkillCompatibilityRecoverySchema: Schema.Struct<{
|
|
22
|
+
readonly action: Schema.Literals<readonly ["none", "inspect-cli", "upgrade-cli", "update-registry-skill", "install-bundled-skill", "preserve-authored-skill"]>;
|
|
23
|
+
readonly targetCliVersion: Schema.NullOr<Schema.String>;
|
|
24
|
+
readonly targetSkillVersion: Schema.NullOr<Schema.String>;
|
|
25
|
+
readonly nextAction: Schema.NullOr<Schema.String>;
|
|
26
|
+
readonly steps: Schema.$Array<Schema.Struct<{
|
|
27
|
+
readonly boundary: Schema.Literals<readonly ["executable", "workspace", "verification"]>;
|
|
28
|
+
readonly command: Schema.String;
|
|
29
|
+
readonly preview: Schema.Boolean;
|
|
30
|
+
}>>;
|
|
31
|
+
}>;
|
|
32
|
+
export type AxmSkillCompatibilityRecovery = typeof AxmSkillCompatibilityRecoverySchema.Type;
|
|
33
|
+
export declare const formatAxmSkillCompatibilityTarget: (target: {
|
|
34
|
+
readonly targetCliVersion: string | null;
|
|
35
|
+
readonly targetSkillVersion: string | null;
|
|
36
|
+
}) => string;
|
|
37
|
+
export declare const AxmSkillCompatibilitySchema: Schema.Struct<{
|
|
38
|
+
readonly status: Schema.Literals<readonly ["compatible", "incompatible"]>;
|
|
39
|
+
readonly cliVersion: Schema.NullOr<Schema.String>;
|
|
40
|
+
readonly skillVersion: Schema.NullOr<Schema.String>;
|
|
41
|
+
readonly source: Schema.NullOr<Schema.String>;
|
|
42
|
+
readonly declaredCliVersion: Schema.NullOr<Schema.String>;
|
|
43
|
+
readonly declaredCliVersionRange: Schema.NullOr<Schema.String>;
|
|
44
|
+
readonly reasonCode: Schema.NullOr<Schema.Literals<readonly ["cli-version-unavailable", "axm-skill-missing", "axm-skill-manifest-invalid", "compatibility-metadata-missing", "compatibility-metadata-malformed", "skill-release-mismatch", "skill-release-range-mismatch", "cli-version-incompatible"]>>;
|
|
45
|
+
readonly detail: Schema.NullOr<Schema.String>;
|
|
46
|
+
readonly recovery: Schema.Struct<{
|
|
47
|
+
readonly action: Schema.Literals<readonly ["none", "inspect-cli", "upgrade-cli", "update-registry-skill", "install-bundled-skill", "preserve-authored-skill"]>;
|
|
48
|
+
readonly targetCliVersion: Schema.NullOr<Schema.String>;
|
|
49
|
+
readonly targetSkillVersion: Schema.NullOr<Schema.String>;
|
|
50
|
+
readonly nextAction: Schema.NullOr<Schema.String>;
|
|
51
|
+
readonly steps: Schema.$Array<Schema.Struct<{
|
|
52
|
+
readonly boundary: Schema.Literals<readonly ["executable", "workspace", "verification"]>;
|
|
53
|
+
readonly command: Schema.String;
|
|
54
|
+
readonly preview: Schema.Boolean;
|
|
55
|
+
}>>;
|
|
56
|
+
}>;
|
|
57
|
+
}>;
|
|
58
|
+
export type AxmSkillCompatibility = typeof AxmSkillCompatibilitySchema.Type;
|
|
59
|
+
export interface AxmSkillCompatibilityCandidate {
|
|
60
|
+
readonly manifestVersion: string | null;
|
|
61
|
+
readonly metadata: Readonly<Record<string, string>> | null;
|
|
62
|
+
readonly source: string | null;
|
|
63
|
+
}
|
|
64
|
+
export interface AxmSkillCompatibilityInput {
|
|
65
|
+
readonly cliVersion: string | null;
|
|
66
|
+
readonly skill: AxmSkillCompatibilityCandidate | null;
|
|
67
|
+
}
|
|
68
|
+
export interface AxmSkillCompatibilityPolicyInput {
|
|
69
|
+
readonly fqn: string;
|
|
70
|
+
readonly candidate: AxmSkillCompatibilityCandidate | null;
|
|
71
|
+
}
|
|
72
|
+
export interface AxmSkillCompatibilityPolicyService {
|
|
73
|
+
readonly evaluate: (input: AxmSkillCompatibilityPolicyInput) => AxmSkillCompatibility | null;
|
|
74
|
+
}
|
|
75
|
+
declare const AxmSkillCompatibilityPolicy_base: ServiceMap.ServiceClass<AxmSkillCompatibilityPolicy, "@agentxm/extension-resolution/axm-skill-compatibility/AxmSkillCompatibilityPolicy", AxmSkillCompatibilityPolicyService>;
|
|
76
|
+
export declare class AxmSkillCompatibilityPolicy extends AxmSkillCompatibilityPolicy_base {
|
|
77
|
+
}
|
|
78
|
+
export type AxmSkillCliVersionRangeValidation = {
|
|
79
|
+
readonly valid: true;
|
|
80
|
+
} | {
|
|
81
|
+
readonly valid: false;
|
|
82
|
+
};
|
|
83
|
+
export declare const validateAxmSkillCliVersionRange: (value: string) => AxmSkillCliVersionRangeValidation;
|
|
84
|
+
export declare const evaluateAxmSkillCompatibility: (input: AxmSkillCompatibilityInput) => AxmSkillCompatibility;
|
|
85
|
+
export declare const makeAxmSkillCompatibilityPolicyLayer: (cliVersion: string | null) => Layer.Layer<AxmSkillCompatibilityPolicy>;
|
|
86
|
+
export {};
|
|
87
|
+
//# sourceMappingURL=axm-skill-compatibility.d.ts.map
|