agentwheel 0.18.4 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +187 -30
- package/openpack.json +1 -1
- package/package.json +1 -1
- package/skills/agentwheel/SKILL.md +1 -1
- package/skills/agentwheel-discovery/SKILL.md +1 -1
package/dist/index.js
CHANGED
|
@@ -56,6 +56,18 @@ var packageComposeEntrySchema = z.object({
|
|
|
56
56
|
markers: z.boolean().optional(),
|
|
57
57
|
optional: z.boolean().optional()
|
|
58
58
|
});
|
|
59
|
+
var packageCompositionRuleSchema = z.object({
|
|
60
|
+
target: z.string().min(1),
|
|
61
|
+
include: z.string().min(1),
|
|
62
|
+
exclude: z.array(z.string().min(1)).optional(),
|
|
63
|
+
runtimes: z.array(z.string().min(1)).optional(),
|
|
64
|
+
markers: z.boolean().optional()
|
|
65
|
+
});
|
|
66
|
+
var packageSupersedesEntrySchema = z.object({
|
|
67
|
+
package: z.string().min(1),
|
|
68
|
+
selector: z.string().min(1),
|
|
69
|
+
reason: z.string().min(1)
|
|
70
|
+
});
|
|
59
71
|
var packageItemRequireObjectSchema = z.object({
|
|
60
72
|
selector: z.string().min(1),
|
|
61
73
|
optional: z.boolean().optional(),
|
|
@@ -97,6 +109,7 @@ var artifactSchema = z.object({
|
|
|
97
109
|
requires: z.array(packageItemRequireSchema).optional(),
|
|
98
110
|
suggests: z.array(packageItemSuggestSchema).optional(),
|
|
99
111
|
compose: z.array(packageComposeEntrySchema).optional(),
|
|
112
|
+
supersedes: z.array(packageSupersedesEntrySchema).optional(),
|
|
100
113
|
runtimes: z.array(z.string().min(1)).optional(),
|
|
101
114
|
composedFrom: z.array(composedFromEntrySchema).optional()
|
|
102
115
|
});
|
|
@@ -580,7 +593,8 @@ var graphLockArtifactSchema = z4.object({
|
|
|
580
593
|
kind: fileKindSchema,
|
|
581
594
|
hash: z4.string().min(16),
|
|
582
595
|
channel: z4.enum(["managed", "overlay", "addition", "override", "ejected"]).default("managed"),
|
|
583
|
-
composedFrom: z4.array(composedFromEntrySchema).optional()
|
|
596
|
+
composedFrom: z4.array(composedFromEntrySchema).optional(),
|
|
597
|
+
supersedes: z4.array(packageSupersedesEntrySchema).optional()
|
|
584
598
|
});
|
|
585
599
|
var graphLockPlainNameIncumbentSchema = z4.object({
|
|
586
600
|
adapter: z4.string().min(1),
|
|
@@ -5638,7 +5652,7 @@ var legacyArtifactTypeSchema = z6.enum([
|
|
|
5638
5652
|
"plugins"
|
|
5639
5653
|
]);
|
|
5640
5654
|
var runtimeListSchema = z6.array(z6.string().min(1));
|
|
5641
|
-
var CURRENT_OPENPACK_SCHEMA_VERSION =
|
|
5655
|
+
var CURRENT_OPENPACK_SCHEMA_VERSION = 3;
|
|
5642
5656
|
var packageProvideBaseSchema = z6.object({
|
|
5643
5657
|
path: z6.string().min(1),
|
|
5644
5658
|
format: artifactFormatSchema.optional(),
|
|
@@ -5650,6 +5664,7 @@ var packageItemSchema = z6.object({
|
|
|
5650
5664
|
requires: z6.array(packageItemRequireSchema).optional(),
|
|
5651
5665
|
suggests: z6.array(packageItemSuggestSchema).optional(),
|
|
5652
5666
|
compose: z6.array(packageComposeEntrySchema).optional(),
|
|
5667
|
+
supersedes: z6.array(packageSupersedesEntrySchema).optional(),
|
|
5653
5668
|
runtimes: runtimeListSchema.optional()
|
|
5654
5669
|
});
|
|
5655
5670
|
var packageDependencySchema = z6.object({
|
|
@@ -5680,8 +5695,7 @@ var packageManifestV1Schema = z6.object({
|
|
|
5680
5695
|
version: z6.string().min(1),
|
|
5681
5696
|
provides: z6.array(packageProvideV1Schema).min(1)
|
|
5682
5697
|
});
|
|
5683
|
-
var
|
|
5684
|
-
schemaVersion: z6.literal(CURRENT_OPENPACK_SCHEMA_VERSION),
|
|
5698
|
+
var packageManifestModernShape = {
|
|
5685
5699
|
name: z6.string().min(1),
|
|
5686
5700
|
version: z6.string().min(1),
|
|
5687
5701
|
runtimes: runtimeListSchema.optional(),
|
|
@@ -5689,7 +5703,8 @@ var packageManifestV2Schema = z6.object({
|
|
|
5689
5703
|
suggests: z6.record(z6.string().min(1), packageSuggestionSchema).optional(),
|
|
5690
5704
|
compose: z6.array(packageComposeEntrySchema).optional(),
|
|
5691
5705
|
provides: z6.array(packageProvideSchema).default([])
|
|
5692
|
-
}
|
|
5706
|
+
};
|
|
5707
|
+
function requireProvidesOrDependencies(manifest, ctx) {
|
|
5693
5708
|
const hasProvides = manifest.provides.length > 0;
|
|
5694
5709
|
const hasRequires = Object.keys(manifest.requires ?? {}).length > 0;
|
|
5695
5710
|
if (!hasProvides && !hasRequires) {
|
|
@@ -5699,8 +5714,17 @@ var packageManifestV2Schema = z6.object({
|
|
|
5699
5714
|
message: "OpenPack v2 manifest must declare at least one provides entry or one requires dependency"
|
|
5700
5715
|
});
|
|
5701
5716
|
}
|
|
5702
|
-
}
|
|
5703
|
-
var
|
|
5717
|
+
}
|
|
5718
|
+
var packageManifestV2Schema = z6.object({
|
|
5719
|
+
schemaVersion: z6.literal(2),
|
|
5720
|
+
...packageManifestModernShape
|
|
5721
|
+
}).superRefine(requireProvidesOrDependencies);
|
|
5722
|
+
var packageManifestV3Schema = z6.object({
|
|
5723
|
+
schemaVersion: z6.literal(CURRENT_OPENPACK_SCHEMA_VERSION),
|
|
5724
|
+
...packageManifestModernShape,
|
|
5725
|
+
compositionRules: z6.array(packageCompositionRuleSchema).optional()
|
|
5726
|
+
}).superRefine(requireProvidesOrDependencies);
|
|
5727
|
+
var packageManifestSchema = z6.union([packageManifestV1Schema, packageManifestV2Schema, packageManifestV3Schema]);
|
|
5704
5728
|
var openPackManifestNames = ["openpack.json", "openpack.jsonc"];
|
|
5705
5729
|
var legacyPackageManifestNames = ["agentwheel.json", "agentwheel.jsonc"];
|
|
5706
5730
|
var packageManifestNames = [...openPackManifestNames, ...legacyPackageManifestNames];
|
|
@@ -5741,9 +5765,30 @@ function parsePackageManifest(parsed, path = "package manifest") {
|
|
|
5741
5765
|
return parseWithSchema(packageManifestV1Schema, parsed, path);
|
|
5742
5766
|
}
|
|
5743
5767
|
if (parsed.schemaVersion === 2) {
|
|
5768
|
+
const violations = v2OpenPackViolations(parsed);
|
|
5769
|
+
if (violations.length > 0) {
|
|
5770
|
+
throw new Error(`OpenPack schemaVersion 3 is required for ${violations.join(", ")} in ${path}. Set "schemaVersion": 3.`);
|
|
5771
|
+
}
|
|
5744
5772
|
return parseWithSchema(packageManifestV2Schema, parsed, path);
|
|
5745
5773
|
}
|
|
5746
|
-
|
|
5774
|
+
if (parsed.schemaVersion === 3) {
|
|
5775
|
+
return parseWithSchema(packageManifestV3Schema, parsed, path);
|
|
5776
|
+
}
|
|
5777
|
+
throw new Error(`Invalid package manifest ${path}: schemaVersion must be 1, 2, or 3`);
|
|
5778
|
+
}
|
|
5779
|
+
function v2OpenPackViolations(manifest) {
|
|
5780
|
+
const violations = [];
|
|
5781
|
+
if (Object.prototype.hasOwnProperty.call(manifest, "compositionRules")) violations.push("compositionRules");
|
|
5782
|
+
const provides = Array.isArray(manifest.provides) ? manifest.provides : [];
|
|
5783
|
+
for (const [provideIndex, provide] of provides.entries()) {
|
|
5784
|
+
if (!isRecord7(provide) || !isRecord7(provide.items)) continue;
|
|
5785
|
+
for (const [itemName, item] of Object.entries(provide.items)) {
|
|
5786
|
+
if (isRecord7(item) && Object.prototype.hasOwnProperty.call(item, "supersedes")) {
|
|
5787
|
+
violations.push(`provides[${provideIndex}].items.${itemName}.supersedes`);
|
|
5788
|
+
}
|
|
5789
|
+
}
|
|
5790
|
+
}
|
|
5791
|
+
return violations;
|
|
5747
5792
|
}
|
|
5748
5793
|
function parseWithSchema(schema, parsed, path) {
|
|
5749
5794
|
const result = schema.safeParse(parsed);
|
|
@@ -5753,7 +5798,7 @@ function parseWithSchema(schema, parsed, path) {
|
|
|
5753
5798
|
}
|
|
5754
5799
|
function v1OpenPackViolations(manifest) {
|
|
5755
5800
|
const violations = [];
|
|
5756
|
-
for (const key of ["requires", "items", "compose", "runtimes"]) {
|
|
5801
|
+
for (const key of ["requires", "items", "compose", "runtimes", "compositionRules", "supersedes"]) {
|
|
5757
5802
|
if (Object.prototype.hasOwnProperty.call(manifest, key)) violations.push(key);
|
|
5758
5803
|
}
|
|
5759
5804
|
const provides = Array.isArray(manifest.provides) ? manifest.provides : [];
|
|
@@ -6003,6 +6048,7 @@ async function artifactForFile(type, name, sourcePath, relativePath, packageName
|
|
|
6003
6048
|
requires: item.requires,
|
|
6004
6049
|
suggests: item.suggests,
|
|
6005
6050
|
compose: item.compose,
|
|
6051
|
+
supersedes: item.supersedes,
|
|
6006
6052
|
runtimes: item.runtimes ?? provideRuntimes(provide) ?? manifestRuntimes(manifest)
|
|
6007
6053
|
};
|
|
6008
6054
|
}
|
|
@@ -6023,6 +6069,7 @@ async function artifactForDir(type, name, sourcePath, relativePath, packageName,
|
|
|
6023
6069
|
requires: item.requires,
|
|
6024
6070
|
suggests: item.suggests,
|
|
6025
6071
|
compose: item.compose,
|
|
6072
|
+
supersedes: item.supersedes,
|
|
6026
6073
|
runtimes: item.runtimes ?? provideRuntimes(provide) ?? manifestRuntimes(manifest)
|
|
6027
6074
|
};
|
|
6028
6075
|
}
|
|
@@ -6030,13 +6077,13 @@ function itemMetadata(provide, itemName) {
|
|
|
6030
6077
|
if (!provide || !("items" in provide) || !provide.items || !itemName) return {};
|
|
6031
6078
|
const item = provide.items[itemName];
|
|
6032
6079
|
if (!item) return {};
|
|
6033
|
-
return { format: item.format, requires: item.requires, suggests: item.suggests, compose: item.compose, runtimes: item.runtimes };
|
|
6080
|
+
return { format: item.format, requires: item.requires, suggests: item.suggests, compose: item.compose, supersedes: item.supersedes, runtimes: item.runtimes };
|
|
6034
6081
|
}
|
|
6035
6082
|
function provideRuntimes(provide) {
|
|
6036
6083
|
return provide && "runtimes" in provide ? provide.runtimes : void 0;
|
|
6037
6084
|
}
|
|
6038
6085
|
function manifestRuntimes(manifest) {
|
|
6039
|
-
return manifest && manifest.schemaVersion
|
|
6086
|
+
return manifest && manifest.schemaVersion !== 1 ? manifest.runtimes : void 0;
|
|
6040
6087
|
}
|
|
6041
6088
|
|
|
6042
6089
|
// src/source/clawhub.ts
|
|
@@ -7229,7 +7276,14 @@ async function expandMarkdownIncludes(artifacts, packageRoot, options = {}) {
|
|
|
7229
7276
|
if (files.length === 0) continue;
|
|
7230
7277
|
const composedFrom = [];
|
|
7231
7278
|
for (const file of files) {
|
|
7232
|
-
const
|
|
7279
|
+
const localEntries = composeEntriesForFile(artifact, file).map((entry) => ({
|
|
7280
|
+
entry,
|
|
7281
|
+
packageRoot,
|
|
7282
|
+
artifactPaths,
|
|
7283
|
+
nodeId: options.nodeId
|
|
7284
|
+
}));
|
|
7285
|
+
const externalEntries = isPrimaryMarkdownFile(artifact, file) ? options.additionalComposeEntries?.(artifact) ?? [] : [];
|
|
7286
|
+
const result = await expandFile(file, packageRoot, [...localEntries, ...externalEntries], artifactPaths, options);
|
|
7233
7287
|
if (result.changed) await writeFile17(file, result.content, "utf8");
|
|
7234
7288
|
composedFrom.push(...result.composedFrom);
|
|
7235
7289
|
}
|
|
@@ -7247,7 +7301,8 @@ async function validateMarkdownIncludes(artifacts, packageRoot, options = {}) {
|
|
|
7247
7301
|
const artifactPaths = artifactPathMap(artifacts);
|
|
7248
7302
|
for (const artifact of artifacts) {
|
|
7249
7303
|
for (const file of await markdownFilesForArtifact(artifact)) {
|
|
7250
|
-
|
|
7304
|
+
const entries = composeEntriesForFile(artifact, file).map((entry) => ({ entry, packageRoot, artifactPaths, nodeId: options.nodeId }));
|
|
7305
|
+
await expandFile(file, packageRoot, entries, artifactPaths, options);
|
|
7251
7306
|
}
|
|
7252
7307
|
}
|
|
7253
7308
|
}
|
|
@@ -7257,9 +7312,11 @@ async function expandFile(file, packageRoot, appendEntries, artifactPaths, optio
|
|
|
7257
7312
|
const expanded = await expandContent(raw, packageRoot, [owner], artifactPaths, options);
|
|
7258
7313
|
let content = expanded.content;
|
|
7259
7314
|
const composedFrom = [...expanded.composedFrom];
|
|
7260
|
-
for (const
|
|
7261
|
-
const
|
|
7315
|
+
for (const external of appendEntries) {
|
|
7316
|
+
const { entry } = external;
|
|
7317
|
+
const included = await expandInclude(entry.include, external.packageRoot, external.artifactPaths, {
|
|
7262
7318
|
...options,
|
|
7319
|
+
nodeId: external.nodeId,
|
|
7263
7320
|
optional: entry.optional === true,
|
|
7264
7321
|
markers: entry.markers !== false,
|
|
7265
7322
|
chain: [owner]
|
|
@@ -7437,6 +7494,10 @@ function composeEntriesForFile(artifact, file) {
|
|
|
7437
7494
|
if (artifact.kind === "file") return [resolve11(artifact.stagedPath ?? artifact.sourcePath), resolve11(file)].every(Boolean) && resolve11(artifact.stagedPath ?? artifact.sourcePath) === resolve11(file) ? artifact.compose : [];
|
|
7438
7495
|
return basename16(file) === "SKILL.md" && dirname21(file) === resolve11(artifact.stagedPath ?? artifact.sourcePath) ? artifact.compose : [];
|
|
7439
7496
|
}
|
|
7497
|
+
function isPrimaryMarkdownFile(artifact, file) {
|
|
7498
|
+
if (artifact.kind === "file") return resolve11(artifact.stagedPath ?? artifact.sourcePath) === resolve11(file);
|
|
7499
|
+
return basename16(file) === "SKILL.md" && dirname21(file) === resolve11(artifact.stagedPath ?? artifact.sourcePath);
|
|
7500
|
+
}
|
|
7440
7501
|
function orderedForExpansion(artifacts) {
|
|
7441
7502
|
return [...artifacts].sort((a, b) => Number(a.type === "fragments") - Number(b.type === "fragments"));
|
|
7442
7503
|
}
|
|
@@ -8923,7 +8984,7 @@ Dependency chain: ${requirement.chain.join(" -> ")}`);
|
|
|
8923
8984
|
}
|
|
8924
8985
|
}
|
|
8925
8986
|
async function collectDependencyNeeds(state, fetched, options, chain) {
|
|
8926
|
-
if (fetched.manifest
|
|
8987
|
+
if (!fetched.manifest || fetched.manifest.schemaVersion === 1) return [];
|
|
8927
8988
|
const dependencies = fetched.manifest.requires ?? {};
|
|
8928
8989
|
const suggestions = fetched.manifest.suggests ?? {};
|
|
8929
8990
|
const dependencyEntries = Object.entries(dependencies).sort(([a], [b]) => a.localeCompare(b));
|
|
@@ -9487,6 +9548,14 @@ function detectDirectCollisions(nodes) {
|
|
|
9487
9548
|
for (const [selector, owners] of bySelector) {
|
|
9488
9549
|
const uniqueOwners = [...new Map(owners.map((owner) => [owner.node.id, owner])).values()];
|
|
9489
9550
|
if (uniqueOwners.length <= 1) continue;
|
|
9551
|
+
const replacements = uniqueOwners.filter((owner) => {
|
|
9552
|
+
const artifact = owner.artifacts.find((candidate) => artifactSelectorKey(candidate) === selector);
|
|
9553
|
+
return uniqueOwners.every((other) => {
|
|
9554
|
+
if (other === owner) return true;
|
|
9555
|
+
return artifact?.supersedes?.some((entry) => entry.package === other.node.name && entry.selector === selector) === true;
|
|
9556
|
+
});
|
|
9557
|
+
});
|
|
9558
|
+
if (replacements.length === 1) continue;
|
|
9490
9559
|
throw new Error(
|
|
9491
9560
|
`Direct dependency artifact collision for ${selector}: ${uniqueOwners.map((owner) => `${owner.node.id} required by ${owner.node.requiredBy.join(", ")}`).join("; ")}. Resolve by aliasing, deselecting one artifact, or overriding the dependency selection.`
|
|
9492
9561
|
);
|
|
@@ -9806,7 +9875,8 @@ async function renderGraphForTarget(graph, targetContext = {}) {
|
|
|
9806
9875
|
const includeEdges = /* @__PURE__ */ new Map();
|
|
9807
9876
|
const ambiguousPackageNames = ambiguousGraphPackageNames(graph);
|
|
9808
9877
|
for (const rawNode of graph.rawNodes) {
|
|
9809
|
-
|
|
9878
|
+
const ownsCompositionRules = rawNode.depth === 0 && rawNode.manifest?.schemaVersion === 3 && Boolean(rawNode.manifest.compositionRules?.length);
|
|
9879
|
+
if (rawNode.node.selected.length === 0 && !ownsCompositionRules) continue;
|
|
9810
9880
|
const rawBundle = await stageResolvedArtifactsRaw(rawNode.resolved, rawNode.artifacts);
|
|
9811
9881
|
const fragmentCustomized = targetContext.workspaceRoot && targetContext.adapter ? await applyFragmentCustomizations(rawBundle.artifacts, {
|
|
9812
9882
|
workspaceRoot: targetContext.workspaceRoot,
|
|
@@ -9826,11 +9896,18 @@ async function renderGraphForTarget(graph, targetContext = {}) {
|
|
|
9826
9896
|
});
|
|
9827
9897
|
}
|
|
9828
9898
|
const aliasEdges = aliasEdgeMap(graph);
|
|
9899
|
+
const compositionRules = collectCompositionRules(stagedNodes);
|
|
9829
9900
|
for (const staged of [...stagedNodes.values()].sort((a, b) => a.rawNode.node.id.localeCompare(b.rawNode.node.id))) {
|
|
9830
9901
|
const rawNode = staged.rawNode;
|
|
9831
9902
|
const expandedArtifacts = await expandMarkdownIncludes(staged.artifacts, staged.root, {
|
|
9832
9903
|
nodeId: rawNode.node.id,
|
|
9833
9904
|
originNodeId: rawNode.node.id,
|
|
9905
|
+
additionalComposeEntries: (artifact) => matchingCompositionEntries(
|
|
9906
|
+
artifact,
|
|
9907
|
+
rawNode.node.id,
|
|
9908
|
+
targetContext.adapter?.name,
|
|
9909
|
+
compositionRules
|
|
9910
|
+
),
|
|
9834
9911
|
resolveCrossPackageInclude: async (request) => {
|
|
9835
9912
|
const edge = aliasEdges.get(`${request.fromNodeId}\0${request.alias}`);
|
|
9836
9913
|
if (!edge) {
|
|
@@ -9908,6 +9985,50 @@ async function renderGraphForTarget(graph, targetContext = {}) {
|
|
|
9908
9985
|
graphLock: createGraphLock(graph, sortedArtifacts.map(lockArtifactFor), targetContext.targetFingerprint, [...includeEdges.values()], namespacing, overrides)
|
|
9909
9986
|
};
|
|
9910
9987
|
}
|
|
9988
|
+
function collectCompositionRules(stagedNodes) {
|
|
9989
|
+
const rules = [];
|
|
9990
|
+
for (const staged of stagedNodes.values()) {
|
|
9991
|
+
if (staged.rawNode.depth !== 0) continue;
|
|
9992
|
+
const manifest = staged.rawNode.manifest;
|
|
9993
|
+
if (!manifest || manifest.schemaVersion !== 3) continue;
|
|
9994
|
+
for (const rule of manifest.compositionRules ?? []) {
|
|
9995
|
+
rules.push({
|
|
9996
|
+
ownerNodeId: staged.rawNode.node.id,
|
|
9997
|
+
ownerPackageName: staged.rawNode.node.name,
|
|
9998
|
+
rule,
|
|
9999
|
+
packageRoot: staged.root,
|
|
10000
|
+
artifactPaths: staged.artifactPaths
|
|
10001
|
+
});
|
|
10002
|
+
}
|
|
10003
|
+
}
|
|
10004
|
+
return rules.sort((a, b) => `${a.ownerNodeId}\0${a.rule.target}\0${a.rule.include}`.localeCompare(`${b.ownerNodeId}\0${b.rule.target}\0${b.rule.include}`));
|
|
10005
|
+
}
|
|
10006
|
+
function matchingCompositionEntries(artifact, targetNodeId, runtime, rules) {
|
|
10007
|
+
const selector = `${artifact.type}/${artifact.name}`;
|
|
10008
|
+
const qualifiedSelector = `${artifact.packageName ?? targetNodeId}:${selector}`;
|
|
10009
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10010
|
+
const entries = [];
|
|
10011
|
+
for (const candidate of rules) {
|
|
10012
|
+
const { rule } = candidate;
|
|
10013
|
+
if (rule.runtimes?.length && (!runtime || !rule.runtimes.includes(runtime))) continue;
|
|
10014
|
+
if (!globMatches(rule.target, selector) && !globMatches(rule.target, qualifiedSelector)) continue;
|
|
10015
|
+
if (rule.exclude?.some((pattern) => globMatches(pattern, selector) || globMatches(pattern, qualifiedSelector))) continue;
|
|
10016
|
+
const key = `${candidate.ownerNodeId}\0${rule.include}`;
|
|
10017
|
+
if (seen.has(key)) continue;
|
|
10018
|
+
seen.add(key);
|
|
10019
|
+
entries.push({
|
|
10020
|
+
entry: { include: rule.include, markers: rule.markers },
|
|
10021
|
+
packageRoot: candidate.packageRoot,
|
|
10022
|
+
artifactPaths: candidate.artifactPaths,
|
|
10023
|
+
nodeId: candidate.ownerNodeId
|
|
10024
|
+
});
|
|
10025
|
+
}
|
|
10026
|
+
return entries;
|
|
10027
|
+
}
|
|
10028
|
+
function globMatches(pattern, value) {
|
|
10029
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replaceAll("*", ".*");
|
|
10030
|
+
return new RegExp(`^${escaped}$`).test(value);
|
|
10031
|
+
}
|
|
9911
10032
|
function aliasEdgeMap(graph) {
|
|
9912
10033
|
return new Map(graph.edges.map((edge) => [`${edge.from}\0${edge.alias}`, { to: edge.to }]));
|
|
9913
10034
|
}
|
|
@@ -9939,10 +10060,12 @@ function sha2563(content) {
|
|
|
9939
10060
|
return createHash10("sha256").update(content).digest("hex");
|
|
9940
10061
|
}
|
|
9941
10062
|
function assignInstallNames(graph, artifacts) {
|
|
10063
|
+
const superseded = supersededLogicalSelectors(artifacts);
|
|
10064
|
+
const effectiveArtifacts = artifacts.filter((artifact) => !superseded.has(artifact.logicalSelector));
|
|
9942
10065
|
const aliases = workspaceAliases(graph);
|
|
9943
|
-
validateAliasScopes(graph,
|
|
10066
|
+
validateAliasScopes(graph, effectiveArtifacts, aliases);
|
|
9944
10067
|
const decisions = /* @__PURE__ */ new Map();
|
|
9945
|
-
const withAliases =
|
|
10068
|
+
const withAliases = effectiveArtifacts.map((artifact) => {
|
|
9946
10069
|
const alias = aliasForArtifact(artifact, graph, aliases);
|
|
9947
10070
|
if (!alias) return artifact;
|
|
9948
10071
|
const updated = { ...artifact, installName: alias };
|
|
@@ -9981,6 +10104,23 @@ function assignInstallNames(graph, artifacts) {
|
|
|
9981
10104
|
}));
|
|
9982
10105
|
return { artifacts: out, namespacing: [...decisions.values()], overrides: finalOverrides };
|
|
9983
10106
|
}
|
|
10107
|
+
function supersededLogicalSelectors(artifacts) {
|
|
10108
|
+
const removed = /* @__PURE__ */ new Set();
|
|
10109
|
+
for (const replacement of artifacts) {
|
|
10110
|
+
for (const declaration of replacement.supersedes ?? []) {
|
|
10111
|
+
const replacementSelector = `${replacement.type}/${replacement.name}`;
|
|
10112
|
+
if (declaration.selector !== replacementSelector) {
|
|
10113
|
+
throw new Error(`Supersedes selector must match the replacement artifact ${replacement.logicalSelector}: ${declaration.selector}`);
|
|
10114
|
+
}
|
|
10115
|
+
const matches = artifacts.filter((candidate) => candidate !== replacement && candidate.packageName === declaration.package && `${candidate.type}/${candidate.name}` === declaration.selector);
|
|
10116
|
+
if (matches.length > 1) {
|
|
10117
|
+
throw new Error(`Supersedes target is ambiguous for ${replacement.logicalSelector}: ${declaration.package}:${declaration.selector}`);
|
|
10118
|
+
}
|
|
10119
|
+
if (matches[0]) removed.add(matches[0].logicalSelector);
|
|
10120
|
+
}
|
|
10121
|
+
}
|
|
10122
|
+
return removed;
|
|
10123
|
+
}
|
|
9984
10124
|
function applyWorkspaceOverrides(graph, artifacts) {
|
|
9985
10125
|
const directives = workspaceOverrides(graph);
|
|
9986
10126
|
if (directives.length === 0) return { artifacts, overrides: [] };
|
|
@@ -10180,7 +10320,8 @@ function lockArtifactFor(artifact) {
|
|
|
10180
10320
|
kind: artifact.kind,
|
|
10181
10321
|
hash: artifact.hash,
|
|
10182
10322
|
channel: artifact.channel ?? "managed",
|
|
10183
|
-
composedFrom: artifact.composedFrom
|
|
10323
|
+
composedFrom: artifact.composedFrom,
|
|
10324
|
+
supersedes: artifact.supersedes
|
|
10184
10325
|
};
|
|
10185
10326
|
}
|
|
10186
10327
|
|
|
@@ -11336,15 +11477,25 @@ async function validatePackage(root) {
|
|
|
11336
11477
|
} catch (error) {
|
|
11337
11478
|
findings.push({ level: "error", message: error instanceof Error ? error.message : String(error), path: packageRoot });
|
|
11338
11479
|
}
|
|
11339
|
-
if (manifest.schemaVersion
|
|
11480
|
+
if (manifest.schemaVersion !== 1 && manifest.compose) {
|
|
11340
11481
|
for (const entry of manifest.compose) {
|
|
11341
11482
|
await validateManifestComposeInclude(packageRoot, entry.include, entry.optional === true, findings, manifestPath, Object.keys(manifest.requires ?? {}));
|
|
11342
11483
|
}
|
|
11343
11484
|
}
|
|
11485
|
+
if (manifest.schemaVersion === 3) {
|
|
11486
|
+
const aliases = Object.keys(manifest.requires ?? {});
|
|
11487
|
+
for (const [index, rule] of (manifest.compositionRules ?? []).entries()) {
|
|
11488
|
+
validateSelector(rule.include, `compositionRules[${index}].include`, findings, manifestPath, { fragmentsOnly: true, aliases });
|
|
11489
|
+
if (!rule.target.startsWith("skills/")) {
|
|
11490
|
+
findings.push({ level: "error", message: `compositionRules[${index}].target: v3 composition rules may target only skills/*`, path: manifestPath });
|
|
11491
|
+
}
|
|
11492
|
+
await validateManifestComposeInclude(packageRoot, rule.include, false, findings, manifestPath, aliases);
|
|
11493
|
+
}
|
|
11494
|
+
}
|
|
11344
11495
|
return { ok: !findings.some((finding) => finding.level === "error"), manifestPath, findings };
|
|
11345
11496
|
}
|
|
11346
11497
|
function validateDeclaredSelectors(manifest, findings, manifestPath) {
|
|
11347
|
-
if (manifest.schemaVersion
|
|
11498
|
+
if (manifest.schemaVersion !== 1) {
|
|
11348
11499
|
for (const [alias, dependency] of Object.entries(manifest.requires ?? {})) {
|
|
11349
11500
|
if (!alias.trim()) {
|
|
11350
11501
|
findings.push({ level: "error", message: "Dependency alias must be non-empty", path: manifestPath });
|
|
@@ -11365,13 +11516,19 @@ function validateDeclaredSelectors(manifest, findings, manifestPath) {
|
|
|
11365
11516
|
for (const [provideIndex, provide] of manifest.provides.entries()) {
|
|
11366
11517
|
if (!("items" in provide) || !provide.items) continue;
|
|
11367
11518
|
for (const [itemName, item] of Object.entries(provide.items)) {
|
|
11519
|
+
for (const declaration of item.supersedes ?? []) {
|
|
11520
|
+
const expected = `${provide.type}/${itemName}`;
|
|
11521
|
+
if (declaration.selector !== expected) {
|
|
11522
|
+
findings.push({ level: "error", message: `provides[${provideIndex}].items.${itemName}.supersedes: selector must equal ${expected}`, path: manifestPath });
|
|
11523
|
+
}
|
|
11524
|
+
}
|
|
11368
11525
|
for (const requirement of item.requires ?? []) {
|
|
11369
11526
|
const selector = typeof requirement === "string" ? requirement : requirement.selector;
|
|
11370
|
-
validateSelector(selector, `provides[${provideIndex}].items.${itemName}.requires`, findings, manifestPath, { aliases: manifest.schemaVersion
|
|
11527
|
+
validateSelector(selector, `provides[${provideIndex}].items.${itemName}.requires`, findings, manifestPath, { aliases: manifest.schemaVersion !== 1 ? Object.keys(manifest.requires ?? {}) : [] });
|
|
11371
11528
|
}
|
|
11372
11529
|
for (const suggestion of item.suggests ?? []) {
|
|
11373
11530
|
const alias = typeof suggestion === "string" ? suggestion : suggestion.alias;
|
|
11374
|
-
if (manifest.schemaVersion
|
|
11531
|
+
if (manifest.schemaVersion !== 1 && !Object.keys(manifest.suggests ?? {}).includes(alias)) {
|
|
11375
11532
|
findings.push({ level: "error", message: `provides[${provideIndex}].items.${itemName}.suggests: suggestion alias not declared: ${alias}`, path: manifestPath });
|
|
11376
11533
|
}
|
|
11377
11534
|
for (const selector of typeof suggestion === "string" ? [] : suggestion.select ?? []) {
|
|
@@ -11380,7 +11537,7 @@ function validateDeclaredSelectors(manifest, findings, manifestPath) {
|
|
|
11380
11537
|
}
|
|
11381
11538
|
for (const entry of item.compose ?? []) {
|
|
11382
11539
|
validateSelector(entry.include, `provides[${provideIndex}].items.${itemName}.compose.include`, findings, manifestPath, {
|
|
11383
|
-
aliases: manifest.schemaVersion
|
|
11540
|
+
aliases: manifest.schemaVersion !== 1 ? Object.keys(manifest.requires ?? {}) : [],
|
|
11384
11541
|
fragmentsOnly: true
|
|
11385
11542
|
});
|
|
11386
11543
|
}
|
|
@@ -14364,9 +14521,7 @@ async function buildJournalManifestStates(plan, selected) {
|
|
|
14364
14521
|
const parsed = installManifestSchema.parse(before);
|
|
14365
14522
|
if (parsed.version !== 2) throw new Error(`Manifest changed to unsupported v1 state: ${path}`);
|
|
14366
14523
|
sourceByPath.set(path, { raw: before, manifest: { ...parsed, revision: computeManifestRevision(before), legacy: false } });
|
|
14367
|
-
const entries = parsed.entries.filter(
|
|
14368
|
-
(entry) => !(entryMatchesPackages(entry, selected) && renderedPaths.has(renderedEntryPath(parsed, entry)))
|
|
14369
|
-
);
|
|
14524
|
+
const entries = parsed.entries.filter((entry) => !renderedPaths.has(renderedEntryPath(parsed, entry)));
|
|
14370
14525
|
const removeEmptyLegacyManifest = isLegacySelfNormalizationPlan(plan) && entries.length === 0;
|
|
14371
14526
|
const afterManifest = removeEmptyLegacyManifest ? void 0 : withManifestRevision({ ...parsed, revision: computeManifestRevision(before), legacy: false, entries });
|
|
14372
14527
|
const after = afterManifest ? writableManifest(afterManifest) : null;
|
|
@@ -14384,7 +14539,7 @@ async function buildJournalManifestStates(plan, selected) {
|
|
|
14384
14539
|
if (source.manifest.revision !== transfer.sourceManifestRevision) {
|
|
14385
14540
|
throw new Error(`Source manifest changed after planning: ${transfer.sourceManifestPath}`);
|
|
14386
14541
|
}
|
|
14387
|
-
const desiredEntries = source.manifest.entries.filter((entry) =>
|
|
14542
|
+
const desiredEntries = source.manifest.entries.filter((entry) => transfer.renderedPaths.includes(renderedEntryPath(source.manifest, entry)) && !transfer.unmanagedSourceRenderedPaths.includes(renderedEntryPath(source.manifest, entry))).map((entry) => ({ ...entry, workspaceOwner: workspaceOwnerForRoot(plan.destination.root, plan.destination.fleetId) }));
|
|
14388
14543
|
const before = await readOptionalRecord(transfer.destinationManifestPath);
|
|
14389
14544
|
const parsedBefore = before ? installManifestSchema.parse(before) : void 0;
|
|
14390
14545
|
if (parsedBefore && parsedBefore.version !== 2) {
|
|
@@ -14415,7 +14570,9 @@ async function buildJournalManifestStates(plan, selected) {
|
|
|
14415
14570
|
const beforeRevision = before ? computeManifestRevision(before) : null;
|
|
14416
14571
|
const afterRevision = after ? computeManifestRevision(after) : null;
|
|
14417
14572
|
if (beforeRevision !== transfer.destinationManifestRevision || afterRevision !== transfer.destinationManifestAfterRevision) {
|
|
14418
|
-
throw new Error(
|
|
14573
|
+
throw new Error(
|
|
14574
|
+
`Destination manifest changed after planning: ${transfer.destinationManifestPath} (before ${beforeRevision ?? "absent"}, expected ${transfer.destinationManifestRevision ?? "absent"}; after ${afterRevision ?? "absent"}, expected ${transfer.destinationManifestAfterRevision ?? "absent"}).`
|
|
14575
|
+
);
|
|
14419
14576
|
}
|
|
14420
14577
|
if (transfer.sourceManifestPath === transfer.destinationManifestPath) {
|
|
14421
14578
|
const sourceState = states.find((candidate) => candidate.path === transfer.sourceManifestPath);
|
package/openpack.json
CHANGED
package/package.json
CHANGED