@acta-dev/cli 1.2.0 → 1.4.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 (2) hide show
  1. package/dist/index.js +325 -57
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // src/index.ts
4
4
  import { realpathSync } from "fs";
5
5
  import { fileURLToPath } from "url";
6
- import { defineCommand as defineCommand10, runMain } from "citty";
6
+ import { defineCommand as defineCommand11, runMain } from "citty";
7
7
 
8
8
  // src/commands/build.ts
9
9
  import { buildArtifacts } from "@acta-dev/core";
@@ -222,14 +222,17 @@ var graphCommand = defineCommand2({
222
222
  });
223
223
 
224
224
  // src/commands/init.ts
225
- import { existsSync as existsSync2 } from "fs";
226
- import { mkdir, writeFile } from "fs/promises";
227
- import { join as join2, resolve as resolve2 } from "path";
225
+ import { existsSync as existsSync3 } from "fs";
226
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
227
+ import { join as join3, resolve as resolve2 } from "path";
228
228
  import { createInterface } from "readline";
229
229
  import { resolveConfig as resolveConfig3 } from "@acta-dev/core";
230
230
  import { defineCommand as defineCommand3 } from "citty";
231
231
 
232
232
  // src/skill.ts
233
+ import { existsSync as existsSync2 } from "fs";
234
+ import { mkdir, readFile, writeFile } from "fs/promises";
235
+ import { join as join2 } from "path";
233
236
  import {
234
237
  adrStatuses,
235
238
  documentKinds,
@@ -239,6 +242,7 @@ import {
239
242
  specStatuses
240
243
  } from "@acta-dev/core";
241
244
  var SKILL_NAME = "acta-document";
245
+ var skillFormats = ["codex", "claude", "both"];
242
246
  var LINK_DESCRIPTIONS = {
243
247
  related: "Loosely related documents.",
244
248
  supersedes: "This document supersedes the target; mirror with `replacedBy`.",
@@ -388,6 +392,212 @@ ${block}
388
392
  ` : `${block}
389
393
  `;
390
394
  }
395
+ async function installAgentSkill(cwd, format) {
396
+ const skillPaths = [];
397
+ const skillContent = renderSkill();
398
+ if (format === "codex" || format === "both") {
399
+ const skillDir = join2(cwd, ".agents", "skills", SKILL_NAME);
400
+ await mkdir(skillDir, { recursive: true });
401
+ const skillPath = join2(skillDir, "SKILL.md");
402
+ await writeFile(skillPath, skillContent, "utf8");
403
+ skillPaths.push(skillPath);
404
+ const agentsPath = join2(cwd, "AGENTS.md");
405
+ const existing = existsSync2(agentsPath) ? await readFile(agentsPath, "utf8") : "";
406
+ await writeFile(agentsPath, upsertAgentsBlock(existing), "utf8");
407
+ if (format === "codex") {
408
+ return { skillPaths, agentsPath };
409
+ }
410
+ }
411
+ if (format === "claude" || format === "both") {
412
+ const skillDir = join2(cwd, ".claude", "skills", SKILL_NAME);
413
+ await mkdir(skillDir, { recursive: true });
414
+ const skillPath = join2(skillDir, "SKILL.md");
415
+ await writeFile(skillPath, skillContent, "utf8");
416
+ skillPaths.push(skillPath);
417
+ }
418
+ return format === "both" ? { skillPaths, agentsPath: join2(cwd, "AGENTS.md") } : { skillPaths };
419
+ }
420
+
421
+ // src/commands/deploy-workflows.ts
422
+ var DEPLOY_PROVIDERS = ["pages", "cloudflare", "vercel", "netlify"];
423
+ var DEPLOY_WORKFLOW_TEMPLATES = {
424
+ pages: `name: Deploy Acta Pages
425
+
426
+ on:
427
+ push:
428
+ branches:
429
+ - main
430
+ workflow_dispatch:
431
+
432
+ permissions:
433
+ contents: read
434
+ pages: write
435
+ id-token: write
436
+
437
+ concurrency:
438
+ group: acta-pages
439
+ cancel-in-progress: false
440
+
441
+ jobs:
442
+ build:
443
+ name: Build Acta static viewer
444
+ runs-on: ubuntu-latest
445
+ steps:
446
+ - name: Checkout
447
+ uses: actions/checkout@v4
448
+
449
+ - name: Setup pnpm
450
+ uses: pnpm/action-setup@v4
451
+ with:
452
+ version: 11
453
+
454
+ - name: Setup Node
455
+ uses: actions/setup-node@v4
456
+ with:
457
+ node-version: 22
458
+
459
+ - name: Build Acta site
460
+ run: pnpm dlx @acta-dev/cli site --base "/\${{ github.event.repository.name }}"
461
+
462
+ - name: Configure Pages
463
+ uses: actions/configure-pages@v5
464
+
465
+ - name: Upload Pages artifact
466
+ uses: actions/upload-pages-artifact@v4
467
+ with:
468
+ path: .acta/site
469
+
470
+ deploy:
471
+ name: Deploy to GitHub Pages
472
+ needs: build
473
+ runs-on: ubuntu-latest
474
+ environment:
475
+ name: github-pages
476
+ url: \${{ steps.deployment.outputs.page_url }}
477
+ steps:
478
+ - name: Deploy Pages
479
+ id: deployment
480
+ uses: actions/deploy-pages@v4
481
+ `,
482
+ cloudflare: `name: Deploy Acta to Cloudflare Pages
483
+
484
+ on:
485
+ push:
486
+ branches:
487
+ - main
488
+ workflow_dispatch:
489
+
490
+ permissions:
491
+ contents: read
492
+
493
+ jobs:
494
+ deploy:
495
+ name: Deploy Acta static viewer
496
+ runs-on: ubuntu-latest
497
+ steps:
498
+ - name: Checkout
499
+ uses: actions/checkout@v4
500
+
501
+ - name: Setup pnpm
502
+ uses: pnpm/action-setup@v4
503
+ with:
504
+ version: 11
505
+
506
+ - name: Setup Node
507
+ uses: actions/setup-node@v4
508
+ with:
509
+ node-version: 22
510
+
511
+ - name: Build Acta site
512
+ run: pnpm dlx @acta-dev/cli site
513
+
514
+ - name: Deploy to Cloudflare Pages
515
+ uses: cloudflare/wrangler-action@v3
516
+ with:
517
+ apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
518
+ accountId: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
519
+ command: pages deploy .acta/site --project-name="\${{ vars.CLOUDFLARE_PROJECT_NAME }}"
520
+ `,
521
+ vercel: `name: Deploy Acta to Vercel
522
+
523
+ on:
524
+ push:
525
+ branches:
526
+ - main
527
+ workflow_dispatch:
528
+
529
+ permissions:
530
+ contents: read
531
+
532
+ jobs:
533
+ deploy:
534
+ name: Deploy Acta static viewer
535
+ runs-on: ubuntu-latest
536
+ steps:
537
+ - name: Checkout
538
+ uses: actions/checkout@v4
539
+
540
+ - name: Setup pnpm
541
+ uses: pnpm/action-setup@v4
542
+ with:
543
+ version: 11
544
+
545
+ - name: Setup Node
546
+ uses: actions/setup-node@v4
547
+ with:
548
+ node-version: 22
549
+
550
+ - name: Build Acta site
551
+ run: pnpm dlx @acta-dev/cli site
552
+
553
+ - name: Deploy to Vercel
554
+ run: pnpm dlx vercel .acta/site --prod --yes --token="\${{ secrets.VERCEL_TOKEN }}"
555
+ env:
556
+ VERCEL_ORG_ID: \${{ secrets.VERCEL_ORG_ID }}
557
+ VERCEL_PROJECT_ID: \${{ secrets.VERCEL_PROJECT_ID }}
558
+ `,
559
+ netlify: `name: Deploy Acta to Netlify
560
+
561
+ on:
562
+ push:
563
+ branches:
564
+ - main
565
+ workflow_dispatch:
566
+
567
+ permissions:
568
+ contents: read
569
+
570
+ jobs:
571
+ deploy:
572
+ name: Deploy Acta static viewer
573
+ runs-on: ubuntu-latest
574
+ steps:
575
+ - name: Checkout
576
+ uses: actions/checkout@v4
577
+
578
+ - name: Setup pnpm
579
+ uses: pnpm/action-setup@v4
580
+ with:
581
+ version: 11
582
+
583
+ - name: Setup Node
584
+ uses: actions/setup-node@v4
585
+ with:
586
+ node-version: 22
587
+
588
+ - name: Build Acta site
589
+ run: pnpm dlx @acta-dev/cli site
590
+
591
+ - name: Deploy to Netlify
592
+ run: pnpm dlx netlify-cli deploy --dir=.acta/site --prod
593
+ env:
594
+ NETLIFY_AUTH_TOKEN: \${{ secrets.NETLIFY_AUTH_TOKEN }}
595
+ NETLIFY_SITE_ID: \${{ secrets.NETLIFY_SITE_ID }}
596
+ `
597
+ };
598
+ function isDeployProvider(value) {
599
+ return DEPLOY_PROVIDERS.includes(value);
600
+ }
391
601
 
392
602
  // src/commands/init.ts
393
603
  var ADR_TEMPLATE = `---
@@ -566,7 +776,7 @@ async function confirm(message) {
566
776
  });
567
777
  }
