@acta-dev/cli 1.2.0 → 1.3.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 +125 -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,31 @@ ${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
+ }
391
420
 
392
421
  // src/commands/init.ts
393
422
  var ADR_TEMPLATE = `---
@@ -566,7 +595,7 @@ async function confirm(message) {
566
595
  });
567
596
  }
568
597
  async function safeWriteFile(filePath, content, yes) {
569
- if (existsSync2(filePath)) {
598
+ if (existsSync3(filePath)) {
570
599
  if (!yes) {
571
600
  const ok = await confirm(` Overwrite ${filePath}?`);
572
601
  if (!ok) {
@@ -577,7 +606,7 @@ async function safeWriteFile(filePath, content, yes) {
577
606
  printWarn(`Overwriting ${filePath}`);
578
607
  }
579
608
  }
580
- await writeFile(filePath, content, "utf8");
609
+ await writeFile2(filePath, content, "utf8");
581
610
  return true;
582
611
  }
583
612
  var initCommand = defineCommand3({
@@ -604,7 +633,7 @@ var initCommand = defineCommand3({
604
633
  },
605
634
  skill: {
606
635
  type: "boolean",
607
- description: "Install the acta-document agent skill and AGENTS.md guidance",
636
+ description: "Compatibility alias for `acta skill --init` after scaffolding",
608
637
  default: false
609
638
  },
610
639
  config: {
@@ -619,7 +648,7 @@ var initCommand = defineCommand3({
619
648
  const config = resolveConfig3({}, { rootDir: cwd });
620
649
  printLine("Initializing Acta docs structure...");
621
650
  printLine();
622
- const configPath = join2(cwd, "acta.config.ts");
651
+ const configPath = join3(cwd, "acta.config.ts");
623
652
  const configWritten = await safeWriteFile(configPath, CONFIG_TEMPLATE, yes);
624
653
  if (configWritten) printSuccess(`Created ${configPath}`);
625
654
  const dirs = [
@@ -628,47 +657,44 @@ var initCommand = defineCommand3({
628
657
  config.resolvedDocs.templatesDir
629
658
  ];
630
659
  for (const dir of dirs) {
631
- await mkdir(dir, { recursive: true });
660
+ await mkdir2(dir, { recursive: true });
632
661
  printSuccess(`Created dir ${dir}`);
633
662
  }
634
- const adrTplPath = join2(config.resolvedDocs.templatesDir, "adr.md");
635
- const specTplPath = join2(config.resolvedDocs.templatesDir, "spec.md");
663
+ const adrTplPath = join3(config.resolvedDocs.templatesDir, "adr.md");
664
+ const specTplPath = join3(config.resolvedDocs.templatesDir, "spec.md");
636
665
  const adrWritten = await safeWriteFile(adrTplPath, ADR_TEMPLATE, yes);
637
666
  if (adrWritten) printSuccess(`Created ${adrTplPath}`);
638
667
  const specWritten = await safeWriteFile(specTplPath, SPEC_TEMPLATE, yes);
639
668
  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");
669
+ const gitignorePath = join3(cwd, ".gitignore");
670
+ if (existsSync3(gitignorePath)) {
671
+ const { readFile: readFile4, appendFile } = await import("fs/promises");
672
+ const content = await readFile4(gitignorePath, "utf8");
644
673
  if (!content.includes(".acta/")) {
645
674
  await appendFile(gitignorePath, "\n# Acta build artifacts\n.acta/\n");
646
675
  printSuccess(`Added .acta/ to .gitignore`);
647
676
  }
648
677
  }
649
678
  if (args.hooks) {
650
- const lefthookPath = join2(cwd, "lefthook.yml");
679
+ const lefthookPath = join3(cwd, "lefthook.yml");
651
680
  const lefthookWritten = await safeWriteFile(lefthookPath, LEFTHOOK_TEMPLATE, yes);
652
681
  if (lefthookWritten) printSuccess(`Created ${lefthookPath}`);
653
682
  }
654
683
  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");
684
+ const workflowsDir = join3(cwd, ".github", "workflows");
685
+ await mkdir2(workflowsDir, { recursive: true });
686
+ const workflowPath = join3(workflowsDir, "acta-ci.yml");
658
687
  const workflowWritten = await safeWriteFile(workflowPath, GITHUB_ACTION_TEMPLATE, yes);
659
688
  if (workflowWritten) printSuccess(`Created ${workflowPath}`);
660
689
  }
661
690
  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`);
