agentwheel 0.21.2 → 0.21.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -98,6 +98,7 @@ Fragments are Agentwheel composition inputs, not runtime file-drop targets.
98
98
  |---|---|
99
99
  | `agentwheel search <query>` | Search configured registries and the public enriched/Vercel catalogue; supports stable JSON output for agent reranking. |
100
100
  | `agentwheel add <source>` | Validate and save a package entry in `.agentwheel/config.json`; does not touch runtimes. |
101
+ | `agentwheel pin <alias> <commit>` | Change an existing pinned alias's exact commit, preserving its configuration; does not resolve sources or touch runtimes. |
101
102
  | `agentwheel plan [name-or-source]` | Preview what `install` would reconcile without writing; supports `--profile <name>` and `--json`. |
102
103
  | `agentwheel install` | Reconcile configured packages into the current target or selected fleet. Uses the graph lock as input by default. |
103
104
  | `agentwheel install <name-or-source>` | Ensure semantics: configured name/source scopes the install; a new source is added and installed. |
@@ -583,6 +584,44 @@ agentwheel plan
583
584
  agentwheel install
584
585
  ```
585
586
 
587
+ Use `add --runtimes codex` to restrict a saved package to matching runtime adapters. The option
588
+ accepts comma-separated names and can be repeated. When replacing an existing package alias,
589
+ pass its runtime restrictions and selection again; `add` replaces the saved entry.
590
+
591
+ To change only an existing pinned alias's revision, use its exact configured name and a full
592
+ 40-hex commit SHA:
593
+
594
+ ```bash
595
+ agentwheel pin shared-pack 0123456789abcdef0123456789abcdef01234567 --fleet delivery --reason "Pin the reviewed source revision"
596
+ ```
597
+
598
+ `pin` preserves the source URL, driver, adapter, runtime restrictions, installation type (including
599
+ its absence), package order and other fields. It accepts the normal workspace selectors
600
+ `--fleet`, `--local`, `--user`, or `--target-root`, and uses the same mutation policy, durable
601
+ receipts and revision provider as other source mutations. Missing or duplicate aliases, tracking
602
+ packages and abbreviated or symbolic revisions are refused. No sources are fetched or rendered;
603
+ use the normal plan/dry-run before installing the new revision.
604
+
605
+ Omitting `--select` preserves the complete existing selection. Supplying repeatable or
606
+ comma-separated `--select type/name` replaces the complete selection, including any legacy
607
+ `skills` or imported `selection` field. An explicit empty selection is refused.
608
+
609
+ For one source mutation with several aliases, use `pin --pins-file reviewed-pins.json --fleet
610
+ delivery --reason "Pin the reviewed source set"`. The JSON file is a nonempty array of objects
611
+ containing only `alias`, `commit` and optional `select`:
612
+
613
+ ```json
614
+ [
615
+ { "alias": "shared-pack", "commit": "0123456789abcdef0123456789abcdef01234567" },
616
+ { "alias": "companion-pack", "commit": "abcdef0123456789abcdef0123456789abcdef01", "select": ["skills/companion"] }
617
+ ]
618
+ ```
619
+
620
+ The batch cannot be combined with positional pins or `--select`. Every entry is validated before
621
+ the config write; duplicate aliases and extra fields are refused. An omitted `select` preserves
622
+ that package's selection; an explicit list replaces only that package's complete selection. The
623
+ batch shares one durable receipt and revision-provider transaction.
624
+
586
625
  Package authors can mark artifacts as required. Required artifacts are always installed and cannot
587
626
  be deselected:
588
627
 
package/dist/index.js CHANGED
@@ -2805,6 +2805,62 @@ var init_semver = __esm({
2805
2805
  }
2806
2806
  });
2807
2807
 
2808
+ // src/model/selection.ts
2809
+ function artifactSelectorKey(artifact) {
2810
+ return `${artifact.type}/${artifact.name}`;
2811
+ }
2812
+ function artifactSelectorAliases(artifact) {
2813
+ const primary = artifactSelectorKey(artifact);
2814
+ if (artifact.type !== "subagents") return [primary];
2815
+ const baseName = subagentBaseName(artifact.name);
2816
+ if (baseName === artifact.name) return [primary];
2817
+ return [primary, `subagents/${baseName}`];
2818
+ }
2819
+ function normalizeArtifactSelectors(select, legacySkills) {
2820
+ const selected = [
2821
+ ...select ?? [],
2822
+ ...(legacySkills ?? []).map((name) => `skills/${name}`)
2823
+ ].flatMap(splitSelectorList);
2824
+ if (selected.length === 0) return void 0;
2825
+ return [...new Set(selected.map(parseArtifactSelector))];
2826
+ }
2827
+ function filterArtifactsBySelection(artifacts, selectors, legacySkills, options = {}) {
2828
+ const selected = normalizeArtifactSelectors(selectors, legacySkills);
2829
+ if (!selected?.length) return artifacts;
2830
+ const selectedSet = new Set(selected);
2831
+ const available = new Set((options.validationArtifacts ?? artifacts).flatMap(artifactSelectorAliases));
2832
+ const missing = selected.filter((selector) => !available.has(selector));
2833
+ if (missing.length > 0) {
2834
+ throw new Error(`Selected artifact not found in package: ${missing.join(", ")}`);
2835
+ }
2836
+ return artifacts.filter((artifact) => artifact.required || artifactSelectorAliases(artifact).some((selector) => selectedSet.has(selector)));
2837
+ }
2838
+ function splitSelectorList(value) {
2839
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
2840
+ }
2841
+ function parseArtifactSelector(value) {
2842
+ const slash = value.indexOf("/");
2843
+ if (slash <= 0 || slash === value.length - 1) {
2844
+ throw new Error(`Invalid artifact selector: ${value}. Expected <type>/<name>.`);
2845
+ }
2846
+ const type = value.slice(0, slash);
2847
+ const name = value.slice(slash + 1);
2848
+ const parsedType = artifactTypeSchema.safeParse(type);
2849
+ if (!parsedType.success) {
2850
+ throw new Error(`Invalid artifact selector type: ${type}`);
2851
+ }
2852
+ return `${parsedType.data}/${name}`;
2853
+ }
2854
+ function subagentBaseName(name) {
2855
+ return name.replace(/\.agent\.md$/i, "").replace(/\.toml$/i, "").replace(/\.md$/i, "");
2856
+ }
2857
+ var init_selection = __esm({
2858
+ "src/model/selection.ts"() {
2859
+ "use strict";
2860
+ init_artifact();
2861
+ }
2862
+ });
2863
+
2808
2864
  // src/model/workspace.ts
2809
2865
  import { readFile as readFile10 } from "fs/promises";
2810
2866
  import { homedir as homedir4 } from "os";
@@ -2829,6 +2885,43 @@ async function writeWorkspaceConfig(workspaceRoot, config) {
2829
2885
  declareMutationPath(path);
2830
2886
  await writeJsonAtomic(path, workspaceConfigSchema.parse(config));
2831
2887
  }
2888
+ async function pinConfiguredPackages(workspaceRoot, input) {
2889
+ const pins = z10.array(z10.object({
2890
+ alias: z10.string().min(1),
2891
+ commit: z10.string().regex(/^[a-f0-9]{40}$/i, "Pin requires an exact 40-hex commit SHA."),
2892
+ select: z10.array(z10.string().min(1)).min(1).optional()
2893
+ }).strict()).min(1).parse(input).map((pin) => {
2894
+ const select = pin.select === void 0 ? void 0 : normalizeArtifactSelectors(pin.select);
2895
+ if (pin.select !== void 0 && !select?.length) throw new Error("Explicit pin selection must not be empty.");
2896
+ return { ...pin, select };
2897
+ });
2898
+ if (new Set(pins.map((pin) => pin.alias)).size !== pins.length) {
2899
+ throw new Error("Pin requires unique configured aliases.");
2900
+ }
2901
+ const path = workspaceConfigPath(workspaceRoot);
2902
+ const config = JSON.parse(await readFile10(path, "utf8"));
2903
+ workspaceConfigSchema.parse(config);
2904
+ const updates = pins.map(({ alias, commit, select }) => {
2905
+ const matches = (config.packages ?? []).filter((pkg2) => pkg2.name === alias);
2906
+ if (matches.length !== 1) {
2907
+ throw new Error(matches.length === 0 ? `Configured package alias not found: ${alias}` : `Ambiguous configured package alias: ${alias}`);
2908
+ }
2909
+ const pkg = matches[0];
2910
+ if (pkg.mode === "tracking") throw new Error(`Configured package ${alias} is tracking; pin requires pinned mode.`);
2911
+ return { pkg, requestedRef: commit, select };
2912
+ });
2913
+ for (const { pkg, requestedRef, select } of updates) {
2914
+ pkg.requestedRef = requestedRef;
2915
+ if (select !== void 0) {
2916
+ pkg.select = select;
2917
+ delete pkg.skills;
2918
+ delete pkg.selection;
2919
+ }
2920
+ }
2921
+ workspaceConfigSchema.parse(config);
2922
+ declareMutationPath(path);
2923
+ await writeJsonAtomic(path, config);
2924
+ }
2832
2925
  function upsertPackage(config, entry) {
2833
2926
  const parsed = workspaceConfigSchema.parse(config);
2834
2927
  const packages = parsed.packages.filter((candidate) => candidate.name !== entry.name);
@@ -2920,6 +3013,7 @@ var init_workspace = __esm({
2920
3013
  init_mutation();
2921
3014
  init_declarations();
2922
3015
  init_adapters();
3016
+ init_selection();
2923
3017
  artifactSelectorListSchema = z10.array(z10.string().min(1));
2924
3018
  CURRENT_WORKSPACE_SCHEMA_VERSION = 4;
2925
3019
  workspaceSelectionImportSchema = z10.object({
@@ -6874,7 +6968,7 @@ var init_identify = __esm({
6874
6968
  // src/cli/index.ts
6875
6969
  import { createHash as createHash28 } from "crypto";
6876
6970
  import { existsSync } from "fs";
6877
- import { mkdir as mkdir27, mkdtemp as mkdtemp6, realpath as realpath4, rm as rm17, writeFile as writeFile24 } from "fs/promises";
6971
+ import { mkdir as mkdir27, mkdtemp as mkdtemp6, readFile as readFile45, realpath as realpath4, rm as rm17, writeFile as writeFile24 } from "fs/promises";
6878
6972
  import { homedir as homedir18, tmpdir as tmpdir7 } from "os";
6879
6973
  import { basename as basename24, dirname as dirname37, isAbsolute as isAbsolute14, join as join61, relative as relative19, resolve as resolve44 } from "path";
6880
6974
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -7505,59 +7599,7 @@ init_transport();
7505
7599
 
7506
7600
  // src/validation/adapter-targets.ts
7507
7601
  init_adapter();
7508
-
7509
- // src/model/selection.ts
7510
- init_artifact();
7511
- function artifactSelectorKey(artifact) {
7512
- return `${artifact.type}/${artifact.name}`;
7513
- }
7514
- function artifactSelectorAliases(artifact) {
7515
- const primary = artifactSelectorKey(artifact);
7516
- if (artifact.type !== "subagents") return [primary];
7517
- const baseName = subagentBaseName(artifact.name);
7518
- if (baseName === artifact.name) return [primary];
7519
- return [primary, `subagents/${baseName}`];
7520
- }
7521
- function normalizeArtifactSelectors(select, legacySkills) {
7522
- const selected = [
7523
- ...select ?? [],
7524
- ...(legacySkills ?? []).map((name) => `skills/${name}`)
7525
- ].flatMap(splitSelectorList);
7526
- if (selected.length === 0) return void 0;
7527
- return [...new Set(selected.map(parseArtifactSelector))];
7528
- }
7529
- function filterArtifactsBySelection(artifacts, selectors, legacySkills, options = {}) {
7530
- const selected = normalizeArtifactSelectors(selectors, legacySkills);
7531
- if (!selected?.length) return artifacts;
7532
- const selectedSet = new Set(selected);
7533
- const available = new Set((options.validationArtifacts ?? artifacts).flatMap(artifactSelectorAliases));
7534
- const missing = selected.filter((selector) => !available.has(selector));
7535
- if (missing.length > 0) {
7536
- throw new Error(`Selected artifact not found in package: ${missing.join(", ")}`);
7537
- }
7538
- return artifacts.filter((artifact) => artifact.required || artifactSelectorAliases(artifact).some((selector) => selectedSet.has(selector)));
7539
- }
7540
- function splitSelectorList(value) {
7541
- return value.split(",").map((item) => item.trim()).filter(Boolean);
7542
- }
7543
- function parseArtifactSelector(value) {
7544
- const slash = value.indexOf("/");
7545
- if (slash <= 0 || slash === value.length - 1) {
7546
- throw new Error(`Invalid artifact selector: ${value}. Expected <type>/<name>.`);
7547
- }
7548
- const type = value.slice(0, slash);
7549
- const name = value.slice(slash + 1);
7550
- const parsedType = artifactTypeSchema.safeParse(type);
7551
- if (!parsedType.success) {
7552
- throw new Error(`Invalid artifact selector type: ${type}`);
7553
- }
7554
- return `${parsedType.data}/${name}`;
7555
- }
7556
- function subagentBaseName(name) {
7557
- return name.replace(/\.agent\.md$/i, "").replace(/\.toml$/i, "").replace(/\.md$/i, "");
7558
- }
7559
-
7560
- // src/validation/adapter-targets.ts
7602
+ init_selection();
7561
7603
  function filterArtifactsByAdapterTargets(artifacts, adapter, installationType, options = {}) {
7562
7604
  const skipped = [];
7563
7605
  const installable = artifacts.filter((artifact) => {
@@ -7600,10 +7642,11 @@ function skipWarning(selector, adapter, installationType, artifactType, support)
7600
7642
 
7601
7643
  // src/validation/artifacts.ts
7602
7644
  init_adapter();
7645
+ init_selection();
7646
+ init_fs();
7603
7647
  import { readFile as readFile24 } from "fs/promises";
7604
7648
  import { basename as basename7, join as join23 } from "path";
7605
7649
  import { parseDocument as parseDocument2 } from "yaml";
7606
- init_fs();
7607
7650
  var behavioralRuleFormats = ["markdown-rule", "claude-markdown-rule", "copilot-instruction-rule"];
7608
7651
  var pluginFormats = ["claude-plugin", "codex-plugin", "hermes-plugin", "copilot-plugin", "openclaw-plugin", "openclaw-clawhub-plugin"];
7609
7652
  async function filterArtifactsByInstallFormat(artifacts, adapter, installationType, options = {}) {
@@ -12027,6 +12070,7 @@ function claudeAgentName(artifact) {
12027
12070
  }
12028
12071
 
12029
12072
  // src/staging/staging.ts
12073
+ init_selection();
12030
12074
  async function stageSource(driver, source, options = {}) {
12031
12075
  const raw = await stageSourceRaw(driver, source, options);
12032
12076
  return removeOnFailure(raw.root, () => renderStagedBundle(raw, options));
@@ -12232,13 +12276,15 @@ import { readdir as readdir12, readFile as readFile34, stat as stat14 } from "fs
12232
12276
  import { basename as basename20, extname as extname4, join as join41 } from "path";
12233
12277
  init_artifact();
12234
12278
  init_fs();
12279
+ init_selection();
12235
12280
 
12236
12281
  // src/model/workspace-composition.ts
12237
12282
  init_workspace();
12283
+ init_selection();
12284
+ init_fs();
12238
12285
  import { createHash as createHash16 } from "crypto";
12239
12286
  import { readFile as readFile32 } from "fs/promises";
12240
12287
  import { z as z12 } from "zod";
12241
- init_fs();
12242
12288
  var selectionSourceConfigSchema = z12.object({
12243
12289
  schemaVersion: z12.literal(2),
12244
12290
  exports: workspaceExportsSchema
@@ -12397,6 +12443,7 @@ var registryCacheSchema = z13.object({
12397
12443
  });
12398
12444
 
12399
12445
  // src/registry/client.ts
12446
+ init_selection();
12400
12447
  init_workspace();
12401
12448
  init_fs();
12402
12449
  var DEFAULT_REGISTRY_SOURCE = "github:NestDevLab/agentwheel-registry";
@@ -13924,6 +13971,7 @@ function formatSelectionImport(root) {
13924
13971
  }
13925
13972
 
13926
13973
  // src/resolve/render.ts
13974
+ init_selection();
13927
13975
  import { createHash as createHash18 } from "crypto";
13928
13976
  import { readFile as readFile35, mkdtemp as mkdtemp5 } from "fs/promises";
13929
13977
  import { tmpdir as tmpdir6 } from "os";
@@ -14528,6 +14576,7 @@ function defaultTrustStorePath() {
14528
14576
 
14529
14577
  // src/lifecycle/source-plan.ts
14530
14578
  init_workspace();
14579
+ init_selection();
14531
14580
 
14532
14581
  // src/model/workspace-owner.ts
14533
14582
  import { Buffer as Buffer2 } from "buffer";
@@ -15998,6 +16047,7 @@ function runtimeScanRoot(request) {
15998
16047
  // src/lifecycle/profile.ts
15999
16048
  init_identify();
16000
16049
  init_transport();
16050
+ init_selection();
16001
16051
  init_declarations();
16002
16052
  async function syncProfile(options) {
16003
16053
  const config = await readMergedWorkspaceConfig(options.workspaceRoot);
@@ -16155,6 +16205,7 @@ function combinedSuggestionAliases(packageAliases, optionAliases) {
16155
16205
  }
16156
16206
 
16157
16207
  // src/registry/publish.ts
16208
+ init_selection();
16158
16209
  var DEFAULT_REGISTRY_SUBMISSION_URL = "https://github.com/NestDevLab/agentwheel-registry/issues/new";
16159
16210
  var registryEntryTypes = ["package", "skill", "plugin", "mcp", "adapter"];
16160
16211
  var explicitSourcePrefixes = ["github:", "git:", "skillkit:", "vercel:", "mcp-registry:", "clawhub:"];
@@ -16318,6 +16369,9 @@ function shellQuoteArg(value) {
16318
16369
  return `'${value.replaceAll("'", `'"'"'`)}'`;
