@agent-native/skills 0.2.11 → 0.2.13

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
@@ -15,7 +15,8 @@ Usage:
15
15
 
16
16
  Options:
17
17
  --skill <name> Install only this skill (repeatable)
18
- --client, -a <client> codex, claude-code, or all (default: all; repeatable or comma-separated)
18
+ --client, -a <client> codex, claude-code, cowork, pi, cursor, opencode, github-copilot, or all
19
+ (default: all; repeatable or comma-separated)
19
20
  --scope <user|project> Install globally or into the current project (default: user)
20
21
  -g, --global Alias for --scope user
21
22
  --project Alias for --scope project
@@ -32,9 +33,9 @@ Options:
32
33
  --dry-run Print intended writes without changing files
33
34
  --json Print the result as JSON
34
35
 
35
- App-backed skills (visual-plan, visual-recap, assets, design-exploration)
36
- register their hosted MCP server in your agent config by default so the agent
37
- can actually use them. Use --no-mcp to skip that and copy the files only.
36
+ App-backed skills (visual-plan, visual-recap) register their hosted MCP server
37
+ in your agent config by default so the agent can actually use them. Use
38
+ --no-mcp to skip that and copy the files only.
38
39
  For visual-plan/visual-recap, choose --mode local-files for no sharing and all
39
40
  local files, or --mode self-hosted --mcp-url <url> for your own Plan app.
40
41
 
@@ -43,7 +44,15 @@ Examples:
43
44
  npx @agent-native/skills@latest add --skill quick-recap
44
45
  npx @agent-native/skills@latest add --skill visual-recap --with-github-action