691
+ const result = await installAgentSkill(cwd, "both");
692
+ for (const skillPath of result.skillPaths) {
693
+ printSuccess(`Installed ${skillPath}`);
694
+ }
695
+ if (result.agentsPath) {
696
+ printSuccess(`Updated ${result.agentsPath} with Acta agent guidance`);
697
+ }
672
698
  }
673
699
  printLine();
674
700
  printSuccess("Acta initialized. Run `acta validate` to check your documents.");
@@ -782,9 +808,9 @@ var listCommand = defineCommand4({
782
808
  });
783
809
 
784
810
  // 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";
811
+ import { existsSync as existsSync4 } from "fs";
812
+ import { writeFile as writeFile3 } from "fs/promises";
813
+ import { join as join5, relative } from "path";
788
814
  import { adrStatuses as adrStatuses2, specStatuses as specStatuses2 } from "@acta-dev/core";
789
815
  import { defineCommand as defineCommand5 } from "citty";
790
816
 
@@ -805,11 +831,11 @@ function titleToSlug(title) {
805
831
  }
806
832
 
807
833
  // src/template.ts
808
- import { readFile } from "fs/promises";
809
- import { join as join3 } from "path";
834
+ import { readFile as readFile2 } from "fs/promises";
835
+ import { join as join4 } from "path";
810
836
  async function renderTemplate(kind, vars, config) {
811
- const templateFile = join3(config.resolvedDocs.templatesDir, `${kind}.md`);
812
- const raw = await readFile(templateFile, "utf8");
837
+ const templateFile = join4(config.resolvedDocs.templatesDir, `${kind}.md`);
838
+ const raw = await readFile2(templateFile, "utf8");
813
839
  return interpolate(raw, vars);
814
840
  }