16319
16370
  }
16320
16371
 
16372
+ // src/cli/index.ts
16373
+ init_selection();
16374
+
16321
16375
  // src/cli/update-check.ts
16322
16376
  import { mkdir as mkdir26, readFile as readFile38, writeFile as writeFile22 } from "fs/promises";
16323
16377
  import { homedir as homedir14 } from "os";
@@ -16818,6 +16872,7 @@ init_manifest2();
16818
16872
  init_apply();
16819
16873
  init_paths();
16820
16874
  init_transaction();
16875
+ init_selection();
16821
16876
  import { createHash as createHash20 } from "crypto";
16822
16877
  import { resolve as resolve37 } from "path";
16823
16878
  init_declarations();
@@ -19479,6 +19534,7 @@ function ensureTrailingSlash(value) {
19479
19534
  }
19480
19535
 
19481
19536
  // src/trial/skill.ts
19537
+ init_selection();
19482
19538
  import { createHash as createHash26 } from "crypto";
19483
19539
  import { readFile as readFile43, stat as stat16 } from "fs/promises";
19484
19540
  import { join as join59 } from "path";
@@ -21129,6 +21185,7 @@ var commandGovernance = {
21129
21185
  "fleet normalize": "governed-apply-or-recover",
21130
21186
  "cache prune": "governed-apply",
21131
21187
  add: "governed-always",
21188
+ pin: "governed-always",
21132
21189
  list: "incidental-cache",
21133
21190
  search: "incidental-cache",
21134
21191
  try: "incidental-cache",
@@ -21185,6 +21242,7 @@ function requiresCleanMutationPreflight(path) {
21185
21242
  "init",
21186
21243
  "fleet register",
21187
21244
  "add",
21245
+ "pin",
21188
21246
  "package migrate",
21189
21247
  "remember",
21190
21248
  "journal abort"
@@ -21264,13 +21322,22 @@ cacheCommand.command("prune").description("remove old Git source snapshots while
21264
21322
  for (const path of result.removedPaths) console.log(`${verb} ${path}`);
21265
21323
  console.log(`${options.apply ? "Pruned" : "Preview"}: ${result.removedPaths.length} snapshots; retained ${result.retainedPaths.length}.`);
21266
21324
  });
21267
- program.command("add").description("add a package to .agentwheel/config.json without touching runtimes").argument("<source>", "package source").option("--driver <driver>", "source driver (local, git, skillkit, vercel-skills, mcp-registry, or clawhub)").option("--adapter <adapter>", "built-in adapter", "openclaw").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "use the user workspace", false).option("--local", "use the nearest local workspace", false).option("--fleet <id>", "use one registered named fleet").option("--adapter-config <path>", "adapter JSON/JSONC file").option("--adapter-module <path>", "local programmatic adapter module").option("--allow-adapter-code", "allow loading local adapter code", false).option("-t, --target-root <path>", "workspace root").option("--mode <mode>", "pinned or tracking", "pinned").option("--version <range>", "root package version policy (exact, ~, ^, or *)").option("--name <name>", "package alias").option("--select <type/name>", "select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "select a skill by name (repeatable or comma-separated)", collectSkillOption, []).option("--with-suggestions", "include suggested companion artifacts for selected roots on future installs", false).option("--suggestion <alias>", "include one suggested companion alias on future installs (repeatable or comma-separated)", collectSuggestionOption, []).option("--override <source-or-package::type/name>", "allow this package to replace a colliding artifact (repeatable)", collectOverrideOption, []).action(async (source, options) => {
21325
+ program.command("add").description("add a package to .agentwheel/config.json without touching runtimes").argument("<source>", "package source").option("--driver <driver>", "source driver (local, git, skillkit, vercel-skills, mcp-registry, or clawhub)").option("--adapter <adapter>", "built-in adapter", "openclaw").option("--runtimes <adapters>", "restrict package runtimes (repeatable or comma-separated)", collectSelectOption, []).option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "use the user workspace", false).option("--local", "use the nearest local workspace", false).option("--fleet <id>", "use one registered named fleet").option("--adapter-config <path>", "adapter JSON/JSONC file").option("--adapter-module <path>", "local programmatic adapter module").option("--allow-adapter-code", "allow loading local adapter code", false).option("-t, --target-root <path>", "workspace root").option("--mode <mode>", "pinned or tracking", "pinned").option("--version <range>", "root package version policy (exact, ~, ^, or *)").option("--name <name>", "package alias").option("--select <type/name>", "select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "select a skill by name (repeatable or comma-separated)", collectSkillOption, []).option("--with-suggestions", "include suggested companion artifacts for selected roots on future installs", false).option("--suggestion <alias>", "include one suggested companion alias on future installs (repeatable or comma-separated)", collectSuggestionOption, []).option("--override <source-or-package::type/name>", "allow this package to replace a colliding artifact (repeatable)", collectOverrideOption, []).action(async (source, options) => {
21268
21326
  const normalizedOptions = normalizeRuntimeScopeOptions(options);
21269
21327
  const targetRoot = await workspaceRootFromOptions(normalizedOptions);
21270
21328
  const entry = await packageEntryFromSource(source, targetRoot, normalizedOptions);
21271
21329
  await writeWorkspaceConfig(targetRoot, upsertPackage(await readWorkspaceConfig(targetRoot), entry));
21272
21330
  console.log(`Added ${entry.name}. Preview: agentwheel plan - Apply: agentwheel install`);
21273
21331
  });
