agentwheel 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +17 -2
  2. package/dist/index.js +176 -68
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -33,10 +33,10 @@ No lock-in. No central gatekeeper. Your packages live in plain git repos, your c
33
33
 
34
34
  ---
35
35
 
36
- > **Status: early (v0.6).** The lifecycle core is real and tested — local/git/skillkit/vercel
36
+ > **Status: early (v0.7).** The lifecycle core is real and tested — local/git/skillkit/vercel
37
37
  > sources, optional registry discovery, plan/sync/update/drift/uninstall, overlays, eject/remember,
38
38
  > profiles, runtime auto-detection, fleet targeting, asset-includes, selective installs,
39
- > update notifications, rich JSON merge, and pluggable adapters.
39
+ > update notifications, full Claude/Codex adapters, rich JSON/TOML merge, and pluggable adapters.
40
40
  > Expect sharp edges.
41
41
 
42
42
  ## What it does
@@ -260,6 +260,20 @@ agentwheel sync ./my-pack --adapter-config ./myco-internal.jsonc
260
260
  Built-in adapters ship for common runtimes; declarative adapters need no code and stay private.
261
261
  Programmatic adapters, for private runtime logic beyond file placement, require explicit `--allow-adapter-code`.
262
262
 
263
+ Built-in runtime targets:
264
+
265
+ | Runtime | Main targets |
266
+ |---|---|
267
+ | **OpenClaw** | `.openclaw/AGENTS.md`, `.openclaw/skills`, `.openclaw/rules`, `.openclaw/commands`, MCP/hooks/settings, semantic plugin planning |
268
+ | **Claude Code** | `.claude/CLAUDE.md`, `.claude/skills`, `.claude/commands`, `.claude/agents`, `.claude/rules`, `.claude/.mcp.json`, `.claude/settings.json` |
269
+ | **Codex CLI** | `.codex/AGENTS.md`, `.codex/skills`, `.codex/commands`, `.codex/agents`, `.codex/rules`, `.codex/config.toml`, `.codex/hooks.json` |
270
+ | **Hermes** | `.hermes/AGENTS.md`, `.hermes/skills`, `.hermes/rules`, `.hermes/commands`, MCP/hooks/settings |
271
+ | **GitHub Copilot** | `.github/copilot-instructions.md`, `.github/instructions`, `.github/prompts` |
272
+
273
+ Claude MCP and hooks/settings are merged as JSON. Codex MCP entries are merged into
274
+ `[mcp_servers]` in `.codex/config.toml` without deleting unrelated user config; hooks use
275
+ `.codex/hooks.json`.
276
+
263
277
  Copilot support is intentionally file-drop only: instructions, rules, and prompt/command files are
264
278
  placed in GitHub-native locations, while raw `SKILL.md` directories stay disabled until there is a
265
279
  clear conversion format.
@@ -272,6 +286,7 @@ clear conversion format.
272
286
  - [x] **v0.4** — runtime auto-detection; no `--target-root` needed for normal use; fleet config with named agents; global + project config merge; `--agent` and `--all`.
273
287
  - [x] **v0.5** — asset-includes compose shared files into skills at install time; executable bits preserved; hashes include composed assets.
274
288
  - [x] **v0.6** — selective installs with `--select`/`--skill`; required artifacts; cached npm update notifier.
289
+ - [x] **v0.7** — full Claude/Codex adapters; Codex TOML MCP merge; subagent enumeration; `--skill` selector fix.
275
290
 
276
291
  ## Design docs
277
292
 
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-N2LZY7LO.js";
9
9
 
10
10
  // src/cli/index.ts
11
- import { mkdir as mkdir8, rm as rm8, writeFile as writeFile5 } from "fs/promises";
11
+ import { mkdir as mkdir9, rm as rm8, writeFile as writeFile6 } from "fs/promises";
12
12
  import { join as join20 } from "path";
13
13
  import { Command } from "commander";
14
14
 
@@ -59,7 +59,7 @@ var targetMappingSchema = z2.object({
59
59
  dest: z2.string().min(1),
60
60
  enabled: z2.boolean().default(true),
61
61
  semantic: z2.enum(["openclaw-plugin"]).optional(),
62
- merge: z2.enum(["json-deep"]).optional()
62
+ merge: z2.enum(["json-deep", "codex-toml-mcp"]).optional()
63
63
  });
