@aigentdocs/core 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 rodrigo-amc and AIGenticDocs contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # @aigentdocs/core
2
+
3
+ Shared domain model and validation logic for the [AIGentDocs](https://github.com/rodrigo-amc/AIGentDocs) tooling: frontmatter parsing, the deterministic lint rule engine, scaffolding, adapter generation, and standard updates.
4
+
5
+ You probably want the CLI instead: [`aigentdocs`](https://www.npmjs.com/package/aigentdocs). This package exists so the CLI and the future MCP server share one implementation.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `adapt` — generate thin per-tool adapter files (Layer 4).
3
+ *
4
+ * Most AI coding tools read AGENTS.md natively (Antigravity since v1.20.3,
5
+ * Codex, Cursor, Copilot, and others), so adapters do not duplicate content:
6
+ * they are generated pointers to AGENTS.md — the single canonical source —
7
+ * for tools that use their own file name or support tool-specific overrides.
8
+ *
9
+ * Files carry a generation marker; adapt only overwrites files it generated
10
+ * itself and refuses to touch hand-edited ones.
11
+ */
12
+ export declare const GENERATION_MARKER = "Generated by `aigentdocs adapt` \u2014 edit AGENTS.md instead; this file is regenerated.";
13
+ export interface AdapterTarget {
14
+ /** File to generate, relative to the repository root. */
15
+ file: string;
16
+ description: string;
17
+ content: string;
18
+ }
19
+ export declare const ADAPTER_TARGETS: Record<string, AdapterTarget>;
20
+ export interface AdaptResult {
21
+ written: Array<{
22
+ file: string;
23
+ description: string;
24
+ }>;
25
+ skipped: Array<{
26
+ file: string;
27
+ reason: string;
28
+ }>;
29
+ }
30
+ /** Generate adapter files for the given tools (default: all registered). */
31
+ export declare function adaptProject(targetDir: string, tools?: string[]): Promise<AdaptResult>;
@@ -0,0 +1,96 @@
1
+ import { access, mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ /**
4
+ * `adapt` — generate thin per-tool adapter files (Layer 4).
5
+ *
6
+ * Most AI coding tools read AGENTS.md natively (Antigravity since v1.20.3,
7
+ * Codex, Cursor, Copilot, and others), so adapters do not duplicate content:
8
+ * they are generated pointers to AGENTS.md — the single canonical source —
9
+ * for tools that use their own file name or support tool-specific overrides.
10
+ *
11
+ * Files carry a generation marker; adapt only overwrites files it generated
12
+ * itself and refuses to touch hand-edited ones.
13
+ */
14
+ export const GENERATION_MARKER = "Generated by `aigentdocs adapt` — edit AGENTS.md instead; this file is regenerated.";
15
+ const marker = (commentOpen, commentClose) => `${commentOpen} ${GENERATION_MARKER} ${commentClose}`;
16
+ export const ADAPTER_TARGETS = {
17
+ claude: {
18
+ file: "CLAUDE.md",
19
+ description: "Claude Code entry file (imports AGENTS.md)",
20
+ content: `${marker("<!--", "-->")}
21
+
22
+ @AGENTS.md
23
+ `,
24
+ },
25
+ cursor: {
26
+ file: ".cursor/rules/aigentdocs.mdc",
27
+ description: "Cursor project rule pointing to AGENTS.md",
28
+ content: `---
29
+ description: AIGentDocs project instructions
30
+ alwaysApply: true
31
+ ---
32
+
33
+ ${marker("<!--", "-->")}
34
+
35
+ Follow the AI agent instructions in \`AGENTS.md\` at the repository root.
36
+ The project documentation under \`docs/project/\` is the source of truth;
37
+ start from \`docs/standard/AGENT.md\`.
38
+ `,
39
+ },
40
+ copilot: {
41
+ file: ".github/copilot-instructions.md",
42
+ description: "GitHub Copilot instructions pointing to AGENTS.md",
43
+ content: `${marker("<!--", "-->")}
44
+
45
+ Follow the AI agent instructions in \`AGENTS.md\` at the repository root.
46
+ The project documentation under \`docs/project/\` is the source of truth;
47
+ start from \`docs/standard/AGENT.md\`.
48
+ `,
49
+ },
50
+ antigravity: {
51
+ file: "GEMINI.md",
52
+ description: "Antigravity-specific overrides (Antigravity reads AGENTS.md natively)",
53
+ content: `${marker("<!--", "-->")}
54
+
55
+ <!-- Antigravity (CLI, IDE, and agent tooling) reads AGENTS.md natively, and
56
+ this file takes priority over it for Antigravity-specific behavior.
57
+ Keep it empty of duplicated rules: add only Antigravity-specific
58
+ overrides below. -->
59
+
60
+ Follow the AI agent instructions in \`AGENTS.md\` at the repository root.
61
+ `,
62
+ },
63
+ };
64
+ const exists = (p) => access(p).then(() => true, () => false);
65
+ /** Generate adapter files for the given tools (default: all registered). */
66
+ export async function adaptProject(targetDir, tools) {
67
+ const requested = tools === undefined || tools.length === 0 ? Object.keys(ADAPTER_TARGETS) : tools;
68
+ for (const tool of requested) {
69
+ if (!(tool in ADAPTER_TARGETS)) {
70
+ throw new Error(`unknown tool '${tool}' (available: ${Object.keys(ADAPTER_TARGETS).join(", ")})`);
71
+ }
72
+ }
73
+ if (!(await exists(path.join(targetDir, "AGENTS.md")))) {
74
+ throw new Error(`'AGENTS.md' not found in '${targetDir}' — adapters point to it. Run 'aigentdocs init' first.`);
75
+ }
76
+ const result = { written: [], skipped: [] };
77
+ for (const tool of requested) {
78
+ const target = ADAPTER_TARGETS[tool];
79
+ if (target === undefined) {
80
+ continue;
81
+ }
82
+ const filePath = path.join(targetDir, target.file);
83
+ if (await exists(filePath)) {
84
+ const current = await readFile(filePath, "utf8");
85
+ if (!current.includes(GENERATION_MARKER)) {
86
+ result.skipped.push({ file: target.file, reason: "exists and was not generated by adapt — left untouched" });
87
+ continue;
88
+ }
89
+ }
90
+ await mkdir(path.dirname(filePath), { recursive: true });
91
+ await writeFile(filePath, target.content);
92
+ result.written.push({ file: target.file, description: target.description });
93
+ }
94
+ return result;
95
+ }
96
+ //# sourceMappingURL=adapt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapt.js","sourceRoot":"","sources":["../../src/adapt.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { type Finding } from "./index.js";
2
+ import type { ProjectModel } from "./project.js";
3
+ /**
4
+ * Lint v1 — cross-document consistency checks (Mechanical layer of
5
+ * AGENT_REVIEW.md, "Consistency Validation"):
6
+ *
7
+ * - tech_stack.yaml ADR references resolve to files in 04_adrs/
8
+ * (empty `adr` is a suggestion: the Lite profile allows it).
9
+ * - ADR supersedes/superseded_by reciprocity and superseded status.
10
+ * - Domain module code_paths point to paths that exist in the repository.
11
+ * - Roadmap references using the standard's `(see X.md)` / `(ver X.md)`
12
+ * convention resolve to project documents.
13
+ * - project_status.yaml (when present) agrees with module frontmatter
14
+ * states — the authority rule of the Project Status Artifacts.
15
+ */
16
+ export declare function checkConsistency(model: ProjectModel): Promise<Finding[]>;
@@ -0,0 +1,154 @@
1
+ import { access } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { STATES } from "./index.js";
4
+ /**
5
+ * Lint v1 — cross-document consistency checks (Mechanical layer of
6
+ * AGENT_REVIEW.md, "Consistency Validation"):
7
+ *
8
+ * - tech_stack.yaml ADR references resolve to files in 04_adrs/
9
+ * (empty `adr` is a suggestion: the Lite profile allows it).
10
+ * - ADR supersedes/superseded_by reciprocity and superseded status.
11
+ * - Domain module code_paths point to paths that exist in the repository.
12
+ * - Roadmap references using the standard's `(see X.md)` / `(ver X.md)`
13
+ * convention resolve to project documents.
14
+ * - project_status.yaml (when present) agrees with module frontmatter
15
+ * states — the authority rule of the Project Status Artifacts.
16
+ */
17
+ export async function checkConsistency(model) {
18
+ const findings = [];
19
+ const add = (rule, severity, file, message) => {
20
+ findings.push({ rule, severity, file, message });
21
+ };
22
+ const docsByType = new Map();
23
+ for (const doc of model.documents) {
24
+ const type = doc.frontmatter?.["type"];
25
+ if (typeof type === "string") {
26
+ const list = docsByType.get(type) ?? [];
27
+ list.push(doc);
28
+ docsByType.set(type, list);
29
+ }
30
+ }
31
+ // --- tech_stack.yaml → ADR references -----------------------------------
32
+ if (model.techStack !== undefined) {
33
+ if (model.techStack.parseError !== undefined) {
34
+ add("yaml/invalid", "critical", model.techStack.relPath, `does not parse: ${model.techStack.parseError}`);
35
+ }
36
+ else {
37
+ for (const [keyPath, adrRef] of collectAdrRefs(model.techStack.data, [])) {
38
+ if (adrRef === "") {
39
+ add("ref/tech-stack-adr-empty", "suggestion", model.techStack.relPath, `'${keyPath}' has no ADR recorded (allowed in the Lite profile; required in Full)`);
40
+ continue;
41
+ }
42
+ const adrPath = path.join(model.repoRoot, "docs", "project", "04_adrs", adrRef);
43
+ const exists = await access(adrPath).then(() => true, () => false);
44
+ if (!exists) {
45
+ add("ref/tech-stack-adr", "critical", model.techStack.relPath, `'${keyPath}' references ADR '${adrRef}', which does not exist in 04_adrs/`);
46
+ }
47
+ }
48
+ }
49
+ }
50
+ // --- ADR reciprocity ------------------------------------------------------
51
+ const adrs = (docsByType.get("adr") ?? []).map((doc) => ({
52
+ doc,
53
+ id: typeof doc.frontmatter?.["id"] === "number" ? doc.frontmatter["id"] : undefined,
54
+ status: doc.frontmatter?.["status"],
55
+ supersedes: doc.frontmatter?.["supersedes"] ?? null,
56
+ supersededBy: doc.frontmatter?.["superseded_by"] ?? null,
57
+ }));
58
+ const adrById = new Map(adrs.filter((a) => a.id !== undefined).map((a) => [a.id, a]));
59
+ for (const adr of adrs) {
60
+ if (typeof adr.supersedes === "number") {
61
+ const target = adrById.get(adr.supersedes);
62
+ if (target === undefined) {
63
+ add("ref/adr-supersedes-target", "critical", adr.doc.relPath, `supersedes ADR ${adr.supersedes}, which does not exist`);
64
+ }
65
+ else if (target.supersededBy !== adr.id) {
66
+ add("adr/supersedes-reciprocity", "critical", target.doc.relPath, `must carry 'superseded_by: ${adr.id}' (it is superseded by ${adr.doc.relPath})`);
67
+ }
68
+ }
69
+ if (adr.supersededBy !== null && adr.status !== "superseded") {
70
+ add("adr/superseded-status", "warning", adr.doc.relPath, `has 'superseded_by' set, so its status should be 'superseded' (got '${String(adr.status)}')`);
71
+ }
72
+ }
73
+ // --- Domain module code_paths ----------------------------------------------
74
+ for (const doc of docsByType.get("domain_module") ?? []) {
75
+ const codePaths = doc.frontmatter?.["code_paths"];
76
+ if (!Array.isArray(codePaths)) {
77
+ continue; // shape already reported by lint v0
78
+ }
79
+ for (const entry of codePaths) {
80
+ if (typeof entry !== "string" || entry === "") {
81
+ continue;
82
+ }
83
+ const target = path.join(model.repoRoot, entry.replace(/^\//, ""));
84
+ const exists = await access(target).then(() => true, () => false);
85
+ if (!exists) {
86
+ add("ref/code-paths", "warning", doc.relPath, `code path '${entry}' does not exist in the repository`);
87
+ }
88
+ }
89
+ }
90
+ // --- Roadmap references: the standard's "(see X.md)" convention -------------
91
+ const basenames = new Set(model.documents.map((doc) => path.posix.basename(doc.relPath)));
92
+ const REF = /\((?:see|ver)\s+([A-Za-z0-9_.-]+\.(?:md|yaml))\)/g;
93
+ for (const doc of docsByType.get("roadmap") ?? []) {
94
+ for (const match of doc.content.matchAll(REF)) {
95
+ const ref = match[1] ?? "";
96
+ if (!basenames.has(ref) && ref !== "tech_stack.yaml" && ref !== "project_status.yaml") {
97
+ add("ref/roadmap-reference", "warning", doc.relPath, `references '${ref}', which does not exist under docs/project/`);
98
+ }
99
+ }
100
+ }
101
+ // --- project_status.yaml authority rule -------------------------------------
102
+ if (model.projectStatus !== undefined) {
103
+ const statusFile = model.projectStatus.relPath;
104
+ if (model.projectStatus.parseError !== undefined) {
105
+ add("yaml/invalid", "critical", statusFile, `does not parse: ${model.projectStatus.parseError}`);
106
+ return findings;
107
+ }
108
+ const data = model.projectStatus.data;
109
+ const modules = (data?.["modules"] ?? {});
110
+ const moduleDocs = new Map((docsByType.get("domain_module") ?? []).map((doc) => [
111
+ String(doc.frontmatter?.["module_name"] ?? path.posix.basename(doc.relPath, ".md")),
112
+ doc,
113
+ ]));
114
+ if (modules !== null && typeof modules === "object" && !Array.isArray(modules)) {
115
+ for (const [name, value] of Object.entries(modules)) {
116
+ const state = value?.["state"];
117
+ if (typeof state !== "string" || !STATES.includes(state)) {
118
+ add("status/state-value", "critical", statusFile, `module '${name}' has invalid state '${String(state)}'`);
119
+ continue;
120
+ }
121
+ const moduleDoc = moduleDocs.get(name);
122
+ if (moduleDoc === undefined) {
123
+ add("status/unknown-module", "warning", statusFile, `module '${name}' has no document in domain_modules/`);
124
+ }
125
+ else if (moduleDoc.frontmatter?.["state"] !== state) {
126
+ add("status/module-state-sync", "critical", moduleDoc.relPath, `frontmatter state '${String(moduleDoc.frontmatter?.["state"])}' contradicts project_status.yaml ('${state}') — project_status.yaml is authoritative`);
127
+ }
128
+ }
129
+ for (const [name, doc] of moduleDocs) {
130
+ if (!(name in modules)) {
131
+ add("status/module-missing", "warning", doc.relPath, `module '${name}' is not registered in project_status.yaml`);
132
+ }
133
+ }
134
+ }
135
+ }
136
+ return findings;
137
+ }
138
+ /** Recursively collect every `adr:` string value with its key path. */
139
+ function collectAdrRefs(node, keyPath) {
140
+ if (node === null || typeof node !== "object") {
141
+ return [];
142
+ }
143
+ const refs = [];
144
+ for (const [key, value] of Object.entries(node)) {
145
+ if (key === "adr" && typeof value === "string") {
146
+ refs.push([keyPath.join("."), value]);
147
+ }
148
+ else {
149
+ refs.push(...collectAdrRefs(value, [...keyPath, key]));
150
+ }
151
+ }
152
+ return refs;
153
+ }
154
+ //# sourceMappingURL=consistency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consistency.js","sourceRoot":"","sources":["../../src/consistency.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Result of looking for a YAML frontmatter block at the top of a markdown file.
3
+ * `yaml` is the only module allowed to be imported here (ADR-0003); everything
4
+ * else in the tooling goes through this wrapper.
5
+ */
6
+ export interface FrontmatterResult {
7
+ /** True when a `---` ... `---` block exists at the very top of the file. */
8
+ found: boolean;
9
+ /** The parsed mapping, when found and valid. */
10
+ data?: Record<string, unknown>;
11
+ /** Parse or shape error, when found but unusable. */
12
+ error?: string;
13
+ }
14
+ /** Parse a full YAML document. Throws on invalid YAML (caller decides severity). */
15
+ export declare function parseYaml(text: string): unknown;
16
+ export declare function extractFrontmatter(markdown: string): FrontmatterResult;
@@ -0,0 +1,24 @@
1
+ import { parse } from "yaml";
2
+ const FENCE = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;
3
+ /** Parse a full YAML document. Throws on invalid YAML (caller decides severity). */
4
+ export function parseYaml(text) {
5
+ return parse(text);
6
+ }
7
+ export function extractFrontmatter(markdown) {
8
+ const match = FENCE.exec(markdown);
9
+ if (!match) {
10
+ return { found: false };
11
+ }
12
+ let parsed;
13
+ try {
14
+ parsed = parse(match[1] ?? "");
15
+ }
16
+ catch (error) {
17
+ return { found: true, error: error instanceof Error ? error.message : String(error) };
18
+ }
19
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
20
+ return { found: true, error: "frontmatter is not a YAML mapping" };
21
+ }
22
+ return { found: true, data: parsed };
23
+ }
24
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAgB7B,MAAM,KAAK,GAAG,wCAAwC,CAAC;AAEvD,oFAAoF;AACpF,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC1B,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACxF,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,mCAAmC,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAiC,EAAE,CAAC;AAClE,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @aigentdocs/core — shared domain model for the AIGentDocs tooling.
3
+ *
4
+ * The values here mirror the standard (docs/standard/): if the standard
5
+ * changes its allowed values, this module is the single place to update.
6
+ */
7
+ /** Severity scale of a lint finding, as defined in AGENT_REVIEW.md. */
8
+ export type Severity = "critical" | "warning" | "suggestion";
9
+ /** One result of a mechanical validation against an adopting project. */
10
+ export interface Finding {
11
+ /** Lint rule ID, e.g. "frontmatter/required-fields". */
12
+ rule: string;
13
+ severity: Severity;
14
+ /** Path of the offending file, relative to the repository root. */
15
+ file: string;
16
+ message: string;
17
+ }
18
+ /** Adoption depth declared by an adopting project. */
19
+ export type AdoptionProfile = "lite" | "full";
20
+ /** Allowed values of the `state` frontmatter field (working documents). */
21
+ export declare const STATES: readonly ["pending", "doing", "done", "deprecated"];
22
+ export type State = (typeof STATES)[number];
23
+ /** Allowed values of the `status` frontmatter field of ADRs. */
24
+ export declare const ADR_STATUSES: readonly ["proposed", "accepted", "rejected", "superseded"];
25
+ export type AdrStatus = (typeof ADR_STATUSES)[number];
26
+ /** Allowed values of the `status` frontmatter field of Correction Records. */
27
+ export declare const CORRECTION_STATUSES: readonly ["proposed", "approved", "applied", "rejected"];
28
+ export type CorrectionStatus = (typeof CORRECTION_STATUSES)[number];
29
+ /** Frontmatter fields required on every content document of the standard. */
30
+ export declare const REQUIRED_COMMON_FIELDS: readonly ["type", "version", "last_updated"];
31
+ export { extractFrontmatter, parseYaml, type FrontmatterResult } from "./frontmatter.js";
32
+ export { lintMarkdown, lintProject, type LintProjectResult } from "./lint.js";
33
+ export { loadProject, type ProjectDocument, type ProjectModel, type YamlArtifact } from "./project.js";
34
+ export { checkConsistency } from "./consistency.js";
35
+ export { initProject, type InitProfile, type InitResult } from "./scaffold.js";
36
+ export { adaptProject, ADAPTER_TARGETS, GENERATION_MARKER, type AdaptResult, type AdapterTarget } from "./adapt.js";
37
+ export { compareVersions, updateStandard, type ChangelogEntry, type UpdateResult } from "./update.js";
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @aigentdocs/core — shared domain model for the AIGentDocs tooling.
3
+ *
4
+ * The values here mirror the standard (docs/standard/): if the standard
5
+ * changes its allowed values, this module is the single place to update.
6
+ */
7
+ /** Allowed values of the `state` frontmatter field (working documents). */
8
+ export const STATES = ["pending", "doing", "done", "deprecated"];
9
+ /** Allowed values of the `status` frontmatter field of ADRs. */
10
+ export const ADR_STATUSES = ["proposed", "accepted", "rejected", "superseded"];
11
+ /** Allowed values of the `status` frontmatter field of Correction Records. */
12
+ export const CORRECTION_STATUSES = ["proposed", "approved", "applied", "rejected"];
13
+ /** Frontmatter fields required on every content document of the standard. */
14
+ export const REQUIRED_COMMON_FIELDS = ["type", "version", "last_updated"];
15
+ export { extractFrontmatter, parseYaml } from "./frontmatter.js";
16
+ export { lintMarkdown, lintProject } from "./lint.js";
17
+ export { loadProject } from "./project.js";
18
+ export { checkConsistency } from "./consistency.js";
19
+ export { initProject } from "./scaffold.js";
20
+ export { adaptProject, ADAPTER_TARGETS, GENERATION_MARKER } from "./adapt.js";
21
+ export { compareVersions, updateStandard } from "./update.js";
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkBH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,CAAU,CAAC;AAG1E,gEAAgE;AAChE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,CAAU,CAAC;AAGxF,8EAA8E;AAC9E,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAU,CAAC;AAG5F,6EAA6E;AAC7E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,cAAc,CAAU,CAAC;AAEnF,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAA0B,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,WAAW,EAA0B,MAAM,WAAW,CAAC;AAC9E,OAAO,EAAE,WAAW,EAA8D,MAAM,cAAc,CAAC;AACvG,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAqC,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAwC,MAAM,YAAY,CAAC;AACpH,OAAO,EAAE,eAAe,EAAE,cAAc,EAA0C,MAAM,aAAa,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type Finding } from "./index.js";
2
+ /** Lint a single markdown document. `file` is used verbatim in findings. */
3
+ export declare function lintMarkdown(file: string, content: string): Finding[];
4
+ export interface LintProjectResult {
5
+ findings: Finding[];
6
+ filesChecked: number;
7
+ }
8
+ /**
9
+ * Lint everything under `<repoRoot>/docs/project/`: per-document frontmatter
10
+ * rules (v0) plus cross-document consistency rules (v1).
11
+ * Throws if the directory does not exist (not an AIGentDocs repository).
12
+ */
13
+ export declare function lintProject(repoRoot: string): Promise<LintProjectResult>;
@@ -0,0 +1,121 @@
1
+ import { ADR_STATUSES, CORRECTION_STATUSES, REQUIRED_COMMON_FIELDS, STATES, } from "./index.js";
2
+ import { extractFrontmatter } from "./frontmatter.js";
3
+ import { checkConsistency } from "./consistency.js";
4
+ import { checkSections } from "./sections.js";
5
+ import { loadProject } from "./project.js";
6
+ /**
7
+ * Lint v0 — the frontmatter slice of the Mechanical layer of AGENT_REVIEW.md:
8
+ * block presence, required common fields, allowed state/status values,
9
+ * date format, and array-typed fields.
10
+ */
11
+ /** Document types whose frontmatter carries the `state` field. */
12
+ const STATE_BEARING_TYPES = new Set([
13
+ "quality_attributes",
14
+ "system_overview",
15
+ "data_flow",
16
+ "infrastructure",
17
+ "testing_strategy",
18
+ "api_guidelines",
19
+ "domain_module",
20
+ ]);
21
+ const KNOWN_TYPES = new Set([...STATE_BEARING_TYPES, "vision", "roadmap", "adr", "correction", "todo"]);
22
+ const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
23
+ function isValidIsoDate(value) {
24
+ if (typeof value !== "string" || !DATE_RE.test(value)) {
25
+ return false;
26
+ }
27
+ const [y, m, d] = value.split("-").map(Number);
28
+ const date = new Date(Date.UTC(y ?? 0, (m ?? 1) - 1, d ?? 0));
29
+ return date.getUTCFullYear() === y && date.getUTCMonth() === (m ?? 1) - 1 && date.getUTCDate() === d;
30
+ }
31
+ function isOneOf(value, allowed) {
32
+ return typeof value === "string" && allowed.includes(value);
33
+ }
34
+ /** Lint a single markdown document. `file` is used verbatim in findings. */
35
+ export function lintMarkdown(file, content) {
36
+ const findings = [];
37
+ const add = (rule, severity, message) => {
38
+ findings.push({ rule, severity, file, message });
39
+ };
40
+ const fm = extractFrontmatter(content);
41
+ if (!fm.found) {
42
+ add("frontmatter/missing", "critical", "no YAML frontmatter block at the top of the file");
43
+ return findings;
44
+ }
45
+ if (fm.error !== undefined || fm.data === undefined) {
46
+ add("frontmatter/invalid-yaml", "critical", `frontmatter does not parse: ${fm.error ?? "unknown error"}`);
47
+ return findings;
48
+ }
49
+ const data = fm.data;
50
+ for (const field of REQUIRED_COMMON_FIELDS) {
51
+ if (data[field] === undefined || data[field] === null || data[field] === "") {
52
+ add("frontmatter/required-fields", "critical", `missing required field '${field}'`);
53
+ }
54
+ }
55
+ if (data["last_updated"] !== undefined && data["last_updated"] !== null && !isValidIsoDate(data["last_updated"])) {
56
+ add("frontmatter/date-format", "critical", `'last_updated' must be a valid YYYY-MM-DD date, got '${String(data["last_updated"])}'`);
57
+ }
58
+ const type = data["type"];
59
+ if (typeof type !== "string" || type === "") {
60
+ return findings; // already reported by required-fields; nothing type-specific to check
61
+ }
62
+ if (!KNOWN_TYPES.has(type)) {
63
+ add("frontmatter/unknown-type", "warning", `unknown document type '${type}'`);
64
+ return findings;
65
+ }
66
+ findings.push(...checkSections(file, type, content, data));
67
+ if (STATE_BEARING_TYPES.has(type)) {
68
+ const state = data["state"];
69
+ if (state === undefined || state === null) {
70
+ add("frontmatter/state-missing", "warning", `documents of type '${type}' carry a 'state' field`);
71
+ }
72
+ else if (!isOneOf(state, STATES)) {
73
+ add("frontmatter/state-value", "critical", `'state' must be one of ${STATES.join(" | ")}, got '${String(state)}'`);
74
+ }
75
+ }
76
+ if (type === "adr") {
77
+ const status = data["status"];
78
+ if (!isOneOf(status, ADR_STATUSES)) {
79
+ add("frontmatter/adr-status", "critical", `ADR 'status' must be one of ${ADR_STATUSES.join(" | ")}, got '${String(status)}'`);
80
+ }
81
+ if (typeof data["id"] !== "number") {
82
+ add("frontmatter/adr-id", "warning", "ADR frontmatter should carry a numeric 'id'");
83
+ }
84
+ if (data["date"] !== undefined && data["date"] !== null && !isValidIsoDate(data["date"])) {
85
+ add("frontmatter/date-format", "critical", `'date' must be a valid YYYY-MM-DD date, got '${String(data["date"])}'`);
86
+ }
87
+ }
88
+ if (type === "correction") {
89
+ const status = data["status"];
90
+ if (!isOneOf(status, CORRECTION_STATUSES)) {
91
+ add("frontmatter/correction-status", "critical", `Correction 'status' must be one of ${CORRECTION_STATUSES.join(" | ")}, got '${String(status)}'`);
92
+ }
93
+ }
94
+ if (type === "domain_module") {
95
+ if (!Array.isArray(data["code_paths"])) {
96
+ add("frontmatter/code-paths", "critical", "domain modules must carry 'code_paths' as an array");
97
+ }
98
+ for (const field of ["entities", "depends_on"]) {
99
+ if (data[field] !== undefined && data[field] !== null && !Array.isArray(data[field])) {
100
+ add("frontmatter/array-fields", "warning", `'${field}' should be an array`);
101
+ }
102
+ }
103
+ }
104
+ return findings;
105
+ }
106
+ /**
107
+ * Lint everything under `<repoRoot>/docs/project/`: per-document frontmatter
108
+ * rules (v0) plus cross-document consistency rules (v1).
109
+ * Throws if the directory does not exist (not an AIGentDocs repository).
110
+ */
111
+ export async function lintProject(repoRoot) {
112
+ const model = await loadProject(repoRoot);
113
+ const findings = [];
114
+ for (const doc of model.documents) {
115
+ findings.push(...lintMarkdown(doc.relPath, doc.content));
116
+ }
117
+ findings.push(...(await checkConsistency(model)));
118
+ const filesChecked = model.documents.length + (model.techStack === undefined ? 0 : 1) + (model.projectStatus === undefined ? 0 : 1);
119
+ return { findings, filesChecked };
120
+ }
121
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/lint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /** One markdown document under docs/project/, with its frontmatter pre-parsed. */
2
+ export interface ProjectDocument {
3
+ /** Path relative to the repository root, POSIX-style. */
4
+ relPath: string;
5
+ content: string;
6
+ /** Parsed frontmatter mapping; undefined when missing or unparseable. */
7
+ frontmatter?: Record<string, unknown>;
8
+ }
9
+ /** A YAML artifact (tech_stack.yaml, project_status.yaml). */
10
+ export interface YamlArtifact {
11
+ relPath: string;
12
+ /** Parsed content; undefined when the file does not parse. */
13
+ data?: unknown;
14
+ parseError?: string;
15
+ }
16
+ export interface ProjectModel {
17
+ repoRoot: string;
18
+ documents: ProjectDocument[];
19
+ techStack?: YamlArtifact;
20
+ projectStatus?: YamlArtifact;
21
+ }
22
+ /**
23
+ * Load every documentation artifact under `<repoRoot>/docs/project/`.
24
+ * Throws if the directory does not exist (not an AIGentDocs repository).
25
+ */
26
+ export declare function loadProject(repoRoot: string): Promise<ProjectModel>;
@@ -0,0 +1,49 @@
1
+ import { access, readdir, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { extractFrontmatter, parseYaml } from "./frontmatter.js";
4
+ async function loadYamlArtifact(repoRoot, relPath) {
5
+ const absPath = path.join(repoRoot, relPath);
6
+ const exists = await access(absPath).then(() => true, () => false);
7
+ if (!exists) {
8
+ return undefined;
9
+ }
10
+ const text = await readFile(absPath, "utf8");
11
+ try {
12
+ return { relPath, data: parseYaml(text) };
13
+ }
14
+ catch (error) {
15
+ return { relPath, parseError: error instanceof Error ? error.message : String(error) };
16
+ }
17
+ }
18
+ /**
19
+ * Load every documentation artifact under `<repoRoot>/docs/project/`.
20
+ * Throws if the directory does not exist (not an AIGentDocs repository).
21
+ */
22
+ export async function loadProject(repoRoot) {
23
+ const projectDir = path.join(repoRoot, "docs", "project");
24
+ await access(projectDir).catch(() => {
25
+ throw new Error(`'${projectDir}' not found — is this an AIGentDocs repository?`);
26
+ });
27
+ const entries = await readdir(projectDir, { recursive: true, withFileTypes: true });
28
+ const files = entries
29
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
30
+ .map((entry) => path.join(entry.parentPath, entry.name))
31
+ .sort();
32
+ const documents = [];
33
+ for (const file of files) {
34
+ const content = await readFile(file, "utf8");
35
+ const fm = extractFrontmatter(content);
36
+ documents.push({
37
+ relPath: path.relative(repoRoot, file).split(path.sep).join("/"),
38
+ content,
39
+ frontmatter: fm.data,
40
+ });
41
+ }
42
+ return {
43
+ repoRoot,
44
+ documents,
45
+ techStack: await loadYamlArtifact(repoRoot, "docs/project/03_engineering/tech_stack.yaml"),
46
+ projectStatus: await loadYamlArtifact(repoRoot, "docs/project/project_status.yaml"),
47
+ };
48
+ }
49
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AA0BjE,KAAK,UAAU,gBAAgB,CAAC,QAAgB,EAAE,OAAe;IAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;IACnE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IACzF,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAC1D,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QAClC,MAAM,IAAI,KAAK,CAAC,IAAI,UAAU,iDAAiD,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACpF,MAAM,KAAK,GAAG,OAAO;SAClB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SAC/D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;SACvD,IAAI,EAAE,CAAC;IAEV,MAAM,SAAS,GAAsB,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC7C,MAAM,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACvC,SAAS,CAAC,IAAI,CAAC;YACb,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAChE,OAAO;YACP,WAAW,EAAE,EAAE,CAAC,IAAI;SACrB,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,QAAQ;QACR,SAAS;QACT,SAAS,EAAE,MAAM,gBAAgB,CAAC,QAAQ,EAAE,6CAA6C,CAAC;QAC1F,aAAa,EAAE,MAAM,gBAAgB,CAAC,QAAQ,EAAE,kCAAkC,CAAC;KACpF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `init` — scaffold the AIGentDocs structure into a repository.
3
+ *
4
+ * - full: docs/standard/ + empty docs/project/ tree + status artifacts
5
+ * (project_status.yaml, TODO.md, stamped with today's date) + AGENTS.md.
6
+ * Content documents are NOT created: sessions create them from templates
7
+ * (empty placeholders would wrongly signal Onboarding Mode).
8
+ * - lite: docs/standard/ + the three Lite files copied from templates
9
+ * (vision.md, roadmap.md, tech_stack.yaml) + AGENTS.md. Running `lint`
10
+ * right after a lite init lists the empty [REQUIRED] sections — that is
11
+ * the adopter's documentation to-do list, by design.
12
+ */
13
+ export type InitProfile = "full" | "lite";
14
+ export interface InitResult {
15
+ profile: InitProfile;
16
+ /** Paths created, relative to the target directory. */
17
+ created: string[];
18
+ }
19
+ export declare function initProject(targetDir: string, standardDir: string, profile: InitProfile): Promise<InitResult>;
@@ -0,0 +1,52 @@
1
+ import { access, cp, mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ const exists = (p) => access(p).then(() => true, () => false);
4
+ const FULL_PROJECT_DIRS = [
5
+ "01_product/domain_modules",
6
+ "02_architecture",
7
+ "03_engineering",
8
+ "04_adrs",
9
+ "05_corrections",
10
+ ];
11
+ export async function initProject(targetDir, standardDir, profile) {
12
+ const docsDir = path.join(targetDir, "docs");
13
+ if (await exists(docsDir)) {
14
+ throw new Error(`'${docsDir}' already exists — refusing to overwrite. Remove it or run init in a clean repository.`);
15
+ }
16
+ if (!(await exists(path.join(standardDir, "AGENT.md")))) {
17
+ throw new Error(`'${standardDir}' does not look like the standard (AGENT.md not found)`);
18
+ }
19
+ const created = [];
20
+ const today = new Date().toISOString().slice(0, 10);
21
+ await mkdir(docsDir, { recursive: true });
22
+ await cp(standardDir, path.join(docsDir, "standard"), { recursive: true });
23
+ created.push("docs/standard/");
24
+ const copyTemplate = async (template, relTarget) => {
25
+ const target = path.join(targetDir, relTarget);
26
+ await mkdir(path.dirname(target), { recursive: true });
27
+ const content = await readFile(path.join(standardDir, "templates", template), "utf8");
28
+ await writeFile(target, content.replaceAll("YYYY-MM-DD", today));
29
+ created.push(relTarget);
30
+ };
31
+ if (profile === "lite") {
32
+ await copyTemplate("vision.md", "docs/project/01_product/vision.md");
33
+ await copyTemplate("roadmap.md", "docs/project/01_product/roadmap.md");
34
+ await copyTemplate("tech_stack.yaml", "docs/project/03_engineering/tech_stack.yaml");
35
+ }
36
+ else {
37
+ for (const dir of FULL_PROJECT_DIRS) {
38
+ await mkdir(path.join(targetDir, "docs", "project", dir), { recursive: true });
39
+ created.push(`docs/project/${dir}/`);
40
+ }
41
+ await copyTemplate("project_status.yaml", "docs/project/project_status.yaml");
42
+ await copyTemplate("TODO.md", "docs/project/TODO.md");
43
+ }
44
+ if (await exists(path.join(targetDir, "AGENTS.md"))) {
45
+ created.push("(AGENTS.md already present — left untouched)");
46
+ }
47
+ else {
48
+ await copyTemplate("AGENTS.md", "AGENTS.md");
49
+ }
50
+ return { profile, created };
51
+ }
52
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/scaffold.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Finding } from "./index.js";
2
+ export declare function checkSections(file: string, type: string, content: string, frontmatter?: Record<string, unknown>): Finding[];
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Lint v2 — [REQUIRED] section presence/non-emptiness per document type and
3
+ * countable thresholds (US with too many or zero ACs, oversized Mermaid
4
+ * diagrams), per AGENT_REVIEW.md Mechanical layer.
5
+ *
6
+ * Section names are the canonical English headings of the standard's
7
+ * templates. Projects documented in another language are not yet covered
8
+ * by these checks (per-language catalogs are future work).
9
+ */
10
+ /** Canonical [REQUIRED] headings per document type. */
11
+ const REQUIRED_SECTIONS = {
12
+ vision: ["Elevator Pitch", "Problem It Solves", "Target Users (Personas)", "Project Scope", "Domain Glossary", "Domain Entity Map"],
13
+ roadmap: ["Current Phase/Milestone", "Task Board"],
14
+ quality_attributes: ["Performance", "Security"],
15
+ domain_module: ["Description", "Attributes / Properties", "Business Rules", "User Stories", "Relationships"],
16
+ system_overview: ["Context Diagram (C4 Level 1)", "Container Diagram (C4 Level 2)", "Folder Structure", "Architectural Patterns"],
17
+ data_flow: ["Global Process View", "Data Model"],
18
+ infrastructure: ["Environment", "Deployment Diagram", "CI/CD", "Variables and Secrets"],
19
+ testing_strategy: ["Required Test Types", "Testing Tools", "Minimum Expected Coverage", "Test File Structure"],
20
+ api_guidelines: ["API Standard", "Endpoint Conventions", "Request/Response Format", "Authentication and Authorization"],
21
+ adr: ["Context and Problem", "Decision", "Consequences"],
22
+ correction: ["Defect Report", "Impact Map"],
23
+ };
24
+ const MERMAID_NODE_LIMIT = 20;
25
+ const US_AC_LIMIT = 6;
26
+ function parseHeadings(lines) {
27
+ const headings = [];
28
+ let inFence = false;
29
+ for (let i = 0; i < lines.length; i++) {
30
+ const line = lines[i] ?? "";
31
+ if (/^\s*```/.test(line)) {
32
+ inFence = !inFence;
33
+ continue;
34
+ }
35
+ const match = inFence ? null : /^(#{1,6})\s+(.+?)\s*$/.exec(line);
36
+ if (match) {
37
+ headings.push({ level: match[1]?.length ?? 1, text: match[2] ?? "", line: i });
38
+ }
39
+ }
40
+ return headings;
41
+ }
42
+ const normalize = (text) => text.toLowerCase().replace(/\s+/g, " ").replace(/\s*\/\s*/g, "/").trim();
43
+ /** Body of a section: from its heading to the next heading of same or higher level. */
44
+ function sectionBody(lines, headings, index) {
45
+ const start = (headings[index]?.line ?? 0) + 1;
46
+ const level = headings[index]?.level ?? 1;
47
+ let end = lines.length;
48
+ for (let i = index + 1; i < headings.length; i++) {
49
+ if ((headings[i]?.level ?? 6) <= level) {
50
+ end = headings[i]?.line ?? lines.length;
51
+ break;
52
+ }
53
+ }
54
+ return lines.slice(start, end).join("\n");
55
+ }
56
+ const isEmptyBody = (body) => body.replace(/<!--[\s\S]*?-->/g, "").replace(/^---\s*$/gm, "").trim() === "";
57
+ export function checkSections(file, type, content, frontmatter) {
58
+ const findings = [];
59
+ const add = (rule, severity, message) => {
60
+ findings.push({ rule, severity, file, message });
61
+ };
62
+ const lines = content.split(/\r?\n/);
63
+ const headings = parseHeadings(lines);
64
+ const byName = new Map();
65
+ headings.forEach((h, i) => {
66
+ if (!byName.has(normalize(h.text))) {
67
+ byName.set(normalize(h.text), i);
68
+ }
69
+ });
70
+ // --- [REQUIRED] sections: present and non-empty ---------------------------
71
+ for (const section of REQUIRED_SECTIONS[type] ?? []) {
72
+ const index = byName.get(normalize(section));
73
+ if (index === undefined) {
74
+ add("section/missing", "critical", `missing [REQUIRED] section '${section}'`);
75
+ }
76
+ else if (isEmptyBody(sectionBody(lines, headings, index))) {
77
+ add("section/empty", "critical", `[REQUIRED] section '${section}' is empty`);
78
+ }
79
+ }
80
+ // --- Correction Records: Resolution is required once applied --------------
81
+ if (type === "correction" && frontmatter?.["status"] === "applied") {
82
+ const index = byName.get(normalize("Resolution"));
83
+ if (index === undefined || isEmptyBody(sectionBody(lines, headings, index))) {
84
+ add("section/correction-resolution", "critical", "an applied Correction Record must have a non-empty 'Resolution' section");
85
+ }
86
+ }
87
+ // --- User Stories: every US needs ACs; more than 6 needs a human decision --
88
+ if (type === "domain_module") {
89
+ headings.forEach((h, i) => {
90
+ const usMatch = /^(US-\d+)/i.exec(h.text);
91
+ if (!usMatch) {
92
+ return;
93
+ }
94
+ const acCount = (sectionBody(lines, headings, i).match(/^\s*[-*]\s*\[[ xX]\]\s*AC-/gm) ?? []).length;
95
+ if (acCount === 0) {
96
+ add("us/no-acceptance-criteria", "critical", `${usMatch[1]} has no Acceptance Criteria (expected '- [ ] AC-NN: ...' items)`);
97
+ }
98
+ else if (acCount > US_AC_LIMIT) {
99
+ add("threshold/us-ac-count", "warning", `${usMatch[1]} has ${acCount} ACs (> ${US_AC_LIMIT}): ask the human to split it or approve it as indivisible`);
100
+ }
101
+ });
102
+ }
103
+ // --- Mermaid diagrams: rough node-count heuristic --------------------------
104
+ for (const block of content.matchAll(/```mermaid\r?\n([\s\S]*?)```/g)) {
105
+ const nodes = countMermaidNodes(block[1] ?? "");
106
+ if (nodes > MERMAID_NODE_LIMIT) {
107
+ add("threshold/mermaid-size", "suggestion", `a Mermaid diagram has ~${nodes} nodes (> ${MERMAID_NODE_LIMIT}): consider splitting it`);
108
+ }
109
+ }
110
+ return findings;
111
+ }
112
+ const MERMAID_KEYWORDS = new Set([
113
+ "graph", "flowchart", "subgraph", "end", "direction", "sequencediagram", "participant", "actor",
114
+ "erdiagram", "classdiagram", "statediagram", "note", "over", "alt", "else", "opt", "loop", "par",
115
+ "and", "rect", "activate", "deactivate", "title", "td", "tb", "lr", "rl", "bt",
116
+ ]);
117
+ /** Heuristic: unique identifiers appearing on relationship/edge lines. */
118
+ function countMermaidNodes(source) {
119
+ const ids = new Set();
120
+ for (const line of source.split(/\r?\n/)) {
121
+ if (!/-->|---|==>|\.\.>|\|\|--|}o--|\|o--|}\|--|->>|-->>|--x|-x/.test(line)) {
122
+ continue;
123
+ }
124
+ for (const token of line.matchAll(/[A-Za-z_][A-Za-z0-9_]*/g)) {
125
+ const id = token[0];
126
+ if (!MERMAID_KEYWORDS.has(id.toLowerCase())) {
127
+ ids.add(id);
128
+ }
129
+ }
130
+ }
131
+ return ids.size;
132
+ }
133
+ //# sourceMappingURL=sections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sections.js","sourceRoot":"","sources":["../../src/sections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `update` — upgrade an adopter's docs/standard/ to the standard bundled
3
+ * with the CLI.
4
+ *
5
+ * Version detection needs no configuration: the adopter's own copy of
6
+ * changelog.yaml declares the installed version (top entry), and the
7
+ * packaged standard declares the available one. The entries between the
8
+ * two ARE the migration notes.
9
+ *
10
+ * README.md is the adopter's customization point (title, conventions), so
11
+ * a customized README is preserved and the incoming one is written next to
12
+ * it as README.md.new for manual merging. An uncustomized README (still
13
+ * carrying the generic title) is simply replaced.
14
+ */
15
+ export interface ChangelogEntry {
16
+ version: string;
17
+ date?: string;
18
+ summary?: string;
19
+ }
20
+ export interface UpdateResult {
21
+ status: "up-to-date" | "would-update" | "updated" | "ahead";
22
+ /** Installed standard version (top of the adopter's changelog copy). */
23
+ from: string;
24
+ /** Packaged standard version. */
25
+ to: string;
26
+ /** Changelog entries newer than `from` — the migration notes. */
27
+ notes: ChangelogEntry[];
28
+ /** True when README.md was preserved and README.md.new needs a manual merge. */
29
+ readmeNeedsMerge: boolean;
30
+ }
31
+ /** Compare dotted numeric versions ("1.4.3" vs "1.4"): -1 | 0 | 1. */
32
+ export declare function compareVersions(a: string, b: string): number;
33
+ export declare function updateStandard(targetDir: string, packagedStandardDir: string, options?: {
34
+ check?: boolean;
35
+ }): Promise<UpdateResult>;
@@ -0,0 +1,60 @@
1
+ import { access, cp, readFile, rm, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { parseYaml } from "./frontmatter.js";
4
+ const GENERIC_README_TITLE = "# Documentation Standard for AI-Augmented Software Engineering";
5
+ /** Compare dotted numeric versions ("1.4.3" vs "1.4"): -1 | 0 | 1. */
6
+ export function compareVersions(a, b) {
7
+ const pa = a.split(".").map(Number);
8
+ const pb = b.split(".").map(Number);
9
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
10
+ const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
11
+ if (diff !== 0) {
12
+ return diff < 0 ? -1 : 1;
13
+ }
14
+ }
15
+ return 0;
16
+ }
17
+ async function readChangelog(standardDir) {
18
+ const file = path.join(standardDir, "changelog.yaml");
19
+ const parsed = parseYaml(await readFile(file, "utf8"));
20
+ if (!Array.isArray(parsed) || parsed.length === 0 || typeof parsed[0].version !== "string") {
21
+ throw new Error(`'${file}' does not look like a standard changelog`);
22
+ }
23
+ return parsed;
24
+ }
25
+ export async function updateStandard(targetDir, packagedStandardDir, options = {}) {
26
+ const installedDir = path.join(targetDir, "docs", "standard");
27
+ await access(installedDir).catch(() => {
28
+ throw new Error(`'${installedDir}' not found — is this an AIGentDocs repository?`);
29
+ });
30
+ const from = (await readChangelog(installedDir))[0]?.version ?? "0.0.0";
31
+ const packaged = await readChangelog(packagedStandardDir);
32
+ const to = packaged[0]?.version ?? "0.0.0";
33
+ const base = { status: "up-to-date", from, to, notes: [], readmeNeedsMerge: false };
34
+ const cmp = compareVersions(from, to);
35
+ if (cmp === 0) {
36
+ return base;
37
+ }
38
+ if (cmp > 0) {
39
+ return { ...base, status: "ahead" };
40
+ }
41
+ const notes = packaged.filter((entry) => compareVersions(entry.version, from) > 0);
42
+ if (options.check === true) {
43
+ return { ...base, status: "would-update", notes };
44
+ }
45
+ const theirReadme = await readFile(path.join(installedDir, "README.md"), "utf8").catch(() => undefined);
46
+ await rm(installedDir, { recursive: true, force: true });
47
+ await cp(packagedStandardDir, installedDir, { recursive: true });
48
+ let readmeNeedsMerge = false;
49
+ const customized = theirReadme !== undefined && !theirReadme.startsWith(GENERIC_README_TITLE);
50
+ if (customized) {
51
+ const incoming = await readFile(path.join(installedDir, "README.md"), "utf8");
52
+ if (incoming !== theirReadme) {
53
+ await writeFile(path.join(installedDir, "README.md"), theirReadme);
54
+ await writeFile(path.join(installedDir, "README.md.new"), incoming);
55
+ readmeNeedsMerge = true;
56
+ }
57
+ }
58
+ return { ...base, status: "updated", notes, readmeNeedsMerge };
59
+ }
60
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/update.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@aigentdocs/core",
3
+ "version": "0.1.0",
4
+ "description": "Shared domain model and validation logic for the AIGentDocs tooling (frontmatter parsing, deterministic lint rules, scaffolding, adapters, standard updates).",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/rodrigo-amc/AIGentDocs#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/rodrigo-amc/AIGentDocs.git",
10
+ "directory": "packages/core"
11
+ },
12
+ "keywords": ["documentation", "docs-as-code", "ai-agents", "lint"],
13
+ "type": "module",
14
+ "main": "dist/src/index.js",
15
+ "types": "dist/src/index.d.ts",
16
+ "files": [
17
+ "dist/src"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "engines": {
23
+ "node": ">=20"
24
+ },
25
+ "dependencies": {
26
+ "yaml": "^2.9.0"
27
+ }
28
+ }