45
46
  `;
46
- const CLIENTS = ["codex", "claude-code"];
47
+ const CLIENTS = [
48
+ "codex",
49
+ "claude-code",
50
+ "cowork",
51
+ "pi",
52
+ "cursor",
53
+ "opencode",
54
+ "github-copilot",
55
+ ];
47
56
  const DEFAULT_SKILLS_SOURCE = "BuilderIO/skills";
48
57
  const MANAGED_INSTRUCTIONS_START = "<!-- BEGIN @agent-native/skills -->";
49
58
  const MANAGED_INSTRUCTIONS_END = "<!-- END @agent-native/skills -->";
@@ -110,6 +119,8 @@ export function parseSkillsCliArgs(argv) {
110
119
  out.dryRun = true;
111
120
  else if (arg === "--json")
112
121
  out.printJson = true;
122
+ else if (arg === "--quiet")
123
+ out.quiet = true;
113
124
  else if (arg === "--update-instructions")
114
125
  out.updateInstructions = true;
115
126
  else if (arg === "--no-update-instructions")
@@ -227,6 +238,11 @@ function shouldLoadPublicCatalog(parsed) {
227
238
  return true;
228
239
  return parsed.skillNames.some((name) => !resolveAppForSkill(name));
229
240
  }
241
+ const HIDDEN_STANDALONE_BUILT_INS = [
242
+ "assets",
243
+ "design-exploration",
244
+ "context-xray",
245
+ ];
230
246
  export async function runSkillsCli(argv, options = {}) {
231
247
  const parsed = parseSkillsCliArgs(argv);
232
248
  // `@agent-native/skills` normally uses the exact same core flow as
@@ -255,6 +271,7 @@ export async function runSkillsCli(argv, options = {}) {
255
271
  isInteractive: options.isInteractive,
256
272
  baseDir: parsed.baseDir ?? options.baseDir,
257
273
  catalogMode: "all",
274
+ hiddenBuiltInSkillTargets: HIDDEN_STANDALONE_BUILT_INS,
258
275
  publicSkillSource: loadedSource?.root ?? parsed.source ?? DEFAULT_SKILLS_SOURCE,
259
276
  publicSkillEntries,
260
277
  promptSkills: options.promptSkills
@@ -268,6 +285,8 @@ export async function runSkillsCli(argv, options = {}) {
268
285
  promptGithubAction: options.promptGithubAction
269
286
  ? async (context) => options.promptGithubAction?.({
270
287
  workflowPath: context.workflowPath,
288
+ setupCommand: context.setupCommand,
289
+ docsUrl: context.docsUrl,
271
290
  }) ?? null
272
291
  : undefined,
273
292
  promptPlanMode: options.promptPlanMode,
@@ -333,8 +352,8 @@ export async function runSkillsCli(argv, options = {}) {
333
352
  withGithubAction: parsed.withGithubAction,
334
353
  force: parsed.force,
335
354
  connect: parsed.connect,
336
- quiet: parsed.printJson,
337
- log: parsed.printJson ? undefined : stdoutLog,
355
+ quiet: parsed.printJson || parsed.quiet,
356
+ log: parsed.printJson || parsed.quiet ? undefined : stdoutLog,
338
357
  isInteractive: options.isInteractive,
339
358
  promptSkills: options.promptSkills,
340
359
  promptClients: options.promptClients,
@@ -359,6 +378,8 @@ export async function runSkillsCli(argv, options = {}) {
359
378
  process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
360
379
  return;
361
380
  }
381
+ if (parsed.quiet)
382
+ return;
362
383
  await printInstallResult(result, {
363
384
  baseDir: parsed.baseDir ?? options.baseDir ?? process.cwd(),
364
385
  dryRun: parsed.dryRun,
@@ -426,11 +447,14 @@ export async function installSkills(options) {
426
447
  options.telemetry?.track("skills_cli scope selected", { scope });
427
448
  const instructionBlocks = managedInstructionBlocksForSkills(skillNames);
428
449
  const shouldUpdateInstructions = await shouldUpdateManagedInstructions(instructionBlocks, options);
429
- const shouldWriteGithubAction = selected.some((skill) => skill.name === "visual-recap") &&
430
- shouldWritePrVisualRecapWorkflow(options, baseDir);
450
+ const shouldWriteGithubAction = await shouldWritePrVisualRecapWorkflow(selected.some((skill) => skill.name === "visual-recap"), options, baseDir);
431
451
  const mcpApps = options.mcp === false || planMode === "local-files"
432
452
  ? []
433
453
  : mcpAppsForSkills(skillNames, planMcpOverride);
454
+ const skillFileClients = clients.filter(supportsSkillFiles);
455
+ if (skillFileClients.length === 0 && mcpApps.length === 0) {
456
+ throw new Error("Claude Cowork is MCP-only for Agent Native skills. Choose Codex, Claude Code, Pi, Cursor, OpenCode, or GitHub Copilot for local skill files, or install an app-backed skill with MCP enabled.");
457
+ }
434
458
  const progress = await createInstallProgress(options, 1 +
435
459
  (shouldUpdateInstructions ? 1 : 0) +
436
460
  (shouldWriteGithubAction ? 1 : 0) +
@@ -441,8 +465,7 @@ export async function installSkills(options) {
441
465
  const mcpServers = [];
442
466
  try {
443
467
  progress?.start("Installing skill files...");
444
- for (const client of clients) {
445
- const root = installRootForClient(client, scope, baseDir);
468
+ for (const root of unique(skillFileClients.map((client) => installRootForClient(client, scope, baseDir)))) {
446
469
  for (const skill of selected) {
447
470
  const destination = path.join(root, skill.name);
448
471
  written.push(destination);
@@ -463,7 +486,7 @@ export async function installSkills(options) {
463
486
  });
464
487
  if (shouldUpdateInstructions) {
465
488
  progress?.message("Updating managed instructions...");
466
- instructionFiles = writeManagedInstructions(instructionBlocks, baseDir, clients, scope, options);
489
+ instructionFiles = writeManagedInstructions(instructionBlocks, baseDir, skillFileClients, scope, options);
467
490
  progress?.advance("Managed instructions updated");
468
491
  if (instructionFiles.length) {
469
492
  options.telemetry?.track("skills_cli instructions updated", {
@@ -480,12 +503,17 @@ export async function installSkills(options) {
480
503
  }
481
504
  }
482
505
  // Register the hosted MCP server for app-backed skills (visual-plan /
483
- // visual-recap → Agent-Native Plan, assets, design-exploration) so the
484
- // agent can actually call them — not just read the SKILL.md. On by
485
- // default; `--no-mcp` installs the skill files only. One registration per
486
- // app, so visual-plan + visual-recap share a single "plan" server.
506
+ // visual-recap → Agent-Native Plan) so the agent can actually call them,
507
+ // not just read the SKILL.md. On by default; `--no-mcp` installs the
508
+ // skill files only. One registration per app, so visual-plan +
509
+ // visual-recap share a single "plan" server.
487
510
  if (mcpApps.length > 0) {
488
- const mcpClients = clients.map((client) => client === "claude-code" ? "claude-code" : "codex");
511
+ const mcpClients = clients
512
+ .map(skillClientToMcpClient)
513
+ .filter((client) => Boolean(client));
514
+ if (mcpClients.length === 0) {
515
+ throw new Error("MCP setup supports Claude Code, Codex, Cursor, OpenCode, GitHub Copilot / VS Code, or Claude Cowork. Use --mode local-files or --no-mcp for Pi.");
516
+ }
489
517
  for (const app of mcpApps) {
490
518
  progress?.message(`Registering ${app.displayName} MCP server...`);
491
519
  if (!options.dryRun) {
@@ -574,6 +602,7 @@ function defaultArgs(command) {
574
602
  force: false,
575
603
  connect: true,
576
604
  mcp: true,
605
+ quiet: false,
577
606
  };
578
607
  }
579
608
  function selectedPlanApp(skillNames) {
@@ -651,14 +680,40 @@ function normalizeClients(value) {
651
680
  return CLIENTS;
652
681
  if (client === "codex")
653
682
  return ["codex"];
683
+ if (client === "cowork" || client === "claude-cowork") {
684
+ return ["cowork"];
685
+ }
686
+ if (client === "pi")
687
+ return ["pi"];
688
+ if (client === "cursor")
689
+ return ["cursor"];
690
+ if (client === "opencode" || client === "open-code") {
691
+ return ["opencode"];
692
+ }
693
+ if (client === "github-copilot" ||
694
+ client === "copilot" ||
695
+ client === "vscode" ||
696
+ client === "vs-code") {
697
+ return ["github-copilot"];
698
+ }
654
699
  if (client === "claude" ||
655
700
  client === "claude-code" ||
656
701
  client === "claude-code-cli") {
657
702
  return ["claude-code"];
658
703
  }
659
- throw new Error(`Unsupported client "${raw}". Use codex, claude-code, or all.`);
704
+ throw new Error(`Unsupported client "${raw}". Use codex, claude-code, cowork, pi, cursor, opencode, github-copilot, or all.`);
660
705
  });
661
706
  }
707
+ function skillClientToMcpClient(client) {
708
+ if (client === "pi")
709
+ return null;
710
+ if (client === "claude-code")
711
+ return "claude-code";
712
+ return client;
713
+ }
714
+ function supportsSkillFiles(client) {
715
+ return client !== "cowork";
716
+ }
662
717
  function normalizeSkillName(value) {
663
718
  const normalized = value.trim().toLowerCase();
664
719
  if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
@@ -840,15 +895,24 @@ function isInteractive(options) {
840
895
  function installRootForClient(client, scope, baseDir) {
841
896
  const home = process.env.HOME || os.homedir();
842
897
  if (scope === "project") {
843
- return client === "codex"
844
- ? path.join(baseDir, ".agents", "skills")
845
- : path.join(baseDir, ".claude", "skills");
898
+ if (client !== "claude-code") {
899
+ return path.join(baseDir, ".agents", "skills");
900
+ }
901
+ return path.join(baseDir, ".claude", "skills");
846
902
  }
847
903
  if (client === "codex") {
848
904
  return process.env.CODEX_HOME
849
905
  ? path.join(process.env.CODEX_HOME, "skills")
850
906
  : path.join(home, ".codex", "skills");
851
907
  }
908
+ if (client === "pi") {
909
+ return path.join(home, ".agents", "skills");
910
+ }
911
+ if (client === "cursor" ||
912
+ client === "opencode" ||
913
+ client === "github-copilot") {
914
+ return path.join(home, ".agents", "skills");
915
+ }
852
916
  return path.join(home, ".claude", "skills");
853
917
  }
854
918
  function discoverSkills(root) {
@@ -1055,14 +1119,17 @@ function resolveInstructionFiles(baseDir, explicit, clients, scope) {
1055
1119
  if (explicit && explicit.length > 0) {
1056
1120
  return explicit.map((file) => path.resolve(baseDir, file));
1057
1121
  }
1122
+ const instructionClients = clients.filter(supportsSkillFiles);
1123
+ if (instructionClients.length === 0)
1124
+ return [];
1058
1125
  if (scope === "user") {
1059
1126
  const home = process.env.HOME || os.homedir();
1060
1127
  const files = [];
1061
- if (clients.includes("codex")) {
1128
+ if (instructionClients.includes("codex")) {
1062
1129
  const codexHome = process.env.CODEX_HOME || path.join(home, ".codex");
1063
1130
  files.push(path.join(codexHome, "AGENTS.md"));
1064
1131
  }
1065
- if (clients.includes("claude-code")) {
1132
+ if (instructionClients.includes("claude-code")) {
1066
1133
  files.push(path.join(home, ".claude", "CLAUDE.md"));
1067
1134
  }
1068
1135
  return unique(files);
@@ -1083,13 +1150,44 @@ function upsertManagedBlock(file, block) {
1083
1150
  function escapeRegExp(value) {
1084
1151
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1085
1152
  }
1086
- function shouldWritePrVisualRecapWorkflow(options, baseDir) {
1153
+ const PR_VISUAL_RECAP_DOCS_URL = "https://www.agent-native.com/docs/pr-visual-recap";
1154
+ function prVisualRecapWorkflowPath(baseDir) {
1155
+ return path.join(baseDir, ".github", "workflows", "pr-visual-recap.yml");
1156
+ }
1157
+ function prVisualRecapSetupCommand() {
1158
+ return "npx @agent-native/core@latest recap setup";
1159
+ }
1160
+ async function promptForGithubAction(context) {
1161
+ const clack = await import("@clack/prompts");
1162
+ const result = await clack.confirm({
1163
+ message: "Optional: add automatic PR Visual Recaps? (GitHub Action)\n" +
1164
+ " Posts a human-friendly recap on every pull request.\n" +
1165
+ ` Learn more: ${context.docsUrl}\n` +
1166
+ ` Writes ${context.workflowPath}; ${context.setupCommand} finishes the GitHub secrets.`,
1167
+ initialValue: false,
1168
+ });
1169
+ if (clack.isCancel(result)) {
1170
+ clack.cancel("Skipped PR Visual Recap workflow.");
1171
+ return null;
1172
+ }
1173
+ return Boolean(result);
1174
+ }
1175
+ async function shouldWritePrVisualRecapWorkflow(hasVisualRecap, options, baseDir) {
1176
+ if (!hasVisualRecap)
1177
+ return false;
1087
1178
  if (options.withGithubAction)
1088
1179
  return true;
1089
- if (fs.existsSync(path.join(baseDir, ".github", "workflows", "pr-visual-recap.yml"))) {
1180
+ if (fs.existsSync(prVisualRecapWorkflowPath(baseDir)))
1090
1181
  return false;
1091
- }
1092
- return false;
1182
+ if (options.yes || !isInteractive(options))
1183
+ return false;
1184
+ const prompt = options.promptGithubAction ?? promptForGithubAction;
1185
+ const choice = await prompt({
1186
+ workflowPath: path.join(".github", "workflows", "pr-visual-recap.yml"),
1187
+ setupCommand: prVisualRecapSetupCommand(),
1188
+ docsUrl: PR_VISUAL_RECAP_DOCS_URL,
1189
+ });
1190
+ return choice === true;
1093
1191
  }
1094
1192
  const PR_VISUAL_RECAP_REUSABLE_WORKFLOW = `name: PR Visual Recap
1095
1193