agentwheel 0.18.5 → 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 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 = 2;
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 packageManifestV2Schema = z6.object({
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
- }).superRefine((manifest, ctx) => {
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 packageManifestSchema = z6.union([packageManifestV1Schema, packageManifestV2Schema]);
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
- throw new Error(`Invalid package manifest ${path}: schemaVersion must be 1 or 2`);
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 === 2 ? manifest.runtimes : void 0;
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 result = await expandFile(file, packageRoot, composeEntriesForFile(artifact, file), artifactPaths, options);
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
- await expandFile(file, packageRoot, composeEntriesForFile(artifact, file), artifactPaths, options);
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 entry of appendEntries) {
7261
- const included = await expandInclude(entry.include, packageRoot, artifactPaths, {
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?.schemaVersion !== 2) return [];
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
- if (rawNode.node.selected.length === 0) continue;
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, artifacts, aliases);
10066
+ validateAliasScopes(graph, effectiveArtifacts, aliases);
9944
10067
  const decisions = /* @__PURE__ */ new Map();
9945
- const withAliases = artifacts.map((artifact) => {
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 === 2 && manifest.compose) {
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 === 2) {
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 === 2 ? Object.keys(manifest.requires ?? {}) : [] });
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 === 2 && !Object.keys(manifest.suggests ?? {}).includes(alias)) {
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 === 2 ? Object.keys(manifest.requires ?? {}) : [],
11540
+ aliases: manifest.schemaVersion !== 1 ? Object.keys(manifest.requires ?? {}) : [],
11384
11541
  fragmentsOnly: true
11385
11542
  });
11386
11543
  }
package/openpack.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "name": "NestDevLab/agentwheel",
4
- "version": "0.18.5",
4
+ "version": "0.19.0",
5
5
  "provides": [
6
6
  { "type": "skills", "path": "skills" }
7
7
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentwheel",
3
- "version": "0.18.5",
3
+ "version": "0.19.0",
4
4
  "description": "Weave skills, rules, and instructions across every AI agent.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -5,7 +5,7 @@ allowed-tools: [Bash]
5
5
  license: MIT
6
6
  metadata:
7
7
  author: NestDevLab
8
- version: "0.18.5"
8
+ version: "0.19.0"
9
9
  ---
10
10
 
11
11
  # agentwheel
@@ -5,7 +5,7 @@ allowed-tools: [Bash]
5
5
  license: MIT
6
6
  metadata:
7
7
  author: NestDevLab
8
- version: "0.18.5"
8
+ version: "0.19.0"
9
9
  ---
10
10
 
11
11
  # Agentwheel Discovery