agentwheel 0.22.3 → 0.22.4

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
@@ -16558,7 +16558,8 @@ var init_local = __esm({
16558
16558
  atomicCopy,
16559
16559
  rm: (path) => rm3(path, { recursive: true, force: true }),
16560
16560
  async execFile(command, args, options = {}) {
16561
- await execFileAsync(command, args, { cwd: options.cwd });
16561
+ const { stdout } = await execFileAsync(command, args, { cwd: options.cwd });
16562
+ return stdout;
16562
16563
  }
16563
16564
  };
16564
16565
  }
@@ -16627,7 +16628,7 @@ function createSshTransport(config2) {
16627
16628
  execFile(command, commandArgs, options = {}) {
16628
16629
  const quoted = [command, ...commandArgs].map(quoteSh).join(" ");
16629
16630
  const remoteCommand = options.cwd ? `cd ${quoteSh(options.cwd)} && ${quoted}` : quoted;
16630
- return run(remoteCommand).then(() => void 0);
16631
+ return run(remoteCommand);
16631
16632
  }
16632
16633
  };
16633
16634
  }
@@ -17180,6 +17181,189 @@ var init_transport = __esm({
17180
17181
  }
17181
17182
  });
17182
17183
 
17184
+ // src/resolve/semver.ts
17185
+ function parseSemver(value) {
17186
+ const match = semverPattern.exec(value.trim());
17187
+ if (!match) return void 0;
17188
+ return {
17189
+ major: Number(match[1]),
17190
+ minor: Number(match[2]),
17191
+ patch: Number(match[3]),
17192
+ prerelease: match[4]
17193
+ };
17194
+ }
17195
+ function satisfiesVersionRange(version2, range) {
17196
+ if (!range || range.trim() === "" || range.trim() === "*") return true;
17197
+ const parsedVersion = parseSemver(version2);
17198
+ const trimmed = range.trim();
17199
+ if (!parsedVersion) {
17200
+ return trimmed === "*" || trimmed === version2;
17201
+ }
17202
+ const comparators = parseRange(trimmed);
17203
+ if (!comparators) return trimmed === version2;
17204
+ return comparators.every((comparator) => compareWith(parsedVersion, comparator));
17205
+ }
17206
+ function semverMajorOrVersion(version2) {
17207
+ const parsed = parseSemver(version2);
17208
+ return parsed ? String(parsed.major) : version2;
17209
+ }
17210
+ function compareSemverStrings(a, b) {
17211
+ const parsedA = parseSemver(a);
17212
+ const parsedB = parseSemver(b);
17213
+ if (!parsedA || !parsedB) return a.localeCompare(b);
17214
+ return compareSemver(parsedA, parsedB);
17215
+ }
17216
+ function isSupportedVersionRange(range) {
17217
+ const trimmed = range.trim();
17218
+ return trimmed === "*" || parseRange(trimmed) !== void 0;
17219
+ }
17220
+ function parseRange(range) {
17221
+ if (range === "*") return [];
17222
+ if (range.startsWith("^")) {
17223
+ const base = parseSemver(range.slice(1));
17224
+ if (!base) return void 0;
17225
+ return [
17226
+ { op: ">=", version: base },
17227
+ { op: "<", version: caretUpperBound(base) }
17228
+ ];
17229
+ }
17230
+ if (range.startsWith("~")) {
17231
+ const base = parseSemver(range.slice(1));
17232
+ if (!base) return void 0;
17233
+ return [
17234
+ { op: ">=", version: base },
17235
+ { op: "<", version: { major: base.major, minor: base.minor + 1, patch: 0 } }
17236
+ ];
17237
+ }
17238
+ const parts = range.split(/\s+/).filter(Boolean);
17239
+ const comparators = [];
17240
+ for (const part of parts) {
17241
+ const match = /^(>=|<=|>|<|=)?(.+)$/.exec(part);
17242
+ if (!match) return void 0;
17243
+ const version2 = parseSemver(match[2] ?? "");
17244
+ if (!version2) return void 0;
17245
+ comparators.push({ op: match[1] ?? "=", version: version2 });
17246
+ }
17247
+ return comparators;
17248
+ }
17249
+ function caretUpperBound(version2) {
17250
+ if (version2.major > 0) return { major: version2.major + 1, minor: 0, patch: 0 };
17251
+ if (version2.minor > 0) return { major: 0, minor: version2.minor + 1, patch: 0 };
17252
+ return { major: 0, minor: 0, patch: version2.patch + 1 };
17253
+ }
17254
+ function compareWith(version2, comparator) {
17255
+ const order = compareSemver(version2, comparator.version);
17256
+ switch (comparator.op) {
17257
+ case "=":
17258
+ return order === 0;
17259
+ case ">":
17260
+ return order > 0;
17261
+ case ">=":
17262
+ return order >= 0;
17263
+ case "<":
17264
+ return order < 0;
17265
+ case "<=":
17266
+ return order <= 0;
17267
+ }
17268
+ }
17269
+ function compareSemver(a, b) {
17270
+ for (const key of ["major", "minor", "patch"]) {
17271
+ if (a[key] !== b[key]) return a[key] > b[key] ? 1 : -1;
17272
+ }
17273
+ if (a.prerelease === b.prerelease) return 0;
17274
+ if (!a.prerelease) return 1;
17275
+ if (!b.prerelease) return -1;
17276
+ return a.prerelease.localeCompare(b.prerelease);
17277
+ }
17278
+ var semverPattern;
17279
+ var init_semver = __esm({
17280
+ "src/resolve/semver.ts"() {
17281
+ "use strict";
17282
+ semverPattern = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
17283
+ }
17284
+ });
17285
+
17286
+ // src/targets/plugins/openclaw.ts
17287
+ import { readFile as readFile8 } from "fs/promises";
17288
+ import { join as join10 } from "path";
17289
+ function openClawPluginInstallCommand(request) {
17290
+ return ["openclaw", "plugins", "install", "--force", ...request.acceptCapabilities ? ["--accept-capabilities"] : [], request.path];
17291
+ }
17292
+ function createOpenClawCapabilityDetector(run) {
17293
+ let cached2;
17294
+ return () => cached2 ??= detectOpenClawCapabilitySupport(run);
17295
+ }
17296
+ async function detectOpenClawCapabilitySupport(run) {
17297
+ try {
17298
+ const help = await run(["plugins", "install", "--help"]);
17299
+ if (help?.trim()) return /(?:^|\s)--accept-capabilities(?=[\s=,]|$)/m.test(help);
17300
+ } catch {
17301
+ }
17302
+ try {
17303
+ const output = await run(["--version"]);
17304
+ const version2 = output?.match(/(?:^|\s)v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)(?=\s|$)/)?.[1];
17305
+ return version2 !== void 0 && parseSemver(version2) !== void 0 && satisfiesVersionRange(version2, ">=2026.8.1");
17306
+ } catch {
17307
+ return false;
17308
+ }
17309
+ }
17310
+ function openClawPluginUninstallCommand(pluginName) {
17311
+ return ["openclaw", "plugins", "uninstall", pluginName, "--force"];
17312
+ }
17313
+ async function openClawPluginSpec(request) {
17314
+ if (request.format === "openclaw-clawhub-plugin") {
17315
+ const metadata = await openClawClawHubPluginMetadata(request.path, request.fallbackPluginName);
17316
+ return {
17317
+ runtime: "openclaw",
17318
+ pluginName: metadata.pluginName,
17319
+ installCommands: [openClawPluginInstallCommand({ path: metadata.installSpec, dryRun: true })],
17320
+ uninstallCommands: [openClawPluginUninstallCommand(metadata.pluginName)]
17321
+ };
17322
+ }
17323
+ const pluginName = await openClawPluginName(request.path, request.fallbackPluginName);
17324
+ return {
17325
+ runtime: "openclaw",
17326
+ pluginName,
17327
+ installCommands: [openClawPluginInstallCommand({ path: request.path, dryRun: true })],
17328
+ uninstallCommands: [openClawPluginUninstallCommand(pluginName)]
17329
+ };
17330
+ }
17331
+ async function openClawPluginName(root, fallback) {
17332
+ for (const manifestName of ["plugin.json", "openclaw.plugin.json"]) {
17333
+ const manifestPath = join10(root, manifestName);
17334
+ if (!await pathExists(manifestPath)) continue;
17335
+ const parsed = JSON.parse(await readFile8(manifestPath, "utf8"));
17336
+ if (typeof parsed.name === "string" && parsed.name.trim().length > 0) return parsed.name.trim();
17337
+ }
17338
+ return fallback;
17339
+ }
17340
+ async function openClawClawHubPluginMetadata(root, fallback) {
17341
+ const metadataPath = join10(root, "clawhub.json");
17342
+ if (!await pathExists(metadataPath)) {
17343
+ throw new Error("OpenClaw ClawHub plugins must contain clawhub.json");
17344
+ }
17345
+ const parsed = JSON.parse(await readFile8(metadataPath, "utf8"));
17346
+ const installSpec = stringField(parsed.installSpec);
17347
+ if (!installSpec?.startsWith("clawhub:")) {
17348
+ throw new Error("OpenClaw ClawHub plugin metadata must declare installSpec starting with clawhub:");
17349
+ }
17350
+ const pluginName = stringField(parsed.runtimeId) ?? installNameFor(stringField(parsed.name) ?? fallback);
17351
+ return { installSpec, pluginName };
17352
+ }
17353
+ function stringField(value) {
17354
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
17355
+ }
17356
+ function installNameFor(value) {
17357
+ return value.split("/").at(-1).replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "clawhub-plugin";
17358
+ }
17359
+ var init_openclaw2 = __esm({
17360
+ "src/targets/plugins/openclaw.ts"() {
17361
+ "use strict";
17362
+ init_fs();
17363
+ init_semver();
17364
+ }
17365
+ });
17366
+
17183
17367
  // src/transport/run-as-policy.ts