21332
+ program.command("pin").description("pin configured package aliases without resolving sources or touching runtimes").argument("[alias]", "exact configured package alias").argument("[commit]", "exact 40-hex commit SHA").option("--user", "use the user workspace", false).option("--local", "use the nearest local workspace", false).option("--fleet <id>", "use one registered named fleet").option("-t, --target-root <path>", "explicit workspace root").option("--pins-file <path>", "JSON array of {alias, commit, select?} pins in one mutation").option("--select <type/name>", "replace the complete selection (repeatable or comma-separated)", collectSelectOption).action(async (alias, commit, options) => {
21333
+ const workspaceRoot = await workspaceRootFromOptions(normalizeRuntimeScopeOptions(options));
21334
+ if (options.pinsFile ? alias !== void 0 || commit !== void 0 || options.select !== void 0 : !alias || !commit) {
21335
+ throw new Error("Choose pin <alias> <commit> [--select ...] or pin --pins-file <path>, exclusively.");
21336
+ }
21337
+ const pins = options.pinsFile ? JSON.parse(await readFile45(resolve44(options.pinsFile), "utf8")) : [{ alias, commit, ...options.select === void 0 ? {} : { select: options.select } }];
21338
+ await pinConfiguredPackages(workspaceRoot, pins);
21339
+ console.log("Pinned configured package revisions. Preview: agentwheel plan - Apply: agentwheel install");
21340
+ });
21274
21341
  program.command("list").description("list artifacts exposed by a package source").argument("<source>", "package source").option("--driver <driver>", "source driver").option("--user", "use the user workspace", false).option("--local", "use the nearest local workspace", false).option("--fleet <id>", "use one registered named fleet").option("-t, --target-root <path>", "explicit workspace root").option("--select <type/name>", "select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "select a skill by name (repeatable or comma-separated)", collectSkillOption, []).action(async (source, options) => {
21275
21342
  const targetRoot = await workspaceContextRootFromOptions(normalizeRuntimeScopeOptions(options));
21276
21343
  const resolvedInput = await resolvePackageSource(source, targetRoot);
@@ -22365,6 +22432,7 @@ async function packageEntryFromSource(source, targetRoot, options) {
22365
22432
  source: resolvedSource,
22366
22433
  driver: driverName,
22367
22434
  adapter: adapter.name,
22435
+ runtimes: options.runtimes?.length ? options.runtimes : void 0,
22368
22436
  installationType,
22369
22437
  adapterConfig: options.adapterConfig,
22370
22438
  adapterModule: options.adapterModule,
@@ -24401,7 +24469,7 @@ function shellQuoteArg2(value) {
24401
24469
  if (/^[A-Za-z0-9_./:@=-]+$/.test(value)) return value;
24402
24470
  return `'${value.replaceAll("'", `'"'"'`)}'`;
24403
24471
  }
24404
- function collectSelectOption(value, previous) {
24472
+ function collectSelectOption(value, previous = []) {
24405
24473
  return [...previous, ...splitSelectorList(value)];
24406
24474
  }
24407
24475
  function parsePositiveInteger(value) {
@@ -24808,7 +24876,7 @@ async function governedCommandContext(command, options) {
24808
24876
  const contextOnly = path === "cache prune";
24809
24877
  const workspaceRoot = contextOnly ? await workspaceContextRootFromOptions(normalized) : await workspaceRootFromOptions(normalized);
24810
24878
  const anticipatedPaths = [];
24811
- if (path === "add") anticipatedPaths.push(workspaceConfigPath(workspaceRoot));
24879
+ if (path === "add" || path === "pin") anticipatedPaths.push(workspaceConfigPath(workspaceRoot));
24812
24880
  if (path === "remember" && options.runtime) {
24813
24881
  anticipatedPaths.push(join61(workspaceRoot, ".agentwheel", "overlays", options.runtime, "instructions.local.md"));
24814
24882
  }
package/openpack.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "name": "NestDevLab/agentwheel",
4
- "version": "0.21.2",
4
+ "version": "0.21.3",
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.21.2",
3
+ "version": "0.21.3",
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.21.2"
8
+ version: "0.21.3"
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.21.2"
8
+ version: "0.21.3"
9
9
  ---
10
10
 
11
11
  # Agentwheel Discovery