agentwheel 0.21.0 → 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/dist/index.js CHANGED
@@ -522,13 +522,13 @@ async function hashPath(path) {
522
522
  if (!stats.isDirectory()) {
523
523
  throw new Error(`Unsupported path kind: ${path}`);
524
524
  }
525
- const hash = createHash("sha256").update("dir\0");
525
+ const hash2 = createHash("sha256").update("dir\0");
526
526
  const files = await listFiles(path);
527
527
  for (const file of files) {
528
- hash.update(relative(path, file).replaceAll("\\", "/")).update("\0");
529
- hash.update(await hashPath(file)).update("\0");
528
+ hash2.update(relative(path, file).replaceAll("\\", "/")).update("\0");
529
+ hash2.update(await hashPath(file)).update("\0");
530
530
  }
531
- return hash.digest("hex");
531
+ return hash2.digest("hex");
532
532
  }
533
533
  async function listFiles(root) {
534
534
  const out = [];
@@ -583,7 +583,7 @@ async function withFilesystemLock(lockPath, timeoutMs, fn, description = "cache"
583
583
  if (Date.now() - started > timeoutMs) {
584
584
  throw new Error(`Timed out waiting for ${description} lock at ${lockPath}`);
585
585
  }
586
- await new Promise((resolve44) => setTimeout(resolve44, 50));
586
+ await new Promise((resolve45) => setTimeout(resolve45, 50));
587
587
  }
588
588
  }
