@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.
- package/dist/index.js +125 -57
- 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
|
|
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
|
|
226
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
227
|
-
import { join as
|
|
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 (
|
|
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
|
|
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: "
|
|
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 =
|
|
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
|
|
660
|
+
await mkdir2(dir, { recursive: true });
|
|
632
661
|
printSuccess(`Created dir ${dir}`);
|
|
633
662
|
}
|
|
634
|
-
const adrTplPath =
|
|
635
|
-
const specTplPath =
|
|
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 =
|
|
641
|
-
if (
|
|
642
|
-
const { readFile:
|
|
643
|
-
const content = await
|
|
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 =
|
|
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 =
|
|
656
|
-
await
|
|
657
|
-
const workflowPath =
|
|
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
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
if (
|
|
667
|
-
|
|
668
|
-
|
|
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
|
|
786
|
-
import { writeFile as
|
|
787
|
-
import { join as
|
|
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
|
|
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 =
|
|
812
|
-
const raw = await
|
|
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 =
|
|
858
|
-
if (
|
|
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
|
|
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
|
|
975
|
-
import { basename, dirname, join as
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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() ?
|
|
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
|
|
1572
|
-
import { join as
|
|
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
|
|
1641
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
1575
1642
|
import kleur7 from "kleur";
|
|
1576
|
-
var validateCommand =
|
|
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
|
|
1608
|
-
const outPath =
|
|
1609
|
-
await
|
|
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 =
|
|
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
|
});
|