568
778
  async function safeWriteFile(filePath, content, yes) {
569
- if (existsSync2(filePath)) {
779
+ if (existsSync3(filePath)) {
570
780
  if (!yes) {
571
781
  const ok = await confirm(` Overwrite ${filePath}?`);
572
782
  if (!ok) {
@@ -577,7 +787,7 @@ async function safeWriteFile(filePath, content, yes) {
577
787
  printWarn(`Overwriting ${filePath}`);
578
788
  }
579
789
  }
580
- await writeFile(filePath, content, "utf8");
790
+ await writeFile2(filePath, content, "utf8");
581
791
  return true;
582
792
  }
583
793
  var initCommand = defineCommand3({
@@ -602,9 +812,13 @@ var initCommand = defineCommand3({
602
812
  description: "Install GitHub Actions workflow template",
603
813
  default: false
604
814
  },
815
+ deploy: {
816
+ type: "string",
817
+ description: "Install a deploy workflow template: pages, cloudflare, vercel or netlify"
818
+ },
605
819
  skill: {
606
820
  type: "boolean",
607
- description: "Install the acta-document agent skill and AGENTS.md guidance",
821
+ description: "Compatibility alias for `acta skill --init` after scaffolding",
608
822
  default: false
609
823
  },
610
824
  config: {
@@ -616,10 +830,14 @@ var initCommand = defineCommand3({
616
830
  async run({ args }) {
617
831
  const cwd = resolve2(process.cwd());
618
832
  const yes = args.yes;
833
+ const deploy = args.deploy;
834
+ if (deploy !== void 0 && !isDeployProvider(deploy)) {
835
+ return exitUsage(`Expected --deploy to be one of: ${DEPLOY_PROVIDERS.join(", ")}.`);
836
+ }
619
837
  const config = resolveConfig3({}, { rootDir: cwd });
620
838
  printLine("Initializing Acta docs structure...");
621
839
  printLine();
622
- const configPath = join2(cwd, "acta.config.ts");
840
+ const configPath = join3(cwd, "acta.config.ts");
623
841
  const configWritten = await safeWriteFile(configPath, CONFIG_TEMPLATE, yes);
624
842
  if (configWritten) printSuccess(`Created ${configPath}`);
625
843
  const dirs = [
@@ -628,47 +846,55 @@ var initCommand = defineCommand3({
628
846
  config.resolvedDocs.templatesDir
629
847
  ];
630
848
  for (const dir of dirs) {
631
- await mkdir(dir, { recursive: true });
849
+ await mkdir2(dir, { recursive: true });
632
850
  printSuccess(`Created dir ${dir}`);
633
851
  }
634
- const adrTplPath = join2(config.resolvedDocs.templatesDir, "adr.md");
635
- const specTplPath = join2(config.resolvedDocs.templatesDir, "spec.md");
852
+ const adrTplPath = join3(config.resolvedDocs.templatesDir, "adr.md");
853
+ const specTplPath = join3(config.resolvedDocs.templatesDir, "spec.md");
636
854
  const adrWritten = await safeWriteFile(adrTplPath, ADR_TEMPLATE, yes);
637
855
  if (adrWritten) printSuccess(`Created ${adrTplPath}`);
638
856
  const specWritten = await safeWriteFile(specTplPath, SPEC_TEMPLATE, yes);
639
857
  if (specWritten) printSuccess(`Created ${specTplPath}`);
640
- const gitignorePath = join2(cwd, ".gitignore");
641
- if (existsSync2(gitignorePath)) {
642
- const { readFile: readFile3, appendFile } = await import("fs/promises");
643
- const content = await readFile3(gitignorePath, "utf8");
858
+ const gitignorePath = join3(cwd, ".gitignore");
859
+ if (existsSync3(gitignorePath)) {
860
+ const { readFile: readFile4, appendFile } = await import("fs/promises");
861
+ const content = await readFile4(gitignorePath, "utf8");
644
862
  if (!content.includes(".acta/")) {
645
863
  await appendFile(gitignorePath, "\n# Acta build artifacts\n.acta/\n");
646
864
  printSuccess(`Added .acta/ to .gitignore`);
647
865
  }
648
866
  }
649
867
  if (args.hooks) {
650
- const lefthookPath = join2(cwd, "lefthook.yml");
868
+ const lefthookPath = join3(cwd, "lefthook.yml");
651
869
  const lefthookWritten = await safeWriteFile(lefthookPath, LEFTHOOK_TEMPLATE, yes);
652
870
  if (lefthookWritten) printSuccess(`Created ${lefthookPath}`);
653
871
  }
654
872
  if (args["github-action"]) {
655
- const workflowsDir = join2(cwd, ".github", "workflows");
656
- await mkdir(workflowsDir, { recursive: true });
657
- const workflowPath = join2(workflowsDir, "acta-ci.yml");
873
+ const workflowsDir = join3(cwd, ".github", "workflows");
874
+ await mkdir2(workflowsDir, { recursive: true });
875
+ const workflowPath = join3(workflowsDir, "acta-ci.yml");
658
876
  const workflowWritten = await safeWriteFile(workflowPath, GITHUB_ACTION_TEMPLATE, yes);
659
877
  if (workflowWritten) printSuccess(`Created ${workflowPath}`);
660
878
  }
879
+ if (deploy !== void 0) {
880
+ const workflowsDir = join3(cwd, ".github", "workflows");
881
+ await mkdir2(workflowsDir, { recursive: true });
882
+ const workflowPath = join3(workflowsDir, `acta-deploy-${deploy}.yml`);
883
+ const workflowWritten = await safeWriteFile(
884
+ workflowPath,
885
+ DEPLOY_WORKFLOW_TEMPLATES[deploy],
886
+ yes
887
+ );
888
+ if (workflowWritten) printSuccess(`Created ${workflowPath}`);
889
+ }
661
890
  if (args.skill) {
662
- const skillDir = join2(cwd, ".claude", "skills", "acta-document");
663
- await mkdir(skillDir, { recursive: true });
664
- const skillPath = join2(skillDir, "SKILL.md");
665
- const skillWritten = await safeWriteFile(skillPath, renderSkill(), yes);
666
- if (skillWritten) printSuccess(`Created ${skillPath}`);
667
- const { readFile: readFile3 } = await import("fs/promises");
668
- const agentsPath = join2(cwd, "AGENTS.md");
669
- const existing = existsSync2(agentsPath) ? await readFile3(agentsPath, "utf8") : "";
670
- await writeFile(agentsPath, upsertAgentsBlock(existing), "utf8");
671
- printSuccess(`Updated ${agentsPath} with Acta agent guidance`);
891
+ const result = await installAgentSkill(cwd, "both");
892
+ for (const skillPath of result.skillPaths) {
893
+ printSuccess(`Installed ${skillPath}`);
894
+ }
895
+ if (result.agentsPath) {
896
+ printSuccess(`Updated ${result.agentsPath} with Acta agent guidance`);
897
+ }
672
898
  }
673
899
  printLine();
674
900
  printSuccess("Acta initialized. Run `acta validate` to check your documents.");
@@ -782,9 +1008,9 @@ var listCommand = defineCommand4({
782
1008
  });
783
1009
 
784
1010
  // src/commands/new.ts
785
- import { existsSync as existsSync3 } from "fs";
786
- import { writeFile as writeFile2 } from "fs/promises";
787
- import { join as join4, relative } from "path";
1011
+ import { existsSync as existsSync4 } from "fs";
1012
+ import { writeFile as writeFile3 } from "fs/promises";
1013
+ import { join as join5, relative } from "path";
788
1014
  import { adrStatuses as adrStatuses2, specStatuses as specStatuses2 } from "@acta-dev/core";
789
1015
  import { defineCommand as defineCommand5 } from "citty";
790
1016
 
@@ -805,11 +1031,11 @@ function titleToSlug(title) {
805
1031
  }
806
1032
 
807
1033
  // src/template.ts
808
- import { readFile } from "fs/promises";
809
- import { join as join3 } from "path";
1034
+ import { readFile as readFile2 } from "fs/promises";
1035
+ import { join as join4 } from "path";
810
1036
  async function renderTemplate(kind, vars, config) {
811
- const templateFile = join3(config.resolvedDocs.templatesDir, `${kind}.md`);
812
- const raw = await readFile(templateFile, "utf8");
1037
+ const templateFile = join4(config.resolvedDocs.templatesDir, `${kind}.md`);
1038
+ const raw = await readFile2(templateFile, "utf8");
813
1039
  return interpolate(raw, vars);
814
1040
  }
815
1041
  function interpolate(raw, vars) {
@@ -854,8 +1080,8 @@ async function createDocument(kind, title, opts) {
854
1080
  const slug = titleToSlug(title.trim());
855
1081
  const filename = `${id}-${slug}.md`;
856
1082
  const dir = kind === "adr" ? config.resolvedDocs.adrDir : config.resolvedDocs.specDir;
857
- const destPath = join4(dir, filename);
858
- if (existsSync3(destPath)) {
1083
+ const destPath = join5(dir, filename);
1084
+ if (existsSync4(destPath)) {
859
1085
  exitFailure(`File already exists: ${destPath}`);
860
1086
  }
861
1087
  const content = await renderTemplate(
@@ -863,7 +1089,7 @@ async function createDocument(kind, title, opts) {
863
1089
  { id, title: title.trim(), date: nowIsoDateTime(), status, tags: parseTags(opts.tags) },
864
1090
  config
865
1091
  );
866
- await writeFile2(destPath, content, "utf8");
1092
+ await writeFile3(destPath, content, "utf8");
867
1093
  if (opts.json) {
868
1094
  printJson({
869
1095
  id,
@@ -971,8 +1197,8 @@ function parseTags(value) {
971
1197
  }
972
1198
 
973
1199
  // src/commands/renumber.ts
974
- import { readFile as readFile2, rename, writeFile as writeFile3 } from "fs/promises";
975
- import { basename, dirname, join as join5 } from "path";
1200
+ import { readFile as readFile3, rename, writeFile as writeFile4 } from "fs/promises";
1201
+ import { basename, dirname, join as join6 } from "path";
976
1202
  import { internalLinkKeys as internalLinkKeys2, loadProject as loadProject3 } from "@acta-dev/core";
977
1203
  import { defineCommand as defineCommand6 } from "citty";
978
1204
  import kleur4 from "kleur";
@@ -996,7 +1222,7 @@ function buildRenumberPlan(fromId, toId, project) {
996
1222
  const oldFilename = basename(target.file.path);
997
1223
  const oldSlug = oldFilename.replace(`${target.id}-`, "").replace(/\.md$/, "");
998
1224
  const newFilename = `${toId}-${oldSlug}.md`;
999
- const newPath = join5(dirname(target.file.path), newFilename);
1225
+ const newPath = join6(dirname(target.file.path), newFilename);
1000
1226
  const affectedDocs = project.documents.filter((d) => d.id !== target.id).filter((d) => internalLinkKeys2.some((key) => d.links[key].includes(target.id))).map((d) => ({ doc: d, path: d.file.path }));
1001
1227
  return {
1002
1228
  target,
@@ -1007,7 +1233,7 @@ function buildRenumberPlan(fromId, toId, project) {
1007
1233
  };
1008
1234
  }
1009
1235
  async function rewriteDocument(filePath, oldId, newId, isTarget) {
1010
- const raw = await readFile2(filePath, "utf8");
1236
+ const raw = await readFile3(filePath, "utf8");
1011
1237
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
1012
1238
  if (!match) {
1013
1239
  throw new Error(`Cannot parse frontmatter in ${filePath}`);
@@ -1091,11 +1317,11 @@ var renumberCommand = defineCommand6({
1091
1317
  printLine();
1092
1318
  for (const { doc, path } of plan.affectedDocs) {
1093
1319
  const rewritten = await rewriteDocument(path, fromId, toId, false);
1094
- await writeFile3(path, rewritten, "utf8");
1320
+ await writeFile4(path, rewritten, "utf8");
1095
1321
  printSuccess(`Updated links in ${doc.id}`);
1096
1322
  }
1097
1323
  const rewrittenTarget = await rewriteDocument(plan.oldPath, fromId, toId, true);
1098
- await writeFile3(plan.oldPath, rewrittenTarget, "utf8");
1324
+ await writeFile4(plan.oldPath, rewrittenTarget, "utf8");
1099
1325
  await rename(plan.oldPath, plan.newPath);
1100
1326
  printSuccess(`Renamed ${basename(plan.oldPath)} \u2192 ${plan.newFilename}`);
1101
1327
  printLine();
@@ -1221,7 +1447,7 @@ import { createReadStream } from "fs";
1221
1447
  import { stat } from "fs/promises";
1222
1448
  import { createServer } from "http";
1223
1449
  import { createRequire } from "module";
1224
- import { dirname as dirname2, extname, join as join6, relative as relative2, resolve as resolve3, sep } from "path";
1450
+ import { dirname as dirname2, extname, join as join7, relative as relative2, resolve as resolve3, sep } from "path";
1225
1451
  import { buildArtifacts as buildArtifacts2 } from "@acta-dev/core";
1226
1452
  import { defineCommand as defineCommand8 } from "citty";
1227
1453
  import kleur6 from "kleur";
@@ -1388,13 +1614,13 @@ function resolveWebPackageDir() {
1388
1614
  }
1389
1615
  }
1390
1616
  function resolveAstroBin(webDir) {
1391
- const require2 = createRequire(join6(webDir, "package.json"));
1617
+ const require2 = createRequire(join7(webDir, "package.json"));
1392
1618
  try {
1393
1619
  const astroPkgJsonPath = require2.resolve("astro/package.json");
1394
1620
  const astroPkg = require2("astro/package.json");
1395
1621
  const binRel = typeof astroPkg.bin === "string" ? astroPkg.bin : astroPkg.bin?.astro;
1396
1622
  if (!binRel) return void 0;
1397
- return join6(dirname2(astroPkgJsonPath), binRel);
1623
+ return join7(dirname2(astroPkgJsonPath), binRel);
1398
1624
  } catch {
1399
1625
  return void 0;
1400
1626
  }
@@ -1502,7 +1728,7 @@ async function resolveStaticSiteResponse(options) {
1502
1728
  }
1503
1729
  try {
1504
1730
  const fileStat = await stat(filePath);
1505
- const finalPath = fileStat.isDirectory() ? join6(filePath, "index.html") : filePath;
1731
+ const finalPath = fileStat.isDirectory() ? join7(filePath, "index.html") : filePath;
1506
1732
  const finalStat = fileStat.isDirectory() ? await stat(finalPath) : fileStat;
1507
1733
  if (!finalStat.isFile()) {
1508
1734
  return { status: 404, contentType: "text/plain; charset=utf-8", text: "Not Found" };
@@ -1567,13 +1793,54 @@ function isAddressInUse(error) {
1567
1793
  return typeof error === "object" && error !== null && "code" in error && error.code === "EADDRINUSE";
1568
1794
  }
1569
1795
 
1796
+ // src/commands/skill.ts
1797
+ import { resolve as resolve4 } from "path";
1798
+ import { defineCommand as defineCommand9 } from "citty";
1799
+ function parseSkillFormat(value) {
1800
+ const format = value ?? "both";
1801
+ if (!skillFormats.includes(format)) {
1802
+ exitUsage(`Unknown skill format "${format}". Use: codex, claude, both`);
1803
+ }
1804
+ return format;
1805
+ }
1806
+ var skillCommand = defineCommand9({
1807
+ meta: {
1808
+ name: "skill",
1809
+ description: "Install or refresh the bundled acta-document agent skill"
1810
+ },
1811
+ args: {
1812
+ init: {
1813
+ type: "boolean",
1814
+ description: "Install or overwrite the bundled acta-document skill",
1815
+ default: false
1816
+ },
1817
+ format: {
1818
+ type: "string",
1819
+ description: "Skill target format: codex | claude | both (default: both)"
1820
+ }
1821
+ },
1822
+ async run({ args }) {
1823
+ if (!args.init) {
1824
+ exitUsage("Usage: acta skill --init [--format codex|claude|both]");
1825
+ }
1826
+ const cwd = resolve4(process.cwd());
1827
+ const result = await installAgentSkill(cwd, parseSkillFormat(args.format));
1828
+ for (const skillPath of result.skillPaths) {
1829
+ printSuccess(`Installed ${skillPath}`);
1830
+ }
1831
+ if (result.agentsPath) {
1832
+ printSuccess(`Updated ${result.agentsPath} with Acta agent guidance`);
1833
+ }
1834
+ }
1835
+ });
1836
+
1570
1837
  // src/commands/validate.ts
1571
- import { mkdir as mkdir2, writeFile as writeFile4 } from "fs/promises";
1572
- import { join as join7 } from "path";
1838
+ import { mkdir as mkdir3, writeFile as writeFile5 } from "fs/promises";
1839
+ import { join as join8 } from "path";
1573
1840
  import { validateLoadedProject } from "@acta-dev/core";
1574
- import { defineCommand as defineCommand9 } from "citty";
1841
+ import { defineCommand as defineCommand10 } from "citty";
1575
1842
  import kleur7 from "kleur";
1576
- var validateCommand = defineCommand9({
1843
+ var validateCommand = defineCommand10({
1577
1844
  meta: {
1578
1845
  name: "validate",
1579
1846
  description: "Validate frontmatter, IDs, links, sections and repository rules"
@@ -1604,9 +1871,9 @@ var validateCommand = defineCommand9({
1604
1871
  return;
1605
1872
  }
1606
1873
  if (args.ci) {
1607
- await mkdir2(config.resolvedBuild.outDir, { recursive: true });
1608
- const outPath = join7(config.resolvedBuild.outDir, "validation.json");
1609
- await writeFile4(outPath, `${JSON.stringify(result, null, 2)}
1874
+ await mkdir3(config.resolvedBuild.outDir, { recursive: true });
1875
+ const outPath = join8(config.resolvedBuild.outDir, "validation.json");
1876
+ await writeFile5(outPath, `${JSON.stringify(result, null, 2)}
1610
1877
  `, "utf8");
1611
1878
  if (result.errors.length > 0) {
1612
1879
  for (const issue of result.errors) {
@@ -1643,7 +1910,7 @@ var validateCommand = defineCommand9({
1643
1910
  });
1644
1911
 
1645
1912
  // src/index.ts
1646
- var main = defineCommand10({
1913
+ var main = defineCommand11({
1647
1914
  meta: {
1648
1915
  name: "acta",
1649
1916
  version: "0.0.0",
@@ -1658,6 +1925,7 @@ var main = defineCommand10({
1658
1925
  graph: graphCommand,
1659
1926
  build: buildCommand,
1660
1927
  site: siteCommand,
1928
+ skill: skillCommand,
1661
1929
  renumber: renumberCommand
1662
1930
  }
1663
1931
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acta-dev/cli",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Acta CLI — TypeScript-first docs-as-code tooling for ADR and spec documents in Git. Provides the `acta` binary.",
5
5
  "keywords": [
6
6
  "adr",