17184
17368
  function assertRunAsPlanSupported(plan, transport) {
17185
17369
  if (transport.kind !== "local-run-as") return;
@@ -17194,12 +17378,12 @@ var init_run_as_policy = __esm({
17194
17378
  });
17195
17379
 
17196
17380
  // src/install/json-merge.ts
17197
- import { readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
17381
+ import { readFile as readFile9, writeFile as writeFile5 } from "fs/promises";
17198
17382
  import { dirname as dirname7 } from "path";
17199
17383
  import { mkdir as mkdir5 } from "fs/promises";
17200
17384
  async function mergeJsonFile(sourcePath, destPath) {
17201
- const source = JSON.parse(await readFile8(sourcePath, "utf8"));
17202
- const current = await pathExists(destPath) ? JSON.parse(await readFile8(destPath, "utf8")) : {};
17385
+ const source = JSON.parse(await readFile9(sourcePath, "utf8"));
17386
+ const current = await pathExists(destPath) ? JSON.parse(await readFile9(destPath, "utf8")) : {};
17203
17387
  const merged = deepMerge(current, source);
17204
17388
  await mkdir5(dirname7(destPath), { recursive: true });
17205
17389
  await writeFile5(destPath, `${JSON.stringify(merged, null, 2)}
@@ -17240,11 +17424,11 @@ var init_json_merge = __esm({
17240
17424
  });
17241
17425
 
17242
17426
  // src/install/openclaw-json-merge.ts
17243
- import { mkdir as mkdir6, readFile as readFile9, writeFile as writeFile6 } from "fs/promises";
17427
+ import { mkdir as mkdir6, readFile as readFile10, writeFile as writeFile6 } from "fs/promises";
17244
17428
  import { dirname as dirname8 } from "path";
17245
17429
  async function mergeOpenClawJsonFile(sourcePath, destPath) {
17246
17430
  const source = await renderOpenClawJsonMergeSource(sourcePath);
17247
- const current = await pathExists(destPath) ? JSON.parse(await readFile9(destPath, "utf8")) : {};
17431
+ const current = await pathExists(destPath) ? JSON.parse(await readFile10(destPath, "utf8")) : {};
17248
17432
  const merged = mergeOpenClawJson(current, source);
17249
17433
  await mkdir6(dirname8(destPath), { recursive: true });
17250
17434
  await writeFile6(destPath, `${JSON.stringify(merged, null, 2)}
@@ -17252,7 +17436,7 @@ async function mergeOpenClawJsonFile(sourcePath, destPath) {
17252
17436
  }
17253
17437
  async function renderOpenClawJsonMergeSource(sourcePath) {
17254
17438
  return expandEnvPlaceholders(
17255
- normalizeOpenClawConfig(JSON.parse(await readFile9(sourcePath, "utf8"))),
17439
+ normalizeOpenClawConfig(JSON.parse(await readFile10(sourcePath, "utf8"))),
17256
17440
  sourcePath
17257
17441
  );
17258
17442
  }
@@ -17517,9 +17701,9 @@ var init_manifest = __esm({
17517
17701
  });
17518
17702
 
17519
17703
  // src/install/paths.ts
17520
- import { join as join10 } from "path";
17704
+ import { join as join11 } from "path";
17521
17705
  function metadataDir(targetRoot) {
17522
- return join10(targetRoot, ".agentwheel");
17706
+ return join11(targetRoot, ".agentwheel");
17523
17707
  }
17524
17708
  function stateKeyFor(adapter, scope = {}) {
17525
17709
  assertPathSafeAdapterName(adapter);
@@ -17539,10 +17723,10 @@ function assertPathSafeAdapterName(adapter) {
17539
17723
  }
17540
17724
  }
17541
17725
  function installManifestPath(targetRoot, adapter, scope = {}) {
17542
- return join10(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.install-manifest.json`);
17726
+ return join11(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.install-manifest.json`);
17543
17727
  }
17544
17728
  function sourceLockPath(targetRoot, adapter, scope = {}) {
17545
- return join10(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.source-lock.json`);
17729
+ return join11(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.source-lock.json`);
17546
17730
  }
17547
17731
  function sanitizeStateKey(value) {
17548
17732
  return value.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "default";
@@ -17556,7 +17740,7 @@ var init_paths = __esm({
17556
17740
 
17557
17741
  // src/install/manifest.ts
17558
17742
  import { createHash as createHash7 } from "crypto";
17559
- import { join as join11, resolve as resolve10 } from "path";
17743
+ import { join as join12, resolve as resolve10 } from "path";
17560
17744
  async function readInstallManifest(targetRoot, adapter, transport = localTransport, scope = {}) {
17561
17745
  const path = installManifestPath(targetRoot, adapter, scope);
17562
17746
  if (!await transport.pathExists(path)) return void 0;
@@ -17574,7 +17758,7 @@ async function listInstallManifests(targetRoot, adapter, transport = localTransp
17574
17758
  for (const fileName of await transport.listDir(dir)) {
17575
17759
  if (!fileName.endsWith(suffix)) continue;
17576
17760
  const stateKey = fileName.slice(0, -suffix.length);
17577
- const path = join11(dir, fileName);
17761
+ const path = join12(dir, fileName);
17578
17762
  try {
17579
17763
  const raw = JSON.parse(await transport.readFile(path));
17580
17764
  const parsed = installManifestSchema.parse(raw);
@@ -17759,108 +17943,6 @@ if private and (s.st_uid!=os.geteuid() or not stat.S_ISREG(s.st_mode) or s.st_nl
17759
17943
  }
17760
17944
  });
17761
17945
 
17762
- // src/resolve/semver.ts
17763
- function parseSemver(value) {
17764
- const match = semverPattern.exec(value.trim());
17765
- if (!match) return void 0;
17766
- return {
17767
- major: Number(match[1]),
17768
- minor: Number(match[2]),
17769
- patch: Number(match[3]),
17770
- prerelease: match[4]
17771
- };
17772
- }
17773
- function satisfiesVersionRange(version2, range) {
17774
- if (!range || range.trim() === "" || range.trim() === "*") return true;
17775
- const parsedVersion = parseSemver(version2);
17776
- const trimmed = range.trim();
17777
- if (!parsedVersion) {
17778
- return trimmed === "*" || trimmed === version2;
17779
- }
17780
- const comparators = parseRange(trimmed);
17781
- if (!comparators) return trimmed === version2;
17782
- return comparators.every((comparator) => compareWith(parsedVersion, comparator));
17783
- }
17784
- function semverMajorOrVersion(version2) {
17785
- const parsed = parseSemver(version2);
17786
- return parsed ? String(parsed.major) : version2;
17787
- }
17788
- function compareSemverStrings(a, b) {
17789
- const parsedA = parseSemver(a);
17790
- const parsedB = parseSemver(b);
17791
- if (!parsedA || !parsedB) return a.localeCompare(b);
17792
- return compareSemver(parsedA, parsedB);
17793
- }
17794
- function isSupportedVersionRange(range) {
17795
- const trimmed = range.trim();
17796
- return trimmed === "*" || parseRange(trimmed) !== void 0;
17797
- }
17798
- function parseRange(range) {
17799
- if (range === "*") return [];
17800
- if (range.startsWith("^")) {
17801
- const base = parseSemver(range.slice(1));
17802
- if (!base) return void 0;
17803
- return [
17804
- { op: ">=", version: base },
17805
- { op: "<", version: caretUpperBound(base) }
17806
- ];
17807
- }
17808
- if (range.startsWith("~")) {
17809
- const base = parseSemver(range.slice(1));
17810
- if (!base) return void 0;
17811
- return [
17812
- { op: ">=", version: base },
17813
- { op: "<", version: { major: base.major, minor: base.minor + 1, patch: 0 } }
17814
- ];
17815
- }
17816
- const parts = range.split(/\s+/).filter(Boolean);
17817
- const comparators = [];
17818
- for (const part of parts) {
17819
- const match = /^(>=|<=|>|<|=)?(.+)$/.exec(part);
17820
- if (!match) return void 0;
17821
- const version2 = parseSemver(match[2] ?? "");
17822
- if (!version2) return void 0;
17823
- comparators.push({ op: match[1] ?? "=", version: version2 });
17824
- }
17825
- return comparators;
17826
- }
17827
- function caretUpperBound(version2) {
17828
- if (version2.major > 0) return { major: version2.major + 1, minor: 0, patch: 0 };
17829
- if (version2.minor > 0) return { major: 0, minor: version2.minor + 1, patch: 0 };
17830
- return { major: 0, minor: 0, patch: version2.patch + 1 };
17831
- }
17832
- function compareWith(version2, comparator) {
17833
- const order = compareSemver(version2, comparator.version);
17834
- switch (comparator.op) {
17835
- case "=":
17836
- return order === 0;
17837
- case ">":
17838
- return order > 0;
17839
- case ">=":
17840
- return order >= 0;
17841
- case "<":
17842
- return order < 0;
17843
- case "<=":
17844
- return order <= 0;
17845
- }
17846
- }
17847
- function compareSemver(a, b) {
17848
- for (const key of ["major", "minor", "patch"]) {
17849
- if (a[key] !== b[key]) return a[key] > b[key] ? 1 : -1;
17850
- }
17851
- if (a.prerelease === b.prerelease) return 0;
17852
- if (!a.prerelease) return 1;
17853
- if (!b.prerelease) return -1;
17854
- return a.prerelease.localeCompare(b.prerelease);
17855
- }
17856
- var semverPattern;
17857
- var init_semver = __esm({
17858
- "src/resolve/semver.ts"() {
17859
- "use strict";
17860
- semverPattern = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
17861
- }
17862
- });
17863
-
17864
17946
  // src/model/selection.ts
17865
17947
  function artifactSelectorKey(artifact) {
17866
17948
  return `${artifact.type}/${artifact.name}`;
@@ -17918,9 +18000,9 @@ var init_selection = __esm({
17918
18000
  });
17919
18001
 
17920
18002
  // src/model/workspace.ts
17921
- import { readFile as readFile10 } from "fs/promises";
18003
+ import { readFile as readFile11 } from "fs/promises";
17922
18004
  import { homedir as homedir4 } from "os";
17923
- import { dirname as dirname9, join as join12, resolve as resolve13 } from "path";
18005
+ import { dirname as dirname9, join as join13, resolve as resolve13 } from "path";
17924
18006
  function packagesForTarget(packages, target, targetForPackage2) {
17925
18007
  return packages.filter((pkg) => !pkg.runtimes || pkg.runtimes.includes((targetForPackage2?.(pkg) ?? target).adapter));
17926
18008
  }
@@ -17928,12 +18010,12 @@ function supportsFleetConfig(config2) {
17928
18010
  return config2.schemaVersion === 3 || config2.schemaVersion === 4;
17929
18011
  }
17930
18012
  function workspaceConfigPath(workspaceRoot) {
17931
- return join12(workspaceRoot, ".agentwheel", "config.json");
18013
+ return join13(workspaceRoot, ".agentwheel", "config.json");
17932
18014
  }
17933
18015
  async function readWorkspaceConfig(workspaceRoot) {
17934
18016
  const path = workspaceConfigPath(workspaceRoot);
17935
18017
  if (!await pathExists(path)) return emptyWorkspaceConfig();
17936
- return workspaceConfigSchema.parse(JSON.parse(await readFile10(path, "utf8")));
18018
+ return workspaceConfigSchema.parse(JSON.parse(await readFile11(path, "utf8")));
17937
18019
  }
17938
18020
  async function writeWorkspaceConfig(workspaceRoot, config2) {
17939
18021
  const path = workspaceConfigPath(workspaceRoot);
@@ -17947,7 +18029,7 @@ async function pinConfiguredPackages(workspaceRoot, input, options = {}) {
17947
18029
  throw new Error("Package declarations require unique aliases.");
17948
18030
  }
17949
18031
  const path2 = workspaceConfigPath(workspaceRoot);
17950
- const config3 = JSON.parse(await readFile10(path2, "utf8"));
18032
+ const config3 = JSON.parse(await readFile11(path2, "utf8"));
17951
18033
  workspaceConfigSchema.parse(config3);
17952
18034
  config3.packages = input;
17953
18035
  workspaceConfigSchema.parse(config3);
@@ -17970,7 +18052,7 @@ async function pinConfiguredPackages(workspaceRoot, input, options = {}) {
17970
18052
  throw new Error("Pin requires unique configured aliases.");
17971
18053
  }
17972
18054
  const path = workspaceConfigPath(workspaceRoot);
17973
- const config2 = JSON.parse(await readFile10(path, "utf8"));
18055
+ const config2 = JSON.parse(await readFile11(path, "utf8"));
17974
18056
  workspaceConfigSchema.parse(config2);
17975
18057
  const updates = pins.map(({ alias, commit, select }) => {
17976
18058
  const matches = (config2.packages ?? []).filter((pkg2) => pkg2.name === alias);
@@ -18004,7 +18086,7 @@ function upsertPackage(config2, entry) {
18004
18086
  return workspaceConfigSchema.parse({ ...parsed, packages });
18005
18087
  }
18006
18088
  function globalWorkspaceConfigPath(globalRoot = homedir4()) {
18007
- return join12(globalRoot, ".agentwheel", "config.json");
18089
+ return join13(globalRoot, ".agentwheel", "config.json");
18008
18090
  }
18009
18091
  async function findWorkspaceRoot(start = process.cwd()) {
18010
18092
  let current = resolve13(start);
@@ -18063,7 +18145,7 @@ function isCompositeWorkspaceProfile(profile) {
18063
18145
  }
18064
18146
  async function readConfigPath(path) {
18065
18147
  if (!await pathExists(path)) return emptyWorkspaceConfig();
18066
- return workspaceConfigSchema.parse(JSON.parse(await readFile10(path, "utf8")));
18148
+ return workspaceConfigSchema.parse(JSON.parse(await readFile11(path, "utf8")));
18067
18149
  }
18068
18150
  function mergeWorkspaceTrust(global, project) {
18069
18151
  return {
@@ -18324,7 +18406,7 @@ var init_workspace = __esm({
18324
18406
  });
18325
18407
 
18326
18408
  // src/model/fleet.ts
18327
- import { lstat as lstat2, readFile as readFile11, realpath } from "fs/promises";
18409
+ import { lstat as lstat2, readFile as readFile12, realpath } from "fs/promises";
18328
18410
  import { homedir as homedir5 } from "os";
18329
18411
  import { isAbsolute as isAbsolute10, relative as relative6, resolve as resolve14 } from "path";
18330
18412
  async function resolveWorkspaceScope(request = {}) {
@@ -18441,7 +18523,7 @@ async function readRequiredConfig(root, label) {
18441
18523
  const path = workspaceConfigPath(root);
18442
18524
  if (!await pathExists(path)) throw missingScopeError(label);
18443
18525
  try {
18444
- return workspaceConfigSchema.parse(JSON.parse(await readFile11(path, "utf8")));
18526
+ return workspaceConfigSchema.parse(JSON.parse(await readFile12(path, "utf8")));
18445
18527
  } catch (error46) {
18446
18528
  throw new Error(`Invalid ${label} Agentwheel config at ${path}: ${error46 instanceof Error ? error46.message : String(error46)}`);
18447
18529
  }
@@ -18512,7 +18594,7 @@ var init_fleet = __esm({
18512
18594
 
18513
18595
  // src/mutation/repository.ts
18514
18596
  import { createHash as createHash8 } from "crypto";
18515
- import { lstat as lstat3, readFile as readFile12, readlink, readdir as readdir5 } from "fs/promises";
18597
+ import { lstat as lstat3, readFile as readFile13, readlink, readdir as readdir5 } from "fs/promises";
18516
18598
  import { dirname as dirname10, posix as posix4, relative as relative7, resolve as resolve15, sep as sep5 } from "path";
18517
18599
  async function discoverGitRepository(start) {
18518
18600
  const probe = await runProcess("git", ["-C", start, "rev-parse", "--show-toplevel"], { allowExitCodes: [0, 128] });
@@ -18719,7 +18801,7 @@ async function hashWorkingPath(repositoryRoot, path) {
18719
18801
  throw error46;
18720
18802
  }
18721
18803
  if (stats.isSymbolicLink()) return sha256(Buffer.from(await readlink(absolute), "utf8"));
18722
- if (stats.isFile()) return sha256(await readFile12(absolute));
18804
+ if (stats.isFile()) return sha256(await readFile13(absolute));
18723
18805
  if (stats.isDirectory()) return hashDirectory(absolute);
18724
18806
  throw new Error(`Unsupported repository path kind: ${path}`);
18725
18807
  }
@@ -18732,7 +18814,7 @@ async function hashDirectory(root) {
18732
18814
  const relativePath = normalizeRepoPath(relative7(root, absolute));
18733
18815
  if (entry.isDirectory()) await walk2(absolute);
18734
18816
  else if (entry.isSymbolicLink()) hash3.update(relativePath).update("\0").update(await readlink(absolute)).update("\0");
18735
- else if (entry.isFile()) hash3.update(relativePath).update("\0").update(await readFile12(absolute)).update("\0");
18817
+ else if (entry.isFile()) hash3.update(relativePath).update("\0").update(await readFile13(absolute)).update("\0");
18736
18818
  }
18737
18819
  }
18738
18820
  await walk2(root);
@@ -18768,9 +18850,9 @@ var init_repository = __esm({
18768
18850
 
18769
18851
  // src/mutation/providers.ts
18770
18852
  import { createHash as createHash9 } from "crypto";
18771
- import { chmod as chmod2, mkdtemp, open as open3, readFile as readFile13, rename as rename5, rm as rm4, rmdir, stat as stat3, writeFile as writeFile7 } from "fs/promises";
18853
+ import { chmod as chmod2, mkdtemp, open as open3, readFile as readFile14, rename as rename5, rm as rm4, rmdir, stat as stat3, writeFile as writeFile7 } from "fs/promises";
18772
18854
  import { tmpdir as tmpdir2 } from "os";
18773
- import { isAbsolute as isAbsolute11, join as join13, resolve as resolve16 } from "path";
18855
+ import { isAbsolute as isAbsolute11, join as join14, resolve as resolve16 } from "path";
18774
18856
  function revisionProviderRejection(error46) {
18775
18857
  return error46 instanceof RevisionProviderRejectedError ? error46.response : void 0;
18776
18858
  }
@@ -18879,8 +18961,8 @@ async function openImmutableExecutableSnapshot(bytes) {
18879
18961
  `Command revision providers require an unlinked immutable executable snapshot, which is unsupported on ${process.platform}.`
18880
18962
  );
18881
18963
  }
18882
- const root = await mkdtemp(join13(tmpdir2(), "agentwheel-revision-command-"));
18883
- const path = join13(root, "entrypoint");
18964
+ const root = await mkdtemp(join14(tmpdir2(), "agentwheel-revision-command-"));
18965
+ const path = join14(root, "entrypoint");
18884
18966
  let snapshot;
18885
18967
  try {
18886
18968
  await chmod2(root, 448);
@@ -19034,8 +19116,8 @@ async function finalizeGit(providerId, request, config2) {
19034
19116
  const indexLease = await captureIndexLease(request.repositoryRoot);
19035
19117
  await assertIndexTree(request.repositoryRoot, repository.head);
19036
19118
  const hookBaseline = await snapshotRepository(request.repositoryRoot);
19037
- const tempRoot = await mkdtemp(join13(tmpdir2(), "agentwheel-git-index-"));
19038
- const indexPath = join13(tempRoot, "index");
19119
+ const tempRoot = await mkdtemp(join14(tmpdir2(), "agentwheel-git-index-"));
19120
+ const indexPath = join14(tempRoot, "index");
19039
19121
  const env2 = { ...process.env, GIT_INDEX_FILE: indexPath };
19040
19122
  let commitSha;
19041
19123
  try {
@@ -19046,14 +19128,14 @@ async function finalizeGit(providerId, request, config2) {
19046
19128
  await verifyTemporaryIndexPaths(request, env2);
19047
19129
  await runProcess("git", ["-C", request.repositoryRoot, "diff", "--cached", "--check"], { env: env2 });
19048
19130
  const tree = (await runProcess("git", ["-C", request.repositoryRoot, "write-tree"], { env: env2 })).stdout.toString("utf8").trim();
19049
- const messagePath = join13(tempRoot, "COMMIT_EDITMSG");
19131
+ const messagePath = join14(tempRoot, "COMMIT_EDITMSG");
19050
19132
  await writeFile7(messagePath, commitMessage(request, planDigest), { encoding: "utf8", mode: 384 });
19051
19133
  await runCommitHooks(request, env2, messagePath);
19052
19134
  assertRepositorySnapshotEqual(hookBaseline, await snapshotRepository(request.repositoryRoot), "Git commit hooks");
19053
19135
  const stagedAfterHooks = splitNull2((await runProcess("git", ["-C", request.repositoryRoot, "diff", "--cached", "--name-only", "-z"], { env: env2 })).stdout);
19054
19136
  assertExactSet(stagedAfterHooks, request.paths.map((entry) => entry.path), "temporary Git index after hooks");
19055
19137
  await verifyTemporaryIndexPaths(request, env2);
19056
- const message = await readFile13(messagePath, "utf8");
19138
+ const message = await readFile14(messagePath, "utf8");
19057
19139
  assertCommitMessageContract(message, request, planDigest);
19058
19140
  commitSha = (await runProcess("git", ["-C", request.repositoryRoot, "commit-tree", tree, "-p", repository.head], {
19059
19141
  env: env2,
@@ -19172,7 +19254,7 @@ async function captureIndexLease(repositoryRoot) {
19172
19254
  const rawPath = (await runProcess("git", ["-C", repositoryRoot, "rev-parse", "--git-path", "index"])).stdout.toString("utf8").trim();
19173
19255
  const path = isAbsolute11(rawPath) ? rawPath : resolve16(repositoryRoot, rawPath);
19174
19256
  try {
19175
- const [content, info] = await Promise.all([readFile13(path), stat3(path)]);
19257
+ const [content, info] = await Promise.all([readFile14(path), stat3(path)]);
19176
19258
  return { path, sha256: sha2562(content), mode: info.mode & 511 };
19177
19259
  } catch (error46) {
19178
19260
  if (isMissing4(error46)) return { path, sha256: null, mode: 384 };
@@ -19180,15 +19262,15 @@ async function captureIndexLease(repositoryRoot) {
19180
19262
  }
19181
19263
  }
19182
19264
  async function replaceIndexCas(repositoryRoot, lease, commitSha) {
19183
- const tempRoot = await mkdtemp(join13(tmpdir2(), "agentwheel-index-replacement-"));
19184
- const replacementPath = join13(tempRoot, "index");
19265
+ const tempRoot = await mkdtemp(join14(tmpdir2(), "agentwheel-index-replacement-"));
19266
+ const replacementPath = join14(tempRoot, "index");
19185
19267
  const lockPath = `${lease.path}.lock`;
19186
19268
  let handle;
19187
19269
  try {
19188
19270
  await runProcess("git", ["-C", repositoryRoot, "read-tree", commitSha], {
19189
19271
  env: { ...process.env, GIT_INDEX_FILE: replacementPath }
19190
19272
  });
19191
- const replacement = await readFile13(replacementPath);
19273
+ const replacement = await readFile14(replacementPath);
19192
19274
  handle = await open3(lockPath, "wx", lease.mode);
19193
19275
  const current = await readOptionalFile(lease.path);
19194
19276
  const currentSha256 = current ? sha2562(current) : null;
@@ -19230,7 +19312,7 @@ async function hashGitObject(repositoryRoot, spec) {
19230
19312
  }
19231
19313
  async function readOptionalFile(path) {
19232
19314
  try {
19233
- return await readFile13(path);
19315
+ return await readFile14(path);
19234
19316
  } catch (error46) {
19235
19317
  if (isMissing4(error46)) return null;
19236
19318
  throw error46;
@@ -19995,8 +20077,8 @@ var init_coordinator = __esm({
19995
20077
 
19996
20078
  // src/transport/ownership-snapshot.ts
19997
20079
  import { createHash as createHash10 } from "crypto";
19998
- import { lstat as lstat4, readdir as readdir6, readFile as readFile14 } from "fs/promises";
19999
- import { dirname as dirname12, join as join14, relative as relative9, resolve as resolve18 } from "path";
20080
+ import { lstat as lstat4, readdir as readdir6, readFile as readFile15 } from "fs/promises";
20081
+ import { dirname as dirname12, join as join15, relative as relative9, resolve as resolve18 } from "path";
20000
20082
  async function assertSnapshotAncestors(path) {
20001
20083
  let current = resolve18(path);
20002
20084
  while (true) {
@@ -20016,9 +20098,9 @@ async function ownershipRuntimeSnapshot(path) {
20016
20098
  }
20017
20099
  hash3.update(JSON.stringify([relative9(path, candidate), info.isDirectory() ? "dir" : "file", info.mode & 4095]));
20018
20100
  if (info.isDirectory()) {
20019
- for (const name of (await readdir6(candidate)).sort()) await visit2(join14(candidate, name));
20101
+ for (const name of (await readdir6(candidate)).sort()) await visit2(join15(candidate, name));
20020
20102
  } else {
20021
- const content = await readFile14(candidate);
20103
+ const content = await readFile15(candidate);
20022
20104
  hash3.update(String(content.length)).update("\0").update(content);
20023
20105
  }
20024
20106
  }
@@ -20067,7 +20149,7 @@ __export(transaction_exports, {
20067
20149
  });
20068
20150
  import { createHash as createHash11 } from "crypto";
20069
20151
  import { cp as cp2, lstat as lstat5, mkdir as mkdir7, open as open4, rm as rm5, stat as stat4 } from "fs/promises";
20070
- import { dirname as dirname13, join as join15, relative as relative10, resolve as resolve19, sep as sep7 } from "path";
20152
+ import { dirname as dirname13, join as join16, relative as relative10, resolve as resolve19, sep as sep7 } from "path";
20071
20153
  async function assertNoSymlinkPath2(path) {
20072
20154
  const absolute = resolve19(path);
20073
20155
  let current = absolute;
@@ -20130,7 +20212,7 @@ function metadataAuditPath(audit, path) {
20130
20212
  if (resolve19(audit.workspaceRoot) !== audit.workspaceRoot || path !== `.agentwheel/${audit.kind === "ownership-handoff" ? "ownership-handoffs" : "ownership-releases"}/${audit.operationId}.json`) {
20131
20213
  throw new Error("Invalid ownership release audit path.");
20132
20214
  }
20133
- return join15(audit.workspaceRoot, ...path.split("/"));
20215
+ return join16(audit.workspaceRoot, ...path.split("/"));
20134
20216
  }
20135
20217
  function metadataRuntimePath(root, path) {
20136
20218
  const result = resolve19(root, path);
@@ -20157,19 +20239,19 @@ async function syncMetadataPath(path, directoryOnly = false) {
20157
20239
  }
20158
20240
  function applyLockPath(targetRoot, adapter, scope = {}) {
20159
20241
  const installationType = scope.installationType ?? "local";
20160
- return join15(metadataDir(targetRoot), `${stateKeyFor(adapter, { installationType })}.runtime-apply-lock`);
20242
+ return join16(metadataDir(targetRoot), `${stateKeyFor(adapter, { installationType })}.runtime-apply-lock`);
20161
20243
  }
20162
20244
  function applyJournalPath(targetRoot, adapter, scope = {}) {
20163
- return join15(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.apply-journal.json`);
20245
+ return join16(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.apply-journal.json`);
20164
20246
  }
20165
20247
  function applyBackupDir(targetRoot, adapter, scope = {}) {
20166
- return join15(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.apply-backups`);
20248
+ return join16(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.apply-backups`);
20167
20249
  }
20168
20250
  async function acquireApplyLock(targetRoot, adapter, transport = localTransport, options = {}, scope = {}) {
20169
20251
  assertGovernedRuntimeTransportSupported(transport);
20170
20252
  if (transport.kind === "local-run-as") await transport.prepareApply();
20171
20253
  const lockPath = applyLockPath(targetRoot, adapter, scope);
20172
- const ownerPath = join15(lockPath, "owner.json");
20254
+ const ownerPath = join16(lockPath, "owner.json");
20173
20255
  const metadata = {
20174
20256
  pid: process.pid,
20175
20257
  adapter,
@@ -20238,7 +20320,7 @@ async function listApplyJournals(targetRoot, adapter, transport = localTransport
20238
20320
  const found = [];
20239
20321
  for (const fileName of await transport.listDir(metadataDir(targetRoot))) {
20240
20322
  if (!fileName.endsWith(suffix)) continue;
20241
- const path = join15(metadataDir(targetRoot), fileName);
20323
+ const path = join16(metadataDir(targetRoot), fileName);
20242
20324
  const journal = parseApplyJournal(JSON.parse(await transport.readFile(path)));
20243
20325
  if (journal.adapter !== adapter || (journal.installationType ?? "local") !== installationType) continue;
20244
20326
  found.push({ path, journal });
@@ -20250,7 +20332,7 @@ async function listAllApplyJournals(targetRoot, adapter, transport = localTransp
20250
20332
  const found = [];
20251
20333
  for (const fileName of await transport.listDir(metadataDir(targetRoot))) {
20252
20334
  if (!fileName.endsWith(suffix)) continue;
20253
- const path = join15(metadataDir(targetRoot), fileName);
20335
+ const path = join16(metadataDir(targetRoot), fileName);
20254
20336
  const journal = parseApplyJournal(JSON.parse(await transport.readFile(path)));
20255
20337
  if (adapter === void 0 || journal.adapter === adapter) found.push({ path, journal });
20256
20338
  }
@@ -20308,7 +20390,7 @@ async function abortApplyJournal(targetRoot, adapter, transport = localTransport
20308
20390
  const journalPath = applyJournalPath(targetRoot, adapter, scope);
20309
20391
  if (!await transport.pathExists(journalPath)) return void 0;
20310
20392
  const stateKey = stateKeyFor(adapter, scope);
20311
- const archivePath = join15(metadataDir(targetRoot), "archive", `${stateKey}.apply-journal.failed-${journalTimestamp(/* @__PURE__ */ new Date())}.json`);
20393
+ const archivePath = join16(metadataDir(targetRoot), "archive", `${stateKey}.apply-journal.failed-${journalTimestamp(/* @__PURE__ */ new Date())}.json`);
20312
20394
  const content = await transport.readFile(journalPath);
20313
20395
  const journal = parseApplyJournal(JSON.parse(content));
20314
20396
  if (journal.metadataAudit || journal.metadataGuards) {
@@ -20441,7 +20523,7 @@ async function recordBackup(operation, index, targetRoot, adapter, transport = l
20441
20523
  hadExisting
20442
20524
  };
20443
20525
  }
20444
- const backupPath = join15(applyBackupDir(targetRoot, adapter, scope), String(index));
20526
+ const backupPath = join16(applyBackupDir(targetRoot, adapter, scope), String(index));
20445
20527
  if (transport.kind === "local-run-as") {
20446
20528
  assertGovernedRuntimeTransportSupported(transport);
20447
20529
  await transport.rm(backupPath);
@@ -20520,7 +20602,7 @@ function assertApplyJournalCompletedOperations(journal) {
20520
20602
  if (!operation || !["create", "update", "remove"].includes(operation.action) || item.destPath !== operation.destPath || item.kind !== operation.kind || typeof item.hadExisting !== "boolean" || item.completed !== void 0 && typeof item.completed !== "boolean") {
20521
20603
  throw new Error("Apply journal completion does not match its immutable operation.");
20522
20604
  }
20523
- const expectedBackup = join15(applyBackupDir(journal.targetRoot, journal.adapter, {
20605
+ const expectedBackup = join16(applyBackupDir(journal.targetRoot, journal.adapter, {
20524
20606
  installationType: journal.installationType,
20525
20607
  stateKey: journal.stateKey
20526
20608
  }), String(item.index));
@@ -20546,15 +20628,24 @@ var init_transaction = __esm({
20546
20628
  });
20547
20629
 
20548
20630
  // src/install/toml-merge.ts
20549
- import { mkdir as mkdir8, readFile as readFile16, writeFile as writeFile8 } from "fs/promises";
20550
- import { parse as parseToml } from "smol-toml";
20631
+ import { mkdir as mkdir8, readFile as readFile17, writeFile as writeFile8 } from "fs/promises";
20632
+ import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
20551
20633
  import { dirname as dirname14 } from "path";
20552
20634
  async function mergeCodexTomlMcp(sourcePath, destPath) {
20553
- const source = JSON.parse(await readFile16(sourcePath, "utf8"));
20635
+ const source = JSON.parse(await readFile17(sourcePath, "utf8"));
20554
20636
  const servers = extractMcpServers(source);
20555
- const current = await pathExists(destPath) ? await readFile16(destPath, "utf8") : "";
20556
- const withoutManaged = removeManagedMcpSections(current, Object.keys(servers));
20557
- const merged = appendMcpServers(withoutManaged, servers);
20637
+ const current = await pathExists(destPath) ? await readFile17(destPath, "utf8") : "";
20638
+ const parsed = parseToml(current, { integersAsBigInt: "asNeeded" });
20639
+ const currentServers = isPlainRecord(parsed.mcp_servers) ? parsed.mcp_servers : {};
20640
+ const blocks = [];
20641
+ for (const [name, server] of Object.entries(servers).sort(([a], [b]) => a.localeCompare(b))) {
20642
+ const rendered = parseToml(formatMcpServer(name, server), { integersAsBigInt: "asNeeded" });
20643
+ const declared = rendered.mcp_servers[name];
20644
+ const mergedServer = mergeManagedFields(currentServers[name], declared);
20645
+ blocks.push(managedValueMatches(declared, mergedServer) ? formatMcpServer(name, server) : stringifyToml({ mcp_servers: { [name]: mergedServer } }).trimEnd());
20646
+ }
20647
+ const merged = appendMcpServers(removeManagedMcpSections(current, Object.keys(servers)), blocks);
20648
+ parseToml(merged, { integersAsBigInt: "asNeeded" });
20558
20649
  await mkdir8(dirname14(destPath), { recursive: true });
20559
20650
  await writeFile8(destPath, merged, "utf8");
20560
20651
  }
@@ -20597,7 +20688,7 @@ function isPlainRecord(value) {
20597
20688
  }
20598
20689
  function extractMcpServers(source) {
20599
20690
  const raw = isRecord2(source.mcpServers) ? source.mcpServers : source;
20600
- const servers = {};
20691
+ const servers = /* @__PURE__ */ Object.create(null);
20601
20692
  for (const [name, value] of Object.entries(raw)) {
20602
20693
  if (!isRecord2(value)) continue;
20603
20694
  servers[name] = value;
@@ -20608,23 +20699,39 @@ function extractMcpServers(source) {
20608
20699
  return servers;
20609
20700
  }
20610
20701
  function removeManagedMcpSections(content, serverNames) {
20611
- if (serverNames.length === 0 || content.trim() === "") return content;
20612
20702
  const names = new Set(serverNames);
20613
- const lines = content.split(/\r?\n/);
20614
20703
  const kept = [];
20615
20704
  let skipping = false;
20616
- for (const line of lines) {
20617
- const section = line.match(/^\s*\[([^\]]+)]\s*$/)?.[1];
20618
- if (section) {
20619
- const match = section.match(/^mcp_servers\.([^.\]]+)(?:\.|$)/);
20620
- skipping = match ? names.has(unquoteTomlKey(match[1] ?? "")) : false;
20705
+ let offset = 0;
20706
+ for (const line of content.split(/(?<=\n)/)) {
20707
+ if (line.trimStart().startsWith("[")) {
20708
+ try {
20709
+ parseToml(content.slice(0, offset), { integersAsBigInt: "asNeeded" });
20710
+ const header = parseToml(line, { integersAsBigInt: "asNeeded" });
20711
+ const servers = isPlainRecord(header.mcp_servers) ? header.mcp_servers : {};
20712
+ skipping = Object.keys(servers).some((name) => names.has(name));
20713
+ } catch {
20714
+ }
20621
20715
  }
20622
20716
  if (!skipping) kept.push(line);
20717
+ offset += line.length;
20623
20718
  }
20624
- return kept.join("\n").replace(/\n{3,}$/g, "\n\n");
20719
+ return kept.join("");
20720
+ }
20721
+ function mergeManagedFields(current, declared) {
20722
+ if (!isPlainRecord(declared)) return declared;
20723
+ const merged = isPlainRecord(current) ? { ...current } : {};
20724
+ for (const [key, value] of Object.entries(declared)) {
20725
+ Object.defineProperty(merged, key, {
20726
+ value: mergeManagedFields(Object.hasOwn(merged, key) ? merged[key] : void 0, value),
20727
+ enumerable: true,
20728
+ configurable: true,
20729
+ writable: true
20730
+ });
20731
+ }
20732
+ return merged;
20625
20733
  }
20626
- function appendMcpServers(content, servers) {
20627
- const blocks = Object.entries(servers).sort(([a], [b]) => a.localeCompare(b)).map(([name, server]) => formatMcpServer(name, server));
20734
+ function appendMcpServers(content, blocks) {
20628
20735
  const prefix = content.trimEnd();
20629
20736
  return `${prefix ? `${prefix}
20630
20737
 
@@ -20704,12 +20811,12 @@ var init_toml_merge = __esm({
20704
20811
  });
20705
20812
 
20706
20813
  // src/install/yaml-merge.ts
20707
- import { mkdir as mkdir9, readFile as readFile17, writeFile as writeFile9 } from "fs/promises";
20814
+ import { mkdir as mkdir9, readFile as readFile18, writeFile as writeFile9 } from "fs/promises";
20708
20815
  import { dirname as dirname15 } from "path";
20709
20816
  import { parse as parse7, stringify } from "yaml";
20710
20817
  async function mergeYamlFile(sourcePath, destPath) {
20711
- const source = parseYamlValue(await readFile17(sourcePath, "utf8"));
20712
- const current = await pathExists(destPath) ? parseYamlValue(await readFile17(destPath, "utf8")) : {};
20818
+ const source = parseYamlValue(await readFile18(sourcePath, "utf8"));
20819
+ const current = await pathExists(destPath) ? parseYamlValue(await readFile18(destPath, "utf8")) : {};
20713
20820
  const merged = deepMerge2(current, source);
20714
20821
  await mkdir9(dirname15(destPath), { recursive: true });
20715
20822
  await writeFile9(destPath, stringify(merged), "utf8");
@@ -20769,7 +20876,7 @@ var init_yaml_merge = __esm({
20769
20876
  });
20770
20877
 
20771
20878
  // src/install/merge-removal.ts
20772
- import { mkdir as mkdir10, readFile as readFile18, writeFile as writeFile10 } from "fs/promises";
20879
+ import { mkdir as mkdir10, readFile as readFile19, writeFile as writeFile10 } from "fs/promises";
20773
20880
  import { dirname as dirname16 } from "path";
20774
20881
  import { parse as parse8, stringify as stringify2 } from "yaml";
20775
20882
  function assertExactMergeContribution(contribution, strategy, currentContent) {
@@ -20847,7 +20954,7 @@ async function mergeRemovalForInstall(sourcePath, strategy, currentContent, opti
20847
20954
  return introducedMergeContent(parseMergeDestination(currentContent, strategy), source);
20848
20955
  }
20849
20956
  async function removeMergeContribution(destPath, strategy, removal) {
20850
- const content = await readFile18(destPath, "utf8");
20957
+ const content = await readFile19(destPath, "utf8");
20851
20958
  if (strategy === "codex-toml-mcp") {
20852
20959
  const servers = isRecord4(removal.mcpServers) ? removal.mcpServers : removal;
20853
20960
  await writeFile10(destPath, removeCodexTomlMcpSections(content, Object.keys(servers)), "utf8");
@@ -20871,7 +20978,7 @@ async function readMergeSource(sourcePath, strategy) {
20871
20978
  if (strategy === "openclaw-json-deep") {
20872
20979
  return requireRecord(await renderOpenClawJsonMergeSource(sourcePath), "OpenClaw JSON merge source");
20873
20980
  }
20874
- const content = await readFile18(sourcePath, "utf8");
20981
+ const content = await readFile19(sourcePath, "utf8");
20875
20982
  if (strategy === "yaml-deep") return requireRecord(normalizeYamlValue2(parse8(content)), "YAML merge source");
20876
20983
  return requireRecord(JSON.parse(content), "JSON merge source");
20877
20984
  }
@@ -21123,9 +21230,9 @@ var init_desired = __esm({
21123
21230
 
21124
21231
  // src/install/instructions-block.ts
21125
21232
  import { createHash as createHash12 } from "crypto";
21126
- import { mkdtemp as mkdtemp2, readFile as readFile19, realpath as realpath2, rm as rm6, writeFile as writeFile11 } from "fs/promises";
21233
+ import { mkdtemp as mkdtemp2, readFile as readFile20, realpath as realpath2, rm as rm6, writeFile as writeFile11 } from "fs/promises";
21127
21234
  import { tmpdir as tmpdir3 } from "os";
21128
- import { basename as basename2, dirname as dirname17, join as join16, relative as relative11 } from "path";
21235
+ import { basename as basename2, dirname as dirname17, join as join17, relative as relative11 } from "path";
21129
21236
  function exactManagedInstructionBlockSnapshot(content, selector) {
21130
21237
  const beginCount = [...content.matchAll(new RegExp(`<!-- BEGIN openpack:include ${escapeRegex2(selector)}(?=\\s|-->)`, "gu"))].length;
21131
21238
  const endCount = [...content.matchAll(new RegExp(`<!-- END openpack:include ${escapeRegex2(selector)}(?=\\s|-->)`, "gu"))].length;
@@ -21176,7 +21283,7 @@ function exactManagedInstructionBlockSnapshot(content, selector) {
21176
21283
  };
21177
21284
  }
21178
21285
  async function desiredManagedInstructionBlockHash(sourcePath) {
21179
- const source = await readFile19(sourcePath, "utf8");
21286
+ const source = await readFile20(sourcePath, "utf8");
21180
21287
  return hashText(managedBlockBody(source));
21181
21288
  }
21182
21289
  async function readManagedInstructionBlockState(destPath, selector, transport) {
@@ -21196,7 +21303,7 @@ async function readManagedInstructionBlockState(destPath, selector, transport) {
21196
21303
  };
21197
21304
  }
21198
21305
  async function writeManagedInstructionBlock(sourcePath, destPath, selector, transport, options = {}) {
21199
- const source = await readFile19(sourcePath, "utf8");
21306
+ const source = await readFile20(sourcePath, "utf8");
21200
21307
  const desired = renderManagedInstructionBlock(selector, source);
21201
21308
  const existing = await readOptionalText(destPath, transport);
21202
21309
  const merged = upsertManagedInstructionBlock(existing ?? "", selector, desired.block, options);
@@ -21317,7 +21424,7 @@ function referencesAgentsMd(content, claudePath, agentsPath) {
21317
21424
  if (!referenced) continue;
21318
21425
  const cleaned = referenced.trim().replace(/^["']|["']$/g, "");
21319
21426
  if (!/AGENTS\.md$/i.test(cleaned)) continue;
21320
- const candidate = cleaned.startsWith("/") ? cleaned : join16(claudeDir, cleaned);
21427
+ const candidate = cleaned.startsWith("/") ? cleaned : join17(claudeDir, cleaned);
21321
21428
  if (relative11(dirname17(agentsPath), candidate).replaceAll("\\", "/") === "AGENTS.md") return true;
21322
21429
  if (candidate === agentsPath) return true;
21323
21430
  }
@@ -21337,8 +21444,8 @@ async function writeTextWithTransport(path, content, transport) {
21337
21444
  await transport.writeFileAtomic(path, content);
21338
21445
  return;
21339
21446
  }
21340
- const tempRoot = await mkdtemp2(join16(tmpdir3(), "agentwheel-instructions-"));
21341
- const localPath = join16(tempRoot, basename2(path) || "instructions.md");
21447
+ const tempRoot = await mkdtemp2(join17(tmpdir3(), "agentwheel-instructions-"));
21448
+ const localPath = join17(tempRoot, basename2(path) || "instructions.md");
21342
21449
  try {
21343
21450
  await writeFile11(localPath, content, "utf8");
21344
21451
  await transport.atomicCopy(localPath, path, "file");
@@ -21376,9 +21483,9 @@ __export(apply_exports, {
21376
21483
  });
21377
21484
  import { execFile as execFile5 } from "child_process";
21378
21485
  import { createHash as createHash13, randomUUID as randomUUID3 } from "crypto";
21379
- import { chmod as chmod3, link as link2, lstat as lstat6, mkdir as mkdir11, mkdtemp as mkdtemp3, open as open5, readFile as readFile20, rm as rm7, writeFile as writeFile12 } from "fs/promises";
21486
+ import { chmod as chmod3, link as link2, lstat as lstat6, mkdir as mkdir11, mkdtemp as mkdtemp3, open as open5, readFile as readFile21, rm as rm7, writeFile as writeFile12 } from "fs/promises";
21380
21487
  import { tmpdir as tmpdir4 } from "os";
21381
- import { basename as basename3, dirname as dirname18, join as join17, resolve as resolve20 } from "path";
21488
+ import { basename as basename3, dirname as dirname18, join as join18, resolve as resolve20 } from "path";
21382
21489
  import { promisify as promisify5 } from "util";
21383
21490
  async function applyInstallPlan(plan, sourceLock, options = {}) {
21384
21491
  return applyPlanTransactionally(plan, { ...options, sourceLock });
@@ -21478,6 +21585,10 @@ async function assertRuntimeStateRevision(plan, transport) {
21478
21585
  async function applyPlanTransactionally(plan, options = {}) {
21479
21586
  const transport = options.transport ?? localTransport;
21480
21587
  const scope = { installationType: plan.installationType, stateKey: plan.stateKey };
21588
+ const openClawAcceptCapabilities = createOpenClawCapabilityDetector(async (args) => {
21589
+ if (transport.kind === "local") return (await execFileAsync4("openclaw", args, { timeout: 1e4 })).stdout;
21590
+ return transport.execFile?.("openclaw", args, { cwd: plan.targetRoot });
21591
+ });
21481
21592
  if (plan.hasBlockingChanges) {
21482
21593
  const blockers = plan.operations.filter((operation) => operation.action === "drift" || operation.action === "conflict");
21483
21594
  throw new Error(`Refusing to apply with blocking changes: ${blockers.map((item) => item.relativeDestPath).join(", ")}`);
@@ -21538,6 +21649,7 @@ async function applyPlanTransactionally(plan, options = {}) {
21538
21649
  transport,
21539
21650
  now,
21540
21651
  executePlugins: options.executePlugins,
21652
+ openClawAcceptCapabilities,
21541
21653
  graphLockDigest,
21542
21654
  plan
21543
21655
  });
@@ -21773,7 +21885,7 @@ async function assertCommittedJournalState(journal, expectedManifest, transport)
21773
21885
  }
21774
21886
  }
21775
21887
  if (journal.workspaceConfigPath && journal.workspaceConfig) {
21776
- const actual = JSON.parse(await readFile20(journal.workspaceConfigPath, "utf8"));
21888
+ const actual = JSON.parse(await readFile21(journal.workspaceConfigPath, "utf8"));
21777
21889
  if (canonicalJson5(actual) !== canonicalJson5(journal.workspaceConfig)) {
21778
21890
  throw new Error(`Workspace config postcheck failed for ${journal.workspaceConfigPath}.`);
21779
21891
  }
@@ -21795,7 +21907,7 @@ async function assertMetadataAuditGuards(journal, after, transport, requireAfter
21795
21907
  throw new Error("Metadata-audit content digest is invalid.");
21796
21908
  }
21797
21909
  try {
21798
- if (await readFile20(path, "utf8") !== file2.content) throw new Error(`Metadata-audit file changed: ${path}`);
21910
+ if (await readFile21(path, "utf8") !== file2.content) throw new Error(`Metadata-audit file changed: ${path}`);
21799
21911
  } catch (error46) {
21800
21912
  if (error46.code !== "ENOENT" || requireAfter) throw error46;
21801
21913
  }
@@ -21878,7 +21990,7 @@ async function writeAuditFileExclusive(path, content, validateCallerPath) {
21878
21990
  try {
21879
21991
  await link2(temporary, path);
21880
21992
  } catch (error46) {
21881
- if (error46.code !== "EEXIST" || await readFile20(path, "utf8") !== content) throw error46;
21993
+ if (error46.code !== "EEXIST" || await readFile21(path, "utf8") !== content) throw error46;
21882
21994
  }
21883
21995
  const directory = await open5(dirname18(path), "r");
21884
21996
  try {
@@ -21903,7 +22015,7 @@ async function applyOperation(operation, context) {
21903
22015
  throw new Error(`Invalid plugin operation missing hash: ${operation.relativeDestPath}`);
21904
22016
  }
21905
22017
  if (context.executePlugins) {
21906
- await executePluginInstall(operation, transport);
22018
+ await executePluginInstall(operation, transport, context.openClawAcceptCapabilities);
21907
22019
  }
21908
22020
  return manifestEntryForOperation(operation, {
21909
22021
  now,
@@ -22063,8 +22175,15 @@ async function applyOperation(operation, context) {
22063
22175
  }
22064
22176
  return void 0;
22065
22177
  }
22066
- async function executePluginInstall(operation, transport) {
22067
- const commands = semanticInstallCommands(operation);
22178
+ async function executePluginInstall(operation, transport, openClawAcceptCapabilities) {
22179
+ const commands = await Promise.all(semanticInstallCommands(operation).map(async (command) => {
22180
+ if (command.length !== 5 || command.slice(0, 4).join(" ") !== "openclaw plugins install --force") return command;
22181
+ return openClawPluginInstallCommand({
22182
+ path: command[4],
22183
+ dryRun: false,
22184
+ acceptCapabilities: await openClawAcceptCapabilities?.() ?? false
22185
+ });
22186
+ }));
22068
22187
  if (commands.length === 0) throw new Error(`Invalid plugin operation missing command: ${operation.relativeDestPath}`);
22069
22188
  if (!operation.sourcePath) {
22070
22189
  throw new Error(`Invalid plugin operation missing source path: ${operation.relativeDestPath}`);
@@ -22112,10 +22231,10 @@ async function prepareSemanticPluginState(operation, transport) {
22112
22231
  async function prepareClaudeMarketplace(operation, transport) {
22113
22232
  const spec = requireSemanticPluginState(operation);
22114
22233
  const marketplaceName = requireMarketplaceName(operation);
22115
- const marketplaceRoot = join17(spec.stateRoot, "marketplace");
22234
+ const marketplaceRoot = join18(spec.stateRoot, "marketplace");
22116
22235
  await transport.rm(spec.stateRoot);
22117
- await transport.atomicCopy(requireSourcePath(operation), join17(marketplaceRoot, "plugins", spec.pluginName), operation.kind);
22118
- await transport.writeJsonAtomic(join17(marketplaceRoot, ".claude-plugin", "marketplace.json"), {
22236
+ await transport.atomicCopy(requireSourcePath(operation), join18(marketplaceRoot, "plugins", spec.pluginName), operation.kind);
22237
+ await transport.writeJsonAtomic(join18(marketplaceRoot, ".claude-plugin", "marketplace.json"), {
22119
22238
  name: marketplaceName,
22120
22239
  owner: { name: "Agentwheel" },
22121
22240
  plugins: [
@@ -22130,10 +22249,10 @@ async function prepareClaudeMarketplace(operation, transport) {
22130
22249
  async function prepareCodexMarketplace(operation, transport) {
22131
22250
  const spec = requireSemanticPluginState(operation);
22132
22251
  const marketplaceName = requireMarketplaceName(operation);
22133
- const marketplaceRoot = join17(spec.stateRoot, "marketplace");
22252
+ const marketplaceRoot = join18(spec.stateRoot, "marketplace");
22134
22253
  await transport.rm(spec.stateRoot);
22135
- await transport.atomicCopy(requireSourcePath(operation), join17(marketplaceRoot, "plugins", spec.pluginName), operation.kind);
22136
- await transport.writeJsonAtomic(join17(marketplaceRoot, ".agents", "plugins", "marketplace.json"), {
22254
+ await transport.atomicCopy(requireSourcePath(operation), join18(marketplaceRoot, "plugins", spec.pluginName), operation.kind);
22255
+ await transport.writeJsonAtomic(join18(marketplaceRoot, ".agents", "plugins", "marketplace.json"), {
22137
22256
  name: marketplaceName,
22138
22257
  interface: {
22139
22258
  displayName: "Agentwheel"
@@ -22157,11 +22276,11 @@ async function prepareCodexMarketplace(operation, transport) {
22157
22276
  async function prepareCopilotPlugin(operation, transport) {
22158
22277
  const spec = requireSemanticPluginState(operation);
22159
22278
  await transport.rm(spec.stateRoot);
22160
- await transport.atomicCopy(requireSourcePath(operation), join17(spec.stateRoot, "plugin"), operation.kind);
22279
+ await transport.atomicCopy(requireSourcePath(operation), join18(spec.stateRoot, "plugin"), operation.kind);
22161
22280
  }
22162
22281
  async function prepareHermesGitShim(operation, transport) {
22163
22282
  const spec = requireSemanticPluginState(operation);
22164
- const repoRoot = join17(spec.stateRoot, "repo");
22283
+ const repoRoot = join18(spec.stateRoot, "repo");
22165
22284
  await transport.rm(spec.stateRoot);
22166
22285
  await transport.atomicCopy(requireSourcePath(operation), repoRoot, operation.kind);
22167
22286
  if (!transport.execFile) {
@@ -22216,8 +22335,8 @@ async function executeSemanticCommands(operation, commands, transport, options =
22216
22335
  if (!operation.sourcePath) {
22217
22336
  throw new Error(`Invalid semantic plugin operation missing source path: ${operation.relativeDestPath}`);
22218
22337
  }
22219
- const stagingRoot = join17(operation.destPath, ".agentwheel", "plugin-staging", `${process.pid}-${Date.now()}`);
22220
- const remoteSourcePath = join17(stagingRoot, basename3(operation.sourcePath));
22338
+ const stagingRoot = join18(operation.destPath, ".agentwheel", "plugin-staging", `${process.pid}-${Date.now()}`);
22339
+ const remoteSourcePath = join18(stagingRoot, basename3(operation.sourcePath));
22221
22340
  try {
22222
22341
  await transport.atomicCopy(operation.sourcePath, remoteSourcePath, operation.kind);
22223
22342
  for (const [command, ...args] of commands) {
@@ -22484,8 +22603,8 @@ async function mergeWithTransport(sourcePath, destPath, transport, merge2) {
22484
22603
  await merge2(sourcePath, destPath);
22485
22604
  return;
22486
22605
  }
22487
- const tempRoot = await mkdtemp3(join17(tmpdir4(), "agentwheel-merge-"));
22488
- const localDest = join17(tempRoot, basename3(destPath) || "merged");
22606
+ const tempRoot = await mkdtemp3(join18(tmpdir4(), "agentwheel-merge-"));
22607
+ const localDest = join18(tempRoot, basename3(destPath) || "merged");
22489
22608
  try {
22490
22609
  if (await transport.pathExists(destPath)) {
22491
22610
  await writeFile12(localDest, await transport.readFile(destPath), "utf8");
@@ -22501,8 +22620,8 @@ async function removeMergeWithTransport(destPath, strategy, removal, transport)
22501
22620
  await removeMergeContribution(destPath, strategy, removal);
22502
22621
  return;
22503
22622
  }
22504
- const tempRoot = await mkdtemp3(join17(tmpdir4(), "agentwheel-merge-remove-"));
22505
- const localDest = join17(tempRoot, basename3(destPath) || "merged");
22623
+ const tempRoot = await mkdtemp3(join18(tmpdir4(), "agentwheel-merge-remove-"));
22624
+ const localDest = join18(tempRoot, basename3(destPath) || "merged");
22506
22625
  try {
22507
22626
  await writeFile12(localDest, await transport.readFile(destPath), "utf8");
22508
22627
  await removeMergeContribution(localDest, strategy, removal);
@@ -22512,8 +22631,8 @@ async function removeMergeWithTransport(destPath, strategy, removal, transport)
22512
22631
  }
22513
22632
  }
22514
22633
  async function mergeOpenClawJsonWithTransport(sourcePath, destPath, transport) {
22515
- const tempRoot = await mkdtemp3(join17(tmpdir4(), "agentwheel-openclaw-merge-"));
22516
- const localDest = join17(tempRoot, basename3(destPath) || "openclaw.json");
22634
+ const tempRoot = await mkdtemp3(join18(tmpdir4(), "agentwheel-openclaw-merge-"));
22635
+ const localDest = join18(tempRoot, basename3(destPath) || "openclaw.json");
22517
22636
  const validationPath = transport.kind === "local" ? localDest : `${destPath}.validate-agentwheel-${process.pid}-${Date.now()}`;
22518
22637
  try {
22519
22638
  if (await transport.pathExists(destPath)) {
@@ -22540,7 +22659,7 @@ async function validateOpenClawConfig(configPath, destPath, transport) {
22540
22659
  throw new Error(`Cannot validate OpenClaw config over ${transport.description}: transport does not support command execution.`);
22541
22660
  }
22542
22661
  const openClawHome = dirname18(destPath);
22543
- const bundledBin = join17(openClawHome, "npm", "node_modules", ".bin", "openclaw");
22662
+ const bundledBin = join18(openClawHome, "npm", "node_modules", ".bin", "openclaw");
22544
22663
  const script = String.raw`
22545
22664
  set -euo pipefail
22546
22665
  cfg=$1
@@ -22568,6 +22687,7 @@ var init_apply = __esm({
22568
22687
  init_declarations();
22569
22688
  init_graph_lock();
22570
22689
  init_transport();
22690
+ init_openclaw2();
22571
22691
  init_run_as_policy();
22572
22692
  init_json_merge();
22573
22693
  init_openclaw_json_merge();
@@ -22718,8 +22838,8 @@ import { basename as basename8, join as join28, relative as relative12 } from "p
22718
22838
 
22719
22839
  // src/staging/codex-subagents.ts
22720
22840
  init_fs();
22721
- import { mkdir as mkdir12, readFile as readFile21, writeFile as writeFile13 } from "fs/promises";
22722
- import { basename as basename4, dirname as dirname19, join as join18 } from "path";
22841
+ import { mkdir as mkdir12, readFile as readFile22, writeFile as writeFile13 } from "fs/promises";
22842
+ import { basename as basename4, dirname as dirname19, join as join19 } from "path";
22723
22843
  import { parse as parseYaml } from "yaml";
22724
22844
  var requiredCodexAgentFields = ["name", "description", "developer_instructions"];
22725
22845
  async function renderCodexSubagents(artifacts, stageRoot, adapter) {
@@ -22743,27 +22863,27 @@ async function renderCodexSubagents(artifacts, stageRoot, adapter) {
22743
22863
  async function renderCodexSubagent(artifact, stageRoot) {
22744
22864
  const sourcePath = artifact.stagedPath ?? artifact.sourcePath;
22745
22865
  const agentName = codexAgentName(artifact);
22746
- const renderedPath = join18(stageRoot, ".agentwheel-rendered", "codex-subagents", `${agentName}.toml`);
22866
+ const renderedPath = join19(stageRoot, ".agentwheel-rendered", "codex-subagents", `${agentName}.toml`);
22747
22867
  const lowerSourcePath = sourcePath.toLowerCase();
22748
22868
  if (artifact.kind === "file" && (artifact.name.toLowerCase().endsWith(".toml") || lowerSourcePath.endsWith(".toml"))) {
22749
- const content = await readFile21(sourcePath, "utf8");
22869
+ const content = await readFile22(sourcePath, "utf8");
22750
22870
  validateCodexAgentToml(content, sourcePath);
22751
22871
  return {
22752
22872
  ...artifact,
22753
22873
  name: agentName,
22754
- relativePath: join18("subagents", `${agentName}.toml`),
22874
+ relativePath: join19("subagents", `${agentName}.toml`),
22755
22875
  kind: "file",
22756
22876
  hash: await hashPath(sourcePath)
22757
22877
  };
22758
22878
  }
22759
- const markdownPath = artifact.kind === "dir" ? join18(sourcePath, "AGENTS.md") : sourcePath;
22879
+ const markdownPath = artifact.kind === "dir" ? join19(sourcePath, "AGENTS.md") : sourcePath;
22760
22880
  if (artifact.kind === "dir" && !await pathExists(markdownPath)) {
22761
22881
  throw new Error(`Codex subagent directory ${artifact.relativePath} must contain AGENTS.md.`);
22762
22882
  }
22763
22883
  if (artifact.kind === "file" && !artifact.name.toLowerCase().endsWith(".md") && !lowerSourcePath.endsWith(".md")) {
22764
22884
  throw new Error(`Codex subagent ${artifact.relativePath} must be a .toml file, .md file, or directory containing AGENTS.md.`);
22765
22885
  }
22766
- const markdown = await readFile21(markdownPath, "utf8");
22886
+ const markdown = await readFile22(markdownPath, "utf8");
22767
22887
  const toml = markdownToCodexAgentToml(agentName, markdown);
22768
22888
  await mkdir12(dirname19(renderedPath), { recursive: true });
22769
22889
  await writeFile13(renderedPath, toml, "utf8");
@@ -22772,7 +22892,7 @@ async function renderCodexSubagent(artifact, stageRoot) {
22772
22892
  name: agentName,
22773
22893
  sourcePath: renderedPath,
22774
22894
  stagedPath: renderedPath,
22775
- relativePath: join18("subagents", `${agentName}.toml`),
22895
+ relativePath: join19("subagents", `${agentName}.toml`),
22776
22896
  kind: "file",
22777
22897
  hash: await hashPath(renderedPath)
22778
22898
  };
@@ -22847,8 +22967,8 @@ function escapeRegExp2(value) {
22847
22967
 
22848
22968
  // src/staging/copilot-artifacts.ts
22849
22969
  init_fs();
22850
- import { mkdir as mkdir13, readFile as readFile22, writeFile as writeFile14 } from "fs/promises";
22851
- import { basename as basename5, dirname as dirname20, join as join19 } from "path";
22970
+ import { mkdir as mkdir13, readFile as readFile23, writeFile as writeFile14 } from "fs/promises";
22971
+ import { basename as basename5, dirname as dirname20, join as join20 } from "path";
22852
22972
  async function renderCopilotArtifacts(artifacts, stageRoot, adapter) {
22853
22973
  if (adapter?.name !== "copilot") return artifacts;
22854
22974
  const names = /* @__PURE__ */ new Set();
@@ -22870,15 +22990,15 @@ async function renderCopilotArtifacts(artifacts, stageRoot, adapter) {
22870
22990
  async function renderCopilotSubagent(artifact, stageRoot) {
22871
22991
  const sourcePath = artifact.stagedPath ?? artifact.sourcePath;
22872
22992
  const agentName = copilotAgentName(artifact);
22873
- const renderedPath = join19(stageRoot, ".agentwheel-rendered", "copilot-subagents", `${agentName}.agent.md`);
22874
- const markdownPath = artifact.kind === "dir" ? join19(sourcePath, "AGENTS.md") : sourcePath;
22993
+ const renderedPath = join20(stageRoot, ".agentwheel-rendered", "copilot-subagents", `${agentName}.agent.md`);
22994
+ const markdownPath = artifact.kind === "dir" ? join20(sourcePath, "AGENTS.md") : sourcePath;
22875
22995
  if (artifact.kind === "dir" && !await pathExists(markdownPath)) {
22876
22996
  throw new Error(`Copilot subagent directory ${artifact.relativePath} must contain AGENTS.md.`);
22877
22997
  }
22878
22998
  if (artifact.kind === "file" && !artifact.name.toLowerCase().endsWith(".md")) {
22879
22999
  throw new Error(`Copilot subagent ${artifact.relativePath} must be a .md file or directory containing AGENTS.md.`);
22880
23000
  }
22881
- const markdown = await readFile22(markdownPath, "utf8");
23001
+ const markdown = await readFile23(markdownPath, "utf8");
22882
23002
  await mkdir13(dirname20(renderedPath), { recursive: true });
22883
23003
  await writeFile14(renderedPath, ensureCopilotAgentDescription(agentName, markdown), "utf8");
22884
23004
  return {
@@ -22886,7 +23006,7 @@ async function renderCopilotSubagent(artifact, stageRoot) {
22886
23006
  name: `${agentName}.agent.md`,
22887
23007
  sourcePath: renderedPath,
22888
23008
  stagedPath: renderedPath,
22889
- relativePath: join19("subagents", `${agentName}.agent.md`),
23009
+ relativePath: join20("subagents", `${agentName}.agent.md`),
22890
23010
  kind: "file",
22891
23011
  hash: await hashPath(renderedPath)
22892
23012
  };
@@ -22934,8 +23054,8 @@ function yamlString(value) {
22934
23054
 
22935
23055
  // src/staging/openclaw-subagents.ts
22936
23056
  init_fs();
22937
- import { mkdir as mkdir14, readFile as readFile23, writeFile as writeFile15 } from "fs/promises";
22938
- import { basename as basename6, dirname as dirname21, join as join20 } from "path";
23057
+ import { mkdir as mkdir14, readFile as readFile24, writeFile as writeFile15 } from "fs/promises";
23058
+ import { basename as basename6, dirname as dirname21, join as join21 } from "path";
22939
23059
  async function renderOpenClawSubagents(artifacts, stageRoot, adapter) {
22940
23060
  if (adapter?.name !== "openclaw") return artifacts;
22941
23061
  const names = /* @__PURE__ */ new Set();
@@ -22957,18 +23077,18 @@ async function renderOpenClawSubagents(artifacts, stageRoot, adapter) {
22957
23077
  async function renderOpenClawSubagent(artifact, stageRoot) {
22958
23078
  const sourcePath = artifact.stagedPath ?? artifact.sourcePath;
22959
23079
  const agentId = openClawAgentId(artifact);
22960
- const markdownPath = artifact.kind === "dir" ? join20(sourcePath, "AGENTS.md") : sourcePath;
23080
+ const markdownPath = artifact.kind === "dir" ? join21(sourcePath, "AGENTS.md") : sourcePath;
22961
23081
  if (artifact.kind === "dir" && !await pathExists(markdownPath)) {
22962
23082
  throw new Error(`OpenClaw subagent directory ${artifact.relativePath} must contain AGENTS.md.`);
22963
23083
  }
22964
23084
  if (artifact.kind === "file" && !artifact.name.toLowerCase().endsWith(".md") && !sourcePath.toLowerCase().endsWith(".md")) {
22965
23085
  throw new Error(`OpenClaw subagent ${artifact.relativePath} must be a .md file or directory containing AGENTS.md.`);
22966
23086
  }
22967
- const parsed = splitFrontmatter3(await readFile23(markdownPath, "utf8"));
23087
+ const parsed = splitFrontmatter3(await readFile24(markdownPath, "utf8"));
22968
23088
  const body = parsed.body.trim().length > 0 ? parsed.body.trim() : `# ${titleFromAgentId(agentId)}
22969
23089
 
22970
23090
  ${parsed.description ?? `OpenClaw subagent ${agentId}.`}`;
22971
- const renderedPath = join20(stageRoot, ".agentwheel-rendered", "openclaw-subagents", agentId, "AGENTS.md");
23091
+ const renderedPath = join21(stageRoot, ".agentwheel-rendered", "openclaw-subagents", agentId, "AGENTS.md");
22972
23092
  await mkdir14(dirname21(renderedPath), { recursive: true });
22973
23093
  await writeFile15(renderedPath, `${body}
22974
23094
  `, "utf8");
@@ -22978,7 +23098,7 @@ ${parsed.description ?? `OpenClaw subagent ${agentId}.`}`;
22978
23098
  name: agentId,
22979
23099
  sourcePath: renderedDir,
22980
23100
  stagedPath: renderedDir,
22981
- relativePath: join20("subagents", agentId),
23101
+ relativePath: join21("subagents", agentId),
22982
23102
  kind: "dir",
22983
23103
  hash: await hashPath(renderedDir)
22984
23104
  };
@@ -23003,15 +23123,15 @@ function titleFromAgentId(agentId) {
23003
23123
  }
23004
23124
 
23005
23125
  // src/targets/plugins/claude.ts
23006
- import { join as join22 } from "path";
23126
+ import { join as join23 } from "path";
23007
23127
 
23008
23128
  // src/targets/plugins/common.ts
23009
23129
  init_fs();
23010
- import { readFile as readFile24 } from "fs/promises";
23011
- import { join as join21 } from "path";
23130
+ import { readFile as readFile25 } from "fs/promises";
23131
+ import { join as join22 } from "path";
23012
23132
  import { parseDocument } from "yaml";
23013
23133
  function pluginStateRoot(request) {
23014
- return join21(
23134
+ return join22(
23015
23135
  request.targetRoot,
23016
23136
  ".agentwheel",
23017
23137
  "plugins",
@@ -23029,16 +23149,16 @@ function safeNameSegment(value) {
23029
23149
  return normalized.length > 0 ? normalized : "unnamed";
23030
23150
  }
23031
23151
  async function jsonPluginName(root, relativeManifestPath, fallback) {
23032
- const manifestPath = join21(root, relativeManifestPath);
23152
+ const manifestPath = join22(root, relativeManifestPath);
23033
23153
  if (!await pathExists(manifestPath)) return fallback;
23034
- const parsed = JSON.parse(await readFile24(manifestPath, "utf8"));
23154
+ const parsed = JSON.parse(await readFile25(manifestPath, "utf8"));
23035
23155
  return typeof parsed.name === "string" && parsed.name.trim().length > 0 ? parsed.name.trim() : fallback;
23036
23156
  }
23037
23157
  async function yamlPluginName(root, relativeManifestPaths, fallback) {
23038
23158
  for (const relativeManifestPath of relativeManifestPaths) {
23039
- const manifestPath = join21(root, relativeManifestPath);
23159
+ const manifestPath = join22(root, relativeManifestPath);
23040
23160
  if (!await pathExists(manifestPath)) continue;
23041
- const document = parseDocument(await readFile24(manifestPath, "utf8"));
23161
+ const document = parseDocument(await readFile25(manifestPath, "utf8"));
23042
23162
  const parsed = document.toJSON();
23043
23163
  if (!isRecord5(parsed)) continue;
23044
23164
  for (const key of ["name", "module", "package"]) {
@@ -23067,7 +23187,7 @@ async function claudePluginSpec(request) {
23067
23187
  packageName: request.artifact.packageName,
23068
23188
  installName: request.installName
23069
23189
  });
23070
- const marketplaceRoot = join22(stateRoot, "marketplace");
23190
+ const marketplaceRoot = join23(stateRoot, "marketplace");
23071
23191
  const scope = claudeScope(request.installationType);
23072
23192
  const selector = `${pluginName}@${marketplaceName}`;
23073
23193
  return {
@@ -23092,7 +23212,7 @@ function claudeScope(installationType) {
23092
23212
  }
23093
23213
 
23094
23214
  // src/targets/plugins/codex.ts
23095
- import { join as join23 } from "path";
23215
+ import { join as join24 } from "path";
23096
23216
  async function codexPluginSpec(request) {
23097
23217
  const pluginName = await jsonPluginName(request.sourcePath, ".codex-plugin/plugin.json", request.installName);
23098
23218
  const marketplaceName = agentwheelMarketplaceName(request.artifact.packageName, pluginName);
@@ -23103,7 +23223,7 @@ async function codexPluginSpec(request) {
23103
23223
  packageName: request.artifact.packageName,
23104
23224
  installName: request.installName
23105
23225
  });
23106
- const marketplaceRoot = join23(stateRoot, "marketplace");
23226
+ const marketplaceRoot = join24(stateRoot, "marketplace");
23107
23227
  const selector = `${pluginName}@${marketplaceName}`;
23108
23228
  return {
23109
23229
  runtime: "codex",
@@ -23122,7 +23242,7 @@ async function codexPluginSpec(request) {
23122
23242
  }
23123
23243
 
23124
23244
  // src/targets/plugins/copilot.ts
23125
- import { join as join24 } from "path";
23245
+ import { join as join25 } from "path";
23126
23246
  async function copilotPluginSpec(request) {
23127
23247
  if (request.installationType !== "user") {
23128
23248
  throw new Error("Copilot plugins are persistent user-level installs only; pass --installation-type user.");
@@ -23135,7 +23255,7 @@ async function copilotPluginSpec(request) {
23135
23255
  packageName: request.artifact.packageName,
23136
23256
  installName: request.installName
23137
23257
  });
23138
- const pluginRoot = join24(stateRoot, "plugin");
23258
+ const pluginRoot = join25(stateRoot, "plugin");
23139
23259
  return {
23140
23260
  runtime: "copilot",
23141
23261
  pluginName,
@@ -23146,7 +23266,7 @@ async function copilotPluginSpec(request) {
23146
23266
  }
23147
23267
 
23148
23268
  // src/targets/plugins/hermes.ts
23149
- import { join as join25 } from "path";
23269
+ import { join as join26 } from "path";
23150
23270
  async function hermesPluginSpec(request) {
23151
23271
  if (request.installationType !== "user") {
23152
23272
  throw new Error("Hermes plugins are user-level installs only; pass --installation-type user.");
@@ -23159,7 +23279,7 @@ async function hermesPluginSpec(request) {
23159
23279
  packageName: request.artifact.packageName,
23160
23280
  installName: request.installName
23161
23281
  });
23162
- const repoRoot = join25(stateRoot, "repo");
23282
+ const repoRoot = join26(stateRoot, "repo");
23163
23283
  return {
23164
23284
  runtime: "hermes",
23165
23285
  pluginName,
@@ -23169,64 +23289,8 @@ async function hermesPluginSpec(request) {
23169
23289
  };
23170
23290
  }
23171
23291
 
23172
- // src/targets/plugins/openclaw.ts
23173
- init_fs();
23174
- import { readFile as readFile25 } from "fs/promises";
23175
- import { join as join26 } from "path";
23176
- function openClawPluginInstallCommand(request) {
23177
- return ["openclaw", "plugins", "install", "--force", request.path];
23178
- }
23179
- function openClawPluginUninstallCommand(pluginName) {
23180
- return ["openclaw", "plugins", "uninstall", pluginName, "--force"];
23181
- }
23182
- async function openClawPluginSpec(request) {
23183
- if (request.format === "openclaw-clawhub-plugin") {
23184
- const metadata = await openClawClawHubPluginMetadata(request.path, request.fallbackPluginName);
23185
- return {
23186
- runtime: "openclaw",
23187
- pluginName: metadata.pluginName,
23188
- installCommands: [openClawPluginInstallCommand({ path: metadata.installSpec, dryRun: true })],
23189
- uninstallCommands: [openClawPluginUninstallCommand(metadata.pluginName)]
23190
- };
23191
- }
23192
- const pluginName = await openClawPluginName(request.path, request.fallbackPluginName);
23193
- return {
23194
- runtime: "openclaw",
23195
- pluginName,
23196
- installCommands: [openClawPluginInstallCommand({ path: request.path, dryRun: true })],
23197
- uninstallCommands: [openClawPluginUninstallCommand(pluginName)]
23198
- };
23199
- }
23200
- async function openClawPluginName(root, fallback) {
23201
- for (const manifestName of ["plugin.json", "openclaw.plugin.json"]) {
23202
- const manifestPath = join26(root, manifestName);
23203
- if (!await pathExists(manifestPath)) continue;
23204
- const parsed = JSON.parse(await readFile25(manifestPath, "utf8"));
23205
- if (typeof parsed.name === "string" && parsed.name.trim().length > 0) return parsed.name.trim();
23206
- }
23207
- return fallback;
23208
- }
23209
- async function openClawClawHubPluginMetadata(root, fallback) {
23210
- const metadataPath = join26(root, "clawhub.json");
23211
- if (!await pathExists(metadataPath)) {
23212
- throw new Error("OpenClaw ClawHub plugins must contain clawhub.json");
23213
- }
23214
- const parsed = JSON.parse(await readFile25(metadataPath, "utf8"));
23215
- const installSpec = stringField(parsed.installSpec);
23216
- if (!installSpec?.startsWith("clawhub:")) {
23217
- throw new Error("OpenClaw ClawHub plugin metadata must declare installSpec starting with clawhub:");
23218
- }
23219
- const pluginName = stringField(parsed.runtimeId) ?? installNameFor(stringField(parsed.name) ?? fallback);
23220
- return { installSpec, pluginName };
23221
- }
23222
- function stringField(value) {
23223
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
23224
- }
23225
- function installNameFor(value) {
23226
- return value.split("/").at(-1).replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "clawhub-plugin";
23227
- }
23228
-
23229
23292
  // src/targets/plugins/index.ts
23293
+ init_openclaw2();
23230
23294
  async function semanticPluginSpecForArtifact(request) {
23231
23295
  if (request.semantic === "openclaw-plugin") {
23232
23296
  return openClawPluginSpec({
@@ -28570,6 +28634,7 @@ Run without ${lockLabel === "Offline" ? "--offline" : "--frozen-lock"} first.`
28570
28634
  if (!satisfiesVersionRange(fetched.version, requirement.version)) {
28571
28635
  throw new Error(`Package ${fetched.name}@${fetched.version} does not satisfy requested version ${requirement.version}`);
28572
28636
  }
28637
+ const requestedRef = frozen ? frozen.node.requestedRef : fetched.resolved.requestedRef;
28573
28638
  const nodeKey = `${normalized.normalizedSource}\0${fetched.name}`;
28574
28639
  let selectionImport = requirement.selection ? await resolveSelectionImport(fetched.resolved.resolvedPath, fetched.resolved.driver, requirement.selection) : void 0;
28575
28640
  const selected = computeSelectedSelectors(
@@ -28596,7 +28661,7 @@ Run without ${lockLabel === "Offline" ? "--offline" : "--frozen-lock"} first.`
28596
28661
  source: fetched.resolved.source,
28597
28662
  normalizedSource: normalized.normalizedSource,
28598
28663
  driver: fetched.resolved.driver,
28599
- requestedRef: fetched.resolved.requestedRef,
28664
+ requestedRef,
28600
28665
  resolvedCommit: fetched.resolved.resolvedCommit,
28601
28666
  cacheIdentity: fetched.resolved.cacheIdentity,
28602
28667
  sourceHash: fetched.sourceHash,
@@ -28654,7 +28719,7 @@ Run without ${lockLabel === "Offline" ? "--offline" : "--frozen-lock"} first.`
28654
28719
  alias: requirement.alias,
28655
28720
  source: requirement.source,
28656
28721
  normalizedSource: normalized.normalizedSource,
28657
- requestedRef: fetched.resolved.requestedRef,
28722
+ requestedRef,
28658
28723
  version: requirement.version,
28659
28724
  mode: requirement.mode,
28660
28725
  optional: requirement.optional,