64
64
  var adapterSchema = z2.object({
65
65
  name: z2.string().min(1),
@@ -86,8 +86,17 @@ async function loadAdapterConfig(path) {
86
86
  // src/adapters/claude.ts
87
87
  var claudeAdapter = {
88
88
  name: "claude",
89
- displayName: "Claude",
90
- targets: {}
89
+ displayName: "Claude Code",
90
+ targets: {
91
+ instructions: { enabled: true, dest: ".claude/CLAUDE.md" },
92
+ rules: { enabled: true, dest: ".claude/rules" },
93
+ skills: { enabled: true, dest: ".claude/skills" },
94
+ commands: { enabled: true, dest: ".claude/commands" },
95
+ subagents: { enabled: true, dest: ".claude/agents" },
96
+ mcp: { enabled: true, dest: ".claude/.mcp.json", merge: "json-deep" },
97
+ hooks: { enabled: true, dest: ".claude/settings.json", merge: "json-deep" },
98
+ settings: { enabled: true, dest: ".claude/settings.json", merge: "json-deep" }
99
+ }
91
100
  };
92
101
 
93
102
  // src/adapters/copilot.ts
@@ -107,8 +116,17 @@ var copilotAdapter = {
107
116
  // src/adapters/codex.ts
108
117
  var codexAdapter = {
109
118
  name: "codex",
110
- displayName: "Codex",
111
- targets: {}
119
+ displayName: "Codex CLI",
120
+ targets: {
121
+ instructions: { enabled: true, dest: ".codex/AGENTS.md" },
122
+ rules: { enabled: true, dest: ".codex/rules" },
123
+ skills: { enabled: true, dest: ".codex/skills" },
124
+ commands: { enabled: true, dest: ".codex/commands" },
125
+ subagents: { enabled: true, dest: ".codex/agents" },
126
+ mcp: { enabled: true, dest: ".codex/config.toml", merge: "codex-toml-mcp" },
127
+ hooks: { enabled: true, dest: ".codex/hooks.json", merge: "json-deep" },
128
+ settings: { enabled: true, dest: ".codex/settings.json", merge: "json-deep" }
129
+ }
112
130
  };
113
131
 
114
132
  // src/adapters/hermes.ts
@@ -282,7 +300,7 @@ var manifestEntrySchema = z3.object({
282
300
  packageName: z3.string().min(1).optional(),
283
301
  semanticCommand: z3.array(z3.string()).optional(),
284
302
  executed: z3.boolean().optional(),
285
- mergeStrategy: z3.enum(["json-deep"]).optional()
303
+ mergeStrategy: z3.enum(["json-deep", "codex-toml-mcp"]).optional()
286
304
  });
287
305
  var installManifestSchema = z3.object({
288
306
  version: z3.literal(1),
@@ -355,6 +373,94 @@ function normalizeTargetRoot(path) {
355
373
  return resolve3(path);
356
374
  }
357
375
 
376
+ // src/install/toml-merge.ts
377
+ import { mkdir as mkdir2, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
378
+ import { dirname as dirname2 } from "path";
379
+ async function mergeCodexTomlMcp(sourcePath, destPath) {
380
+ const source = JSON.parse(await readFile5(sourcePath, "utf8"));
381
+ const servers = extractMcpServers(source);
382
+ const current = await pathExists(destPath) ? await readFile5(destPath, "utf8") : "";
383
+ const withoutManaged = removeManagedMcpSections(current, Object.keys(servers));
384
+ const merged = appendMcpServers(withoutManaged, servers);
385
+ await mkdir2(dirname2(destPath), { recursive: true });
386
+ await writeFile3(destPath, merged, "utf8");
387
+ }
388
+ function extractMcpServers(source) {
389
+ const raw = isRecord2(source.mcpServers) ? source.mcpServers : source;
390
+ const servers = {};
391
+ for (const [name, value] of Object.entries(raw)) {
392
+ if (!isRecord2(value)) continue;
393
+ servers[name] = value;
394
+ }
395
+ if (Object.keys(servers).length === 0) {
396
+ throw new Error("Codex MCP TOML merge needs a JSON object with mcpServers");
397
+ }
398
+ return servers;
399
+ }
400
+ function removeManagedMcpSections(content, serverNames) {
401
+ if (serverNames.length === 0 || content.trim() === "") return content;
402
+ const names = new Set(serverNames);
403
+ const lines = content.split(/\r?\n/);
404
+ const kept = [];
405
+ let skipping = false;
406
+ for (const line of lines) {
407
+ const section = line.match(/^\s*\[([^\]]+)]\s*$/)?.[1];
408
+ if (section) {
409
+ const match = section.match(/^mcp_servers\.([^.\]]+)(?:\.|$)/);
410
+ skipping = match ? names.has(unquoteTomlKey(match[1] ?? "")) : false;
411
+ }
412
+ if (!skipping) kept.push(line);
413
+ }
414
+ return kept.join("\n").replace(/\n{3,}$/g, "\n\n");
415
+ }
416
+ function appendMcpServers(content, servers) {
417
+ const blocks = Object.entries(servers).sort(([a], [b]) => a.localeCompare(b)).map(([name, server]) => formatMcpServer(name, server));
418
+ const prefix = content.trimEnd();
419
+ return `${prefix ? `${prefix}
420
+
421
+ ` : ""}${blocks.join("\n\n")}
422
+ `;
423
+ }
424
+ function formatMcpServer(name, server) {
425
+ const env = isRecord2(server.env) ? server.env : void 0;
426
+ const lines = [`[mcp_servers.${quoteTomlKey(name)}]`];
427
+ for (const [key, value] of Object.entries(server)) {
428
+ if (key === "env" || value === void 0) continue;
429
+ lines.push(`${quoteTomlKey(key)} = ${formatTomlValue(value)}`);
430
+ }
431
+ if (env && Object.keys(env).length > 0) {
432
+ lines.push("", `[mcp_servers.${quoteTomlKey(name)}.env]`);
433
+ for (const [key, value] of Object.entries(env)) {
434
+ lines.push(`${quoteTomlKey(key)} = ${formatTomlValue(value)}`);
435
+ }
436
+ }
437
+ return lines.join("\n");
438
+ }
439
+ function formatTomlValue(value) {
440
+ if (typeof value === "string") return JSON.stringify(value);
441
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
442
+ if (Array.isArray(value)) return `[${value.map(formatTomlValue).join(", ")}]`;
443
+ if (isRecord2(value)) {
444
+ const entries = Object.entries(value).map(([key, child]) => `${quoteTomlKey(key)} = ${formatTomlValue(child)}`);
445
+ return `{ ${entries.join(", ")} }`;
446
+ }
447
+ return '""';
448
+ }
449
+ function quoteTomlKey(key) {
450
+ return /^[A-Za-z0-9_-]+$/.test(key) ? key : JSON.stringify(key);
451
+ }
452
+ function unquoteTomlKey(key) {
453
+ if (!key.startsWith('"')) return key;
454
+ try {
455
+ return JSON.parse(key);
456
+ } catch {
457
+ return key;
458
+ }
459
+ }
460
+ function isRecord2(value) {
461
+ return typeof value === "object" && value !== null && !Array.isArray(value);
462
+ }
463
+
358
464
  // src/install/apply.ts
359
465
  var execFileAsync = promisify(execFile);
360
466
  async function applyInstallPlan(plan, sourceLock, options = {}) {
@@ -420,6 +526,8 @@ async function applyInstallPlan(plan, sourceLock, options = {}) {
420
526
  }
421
527
  if (operation.mergeStrategy === "json-deep") {
422
528
  await mergeJsonFile(operation.sourcePath, operation.destPath);
529
+ } else if (operation.mergeStrategy === "codex-toml-mcp") {
530
+ await mergeCodexTomlMcp(operation.sourcePath, operation.destPath);
423
531
  } else {
424
532
  await atomicCopy(operation.sourcePath, operation.destPath, operation.kind);
425
533
  }
@@ -445,7 +553,7 @@ async function applyInstallPlan(plan, sourceLock, options = {}) {
445
553
  artifactType: operation.artifactType,
446
554
  artifactName: operation.artifactName,
447
555
  kind: operation.kind,
448
- hash: operation.mergeStrategy === "json-deep" && operation.currentHash ? operation.currentHash : operation.desiredHash,
556
+ hash: operation.mergeStrategy && operation.currentHash ? operation.currentHash : operation.desiredHash,
449
557
  sourceHash: operation.desiredHash,
450
558
  updatedAt: now,
451
559
  channel: operation.channel,
@@ -574,7 +682,7 @@ async function createInstallPlan(bundle, adapter, targetRoot, manifest) {
574
682
  }
575
683
  continue;
576
684
  }
577
- if (op.mergeStrategy === "json-deep") {
685
+ if (op.mergeStrategy) {
578
686
  const existing2 = manifestByPath.get(op.relativeDestPath);
579
687
  const exists2 = await pathExists(op.destPath);
580
688
  if (!exists2) {
@@ -682,7 +790,7 @@ function operationForArtifact(artifact, adapter, targetRoot) {
682
790
  semanticCommand: openClawPluginInstallCommand({ path: sourcePath, dryRun: true })
683
791
  };
684
792
  }
685
- const destPath = artifact.type === "instructions" || artifact.type === "settings" ? join3(targetRoot, target.dest) : join3(targetRoot, target.dest, artifact.name);
793
+ const destPath = artifact.type === "instructions" || artifact.type === "settings" || isFileTarget(target.dest) ? join3(targetRoot, target.dest) : join3(targetRoot, target.dest, artifact.name);
686
794
  return {
687
795
  action: "create",
688
796
  artifactType: artifact.type,
@@ -698,6 +806,9 @@ function operationForArtifact(artifact, adapter, targetRoot) {
698
806
  mergeStrategy: target.merge
699
807
  };
700
808
  }
809
+ function isFileTarget(dest) {
810
+ return /\.(json|jsonc|toml|md)$/i.test(dest);
811
+ }
701
812
  function summarizePlan(plan) {
702
813
  const summary = {
703
814
  create: 0,
@@ -805,13 +916,13 @@ function formatPlan(plan) {
805
916
 
806
917
  // src/source/git.ts
807
918
  import { execFile as execFile2 } from "child_process";
808
- import { mkdir as mkdir2, rm as rm3 } from "fs/promises";
919
+ import { mkdir as mkdir3, rm as rm3 } from "fs/promises";
809
920
  import { homedir } from "os";
810
921
  import { basename as basename2, join as join7, resolve as resolve5 } from "path";
811
922
  import { promisify as promisify2 } from "util";
812
923
 
813
924
  // src/model/package.ts
814
- import { readFile as readFile5 } from "fs/promises";
925
+ import { readFile as readFile6 } from "fs/promises";
815
926
  import { join as join5 } from "path";
816
927
  import { parse as parse2, printParseErrorCode as printParseErrorCode2 } from "jsonc-parser";
817
928
  import { z as z4 } from "zod";
@@ -837,7 +948,7 @@ async function findPackageManifestPath(root) {
837
948
  async function readPackageManifest(root) {
838
949
  const path = await findPackageManifestPath(root);
839
950
  if (!path) return void 0;
840
- const content = await readFile5(path, "utf8");
951
+ const content = await readFile6(path, "utf8");
841
952
  const errors = [];
842
953
  const parsed = parse2(content, errors, { allowTrailingComma: true, disallowComments: false });
843
954
  if (errors.length > 0) {
@@ -939,7 +1050,7 @@ var LocalSourceDriver = class {
939
1050
  }
940
1051
  }
941
1052
  }
942
- for (const type of ["commands", "mcp", "hooks", "settings", "plugins"]) {
1053
+ for (const type of ["commands", "subagents", "mcp", "hooks", "settings", "plugins"]) {
943
1054
  const dir = join6(root, type);
944
1055
  if (!await pathExists(dir)) continue;
945
1056
  artifacts.push(...await listGenericArtifacts(type, dir, type, resolved.packageName));
@@ -995,9 +1106,7 @@ async function listFromManifest(root, packageName) {
995
1106
  if (stats.isDirectory()) {
996
1107
  for (const entry of await sortedDirEntries(full)) {
997
1108
  const child = join6(full, entry.name);
998
- if (provide.type === "skills" && entry.isDirectory()) {
999
- artifacts.push(await artifactForDir(provide.type, entry.name, child, join6(provide.path, entry.name), packageName, provide.assets, provide.required));
1000
- } else if (provide.type === "plugins" && entry.isDirectory()) {
1109
+ if ((provide.type === "skills" || provide.type === "plugins" || provide.type === "subagents") && entry.isDirectory()) {
1001
1110
  artifacts.push(await artifactForDir(provide.type, entry.name, child, join6(provide.path, entry.name), packageName, provide.assets, provide.required));
1002
1111
  } else if (entry.isFile()) {
1003
1112
  const name = provide.type === "rules" && entry.name.endsWith(".md") ? entry.name : entry.name;
@@ -1070,7 +1179,7 @@ var GitSourceDriver = class {
1070
1179
  }
1071
1180
  async fetch(resolved) {
1072
1181
  const parsed = parseGitSource(resolved.source);
1073
- await mkdir2(resolve5(resolved.resolvedPath, ".."), { recursive: true });
1182
+ await mkdir3(resolve5(resolved.resolvedPath, ".."), { recursive: true });
1074
1183
  if (!await pathExists(join7(resolved.resolvedPath, ".git"))) {
1075
1184
  await rm3(resolved.resolvedPath, { recursive: true, force: true });
1076
1185
  await git(["clone", "--no-tags", parsed.url, resolved.resolvedPath]);
@@ -1141,14 +1250,14 @@ async function git(args) {
1141
1250
  }
1142
1251
 
1143
1252
  // src/source/skillkit.ts
1144
- import { cp, mkdir as mkdir3, readFile as readFile6, rm as rm4 } from "fs/promises";
1253
+ import { cp, mkdir as mkdir4, readFile as readFile7, rm as rm4 } from "fs/promises";
1145
1254
  import { homedir as homedir2 } from "os";
1146
- import { basename as basename4, dirname as dirname3, join as join9, resolve as resolve6 } from "path";
1255
+ import { basename as basename4, dirname as dirname4, join as join9, resolve as resolve6 } from "path";
1147
1256
  import * as defaultSkillKit from "@skillkit/core";
1148
1257
 
1149
1258
  // src/source/skill-artifacts.ts
1150
1259
  import { readdir as readdir2, stat as stat3 } from "fs/promises";
1151
- import { basename as basename3, dirname as dirname2, extname as extname2, join as join8 } from "path";
1260
+ import { basename as basename3, dirname as dirname3, extname as extname2, join as join8 } from "path";
1152
1261
  async function artifactsFromSkillPaths(paths, packageName) {
1153
1262
  const artifacts = [];
1154
1263
  const seen = /* @__PURE__ */ new Set();
@@ -1185,7 +1294,7 @@ async function artifactFromSkillPath(item, packageName) {
1185
1294
  };
1186
1295
  }
1187
1296
  if (stats.isFile() && basename3(item.path).toLowerCase() === "skill.md") {
1188
- const dir = dirname2(item.path);
1297
+ const dir = dirname3(item.path);
1189
1298
  const name = sanitizeSkillName(item.name ?? basename3(dir));
1190
1299
  return {
1191
1300
  type: "skills",
@@ -1268,7 +1377,7 @@ var SkillKitSourceDriver = class {
1268
1377
  if (!provider?.clone) {
1269
1378
  throw new Error("SkillKit provider API unavailable or cannot resolve source. Expected @skillkit/core detectProvider().clone().");
1270
1379
  }
1271
- await mkdir3(dirname3(resolved.resolvedPath), { recursive: true });
1380
+ await mkdir4(dirname4(resolved.resolvedPath), { recursive: true });
1272
1381
  const result = await provider.clone(providerSpec, resolved.resolvedPath, {});
1273
1382
  if (!result.success || !result.path) {
1274
1383
  throw new Error(`SkillKit provider failed to fetch ${spec}: ${result.error ?? "unknown error"}`);
@@ -1314,7 +1423,7 @@ var SkillKitSourceDriver = class {
1314
1423
  for (const skill of this.discover(resolved.resolvedPath)) {
1315
1424
  const skillMd = join9(skill.path, "SKILL.md");
1316
1425
  if (await pathExists(skillMd)) {
1317
- this.core.translateSkill(await readFile6(skillMd, "utf8"), "openclaw", { sourceFilename: "SKILL.md" });
1426
+ this.core.translateSkill(await readFile7(skillMd, "utf8"), "openclaw", { sourceFilename: "SKILL.md" });
1318
1427
  }
1319
1428
  }
1320
1429
  return resolved;
@@ -1482,13 +1591,13 @@ function getSourceDriver(name = "local") {
1482
1591
  }
1483
1592
 
1484
1593
  // src/staging/staging.ts
1485
- import { chmod, cp as cp3, mkdir as mkdir5, mkdtemp, readdir as readdir4, stat as stat6 } from "fs/promises";
1486
- import { basename as basename7, dirname as dirname5, join as join12, relative as relative2, resolve as resolve8, sep } from "path";
1594
+ import { chmod, cp as cp3, mkdir as mkdir6, mkdtemp, readdir as readdir4, stat as stat6 } from "fs/promises";
1595
+ import { basename as basename7, dirname as dirname6, join as join12, relative as relative2, resolve as resolve8, sep } from "path";
1487
1596
  import { tmpdir as tmpdir2 } from "os";
1488
1597
 
1489
1598
  // src/staging/customize.ts
1490
- import { cp as cp2, mkdir as mkdir4, readdir as readdir3, readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
1491
- import { dirname as dirname4, join as join11 } from "path";
1599
+ import { cp as cp2, mkdir as mkdir5, readdir as readdir3, readFile as readFile8, writeFile as writeFile4 } from "fs/promises";
1600
+ import { dirname as dirname5, join as join11 } from "path";
1492
1601
  async function applyCustomizations(artifacts, options) {
1493
1602
  let next = [...artifacts];
1494
1603
  next = await applyReplacements(next, options, "override");
@@ -1503,11 +1612,11 @@ async function applyInstructionOverlay(artifacts, options) {
1503
1612
  const index = artifacts.findIndex((artifact2) => artifact2.type === "instructions");
1504
1613
  if (index < 0) return artifacts;
1505
1614
  const artifact = artifacts[index];
1506
- const managed = await readFile7(artifact.stagedPath ?? artifact.sourcePath, "utf8");
1507
- const local = await readFile7(overlayPath, "utf8");
1615
+ const managed = await readFile8(artifact.stagedPath ?? artifact.sourcePath, "utf8");
1616
+ const local = await readFile8(overlayPath, "utf8");
1508
1617
  const composedPath = join11(options.stageRoot, ".agentwheel-composed", "instructions", "AGENTS.md");
1509
- await mkdir4(dirname4(composedPath), { recursive: true });
1510
- await writeFile3(
1618
+ await mkdir5(dirname5(composedPath), { recursive: true });
1619
+ await writeFile4(
1511
1620
  composedPath,
1512
1621
  [
1513
1622
  "<!-- BEGIN agentwheel managed: upstream -->",
@@ -1568,7 +1677,7 @@ async function applyReplacements(artifacts, options, channel) {
1568
1677
  const kind = entry.isDirectory() ? "dir" : "file";
1569
1678
  const existing = byKey.get(`${type}:${entry.name}`);
1570
1679
  const stagedPath = join11(options.stageRoot, ".agentwheel-composed", channel, type, entry.name);
1571
- await mkdir4(dirname4(stagedPath), { recursive: true });
1680
+ await mkdir5(dirname5(stagedPath), { recursive: true });
1572
1681
  await cp2(full, stagedPath, { recursive: kind === "dir", dereference: true });
1573
1682
  byKey.set(`${type}:${entry.name}`, {
1574
1683
  type,
@@ -1640,7 +1749,7 @@ async function stageSource(driver, source, options = {}) {
1640
1749
  const stagedArtifacts = [];
1641
1750
  for (const artifact of artifacts) {
1642
1751
  const stagedPath = join12(root, artifact.relativePath);
1643
- await mkdir5(dirname5(stagedPath), { recursive: true });
1752
+ await mkdir6(dirname6(stagedPath), { recursive: true });
1644
1753
  await cp3(artifact.sourcePath, stagedPath, { recursive: artifact.kind === "dir", dereference: true });
1645
1754
  await composeAssets(artifact, resolved.resolvedPath, stagedPath);
1646
1755
  stagedArtifacts.push({
@@ -1699,7 +1808,7 @@ async function copyAsset(asset, source, dest) {
1699
1808
  const sourceStats = await stat6(source);
1700
1809
  if (sourceStats.isFile()) {
1701
1810
  if (matchesAny(basename7(source), asset.include)) {
1702
- await mkdir5(dest, { recursive: true });
1811
+ await mkdir6(dest, { recursive: true });
1703
1812
  await copyAssetFile(source, join12(dest, basename7(source)), asset);
1704
1813
  }
1705
1814
  return;
@@ -1708,7 +1817,7 @@ async function copyAsset(asset, source, dest) {
1708
1817
  throw new Error(`Asset include source is not a file or directory: ${source}`);
1709
1818
  }
1710
1819
  if (!asset.include?.length) {
1711
- await mkdir5(dirname5(dest), { recursive: true });
1820
+ await mkdir6(dirname6(dest), { recursive: true });
1712
1821
  await cp3(source, dest, { recursive: true, dereference: true });
1713
1822
  if (asset.mode === "copy") await normalizeCopiedModes(dest);
1714
1823
  return;
@@ -1720,7 +1829,7 @@ async function copyAsset(asset, source, dest) {
1720
1829
  }
1721
1830
  }
1722
1831
  async function copyAssetFile(source, dest, asset) {
1723
- await mkdir5(dirname5(dest), { recursive: true });
1832
+ await mkdir6(dirname6(dest), { recursive: true });
1724
1833
  await cp3(source, dest, { dereference: true });
1725
1834
  if (asset.mode === "copy") await chmod(dest, 420);
1726
1835
  }
@@ -1768,9 +1877,9 @@ function matchesGlob(path, pattern) {
1768
1877
  }
1769
1878
 
1770
1879
  // src/model/workspace.ts
1771
- import { readFile as readFile8 } from "fs/promises";
1880
+ import { readFile as readFile9 } from "fs/promises";
1772
1881
  import { homedir as homedir3 } from "os";
1773
- import { dirname as dirname6, join as join13, resolve as resolve9 } from "path";
1882
+ import { dirname as dirname7, join as join13, resolve as resolve9 } from "path";
1774
1883
  import { z as z5 } from "zod";
1775
1884
  var workspacePackageSchema = z5.object({
1776
1885
  name: z5.string().min(1),
@@ -1817,7 +1926,7 @@ function workspaceConfigPath(workspaceRoot) {
1817
1926
  async function readWorkspaceConfig(workspaceRoot) {
1818
1927
  const path = workspaceConfigPath(workspaceRoot);
1819
1928
  if (!await pathExists(path)) return emptyWorkspaceConfig();
1820
- return workspaceConfigSchema.parse(JSON.parse(await readFile8(path, "utf8")));
1929
+ return workspaceConfigSchema.parse(JSON.parse(await readFile9(path, "utf8")));
1821
1930
  }
1822
1931
  async function writeWorkspaceConfig(workspaceRoot, config) {
1823
1932
  await writeJsonAtomic(workspaceConfigPath(workspaceRoot), workspaceConfigSchema.parse(config));
@@ -1835,7 +1944,7 @@ async function findWorkspaceRoot(start = process.cwd()) {
1835
1944
  let current = resolve9(start);
1836
1945
  while (true) {
1837
1946
  if (await pathExists(workspaceConfigPath(current))) return current;
1838
- const parent = dirname6(current);
1947
+ const parent = dirname7(current);
1839
1948
  if (parent === current) return resolve9(start);
1840
1949
  current = parent;
1841
1950
  }
@@ -1869,15 +1978,15 @@ function emptyWorkspaceConfig() {
1869
1978
  }
1870
1979
  async function readConfigPath(path) {
1871
1980
  if (!await pathExists(path)) return emptyWorkspaceConfig();
1872
- return workspaceConfigSchema.parse(JSON.parse(await readFile8(path, "utf8")));
1981
+ return workspaceConfigSchema.parse(JSON.parse(await readFile9(path, "utf8")));
1873
1982
  }
1874
1983
 
1875
1984
  // src/lifecycle/customization.ts
1876
- import { appendFile, cp as cp4, mkdir as mkdir6, rm as rm5 } from "fs/promises";
1877
- import { dirname as dirname7, join as join14 } from "path";
1985
+ import { appendFile, cp as cp4, mkdir as mkdir7, rm as rm5 } from "fs/promises";
1986
+ import { dirname as dirname8, join as join14 } from "path";
1878
1987
  async function remember(workspaceRoot, runtime, text) {
1879
1988
  const overlayPath = join14(workspaceRoot, ".agentwheel", "overlays", runtime, "instructions.local.md");
1880
- await mkdir6(dirname7(overlayPath), { recursive: true });
1989
+ await mkdir7(dirname8(overlayPath), { recursive: true });
1881
1990
  await appendFile(overlayPath, `${text.trim()}
1882
1991
  `, "utf8");
1883
1992
  return { overlayPath };
@@ -1902,7 +2011,7 @@ async function ejectArtifact(workspaceRoot, item) {
1902
2011
  throw new Error(`Artifact not found: ${item}`);
1903
2012
  }
1904
2013
  const ejectedPath = join14(workspaceRoot, ".agentwheel", "ejected", ...parsed.packageName.split("/"), parsed.type, parsed.name);
1905
- await mkdir6(dirname7(ejectedPath), { recursive: true });
2014
+ await mkdir7(dirname8(ejectedPath), { recursive: true });
1906
2015
  await rm5(ejectedPath, { recursive: true, force: true });
1907
2016
  await cp4(artifact.stagedPath ?? artifact.sourcePath, ejectedPath, { recursive: artifact.kind === "dir", dereference: true });
1908
2017
  return { ...parsed, ejectedPath };
@@ -1926,9 +2035,9 @@ import { rm as rm7 } from "fs/promises";
1926
2035
  import { join as join16 } from "path";
1927
2036
 
1928
2037
  // src/registry/client.ts
1929
- import { readFile as readFile9, rm as rm6, stat as stat7 } from "fs/promises";
2038
+ import { readFile as readFile10, rm as rm6, stat as stat7 } from "fs/promises";
1930
2039
  import { homedir as homedir4 } from "os";
1931
- import { dirname as dirname8, join as join15, resolve as resolve10 } from "path";
2040
+ import { dirname as dirname9, join as join15, resolve as resolve10 } from "path";
1932
2041
  import { fileURLToPath } from "url";
1933
2042
 
1934
2043
  // src/model/registry.ts
@@ -2014,7 +2123,7 @@ var RegistryClient = class {
2014
2123
  }
2015
2124
  async readCache() {
2016
2125
  if (!await pathExists(this.cachePath)) return void 0;
2017
- return registryCacheSchema.parse(JSON.parse(await readFile9(this.cachePath, "utf8")));
2126
+ return registryCacheSchema.parse(JSON.parse(await readFile10(this.cachePath, "utf8")));
2018
2127
  }
2019
2128
  isExpired(cache, ttlMs) {
2020
2129
  return this.now().getTime() - new Date(cache.fetchedAt).getTime() > ttlMs;
@@ -2033,10 +2142,10 @@ var RegistryClient = class {
2033
2142
  if (await pathExists(filePath)) {
2034
2143
  const fullPath = resolve10(filePath);
2035
2144
  const stats = await stat7(fullPath);
2036
- return readFile9(stats.isDirectory() ? join15(fullPath, "index.json") : fullPath, "utf8");
2145
+ return readFile10(stats.isDirectory() ? join15(fullPath, "index.json") : fullPath, "utf8");
2037
2146
  }
2038
- const resolved = await this.git.fetch(await this.git.resolve(source, { cacheRoot: join15(dirname8(this.cachePath), "registry-repos") }));
2039
- return readFile9(join15(resolved.resolvedPath, "index.json"), "utf8");
2147
+ const resolved = await this.git.fetch(await this.git.resolve(source, { cacheRoot: join15(dirname9(this.cachePath), "registry-repos") }));
2148
+ return readFile10(join15(resolved.resolvedPath, "index.json"), "utf8");
2040
2149
  }
2041
2150
  };
2042
2151
  async function resolvePackageSource(source, workspaceRoot) {
@@ -2172,7 +2281,7 @@ function shouldUpdatePackage(pkg, lock) {
2172
2281
  }
2173
2282
 
2174
2283
  // src/runtime/target.ts
2175
- import { basename as basename8, dirname as dirname9, join as join18, resolve as resolve11 } from "path";
2284
+ import { basename as basename8, dirname as dirname10, join as join18, resolve as resolve11 } from "path";
2176
2285
  var runtimeMarkers = [
2177
2286
  { adapter: "openclaw", dirs: [".openclaw", ".clawdbot", ".moltbot"] },
2178
2287
  { adapter: "claude", dirs: [".claude"] },
@@ -2226,7 +2335,7 @@ async function detectRuntimeTarget(cwd = process.cwd(), adapterFilter) {
2226
2335
  if (adapterFilter && marker.adapter !== adapterFilter) continue;
2227
2336
  for (const dir of marker.dirs) {
2228
2337
  if (basename8(root) === dir) {
2229
- matches.push({ adapter: marker.adapter, targetRoot: dirname9(root) });
2338
+ matches.push({ adapter: marker.adapter, targetRoot: dirname10(root) });
2230
2339
  } else if (await pathExists(join18(root, dir))) {
2231
2340
  matches.push({ adapter: marker.adapter, targetRoot: root });
2232
2341
  }
@@ -2260,9 +2369,9 @@ function dedupeTargets(matches) {
2260
2369
  }
2261
2370
 
2262
2371
  // src/cli/update-check.ts
2263
- import { mkdir as mkdir7, readFile as readFile10, writeFile as writeFile4 } from "fs/promises";
2372
+ import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile5 } from "fs/promises";
2264
2373
  import { homedir as homedir5 } from "os";
2265
- import { dirname as dirname10, join as join19 } from "path";
2374
+ import { dirname as dirname11, join as join19 } from "path";
2266
2375
  var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
2267
2376
  var DEFAULT_TIMEOUT_MS = 300;
2268
2377
  var REGISTRY_URL = "https://registry.npmjs.org/agentwheel";
@@ -2306,7 +2415,7 @@ async function fetchLatestVersion(fetchImpl, timeoutMs) {
2306
2415
  }
2307
2416
  async function readCache(path) {
2308
2417
  try {
2309
- const parsed = JSON.parse(await readFile10(path, "utf8"));
2418
+ const parsed = JSON.parse(await readFile11(path, "utf8"));
2310
2419
  if (typeof parsed.checkedAt !== "string" || typeof parsed.latest !== "string") return void 0;
2311
2420
  return { checkedAt: parsed.checkedAt, latest: parsed.latest };
2312
2421
  } catch {
@@ -2314,8 +2423,8 @@ async function readCache(path) {
2314
2423
  }
2315
2424
  }
2316
2425
  async function writeCache(path, cache) {
2317
- await mkdir7(dirname10(path), { recursive: true });
2318
- await writeFile4(path, `${JSON.stringify(cache, null, 2)}
2426
+ await mkdir8(dirname11(path), { recursive: true });
2427
+ await writeFile5(path, `${JSON.stringify(cache, null, 2)}
2319
2428
  `, "utf8");
2320
2429
  }
2321
2430
  function warnIfNewer(latest, current, stderr = process.stderr) {
@@ -2338,7 +2447,7 @@ function normalizeVersion(version) {
2338
2447
 
2339
2448
  // src/cli/index.ts
2340
2449
  var program = new Command();
2341
- program.name("agentwheel").description("Multi-runtime agent artifact orchestrator").version("0.6.0").option("--no-update-check", "disable npm version update check", false);
2450
+ program.name("agentwheel").description("Multi-runtime agent artifact orchestrator").version("0.7.0").option("--no-update-check", "disable npm version update check", false);
2342
2451
  program.command("init").argument("[kind]", "workspace or package", "workspace").option("--target-root <path>", "workspace root", process.cwd()).action(async (kind, options) => {
2343
2452
  const root = normalizeTargetRoot(options.targetRoot);
2344
2453
  if (kind === "package") {
@@ -2528,8 +2637,7 @@ async function buildPlan(source, target, options) {
2528
2637
  adapter,
2529
2638
  driver: options.driver,
2530
2639
  mode: options.mode,
2531
- select: options.select ?? selectedArtifactsFromOptions(options),
2532
- skills: options.skills
2640
+ select: selectedArtifactsFromOptions(options)
2533
2641
  });
2534
2642
  return { plan: result.plan, bundle: result.bundle };
2535
2643
  }
@@ -2624,9 +2732,9 @@ function filterUninstallPlanBySelection(plan, selected) {
2624
2732
  };
2625
2733
  }
2626
2734
  async function initPackage(root) {
2627
- await mkdir8(join20(root, "instructions"), { recursive: true });
2628
- await mkdir8(join20(root, "rules"), { recursive: true });
2629
- await mkdir8(join20(root, "skills"), { recursive: true });
2735
+ await mkdir9(join20(root, "instructions"), { recursive: true });
2736
+ await mkdir9(join20(root, "rules"), { recursive: true });
2737
+ await mkdir9(join20(root, "skills"), { recursive: true });
2630
2738
  const manifestPath = join20(root, "agentwheel.json");
2631
2739
  const manifest = {
2632
2740
  schemaVersion: 1,
@@ -2638,9 +2746,9 @@ async function initPackage(root) {
2638
2746
  { type: "skills", path: "skills" }
2639
2747
  ]
2640
2748
  };
2641
- await writeFile5(manifestPath, `${JSON.stringify(manifest, null, 2)}
2749
+ await writeFile6(manifestPath, `${JSON.stringify(manifest, null, 2)}
2642
2750
  `, "utf8");
2643
- await writeFile5(join20(root, "instructions", "AGENTS.md"), "# Agent Instructions\n", "utf8");
2751
+ await writeFile6(join20(root, "instructions", "AGENTS.md"), "# Agent Instructions\n", "utf8");
2644
2752
  }
2645
2753
  function formatUninstallResult(result) {
2646
2754
  const removedLabel = result.removed === 1 ? "managed file" : "managed files";
@@ -2660,7 +2768,7 @@ function printRegistryEntries(entries) {
2660
2768
  }
2661
2769
  async function main() {
2662
2770
  await maybeCheckForUpdate({
2663
- currentVersion: "0.6.0",
2771
+ currentVersion: "0.7.0",
2664
2772
  argv: process.argv,
2665
2773
  env: process.env,
2666
2774
  isTTY: process.stderr.isTTY === true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentwheel",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Weave skills, rules, and instructions across every AI agent.",
5
5
  "type": "module",
6
6
  "license": "MIT",