815
841
  function interpolate(raw, vars) {
@@ -854,8 +880,8 @@ async function createDocument(kind, title, opts) {
854
880
  const slug = titleToSlug(title.trim());
855
881
  const filename = `${id}-${slug}.md`;
856
882
  const dir = kind === "adr" ? config.resolvedDocs.adrDir : config.resolvedDocs.specDir;
857
- const destPath = join4(dir, filename);
858
- if (existsSync3(destPath)) {
883
+ const destPath = join5(dir, filename);
884
+ if (existsSync4(destPath)) {
859
885
  exitFailure(`File already exists: ${destPath}`);
860
886
  }
861
887
  const content = await renderTemplate(
@@ -863,7 +889,7 @@ async function createDocument(kind, title, opts) {
863
889
  { id, title: title.trim(), date: nowIsoDateTime(), status, tags: parseTags(opts.tags) },
864
890
  config
865
891
  );
866
- await writeFile2(destPath, content, "utf8");
892
+ await writeFile3(destPath, content, "utf8");
867
893
  if (opts.json) {
868
894
  printJson({
869
895
  id,
@@ -971,8 +997,8 @@ function parseTags(value) {
971
997
  }
972
998
 
973
999
  // 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";
1000
+ import { readFile as readFile3, rename, writeFile as writeFile4 } from "fs/promises";
1001
+ import { basename, dirname, join as join6 } from "path";
976
1002
  import { internalLinkKeys as internalLinkKeys2, loadProject as loadProject3 } from "@acta-dev/core";
977
1003
  import { defineCommand as defineCommand6 } from "citty";
978
1004
  import kleur4 from "kleur";
@@ -996,7 +1022,7 @@ function buildRenumberPlan(fromId, toId, project) {
996
1022
  const oldFilename = basename(target.file.path);
997
1023
  const oldSlug = oldFilename.replace(`${target.id}-`, "").replace(/\.md$/, "");
998
1024
  const newFilename = `${toId}-${oldSlug}.md`;
999
- const newPath = join5(dirname(target.file.path), newFilename);
1025
+ const newPath = join6(dirname(target.file.path), newFilename);
1000
1026
  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
1027
  return {
1002
1028
  target,
@@ -1007,7 +1033,7 @@ function buildRenumberPlan(fromId, toId, project) {
1007
1033
  };
1008
1034
  }
1009
1035
  async function rewriteDocument(filePath, oldId, newId, isTarget) {
1010
- const raw = await readFile2(filePath, "utf8");
1036
+ const raw = await readFile3(filePath, "utf8");
1011
1037
  const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
1012
1038
  if (!match) {
1013
1039
  throw new Error(`Cannot parse frontmatter in ${filePath}`);
@@ -1091,11 +1117,11 @@ var renumberCommand = defineCommand6({
1091
1117
  printLine();
1092
1118
  for (const { doc, path } of plan.affectedDocs) {
1093
1119
  const rewritten = await rewriteDocument(path, fromId, toId, false);
1094
- await writeFile3(path, rewritten, "utf8");
1120
+ await writeFile4(path, rewritten, "utf8");
1095
1121
  printSuccess(`Updated links in ${doc.id}`);
1096
1122
  }
1097
1123
  const rewrittenTarget = await rewriteDocument(plan.oldPath, fromId, toId, true);
1098
- await writeFile3(plan.oldPath, rewrittenTarget, "utf8");
1124
+ await writeFile4(plan.oldPath, rewrittenTarget, "utf8");
1099
1125
  await rename(plan.oldPath, plan.newPath);
1100
1126
  printSuccess(`Renamed ${basename(plan.oldPath)} \u2192 ${plan.newFilename}`);
1101
1127
  printLine();
@@ -1221,7 +1247,7 @@ import { createReadStream } from "fs";
1221
1247
  import { stat } from "fs/promises";
1222
1248
  import { createServer } from "http";
1223
1249
  import { createRequire } from "module";
1224
- import { dirname as dirname2, extname, join as join6, relative as relative2, resolve as resolve3, sep } from "path";
1250
+ import { dirname as dirname2, extname, join as join7, relative as relative2, resolve as resolve3, sep } from "path";
1225
1251
  import { buildArtifacts as buildArtifacts2 } from "@acta-dev/core";
1226
1252
  import { defineCommand as defineCommand8 } from "citty";
1227
1253
  import kleur6 from "kleur";
@@ -1388,13 +1414,13 @@ function resolveWebPackageDir() {
1388
1414
  }
1389
1415
  }
1390
1416
  function resolveAstroBin(webDir) {
1391
- const require2 = createRequire(join6(webDir, "package.json"));
1417
+ const require2 = createRequire(join7(webDir, "package.json"));
1392
1418
  try {
1393
1419
  const astroPkgJsonPath = require2.resolve("astro/package.json");
1394
1420
  const astroPkg = require2("astro/package.json");
1395
1421
  const binRel = typeof astroPkg.bin === "string" ? astroPkg.bin : astroPkg.bin?.astro;
1396
1422
  if (!binRel) return void 0;
1397
- return join6(dirname2(astroPkgJsonPath), binRel);
1423
+ return join7(dirname2(astroPkgJsonPath), binRel);
1398
1424
  } catch {
1399
1425
  return void 0;
1400
1426
  }
@@ -1502,7 +1528,7 @@ async function resolveStaticSiteResponse(options) {
1502
1528
  }
1503
1529
  try {
1504
1530
  const fileStat = await stat(filePath);
1505
- const finalPath = fileStat.isDirectory() ? join6(filePath, "index.html") : filePath;
1531
+ const finalPath = fileStat.isDirectory() ? join7(filePath, "index.html") : filePath;
1506
1532
  const finalStat = fileStat.isDirectory() ? await stat(finalPath) : fileStat;
1507
1533
  if (!finalStat.isFile()) {
1508
1534
  return { status: 404, contentType: "text/plain; charset=utf-8", text: "Not Found" };
@@ -1567,13 +1593,54 @@ function isAddressInUse(error) {
1567
1593
  return typeof error === "object" && error !== null && "code" in error && error.code === "EADDRINUSE";
1568
1594
  }
1569
1595
 
1596
+ // src/commands/skill.ts
1597
+ import { resolve as resolve4 } from "path";
1598
+ import { defineCommand as defineCommand9 } from "citty";
1599
+ function parseSkillFormat(value) {
1600
+ const format = value ?? "both";
1601
+ if (!skillFormats.includes(format)) {
1602
+ exitUsage(`Unknown skill format "${format}". Use: codex, claude, both`);
1603
+ }
1604
+ return format;
1605
+ }
1606
+ var skillCommand = defineCommand9({
1607
+ meta: {
1608
+ name: "skill",
1609
+ description: "Install or refresh the bundled acta-document agent skill"
1610
+ },
1611
+ args: {
1612
+ init: {
1613
+ type: "boolean",
1614
+ description: "Install or overwrite the bundled acta-document skill",
1615
+ default: false
1616
+ },
1617
+ format: {
1618
+ type: "string",
1619
+ description: "Skill target format: codex | claude | both (default: both)"
1620
+ }
1621
+ },
1622
+ async run({ args }) {
1623
+ if (!args.init) {
1624
+ exitUsage("Usage: acta skill --init [--format codex|claude|both]");
1625
+ }
1626
+ const cwd = resolve4(process.cwd());
1627
+ const result = await installAgentSkill(cwd, parseSkillFormat(args.format));
1628
+ for (const skillPath of result.skillPaths) {
1629
+ printSuccess(`Installed ${skillPath}`);
1630
+ }
1631
+ if (result.agentsPath) {
1632
+ printSuccess(`Updated ${result.agentsPath} with Acta agent guidance`);
1633
+ }
1634
+ }
1635
+ });
1636
+
1570
1637
  // src/commands/validate.ts
1571
- import { mkdir as mkdir2, writeFile as writeFile4 } from "fs/promises";
1572
- import { join as join7 } from "path";
1638
+ import { mkdir as mkdir3, writeFile as writeFile5 } from "fs/promises";
1639
+ import { join as join8 } from "path";
1573
1640
  import { validateLoadedProject } from "@acta-dev/core";
1574
- import { defineCommand as defineCommand9 } from "citty";
1641
+ import { defineCommand as defineCommand10 } from "citty";
1575
1642
  import kleur7 from "kleur";
1576
- var validateCommand = defineCommand9({
1643
+ var validateCommand = defineCommand10({
1577
1644
  meta: {
1578
1645
  name: "validate",
1579
1646
  description: "Validate frontmatter, IDs, links, sections and repository rules"
@@ -1604,9 +1671,9 @@ var validateCommand = defineCommand9({
1604
1671
  return;
1605
1672
  }
1606
1673
  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)}
1674
+ await mkdir3(config.resolvedBuild.outDir, { recursive: true });
1675
+ const outPath = join8(config.resolvedBuild.outDir, "validation.json");
1676
+ await writeFile5(outPath, `${JSON.stringify(result, null, 2)}
1610
1677
  `, "utf8");
1611
1678
  if (result.errors.length > 0) {
1612
1679
  for (const issue of result.errors) {
@@ -1643,7 +1710,7 @@ var validateCommand = defineCommand9({
1643
1710
  });
1644
1711
 
1645
1712
  // src/index.ts
1646
- var main = defineCommand10({
1713
+ var main = defineCommand11({
1647
1714
  meta: {
1648
1715
  name: "acta",
1649
1716
  version: "0.0.0",
@@ -1658,6 +1725,7 @@ var main = defineCommand10({
1658
1725
  graph: graphCommand,
1659
1726
  build: buildCommand,
1660
1727
  site: siteCommand,
1728
+ skill: skillCommand,
1661
1729
  renumber: renumberCommand
1662
1730
  }
1663
1731
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acta-dev/cli",
3
- "version": "1.2.0",
3
+ "version": "1.3.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",