589
589
  try {
@@ -853,7 +853,7 @@ var init_protocol = __esm({
853
853
  // src/mutation/process.ts
854
854
  import { spawn } from "child_process";
855
855
  async function runProcess(command, args, options = {}) {
856
- return new Promise((resolve44, reject) => {
856
+ return new Promise((resolve45, reject) => {
857
857
  const useProcessGroup = options.killProcessGroup === true && process.platform !== "win32";
858
858
  const child = spawn(command, args, {
859
859
  cwd: options.cwd,
@@ -913,7 +913,7 @@ async function runProcess(command, args, options = {}) {
913
913
  reject(new Error(`${command} exited ${exitCode}${detail ? `: ${detail}` : ""}`));
914
914
  return;
915
915
  }
916
- resolve44(result);
916
+ resolve45(result);
917
917
  });
918
918
  if (options.input !== void 0) child.stdin.end(options.input);
919
919
  else child.stdin.end();
@@ -939,8 +939,8 @@ function agentMeshGraphPath() {
939
939
  function agentwheelResourceRef(gitCommonDir, repositoryRelativePath) {
940
940
  const commonDir = resolve5(gitCommonDir);
941
941
  const normalizedPath = normalizeRepositoryRelativePath(repositoryRelativePath);
942
- const digest2 = createHash3("sha256").update(commonDir).update("\0").update(normalizedPath).digest("hex");
943
- return `agentwheel-resource:${digest2}`;
942
+ const digest3 = createHash3("sha256").update(commonDir).update("\0").update(normalizedPath).digest("hex");
943
+ return `agentwheel-resource:${digest3}`;
944
944
  }
945
945
  async function resourceRefsForRepositoryPaths(repositoryRoot, paths) {
946
946
  const result = await runProcess("git", [
@@ -1213,8 +1213,8 @@ async function listMutationReceipts() {
1213
1213
  }
1214
1214
  async function acquireMutationLock(repositoryRoot, operationId) {
1215
1215
  const root = mutationStateRoot();
1216
- const digest2 = createHash4("sha256").update(resolve6(repositoryRoot)).digest("hex");
1217
- const lockPath = join4(root, "locks", `${digest2}.lock`);
1216
+ const digest3 = createHash4("sha256").update(resolve6(repositoryRoot)).digest("hex");
1217
+ const lockPath = join4(root, "locks", `${digest3}.lock`);
1218
1218
  await mkdir2(join4(root, "locks"), { recursive: true, mode: 448 });
1219
1219
  await chmod(join4(root, "locks"), 448);
1220
1220
  try {
@@ -1961,13 +1961,13 @@ async function spawnWithInput(command, args, input) {
1961
1961
  if (result.stderr) throw new Error(result.stderr);
1962
1962
  }
1963
1963
  function waitForProcess(child, label) {
1964
- return new Promise((resolve44, reject) => {
1964
+ return new Promise((resolve45, reject) => {
1965
1965
  const stderr = [];
1966
1966
  child.stderr?.on("data", (chunk) => stderr.push(chunk));
1967
1967
  child.on("error", reject);
1968
1968
  child.on("close", (code) => {
1969
1969
  const message = Buffer.concat(stderr).toString("utf8");
1970
- if (code === 0) resolve44({ stderr: "" });
1970
+ if (code === 0) resolve45({ stderr: "" });
1971
1971
  else reject(new Error(`${label} exited ${code}${message ? `: ${message}` : ""}`));
1972
1972
  });
1973
1973
  });
@@ -2582,7 +2582,7 @@ async function listInstallManifests(targetRoot, adapter, transport = localTransp
2582
2582
  try {
2583
2583
  const raw = JSON.parse(await transport.readFile(path));
2584
2584
  const parsed = installManifestSchema.parse(raw);
2585
- if (parsed.adapter !== adapter) continue;
2585
+ if (adapter !== void 0 && parsed.adapter !== adapter) continue;
2586
2586
  found.push({ path, fileName, stateKey, manifest: { ...parsed, revision: computeManifestRevision(raw) } });
2587
2587
  } catch (error) {
2588
2588
  throw new Error(`Unreadable install manifest at ${path}: ${error instanceof Error ? error.message : String(error)}`);
@@ -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({
@@ -3236,15 +3330,15 @@ async function snapshotRepository(repositoryRoot) {
3236
3330
  async function collectIntroducedPaths(repositoryRoot, expectedHead, before, declaredPaths) {
3237
3331
  const after = await snapshotRepository(repositoryRoot);
3238
3332
  const touchedPreexisting = /* @__PURE__ */ new Set();
3239
- for (const [path, hash] of before.changed) {
3333
+ for (const [path, hash2] of before.changed) {
3240
3334
  if (declaredPaths.includes(path)) touchedPreexisting.add(path);
3241
3335
  else if (!after.changed.has(path)) {
3242
3336
  const head = await currentHead(repositoryRoot);
3243
3337
  const ancestor = await runProcess("git", ["-C", repositoryRoot, "merge-base", "--is-ancestor", expectedHead, head], {
3244
3338
  allowExitCodes: [0, 1]
3245
3339
  });
3246
- if (head === expectedHead || ancestor.exitCode !== 0 || await hashWorkingPath(repositoryRoot, path) !== hash || await hashHeadPath(repositoryRoot, head, path) !== hash) touchedPreexisting.add(path);
3247
- } else if (after.changed.get(path) !== hash) touchedPreexisting.add(path);
3340
+ if (head === expectedHead || ancestor.exitCode !== 0 || await hashWorkingPath(repositoryRoot, path) !== hash2 || await hashHeadPath(repositoryRoot, head, path) !== hash2) touchedPreexisting.add(path);
3341
+ } else if (after.changed.get(path) !== hash2) touchedPreexisting.add(path);
3248
3342
  }
3249
3343
  if (touchedPreexisting.size > 0) {
3250
3344
  throw new Error(`Mutation touched pre-existing dirty paths: ${[...touchedPreexisting].sort().join(", ")}.`);
@@ -3310,19 +3404,19 @@ async function hashWorkingPath(repositoryRoot, path) {
3310
3404
  throw new Error(`Unsupported repository path kind: ${path}`);
3311
3405
  }
3312
3406
  async function hashDirectory(root) {
3313
- const hash = createHash7("sha256");
3407
+ const hash2 = createHash7("sha256");
3314
3408
  async function walk2(dir) {
3315
3409
  for (const entry of (await readdir4(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
3316
3410
  if (entry.name === ".git" || entry.name === "node_modules") continue;
3317
3411
  const absolute = resolve12(dir, entry.name);
3318
3412
  const relativePath = normalizeRepoPath(relative5(root, absolute));
3319
3413
  if (entry.isDirectory()) await walk2(absolute);
3320
- else if (entry.isSymbolicLink()) hash.update(relativePath).update("\0").update(await readlink(absolute)).update("\0");
3321
- else if (entry.isFile()) hash.update(relativePath).update("\0").update(await readFile11(absolute)).update("\0");
3414
+ else if (entry.isSymbolicLink()) hash2.update(relativePath).update("\0").update(await readlink(absolute)).update("\0");
3415
+ else if (entry.isFile()) hash2.update(relativePath).update("\0").update(await readFile11(absolute)).update("\0");
3322
3416
  }
3323
3417
  }
3324
3418
  await walk2(root);
3325
- return hash.digest("hex");
3419
+ return hash2.digest("hex");
3326
3420
  }
3327
3421
  function splitNull(value) {
3328
3422
  return value.toString("utf8").split("\0").filter(Boolean);
@@ -3938,11 +4032,11 @@ function dirtyRepositoryPaths(repositoryRoot, baseline, paths) {
3938
4032
  function activeMutationMetadata() {
3939
4033
  return activeMutation?.metadata();
3940
4034
  }
3941
- async function reserveActiveRuntimeJournal(link2) {
3942
- await activeMutation?.transitionRuntimeJournal(link2, "reserved");
4035
+ async function reserveActiveRuntimeJournal(link3) {
4036
+ await activeMutation?.transitionRuntimeJournal(link3, "reserved");
3943
4037
  }
3944
- async function activateActiveRuntimeJournal(link2) {
3945
- await activeMutation?.transitionRuntimeJournal(link2, "pending");
4038
+ async function activateActiveRuntimeJournal(link3) {
4039
+ await activeMutation?.transitionRuntimeJournal(link3, "pending");
3946
4040
  }
3947
4041
  async function beginResolveMutationRuntimeJournal(operationId, path) {
3948
4042
  await transitionMutationRuntimeJournal(operationId, path, "resolving");
@@ -4208,14 +4302,14 @@ function receiptStatusForProvider(status) {
4208
4302
  if (status === "no-repository-delta") return "no-repository-delta";
4209
4303
  return "succeeded";
4210
4304
  }
4211
- function upsertRuntimeJournal(entries, link2, status) {
4212
- const existing = entries.find((entry) => entry.path === link2.path);
4213
- if (existing && (existing.transport !== link2.transport || existing.transportDescription !== link2.transportDescription || existing.journalDigest !== link2.journalDigest)) {
4214
- throw new Error(`Runtime journal link collision for ${link2.path}.`);
4305
+ function upsertRuntimeJournal(entries, link3, status) {
4306
+ const existing = entries.find((entry) => entry.path === link3.path);
4307
+ if (existing && (existing.transport !== link3.transport || existing.transportDescription !== link3.transportDescription || existing.journalDigest !== link3.journalDigest)) {
4308
+ throw new Error(`Runtime journal link collision for ${link3.path}.`);
4215
4309
  }
4216
4310
  return [
4217
- ...entries.filter((entry) => entry.path !== link2.path),
4218
- { ...link2, status }
4311
+ ...entries.filter((entry) => entry.path !== link3.path),
4312
+ { ...link3, status }
4219
4313
  ].sort((a, b) => a.path.localeCompare(b.path));
4220
4314
  }
4221
4315
  var GovernedMutation, activeMutation;
@@ -4416,11 +4510,12 @@ var init_coordinator = __esm({
4416
4510
  operationId: this.receipt.operationId,
4417
4511
  reason: this.receipt.reason,
4418
4512
  noCommit: this.receipt.noCommit,
4419
- revisionMode: this.receipt.revisionMode
4513
+ revisionMode: this.receipt.revisionMode,
4514
+ workspaceRoot: this.receipt.workspaceRoot
4420
4515
  };
4421
4516
  }
4422
- async transitionRuntimeJournal(link2, status) {
4423
- const runtimeJournals = upsertRuntimeJournal(this.receipt.runtimeJournals, link2, status);
4517
+ async transitionRuntimeJournal(link3, status) {
4518
+ const runtimeJournals = upsertRuntimeJournal(this.receipt.runtimeJournals, link3, status);
4424
4519
  this.receipt = await updateMutationReceipt(this.receipt, { runtimeJournals });
4425
4520
  }
4426
4521
  async transitionExistingRuntimeJournal(path, status) {
@@ -4488,20 +4583,88 @@ __export(transaction_exports, {
4488
4583
  applyLockPath: () => applyLockPath,
4489
4584
  assertApplyJournalRecoveryAllowed: () => assertApplyJournalRecoveryAllowed,
4490
4585
  assertGovernedRuntimeTransportSupported: () => assertGovernedRuntimeTransportSupported,
4586
+ assertNoSymlinkPath: () => assertNoSymlinkPath,
4491
4587
  listAllApplyJournals: () => listAllApplyJournals,
4492
4588
  listApplyJournals: () => listApplyJournals,
4493
4589
  localPathExists: () => localPathExists,
4590
+ metadataAuditPath: () => metadataAuditPath,
4591
+ metadataRuntimePath: () => metadataRuntimePath,
4494
4592
  mutationMetadataForApplyJournal: () => mutationMetadataForApplyJournal,
4593
+ ownershipRuntimeSnapshot: () => ownershipRuntimeSnapshot,
4495
4594
  readApplyJournal: () => readApplyJournal,
4496
4595
  readLinkedLocalApplyJournal: () => readLinkedLocalApplyJournal,
4497
4596
  recordBackup: () => recordBackup,
4498
4597
  removeApplyJournal: () => removeApplyJournal,
4499
4598
  rollbackCompletedOperations: () => rollbackCompletedOperations,
4599
+ syncMetadataPath: () => syncMetadataPath,
4500
4600
  writeApplyJournal: () => writeApplyJournal
4501
4601
  });
4502
4602
  import { createHash as createHash9 } from "crypto";
4503
- import { cp as cp2, mkdir as mkdir7, readFile as readFile13, rm as rm5, stat as stat4 } from "fs/promises";
4504
- import { dirname as dirname9, join as join11, resolve as resolve15 } from "path";
4603
+ import { cp as cp2, lstat as lstat2, mkdir as mkdir7, open as open3, readFile as readFile13, readdir as readdir5, rm as rm5, stat as stat4 } from "fs/promises";
4604
+ import { dirname as dirname9, join as join11, relative as relative7, resolve as resolve15, sep as sep5 } from "path";
4605
+ async function assertNoSymlinkPath(path) {
4606
+ const absolute = resolve15(path);
4607
+ let current = absolute;
4608
+ while (true) {
4609
+ try {
4610
+ if ((await lstat2(current)).isSymbolicLink()) throw new Error(`Symlink path is unsupported: ${current}`);
4611
+ } catch (error) {
4612
+ if (error.code !== "ENOENT") throw error;
4613
+ }
4614
+ const parent = dirname9(current);
4615
+ if (parent === current) break;
4616
+ current = parent;
4617
+ }
4618
+ }
4619
+ async function ownershipRuntimeSnapshot(path) {
4620
+ await assertNoSymlinkPath(path);
4621
+ const hash2 = createHash9("sha256");
4622
+ async function visit(candidate) {
4623
+ const info = await lstat2(candidate);
4624
+ if (info.isSymbolicLink() || !info.isDirectory() && !info.isFile()) {
4625
+ throw new Error(`Unsupported ownership runtime path: ${candidate}`);
4626
+ }
4627
+ hash2.update(JSON.stringify([relative7(path, candidate), info.isDirectory() ? "dir" : "file", info.mode & 4095]));
4628
+ if (info.isDirectory()) {
4629
+ for (const name of (await readdir5(candidate)).sort()) await visit(join11(candidate, name));
4630
+ } else {
4631
+ const content = await readFile13(candidate);
4632
+ hash2.update(String(content.length)).update("\0").update(content);
4633
+ }
4634
+ }
4635
+ await visit(path);
4636
+ return hash2.digest("hex");
4637
+ }
4638
+ function metadataAuditPath(audit, path) {
4639
+ mutationOperationIdSchema.parse(audit.operationId);
4640
+ if (resolve15(audit.workspaceRoot) !== audit.workspaceRoot || path !== `.agentwheel/ownership-releases/${audit.operationId}.json`) {
4641
+ throw new Error("Invalid ownership release audit path.");
4642
+ }
4643
+ return join11(audit.workspaceRoot, ...path.split("/"));
4644
+ }
4645
+ function metadataRuntimePath(root, path) {
4646
+ const result = resolve15(root, path);
4647
+ if (!path || relative7(resolve15(root), result).split(sep5).join("/") !== path || path === ".agentwheel" || path.startsWith(".agentwheel/") || result === resolve15(root) || !result.startsWith(`${resolve15(root)}${sep5}`)) {
4648
+ throw new Error(`Unsafe ownership release path: ${path}`);
4649
+ }
4650
+ return result;
4651
+ }
4652
+ async function syncMetadataPath(path, directoryOnly = false) {
4653
+ if (!directoryOnly) {
4654
+ const file = await open3(path, "r");
4655
+ try {
4656
+ await file.sync();
4657
+ } finally {
4658
+ await file.close();
4659
+ }
4660
+ }
4661
+ const directory = await open3(directoryOnly ? path : dirname9(path), "r");
4662
+ try {
4663
+ await directory.sync();
4664
+ } finally {
4665
+ await directory.close();
4666
+ }
4667
+ }
4505
4668
  function applyLockPath(targetRoot, adapter, scope = {}) {
4506
4669
  const installationType = scope.installationType ?? "local";
4507
4670
  return join11(metadataDir(targetRoot), `${stateKeyFor(adapter, { installationType })}.runtime-apply-lock`);
@@ -4543,30 +4706,31 @@ async function writeApplyJournal(journal, transport = localTransport) {
4543
4706
  installationType: journal.installationType,
4544
4707
  stateKey: journal.stateKey
4545
4708
  });
4546
- let link2;
4709
+ let link3;
4547
4710
  if (journal.mutation) {
4548
- const digest2 = applyJournalLinkDigest(journal, transport);
4549
- if (journal.mutation.journalDigest && journal.mutation.journalDigest !== digest2) {
4711
+ const digest3 = applyJournalLinkDigest(journal, transport);
4712
+ if (journal.mutation.journalDigest && journal.mutation.journalDigest !== digest3) {
4550
4713
  throw new Error(`Runtime apply journal identity changed for ${path}.`);
4551
4714
  }
4552
4715
  if (journal.mutation.transport && (journal.mutation.transport.kind !== transport.kind || journal.mutation.transport.description !== transport.description)) {
4553
4716
  throw new Error(`Runtime apply journal transport changed for ${path}.`);
4554
4717
  }
4555
- journal.mutation.journalDigest = digest2;
4718
+ journal.mutation.journalDigest = digest3;
4556
4719
  journal.mutation.transport = { kind: transport.kind, description: transport.description };
4557
- link2 = {
4720
+ link3 = {
4558
4721
  path,
4559
4722
  transport: transport.kind,
4560
4723
  transportDescription: transport.description,
4561
- journalDigest: digest2
4724
+ journalDigest: digest3
4562
4725
  };
4563
- await reserveActiveRuntimeJournal(link2);
4726
+ await reserveActiveRuntimeJournal(link3);
4564
4727
  }
4565
4728
  await transport.writeJsonAtomic(path, {
4566
4729
  ...journal,
4567
4730
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
4568
4731
  });
4569
- if (link2) await activateActiveRuntimeJournal(link2);
4732
+ if ((journal.metadataAudit || journal.metadataGuards) && transport.kind === "local") await syncMetadataPath(path);
4733
+ if (link3) await activateActiveRuntimeJournal(link3);
4570
4734
  }
4571
4735
  async function readApplyJournal(targetRoot, adapter, transport = localTransport, scope = {}) {
4572
4736
  const path = applyJournalPath(targetRoot, adapter, scope);
@@ -4593,7 +4757,7 @@ async function listAllApplyJournals(targetRoot, adapter, transport = localTransp
4593
4757
  if (!fileName.endsWith(suffix)) continue;
4594
4758
  const path = join11(metadataDir(targetRoot), fileName);
4595
4759
  const journal = parseApplyJournal(JSON.parse(await transport.readFile(path)));
4596
- if (journal.adapter === adapter) found.push({ path, journal });
4760
+ if (adapter === void 0 || journal.adapter === adapter) found.push({ path, journal });
4597
4761
  }
4598
4762
  return found.sort((a, b) => a.path.localeCompare(b.path));
4599
4763
  }
@@ -4632,6 +4796,7 @@ async function removeApplyJournal(targetRoot, adapter, transport = localTranspor
4632
4796
  if (existing?.mutation) await beginResolveMutationRuntimeJournal(existing.mutation.operationId, path);
4633
4797
  await transport.rm(applyJournalPath(targetRoot, adapter, scope));
4634
4798
  await transport.rm(applyBackupDir(targetRoot, adapter, scope));
4799
+ if ((existing?.metadataAudit || existing?.metadataGuards) && transport.kind === "local") await syncMetadataPath(dirname9(path), true);
4635
4800
  if (existing?.mutation) await resolveMutationRuntimeJournal(existing.mutation.operationId, path);
4636
4801
  }
4637
4802
  async function abortApplyJournal(targetRoot, adapter, transport = localTransport, scope = {}) {
@@ -4644,6 +4809,9 @@ async function abortApplyJournal(targetRoot, adapter, transport = localTransport
4644
4809
  const archivePath = join11(metadataDir(targetRoot), "archive", `${stateKey}.apply-journal.failed-${journalTimestamp(/* @__PURE__ */ new Date())}.json`);
4645
4810
  const content = await transport.readFile(journalPath);
4646
4811
  const journal = parseApplyJournal(JSON.parse(content));
4812
+ if (journal.metadataAudit || journal.metadataGuards) {
4813
+ throw new Error("A guarded metadata transaction must be recovered and verified; abort cannot discard its partial state.");
4814
+ }
4647
4815
  await transport.writeFileAtomic(archivePath, content.endsWith("\n") ? content : `${content}
4648
4816
  `);
4649
4817
  if (journal.mutation) await beginResolveMutationRuntimeJournal(journal.mutation.operationId, journalPath);
@@ -4695,7 +4863,9 @@ function applyJournalLinkDigest(journal, transport) {
4695
4863
  graphLockRemovePath: journal.graphLockRemovePath ?? null,
4696
4864
  stateRemoveKey: journal.stateRemoveKey ?? null,
4697
4865
  workspaceConfigPath: journal.workspaceConfigPath ?? null,
4698
- operations: journal.operations
4866
+ operations: journal.operations,
4867
+ ...journal.metadataAudit ? { metadataAudit: journal.metadataAudit, manifest: journal.manifest } : {},
4868
+ ...journal.metadataGuards ? { metadataGuards: journal.metadataGuards, manifest: journal.manifest } : {}
4699
4869
  })).digest("hex");
4700
4870
  }
4701
4871
  function assertApplyJournalRecoveryAllowed(journal) {
@@ -5363,7 +5533,56 @@ var init_desired = __esm({
5363
5533
  import { createHash as createHash10 } from "crypto";
5364
5534
  import { mkdtemp as mkdtemp2, readFile as readFile17, realpath, rm as rm6, writeFile as writeFile11 } from "fs/promises";
5365
5535
  import { tmpdir as tmpdir3 } from "os";
5366
- import { basename as basename2, dirname as dirname13, join as join12, relative as relative7 } from "path";
5536
+ import { basename as basename2, dirname as dirname13, join as join12, relative as relative8 } from "path";
5537
+ function exactManagedInstructionBlockSnapshot(content, selector) {
5538
+ const beginCount = [...content.matchAll(new RegExp(`<!-- BEGIN openpack:include ${escapeRegex(selector)}(?=\\s|-->)`, "gu"))].length;
5539
+ const endCount = [...content.matchAll(new RegExp(`<!-- END openpack:include ${escapeRegex(selector)}(?=\\s|-->)`, "gu"))].length;
5540
+ if (beginCount !== 1 || endCount !== 1) throw new Error("Duplicate or missing managed instruction markers; adoption is refused.");
5541
+ const stack = [];
5542
+ let selectedBegin;
5543
+ let selectedEnd;
5544
+ let begins = 0;
5545
+ let ends = 0;
5546
+ for (const token of content.matchAll(/<!-- (BEGIN|END) openpack:include ([^\r\n]*?) -->/gu)) {
5547
+ const at = token.index;
5548
+ if (token[1] === "BEGIN") {
5549
+ const begin = /^(.*?) sha256:([a-f0-9]{64})$/u.exec(token[2]);
5550
+ if (!begin) throw new Error("Malformed managed instruction begin marker; adoption is refused.");
5551
+ const name = begin[1];
5552
+ if (name === selector) {
5553
+ if (++begins !== 1 || stack.length !== 0) throw new Error("Duplicate or overlapping managed instruction block; adoption is refused.");
5554
+ let bodyStart = at + token[0].length;
5555
+ if (content.slice(bodyStart, bodyStart + 2) === "\r\n") bodyStart += 2;
5556
+ else if (content[bodyStart] === "\n") bodyStart++;
5557
+ selectedBegin = { start: at, bodyStart, hash: begin[2] };
5558
+ }
5559
+ stack.push(name);
5560
+ } else {
5561
+ const name = token[2];
5562
+ if (stack.pop() !== name) throw new Error("Overlapping or unmatched managed instruction markers; adoption is refused.");
5563
+ if (name === selector) {
5564
+ if (++ends !== 1 || !selectedBegin) throw new Error("Duplicate or missing managed instruction marker; adoption is refused.");
5565
+ let end = at + token[0].length;
5566
+ if (content.slice(end, end + 2) === "\r\n") end += 2;
5567
+ else if (content[end] === "\n") end++;
5568
+ selectedEnd = { bodyEnd: at, end };
5569
+ }
5570
+ }
5571
+ }
5572
+ if (stack.length || begins !== 1 || ends !== 1 || !selectedBegin || !selectedEnd) {
5573
+ throw new Error(`Missing or incomplete managed instruction block for ${selector}; adoption is refused.`);
5574
+ }
5575
+ const hash2 = hashText(content.slice(selectedBegin.bodyStart, selectedEnd.bodyEnd));
5576
+ if (hash2 !== selectedBegin.hash) throw new Error(`Managed instruction block drift detected for ${selector}; adoption is refused.`);
5577
+ return {
5578
+ selector,
5579
+ hash: hash2,
5580
+ markerHash: selectedBegin.hash,
5581
+ prefixHash: hashText(content.slice(0, selectedBegin.start)),
5582
+ suffixHash: hashText(content.slice(selectedEnd.end)),
5583
+ blockBytesHash: hashText(content.slice(selectedBegin.start, selectedEnd.end))
5584
+ };
5585
+ }
5367
5586
  async function desiredManagedInstructionBlockHash(sourcePath) {
5368
5587
  const source = await readFile17(sourcePath, "utf8");
5369
5588
  return hashText(managedBlockBody(source));
@@ -5375,13 +5594,13 @@ async function readManagedInstructionBlockState(destPath, selector, transport) {
5375
5594
  const content = await transport.readFile(destPath);
5376
5595
  const block = findManagedInstructionBlock(content, selector);
5377
5596
  if (!block) return { exists: true, hasBlock: false, drifted: false };
5378
- const hash = hashText(block.body);
5597
+ const hash2 = hashText(block.body);
5379
5598
  return {
5380
5599
  exists: true,
5381
5600
  hasBlock: true,
5382
- hash,
5601
+ hash: hash2,
5383
5602
  markerHash: block.markerHash,
5384
- drifted: hash !== block.markerHash
5603
+ drifted: hash2 !== block.markerHash
5385
5604
  };
5386
5605
  }
5387
5606
  async function writeManagedInstructionBlock(sourcePath, destPath, selector, transport, options = {}) {
@@ -5420,12 +5639,12 @@ function managedInstructionSelector(selector, artifactType, artifactName) {
5420
5639
  }
5421
5640
  function renderManagedInstructionBlock(selector, source) {
5422
5641
  const body = managedBlockBody(source);
5423
- const hash = hashText(body);
5642
+ const hash2 = hashText(body);
5424
5643
  return {
5425
- block: `<!-- BEGIN openpack:include ${selector} sha256:${hash} -->
5644
+ block: `<!-- BEGIN openpack:include ${selector} sha256:${hash2} -->
5426
5645
  ${body}<!-- END openpack:include ${selector} -->
5427
5646
  `,
5428
- hash
5647
+ hash: hash2
5429
5648
  };
5430
5649
  }
5431
5650
  function upsertManagedInstructionBlock(content, selector, block, options) {
@@ -5507,7 +5726,7 @@ function referencesAgentsMd(content, claudePath, agentsPath) {
5507
5726
  const cleaned = referenced.trim().replace(/^["']|["']$/g, "");
5508
5727
  if (!/AGENTS\.md$/i.test(cleaned)) continue;
5509
5728
  const candidate = cleaned.startsWith("/") ? cleaned : join12(claudeDir, cleaned);
5510
- if (relative7(dirname13(agentsPath), candidate).replaceAll("\\", "/") === "AGENTS.md") return true;
5729
+ if (relative8(dirname13(agentsPath), candidate).replaceAll("\\", "/") === "AGENTS.md") return true;
5511
5730
  if (candidate === agentsPath) return true;
5512
5731
  }
5513
5732
  return false;
@@ -5564,8 +5783,8 @@ __export(apply_exports, {
5564
5783
  uninstall: () => uninstall
5565
5784
  });
5566
5785
  import { execFile as execFile4 } from "child_process";
5567
- import { createHash as createHash11 } from "crypto";
5568
- import { mkdtemp as mkdtemp3, readFile as readFile18, rm as rm7, writeFile as writeFile12 } from "fs/promises";
5786
+ import { createHash as createHash11, randomUUID as randomUUID3 } from "crypto";
5787
+ import { link as link2, mkdir as mkdir11, mkdtemp as mkdtemp3, open as open4, readFile as readFile18, rm as rm7, writeFile as writeFile12 } from "fs/promises";
5569
5788
  import { tmpdir as tmpdir4 } from "os";
5570
5789
  import { basename as basename3, dirname as dirname14, join as join13, resolve as resolve16 } from "path";
5571
5790
  import { promisify as promisify4 } from "util";
@@ -5838,20 +6057,35 @@ async function commitManifestMetadataJournal(journal, transport = localTransport
5838
6057
  async function commitJournalState(journal, transport, entries, now) {
5839
6058
  const manifest = withManifestRevision({
5840
6059
  ...journal.manifest,
5841
- generatedAt: now,
6060
+ generatedAt: journal.metadataAudit || journal.metadataGuards ? journal.createdAt : now,
5842
6061
  entries: entries ? entries.sort((a, b) => a.path.localeCompare(b.path)) : journal.manifest.entries
5843
6062
  });
5844
- if (journal.mode === "uninstall" && manifest.entries.length === 0) {
6063
+ if (journal.metadataGuards) await assertMetadataStateGuards(journal, manifest, journal.metadataGuards, transport);
6064
+ if (journal.metadataAudit) {
6065
+ await assertMetadataAuditGuards(journal, manifest, transport);
6066
+ for (const file of journal.metadataAudit.auditFiles) {
6067
+ const path = metadataAuditPath(journal.metadataAudit, file.path);
6068
+ declareMutationPath(path);
6069
+ await writeAuditFileExclusive(path, file.content);
6070
+ }
6071
+ await assertMetadataAuditGuards(journal, manifest, transport);
6072
+ }
6073
+ if (journal.mode === "uninstall" && manifest.entries.length === 0 && !journal.metadataAudit) {
5845
6074
  await removeStateFiles(journal.targetRoot, journal.adapter, transport, {
5846
6075
  installationType: journal.installationType,
5847
6076
  stateKey: journal.stateKey
5848
6077
  });
6078
+ if (journal.metadataGuards) await syncMetadataPath(metadataDir(journal.targetRoot), true);
5849
6079
  } else {
5850
6080
  if (journal.sourceLock) await writeSourceLock(journal.targetRoot, journal.adapter, journal.sourceLock, transport, {
5851
6081
  installationType: journal.installationType,
5852
6082
  stateKey: journal.stateKey
5853
6083
  });
5854
6084
  await writeInstallManifest(manifest, transport);
6085
+ if (journal.metadataAudit || journal.metadataGuards) await syncMetadataPath(installManifestPath(journal.targetRoot, journal.adapter, {
6086
+ installationType: journal.installationType,
6087
+ stateKey: journal.stateKey
6088
+ }));
5855
6089
  }
5856
6090
  if (journal.graphLockPath && journal.graphLock) await writeGraphLock(journal.graphLockPath, journal.graphLock);
5857
6091
  if (journal.stateRemoveKey && journal.stateRemoveKey !== journal.stateKey) {
@@ -5869,6 +6103,8 @@ async function commitJournalState(journal, transport, entries, now) {
5869
6103
  await writeJsonAtomic(journal.workspaceConfigPath, journal.workspaceConfig);
5870
6104
  }
5871
6105
  const verifiedManifest = await assertCommittedJournalState(journal, manifest, transport);
6106
+ if (journal.metadataAudit) await assertMetadataAuditGuards(journal, manifest, transport, true);
6107
+ if (journal.metadataGuards) await assertMetadataStateGuards(journal, manifest, journal.metadataGuards, transport, true);
5872
6108
  await removeApplyJournal(journal.targetRoot, journal.adapter, transport, {
5873
6109
  installationType: journal.installationType,
5874
6110
  stateKey: journal.stateKey
@@ -5884,7 +6120,7 @@ async function commitJournalState(journal, transport, entries, now) {
5884
6120
  async function assertCommittedJournalState(journal, expectedManifest, transport) {
5885
6121
  const scope = { installationType: journal.installationType, stateKey: journal.stateKey };
5886
6122
  const actualManifest = await readInstallManifest(journal.targetRoot, journal.adapter, transport, scope);
5887
- if (journal.mode === "uninstall" && expectedManifest.entries.length === 0) {
6123
+ if (journal.mode === "uninstall" && expectedManifest.entries.length === 0 && !journal.metadataAudit) {
5888
6124
  if (actualManifest) throw new Error("Uninstall postcheck found an install manifest that should have been removed.");
5889
6125
  } else if (!actualManifest) {
5890
6126
  throw new Error(
@@ -5924,6 +6160,88 @@ async function assertCommittedJournalState(journal, expectedManifest, transport)
5924
6160
  }
5925
6161
  return actualManifest;
5926
6162
  }
6163
+ async function assertMetadataAuditGuards(journal, after, transport, requireAfter = false) {
6164
+ const audit = journal.metadataAudit;
6165
+ const sha = /^[a-f0-9]{64}$/;
6166
+ if (transport.kind !== "local" || audit.kind !== "ownership-release" || after.adapter !== journal.adapter || after.targetRoot !== journal.targetRoot || after.installationType !== journal.installationType || after.stateKey !== journal.stateKey || journal.mode !== "uninstall" || journal.operations.length || journal.completed.length || journal.sourceLock || journal.graphLock || journal.graphLockPath || journal.graphLockRemovePath || journal.stateRemoveKey || journal.workspaceConfigPath || journal.workspaceConfig || !sha.test(audit.planDigest) || !sha.test(journal.baseRevision ?? "") || audit.auditFiles.length !== 1 || audit.runtime.length !== 1 || !audit.inventory.length) {
6167
+ throw new Error("Invalid metadata-audit transaction; no state was committed.");
6168
+ }
6169
+ await assertMetadataStateGuards(journal, after, audit, transport, requireAfter);
6170
+ for (const file of audit.auditFiles) {
6171
+ const path = metadataAuditPath(audit, file.path);
6172
+ await assertNoSymlinkPath(path);
6173
+ if (!sha.test(file.sha256) || createHash11("sha256").update(file.content).digest("hex") !== file.sha256) {
6174
+ throw new Error("Metadata-audit content digest is invalid.");
6175
+ }
6176
+ try {
6177
+ if (await readFile18(path, "utf8") !== file.content) throw new Error(`Metadata-audit file changed: ${path}`);
6178
+ } catch (error) {
6179
+ if (error.code !== "ENOENT" || requireAfter) throw error;
6180
+ }
6181
+ }
6182
+ }
6183
+ async function assertMetadataStateGuards(journal, after, guards, transport, requireAfter = false) {
6184
+ const sha = /^[a-f0-9]{64}$/;
6185
+ if (transport.kind !== "local" || journal.metadataAudit && journal.metadataGuards || after.adapter !== journal.adapter || after.targetRoot !== journal.targetRoot || after.installationType !== journal.installationType || after.stateKey !== journal.stateKey || journal.mode !== "uninstall" || journal.operations.length || journal.completed.length || journal.sourceLock || journal.graphLock || journal.graphLockPath || journal.graphLockRemovePath || journal.stateRemoveKey || journal.workspaceConfigPath || journal.workspaceConfig || journal.baseRevision !== null && !sha.test(journal.baseRevision) || !guards.inventory.length || !guards.runtime.length) {
6186
+ throw new Error("Invalid guarded metadata transaction; no state was committed.");
6187
+ }
6188
+ await assertNoSymlinkPath(journal.targetRoot);
6189
+ await assertNoSymlinkPath(metadataDir(journal.targetRoot));
6190
+ const inventory = await listInstallManifests(journal.targetRoot, void 0, transport);
6191
+ for (const item of inventory) await assertNoSymlinkPath(item.path);
6192
+ const before = new Map(guards.inventory.map((item) => [item.stateKey, item.revision]));
6193
+ if (before.size !== guards.inventory.length || [...before.values()].some((revision) => !sha.test(revision)) || (before.get(journal.stateKey) ?? null) !== journal.baseRevision) {
6194
+ throw new Error("Invalid guarded metadata inventory baseline.");
6195
+ }
6196
+ const next = new Map(before);
6197
+ if (after.entries.length === 0 && !journal.metadataAudit) next.delete(journal.stateKey);
6198
+ else next.set(journal.stateKey, after.revision);
6199
+ const actual = new Map(inventory.map((item) => [item.stateKey, item.manifest.revision]));
6200
+ const equals = (expected) => actual.size === expected.size && [...expected].every(([key, revision]) => actual.get(key) === revision);
6201
+ if (!equals(next) && (requireAfter || !equals(before))) {
6202
+ throw new Error("Metadata inventory/manifest CAS failed; concurrent state was preserved.");
6203
+ }
6204
+ for (const guard of guards.runtime) {
6205
+ const path = metadataRuntimePath(journal.targetRoot, guard.path);
6206
+ if (!sha.test(guard.hash) || !sha.test(guard.snapshotDigest) || await ownershipRuntimeSnapshot(path) !== guard.snapshotDigest || await transport.hashPath(path) !== guard.hash) {
6207
+ throw new Error(`Metadata runtime CAS failed at ${guard.path}; runtime was preserved.`);
6208
+ }
6209
+ if (guard.managedBlock) {
6210
+ const current = exactManagedInstructionBlockSnapshot(await transport.readFile(path), guard.managedBlock.selector);
6211
+ if (canonicalJson5(current) !== canonicalJson5(guard.managedBlock)) {
6212
+ throw new Error(`Managed instruction snapshot CAS failed at ${guard.path}.`);
6213
+ }
6214
+ }
6215
+ }
6216
+ }
6217
+ async function writeAuditFileExclusive(path, content) {
6218
+ await assertNoSymlinkPath(path);
6219
+ await mkdir11(dirname14(path), { recursive: true });
6220
+ await syncMetadataPath(dirname14(dirname14(path)), true);
6221
+ const temporary = `${path}.pending-${randomUUID3()}`;
6222
+ try {
6223
+ const handle = await open4(temporary, "wx", 384);
6224
+ try {
6225
+ await handle.writeFile(content, "utf8");
6226
+ await handle.sync();
6227
+ } finally {
6228
+ await handle.close();
6229
+ }
6230
+ try {
6231
+ await link2(temporary, path);
6232
+ } catch (error) {
6233
+ if (error.code !== "EEXIST" || await readFile18(path, "utf8") !== content) throw error;
6234
+ }
6235
+ const directory = await open4(dirname14(path), "r");
6236
+ try {
6237
+ await directory.sync();
6238
+ } finally {
6239
+ await directory.close();
6240
+ }
6241
+ } finally {
6242
+ await rm7(temporary, { force: true });
6243
+ }
6244
+ }
5927
6245
  function canonicalJson5(value) {
5928
6246
  if (Array.isArray(value)) return `[${value.map((item) => canonicalJson5(item === void 0 ? null : item)).join(",")}]`;
5929
6247
  if (value === null || typeof value !== "object") return JSON.stringify(value);
@@ -5973,13 +6291,13 @@ async function applyOperation(operation, context) {
5973
6291
  }
5974
6292
  if (operation.mode === managedInstructionBlockMode) {
5975
6293
  const selector = managedInstructionSelector(operation.logicalSelector, operation.artifactType, operation.artifactName);
5976
- const hash2 = await writeManagedInstructionBlock(operation.sourcePath, operation.destPath, selector, transport, managedBlockMutationOptions(operation));
5977
- if (hash2 !== operation.desiredHash) {
5978
- throw new Error(`Managed block hash verification failed for ${operation.relativeDestPath}: expected ${operation.desiredHash}, got ${hash2}`);
6294
+ const hash3 = await writeManagedInstructionBlock(operation.sourcePath, operation.destPath, selector, transport, managedBlockMutationOptions(operation));
6295
+ if (hash3 !== operation.desiredHash) {
6296
+ throw new Error(`Managed block hash verification failed for ${operation.relativeDestPath}: expected ${operation.desiredHash}, got ${hash3}`);
5979
6297
  }
5980
6298
  return manifestEntryForOperation(operation, {
5981
6299
  now,
5982
- hash: hash2,
6300
+ hash: hash3,
5983
6301
  sourceHash: operation.desiredHash,
5984
6302
  graphLockDigest: context.graphLockDigest
5985
6303
  });
@@ -5997,13 +6315,13 @@ async function applyOperation(operation, context) {
5997
6315
  } else {
5998
6316
  await transport.atomicCopy(operation.sourcePath, operation.destPath, operation.kind);
5999
6317
  }
6000
- const hash = await transport.hashPath(operation.destPath);
6001
- if (!operation.mergeStrategy && hash !== operation.desiredHash) {
6002
- throw new Error(`Hash verification failed for ${operation.relativeDestPath}: expected ${operation.desiredHash}, got ${hash}`);
6318
+ const hash2 = await transport.hashPath(operation.destPath);
6319
+ if (!operation.mergeStrategy && hash2 !== operation.desiredHash) {
6320
+ throw new Error(`Hash verification failed for ${operation.relativeDestPath}: expected ${operation.desiredHash}, got ${hash2}`);
6003
6321
  }
6004
6322
  return manifestEntryForOperation(operation, {
6005
6323
  now,
6006
- hash,
6324
+ hash: hash2,
6007
6325
  sourceHash: operation.desiredHash,
6008
6326
  graphLockDigest: context.graphLockDigest
6009
6327
  });
@@ -6599,6 +6917,7 @@ var init_apply = __esm({
6599
6917
  init_openclaw_json_merge();
6600
6918
  init_manifest2();
6601
6919
  init_path_safety();
6920
+ init_paths();
6602
6921
  init_transaction();
6603
6922
  init_toml_merge();
6604
6923
  init_yaml_merge();
@@ -6647,11 +6966,11 @@ var init_identify = __esm({
6647
6966
  });
6648
6967
 
6649
6968
  // src/cli/index.ts
6650
- import { createHash as createHash27 } from "crypto";
6969
+ import { createHash as createHash28 } from "crypto";
6651
6970
  import { existsSync } from "fs";
6652
- import { mkdir as mkdir26, 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";
6653
6972
  import { homedir as homedir18, tmpdir as tmpdir7 } from "os";
6654
- import { basename as basename24, dirname as dirname37, isAbsolute as isAbsolute14, join as join59, relative as relative18, resolve as resolve43 } from "path";
6973
+ import { basename as basename24, dirname as dirname37, isAbsolute as isAbsolute14, join as join61, relative as relative19, resolve as resolve44 } from "path";
6655
6974
  import { fileURLToPath as fileURLToPath4 } from "url";
6656
6975
  import { Command } from "commander";
6657
6976
 
@@ -6680,8 +6999,8 @@ async function loadProgrammaticAdapter(modulePath, options) {
6680
6999
  if (!stats.isFile()) {
6681
7000
  throw new Error(`Programmatic adapter module is not a file: ${resolvedPath}`);
6682
7001
  }
6683
- const hash = await hashPath(resolvedPath);
6684
- const importPath = extname(resolvedPath) === ".ts" ? await transpileTypeScriptAdapter(resolvedPath, hash) : resolvedPath;
7002
+ const hash2 = await hashPath(resolvedPath);
7003
+ const importPath = extname(resolvedPath) === ".ts" ? await transpileTypeScriptAdapter(resolvedPath, hash2) : resolvedPath;
6685
7004
  const imported = await import(`${pathToFileURL(importPath).href}?agentwheel=${Date.now()}`);
6686
7005
  const candidate = imported.adapter;
6687
7006
  if (!candidate || typeof candidate !== "object") {
@@ -6690,7 +7009,7 @@ async function loadProgrammaticAdapter(modulePath, options) {
6690
7009
  const parsed = adapterSchema.parse(candidate);
6691
7010
  const runtime = {
6692
7011
  modulePath: resolvedPath,
6693
- hash,
7012
+ hash: hash2,
6694
7013
  capabilities: Array.isArray(candidate.capabilities) ? candidate.capabilities.filter((item) => typeof item === "string") : [],
6695
7014
  plan: typeof candidate.plan === "function" ? candidate.plan.bind(candidate) : void 0,
6696
7015
  apply: typeof candidate.apply === "function" ? candidate.apply.bind(candidate) : void 0,
@@ -6698,7 +7017,7 @@ async function loadProgrammaticAdapter(modulePath, options) {
6698
7017
  };
6699
7018
  return { ...parsed, programmatic: runtime };
6700
7019
  }
6701
- async function transpileTypeScriptAdapter(modulePath, hash) {
7020
+ async function transpileTypeScriptAdapter(modulePath, hash2) {
6702
7021
  const source = await readFile3(modulePath, "utf8");
6703
7022
  const output = ts.transpileModule(source, {
6704
7023
  compilerOptions: {
@@ -6710,7 +7029,7 @@ async function transpileTypeScriptAdapter(modulePath, hash) {
6710
7029
  },
6711
7030
  fileName: modulePath
6712
7031
  });
6713
- const outPath = join2(tmpdir(), `agentwheel-adapter-${hash}.mjs`);
7032
+ const outPath = join2(tmpdir(), `agentwheel-adapter-${hash2}.mjs`);
6714
7033
  await writeFile2(outPath, output.outputText, "utf8");
6715
7034
  return outPath;
6716
7035
  }
@@ -6739,11 +7058,11 @@ init_manifest2();
6739
7058
  // src/install/plan.ts
6740
7059
  init_adapter();
6741
7060
  init_manifest();
6742
- import { basename as basename8, join as join24, relative as relative8 } from "path";
7061
+ import { basename as basename8, join as join24, relative as relative9 } from "path";
6743
7062
 
6744
7063
  // src/staging/codex-subagents.ts
6745
7064
  init_fs();
6746
- import { mkdir as mkdir11, readFile as readFile19, writeFile as writeFile13 } from "fs/promises";
7065
+ import { mkdir as mkdir12, readFile as readFile19, writeFile as writeFile13 } from "fs/promises";
6747
7066
  import { basename as basename4, dirname as dirname15, join as join14 } from "path";
6748
7067
  import { parse as parseYaml } from "yaml";
6749
7068
  var requiredCodexAgentFields = ["name", "description", "developer_instructions"];
@@ -6790,7 +7109,7 @@ async function renderCodexSubagent(artifact, stageRoot) {
6790
7109
  }
6791
7110
  const markdown = await readFile19(markdownPath, "utf8");
6792
7111
  const toml = markdownToCodexAgentToml(agentName, markdown);
6793
- await mkdir11(dirname15(renderedPath), { recursive: true });
7112
+ await mkdir12(dirname15(renderedPath), { recursive: true });
6794
7113
  await writeFile13(renderedPath, toml, "utf8");
6795
7114
  return {
6796
7115
  ...artifact,
@@ -6872,7 +7191,7 @@ function escapeRegExp2(value) {
6872
7191
 
6873
7192
  // src/staging/copilot-artifacts.ts
6874
7193
  init_fs();
6875
- import { mkdir as mkdir12, readFile as readFile20, writeFile as writeFile14 } from "fs/promises";
7194
+ import { mkdir as mkdir13, readFile as readFile20, writeFile as writeFile14 } from "fs/promises";
6876
7195
  import { basename as basename5, dirname as dirname16, join as join15 } from "path";
6877
7196
  async function renderCopilotArtifacts(artifacts, stageRoot, adapter) {
6878
7197
  if (adapter?.name !== "copilot") return artifacts;
@@ -6904,7 +7223,7 @@ async function renderCopilotSubagent(artifact, stageRoot) {
6904
7223
  throw new Error(`Copilot subagent ${artifact.relativePath} must be a .md file or directory containing AGENTS.md.`);
6905
7224
  }
6906
7225
  const markdown = await readFile20(markdownPath, "utf8");
6907
- await mkdir12(dirname16(renderedPath), { recursive: true });
7226
+ await mkdir13(dirname16(renderedPath), { recursive: true });
6908
7227
  await writeFile14(renderedPath, ensureCopilotAgentDescription(agentName, markdown), "utf8");
6909
7228
  return {
6910
7229
  ...artifact,
@@ -6959,7 +7278,7 @@ function yamlString(value) {
6959
7278
 
6960
7279
  // src/staging/openclaw-subagents.ts
6961
7280
  init_fs();
6962
- import { mkdir as mkdir13, readFile as readFile21, writeFile as writeFile15 } from "fs/promises";
7281
+ import { mkdir as mkdir14, readFile as readFile21, writeFile as writeFile15 } from "fs/promises";
6963
7282
  import { basename as basename6, dirname as dirname17, join as join16 } from "path";
6964
7283
  async function renderOpenClawSubagents(artifacts, stageRoot, adapter) {
6965
7284
  if (adapter?.name !== "openclaw") return artifacts;
@@ -6994,7 +7313,7 @@ async function renderOpenClawSubagent(artifact, stageRoot) {
6994
7313
 
6995
7314
  ${parsed.description ?? `OpenClaw subagent ${agentId}.`}`;
6996
7315
  const renderedPath = join16(stageRoot, ".agentwheel-rendered", "openclaw-subagents", agentId, "AGENTS.md");
6997
- await mkdir13(dirname17(renderedPath), { recursive: true });
7316
+ await mkdir14(dirname17(renderedPath), { recursive: true });
6998
7317
  await writeFile15(renderedPath, `${body}
6999
7318
  `, "utf8");
7000
7319
  const renderedDir = dirname17(renderedPath);
@@ -7280,59 +7599,7 @@ init_transport();
7280
7599
 
7281
7600
  // src/validation/adapter-targets.ts
7282
7601
  init_adapter();
7283
-
7284
- // src/model/selection.ts
7285
- init_artifact();
7286
- function artifactSelectorKey(artifact) {
7287
- return `${artifact.type}/${artifact.name}`;
7288
- }
7289
- function artifactSelectorAliases(artifact) {
7290
- const primary = artifactSelectorKey(artifact);
7291
- if (artifact.type !== "subagents") return [primary];
7292
- const baseName = subagentBaseName(artifact.name);
7293
- if (baseName === artifact.name) return [primary];
7294
- return [primary, `subagents/${baseName}`];
7295
- }
7296
- function normalizeArtifactSelectors(select, legacySkills) {
7297
- const selected = [
7298
- ...select ?? [],
7299
- ...(legacySkills ?? []).map((name) => `skills/${name}`)
7300
- ].flatMap(splitSelectorList);
7301
- if (selected.length === 0) return void 0;
7302
- return [...new Set(selected.map(parseArtifactSelector))];
7303
- }
7304
- function filterArtifactsBySelection(artifacts, selectors, legacySkills, options = {}) {
7305
- const selected = normalizeArtifactSelectors(selectors, legacySkills);
7306
- if (!selected?.length) return artifacts;
7307
- const selectedSet = new Set(selected);
7308
- const available = new Set((options.validationArtifacts ?? artifacts).flatMap(artifactSelectorAliases));
7309
- const missing = selected.filter((selector) => !available.has(selector));
7310
- if (missing.length > 0) {
7311
- throw new Error(`Selected artifact not found in package: ${missing.join(", ")}`);
7312
- }
7313
- return artifacts.filter((artifact) => artifact.required || artifactSelectorAliases(artifact).some((selector) => selectedSet.has(selector)));
7314
- }
7315
- function splitSelectorList(value) {
7316
- return value.split(",").map((item) => item.trim()).filter(Boolean);
7317
- }
7318
- function parseArtifactSelector(value) {
7319
- const slash = value.indexOf("/");
7320
- if (slash <= 0 || slash === value.length - 1) {
7321
- throw new Error(`Invalid artifact selector: ${value}. Expected <type>/<name>.`);
7322
- }
7323
- const type = value.slice(0, slash);
7324
- const name = value.slice(slash + 1);
7325
- const parsedType = artifactTypeSchema.safeParse(type);
7326
- if (!parsedType.success) {
7327
- throw new Error(`Invalid artifact selector type: ${type}`);
7328
- }
7329
- return `${parsedType.data}/${name}`;
7330
- }
7331
- function subagentBaseName(name) {
7332
- return name.replace(/\.agent\.md$/i, "").replace(/\.toml$/i, "").replace(/\.md$/i, "");
7333
- }
7334
-
7335
- // src/validation/adapter-targets.ts
7602
+ init_selection();
7336
7603
  function filterArtifactsByAdapterTargets(artifacts, adapter, installationType, options = {}) {
7337
7604
  const skipped = [];
7338
7605
  const installable = artifacts.filter((artifact) => {
@@ -7375,10 +7642,11 @@ function skipWarning(selector, adapter, installationType, artifactType, support)
7375
7642
 
7376
7643
  // src/validation/artifacts.ts
7377
7644
  init_adapter();
7645
+ init_selection();
7646
+ init_fs();
7378
7647
  import { readFile as readFile24 } from "fs/promises";
7379
7648
  import { basename as basename7, join as join23 } from "path";
7380
7649
  import { parseDocument as parseDocument2 } from "yaml";
7381
- init_fs();
7382
7650
  var behavioralRuleFormats = ["markdown-rule", "claude-markdown-rule", "copilot-instruction-rule"];
7383
7651
  var pluginFormats = ["claude-plugin", "codex-plugin", "hermes-plugin", "copilot-plugin", "openclaw-plugin", "openclaw-clawhub-plugin"];
7384
7652
  async function filterArtifactsByInstallFormat(artifacts, adapter, installationType, options = {}) {
@@ -8497,7 +8765,7 @@ async function operationForArtifact(artifact, adapter, targetRoot, installationT
8497
8765
  kind: "file",
8498
8766
  sourcePath: artifact.stagedPath ?? artifact.sourcePath,
8499
8767
  destPath: destPath2,
8500
- relativeDestPath: relative8(targetRoot, destPath2).replaceAll("\\", "/"),
8768
+ relativeDestPath: relative9(targetRoot, destPath2).replaceAll("\\", "/"),
8501
8769
  desiredHash: artifact.hash,
8502
8770
  reason: "destination missing",
8503
8771
  channel: artifact.channel ?? "managed",
@@ -8515,7 +8783,7 @@ async function operationForArtifact(artifact, adapter, targetRoot, installationT
8515
8783
  kind: artifact.kind,
8516
8784
  sourcePath: artifact.stagedPath ?? artifact.sourcePath,
8517
8785
  destPath,
8518
- relativeDestPath: relative8(targetRoot, destPath).replaceAll("\\", "/"),
8786
+ relativeDestPath: relative9(targetRoot, destPath).replaceAll("\\", "/"),
8519
8787
  desiredHash: artifact.hash,
8520
8788
  reason: "destination missing",
8521
8789
  channel: artifact.channel ?? "managed",
@@ -9512,14 +9780,14 @@ async function writeMermaidAsset(response) {
9512
9780
  "content-type": "application/javascript; charset=utf-8",
9513
9781
  "cache-control": "public, max-age=3600"
9514
9782
  });
9515
- await new Promise((resolve44) => {
9783
+ await new Promise((resolve45) => {
9516
9784
  const stream = createReadStream(assetPath);
9517
9785
  stream.on("error", () => {
9518
9786
  if (!response.headersSent) writeText(response, 404, "Mermaid asset unavailable.\n");
9519
9787
  else response.destroy();
9520
- resolve44();
9788
+ resolve45();
9521
9789
  });
9522
- stream.on("end", resolve44);
9790
+ stream.on("end", resolve45);
9523
9791
  stream.pipe(response);
9524
9792
  });
9525
9793
  }
@@ -9546,14 +9814,14 @@ function escapeHtml2(value) {
9546
9814
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
9547
9815
  }
9548
9816
  function listen(server, port, bind) {
9549
- return new Promise((resolve44, reject) => {
9817
+ return new Promise((resolve45, reject) => {
9550
9818
  const onError = (error) => {
9551
9819
  server.off("listening", onListening);
9552
9820
  reject(error);
9553
9821
  };
9554
9822
  const onListening = () => {
9555
9823
  server.off("error", onError);
9556
- resolve44();
9824
+ resolve45();
9557
9825
  };
9558
9826
  server.once("error", onError);
9559
9827
  server.once("listening", onListening);
@@ -9561,7 +9829,7 @@ function listen(server, port, bind) {
9561
9829
  });
9562
9830
  }
9563
9831
  function waitForShutdown(server, beforeClose) {
9564
- return new Promise((resolve44) => {
9832
+ return new Promise((resolve45) => {
9565
9833
  let closing = false;
9566
9834
  const shutdown = () => {
9567
9835
  if (closing) return;
@@ -9569,7 +9837,7 @@ function waitForShutdown(server, beforeClose) {
9569
9837
  process.off("SIGINT", shutdown);
9570
9838
  process.off("SIGTERM", shutdown);
9571
9839
  beforeClose();
9572
- server.close(() => resolve44());
9840
+ server.close(() => resolve45());
9573
9841
  };
9574
9842
  process.once("SIGINT", shutdown);
9575
9843
  process.once("SIGTERM", shutdown);
@@ -9579,7 +9847,7 @@ function waitForShutdown(server, beforeClose) {
9579
9847
  process.off("SIGINT", shutdown);
9580
9848
  process.off("SIGTERM", shutdown);
9581
9849
  beforeClose();
9582
- resolve44();
9850
+ resolve45();
9583
9851
  });
9584
9852
  });
9585
9853
  }
@@ -9597,7 +9865,7 @@ function errorMessage2(error) {
9597
9865
  }
9598
9866
 
9599
9867
  // src/source/clawhub.ts
9600
- import { mkdir as mkdir14, rm as rm8, writeFile as writeFile16 } from "fs/promises";
9868
+ import { mkdir as mkdir15, rm as rm8, writeFile as writeFile16 } from "fs/promises";
9601
9869
  import { basename as basename10, dirname as dirname18, join as join28, resolve as resolve18 } from "path";
9602
9870
 
9603
9871
  // src/model/package.ts
@@ -9791,8 +10059,8 @@ init_fs();
9791
10059
 
9792
10060
  // src/source/local.ts
9793
10061
  import { createHash as createHash13 } from "crypto";
9794
- import { readdir as readdir5, stat as stat5 } from "fs/promises";
9795
- import { basename as basename9, join as join27, relative as relative9, resolve as resolve17 } from "path";
10062
+ import { readdir as readdir6, stat as stat5 } from "fs/promises";
10063
+ import { basename as basename9, join as join27, relative as relative10, resolve as resolve17 } from "path";
9796
10064
  init_fs();
9797
10065
  var LocalSourceDriver = class {
9798
10066
  name = "local";
@@ -9933,23 +10201,23 @@ var LocalSourceDriver = class {
9933
10201
  };
9934
10202
  async function hashLocalSource(root, manifest) {
9935
10203
  if (!manifest) return hashPath(root);
9936
- const hash = createHash13("sha256").update("local-openpack\0");
10204
+ const hash2 = createHash13("sha256").update("local-openpack\0");
9937
10205
  const manifestPath = await findPackageManifestPath(root, { warnLegacy: false });
9938
10206
  if (manifestPath) {
9939
- hash.update("manifest\0");
9940
- hash.update(relative9(root, manifestPath).replaceAll("\\", "/")).update("\0");
9941
- hash.update(await hashPath(manifestPath)).update("\0");
10207
+ hash2.update("manifest\0");
10208
+ hash2.update(relative10(root, manifestPath).replaceAll("\\", "/")).update("\0");
10209
+ hash2.update(await hashPath(manifestPath)).update("\0");
9942
10210
  }
9943
10211
  const provides = [...manifest.provides].sort((a, b) => `${a.type}\0${a.path}`.localeCompare(`${b.type}\0${b.path}`));
9944
10212
  for (const provide of provides) {
9945
10213
  const full = join27(root, provide.path);
9946
10214
  if (!await pathExists(full)) continue;
9947
- hash.update("provide\0");
9948
- hash.update(provide.type).update("\0");
9949
- hash.update(provide.path.replaceAll("\\", "/")).update("\0");
9950
- hash.update(await hashPath(full)).update("\0");
10215
+ hash2.update("provide\0");
10216
+ hash2.update(provide.type).update("\0");
10217
+ hash2.update(provide.path.replaceAll("\\", "/")).update("\0");
10218
+ hash2.update(await hashPath(full)).update("\0");
9951
10219
  }
9952
- return hash.digest("hex");
10220
+ return hash2.digest("hex");
9953
10221
  }
9954
10222
  async function firstExisting(paths) {
9955
10223
  for (const path of paths) {
@@ -9958,7 +10226,7 @@ async function firstExisting(paths) {
9958
10226
  return void 0;
9959
10227
  }
9960
10228
  async function sortedDirEntries(path) {
9961
- return (await readdir5(path, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
10229
+ return (await readdir6(path, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
9962
10230
  }
9963
10231
  async function listFromManifest(root, packageName) {
9964
10232
  const manifest = await readPackageManifest(root);
@@ -10139,7 +10407,7 @@ async function fetchClawHubPackage(fetchImpl, packageName) {
10139
10407
  throw new Error(`ClawHub lookup failed for ${packageName}`);
10140
10408
  }
10141
10409
  async function delay(ms) {
10142
- await new Promise((resolve44) => setTimeout(resolve44, ms));
10410
+ await new Promise((resolve45) => setTimeout(resolve45, ms));
10143
10411
  }
10144
10412
  function parseClawHubSource(source) {
10145
10413
  if (!source.startsWith(sourcePrefix)) {
@@ -10171,7 +10439,7 @@ async function writeGeneratedPackage(root, packageInfo) {
10171
10439
  };
10172
10440
  const pluginPath = join28(root, "plugins", pluginId, "clawhub.json");
10173
10441
  await rm8(root, { recursive: true, force: true });
10174
- await mkdir14(dirname18(pluginPath), { recursive: true });
10442
+ await mkdir15(dirname18(pluginPath), { recursive: true });
10175
10443
  await writeFile16(join28(root, "openpack.json"), `${JSON.stringify({
10176
10444
  schemaVersion: CURRENT_OPENPACK_SCHEMA_VERSION,
10177
10445
  name: `clawhub/${name}`,
@@ -10202,9 +10470,9 @@ function cachePathFor(packageName, cacheRoot) {
10202
10470
 
10203
10471
  // src/source/git.ts
10204
10472
  import { execFile as execFile5 } from "child_process";
10205
- import { mkdir as mkdir16, rename as rename6, rm as rm10, stat as stat7 } from "fs/promises";
10473
+ import { mkdir as mkdir17, rename as rename6, rm as rm10, stat as stat7 } from "fs/promises";
10206
10474
  import { homedir as homedir7 } from "os";
10207
- import { basename as basename11, dirname as dirname20, join as join31, resolve as resolve19, sep as sep5 } from "path";
10475
+ import { basename as basename11, dirname as dirname20, join as join31, resolve as resolve19, sep as sep6 } from "path";
10208
10476
  import { promisify as promisify5 } from "util";
10209
10477
  init_fs();
10210
10478
 
@@ -10285,8 +10553,8 @@ function isMissingFile(error) {
10285
10553
 
10286
10554
  // src/source/cache.ts
10287
10555
  init_fs();
10288
- import { randomUUID as randomUUID3 } from "crypto";
10289
- import { mkdir as mkdir15, readdir as readdir6, readFile as readFile27, rm as rm9, stat as stat6, writeFile as writeFile17 } from "fs/promises";
10556
+ import { randomUUID as randomUUID4 } from "crypto";
10557
+ import { mkdir as mkdir16, readdir as readdir7, readFile as readFile27, rm as rm9, stat as stat6, writeFile as writeFile17 } from "fs/promises";
10290
10558
  import { dirname as dirname19, join as join30 } from "path";
10291
10559
  var snapshotNamePattern = /^(.*)-([0-9a-f]{12})$/i;
10292
10560
  var leaseMarker = ".agentwheel-lease-";
@@ -10301,11 +10569,11 @@ async function pruneGitCache(cacheRoot, options = {}) {
10301
10569
  }
10302
10570
  async function withGitCacheMaintenanceLock(cacheRoot, timeoutMs, fn) {
10303
10571
  const lockPath = join30(cacheRoot, ".maintenance.lock");
10304
- await mkdir15(cacheRoot, { recursive: true });
10572
+ await mkdir16(cacheRoot, { recursive: true });
10305
10573
  const started = Date.now();
10306
10574
  while (true) {
10307
10575
  try {
10308
- await mkdir15(lockPath);
10576
+ await mkdir16(lockPath);
10309
10577
  await writeFile17(
10310
10578
  join30(lockPath, "owner.json"),
10311
10579
  JSON.stringify({ pid: process.pid, createdAt: (/* @__PURE__ */ new Date()).toISOString() }),
@@ -10318,7 +10586,7 @@ async function withGitCacheMaintenanceLock(cacheRoot, timeoutMs, fn) {
10318
10586
  if (Date.now() - started > timeoutMs) {
10319
10587
  throw new Error(`Timed out waiting for git cache maintenance lock at ${lockPath}`);
10320
10588
  }
10321
- await new Promise((resolve44) => setTimeout(resolve44, 50));
10589
+ await new Promise((resolve45) => setTimeout(resolve45, 50));
10322
10590
  }
10323
10591
  }
10324
10592
  try {
@@ -10328,7 +10596,7 @@ async function withGitCacheMaintenanceLock(cacheRoot, timeoutMs, fn) {
10328
10596
  }
10329
10597
  }
10330
10598
  async function createGitSnapshotLease(snapshotPath) {
10331
- const leasePath = `${snapshotPath}${leaseMarker}${process.pid}-${randomUUID3()}`;
10599
+ const leasePath = `${snapshotPath}${leaseMarker}${process.pid}-${randomUUID4()}`;
10332
10600
  await writeFile17(leasePath, JSON.stringify({ pid: process.pid, createdAt: (/* @__PURE__ */ new Date()).toISOString() }), {
10333
10601
  encoding: "utf8",
10334
10602
  flag: "wx"
@@ -10341,7 +10609,7 @@ async function releaseGitSnapshotLease(leasePath) {
10341
10609
  async function removeGeneratedEntries(root, preserveGit) {
10342
10610
  let entries;
10343
10611
  try {
10344
- entries = await readdir6(root, { withFileTypes: true });
10612
+ entries = await readdir7(root, { withFileTypes: true });
10345
10613
  } catch {
10346
10614
  return;
10347
10615
  }
@@ -10356,7 +10624,7 @@ async function removeGeneratedEntries(root, preserveGit) {
10356
10624
  }
10357
10625
  async function pruneGitCacheUnlocked(cacheRoot, options) {
10358
10626
  const referencedCommits = await referencedGraphLockCommits(join30(dirname19(cacheRoot), "locks"));
10359
- const entries = await readdir6(cacheRoot, { withFileTypes: true });
10627
+ const entries = await readdir7(cacheRoot, { withFileTypes: true });
10360
10628
  const groups = /* @__PURE__ */ new Map();
10361
10629
  for (const entry of entries) {
10362
10630
  if (!entry.isDirectory()) continue;
@@ -10403,7 +10671,7 @@ async function referencedGraphLockCommits(lockRoot) {
10403
10671
  async function walkGraphLocks(root, visit) {
10404
10672
  let entries;
10405
10673
  try {
10406
- entries = await readdir6(root, { withFileTypes: true });
10674
+ entries = await readdir7(root, { withFileTypes: true });
10407
10675
  } catch (error) {
10408
10676
  if (isNotFound(error)) return;
10409
10677
  throw new Error(`Cannot inspect graph-lock directory ${root}; cache prune aborted: ${errorMessage3(error)}`);
@@ -10424,7 +10692,7 @@ async function walkGraphLocks(root, visit) {
10424
10692
  async function hasLiveSnapshotLease(snapshotPath, dryRun) {
10425
10693
  const directory = dirname19(snapshotPath);
10426
10694
  const prefix = `${snapshotPath.slice(directory.length + 1)}${leaseMarker}`;
10427
- const entries = await readdir6(directory, { withFileTypes: true });
10695
+ const entries = await readdir7(directory, { withFileTypes: true });
10428
10696
  let live = false;
10429
10697
  for (const entry of entries) {
10430
10698
  if (!entry.isFile() || !entry.name.startsWith(prefix)) continue;
@@ -10523,10 +10791,10 @@ function normalizeGitSubpath(subpath, source) {
10523
10791
  }
10524
10792
  return normalized;
10525
10793
  }
10526
- function resolveGitRelativeSubpath(declaringSubpath, relative19, source) {
10527
- const joined = posix4.normalize(posix4.join(declaringSubpath ?? ".", relative19));
10794
+ function resolveGitRelativeSubpath(declaringSubpath, relative20, source) {
10795
+ const joined = posix4.normalize(posix4.join(declaringSubpath ?? ".", relative20));
10528
10796
  if (joined === ".." || joined.startsWith("../")) {
10529
- throw new Error(`Relative dependency '${relative19}' escapes the git repository it is declared in: ${source}`);
10797
+ throw new Error(`Relative dependency '${relative20}' escapes the git repository it is declared in: ${source}`);
10530
10798
  }
10531
10799
  return normalizeGitSubpath(joined, source);
10532
10800
  }
@@ -10562,7 +10830,7 @@ var GitSourceDriver = class {
10562
10830
  return withFilesystemLock(`${resolved.resolvedPath}.lock`, resolved.cacheLockTimeoutMs ?? 3e4, async () => {
10563
10831
  const parsed = parseGitSource(resolved.source);
10564
10832
  const cacheRoot = dirname20(resolved.resolvedPath);
10565
- await mkdir16(cacheRoot, { recursive: true });
10833
+ await mkdir17(cacheRoot, { recursive: true });
10566
10834
  await assertOwnedByCurrentUser(cacheRoot);
10567
10835
  if (await pathExists(resolved.resolvedPath)) await assertOwnedByCurrentUser(resolved.resolvedPath);
10568
10836
  if (!await pathExists(join31(resolved.resolvedPath, ".git"))) {
@@ -10662,11 +10930,11 @@ async function snapshotCommit(checkoutPath, commit) {
10662
10930
  const tempIndexPath = `${tempPath}.index`;
10663
10931
  await rm10(tempPath, { recursive: true, force: true });
10664
10932
  await rm10(tempIndexPath, { force: true });
10665
- await mkdir16(tempPath, { recursive: true });
10933
+ await mkdir17(tempPath, { recursive: true });
10666
10934
  const env2 = { ...process.env, GIT_INDEX_FILE: tempIndexPath };
10667
10935
  try {
10668
10936
  await git(["-C", checkoutPath, "read-tree", commit], env2);
10669
- await git(["-C", checkoutPath, "checkout-index", "--all", `--prefix=${resolve19(tempPath)}${sep5}`], env2);
10937
+ await git(["-C", checkoutPath, "checkout-index", "--all", `--prefix=${resolve19(tempPath)}${sep6}`], env2);
10670
10938
  await removeGeneratedEntries(tempPath, false);
10671
10939
  } catch (error) {
10672
10940
  await rm10(tempPath, { recursive: true, force: true });
@@ -10695,7 +10963,7 @@ async function assertOwnedByCurrentUser(path) {
10695
10963
  }
10696
10964
 
10697
10965
  // src/source/mcp-registry.ts
10698
- import { mkdir as mkdir17, writeFile as writeFile18 } from "fs/promises";
10966
+ import { mkdir as mkdir18, writeFile as writeFile18 } from "fs/promises";
10699
10967
  import { basename as basename12, dirname as dirname21, join as join32, resolve as resolve20 } from "path";
10700
10968
  init_fs();
10701
10969
  var registryBaseUrl = "https://registry.modelcontextprotocol.io/v0.1";
@@ -10804,7 +11072,7 @@ function isSafeHttpUrl(value) {
10804
11072
  async function writeGeneratedPackage2(root, server) {
10805
11073
  const serverId = installNameFor3(server.serverName);
10806
11074
  const mcpPath = join32(root, "mcp", `${serverId}.json`);
10807
- await mkdir17(dirname21(mcpPath), { recursive: true });
11075
+ await mkdir18(dirname21(mcpPath), { recursive: true });
10808
11076
  await writeFile18(join32(root, "openpack.json"), `${JSON.stringify({
10809
11077
  schemaVersion: CURRENT_OPENPACK_SCHEMA_VERSION,
10810
11078
  name: `mcp-registry/${server.serverName}`,
@@ -10834,9 +11102,9 @@ function cachePathFor3(serverName, cacheRoot) {
10834
11102
  // src/source/skillkit.ts
10835
11103
  init_cache_identity();
10836
11104
  init_fs();
10837
- import { createHash as createHash14, randomUUID as randomUUID4 } from "crypto";
11105
+ import { createHash as createHash14, randomUUID as randomUUID5 } from "crypto";
10838
11106
  import { execFile as execFile6 } from "child_process";
10839
- import { cp as cp3, mkdir as mkdir18, readFile as readFile28, rename as rename7, rm as rm11 } from "fs/promises";
11107
+ import { cp as cp3, mkdir as mkdir19, readFile as readFile28, rename as rename7, rm as rm11 } from "fs/promises";
10840
11108
  import { homedir as homedir8 } from "os";
10841
11109
  import { basename as basename14, dirname as dirname23, join as join34, resolve as resolve21 } from "path";
10842
11110
  import { promisify as promisify6 } from "util";
@@ -10844,7 +11112,7 @@ import * as defaultSkillKit from "@skillkit/core";
10844
11112
 
10845
11113
  // src/source/skill-artifacts.ts
10846
11114
  init_fs();
10847
- import { readdir as readdir7, stat as stat8 } from "fs/promises";
11115
+ import { readdir as readdir8, stat as stat8 } from "fs/promises";
10848
11116
  import { basename as basename13, dirname as dirname22, extname as extname2, join as join33 } from "path";
10849
11117
  async function artifactsFromSkillPaths(paths, packageName) {
10850
11118
  const artifacts = [];
@@ -10912,7 +11180,7 @@ async function artifactFromSkillPath(item, packageName) {
10912
11180
  }
10913
11181
  async function walk(dir, paths) {
10914
11182
  if (!await pathExists(dir)) return;
10915
- const entries = await readdir7(dir, { withFileTypes: true });
11183
+ const entries = await readdir8(dir, { withFileTypes: true });
10916
11184
  if (entries.some((entry) => entry.isFile() && entry.name === "SKILL.md")) {
10917
11185
  paths.push({ path: dir });
10918
11186
  return;
@@ -11015,8 +11283,8 @@ var SkillKitSourceDriver = class {
11015
11283
  if (immutablePath && await pathExists(immutablePath)) {
11016
11284
  return { path: immutablePath, commit: requestedCommit, cacheIdentity: requestedCommit };
11017
11285
  }
11018
- await mkdir18(dirname23(specCachePath), { recursive: true });
11019
- const candidatePath = `${specCachePath}.agentwheel-tmp-${process.pid}-${randomUUID4()}`;
11286
+ await mkdir19(dirname23(specCachePath), { recursive: true });
11287
+ const candidatePath = `${specCachePath}.agentwheel-tmp-${process.pid}-${randomUUID5()}`;
11020
11288
  const publishPath = `${candidatePath}.publish`;
11021
11289
  let result;
11022
11290
  try {
@@ -11171,7 +11439,7 @@ async function checkoutCommit(root, commit) {
11171
11439
  // src/source/vercel-skills.ts
11172
11440
  init_fs();
11173
11441
  import { stat as stat9 } from "fs/promises";
11174
- import { basename as basename15, join as join35, relative as relative10, resolve as resolve22 } from "path";
11442
+ import { basename as basename15, join as join35, relative as relative11, resolve as resolve22 } from "path";
11175
11443
  var VercelSkillsSourceDriver = class {
11176
11444
  name = "vercel-skills";
11177
11445
  git = new GitSourceDriver();
@@ -11238,7 +11506,7 @@ async function resolveVercelSkillSubpath(root, subpath) {
11238
11506
  for (const candidate of candidates) {
11239
11507
  if (await pathExists(candidate)) return candidate;
11240
11508
  }
11241
- const tried = candidates.map((candidate) => relative10(root, candidate)).join(", ");
11509
+ const tried = candidates.map((candidate) => relative11(root, candidate)).join(", ");
11242
11510
  throw new Error(`Vercel skills subpath not found: ${subpath} (tried ${tried})`);
11243
11511
  }
11244
11512
  function parseVercelSource(source) {
@@ -11307,8 +11575,8 @@ function getSourceDriver(name = "local") {
11307
11575
  init_identify();
11308
11576
 
11309
11577
  // src/staging/staging.ts
11310
- import { chmod as chmod3, cp as cp5, mkdir as mkdir21, mkdtemp as mkdtemp4, readdir as readdir10, stat as stat12 } from "fs/promises";
11311
- import { basename as basename19, dirname as dirname27, join as join39, relative as relative12, resolve as resolve25, sep as sep7 } from "path";
11578
+ import { chmod as chmod3, cp as cp5, mkdir as mkdir22, mkdtemp as mkdtemp4, readdir as readdir11, stat as stat12 } from "fs/promises";
11579
+ import { basename as basename19, dirname as dirname27, join as join39, relative as relative13, resolve as resolve25, sep as sep8 } from "path";
11312
11580
  import { tmpdir as tmpdir5 } from "os";
11313
11581
  init_fs();
11314
11582
 
@@ -11316,8 +11584,8 @@ init_fs();
11316
11584
  init_artifact();
11317
11585
  init_fs();
11318
11586
  import { createHash as createHash15 } from "crypto";
11319
- import { readdir as readdir8, readFile as readFile29, stat as stat10, writeFile as writeFile19 } from "fs/promises";
11320
- import { basename as basename16, dirname as dirname24, extname as extname3, join as join36, relative as relative11, resolve as resolve24, sep as sep6 } from "path";
11587
+ import { readdir as readdir9, readFile as readFile29, stat as stat10, writeFile as writeFile19 } from "fs/promises";
11588
+ import { basename as basename16, dirname as dirname24, extname as extname3, join as join36, relative as relative12, resolve as resolve24, sep as sep7 } from "path";
11321
11589
  var includePattern = /<!--\s*openpack:include(\?)?\s+([^>]+?)\s*-->/g;
11322
11590
  var escapedIncludePattern = /<!--\s*openpack\\:include(\?)?\s+([^>]+?)\s*-->/g;
11323
11591
  var generatedPattern = /<!--\s*(?:BEGIN|END)\s+openpack:include\b/;
@@ -11527,7 +11795,7 @@ function extractOpenPackIncludeSelectors(content) {
11527
11795
  function resolvePackageSelector(packageRoot, selector) {
11528
11796
  const root = resolve24(packageRoot);
11529
11797
  const resolved = resolve24(root, selector);
11530
- if (resolved !== root && !resolved.startsWith(`${root}${sep6}`)) {
11798
+ if (resolved !== root && !resolved.startsWith(`${root}${sep7}`)) {
11531
11799
  throw new Error(`OpenPack include escapes package root: ${selector}`);
11532
11800
  }
11533
11801
  return resolved;
@@ -11542,7 +11810,7 @@ async function markdownFilesForArtifact(artifact) {
11542
11810
  async function listMarkdownFiles(root) {
11543
11811
  const out = [];
11544
11812
  async function walk2(dir) {
11545
- for (const entry of (await readdir8(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
11813
+ for (const entry of (await readdir9(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
11546
11814
  const full = join36(dir, entry.name);
11547
11815
  if (entry.isDirectory()) {
11548
11816
  await walk2(full);
@@ -11578,7 +11846,7 @@ function applyReplacements(content, replacements) {
11578
11846
  return out + content.slice(cursor);
11579
11847
  }
11580
11848
  function relativeSelector(root, file) {
11581
- return relative11(root, file).replaceAll("\\", "/");
11849
+ return relative12(root, file).replaceAll("\\", "/");
11582
11850
  }
11583
11851
  function ownerSelector(root, file, nodeId) {
11584
11852
  const selector = relativeSelector(root, file);
@@ -11608,7 +11876,7 @@ function artifactPathMap(artifacts) {
11608
11876
 
11609
11877
  // src/staging/customize.ts
11610
11878
  init_fs();
11611
- import { cp as cp4, mkdir as mkdir19, readdir as readdir9, readFile as readFile30, writeFile as writeFile20 } from "fs/promises";
11879
+ import { cp as cp4, mkdir as mkdir20, readdir as readdir10, readFile as readFile30, writeFile as writeFile20 } from "fs/promises";
11612
11880
  import { dirname as dirname25, join as join37 } from "path";
11613
11881
  async function applyCustomizations(artifacts, options) {
11614
11882
  let next = [...artifacts];
@@ -11633,7 +11901,7 @@ async function applyInstructionOverlay(artifacts, options) {
11633
11901
  const managed = await readFile30(artifact.stagedPath ?? artifact.sourcePath, "utf8");
11634
11902
  const local = await readFile30(overlayPath, "utf8");
11635
11903
  const composedPath = join37(options.stageRoot, ".agentwheel-composed", "instructions", "AGENTS.md");
11636
- await mkdir19(dirname25(composedPath), { recursive: true });
11904
+ await mkdir20(dirname25(composedPath), { recursive: true });
11637
11905
  await writeFile20(
11638
11906
  composedPath,
11639
11907
  [
@@ -11706,7 +11974,7 @@ async function applyReplacements2(artifacts, options, channel, artifactTypes) {
11706
11974
  const artifactKind = entry.isDirectory() ? "dir" : "file";
11707
11975
  const existing = byKey.get(artifactMapKey);
11708
11976
  const stagedPath = join37(options.stageRoot, ".agentwheel-composed", channel, type, entry.name);
11709
- await mkdir19(dirname25(stagedPath), { recursive: true });
11977
+ await mkdir20(dirname25(stagedPath), { recursive: true });
11710
11978
  await cp4(full, stagedPath, { recursive: artifactKind === "dir", dereference: true });
11711
11979
  byKey.set(artifactMapKey, {
11712
11980
  ...existing,
@@ -11746,12 +12014,12 @@ function installableArtifactTypes() {
11746
12014
  return ["instructions", "rules", "skills", "commands", "subagents", "mcp", "hooks", "settings", "plugins"];
11747
12015
  }
11748
12016
  async function sortedDirEntries2(path) {
11749
- return (await readdir9(path, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
12017
+ return (await readdir10(path, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
11750
12018
  }
11751
12019
 
11752
12020
  // src/staging/claude-subagents.ts
11753
12021
  init_fs();
11754
- import { mkdir as mkdir20, readFile as readFile31, writeFile as writeFile21 } from "fs/promises";
12022
+ import { mkdir as mkdir21, readFile as readFile31, writeFile as writeFile21 } from "fs/promises";
11755
12023
  import { basename as basename18, dirname as dirname26, join as join38 } from "path";
11756
12024
  async function renderClaudeSubagents(artifacts, stageRoot, adapter) {
11757
12025
  if (adapter?.name !== "claude") return artifacts;
@@ -11783,7 +12051,7 @@ async function renderClaudeSubagent(artifact, stageRoot) {
11783
12051
  }
11784
12052
  const content = await readFile31(markdownPath, "utf8");
11785
12053
  const renderedPath = join38(stageRoot, ".agentwheel-rendered", "claude-subagents", `${agentName}.md`);
11786
- await mkdir20(dirname26(renderedPath), { recursive: true });
12054
+ await mkdir21(dirname26(renderedPath), { recursive: true });
11787
12055
  await writeFile21(renderedPath, content.endsWith("\n") ? content : `${content}
11788
12056
  `, "utf8");
11789
12057
  return {
@@ -11802,6 +12070,7 @@ function claudeAgentName(artifact) {
11802
12070
  }
11803
12071
 
11804
12072
  // src/staging/staging.ts
12073
+ init_selection();
11805
12074
  async function stageSource(driver, source, options = {}) {
11806
12075
  const raw = await stageSourceRaw(driver, source, options);
11807
12076
  return removeOnFailure(raw.root, () => renderStagedBundle(raw, options));
@@ -11825,7 +12094,7 @@ async function stageResolvedArtifactsRaw(resolved, artifacts, parentDir = tmpdir
11825
12094
  await removeOnFailure(root, async () => {
11826
12095
  for (const artifact of artifacts) {
11827
12096
  const stagedPath = join39(root, artifact.relativePath);
11828
- await mkdir21(dirname27(stagedPath), { recursive: true });
12097
+ await mkdir22(dirname27(stagedPath), { recursive: true });
11829
12098
  await cp5(artifact.sourcePath, stagedPath, {
11830
12099
  recursive: artifact.kind === "dir",
11831
12100
  dereference: true,
@@ -11922,7 +12191,7 @@ async function copyAsset(asset, source, dest) {
11922
12191
  const sourceStats = await stat12(source);
11923
12192
  if (sourceStats.isFile()) {
11924
12193
  if (matchesAny(basename19(source), asset.include)) {
11925
- await mkdir21(dest, { recursive: true });
12194
+ await mkdir22(dest, { recursive: true });
11926
12195
  await copyAssetFile(source, join39(dest, basename19(source)), asset);
11927
12196
  }
11928
12197
  return;
@@ -11931,26 +12200,26 @@ async function copyAsset(asset, source, dest) {
11931
12200
  throw new Error(`Asset include source is not a file or directory: ${source}`);
11932
12201
  }
11933
12202
  if (!asset.include?.length) {
11934
- await mkdir21(dirname27(dest), { recursive: true });
12203
+ await mkdir22(dirname27(dest), { recursive: true });
11935
12204
  await cp5(source, dest, { recursive: true, dereference: true });
11936
12205
  if (asset.mode === "copy") await normalizeCopiedModes(dest);
11937
12206
  return;
11938
12207
  }
11939
12208
  for (const file of await listFiles2(source)) {
11940
- const rel = relative12(source, file).replaceAll("\\", "/");
12209
+ const rel = relative13(source, file).replaceAll("\\", "/");
11941
12210
  if (!matchesAny(rel, asset.include) && !matchesAny(basename19(file), asset.include)) continue;
11942
12211
  await copyAssetFile(file, join39(dest, rel), asset);
11943
12212
  }
11944
12213
  }
11945
12214
  async function copyAssetFile(source, dest, asset) {
11946
- await mkdir21(dirname27(dest), { recursive: true });
12215
+ await mkdir22(dirname27(dest), { recursive: true });
11947
12216
  await cp5(source, dest, { dereference: true });
11948
12217
  if (asset.mode === "copy") await chmod3(dest, 420);
11949
12218
  }
11950
12219
  function resolvePackagePath(packageRoot, path) {
11951
12220
  const resolved = resolve25(packageRoot, path);
11952
12221
  const root = resolve25(packageRoot);
11953
- if (resolved !== root && !resolved.startsWith(`${root}${sep7}`)) {
12222
+ if (resolved !== root && !resolved.startsWith(`${root}${sep8}`)) {
11954
12223
  throw new Error(`Asset include escapes package root: ${path}`);
11955
12224
  }
11956
12225
  return resolved;
@@ -11958,7 +12227,7 @@ function resolvePackagePath(packageRoot, path) {
11958
12227
  async function listFiles2(root) {
11959
12228
  const out = [];
11960
12229
  async function walk2(dir) {
11961
- for (const entry of (await readdir10(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
12230
+ for (const entry of (await readdir11(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
11962
12231
  const full = join39(dir, entry.name);
11963
12232
  if (entry.isDirectory()) {
11964
12233
  await walk2(full);
@@ -11977,7 +12246,7 @@ async function normalizeCopiedModes(path) {
11977
12246
  return;
11978
12247
  }
11979
12248
  if (!stats.isDirectory()) return;
11980
- for (const entry of await readdir10(path, { withFileTypes: true })) {
12249
+ for (const entry of await readdir11(path, { withFileTypes: true })) {
11981
12250
  await normalizeCopiedModes(join39(path, entry.name));
11982
12251
  }
11983
12252
  }
@@ -11998,22 +12267,24 @@ init_adapters();
11998
12267
  init_adapter();
11999
12268
  init_artifact();
12000
12269
  init_workspace();
12001
- import { appendFile, cp as cp6, lstat as lstat2, mkdir as mkdir22, readdir as readdir12, rm as rm13 } from "fs/promises";
12002
- import { dirname as dirname29, join as join42, relative as relative13 } from "path";
12270
+ import { appendFile, cp as cp6, lstat as lstat3, mkdir as mkdir23, readdir as readdir13, rm as rm13 } from "fs/promises";
12271
+ import { dirname as dirname29, join as join42, relative as relative14 } from "path";
12003
12272
 
12004
12273
  // src/resolve/graph.ts
12005
12274
  import { createHash as createHash17 } from "crypto";
12006
- import { readdir as readdir11, readFile as readFile34, stat as stat14 } from "fs/promises";
12275
+ import { readdir as readdir12, readFile as readFile34, stat as stat14 } from "fs/promises";
12007
12276
  import { basename as basename20, extname as extname4, join as join41 } from "path";
12008
12277
  init_artifact();
12009
12278
  init_fs();
12279
+ init_selection();
12010
12280
 
12011
12281
  // src/model/workspace-composition.ts
12012
12282
  init_workspace();
12283
+ init_selection();
12284
+ init_fs();
12013
12285
  import { createHash as createHash16 } from "crypto";
12014
12286
  import { readFile as readFile32 } from "fs/promises";
12015
12287
  import { z as z12 } from "zod";
12016
- init_fs();
12017
12288
  var selectionSourceConfigSchema = z12.object({
12018
12289
  schemaVersion: z12.literal(2),
12019
12290
  exports: workspaceExportsSchema
@@ -12172,6 +12443,7 @@ var registryCacheSchema = z13.object({
12172
12443
  });
12173
12444
 
12174
12445
  // src/registry/client.ts
12446
+ init_selection();
12175
12447
  init_workspace();
12176
12448
  init_fs();
12177
12449
  var DEFAULT_REGISTRY_SOURCE = "github:NestDevLab/agentwheel-registry";
@@ -13075,7 +13347,7 @@ async function markdownFilesForArtifact2(artifact) {
13075
13347
  async function listMarkdownFiles2(root) {
13076
13348
  const out = [];
13077
13349
  async function walk2(dir) {
13078
- for (const entry of (await readdir11(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
13350
+ for (const entry of (await readdir12(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
13079
13351
  const full = join41(dir, entry.name);
13080
13352
  if (entry.isDirectory()) {
13081
13353
  await walk2(full);
@@ -13257,8 +13529,8 @@ function verifyIntegrity(integrity, sourceHash, label) {
13257
13529
  async function withCachePathLock(path, fn) {
13258
13530
  const previous = cacheLocks.get(path) ?? Promise.resolve();
13259
13531
  let release = () => void 0;
13260
- const current = previous.then(() => new Promise((resolve44) => {
13261
- release = resolve44;
13532
+ const current = previous.then(() => new Promise((resolve45) => {
13533
+ release = resolve45;
13262
13534
  }));
13263
13535
  cacheLocks.set(path, current);
13264
13536
  await previous;
@@ -13339,8 +13611,8 @@ function detectDirectCollisions(nodes) {
13339
13611
  }
13340
13612
  }
13341
13613
  function graphNodeId(name, version, normalizedSource, resolvedCommit, sourceHash) {
13342
- const digest2 = createHash17("sha256").update(normalizedSource).update("\0").update(resolvedCommit ?? sourceHash).digest("hex").slice(0, 12);
13343
- return `${name}@${version}+${digest2}`;
13614
+ const digest3 = createHash17("sha256").update(normalizedSource).update("\0").update(resolvedCommit ?? sourceHash).digest("hex").slice(0, 12);
13615
+ return `${name}@${version}+${digest3}`;
13344
13616
  }
13345
13617
  function sortedUnique4(values) {
13346
13618
  return [...new Set(values)].sort((a, b) => a.localeCompare(b));
@@ -13382,7 +13654,7 @@ init_declarations();
13382
13654
  async function remember(workspaceRoot, runtime, text) {
13383
13655
  const overlayPath = join42(workspaceRoot, ".agentwheel", "overlays", runtime, "instructions.local.md");
13384
13656
  declareMutationPath(overlayPath);
13385
- await mkdir22(dirname29(overlayPath), { recursive: true });
13657
+ await mkdir23(dirname29(overlayPath), { recursive: true });
13386
13658
  await appendFile(overlayPath, `${text.trim()}
13387
13659
  `, "utf8");
13388
13660
  return { overlayPath };
@@ -13410,12 +13682,12 @@ async function ejectArtifact(workspaceRoot, item) {
13410
13682
  for (const path of await listFilesIfPresent(ejectedPath)) declareMutationPath(path);
13411
13683
  if (artifact.kind === "dir") {
13412
13684
  for (const sourceFile of await listFiles3(sourcePath)) {
13413
- declareMutationPath(join42(ejectedPath, relative13(sourcePath, sourceFile)));
13685
+ declareMutationPath(join42(ejectedPath, relative14(sourcePath, sourceFile)));
13414
13686
  }
13415
13687
  } else {
13416
13688
  declareMutationPath(ejectedPath);
13417
13689
  }
13418
- await mkdir22(dirname29(ejectedPath), { recursive: true });
13690
+ await mkdir23(dirname29(ejectedPath), { recursive: true });
13419
13691
  await rm13(ejectedPath, { recursive: true, force: true });
13420
13692
  await cp6(sourcePath, ejectedPath, { recursive: artifact.kind === "dir", dereference: true });
13421
13693
  return {
@@ -13431,11 +13703,11 @@ async function ejectArtifact(workspaceRoot, item) {
13431
13703
  }
13432
13704
  }
13433
13705
  async function listFiles3(root) {
13434
- const stats = await lstat2(root);
13706
+ const stats = await lstat3(root);
13435
13707
  if (stats.isFile()) return [root];
13436
13708
  const files = [];
13437
13709
  async function walk2(dir) {
13438
- for (const entry of await readdir12(dir, { withFileTypes: true })) {
13710
+ for (const entry of await readdir13(dir, { withFileTypes: true })) {
13439
13711
  const path = join42(dir, entry.name);
13440
13712
  if (entry.isDirectory()) await walk2(path);
13441
13713
  else files.push(path);
@@ -13533,7 +13805,7 @@ init_adapter();
13533
13805
  init_adapter();
13534
13806
  init_graph_lock();
13535
13807
  import { createHash as createHash19 } from "crypto";
13536
- import { mkdir as mkdir24, readdir as readdir13 } from "fs/promises";
13808
+ import { mkdir as mkdir25, readdir as readdir14 } from "fs/promises";
13537
13809
  import { basename as basename21, dirname as dirname31, join as join45, posix as posix6, resolve as resolve31 } from "path";
13538
13810
  init_paths();
13539
13811
  init_merge_removal();
@@ -13674,8 +13946,8 @@ function formatNamespace(decision) {
13674
13946
  function formatOverride(decision) {
13675
13947
  return `${decision.graphNodeId}:${decision.type}/${decision.name} replaces ${decision.overriddenGraphNodeId}:${decision.type}/${decision.name} via ${decision.rootId} (${decision.selector})`;
13676
13948
  }
13677
- function short(hash) {
13678
- return hash.slice(0, 12);
13949
+ function short(hash2) {
13950
+ return hash2.slice(0, 12);
13679
13951
  }
13680
13952
  function selectionImportKey(root) {
13681
13953
  const selection = root.selectionImport;
@@ -13699,6 +13971,7 @@ function formatSelectionImport(root) {
13699
13971
  }
13700
13972
 
13701
13973
  // src/resolve/render.ts
13974
+ init_selection();
13702
13975
  import { createHash as createHash18 } from "crypto";
13703
13976
  import { readFile as readFile35, mkdtemp as mkdtemp5 } from "fs/promises";
13704
13977
  import { tmpdir as tmpdir6 } from "os";
@@ -14215,7 +14488,7 @@ init_fs();
14215
14488
 
14216
14489
  // src/lifecycle/trust.ts
14217
14490
  init_fs();
14218
- import { mkdir as mkdir23, readFile as readFile36 } from "fs/promises";
14491
+ import { mkdir as mkdir24, readFile as readFile36 } from "fs/promises";
14219
14492
  import { homedir as homedir12 } from "os";
14220
14493
  import { dirname as dirname30, join as join44 } from "path";
14221
14494
  import { z as z14 } from "zod";
@@ -14294,7 +14567,7 @@ async function readTrustStore(path) {
14294
14567
  return trustStoreSchema.parse(JSON.parse(await readFile36(path, "utf8")));
14295
14568
  }
14296
14569
  async function writeTrustStore(path, store) {
14297
- await mkdir23(dirname30(path), { recursive: true });
14570
+ await mkdir24(dirname30(path), { recursive: true });
14298
14571
  await writeJsonAtomic(path, trustStoreSchema.parse(store));
14299
14572
  }
14300
14573
  function defaultTrustStorePath() {
@@ -14303,6 +14576,7 @@ function defaultTrustStorePath() {
14303
14576
 
14304
14577
  // src/lifecycle/source-plan.ts
14305
14578
  init_workspace();
14579
+ init_selection();
14306
14580
 
14307
14581
  // src/model/workspace-owner.ts
14308
14582
  import { Buffer as Buffer2 } from "buffer";
@@ -14422,9 +14696,9 @@ async function createExactMcpRetirementPlan(desiredArtifacts, adapter, targetRoo
14422
14696
  init_fs();
14423
14697
  init_declarations();
14424
14698
  init_workspace();
14425
- import { lstat as lstat3, readFile as readFile37, realpath as realpath2 } from "fs/promises";
14699
+ import { lstat as lstat4, readFile as readFile37, realpath as realpath2 } from "fs/promises";
14426
14700
  import { homedir as homedir13 } from "os";
14427
- import { isAbsolute as isAbsolute10, relative as relative14, resolve as resolve29 } from "path";
14701
+ import { isAbsolute as isAbsolute10, relative as relative15, resolve as resolve29 } from "path";
14428
14702
  async function resolveWorkspaceScope(request = {}) {
14429
14703
  const selected = [request.user === true, request.local === true, request.fleet !== void 0].filter(Boolean).length;
14430
14704
  if (selected > 1) {
@@ -14562,7 +14836,7 @@ function assertFleetContract(id, registration, config) {
14562
14836
  async function assertCanonicalDirectory(input, label) {
14563
14837
  const canonical = await canonicalizeDirectory(input, label);
14564
14838
  const normalized = resolve29(input);
14565
- const stats = await lstat3(input);
14839
+ const stats = await lstat4(input);
14566
14840
  if (stats.isSymbolicLink() || canonical !== normalized || input !== normalized) {
14567
14841
  throw new Error(`${label} must be canonical and symlink-unambiguous: ${input} resolves to ${canonical}.`);
14568
14842
  }
@@ -14576,7 +14850,7 @@ async function canonicalizeDirectory(input, label) {
14576
14850
  } catch {
14577
14851
  throw new Error(`${label} does not exist: ${input}`);
14578
14852
  }
14579
- const stats = await lstat3(canonical);
14853
+ const stats = await lstat4(canonical);
14580
14854
  if (!stats.isDirectory()) throw new Error(`${label} is not a directory: ${input}`);
14581
14855
  return canonical;
14582
14856
  }
@@ -14596,7 +14870,7 @@ function sortedUnique6(values) {
14596
14870
  return [...new Set(values.map((value) => value.trim()).filter(Boolean))].sort((a, b) => a.localeCompare(b));
14597
14871
  }
14598
14872
  function containsPath(parent, candidate) {
14599
- const path = relative14(parent, candidate);
14873
+ const path = relative15(parent, candidate);
14600
14874
  return path === "" || !path.startsWith("..") && !isAbsolute10(path);
14601
14875
  }
14602
14876
 
@@ -15117,7 +15391,7 @@ async function discoverLegacyStateCandidates(options) {
15117
15391
  const directory = dirname31(options.graphLockPath);
15118
15392
  let names;
15119
15393
  try {
15120
- names = await readdir13(directory);
15394
+ names = await readdir14(directory);
15121
15395
  } catch (error) {
15122
15396
  if (error.code === "ENOENT") return [];
15123
15397
  throw error;
@@ -15553,7 +15827,7 @@ import { basename as basename22, dirname as dirname32, join as join47, resolve a
15553
15827
  // src/transport/run-as-identity.ts
15554
15828
  import { execFileSync } from "child_process";
15555
15829
  import { lstatSync, realpathSync as realpathSync2 } from "fs";
15556
- import { isAbsolute as isAbsolute11, join as join46, parse as parse5, resolve as resolve32, sep as sep8 } from "path";
15830
+ import { isAbsolute as isAbsolute11, join as join46, parse as parse5, resolve as resolve32, sep as sep9 } from "path";
15557
15831
  function resolveRunAsIdentity(user, root, getent = (name) => execFileSync("/usr/bin/getent", ["passwd", name], { encoding: "utf8" })) {
15558
15832
  if (!/^[a-z_][a-z0-9_-]*[$]?$/i.test(user) || user === "root") {
15559
15833
  throw new Error(`Invalid local run-as account '${user}'.`);
@@ -15575,19 +15849,19 @@ function resolveRunAsIdentity(user, root, getent = (name) => execFileSync("/usr/
15575
15849
  if (!Number.isSafeInteger(uid) || uid <= 0 || !Number.isSafeInteger(gid) || gid < 0 || !isAbsolute11(home) || resolve32(home) !== home) {
15576
15850
  throw new Error(`Invalid UID, GID or home for local run-as account '${user}'.`);
15577
15851
  }
15578
- assertNoSymlinkPath(home);
15852
+ assertNoSymlinkPath2(home);
15579
15853
  if (realpathSync2(home) !== home || !lstatSync(home).isDirectory()) {
15580
15854
  throw new Error(`Local run-as home ${home} must be a real directory.`);
15581
15855
  }
15582
- assertNoSymlinkPath(root);
15856
+ assertNoSymlinkPath2(root);
15583
15857
  if (realpathSync2(root) !== root || !lstatSync(root).isDirectory() || lstatSync(root).uid !== uid) {
15584
15858
  throw new Error(`Local run-as root ${root} must be a real directory owned by UID ${uid}.`);
15585
15859
  }
15586
15860
  return { user, uid, gid, home, root };
15587
15861
  }
15588
- function assertNoSymlinkPath(path) {
15862
+ function assertNoSymlinkPath2(path) {
15589
15863
  let current = parse5(path).root;
15590
- for (const part of path.slice(current.length).split(sep8).filter(Boolean)) {
15864
+ for (const part of path.slice(current.length).split(sep9).filter(Boolean)) {
15591
15865
  current = join46(current, part);
15592
15866
  if (lstatSync(current).isSymbolicLink()) throw new Error(`Local run-as root contains a symlink: ${current}`);
15593
15867
  }
@@ -15773,6 +16047,7 @@ function runtimeScanRoot(request) {
15773
16047
  // src/lifecycle/profile.ts
15774
16048
  init_identify();
15775
16049
  init_transport();
16050
+ init_selection();
15776
16051
  init_declarations();
15777
16052
  async function syncProfile(options) {
15778
16053
  const config = await readMergedWorkspaceConfig(options.workspaceRoot);
@@ -15930,6 +16205,7 @@ function combinedSuggestionAliases(packageAliases, optionAliases) {
15930
16205
  }
15931
16206
 
15932
16207
  // src/registry/publish.ts
16208
+ init_selection();
15933
16209
  var DEFAULT_REGISTRY_SUBMISSION_URL = "https://github.com/NestDevLab/agentwheel-registry/issues/new";
15934
16210
  var registryEntryTypes = ["package", "skill", "plugin", "mcp", "adapter"];
15935
16211
  var explicitSourcePrefixes = ["github:", "git:", "skillkit:", "vercel:", "mcp-registry:", "clawhub:"];
@@ -16093,8 +16369,11 @@ function shellQuoteArg(value) {
16093
16369
  return `'${value.replaceAll("'", `'"'"'`)}'`;
16094
16370
  }
16095
16371
 
16372
+ // src/cli/index.ts
16373
+ init_selection();
16374
+
16096
16375
  // src/cli/update-check.ts
16097
- import { mkdir as mkdir25, readFile as readFile38, writeFile as writeFile22 } from "fs/promises";
16376
+ import { mkdir as mkdir26, readFile as readFile38, writeFile as writeFile22 } from "fs/promises";
16098
16377
  import { homedir as homedir14 } from "os";
16099
16378
  import { dirname as dirname33, join as join48 } from "path";
16100
16379
  var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
@@ -16149,7 +16428,7 @@ async function readCache(path) {
16149
16428
  }
16150
16429
  }
16151
16430
  async function writeCache(path, cache) {
16152
- await mkdir25(dirname33(path), { recursive: true });
16431
+ await mkdir26(dirname33(path), { recursive: true });
16153
16432
  await writeFile22(path, `${JSON.stringify(cache, null, 2)}
16154
16433
  `, "utf8");
16155
16434
  }
@@ -16593,6 +16872,7 @@ init_manifest2();
16593
16872
  init_apply();
16594
16873
  init_paths();
16595
16874
  init_transaction();
16875
+ init_selection();
16596
16876
  import { createHash as createHash20 } from "crypto";
16597
16877
  import { resolve as resolve37 } from "path";
16598
16878
  init_declarations();
@@ -16872,14 +17152,222 @@ function canonicalJson6(value) {
16872
17152
  return `{${Object.keys(record).filter((key) => record[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson6(record[key])}`).join(",")}}`;
16873
17153
  }
16874
17154
 
17155
+ // src/lifecycle/ownership-release.ts
17156
+ init_apply();
17157
+ init_manifest2();
17158
+ init_paths();
17159
+ init_transaction();
17160
+ import { createHash as createHash21, randomUUID as randomUUID6 } from "crypto";
17161
+ import { lstat as lstat5 } from "fs/promises";
17162
+ import { join as join52, resolve as resolve38 } from "path";
17163
+ init_coordinator();
17164
+ init_declarations();
17165
+ init_protocol();
17166
+ init_repository();
17167
+ init_process();
17168
+ init_transport();
17169
+ async function planReleaseOwnership(request) {
17170
+ return observe2(request);
17171
+ }
17172
+ async function applyReleaseOwnership(request) {
17173
+ for (const [name, value] of Object.entries({
17174
+ planDigest: request.planDigest,
17175
+ expectedSourceRevision: request.expectedSourceRevision,
17176
+ expectedInventoryRevision: request.expectedInventoryRevision
17177
+ })) {
17178
+ if (!value || !/^[a-f0-9]{64}$/.test(value)) throw new Error(`Reviewed SHA-256 ${name} is required to release a claim.`);
17179
+ }
17180
+ const workspaceRoot = resolve38(request.workspaceRoot);
17181
+ const existing = activeMutationMetadata();
17182
+ if (existing && (resolve38(existing.workspaceRoot) !== workspaceRoot || existing.reason !== request.reason.replace(/\r\n?/gu, "\n").trim() || request.operationId && request.operationId !== existing.operationId)) {
17183
+ throw new Error("Ownership release does not match the active governed workspace, reason or operation.");
17184
+ }
17185
+ const operationId = mutationOperationIdSchema.parse(existing?.operationId ?? request.operationId ?? randomUUID6());
17186
+ const auditPath = join52(workspaceRoot, ".agentwheel", "ownership-releases", `${operationId}.json`);
17187
+ const mutation = existing ? void 0 : await GovernedMutation.begin({
17188
+ workspaceRoot,
17189
+ commandName: "agentwheel ownership release-claim",
17190
+ reason: request.reason,
17191
+ operationId,
17192
+ noCommit: request.noCommit,
17193
+ globalRoot: request.globalRoot,
17194
+ anticipatedPaths: [auditPath]
17195
+ });
17196
+ try {
17197
+ if ((existing ?? mutation?.metadata())?.revisionMode === "commit-after-verify") {
17198
+ const repository = await discoverGitRepository(workspaceRoot);
17199
+ if (!repository) throw new Error("Ownership release requires a declarative Git audit path.");
17200
+ const ignored = await runProcess("git", ["-C", repository.root, "check-ignore", "--no-index", "--", auditPath], { allowExitCodes: [0, 1] });
17201
+ if (ignored.exitCode === 0) {
17202
+ throw new Error("Ownership release audit path is Git-ignored; explicitly declare it in repository policy before releasing a claim.");
17203
+ }
17204
+ }
17205
+ const result = await applyLocked(request, operationId, auditPath);
17206
+ await mutation?.complete();
17207
+ return result;
17208
+ } catch (error) {
17209
+ await mutation?.fail(error);
17210
+ throw error;
17211
+ }
17212
+ }
17213
+ async function applyLocked(request, operationId, auditPath) {
17214
+ const transport = request.transport ?? localTransport;
17215
+ if (transport.kind !== "local") throw new Error("Ownership release supports local targets only.");
17216
+ await assertNoSymlinkPath(join52(resolve38(request.targetRoot), ".agentwheel"));
17217
+ await assertNoSymlinkPath(auditPath);
17218
+ const lock = await acquireApplyLock(resolve38(request.targetRoot), request.adapter, transport, {}, {
17219
+ installationType: request.installationType,
17220
+ stateKey: request.stateKey
17221
+ });
17222
+ try {
17223
+ if ((await listAllApplyJournals(request.targetRoot, void 0, transport)).length) {
17224
+ throw new Error("Ownership release refuses pending runtime journals; recover them first.");
17225
+ }
17226
+ const plan = await observe2(request);
17227
+ if (plan.planDigest !== request.planDigest || plan.source.revision !== request.expectedSourceRevision || plan.manifestInventoryRevision !== request.expectedInventoryRevision) {
17228
+ throw new Error("Stale ownership release plan, manifest or inventory; replan required.");
17229
+ }
17230
+ if (await transport.pathExists(auditPath)) throw new Error(`Ownership release audit already exists: ${auditPath}`);
17231
+ declareMutationPath(auditPath);
17232
+ declareMutationPath(plan.source.manifestPath);
17233
+ const manifest = await readInstallManifest(plan.targetRoot, plan.adapter, transport, {
17234
+ installationType: plan.installationType,
17235
+ stateKey: plan.source.stateKey
17236
+ });
17237
+ if (!manifest || manifest.version !== 2 || manifest.revision !== plan.source.revision) {
17238
+ throw new Error("Source manifest changed after selection; replan required.");
17239
+ }
17240
+ const now = (/* @__PURE__ */ new Date()).toISOString();
17241
+ const content = `${JSON.stringify({
17242
+ schemaVersion: 1,
17243
+ event: "ownership-release-intent",
17244
+ operationId,
17245
+ reason: plan.reason,
17246
+ reviewedPlanDigest: plan.planDigest,
17247
+ plan,
17248
+ // This immutable dossier records intent. The linked journal verifies completion separately.
17249
+ completion: "Verify install state and the governed mutation receipt; intent alone does not prove completion."
17250
+ }, null, 2)}
17251
+ `;
17252
+ const metadata = mutationMetadataForApplyJournal();
17253
+ const journal = {
17254
+ version: metadata ? 2 : 1,
17255
+ ...metadata ? { mutation: metadata } : {},
17256
+ mode: "uninstall",
17257
+ adapter: plan.adapter,
17258
+ installationType: plan.installationType,
17259
+ stateKey: plan.source.stateKey,
17260
+ targetRoot: plan.targetRoot,
17261
+ baseRevision: manifest.revision,
17262
+ createdAt: now,
17263
+ updatedAt: now,
17264
+ operations: [],
17265
+ completed: [],
17266
+ manifest: { ...manifest, entries: manifest.entries.filter((entry) => digest2(entry) !== plan.source.entryDigest) },
17267
+ metadataAudit: {
17268
+ kind: "ownership-release",
17269
+ workspaceRoot: plan.workspaceRoot,
17270
+ operationId,
17271
+ planDigest: plan.planDigest,
17272
+ inventory: plan.inventory,
17273
+ runtime: [{ path: plan.path, hash: plan.runtimeHash, snapshotDigest: plan.runtimeSnapshotDigest }],
17274
+ auditFiles: [{ path: `.agentwheel/ownership-releases/${operationId}.json`, content, sha256: hash(content) }]
17275
+ }
17276
+ };
17277
+ await writeApplyJournal(journal, transport);
17278
+ await commitManifestMetadataJournal(journal, transport);
17279
+ return { ...plan, applied: true, operationId, auditPath, retainedEntries: journal.manifest.entries.length };
17280
+ } finally {
17281
+ await lock.release();
17282
+ }
17283
+ }
17284
+ async function observe2(request) {
17285
+ const transport = request.transport ?? localTransport;
17286
+ if (transport.kind !== "local") throw new Error("Ownership release supports local targets only.");
17287
+ const targetRoot = resolve38(request.targetRoot);
17288
+ const workspaceRoot = resolve38(request.workspaceRoot);
17289
+ const reason = mutationReasonSchema.parse(request.reason.trim());
17290
+ if (!request.stateKey || stateKeyFor(request.adapter, { stateKey: request.stateKey }) !== request.stateKey || !request.installationType.trim() || !request.selector.includes("/")) {
17291
+ throw new Error("Ownership release requires an exact state key, installation type and type/name selector.");
17292
+ }
17293
+ const runtimePath = metadataRuntimePath(targetRoot, request.path);
17294
+ await assertNoSymlinkPath(workspaceRoot);
17295
+ await assertNoSymlinkPath(join52(targetRoot, ".agentwheel"));
17296
+ const manifests = await listInstallManifests(targetRoot, void 0, transport);
17297
+ for (const item of manifests) await assertNoSymlinkPath(item.path);
17298
+ const source = manifests.find((item) => item.stateKey === request.stateKey);
17299
+ const manifest = source?.manifest;
17300
+ if (!manifest || manifest.version !== 2 || manifest.adapter !== request.adapter || manifest.targetRoot !== targetRoot || manifest.installationType !== request.installationType || stateKeyFor(manifest.adapter, { stateKey: manifest.stateKey, installationType: manifest.installationType }) !== request.stateKey) {
17301
+ throw new Error("Source manifest does not prove the requested target, adapter, installation type and state key.");
17302
+ }
17303
+ const matches = manifest.entries.filter((entry2) => entry2.path === request.path && `${entry2.artifactType}/${entry2.artifactName}` === request.selector);
17304
+ if (matches.length !== 1) throw new Error(`Expected exactly one ownership claim at ${request.path} for ${request.selector}.`);
17305
+ const entry = matches[0];
17306
+ const owner = workspaceOwnerForRoot(request.fromWorkspaceRoot, request.fromFleetId);
17307
+ if (entry.workspaceOwner !== owner) throw new Error(`Workspace owner does not match the selected claim at ${entry.path}.`);
17308
+ if (entry.mergeStrategy || entry.mode || entry.semanticPlugin || entry.semanticCommand || entry.executed || entry.channel === "ejected") {
17309
+ throw new Error("Ownership release only supports plain file/directory claims; shared or semantic contributions are protected.");
17310
+ }
17311
+ for (const item of manifests) {
17312
+ for (const other of item.manifest.entries) {
17313
+ if (item === source && other === entry) continue;
17314
+ const otherPath = metadataRuntimePath(targetRoot, other.path);
17315
+ if (otherPath === runtimePath || otherPath.startsWith(`${runtimePath}/`) || runtimePath.startsWith(`${otherPath}/`)) {
17316
+ throw new Error(`Ambiguous or overlapping ownership claim at ${entry.path} in ${item.stateKey}.`);
17317
+ }
17318
+ }
17319
+ }
17320
+ const snapshotDigest = await ownershipRuntimeSnapshot(runtimePath);
17321
+ const runtimeKind = (await lstat5(runtimePath)).isDirectory() ? "dir" : "file";
17322
+ if (runtimeKind !== entry.kind) throw new Error("Selected runtime kind does not match the manifest claim.");
17323
+ const runtimeHash = await transport.hashPath(runtimePath);
17324
+ const inventory = manifests.map((item) => ({ stateKey: item.stateKey, revision: item.manifest.revision }));
17325
+ const plan = {
17326
+ adapter: request.adapter,
17327
+ installationType: request.installationType,
17328
+ targetRoot,
17329
+ workspaceRoot,
17330
+ owner,
17331
+ selector: request.selector,
17332
+ path: entry.path,
17333
+ source: {
17334
+ stateKey: request.stateKey,
17335
+ manifestPath: installManifestPath(targetRoot, request.adapter, { installationType: request.installationType, stateKey: request.stateKey }),
17336
+ revision: manifest.revision,
17337
+ entryDigest: digest2(entry),
17338
+ entry
17339
+ },
17340
+ recordedHash: entry.hash,
17341
+ runtimeHash,
17342
+ runtimeSnapshotDigest: snapshotDigest,
17343
+ manifestInventoryRevision: await computeInstallManifestInventoryRevision(targetRoot, void 0, transport),
17344
+ inventory,
17345
+ reason
17346
+ };
17347
+ return { ...plan, planDigest: digest2(plan) };
17348
+ }
17349
+ function hash(content) {
17350
+ return createHash21("sha256").update(content).digest("hex");
17351
+ }
17352
+ function digest2(value) {
17353
+ return hash(canonicalJson7(value));
17354
+ }
17355
+ function canonicalJson7(value) {
17356
+ if (Array.isArray(value)) return `[${value.map(canonicalJson7).join(",")}]`;
17357
+ if (!value || typeof value !== "object") return JSON.stringify(value);
17358
+ const record = value;
17359
+ return `{${Object.keys(record).filter((key) => record[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson7(record[key])}`).join(",")}}`;
17360
+ }
17361
+
16875
17362
  // src/lifecycle/ownership-adopt-legacy.ts
16876
17363
  init_apply();
16877
17364
  init_manifest2();
16878
17365
  init_paths();
16879
17366
  init_transaction();
16880
- import { createHash as createHash22 } from "crypto";
17367
+ init_instructions_block();
17368
+ import { createHash as createHash23 } from "crypto";
16881
17369
  import { realpath as realpath3 } from "fs/promises";
16882
- import { isAbsolute as isAbsolute12, relative as relative16, resolve as resolve39 } from "path";
17370
+ import { isAbsolute as isAbsolute12, join as join54, relative as relative17, resolve as resolve40 } from "path";
16883
17371
  init_manifest();
16884
17372
  init_declarations();
16885
17373
  init_transport();
@@ -16892,18 +17380,18 @@ init_instructions_block();
16892
17380
  init_merge_removal();
16893
17381
  init_graph_lock();
16894
17382
  init_manifest();
16895
- import { createHash as createHash21 } from "crypto";
16896
- import { lstat as lstat4, readdir as readdir14 } from "fs/promises";
16897
- import { basename as basename23, dirname as dirname35, join as join52, posix as posix7, relative as relative15, resolve as resolve38 } from "path";
17383
+ import { createHash as createHash22 } from "crypto";
17384
+ import { lstat as lstat6, readdir as readdir15 } from "fs/promises";
17385
+ import { basename as basename23, dirname as dirname35, join as join53, posix as posix7, relative as relative16, resolve as resolve39 } from "path";
16898
17386
  async function inventoryHistoricalLocks(fleetRoot) {
16899
- const root = join52(fleetRoot, ".agentwheel", "locks");
17387
+ const root = join53(fleetRoot, ".agentwheel", "locks");
16900
17388
  const found = [];
16901
17389
  async function visit(dir) {
16902
- for (const entry of await readdir14(dir, { withFileTypes: true }).catch((error) => {
17390
+ for (const entry of await readdir15(dir, { withFileTypes: true }).catch((error) => {
16903
17391
  if (error.code === "ENOENT") return [];
16904
17392
  throw error;
16905
17393
  })) {
16906
- const path = join52(dir, entry.name);
17394
+ const path = join53(dir, entry.name);
16907
17395
  if (entry.isDirectory()) await visit(path);
16908
17396
  else if (entry.isFile() && entry.name.endsWith(".graph-lock.json")) found.push(await historicalLock(path));
16909
17397
  }
@@ -16912,15 +17400,15 @@ async function inventoryHistoricalLocks(fleetRoot) {
16912
17400
  return found.sort((a, b) => a.path.localeCompare(b.path));
16913
17401
  }
16914
17402
  async function findLegacyNamedLocks(workspaceRoot, adapter, fingerprint) {
16915
- const root = join52(workspaceRoot, ".agentwheel", "locks");
17403
+ const root = join53(workspaceRoot, ".agentwheel", "locks");
16916
17404
  const found = [];
16917
- for (const target of await readdir14(root, { withFileTypes: true }).catch((error) => {
17405
+ for (const target of await readdir15(root, { withFileTypes: true }).catch((error) => {
16918
17406
  if (error.code === "ENOENT") return [];
16919
17407
  throw error;
16920
17408
  })) {
16921
17409
  if (!target.isDirectory()) continue;
16922
- const path = join52(root, target.name, adapter, `${fingerprint}.graph-lock.json`);
16923
- const stats = await lstat4(path).catch((error) => {
17410
+ const path = join53(root, target.name, adapter, `${fingerprint}.graph-lock.json`);
17411
+ const stats = await lstat6(path).catch((error) => {
16924
17412
  if (error.code === "ENOENT") return void 0;
16925
17413
  throw error;
16926
17414
  });
@@ -16959,7 +17447,7 @@ async function planLegacyRecovery(input) {
16959
17447
  const nodeHashes = new Map(graphPlan.bundle.graphLock.canonical.nodes.map((node) => [node.id, node.sourceHash]));
16960
17448
  for (const op of graphPlan.plan.operations) {
16961
17449
  if (!op.desiredHash || op.action === "remove" || op.action === "keep") continue;
16962
- const path = relative15(installRoot, op.destPath);
17450
+ const path = relative16(installRoot, op.destPath);
16963
17451
  if (path.startsWith("..") || path === "") throw new Error(`Planner destination escapes target: ${op.destPath}`);
16964
17452
  paths.add(path);
16965
17453
  const items = desired.get(path) ?? [];
@@ -16980,8 +17468,8 @@ async function planLegacyRecovery(input) {
16980
17468
  const currentNodeIds = [...new Set(current.map((item) => item.graphNodeId).filter((value) => Boolean(value)))].sort();
16981
17469
  const currentSelectors = [...new Set(current.map((item) => item.logicalSelector).filter((value) => Boolean(value)))].sort();
16982
17470
  const currentOwners = [...new Set(current.flatMap((item) => item.owners ?? []))].sort();
16983
- const livePath = resolve38(installRoot, path);
16984
- if (relative15(installRoot, livePath).startsWith("..")) throw new Error(`Manifest path escapes target: ${path}`);
17471
+ const livePath = resolve39(installRoot, path);
17472
+ if (relative16(installRoot, livePath).startsWith("..")) throw new Error(`Manifest path escapes target: ${path}`);
16985
17473
  const liveHash = await transport.pathExists(livePath) ? await transport.hashPath(livePath) : null;
16986
17474
  const reasons = [];
16987
17475
  const currentResults = await Promise.all(current.map((op) => verifyCurrentOperation(op, liveHash, transport)));
@@ -17046,14 +17534,14 @@ async function planLegacyRecovery(input) {
17046
17534
  };
17047
17535
  }
17048
17536
  function claimFor(item, entry, locks, binding) {
17049
- const digest2 = "graphLockDigest" in entry ? entry.graphLockDigest : void 0;
17537
+ const digest3 = "graphLockDigest" in entry ? entry.graphLockDigest : void 0;
17050
17538
  const nodeId = "graphNodeId" in entry ? entry.graphNodeId : void 0;
17051
17539
  const selector = "logicalSelector" in entry ? entry.logicalSelector : void 0;
17052
- const matches = locks.filter((candidate) => candidate.digest === digest2);
17540
+ const matches = locks.filter((candidate) => candidate.digest === digest3);
17053
17541
  const evidence = [];
17054
17542
  const owner = "workspaceOwner" in entry ? entry.workspaceOwner : legacyUnownedWorkspaceOwner;
17055
- const sameRoot = binding.transportKind === "ssh" ? posix7.normalize(item.manifest.targetRoot) === posix7.normalize(binding.installRoot) : resolve38(item.manifest.targetRoot) === resolve38(binding.installRoot);
17056
- const inTargetDir = matches.filter((candidate) => resolve38(dirname35(candidate.path)) === resolve38(binding.targetLockDir));
17543
+ const sameRoot = binding.transportKind === "ssh" ? posix7.normalize(item.manifest.targetRoot) === posix7.normalize(binding.installRoot) : resolve39(item.manifest.targetRoot) === resolve39(binding.installRoot);
17544
+ const inTargetDir = matches.filter((candidate) => resolve39(dirname35(candidate.path)) === resolve39(binding.targetLockDir));
17057
17545
  const boundLocks = inTargetDir.filter((candidate) => lockBindsState(candidate, item, binding));
17058
17546
  if (owner !== binding.expectedOwner) evidence.push("workspace owner differs from selected Fleet target");
17059
17547
  if (item.manifest.version !== 2 || item.manifest.installationType !== binding.installationType) evidence.push("installation type differs or manifest is legacy v1");
@@ -17061,7 +17549,7 @@ function claimFor(item, entry, locks, binding) {
17061
17549
  if (item.manifest.version === 2 && (item.manifest.stateKey !== item.stateKey || item.manifest.adapter !== binding.adapter)) {
17062
17550
  evidence.push("manifest state key or adapter differs from filename");
17063
17551
  }
17064
- if (!digest2) evidence.push("historical graph-lock digest missing");
17552
+ if (!digest3) evidence.push("historical graph-lock digest missing");
17065
17553
  else if (matches.length === 0) evidence.push("historical graph-lock digest has no matching lock");
17066
17554
  if (matches.length && !inTargetDir.length) evidence.push("claim belongs to another Fleet target graph");
17067
17555
  if (inTargetDir.length && !boundLocks.length) evidence.push("graph-lock fingerprint, filename, or state key does not bind claim");
@@ -17082,7 +17570,7 @@ function claimFor(item, entry, locks, binding) {
17082
17570
  owner,
17083
17571
  hash: entry.hash,
17084
17572
  sourceHash: entry.sourceHash,
17085
- graphLockDigest: digest2,
17573
+ graphLockDigest: digest3,
17086
17574
  graphNodeId: nodeId,
17087
17575
  logicalSelector: selector,
17088
17576
  owners: "owners" in entry ? entry.owners : [entry.packageName ?? "legacy"],
@@ -17095,7 +17583,7 @@ function lockBindsState(candidate, manifest, binding) {
17095
17583
  if (!name.endsWith(".graph-lock.json")) return false;
17096
17584
  const fingerprint = name.slice(0, -".graph-lock.json".length);
17097
17585
  if (!/^[a-f0-9]{64}$/u.test(fingerprint)) return false;
17098
- const stable = resolve38(candidate.path) === resolve38(binding.stableLockPath);
17586
+ const stable = resolve39(candidate.path) === resolve39(binding.stableLockPath);
17099
17587
  if (stable) {
17100
17588
  return manifest.stateKey === binding.stableStateKey && candidate.lock.canonical.targetFingerprint === binding.currentFingerprint;
17101
17589
  }
@@ -17163,7 +17651,7 @@ function assertCompleteGraphPlan(plan) {
17163
17651
  }
17164
17652
  }
17165
17653
  function sha2566(value) {
17166
- return createHash21("sha256").update(value).digest("hex");
17654
+ return createHash22("sha256").update(value).digest("hex");
17167
17655
  }
17168
17656
 
17169
17657
  // src/lifecycle/ownership-adopt-legacy.ts
@@ -17174,24 +17662,31 @@ function desiredCoverageFromPlan(plan) {
17174
17662
  artifactType: operation.artifactType,
17175
17663
  artifactName: operation.artifactName,
17176
17664
  kind: operation.kind,
17665
+ ...operation.mode ? { mode: operation.mode } : {},
17666
+ ...operation.mode && operation.logicalSelector ? { logicalSelector: operation.logicalSelector } : {},
17177
17667
  ...operation.packageName ? { packageName: operation.packageName } : {}
17178
17668
  })).sort((left, right) => left.path.localeCompare(right.path));
17179
17669
  }
17180
17670
  async function planAdoptLegacyOwnership(request) {
17181
- return observe2(request, request.transport ?? localTransport);
17671
+ return observe3(request, request.transport ?? localTransport);
17182
17672
  }
17183
17673
  async function applyAdoptLegacyOwnership(request) {
17184
17674
  assertApplyPreconditions2(request);
17185
17675
  const transport = request.transport ?? localTransport;
17186
- const targetRoot = resolve39(request.targetRoot);
17676
+ const targetRoot = resolve40(request.targetRoot);
17187
17677
  const installationType = request.installationType.trim();
17678
+ if (transport.kind !== "local") throw new Error("Legacy ownership adoption requires a local filesystem transport.");
17679
+ const beforeLock = await readInstallManifest(targetRoot, request.adapter, transport, { installationType, stateKey: request.sourceStateKey });
17680
+ if (beforeLock?.entries.some((entry) => entry.mode === "managed-block")) {
17681
+ await assertNoSymlinkPath(join54(targetRoot, ".agentwheel"));
17682
+ }
17188
17683
  const lock = await acquireApplyLock(targetRoot, request.adapter, transport, {}, {
17189
17684
  installationType,
17190
17685
  stateKey: request.destinationStateKey
17191
17686
  });
17192
17687
  try {
17193
17688
  await assertNoPendingJournals(targetRoot, request.adapter, transport);
17194
- const current = await observe2(request, transport);
17689
+ const current = await observe3(request, transport);
17195
17690
  assertExpected(request.planDigest, current.planDigest, "plan digest");
17196
17691
  assertExpected(request.expectedSourceRevision, current.source.revision, "source manifest revision");
17197
17692
  assertExpected(request.expectedDestinationRevision, current.destination.revision ?? absentRevision, "destination manifest revision");
@@ -17211,6 +17706,7 @@ async function applyAdoptLegacyOwnership(request) {
17211
17706
  throw new Error("Source manifest selection changed while locked; replan required.");
17212
17707
  }
17213
17708
  const now = (/* @__PURE__ */ new Date()).toISOString();
17709
+ let guards = current.metadataGuards;
17214
17710
  if (adopted.length > 0) {
17215
17711
  declareMutationPath(current.destination.manifestPath);
17216
17712
  const base = destination ?? {
@@ -17224,13 +17720,22 @@ async function applyAdoptLegacyOwnership(request) {
17224
17720
  legacy: false,
17225
17721
  entries: []
17226
17722
  };
17227
- await commitMetadata({
17723
+ const next = withManifestRevision({
17228
17724
  ...base,
17725
+ generatedAt: now,
17229
17726
  entries: [...base.entries, ...adopted].sort((left, right) => left.path.localeCompare(right.path))
17230
- }, destination?.revision ?? null, now, transport);
17727
+ });
17728
+ await commitMetadata(next, destination?.revision ?? null, now, transport, guards);
17729
+ if (guards) guards = {
17730
+ ...guards,
17731
+ inventory: [
17732
+ ...guards.inventory.filter((item) => item.stateKey !== current.destination.stateKey),
17733
+ { stateKey: current.destination.stateKey, revision: next.revision }
17734
+ ].sort((left, right) => left.stateKey.localeCompare(right.stateKey))
17735
+ };
17231
17736
  }
17232
17737
  declareMutationPath(current.source.manifestPath);
17233
- await commitMetadata({ ...source, entries: retained }, source.revision, now, transport);
17738
+ await commitMetadata({ ...source, entries: retained }, source.revision, now, transport, guards);
17234
17739
  return {
17235
17740
  ...current,
17236
17741
  applied: true,
@@ -17243,7 +17748,7 @@ async function applyAdoptLegacyOwnership(request) {
17243
17748
  await lock.release();
17244
17749
  }
17245
17750
  }
17246
- async function commitMetadata(manifest, baseRevision, now, transport) {
17751
+ async function commitMetadata(manifest, baseRevision, now, transport, metadataGuards) {
17247
17752
  const mutation = mutationMetadataForApplyJournal();
17248
17753
  const journal = {
17249
17754
  version: mutation ? 2 : 1,
@@ -17258,12 +17763,13 @@ async function commitMetadata(manifest, baseRevision, now, transport) {
17258
17763
  updatedAt: now,
17259
17764
  operations: [],
17260
17765
  completed: [],
17261
- manifest
17766
+ manifest,
17767
+ ...metadataGuards ? { metadataGuards } : {}
17262
17768
  };
17263
17769
  await writeApplyJournal(journal, transport);
17264
17770
  await commitManifestMetadataJournal(journal, transport);
17265
17771
  }
17266
- async function observe2(request, transport) {
17772
+ async function observe3(request, transport) {
17267
17773
  if (transport.kind === "ssh") {
17268
17774
  throw new Error("Legacy ownership adoption does not support SSH targets; legacy SSH state does not prove its endpoint.");
17269
17775
  }
@@ -17294,11 +17800,21 @@ async function observe2(request, transport) {
17294
17800
  desiredByPath
17295
17801
  );
17296
17802
  const selectedPaths = new Set(selectedEntries.map((entry) => entry.path));
17803
+ const hasManagedBlock = selectedEntries.some((entry) => entry.mode === "managed-block");
17804
+ if (hasManagedBlock && request.carryDrift) throw new Error("--carry-drift is forbidden for managed instruction block adoption.");
17297
17805
  const selected = [];
17298
17806
  for (const entry of selectedEntries) {
17299
17807
  const runtimePath = containedArtifactPath(targetRoot, entry.path);
17808
+ const managedBlock = entry.mode === "managed-block" ? exactManagedInstructionBlockSnapshot(
17809
+ await transport.readFile(runtimePath),
17810
+ managedInstructionSelector(entry.logicalSelector, entry.artifactType, entry.artifactName)
17811
+ ) : void 0;
17812
+ if (managedBlock && managedBlock.hash !== entry.hash) {
17813
+ throw new Error(`Managed instruction block hash differs from its recorded manifest hash at ${entry.path}; adoption is refused.`);
17814
+ }
17815
+ const runtimeSnapshotDigest = hasManagedBlock ? await ownershipRuntimeSnapshot(runtimePath) : void 0;
17300
17816
  const runtimeHash = await transport.pathExists(runtimePath) ? await transport.hashPath(runtimePath) : null;
17301
- const drift = runtimeHash !== entry.hash;
17817
+ const drift = managedBlock ? false : runtimeHash !== entry.hash;
17302
17818
  if (drift && request.carryDrift !== true) {
17303
17819
  throw new Error(
17304
17820
  runtimeHash === null ? `Managed artifact is missing at ${entry.path}; pass --carry-drift to keep the recorded hash.` : `Managed artifact is drifted at ${entry.path}: manifest ${entry.hash}, current ${runtimeHash}; pass --carry-drift to keep the recorded hash.`
@@ -17321,9 +17837,28 @@ async function observe2(request, transport) {
17321
17837
  ...destinationEntryDigest ? { destinationEntryDigest } : {},
17322
17838
  recordedHash: entry.hash,
17323
17839
  runtimeHash,
17324
- drift
17840
+ drift,
17841
+ ...runtimeSnapshotDigest ? { runtimeSnapshotDigest } : {},
17842
+ ...managedBlock ? { managedBlock } : {}
17325
17843
  });
17326
17844
  }
17845
+ const guardedInventory = hasManagedBlock ? await listInstallManifests(targetRoot, void 0, transport) : void 0;
17846
+ if (guardedInventory) {
17847
+ for (const item of guardedInventory) {
17848
+ await assertNoSymlinkPath(item.path);
17849
+ for (const other of item.manifest.entries) {
17850
+ const otherPath = containedArtifactPath(targetRoot, other.path);
17851
+ for (const entry of selectedEntries) {
17852
+ const path = containedArtifactPath(targetRoot, entry.path);
17853
+ const overlap = otherPath === path || otherPath.startsWith(`${path}/`) || path.startsWith(`${otherPath}/`);
17854
+ if (!overlap) continue;
17855
+ if (item.stateKey === input.sourceStateKey && otherPath === path && "workspaceOwner" in other && entryDigest(other) === entryDigest(entry)) continue;
17856
+ if (item.stateKey === input.destinationStateKey && otherPath === path && "workspaceOwner" in other && coversSourceEntry(other, entry, input.destinationOwner)) continue;
17857
+ throw new Error(`Overlapping or duplicate ownership claim at ${entry.path} in ${item.stateKey}; managed-block adoption is refused.`);
17858
+ }
17859
+ }
17860
+ }
17861
+ }
17327
17862
  const remainingDuplicates = [];
17328
17863
  const selectedByPath = new Map(selectedEntries.map((entry) => [entry.path, entry]));
17329
17864
  for (const item of await listInstallManifests(targetRoot, adapter, transport)) {
@@ -17360,20 +17895,35 @@ async function observe2(request, transport) {
17360
17895
  owner: input.destinationOwner,
17361
17896
  workspaceRoot: input.workspaceRoot
17362
17897
  },
17363
- manifestInventoryRevision: await computeInstallManifestInventoryRevision(targetRoot, adapter, transport),
17898
+ manifestInventoryRevision: await computeInstallManifestInventoryRevision(targetRoot, hasManagedBlock ? void 0 : adapter, transport),
17364
17899
  selected: selected.sort((left, right) => left.path.localeCompare(right.path)),
17365
17900
  retained: retained.sort((left, right) => left.path.localeCompare(right.path) || left.owner.localeCompare(right.owner)),
17366
17901
  remainingDuplicates: remainingDuplicates.sort((left, right) => left.stateKey.localeCompare(right.stateKey) || left.path.localeCompare(right.path)),
17367
17902
  // identity only, so a newer package revision doesn't invalidate a reviewed plan
17368
- desiredCoverage: request.desiredCoverage.filter((item) => selectedPaths.has(item.path)).map(({ path, artifactType, artifactName, kind }) => ({ path, artifactType, artifactName, kind })).sort((left, right) => left.path.localeCompare(right.path) || left.artifactType.localeCompare(right.artifactType) || left.artifactName.localeCompare(right.artifactName))
17903
+ desiredCoverage: request.desiredCoverage.filter((item) => selectedPaths.has(item.path)).map(({ path, artifactType, artifactName, kind, mode, logicalSelector }) => ({
17904
+ path,
17905
+ artifactType,
17906
+ artifactName,
17907
+ kind,
17908
+ ...mode ? { mode, logicalSelector: managedInstructionSelector(logicalSelector, artifactType, artifactName) } : {}
17909
+ })).sort((left, right) => left.path.localeCompare(right.path) || left.artifactType.localeCompare(right.artifactType) || left.artifactName.localeCompare(right.artifactName)),
17910
+ ...guardedInventory ? { metadataGuards: {
17911
+ inventory: guardedInventory.map((item) => ({ stateKey: item.stateKey, revision: item.manifest.revision })),
17912
+ runtime: selected.map((entry) => ({
17913
+ path: entry.path,
17914
+ hash: entry.runtimeHash,
17915
+ snapshotDigest: entry.runtimeSnapshotDigest,
17916
+ ...entry.managedBlock ? { managedBlock: entry.managedBlock } : {}
17917
+ }))
17918
+ } } : {}
17369
17919
  };
17370
- return { ...withoutDigest, planDigest: createHash22("sha256").update(canonicalJson6(withoutDigest)).digest("hex") };
17920
+ return { ...withoutDigest, planDigest: createHash23("sha256").update(canonicalJson6(withoutDigest)).digest("hex") };
17371
17921
  }
17372
17922
  async function normalizeRequest2(request) {
17373
17923
  if (request.destinationFleetId !== void 0) {
17374
17924
  throw new Error("Legacy ownership adoption targets a nested workspace; a Fleet target uses fleet normalize or ownership retire-stale.");
17375
17925
  }
17376
- const targetRoot = resolve39(request.targetRoot);
17926
+ const targetRoot = resolve40(request.targetRoot);
17377
17927
  const installationType = request.installationType.trim();
17378
17928
  const sourceStateKey = exactStateKey(request.adapter, request.sourceStateKey, installationType, "source");
17379
17929
  const destinationStateKey = exactStateKey(request.adapter, request.destinationStateKey, installationType, "destination");
@@ -17385,22 +17935,22 @@ async function normalizeRequest2(request) {
17385
17935
  const scope = await resolveWorkspaceOwnershipScope(request.workspaceRoot, { globalRoot: request.globalRoot });
17386
17936
  const destinationOwner = workspaceOwnerForRoot(scope.root, scope.fleetId);
17387
17937
  const workspaceRoot = await realpath3(request.workspaceRoot);
17388
- const sourceRoot = resolve39(request.fromWorkspaceRoot);
17938
+ const sourceRoot = resolve40(request.fromWorkspaceRoot);
17389
17939
  const sourceOwner = workspaceOwnerForRoot(sourceRoot);
17390
17940
  let sourceClass;
17391
- if (sourceRoot === workspaceRoot || sourceRoot === resolve39(request.workspaceRoot)) {
17941
+ if (sourceRoot === workspaceRoot || sourceRoot === resolve40(request.workspaceRoot)) {
17392
17942
  if (sourceOwner === destinationOwner) {
17393
17943
  throw new Error(`${sourceOwner} is already the destination owner; ordinary install migration handles its legacy state.`);
17394
17944
  }
17395
17945
  sourceClass = "own-legacy-owner";
17396
17946
  } else {
17397
17947
  const sourceForms = [sourceRoot, ...await realpath3(sourceRoot).then((path) => [path], () => [])];
17398
- const workspaceForms = [workspaceRoot, resolve39(request.workspaceRoot), scope.root];
17948
+ const workspaceForms = [workspaceRoot, resolve40(request.workspaceRoot), scope.root];
17399
17949
  if (sourceForms.some((source) => workspaceForms.some((workspace) => containsPath2(source, workspace) || containsPath2(workspace, source)))) {
17400
17950
  throw new Error(`Source root ${sourceRoot} contains or is contained by the destination workspace; it cannot be adopted as a foreign root.`);
17401
17951
  }
17402
17952
  for (const fleet of await listRegisteredFleets({ globalRoot: request.globalRoot })) {
17403
- const fleetForms = [resolve39(fleet.root), ...await realpath3(fleet.root).then((path) => [path], () => [])];
17953
+ const fleetForms = [resolve40(fleet.root), ...await realpath3(fleet.root).then((path) => [path], () => [])];
17404
17954
  if (sourceForms.some((source) => fleetForms.some((root) => containsPath2(root, source)))) {
17405
17955
  throw new Error(`Source root ${sourceRoot} is inside registered Fleet '${fleet.id}'; use fleet normalize or ownership retire-stale.`);
17406
17956
  }
@@ -17436,7 +17986,7 @@ async function selectLegacySource(input, stateKey, fingerprint, source, desiredB
17436
17986
  );
17437
17987
  }
17438
17988
  for (const entry of source.entries) {
17439
- if (entry.workspaceOwner === input.sourceOwner) assertPlainEntry(entry, input.targetRoot);
17989
+ if (entry.workspaceOwner === input.sourceOwner) assertSupportedLegacyEntry(entry, input.targetRoot);
17440
17990
  }
17441
17991
  const entries = [];
17442
17992
  const retained = [];
@@ -17514,20 +18064,21 @@ async function readDestination(identity, stateKey, transport) {
17514
18064
  }
17515
18065
  return requireManifest(identity, stateKey, transport, "destination");
17516
18066
  }
17517
- function assertPlainEntry(entry, targetRoot) {
17518
- if (entry.mode || entry.mergeStrategy || entry.semanticPlugin || entry.semanticCommand || entry.executed) {
18067
+ function assertSupportedLegacyEntry(entry, targetRoot) {
18068
+ const supportedBlock = entry.mode === "managed-block" && entry.kind === "file" && entry.artifactType === "instructions";
18069
+ if (entry.mode && !supportedBlock || entry.mergeStrategy || entry.semanticPlugin || entry.semanticCommand || entry.executed) {
17519
18070
  throw new Error(`Legacy ownership adoption supports only plain file or directory entries; ${entry.path} is not one.`);
17520
18071
  }
17521
18072
  containedArtifactPath(targetRoot, entry.path);
17522
18073
  }
17523
18074
  function desiredCovers(item, entry) {
17524
- return item.artifactType === entry.artifactType && item.artifactName === entry.artifactName && item.kind === entry.kind && (!item.packageName || !entry.packageName || item.packageName === entry.packageName);
18075
+ return item.artifactType === entry.artifactType && item.artifactName === entry.artifactName && item.kind === entry.kind && (!item.packageName || !entry.packageName || item.packageName === entry.packageName) && (entry.mode !== "managed-block" || item.mode === "managed-block" && managedInstructionSelector(item.logicalSelector, item.artifactType, item.artifactName) === managedInstructionSelector(entry.logicalSelector, entry.artifactType, entry.artifactName));
17525
18076
  }
17526
18077
  function coversSourceEntry(destination, source, owner) {
17527
- return destination.workspaceOwner === owner && !destination.mode && !destination.mergeStrategy && !destination.semanticPlugin && sameRecordedArtifact(destination, source);
18078
+ return destination.workspaceOwner === owner && destination.mode === source.mode && !destination.mergeStrategy && !destination.semanticPlugin && sameRecordedArtifact(destination, source) && (source.mode !== "managed-block" || entryDigest({ ...destination, workspaceOwner: source.workspaceOwner }) === entryDigest(source));
17528
18079
  }
17529
18080
  function sameRecordedArtifact(left, right) {
17530
- return left.artifactType === right.artifactType && left.artifactName === right.artifactName && left.kind === right.kind && left.hash === right.hash && left.sourceHash === right.sourceHash;
18081
+ return left.artifactType === right.artifactType && left.artifactName === right.artifactName && left.kind === right.kind && left.hash === right.hash && left.sourceHash === right.sourceHash && left.mode === right.mode && (left.mode !== "managed-block" || managedInstructionSelector(left.logicalSelector, left.artifactType, left.artifactName) === managedInstructionSelector(right.logicalSelector, right.artifactType, right.artifactName));
17531
18082
  }
17532
18083
  async function assertNoPendingJournals(targetRoot, adapter, transport) {
17533
18084
  const pending = await listAllApplyJournals(targetRoot, adapter, transport);
@@ -17549,14 +18100,14 @@ function assertApplyPreconditions2(request) {
17549
18100
  }
17550
18101
  }
17551
18102
  function containsPath2(parent, candidate) {
17552
- const path = relative16(parent, candidate);
18103
+ const path = relative17(parent, candidate);
17553
18104
  return path === "" || !path.startsWith("..") && !isAbsolute12(path);
17554
18105
  }
17555
18106
 
17556
18107
  // src/version/policy.ts
17557
18108
  import { execFile as execFile7 } from "child_process";
17558
18109
  import { readFile as readFile40 } from "fs/promises";
17559
- import { join as join53, resolve as resolve40 } from "path";
18110
+ import { join as join55, resolve as resolve41 } from "path";
17560
18111
  import { promisify as promisify7 } from "util";
17561
18112
  import { parse as parseJsonc } from "jsonc-parser";
17562
18113
  import { z as z15 } from "zod";
@@ -17653,7 +18204,7 @@ async function discoverVersionsFromSource(pkg, workspaceRoot) {
17653
18204
  if (tagged.length > 0) return tagged;
17654
18205
  }
17655
18206
  if (driverName === "local") {
17656
- const root = resolve40(workspaceRoot, pkg.source);
18207
+ const root = resolve41(workspaceRoot, pkg.source);
17657
18208
  const manifest2 = await readPackageManifest(root);
17658
18209
  const current = manifest2 ? [{ version: manifest2.version, ref: pkg.requestedRef ?? root }] : [];
17659
18210
  try {
@@ -17668,7 +18219,7 @@ async function discoverVersionsFromSource(pkg, workspaceRoot) {
17668
18219
  }
17669
18220
  const driver = getSourceDriver(driverName);
17670
18221
  const resolved = await driver.resolve(pkg.source, {
17671
- cacheRoot: join53(workspaceRoot, ".agentwheel", "cache"),
18222
+ cacheRoot: join55(workspaceRoot, ".agentwheel", "cache"),
17672
18223
  mode: "tracking",
17673
18224
  ref: pkg.requestedRef
17674
18225
  });
@@ -17762,7 +18313,7 @@ function gitUrlFromSource(source) {
17762
18313
  throw new Error(`Version discovery does not support Git source: ${source}`);
17763
18314
  }
17764
18315
  function versionCachePath(workspaceRoot) {
17765
- return join53(workspaceRoot, ".agentwheel", "cache", "version-index.json");
18316
+ return join55(workspaceRoot, ".agentwheel", "cache", "version-index.json");
17766
18317
  }
17767
18318
  async function readVersionCache(path) {
17768
18319
  if (!await pathExists(path)) return { schemaVersion: 1, sources: {} };
@@ -17779,7 +18330,7 @@ init_semver();
17779
18330
  // src/profile/members.ts
17780
18331
  import { execFile as execFile8 } from "child_process";
17781
18332
  import { readFile as readFile41 } from "fs/promises";
17782
- import { join as join54, resolve as resolve41 } from "path";
18333
+ import { join as join56, resolve as resolve42 } from "path";
17783
18334
  import { promisify as promisify8 } from "util";
17784
18335
  import { z as z17 } from "zod";
17785
18336
 
@@ -17955,7 +18506,7 @@ async function invokeMemberStatus(member, parentWorkspace, chain, options, cliEn
17955
18506
  let stderr = "";
17956
18507
  try {
17957
18508
  if (member.transport === "local") {
17958
- const workspace = resolve41(parentWorkspace, member.workspace);
18509
+ const workspace = resolve42(parentWorkspace, member.workspace);
17959
18510
  const result = await execFileAsync8(process.execPath, [cliEntry, ...args], {
17960
18511
  cwd: workspace,
17961
18512
  env: env2,
@@ -18001,7 +18552,7 @@ async function runMemberAgentwheel(member, parentWorkspace, args, chain) {
18001
18552
  process.execPath,
18002
18553
  [process.argv[1], ...memberCommandArgs(member, args)],
18003
18554
  {
18004
- cwd: resolve41(parentWorkspace, member.workspace),
18555
+ cwd: resolve42(parentWorkspace, member.workspace),
18005
18556
  env: env2,
18006
18557
  maxBuffer: 20 * 1024 * 1024
18007
18558
  }
@@ -18081,7 +18632,7 @@ function memberFailure(member, health, error) {
18081
18632
  };
18082
18633
  }
18083
18634
  function memberCachePath(workspaceRoot, profileName, memberId) {
18084
- return join54(workspaceRoot, ".agentwheel", "cache", "member-status", profileName, `${memberId}.json`);
18635
+ return join56(workspaceRoot, ".agentwheel", "cache", "member-status", profileName, `${memberId}.json`);
18085
18636
  }
18086
18637
  async function readMemberCache(path) {
18087
18638
  if (!await pathExists(path)) return void 0;
@@ -18107,7 +18658,7 @@ function assertNoCompositeCycle(workspaceRoot, profileName, chain) {
18107
18658
  }
18108
18659
  }
18109
18660
  function compositeKey(workspaceRoot, profileName) {
18110
- return `${resolve41(workspaceRoot)}#${profileName}`;
18661
+ return `${resolve42(workspaceRoot)}#${profileName}`;
18111
18662
  }
18112
18663
 
18113
18664
  // src/status/repository.ts
@@ -18154,10 +18705,10 @@ function valueAfter(lines, prefix) {
18154
18705
  }
18155
18706
 
18156
18707
  // src/catalogue/client.ts
18157
- import { createHash as createHash23 } from "crypto";
18708
+ import { createHash as createHash24 } from "crypto";
18158
18709
  import { readFile as readFile42, rm as rm15 } from "fs/promises";
18159
18710
  import { homedir as homedir15 } from "os";
18160
- import { join as join55 } from "path";
18711
+ import { join as join57 } from "path";
18161
18712
 
18162
18713
  // src/model/catalogue.ts
18163
18714
  import { z as z18 } from "zod";
@@ -18430,18 +18981,18 @@ var CatalogueClient = class {
18430
18981
  }
18431
18982
  return {
18432
18983
  value: schema.parse(value),
18433
- digest: createHash23("sha256").update(bytes).digest("hex")
18984
+ digest: createHash24("sha256").update(bytes).digest("hex")
18434
18985
  };
18435
18986
  }
18436
18987
  };
18437
18988
  function defaultCatalogueCachePath() {
18438
- return join55(homedir15(), ".agentwheel", "catalogue-cache.json");
18989
+ return join57(homedir15(), ".agentwheel", "catalogue-cache.json");
18439
18990
  }
18440
18991
  function sameSources2(a, b) {
18441
18992
  return a.length === b.length && a.every((source, index) => source === b[index]);
18442
18993
  }
18443
18994
  function catalogueContentHash(enriched, vercel) {
18444
- return createHash23("sha256").update(JSON.stringify({ enriched, vercel })).digest("hex");
18995
+ return createHash24("sha256").update(JSON.stringify({ enriched, vercel })).digest("hex");
18445
18996
  }
18446
18997
 
18447
18998
  // src/search/index.ts
@@ -18803,9 +19354,9 @@ function includesToken(normalizedText, token) {
18803
19354
  }
18804
19355
 
18805
19356
  // src/semantic/index.ts
18806
- import { createHash as createHash24 } from "crypto";
19357
+ import { createHash as createHash25 } from "crypto";
18807
19358
  import { homedir as homedir16 } from "os";
18808
- import { join as join56 } from "path";
19359
+ import { join as join58 } from "path";
18809
19360
  import { env, pipeline } from "@huggingface/transformers";
18810
19361
  var DEFAULT_SEMANTIC_INDEX_URL = "https://raw.githubusercontent.com/NestDevLab/agentwheel-registry/main/catalogue-semantic-index/gte-v1/";
18811
19362
  var CONTRACT = {
@@ -18893,13 +19444,13 @@ var SemanticSearchClient = class {
18893
19444
  if (!response.ok) throw new Error(`Semantic index file failed (${response.status}): ${descriptor.path}`);
18894
19445
  const bytes = new Uint8Array(await response.arrayBuffer());
18895
19446
  if (bytes.byteLength !== descriptor.bytes) throw new Error(`Semantic index file size does not match: ${descriptor.path}`);
18896
- const digest2 = createHash24("sha256").update(bytes).digest("hex");
18897
- if (digest2 !== descriptor.sha256) throw new Error(`Semantic index checksum does not match: ${descriptor.path}`);
19447
+ const digest3 = createHash25("sha256").update(bytes).digest("hex");
19448
+ if (digest3 !== descriptor.sha256) throw new Error(`Semantic index checksum does not match: ${descriptor.path}`);
18898
19449
  return bytes;
18899
19450
  }
18900
19451
  };
18901
19452
  async function embedQuery(query) {
18902
- env.cacheDir = join56(homedir16(), ".agentwheel", "semantic-models");
19453
+ env.cacheDir = join58(homedir16(), ".agentwheel", "semantic-models");
18903
19454
  const extractor = await pipeline("feature-extraction", CONTRACT.model.id, {
18904
19455
  revision: CONTRACT.model.revision,
18905
19456
  dtype: CONTRACT.model.dtype,
@@ -18983,9 +19534,10 @@ function ensureTrailingSlash(value) {
18983
19534
  }
18984
19535
 
18985
19536
  // src/trial/skill.ts
18986
- import { createHash as createHash25 } from "crypto";
19537
+ init_selection();
19538
+ import { createHash as createHash26 } from "crypto";
18987
19539
  import { readFile as readFile43, stat as stat16 } from "fs/promises";
18988
- import { join as join57 } from "path";
19540
+ import { join as join59 } from "path";
18989
19541
  import { parse as parseYaml2 } from "yaml";
18990
19542
  var MAX_TRIAL_SKILL_BYTES = 512 * 1024;
18991
19543
  async function createSkillTrial(driver, resolved, selectors) {
@@ -18997,7 +19549,7 @@ async function createSkillTrial(driver, resolved, selectors) {
18997
19549
  throw new Error("Skill trial requires exactly one selected skill. Use --skill <name> or --select skills/<name>.");
18998
19550
  }
18999
19551
  const artifact = skills[0];
19000
- const path = artifact.kind === "dir" ? join57(artifact.sourcePath, "SKILL.md") : artifact.sourcePath;
19552
+ const path = artifact.kind === "dir" ? join59(artifact.sourcePath, "SKILL.md") : artifact.sourcePath;
19001
19553
  const info = await stat16(path);
19002
19554
  if (info.size > MAX_TRIAL_SKILL_BYTES) {
19003
19555
  throw new Error(`Skill trial exceeds the ${MAX_TRIAL_SKILL_BYTES / 1024} KiB content limit.`);
@@ -19013,7 +19565,7 @@ async function createSkillTrial(driver, resolved, selectors) {
19013
19565
  skill: {
19014
19566
  name: artifact.name,
19015
19567
  relativePath: artifact.relativePath,
19016
- sha256: createHash25("sha256").update(content).digest("hex"),
19568
+ sha256: createHash26("sha256").update(content).digest("hex"),
19017
19569
  frontmatter,
19018
19570
  content
19019
19571
  }
@@ -19032,10 +19584,10 @@ function readSkillFrontmatter(content, artifact) {
19032
19584
  }
19033
19585
 
19034
19586
  // src/lifecycle/fleet-normalize.ts
19035
- import { createHash as createHash26 } from "crypto";
19036
- import { readFile as readFile44, readdir as readdir15, rm as rm16 } from "fs/promises";
19587
+ import { createHash as createHash27 } from "crypto";
19588
+ import { readFile as readFile44, readdir as readdir16, rm as rm16 } from "fs/promises";
19037
19589
  import { homedir as homedir17 } from "os";
19038
- import { dirname as dirname36, isAbsolute as isAbsolute13, join as join58, relative as relative17, resolve as resolve42 } from "path";
19590
+ import { dirname as dirname36, isAbsolute as isAbsolute13, join as join60, relative as relative18, resolve as resolve43 } from "path";
19039
19591
  init_manifest2();
19040
19592
  init_paths();
19041
19593
  init_merge_removal();
@@ -19071,14 +19623,14 @@ async function planFleetNormalization(request) {
19071
19623
  if (legacySelfNormalization && normalizedRequest.orphanedOwnerRoots?.length && normalizedRequest.packages?.includes(name)) {
19072
19624
  packages.push({
19073
19625
  name,
19074
- declarationDigest: sha2567(canonicalJson7({ name, evidence: "orphaned-installed-state" }))
19626
+ declarationDigest: sha2567(canonicalJson8({ name, evidence: "orphaned-installed-state" }))
19075
19627
  });
19076
19628
  continue;
19077
19629
  }
19078
19630
  throw new Error(`Package '${name}' must be an existing duplicate in both source and destination fleets.`);
19079
19631
  }
19080
- const sourceDeclaration = canonicalJson7(sourcePackage);
19081
- const destinationDeclaration = canonicalJson7(destinationPackage);
19632
+ const sourceDeclaration = canonicalJson8(sourcePackage);
19633
+ const destinationDeclaration = canonicalJson8(destinationPackage);
19082
19634
  if (sourceDeclaration !== destinationDeclaration) {
19083
19635
  throw new Error(
19084
19636
  `Package '${name}' has divergent declarations. Source, driver, adapter, adapter configuration, installation type, version policy, runtime restrictions, selections, aliases, overrides, and suggestions must match before normalization.`
@@ -19115,7 +19667,7 @@ async function planFleetNormalization(request) {
19115
19667
  packages,
19116
19668
  installedState
19117
19669
  };
19118
- return { ...planWithoutDigest, planDigest: sha2567(canonicalJson7(planWithoutDigest)) };
19670
+ return { ...planWithoutDigest, planDigest: sha2567(canonicalJson8(planWithoutDigest)) };
19119
19671
  }
19120
19672
  async function applyFleetNormalization(request, hooks = {}) {
19121
19673
  if (!request.apply) throw new Error("Fleet normalization is dry-run by default; pass --apply with --plan-digest <digest>.");
@@ -19253,8 +19805,8 @@ async function assertNormalizationPostconditions(journal) {
19253
19805
  }
19254
19806
  for (const graphLock of journal.graphLocks) {
19255
19807
  const raw = await readOptionalRecord(graphLock.path);
19256
- const digest2 = raw ? sha2567(canonicalJson7(await readGraphLock(graphLock.path))) : null;
19257
- if (digest2 !== graphLock.afterDigest) {
19808
+ const digest3 = raw ? sha2567(canonicalJson8(await readGraphLock(graphLock.path))) : null;
19809
+ if (digest3 !== graphLock.afterDigest) {
19258
19810
  throw new Error(`Fleet normalization graph-lock postcheck failed: ${graphLock.path}`);
19259
19811
  }
19260
19812
  }
@@ -19325,17 +19877,17 @@ function normalizeRequest3(request) {
19325
19877
  ...profile ? { profile } : {},
19326
19878
  ...agent ? { agent } : {},
19327
19879
  ...orphanedOwnerRoots ? { orphanedOwnerRoots } : {},
19328
- ...request.globalRoot ? { globalRoot: resolve42(request.globalRoot) } : {}
19880
+ ...request.globalRoot ? { globalRoot: resolve43(request.globalRoot) } : {}
19329
19881
  };
19330
19882
  }
19331
19883
  function normalizeOrphanedOwnerRoot(value) {
19332
19884
  const root = value.trim();
19333
19885
  if (!root || !isAbsolute13(root)) throw new Error(`Invalid orphaned owner root '${value}'; expected an absolute workspace path.`);
19334
- return resolve42(root);
19886
+ return resolve43(root);
19335
19887
  }
19336
19888
  async function normalizationRoots(request) {
19337
19889
  const destination = await showRegisteredFleet(request.destinationFleet, { globalRoot: request.globalRoot });
19338
- const source = request.from === "user" ? resolve42(request.globalRoot ?? homedir17()) : (await showRegisteredFleet(request.from.slice("fleet:".length), { globalRoot: request.globalRoot })).root;
19890
+ const source = request.from === "user" ? resolve43(request.globalRoot ?? homedir17()) : (await showRegisteredFleet(request.from.slice("fleet:".length), { globalRoot: request.globalRoot })).root;
19339
19891
  return { source, destination: destination.root };
19340
19892
  }
19341
19893
  async function withOrderedLocks(roots, fn) {
@@ -19343,7 +19895,7 @@ async function withOrderedLocks(roots, fn) {
19343
19895
  if (index === roots.length) return fn();
19344
19896
  const root = roots[index];
19345
19897
  return withFilesystemLock(
19346
- join58(root, ".agentwheel", "fleet-normalize.lock"),
19898
+ join60(root, ".agentwheel", "fleet-normalize.lock"),
19347
19899
  5e3,
19348
19900
  () => run(index + 1),
19349
19901
  "fleet normalization"
@@ -19442,10 +19994,10 @@ async function inspectInstalledState(source, destination, packageNames) {
19442
19994
  const destinationGraphAfter = destinationGraph?.lock ?? destinationGraphFromSource(sourceGraph.lock, destinationState.targetFingerprint);
19443
19995
  graphTransfers.push({
19444
19996
  sourceGraphLockPath: sourceGraph.path,
19445
- sourceGraphLockDigest: sha2567(canonicalJson7(sourceGraph.lock)),
19997
+ sourceGraphLockDigest: sha2567(canonicalJson8(sourceGraph.lock)),
19446
19998
  destinationGraphLockPath: destinationState.graphLockPath,
19447
- destinationGraphLockDigest: destinationGraph ? sha2567(canonicalJson7(destinationGraph.lock)) : null,
19448
- destinationGraphLockAfterDigest: sha2567(canonicalJson7(destinationGraphAfter)),
19999
+ destinationGraphLockDigest: destinationGraph ? sha2567(canonicalJson8(destinationGraph.lock)) : null,
20000
+ destinationGraphLockAfterDigest: sha2567(canonicalJson8(destinationGraphAfter)),
19449
20001
  targetKey: sourceGraph.targetKey,
19450
20002
  adapter: destinationState.adapter,
19451
20003
  targetFingerprint: destinationState.targetFingerprint
@@ -19550,7 +20102,7 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
19550
20102
  let normalizedGraphCount = 0;
19551
20103
  for (const graph of graphCandidates) {
19552
20104
  const destinationState = await targetStateForGraph(fleet, graph, fleet.fleetId, allowOrphanedRetiredPackages);
19553
- if (resolve42(destinationState.graphLockPath) === resolve42(graph.path)) {
20105
+ if (resolve43(destinationState.graphLockPath) === resolve43(graph.path)) {
19554
20106
  const destinationManifest = (await collectManifestPaths([destinationState.manifestPath]))[0];
19555
20107
  if (destinationManifest?.manifest.entries.some((entry) => entry.workspaceOwner === fleetOwner && entryMatchesPackages(entry, selected))) {
19556
20108
  assertCorrelatedGraphManifest(
@@ -19565,7 +20117,7 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
19565
20117
  }
19566
20118
  }
19567
20119
  const legacyState = await legacyTargetStateForGraph(fleet, graph, allowOrphanedRetiredPackages);
19568
- if (resolve42(legacyState.graphLockPath) !== resolve42(graph.path)) {
20120
+ if (resolve43(legacyState.graphLockPath) !== resolve43(graph.path)) {
19569
20121
  throw new Error(`Legacy graph lock target identity is stale or noncanonical: ${graph.path}`);
19570
20122
  }
19571
20123
  const legacyManifest = (await collectManifestPaths([legacyState.manifestPath]))[0];
@@ -19673,7 +20225,7 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
19673
20225
  )
19674
20226
  });
19675
20227
  if (!selectedArtifacts) {
19676
- const fullDigest = sha2567(canonicalJson7(graph.lock));
20228
+ const fullDigest = sha2567(canonicalJson8(graph.lock));
19677
20229
  const existingDestinationGraph = graphCandidates.find((candidate) => candidate.path === destinationState.graphLockPath);
19678
20230
  if (existingDestinationGraph) assertGraphIsSubset(graph, existingDestinationGraph);
19679
20231
  const destinationGraph = destinationGraphFromSource(graph.lock, destinationState.targetFingerprint);
@@ -19681,8 +20233,8 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
19681
20233
  sourceGraphLockPath: graph.path,
19682
20234
  sourceGraphLockDigest: fullDigest,
19683
20235
  destinationGraphLockPath: destinationState.graphLockPath,
19684
- destinationGraphLockDigest: existingDestinationGraph ? sha2567(canonicalJson7(existingDestinationGraph.lock)) : null,
19685
- destinationGraphLockAfterDigest: sha2567(canonicalJson7(destinationGraph)),
20236
+ destinationGraphLockDigest: existingDestinationGraph ? sha2567(canonicalJson8(existingDestinationGraph.lock)) : null,
20237
+ destinationGraphLockAfterDigest: sha2567(canonicalJson8(destinationGraph)),
19686
20238
  targetKey: graph.targetKey,
19687
20239
  adapter: graph.adapter,
19688
20240
  targetFingerprint: destinationState.targetFingerprint
@@ -19740,7 +20292,7 @@ function targetKeysForAgent(scope, name) {
19740
20292
  async function runtimeRoots(scope) {
19741
20293
  const roots = /* @__PURE__ */ new Set([scope.root]);
19742
20294
  if (scope.config.packages.some((pkg) => pkg.installationType === "user") || Object.values(scope.config.agents).some((agent) => agent.installationType === "user")) {
19743
- roots.add(resolve42(process.env.AGENTWHEEL_TEST_HOME || process.env.HOME || homedir17()));
20295
+ roots.add(resolve43(process.env.AGENTWHEEL_TEST_HOME || process.env.HOME || homedir17()));
19744
20296
  }
19745
20297
  for (const [name, agent] of Object.entries(scope.config.agents)) {
19746
20298
  if (agent.transport === "ssh" || agent.transport === "local-run-as") throw new Error(`Installed-state normalization cannot inspect ${agent.transport} agent '${name}' locally.`);
@@ -19758,17 +20310,17 @@ async function runtimeRoots(scope) {
19758
20310
  async function collectManifests(roots) {
19759
20311
  const found = /* @__PURE__ */ new Map();
19760
20312
  for (const root of roots) {
19761
- const dir = join58(root, ".agentwheel");
20313
+ const dir = join60(root, ".agentwheel");
19762
20314
  let names;
19763
20315
  try {
19764
- names = await readdir15(dir);
20316
+ names = await readdir16(dir);
19765
20317
  } catch (error) {
19766
20318
  if (isMissing5(error)) continue;
19767
20319
  throw error;
19768
20320
  }
19769
20321
  for (const name of names.sort((a, b) => a.localeCompare(b))) {
19770
20322
  if (!name.endsWith(".install-manifest.json")) continue;
19771
- const path = join58(dir, name);
20323
+ const path = join60(dir, name);
19772
20324
  const raw = JSON.parse(await readFile44(path, "utf8"));
19773
20325
  const parsed = installManifestSchema.parse(raw);
19774
20326
  if (parsed.version !== 2) {
@@ -19777,14 +20329,14 @@ async function collectManifests(roots) {
19777
20329
  }
19778
20330
  continue;
19779
20331
  }
19780
- if (resolve42(parsed.targetRoot) !== resolve42(root)) {
20332
+ if (resolve43(parsed.targetRoot) !== resolve43(root)) {
19781
20333
  throw new Error(`Install manifest target root does not match its enumerated runtime root: ${path}`);
19782
20334
  }
19783
20335
  const expectedPath = installManifestPath(parsed.targetRoot, parsed.adapter, {
19784
20336
  installationType: parsed.installationType,
19785
20337
  stateKey: parsed.stateKey
19786
20338
  });
19787
- if (resolve42(expectedPath) !== resolve42(path)) {
20339
+ if (resolve43(expectedPath) !== resolve43(path)) {
19788
20340
  throw new Error(`Install manifest state identity does not match its canonical path: ${path}`);
19789
20341
  }
19790
20342
  found.set(path, { path, raw, manifest: { ...parsed, revision: computeManifestRevision(raw), legacy: false } });
@@ -19805,7 +20357,7 @@ async function collectManifestPaths(paths) {
19805
20357
  installationType: parsed.installationType,
19806
20358
  stateKey: parsed.stateKey
19807
20359
  });
19808
- if (resolve42(expectedPath) !== resolve42(path)) {
20360
+ if (resolve43(expectedPath) !== resolve43(path)) {
19809
20361
  throw new Error(`Install manifest state identity does not match its canonical path: ${path}`);
19810
20362
  }
19811
20363
  found.push({ path, raw, manifest: { ...parsed, revision: computeManifestRevision(raw), legacy: false } });
@@ -19824,14 +20376,14 @@ function assertNoForeignSamePathOwnership(manifests, renderedPaths, allowedOwner
19824
20376
  }
19825
20377
  }
19826
20378
  async function relevantGraphLocks(workspaceRoot, selected, targetKeys, include) {
19827
- const root = join58(workspaceRoot, ".agentwheel", "locks");
20379
+ const root = join60(workspaceRoot, ".agentwheel", "locks");
19828
20380
  if (!await pathExists(root)) return [];
19829
20381
  const results = [];
19830
20382
  for (const path of await listFiles(root)) {
19831
20383
  if (!path.endsWith(".graph-lock.json")) continue;
19832
20384
  const lock = await readGraphLock(path);
19833
20385
  if (!lock.canonical.roots.some((candidate2) => selected.has(candidate2.rootId))) continue;
19834
- const parts = relative17(root, path).split(/[\\/]/);
20386
+ const parts = relative18(root, path).split(/[\\/]/);
19835
20387
  if (parts.length !== 3) throw new Error(`Graph lock path is not canonical: ${path}`);
19836
20388
  const [targetKey2, adapter] = parts;
19837
20389
  if (targetKeys && !targetKeys.has(targetKey2)) continue;
@@ -19848,7 +20400,7 @@ async function relevantGraphLocks(workspaceRoot, selected, targetKeys, include)
19848
20400
  const projection = relevantGraphProjection(lock, selected);
19849
20401
  results.push({
19850
20402
  ...candidate,
19851
- digest: sha2567(canonicalJson7(projection)),
20403
+ digest: sha2567(canonicalJson8(projection)),
19852
20404
  artifactIdentities: lock.canonical.artifacts.filter((artifact) => artifact.owners.some((owner) => ownerMatchesGraphPackage(lock, owner, selected))).map(graphArtifactIdentity).sort()
19853
20405
  });
19854
20406
  }
@@ -19873,7 +20425,7 @@ async function hasRelevantLegacyManifestCandidate(scope, graph, selected) {
19873
20425
  const legacyManifest = (await collectManifestPaths([legacyState.manifestPath]))[0];
19874
20426
  if (legacyManifest?.manifest.entries.some((entry) => entryMatchesGraphPackages(entry, graph.lock, selected))) return true;
19875
20427
  const stableState = await targetStateForGraph(scope, graph, scope.fleetId ?? null);
19876
- if (resolve42(stableState.graphLockPath) !== resolve42(graph.path)) return false;
20428
+ if (resolve43(stableState.graphLockPath) !== resolve43(graph.path)) return false;
19877
20429
  const stableManifest = (await collectManifestPaths([stableState.manifestPath]))[0];
19878
20430
  return stableManifest?.manifest.entries.some((entry) => entryMatchesGraphPackages(entry, graph.lock, selected)) ?? false;
19879
20431
  }
@@ -19894,7 +20446,7 @@ async function legacyManifestPathForConfiguredTarget(scope, graph) {
19894
20446
  baseDir: scope.root
19895
20447
  });
19896
20448
  const targetRoot = resolveConfigPath(agent.root, scope.root);
19897
- const installRoot = resolve42(installRootForAdapterInstallationType(adapter, targetRoot, agent.installationType, { kind: "local" }));
20449
+ const installRoot = resolve43(installRootForAdapterInstallationType(adapter, targetRoot, agent.installationType, { kind: "local" }));
19898
20450
  const stateKey = stateKeyFor(adapter.name, {
19899
20451
  installationType: agent.installationType,
19900
20452
  stateKey: agent.stateKey,
@@ -19962,7 +20514,7 @@ async function targetStateForGraph(scope, graph, identityFleetId = scope.fleetId
19962
20514
  ssh: void 0,
19963
20515
  ...agent?.stateKey ? { stateKey: agent.stateKey } : {}
19964
20516
  };
19965
- const installRoot = resolve42(installRootForAdapterInstallationType(adapter, targetRoot, installationType, { kind: "local" }));
20517
+ const installRoot = resolve43(installRootForAdapterInstallationType(adapter, targetRoot, installationType, { kind: "local" }));
19966
20518
  const targetIdentity = resolveTargetStateIdentity({
19967
20519
  targetFingerprintParts: fingerprintParts,
19968
20520
  workspaceRoot: scope.root,
@@ -19994,16 +20546,16 @@ async function targetStateForGraph(scope, graph, identityFleetId = scope.fleetId
19994
20546
  async function installedTargetStateForGraph(scope, graph, manifests, owners, selected, identityFleetId = scope.fleetId ?? null) {
19995
20547
  const stable = await targetStateForGraph(scope, graph, identityFleetId);
19996
20548
  let state;
19997
- if (resolve42(graph.path) === resolve42(stable.graphLockPath)) {
20549
+ if (resolve43(graph.path) === resolve43(stable.graphLockPath)) {
19998
20550
  state = stable;
19999
20551
  } else {
20000
20552
  const released = await releasedTargetStateForGraph(scope, graph, identityFleetId);
20001
- if (resolve42(graph.path) !== resolve42(released.graphLockPath)) {
20553
+ if (resolve43(graph.path) !== resolve43(released.graphLockPath)) {
20002
20554
  throw new Error(`Graph lock target identity is stale or noncanonical: ${graph.path}`);
20003
20555
  }
20004
20556
  state = released;
20005
20557
  }
20006
- const manifest = manifests.find((candidate) => resolve42(candidate.path) === resolve42(state.manifestPath));
20558
+ const manifest = manifests.find((candidate) => resolve43(candidate.path) === resolve43(state.manifestPath));
20007
20559
  if (!manifest) {
20008
20560
  throw new Error(`Graph lock is not covered by its canonical install manifest: ${state.manifestPath}`);
20009
20561
  }
@@ -20027,7 +20579,7 @@ async function releasedTargetStateForGraph(scope, graph, identityFleetId = scope
20027
20579
  ...current,
20028
20580
  stateKey,
20029
20581
  targetFingerprint,
20030
- graphLockPath: join58(dirname36(graph.path), `${targetFingerprint}.graph-lock.json`),
20582
+ graphLockPath: join60(dirname36(graph.path), `${targetFingerprint}.graph-lock.json`),
20031
20583
  manifestPath: installManifestPath(current.installRoot, current.adapter, {
20032
20584
  installationType: current.installationType,
20033
20585
  stateKey
@@ -20035,7 +20587,7 @@ async function releasedTargetStateForGraph(scope, graph, identityFleetId = scope
20035
20587
  };
20036
20588
  }
20037
20589
  function assertCorrelatedGraphManifest(graph, state, manifest, owners, selected) {
20038
- if (manifest.manifest.adapter !== state.adapter || manifest.manifest.installationType !== state.installationType || manifest.manifest.stateKey !== state.stateKey || resolve42(manifest.manifest.targetRoot) !== resolve42(state.installRoot)) {
20590
+ if (manifest.manifest.adapter !== state.adapter || manifest.manifest.installationType !== state.installationType || manifest.manifest.stateKey !== state.stateKey || resolve43(manifest.manifest.targetRoot) !== resolve43(state.installRoot)) {
20039
20591
  throw new Error(`Install manifest identity does not match graph target state: ${manifest.path}`);
20040
20592
  }
20041
20593
  const entries = manifest.manifest.entries.filter((entry) => entryMatchesGraphPackages(entry, graph.lock, selected));
@@ -20043,7 +20595,7 @@ function assertCorrelatedGraphManifest(graph, state, manifest, owners, selected)
20043
20595
  throw new Error(`Graph lock is not covered by selected install-manifest contributions: ${graph.path}`);
20044
20596
  }
20045
20597
  const graphArtifacts = new Set(graph.artifactIdentities);
20046
- const graphLockDigest = sha2567(canonicalJson7(graph.lock));
20598
+ const graphLockDigest = sha2567(canonicalJson8(graph.lock));
20047
20599
  for (const entry of entries) {
20048
20600
  if (!owners.has(entry.workspaceOwner)) {
20049
20601
  throw new Error(`Graph lock manifest owner mismatch at ${manifest.path}: ${entry.workspaceOwner}.`);
@@ -20060,9 +20612,9 @@ async function legacyTargetStateForGraph(scope, graph, allowMissingNamedAgentPac
20060
20612
  return releasedTargetStateForGraph(scope, graph, null, allowMissingNamedAgentPackages);
20061
20613
  }
20062
20614
  function assertGraphIsSubset(source, destination) {
20063
- const sourceRoots = new Map(source.lock.canonical.roots.map((root) => [root.rootId, canonicalJson7(root)]));
20615
+ const sourceRoots = new Map(source.lock.canonical.roots.map((root) => [root.rootId, canonicalJson8(root)]));
20064
20616
  for (const root of destination.lock.canonical.roots) {
20065
- if (sourceRoots.get(root.rootId) !== canonicalJson7(root)) {
20617
+ if (sourceRoots.get(root.rootId) !== canonicalJson8(root)) {
20066
20618
  throw new Error(
20067
20619
  `Partially normalized destination graph diverges at root '${root.rootId}': ${destination.path}`
20068
20620
  );
@@ -20092,7 +20644,7 @@ function destinationGraphFromSource(source, targetFingerprint) {
20092
20644
  function mergeDestinationManifest(existing, state, generatedAt, desiredEntries, replaceOwners = /* @__PURE__ */ new Set()) {
20093
20645
  if (existing) {
20094
20646
  const manifest2 = existing.manifest;
20095
- if (manifest2.adapter !== state.adapter || manifest2.installationType !== state.installationType || manifest2.stateKey !== state.stateKey || resolve42(manifest2.targetRoot) !== state.installRoot) {
20647
+ if (manifest2.adapter !== state.adapter || manifest2.installationType !== state.installationType || manifest2.stateKey !== state.stateKey || resolve43(manifest2.targetRoot) !== state.installRoot) {
20096
20648
  throw new Error(`Destination manifest identity diverges from the derived target: ${existing.path}`);
20097
20649
  }
20098
20650
  }
@@ -20152,7 +20704,7 @@ async function assertEquivalentRuntimeState(entry, sourcePath, destinationPath)
20152
20704
  const content = await readFile44(path, "utf8");
20153
20705
  if (hasMergeRemovalContent(entry.mergeRemoval)) {
20154
20706
  assertExactMergeContribution(entry.mergeRemoval, entry.mergeStrategy, content);
20155
- } else if (resolve42(sourcePath) === resolve42(destinationPath) && entry.mergeStrategy !== "codex-toml-mcp") {
20707
+ } else if (resolve43(sourcePath) === resolve43(destinationPath) && entry.mergeStrategy !== "codex-toml-mcp") {
20156
20708
  assertExactMergeContribution({}, entry.mergeStrategy, content);
20157
20709
  } else {
20158
20710
  throw new Error(`Installed-state normalization cannot prove incomplete merge ownership at ${path}.`);
@@ -20163,8 +20715,8 @@ async function assertEquivalentRuntimeState(entry, sourcePath, destinationPath)
20163
20715
  await assertEquivalentRuntimeBytes(sourcePath, destinationPath, entry.hash);
20164
20716
  }
20165
20717
  function renderedEntryPathForRoot(root, entryPath) {
20166
- const normalizedRoot = resolve42(root);
20167
- const candidate = resolve42(normalizedRoot, entryPath);
20718
+ const normalizedRoot = resolve43(root);
20719
+ const candidate = resolve43(normalizedRoot, entryPath);
20168
20720
  if (candidate !== normalizedRoot && !candidate.startsWith(`${normalizedRoot}/`)) {
20169
20721
  throw new Error(`Install manifest entry escapes its target root: ${entryPath}`);
20170
20722
  }
@@ -20255,8 +20807,8 @@ function ownerMatchesGraphPackage(lock, owner, selected) {
20255
20807
  return ownerMatchesPackage(owner, selected) || lock.canonical.roots.some((root) => selected.has(root.rootId) && root.graphNodeId === owner);
20256
20808
  }
20257
20809
  function renderedEntryPath(manifest, entry) {
20258
- const root = resolve42(manifest.targetRoot);
20259
- const candidate = resolve42(root, entry.path);
20810
+ const root = resolve43(manifest.targetRoot);
20811
+ const candidate = resolve43(root, entry.path);
20260
20812
  if (candidate !== root && !candidate.startsWith(`${root}/`)) {
20261
20813
  throw new Error(`Install manifest entry escapes its target root: ${entry.path}`);
20262
20814
  }
@@ -20275,7 +20827,7 @@ function assertSimpleVerifiableEntry(entry, path) {
20275
20827
  if (entry.kind !== "file" && entry.kind !== "dir") throw new Error(`Unsupported installed entry kind at ${path}.`);
20276
20828
  }
20277
20829
  function entryIdentity(entry) {
20278
- return canonicalJson7({
20830
+ return canonicalJson8({
20279
20831
  path: entry.path,
20280
20832
  artifactType: entry.artifactType,
20281
20833
  artifactName: entry.artifactName,
@@ -20293,7 +20845,7 @@ function entryIdentity(entry) {
20293
20845
  });
20294
20846
  }
20295
20847
  function graphArtifactIdentity(artifact) {
20296
- return canonicalJson7({
20848
+ return canonicalJson8({
20297
20849
  graphNodeId: artifact.graphNodeId,
20298
20850
  type: artifact.type,
20299
20851
  name: artifact.name,
@@ -20307,7 +20859,7 @@ function graphArtifactIdentity(artifact) {
20307
20859
  });
20308
20860
  }
20309
20861
  function graphEntryIdentity(entry) {
20310
- return canonicalJson7({
20862
+ return canonicalJson8({
20311
20863
  graphNodeId: entry.graphNodeId,
20312
20864
  type: entry.artifactType,
20313
20865
  name: entry.artifactName,
@@ -20411,7 +20963,7 @@ async function buildJournalGraphLockStates(plan) {
20411
20963
  for (const transfer of plan.installedState.graphTransfers) {
20412
20964
  const sourceBefore = JSON.parse(await readFile44(transfer.sourceGraphLockPath, "utf8"));
20413
20965
  const sourceLock = await readGraphLock(transfer.sourceGraphLockPath);
20414
- const sourceDigest = sha2567(canonicalJson7(sourceLock));
20966
+ const sourceDigest = sha2567(canonicalJson8(sourceLock));
20415
20967
  if (sourceDigest !== transfer.sourceGraphLockDigest) {
20416
20968
  throw new Error(`Source graph lock changed after planning: ${transfer.sourceGraphLockPath}`);
20417
20969
  }
@@ -20429,9 +20981,9 @@ async function buildJournalGraphLockStates(plan) {
20429
20981
  continue;
20430
20982
  }
20431
20983
  const destinationBefore = await readOptionalRecord(transfer.destinationGraphLockPath);
20432
- const destinationBeforeDigest = destinationBefore ? sha2567(canonicalJson7(await readGraphLock(transfer.destinationGraphLockPath))) : null;
20984
+ const destinationBeforeDigest = destinationBefore ? sha2567(canonicalJson8(await readGraphLock(transfer.destinationGraphLockPath))) : null;
20433
20985
  const destinationAfter = destinationBefore ? await readGraphLock(transfer.destinationGraphLockPath) : destinationGraphFromSource(sourceLock, transfer.targetFingerprint);
20434
- const destinationAfterDigest = sha2567(canonicalJson7(destinationAfter));
20986
+ const destinationAfterDigest = sha2567(canonicalJson8(destinationAfter));
20435
20987
  if (destinationBeforeDigest !== transfer.destinationGraphLockDigest || destinationAfterDigest !== transfer.destinationGraphLockAfterDigest) {
20436
20988
  throw new Error(`Destination graph lock changed after planning: ${transfer.destinationGraphLockPath}`);
20437
20989
  }
@@ -20541,8 +21093,8 @@ async function assertJournalRecoverable(journal) {
20541
21093
  }
20542
21094
  for (const graphLock of journal.graphLocks) {
20543
21095
  const raw = await readOptionalRecord(graphLock.path);
20544
- const digest2 = raw ? sha2567(canonicalJson7(await readGraphLock(graphLock.path))) : null;
20545
- if (digest2 !== graphLock.beforeDigest && digest2 !== graphLock.afterDigest) {
21096
+ const digest3 = raw ? sha2567(canonicalJson8(await readGraphLock(graphLock.path))) : null;
21097
+ if (digest3 !== graphLock.beforeDigest && digest3 !== graphLock.afterDigest) {
20546
21098
  throw new Error(`Cannot recover fleet normalization because graph lock changed outside the transaction: ${graphLock.path}`);
20547
21099
  }
20548
21100
  }
@@ -20594,12 +21146,12 @@ function packageMap(config) {
20594
21146
  return result;
20595
21147
  }
20596
21148
  function configRevision(config) {
20597
- return sha2567(canonicalJson7(config));
21149
+ return sha2567(canonicalJson8(config));
20598
21150
  }
20599
21151
  function normalizationJournalPath(sourceRoot, destinationFleet) {
20600
- return join58(sourceRoot, ".agentwheel", `fleet-normalize-${destinationFleet}.journal.json`);
21152
+ return join60(sourceRoot, ".agentwheel", `fleet-normalize-${destinationFleet}.journal.json`);
20601
21153
  }
20602
- function canonicalJson7(value) {
21154
+ function canonicalJson8(value) {
20603
21155
  return JSON.stringify(sortValue(value));
20604
21156
  }
20605
21157
  function sortValue(value) {
@@ -20610,7 +21162,7 @@ function sortValue(value) {
20610
21162
  return value;
20611
21163
  }
20612
21164
  function sha2567(value) {
20613
- return createHash26("sha256").update(value).digest("hex");
21165
+ return createHash27("sha256").update(value).digest("hex");
20614
21166
  }
20615
21167
  function assertDigest(value) {
20616
21168
  if (!/^[a-f0-9]{64}$/.test(value)) throw new Error(`Invalid plan digest: ${value}`);
@@ -20633,6 +21185,7 @@ var commandGovernance = {
20633
21185
  "fleet normalize": "governed-apply-or-recover",
20634
21186
  "cache prune": "governed-apply",
20635
21187
  add: "governed-always",
21188
+ pin: "governed-always",
20636
21189
  list: "incidental-cache",
20637
21190
  search: "incidental-cache",
20638
21191
  try: "incidental-cache",
@@ -20655,6 +21208,7 @@ var commandGovernance = {
20655
21208
  "ownership handoff": "governed-unless-dry-run",
20656
21209
  "ownership recovery-plan": "incidental-cache",
20657
21210
  "ownership retire-stale": "governed-apply",
21211
+ "ownership release-claim": "governed-apply",
20658
21212
  "ownership adopt-legacy": "governed-apply",
20659
21213
  "mcp retire": "governed-apply",
20660
21214
  eject: "governed-always",
@@ -20688,6 +21242,7 @@ function requiresCleanMutationPreflight(path) {
20688
21242
  "init",
20689
21243
  "fleet register",
20690
21244
  "add",
21245
+ "pin",
20691
21246
  "package migrate",
20692
21247
  "remember",
20693
21248
  "journal abort"
@@ -20761,25 +21316,34 @@ fleetCommand.command("normalize").description("plan or apply duplicate desired-s
20761
21316
  });
20762
21317
  cacheCommand.command("prune").description("remove old Git source snapshots while preserving locked commits").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("--keep <count>", "newest snapshots to retain per source", parsePositiveInteger, 3).option("--apply", "delete the selected snapshots; without this flag only preview", false).action(async (options) => {
20763
21318
  const targetRoot = await workspaceContextRootFromOptions(normalizeRuntimeScopeOptions(options));
20764
- const cacheRoot = join59(targetRoot, ".agentwheel", "cache");
21319
+ const cacheRoot = join61(targetRoot, ".agentwheel", "cache");
20765
21320
  const result = await pruneGitCache(cacheRoot, { keepSnapshots: options.keep, dryRun: !options.apply });
20766
21321
  const verb = options.apply ? "Removed" : "Would remove";
20767
21322
  for (const path of result.removedPaths) console.log(`${verb} ${path}`);
20768
21323
  console.log(`${options.apply ? "Pruned" : "Preview"}: ${result.removedPaths.length} snapshots; retained ${result.retainedPaths.length}.`);
20769
21324
  });
20770
- 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) => {
20771
21326
  const normalizedOptions = normalizeRuntimeScopeOptions(options);
20772
21327
  const targetRoot = await workspaceRootFromOptions(normalizedOptions);
20773
21328
  const entry = await packageEntryFromSource(source, targetRoot, normalizedOptions);
20774
21329
  await writeWorkspaceConfig(targetRoot, upsertPackage(await readWorkspaceConfig(targetRoot), entry));
20775
21330
  console.log(`Added ${entry.name}. Preview: agentwheel plan - Apply: agentwheel install`);
20776
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
+ });
20777
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) => {
20778
21342
  const targetRoot = await workspaceContextRootFromOptions(normalizeRuntimeScopeOptions(options));
20779
21343
  const resolvedInput = await resolvePackageSource(source, targetRoot);
20780
21344
  const selectedArtifacts = selectedArtifactsFromOptionsOrRegistry(options, resolvedInput.registryEntry);
20781
21345
  const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
20782
- const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join59(targetRoot, ".agentwheel", "cache") }))));
21346
+ const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join61(targetRoot, ".agentwheel", "cache") }))));
20783
21347
  try {
20784
21348
  const artifacts = filterArtifactsBySelection(await driver.list(resolved), selectedArtifacts);
20785
21349
  for (const artifact of artifacts) {
@@ -20848,7 +21412,7 @@ program.command("try").description("read and validate one skill for the current
20848
21412
  const resolvedInput = await resolvePackageSource(source, targetRoot);
20849
21413
  const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
20850
21414
  const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, {
20851
- cacheRoot: join59(targetRoot, ".agentwheel", "cache")
21415
+ cacheRoot: join61(targetRoot, ".agentwheel", "cache")
20852
21416
  }))));
20853
21417
  try {
20854
21418
  const trial = await createSkillTrial(driver, resolved, selectedArtifactsFromOptionsOrRegistry(options, resolvedInput.registryEntry));
@@ -20870,7 +21434,7 @@ program.command("scan").description("scan a package source for validation findin
20870
21434
  const targetRoot = await workspaceContextRootFromOptions(normalizeRuntimeScopeOptions(options));
20871
21435
  const resolvedInput = await resolvePackageSource(source, targetRoot);
20872
21436
  const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
20873
- const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join59(targetRoot, ".agentwheel", "cache") }))));
21437
+ const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join61(targetRoot, ".agentwheel", "cache") }))));
20874
21438
  try {
20875
21439
  const result = await driver.scan(resolved);
20876
21440
  if (result.findings.length === 0) {
@@ -20885,10 +21449,10 @@ program.command("scan").description("scan a package source for validation findin
20885
21449
  await releaseGitSnapshotLease(resolved.cacheLeasePath);
20886
21450
  }
20887
21451
  });
20888
- program.command("plan").description("preview what install would reconcile without writing").argument("[name-or-source]", "configured package name/source or package source to preview").option("--driver <driver>", "source driver").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").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>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--profile <name>", "workspace runtime profile").option("--mode <mode>", "pinned or tracking").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", false).option("--suggestion <alias>", "include one suggested companion alias (repeatable or comma-separated)", collectSuggestionOption, []).option("--override <source-or-package::type/name>", "for source previews, allow the source to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--dry-run", "accepted for symmetry; plan never writes", false).option("--format <fmt>", "output format: human|json|mermaid|html", "human").option("--json", "print the resolved plan as JSON", false).option("--force-drift", "replace drifted managed artifacts during install planning", false).option("--force-foreign-state", "plan even when another workspace owns install state at the same paths", false).option("--force-conflict", "adopt unmanaged destinations when their content already matches the desired artifact", false).option("--replace-conflict", "replace unmanaged destinations even when their content differs", false).option("--recover-legacy-state", "build a stable state while preserving invalid legacy candidates", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "exclude unrelated configured workspace packages", false).option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (source, options) => {
21452
+ program.command("plan").description("preview what install would reconcile without writing").argument("[name-or-source]", "configured package name/source or package source to preview").option("--driver <driver>", "source driver").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").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>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--profile <name>", "workspace runtime profile").option("--mode <mode>", "pinned or tracking").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", false).option("--suggestion <alias>", "include one suggested companion alias (repeatable or comma-separated)", collectSuggestionOption, []).option("--override <source-or-package::type/name>", "for source previews, allow the source to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--dry-run", "accepted for symmetry; plan never writes", false).option("--adopt", "adopt unmanaged destinations; managed drift and foreign ownership remain protected", false).option("--format <fmt>", "output format: human|json|mermaid|html", "human").option("--json", "print the resolved plan as JSON", false).option("--force-drift", "replace drifted managed artifacts during install planning", false).option("--force-foreign-state", "plan even when another workspace owns install state at the same paths", false).option("--force-conflict", "adopt unmanaged destinations when their content already matches the desired artifact", false).option("--replace-conflict", "replace unmanaged destinations even when their content differs", false).option("--recover-legacy-state", "build a stable state while preserving invalid legacy candidates", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "exclude unrelated configured workspace packages", false).option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (source, options) => {
20889
21453
  await runInstallCommand(source, { ...options, dryRun: true }, { apply: false });
20890
21454
  });
20891
- program.command("install").description("install configured packages into runtime targets").argument("[name-or-source]", "configured package name/source or package source to add and install").option("--driver <driver>", "source driver").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").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>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--mode <mode>", "pinned or tracking").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", false).option("--suggestion <alias>", "include one suggested companion alias (repeatable or comma-separated)", collectSuggestionOption, []).option("--override <source-or-package::type/name>", "when adding a source, allow it to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--profile <name>", "workspace runtime profile").option("--dry-run", "show plan without writing", false).option("--format <fmt>", "output format: human|json|mermaid|html", "human").option("--json", "print the resolved plan as JSON", false).option("--force-drift", "replace drifted managed artifacts", false).option("--force-foreign-state", "plan even when another workspace owns install state at the same paths", false).option("--force-conflict", "adopt unmanaged destinations when their content already matches the desired artifact", false).option("--replace-conflict", "replace unmanaged destinations even when their content differs", false).option("--recover-legacy-state", "build a stable state while preserving invalid legacy candidates", false).option("--execute-plugins", "execute semantic plugin installs", false).option("--reload-runtimes", "run configured runtime reload commands after executed semantic plugin changes", false).option("--restart-runtimes", "alias for --reload-runtimes", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "exclude unrelated configured workspace packages", false).option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).addHelpText("after", "\nScoped install never removes files owned only by other configured packages; run a full install to reconcile those removals.\n").action(async (source, options) => {
21455
+ program.command("install").description("install configured packages into runtime targets").argument("[name-or-source]", "configured package name/source or package source to add and install").option("--driver <driver>", "source driver").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").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>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--mode <mode>", "pinned or tracking").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", false).option("--suggestion <alias>", "include one suggested companion alias (repeatable or comma-separated)", collectSuggestionOption, []).option("--override <source-or-package::type/name>", "when adding a source, allow it to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--profile <name>", "workspace runtime profile").option("--dry-run", "show plan without writing", false).option("--adopt", "adopt unmanaged destinations; managed drift and foreign ownership remain protected", false).option("--format <fmt>", "output format: human|json|mermaid|html", "human").option("--json", "print the resolved plan as JSON", false).option("--force-drift", "replace drifted managed artifacts", false).option("--force-foreign-state", "plan even when another workspace owns install state at the same paths", false).option("--force-conflict", "adopt unmanaged destinations when their content already matches the desired artifact", false).option("--replace-conflict", "replace unmanaged destinations even when their content differs", false).option("--recover-legacy-state", "build a stable state while preserving invalid legacy candidates", false).option("--execute-plugins", "execute semantic plugin installs", false).option("--reload-runtimes", "run configured runtime reload commands after executed semantic plugin changes", false).option("--restart-runtimes", "alias for --reload-runtimes", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "exclude unrelated configured workspace packages", false).option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).addHelpText("after", "\nScoped install never removes files owned only by other configured packages; run a full install to reconcile those removals.\n").action(async (source, options) => {
20892
21456
  await runInstallCommand(source, options, { apply: !options.dryRun });
20893
21457
  });
20894
21458
  program.command("serve").description("serve a read-only live dashboard for the resolved install plan").argument("[name-or-source]", "configured package name/source or package source to preview").option("--driver <driver>", "source driver").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").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>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--profile <name>", "workspace runtime profile").option("--mode <mode>", "pinned or tracking").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", false).option("--suggestion <alias>", "include one suggested companion alias (repeatable or comma-separated)", collectSuggestionOption, []).option("--override <source-or-package::type/name>", "for source previews, allow the source to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--force-drift", "replace drifted managed artifacts during install planning", false).option("--force-foreign-state", "plan even when another workspace owns install state at the same paths", false).option("--force-conflict", "adopt unmanaged destinations when their content already matches the desired artifact", false).option("--replace-conflict", "replace unmanaged destinations even when their content differs", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "exclude unrelated configured workspace packages", false).option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).option("--bind <addr>", "interface to bind", "127.0.0.1").option("--port <n>", "TCP port (0 selects an ephemeral port)", "8765").option("--interval <seconds>", "background re-render cadence in seconds", "60").option("--once", "render once and skip the background re-render loop", false).action(async (source, options) => {
@@ -21051,6 +21615,48 @@ program.command("remember").description("append text to the local instructions o
21051
21615
  console.log(nextInstallNudge());
21052
21616
  });
21053
21617
  var ownershipCommand = program.command("ownership").description("inspect and transfer manifest ownership without rewriting runtime artifacts");
21618
+ ownershipCommand.command("release-claim").description("release one exact plain ownership claim while preserving runtime bytes and package declarations").argument("<selector>", "exact artifact selector in type/name form").requiredOption("--path <relative-path>", "exact owned runtime path from the install manifest").requiredOption("--state-key <key>", "exact source install-manifest state key").requiredOption("--from-workspace-root <path>", "exact current workspace owner root").option("--from-fleet-id <id>", "qualify the recorded owner with its Fleet id").option("--fleet <id>", "governing registered Fleet workspace").option("--user", "use the user workspace", false).option("--local", "use the nearest local workspace", false).option("--adapter <adapter>", "built-in adapter").option("--adapter-config <path>", "adapter JSON/JSONC file").option("-i, --installation-type <type>", "exact installation type").option("-t, --target-root <path>", "runtime/project root").option("--agent <name>", "configured agent resolving to one local target").option("--profile <name>", "profile resolving to one local target").option("--plan-digest <sha256>", "reviewed plan digest; required with --apply").option("--expected-source-revision <sha256>", "reviewed source manifest revision; required with --apply").option("--expected-inventory-revision <sha256>", "reviewed manifest inventory revision; required with --apply").option("--apply", "apply the exact reviewed metadata-only release", false).option("--json", "print the complete plan or result as JSON", false).action(async (selector, _options, command) => {
21619
+ const options = command.optsWithGlobals();
21620
+ if (!options.reason) throw new Error("Ownership release requires --reason <why> for planning and applying.");
21621
+ const normalized = normalizeRuntimeScopeOptions(options);
21622
+ const targets = await resolveCliTargets(normalized);
21623
+ if (targets.length !== 1) throw new Error("Ownership release requires exactly one target.");
21624
+ const target = targets[0];
21625
+ const adapterOptions = adapterOptionsForTarget(target, normalized);
21626
+ const adapter = await resolveAdapterForTarget(target, adapterOptions);
21627
+ const installationType = normalized.installationType ?? target.installationType ?? resolveInstallationTypeForAdapter(adapter);
21628
+ const state = installStateForTarget(target, adapter, adapterOptions, installationType);
21629
+ const request = {
21630
+ workspaceRoot: await workspaceRootFromOptions(normalized),
21631
+ fromWorkspaceRoot: normalizeCliPath(options.fromWorkspaceRoot),
21632
+ fromFleetId: options.fromFleetId,
21633
+ targetRoot: state.installRoot,
21634
+ adapter: adapter.name,
21635
+ installationType,
21636
+ stateKey: options.stateKey,
21637
+ selector,
21638
+ path: options.path,
21639
+ reason: options.reason,
21640
+ planDigest: options.planDigest,
21641
+ expectedSourceRevision: options.expectedSourceRevision,
21642
+ expectedInventoryRevision: options.expectedInventoryRevision,
21643
+ operationId: options.operationId,
21644
+ noCommit: options.commit === false,
21645
+ transport: transportForTarget(target)
21646
+ };
21647
+ const result = options.apply ? await applyReleaseOwnership(request) : await planReleaseOwnership(request);
21648
+ if (options.json) {
21649
+ console.log(JSON.stringify(result, null, 2));
21650
+ return;
21651
+ }
21652
+ console.log(`${options.apply ? "Released ownership claim" : "Ownership release plan"}: ${result.selector} at ${result.path}`);
21653
+ console.log(`Owner: ${result.owner}`);
21654
+ console.log(`Source: ${result.source.stateKey} revision ${result.source.revision}`);
21655
+ console.log(`Recorded hash: ${result.recordedHash}; actual runtime hash: ${result.runtimeHash}`);
21656
+ console.log(`Inventory revision: ${result.manifestInventoryRevision}`);
21657
+ console.log(`Plan digest: ${result.planDigest}`);
21658
+ if (!options.apply) console.log("Apply with this same scope and reason plus --apply --plan-digest, --expected-source-revision and --expected-inventory-revision from this plan.");
21659
+ });
21054
21660
  ownershipCommand.command("handoff").description("transfer one managed artifact between Agentwheel workspace roots").argument("<selector>", "exact artifact selector in type/name form").option("--from-workspace-root <path>", "current owning workspace root").option("--from-unknown-owner", "hand off an artifact recorded as workspace:unknown", false).requiredOption("--to-workspace-root <path>", "new owning workspace root").option("--to-fleet <id>", "qualify the new owner with a registered fleet id").option("--expected-hash <sha256>", "expected recorded artifact hash; required when applying").option("--expected-revision <sha256>", "expected install manifest revision; required when applying").option("--carry-drift", "accept a file or directory whose runtime differs from the recorded hash; the recorded hash is kept", false).option("--expected-runtime-hash <sha256>", "expected drifted runtime hash; required when applying with --carry-drift").option("--adapter <adapter>", "built-in adapter").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>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--profile <name>", "workspace runtime profile (must resolve to one target)").option("--dry-run", "validate all preconditions without writing the manifest", false).action(async (selector, options) => {
21055
21661
  if (!options.dryRun && (!options.expectedHash || !options.expectedRevision)) {
21056
21662
  throw new Error("Applying an ownership handoff requires --expected-hash and --expected-revision from a reviewed --dry-run.");
@@ -21078,7 +21684,7 @@ ownershipCommand.command("handoff").description("transfer one managed artifact b
21078
21684
  const toWorkspaceRoot = normalizeCliPath(options.toWorkspaceRoot);
21079
21685
  if (options.toFleet) {
21080
21686
  const fleet = await showRegisteredFleet(options.toFleet);
21081
- if (resolve43(fleet.root) !== resolve43(toWorkspaceRoot)) {
21687
+ if (resolve44(fleet.root) !== resolve44(toWorkspaceRoot)) {
21082
21688
  throw new Error(`Destination fleet '${options.toFleet}' is registered at ${fleet.root}, not ${toWorkspaceRoot}.`);
21083
21689
  }
21084
21690
  }
@@ -21119,8 +21725,8 @@ ownershipCommand.command("recovery-plan").description("write a read-only per-pat
21119
21725
  const adapter = await resolveAdapterForTarget(target, {});
21120
21726
  const transport = transportForTarget(target);
21121
21727
  const requestedReport = normalizeCliPath(options.report);
21122
- const reportPath = join59(await realpath4(dirname37(requestedReport)), basename24(requestedReport));
21123
- const reportInsideTarget = relative18(resolve43(target.targetRoot), reportPath);
21728
+ const reportPath = join61(await realpath4(dirname37(requestedReport)), basename24(requestedReport));
21729
+ const reportInsideTarget = relative19(resolve44(target.targetRoot), reportPath);
21124
21730
  if (reportInsideTarget === "" || !reportInsideTarget.startsWith("..") && !isAbsolute14(reportInsideTarget)) {
21125
21731
  throw new Error("Recovery report must be outside the runtime target root.");
21126
21732
  }
@@ -21151,7 +21757,7 @@ ownershipCommand.command("retire-stale").description("retire stale source-manife
21151
21757
  const normalizedOptions = normalizeRuntimeScopeOptions(options);
21152
21758
  const fleet = await showRegisteredFleet(options.fleet);
21153
21759
  const toWorkspaceRoot = normalizeCliPath(options.toWorkspaceRoot);
21154
- if (resolve43(fleet.root) !== resolve43(toWorkspaceRoot)) {
21760
+ if (resolve44(fleet.root) !== resolve44(toWorkspaceRoot)) {
21155
21761
  throw new Error(`Destination Fleet '${options.fleet}' is registered at ${fleet.root}, not ${toWorkspaceRoot}.`);
21156
21762
  }
21157
21763
  const targets = await resolveCliTargets(normalizedOptions);
@@ -21159,7 +21765,7 @@ ownershipCommand.command("retire-stale").description("retire stale source-manife
21159
21765
  throw new Error(`Stale ownership retirement requires exactly one destination Fleet target, found ${targets.length}.`);
21160
21766
  }
21161
21767
  const target = targets[0];
21162
- if (target.fleetId !== options.fleet || resolve43(target.workspaceRoot) !== resolve43(fleet.root)) {
21768
+ if (target.fleetId !== options.fleet || resolve44(target.workspaceRoot) !== resolve44(fleet.root)) {
21163
21769
  throw new Error(`Resolved target does not belong to destination Fleet '${options.fleet}'.`);
21164
21770
  }
21165
21771
  const adapterOptions = adapterOptionsForTarget(target, normalizedOptions);
@@ -21231,7 +21837,7 @@ ownershipCommand.command("retire-stale").description("retire stale source-manife
21231
21837
  console.log(`Plan digest: ${result.planDigest}`);
21232
21838
  if (!options.apply) console.log(`Apply: ${applyCommand}`);
21233
21839
  });
21234
- ownershipCommand.command("adopt-legacy").description("move proven legacy-keyed ownership into this workspace's stable target state without rewriting runtime artifacts").requiredOption("--source-state-key <key>", "exact legacy install-manifest state key").requiredOption("--from-workspace-root <path>", "exact plain workspace owner root of the entries to move").option("--agent <name>", "named agent of this workspace").option("--profile <name>", "workspace profile resolving to one target").option("-i, --installation-type <type>", "installation type (for example local or user)").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("--carry-drift", "also move entries whose runtime differs from the recorded hash; the recorded hash is kept", false).option("--plan-digest <sha256>", "reviewed plan digest; required with --apply").option("--expected-source-revision <sha256>", "reviewed source manifest revision; required with --apply").option("--expected-destination-revision <sha256|absent>", "reviewed destination manifest revision; required with --apply").option("--expected-inventory-revision <sha256>", "reviewed runtime manifest inventory revision; required with --apply").option("--apply", "apply the exact reviewed metadata-only adoption", false).option("--json", "print the complete deterministic plan as JSON", false).action(async (options) => {
21840
+ ownershipCommand.command("adopt-legacy").description("move proven legacy-keyed ownership into this workspace's stable target state without rewriting runtime artifacts").requiredOption("--source-state-key <key>", "exact legacy install-manifest state key").requiredOption("--from-workspace-root <path>", "exact plain workspace owner root of the entries to move").option("--agent <name>", "named agent of this workspace").option("--profile <name>", "workspace profile resolving to one target").option("-i, --installation-type <type>", "installation type (for example local or user)").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("--carry-drift", "also move drifted plain entries while keeping the recorded hash; forbidden for managed blocks", false).option("--plan-digest <sha256>", "reviewed plan digest; required with --apply").option("--expected-source-revision <sha256>", "reviewed source manifest revision; required with --apply").option("--expected-destination-revision <sha256|absent>", "reviewed destination manifest revision; required with --apply").option("--expected-inventory-revision <sha256>", "reviewed runtime manifest inventory revision; required with --apply").option("--apply", "apply the exact reviewed metadata-only adoption", false).option("--json", "print the complete deterministic plan as JSON", false).action(async (options) => {
21235
21841
  if (Boolean(options.agent) === Boolean(options.profile)) {
21236
21842
  throw new Error("Legacy ownership adoption requires exactly one of --agent or --profile.");
21237
21843
  }
@@ -21281,7 +21887,7 @@ ownershipCommand.command("adopt-legacy").description("move proven legacy-keyed o
21281
21887
  ];
21282
21888
  for (const { flag, requested, resolved, none } of requestedAdapterSettings) {
21283
21889
  if (requested === void 0) continue;
21284
- if (resolved !== void 0 && resolve43(target.workspaceRoot, requested) === resolve43(target.workspaceRoot, resolved)) continue;
21890
+ if (resolved !== void 0 && resolve44(target.workspaceRoot, requested) === resolve44(target.workspaceRoot, resolved)) continue;
21285
21891
  throw new Error(`${flag} ${requested} does not match what install resolves for the configured packages: ${resolved ?? none}.`);
21286
21892
  }
21287
21893
  const adapter = await resolveAdapterForTarget(group.target, adapterOptions);
@@ -21451,7 +22057,7 @@ journalCommand.command("list").description("show pending apply journals for reso
21451
22057
  if (!journal) continue;
21452
22058
  pending += 1;
21453
22059
  console.log(`PENDING ${state.adapter.name}/${state.installationType} at ${state.installRoot}`);
21454
- console.log(` journal: ${join59(state.installRoot, ".agentwheel", `${state.state.stateKey}.apply-journal.json`)}`);
22060
+ console.log(` journal: ${join61(state.installRoot, ".agentwheel", `${state.state.stateKey}.apply-journal.json`)}`);
21455
22061
  console.log(` stateKey: ${state.state.stateKey}`);
21456
22062
  console.log(` createdAt: ${journal.createdAt}`);
21457
22063
  console.log(` updatedAt: ${journal.updatedAt}`);
@@ -21515,7 +22121,11 @@ program.command("doctor").description("check agentwheel runtime setup and compan
21515
22121
  await printDoctor(targets[0], normalizedOptions);
21516
22122
  });
21517
22123
  async function runInstallCommand(nameOrSource, options, behavior) {
21518
- const normalizedOptions = normalizeRuntimeScopeOptions(options, { defaultUser: shouldDefaultUserInstall(nameOrSource, options) });
22124
+ const normalizedOptions = normalizeRuntimeScopeOptions({
22125
+ ...options,
22126
+ forceConflict: options.forceConflict || options.adopt,
22127
+ replaceConflict: options.replaceConflict || options.adopt
22128
+ }, { defaultUser: shouldDefaultUserInstall(nameOrSource, options) });
21519
22129
  const outputFormat = effectivePlanOutputFormat(normalizedOptions);
21520
22130
  const composite = await resolveSelectedCompositeProfile(normalizedOptions);
21521
22131
  if (composite) {
@@ -21797,14 +22407,14 @@ async function packageEntryFromSource(source, targetRoot, options) {
21797
22407
  );
21798
22408
  }
21799
22409
  const bundle = options.deferGraphRendering ? await stageSourceRaw(driver, resolvedSource, {
21800
- cacheRoot: join59(targetRoot, ".agentwheel", "cache"),
22410
+ cacheRoot: join61(targetRoot, ".agentwheel", "cache"),
21801
22411
  mode: options.mode,
21802
22412
  ref: initialVersion?.ref,
21803
22413
  frozenLock: lockMode
21804
22414
  }) : await stageSource(driver, resolvedSource, {
21805
22415
  workspaceRoot: targetRoot,
21806
22416
  adapter,
21807
- cacheRoot: join59(targetRoot, ".agentwheel", "cache"),
22417
+ cacheRoot: join61(targetRoot, ".agentwheel", "cache"),
21808
22418
  mode: options.mode,
21809
22419
  ref: initialVersion?.ref,
21810
22420
  frozenLock: lockMode,
@@ -21822,6 +22432,7 @@ async function packageEntryFromSource(source, targetRoot, options) {
21822
22432
  source: resolvedSource,
21823
22433
  driver: driverName,
21824
22434
  adapter: adapter.name,
22435
+ runtimes: options.runtimes?.length ? options.runtimes : void 0,
21825
22436
  installationType,
21826
22437
  adapterConfig: options.adapterConfig,
21827
22438
  adapterModule: options.adapterModule,
@@ -22412,7 +23023,7 @@ function scopeUpdatePlanToDependencies(result, selectors, previousLock, manifest
22412
23023
  selectedPreviousNodeIds,
22413
23024
  selectedRootIds
22414
23025
  );
22415
- const graphLockDigest = createHash27("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
23026
+ const graphLockDigest = createHash28("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
22416
23027
  return {
22417
23028
  ...result,
22418
23029
  bundle: { ...result.bundle, graphLock },
@@ -22538,7 +23149,7 @@ function operationBelongsToDependencyUpdate(operation, allowedNodeIds, allowedNa
22538
23149
  function scopeInstallPlanToArtifact(result, rootId, focused, manifest) {
22539
23150
  const scoped = scopePlanOperationsToArtifact(result, rootId, focused, manifest);
22540
23151
  const graphLock = focusedGraphLockForInstall(scoped.bundle.graphLock, rootId, focused);
22541
- const graphLockDigest = createHash27("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
23152
+ const graphLockDigest = createHash28("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
22542
23153
  return {
22543
23154
  ...scoped,
22544
23155
  bundle: { ...scoped.bundle, graphLock },
@@ -22549,7 +23160,7 @@ function scopeInstallPlanToArtifact(result, rootId, focused, manifest) {
22549
23160
  function scopeUpdatePlanToArtifact(result, rootId, focused, previousLock, manifest) {
22550
23161
  const scoped = scopePlanOperationsToArtifact(result, rootId, focused, manifest, previousLock);
22551
23162
  const graphLock = mergeFocusedArtifactGraphLock(scoped.bundle.graphLock, previousLock, rootId, focused);
22552
- const graphLockDigest = createHash27("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
23163
+ const graphLockDigest = createHash28("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
22553
23164
  return {
22554
23165
  ...scoped,
22555
23166
  bundle: { ...scoped.bundle, graphLock },
@@ -22844,7 +23455,7 @@ function scopeUpdatePlanToRoot(result, rootId, previousLock, manifest) {
22844
23455
  selectedPreviousNodeIds,
22845
23456
  /* @__PURE__ */ new Set([rootId])
22846
23457
  );
22847
- const graphLockDigest = createHash27("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
23458
+ const graphLockDigest = createHash28("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
22848
23459
  return {
22849
23460
  ...scoped,
22850
23461
  bundle: { ...scoped.bundle, graphLock },
@@ -22916,7 +23527,7 @@ function keepManifestEntryOperation(entry, targetRoot, scopeDescription, operati
22916
23527
  artifactType: entry.artifactType,
22917
23528
  artifactName: entry.artifactName,
22918
23529
  kind: entry.kind,
22919
- destPath: operation?.destPath ?? join59(targetRoot, entry.path),
23530
+ destPath: operation?.destPath ?? join61(targetRoot, entry.path),
22920
23531
  relativeDestPath: entry.path,
22921
23532
  desiredHash: entry.sourceHash,
22922
23533
  currentHash: operation?.currentHash ?? entry.hash,
@@ -23117,7 +23728,7 @@ function installRootContextForTarget(target) {
23117
23728
  return { kind: target.transport, homeRoot: target.runAs?.home };
23118
23729
  }
23119
23730
  async function withFreshReadOnlyGraphPlan(target, adapter, adapterOptions, installationType, packages, use) {
23120
- const stage = await mkdtemp6(join59(tmpdir7(), "agentwheel-recovery-"));
23731
+ const stage = await mkdtemp6(join61(tmpdir7(), "agentwheel-recovery-"));
23121
23732
  const priorTmpdir = process.env.TMPDIR;
23122
23733
  try {
23123
23734
  process.env.TMPDIR = stage;
@@ -23149,8 +23760,8 @@ async function withFreshReadOnlyGraphPlan(target, adapter, adapterOptions, insta
23149
23760
  yes: true,
23150
23761
  freshGraphOnly: true,
23151
23762
  deferForeignStateCheck: true,
23152
- cacheRoot: join59(stage, "source-cache"),
23153
- registryCachePath: join59(stage, "registry.json")
23763
+ cacheRoot: join61(stage, "source-cache"),
23764
+ registryCachePath: join61(stage, "registry.json")
23154
23765
  });
23155
23766
  return await use(graphPlan);
23156
23767
  } finally {
@@ -23237,7 +23848,7 @@ async function resolveCliTargetState(target, options) {
23237
23848
  migration: prior.migration,
23238
23849
  targetStateFilePreconditions: {
23239
23850
  graphLockPath: stableGraphLockPath,
23240
- graphLockRevision: stableLock ? createHash27("sha256").update(canonicalGraphLockJson(stableLock)).digest("hex") : null,
23851
+ graphLockRevision: stableLock ? createHash28("sha256").update(canonicalGraphLockJson(stableLock)).digest("hex") : null,
23241
23852
  sourceLockRevision: computeSourceLockRevision(stableSourceLock)
23242
23853
  }
23243
23854
  };
@@ -23260,7 +23871,7 @@ async function collectTargetStatus(target, options) {
23260
23871
  const pending = await collectPendingInstallWork(target, options);
23261
23872
  const foreignObservations = pending.foreignStateObservations;
23262
23873
  const effectiveGraphLock = graphLock ?? pending.observedGraphLock;
23263
- const observedManifestRevision = foreignObservations.length > 0 ? createHash27("sha256").update(JSON.stringify(foreignObservations.map((observation) => [
23874
+ const observedManifestRevision = foreignObservations.length > 0 ? createHash28("sha256").update(JSON.stringify(foreignObservations.map((observation) => [
23264
23875
  observation.fileName,
23265
23876
  observation.manifestRevision
23266
23877
  ]).sort())).digest("hex") : null;
@@ -23507,7 +24118,7 @@ async function assertCompositeMutationSupported(workspaceRoot, profile, readOnly
23507
24118
  `Composite-profile mutation is refused before member execution because ${member.id} uses ${member.transport}; durable remote policy and recovery preflight is not implemented.`
23508
24119
  );
23509
24120
  }
23510
- const memberRoot = resolve43(workspaceRoot, member.workspace);
24121
+ const memberRoot = resolve44(workspaceRoot, member.workspace);
23511
24122
  const memberPolicy = await mutationPolicyForWorkspace(memberRoot);
23512
24123
  if (memberPolicy?.revisioning.mode === "commit-after-verify") {
23513
24124
  throw new Error(
@@ -23744,12 +24355,12 @@ async function printDoctor(target, options) {
23744
24355
  const requestedSkills = doctorSkillRequests(target, options);
23745
24356
  const skills = [];
23746
24357
  for (const request of requestedSkills) {
23747
- const skillPath = join59(state.installRoot, targetMapping.dest, request.name);
24358
+ const skillPath = join61(state.installRoot, targetMapping.dest, request.name);
23748
24359
  const exists2 = await pathExists(skillPath);
23749
24360
  const manifestEntry = manifest?.entries.find((entry) => {
23750
24361
  if (entry.artifactType !== "skills") return false;
23751
24362
  const legacyInstallName = "installName" in entry && typeof entry.installName === "string" ? entry.installName : void 0;
23752
- return entry.artifactName === request.name || legacyInstallName === request.name || entry.path === join59(targetMapping.dest, request.name);
24363
+ return entry.artifactName === request.name || legacyInstallName === request.name || entry.path === join61(targetMapping.dest, request.name);
23753
24364
  });
23754
24365
  const status = manifestEntry ? "managed" : exists2 ? "present-unmanaged" : "missing";
23755
24366
  skills.push({
@@ -23829,7 +24440,7 @@ function doctorSkillLabel(name) {
23829
24440
  return `${name} skill`;
23830
24441
  }
23831
24442
  function isSyncwheelWorkspace(targetRoot) {
23832
- return existsSync(join59(targetRoot, ".syncwheel", "manifest.json"));
24443
+ return existsSync(join61(targetRoot, ".syncwheel", "manifest.json"));
23833
24444
  }
23834
24445
  function skillInstallCommand(adapter, installationType, options, skill, behavior = {}) {
23835
24446
  const args = [
@@ -23858,7 +24469,7 @@ function shellQuoteArg2(value) {
23858
24469
  if (/^[A-Za-z0-9_./:@=-]+$/.test(value)) return value;
23859
24470
  return `'${value.replaceAll("'", `'"'"'`)}'`;
23860
24471
  }
23861
- function collectSelectOption(value, previous) {
24472
+ function collectSelectOption(value, previous = []) {
23862
24473
  return [...previous, ...splitSelectorList(value)];
23863
24474
  }
23864
24475
  function parsePositiveInteger(value) {
@@ -23992,14 +24603,14 @@ function looksLikeSourceSpecifier(value) {
23992
24603
  }
23993
24604
  function normalizeCliPath(value) {
23994
24605
  if (value === "~") return homedir18();
23995
- if (value.startsWith("~/")) return resolve43(homedir18(), value.slice(2));
23996
- return resolve43(value);
24606
+ if (value.startsWith("~/")) return resolve44(homedir18(), value.slice(2));
24607
+ return resolve44(value);
23997
24608
  }
23998
24609
  function shellQuoteArgument(value) {
23999
24610
  return /^[a-z0-9_./:@%+=,-]+$/i.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`;
24000
24611
  }
24001
24612
  function isHomePath(path) {
24002
- return resolve43(path) === resolve43(homedir18());
24613
+ return resolve44(path) === resolve44(homedir18());
24003
24614
  }
24004
24615
  function adapterListFromOption(adapter) {
24005
24616
  if (!adapter) return [];
@@ -24054,11 +24665,11 @@ function filterUninstallPlanBySelection(plan, selected) {
24054
24665
  };
24055
24666
  }
24056
24667
  async function initPackage(root) {
24057
- await mkdir26(join59(root, "instructions"), { recursive: true });
24058
- await mkdir26(join59(root, "rules"), { recursive: true });
24059
- await mkdir26(join59(root, "skills"), { recursive: true });
24060
- const manifestPath = join59(root, "openpack.json");
24061
- const instructionsPath = join59(root, "instructions", "AGENTS.md");
24668
+ await mkdir27(join61(root, "instructions"), { recursive: true });
24669
+ await mkdir27(join61(root, "rules"), { recursive: true });
24670
+ await mkdir27(join61(root, "skills"), { recursive: true });
24671
+ const manifestPath = join61(root, "openpack.json");
24672
+ const instructionsPath = join61(root, "instructions", "AGENTS.md");
24062
24673
  const manifest = {
24063
24674
  schemaVersion: CURRENT_OPENPACK_SCHEMA_VERSION,
24064
24675
  name: "example/agentwheel-package",
@@ -24120,7 +24731,7 @@ function withFleetExample(config) {
24120
24731
  };
24121
24732
  }
24122
24733
  async function findAgentwheelPackageRoot(start) {
24123
- let current = resolve43(start);
24734
+ let current = resolve44(start);
24124
24735
  while (true) {
24125
24736
  if (await findPackageManifestPath(current, { warnLegacy: false })) return current;
24126
24737
  const parent = dirname37(current);
@@ -24248,14 +24859,14 @@ async function governedCommandContext(command, options) {
24248
24859
  const kind = String(command.args[0] ?? "workspace");
24249
24860
  return {
24250
24861
  workspaceRoot: workspaceRoot2,
24251
- anticipatedPaths: kind === "package" ? [join59(targetRoot, "openpack.json"), join59(targetRoot, "instructions", "AGENTS.md")] : [workspaceConfigPath(targetRoot)]
24862
+ anticipatedPaths: kind === "package" ? [join61(targetRoot, "openpack.json"), join61(targetRoot, "instructions", "AGENTS.md")] : [workspaceConfigPath(targetRoot)]
24252
24863
  };
24253
24864
  }
24254
24865
  if (path === "package migrate") {
24255
24866
  const packageRoot = normalizeTargetRoot(String(command.args[0] ?? "."));
24256
24867
  return {
24257
24868
  workspaceRoot: await findExistingWorkspaceRoot(packageRoot) ?? packageRoot,
24258
- anticipatedPaths: ["agentwheel.json", "agentwheel.jsonc", "openpack.json", "openpack.jsonc"].map((name) => join59(packageRoot, name))
24869
+ anticipatedPaths: ["agentwheel.json", "agentwheel.jsonc", "openpack.json", "openpack.jsonc"].map((name) => join61(packageRoot, name))
24259
24870
  };
24260
24871
  }
24261
24872
  const source = typeof command.args[0] === "string" ? command.args[0] : void 0;
@@ -24265,9 +24876,9 @@ async function governedCommandContext(command, options) {
24265
24876
  const contextOnly = path === "cache prune";
24266
24877
  const workspaceRoot = contextOnly ? await workspaceContextRootFromOptions(normalized) : await workspaceRootFromOptions(normalized);
24267
24878
  const anticipatedPaths = [];
24268
- if (path === "add") anticipatedPaths.push(workspaceConfigPath(workspaceRoot));
24879
+ if (path === "add" || path === "pin") anticipatedPaths.push(workspaceConfigPath(workspaceRoot));
24269
24880
  if (path === "remember" && options.runtime) {
24270
- anticipatedPaths.push(join59(workspaceRoot, ".agentwheel", "overlays", options.runtime, "instructions.local.md"));
24881
+ anticipatedPaths.push(join61(workspaceRoot, ".agentwheel", "overlays", options.runtime, "instructions.local.md"));
24271
24882
  }
24272
24883
  if (path === "uninstall" && source) anticipatedPaths.push(workspaceConfigPath(workspaceRoot));
24273
24884
  return {