@pieai/doc-gov 0.9.9 → 0.9.10
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/cli.js +79 -30
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1098,7 +1098,7 @@ function runCheck() {
|
|
|
1098
1098
|
// src/commands/doctor.ts
|
|
1099
1099
|
import { spawnSync } from "node:child_process";
|
|
1100
1100
|
import { existsSync as existsSync8, readFileSync as readFileSync9 } from "node:fs";
|
|
1101
|
-
import { isAbsolute as isAbsolute2, join as
|
|
1101
|
+
import { isAbsolute as isAbsolute2, join as join11, resolve as resolve4 } from "node:path";
|
|
1102
1102
|
|
|
1103
1103
|
// src/core/router-integrity.ts
|
|
1104
1104
|
import { existsSync as existsSync7, lstatSync as lstatSync3, readlinkSync as readlinkSync2, readFileSync as readFileSync8 } from "node:fs";
|
|
@@ -1716,6 +1716,54 @@ function findGovernedReadmes(rootDir) {
|
|
|
1716
1716
|
}).map((path) => relative4(rootDir, path).split(/\\/g).join("/")).filter((repoPath) => repoPath !== "README.md");
|
|
1717
1717
|
}
|
|
1718
1718
|
|
|
1719
|
+
// src/core/windows-host-adapters.ts
|
|
1720
|
+
import { lstatSync as lstatSync4, realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
|
|
1721
|
+
import { join as join10 } from "node:path";
|
|
1722
|
+
function filterCompatibleWindowsHostAdapterIssues(rootDir, issues) {
|
|
1723
|
+
if (process.platform !== "win32") return [...issues];
|
|
1724
|
+
const claudeEntryOk = isHardLink(join10(rootDir, "CLAUDE.md"), join10(rootDir, "AGENTS.md"));
|
|
1725
|
+
const claudeSkillsOk = resolvesTo(
|
|
1726
|
+
join10(rootDir, ".claude/skills"),
|
|
1727
|
+
join10(rootDir, ".agents/skills")
|
|
1728
|
+
);
|
|
1729
|
+
return issues.filter((issue) => {
|
|
1730
|
+
if (issue.code !== "invalid-host-ssot-adapter" && issue.code !== "noncanonical-host-ssot-adapter") {
|
|
1731
|
+
return true;
|
|
1732
|
+
}
|
|
1733
|
+
if (issue.file === "CLAUDE.md" && claudeEntryOk) return false;
|
|
1734
|
+
if (issue.file === ".claude/skills" && claudeSkillsOk) return false;
|
|
1735
|
+
return true;
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
function isHardLink(candidatePath, canonicalPath) {
|
|
1739
|
+
const candidate = safeLstat3(candidatePath);
|
|
1740
|
+
const canonical = safeLstat3(canonicalPath);
|
|
1741
|
+
if (!candidate?.isFile() || !canonical?.isFile()) return false;
|
|
1742
|
+
try {
|
|
1743
|
+
const left = statSync2(candidatePath);
|
|
1744
|
+
const right = statSync2(canonicalPath);
|
|
1745
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
1746
|
+
} catch {
|
|
1747
|
+
return false;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
function resolvesTo(candidatePath, canonicalPath) {
|
|
1751
|
+
const candidate = safeLstat3(candidatePath);
|
|
1752
|
+
if (!candidate?.isSymbolicLink()) return false;
|
|
1753
|
+
try {
|
|
1754
|
+
return realpathSync2(candidatePath) === realpathSync2(canonicalPath);
|
|
1755
|
+
} catch {
|
|
1756
|
+
return false;
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
function safeLstat3(path) {
|
|
1760
|
+
try {
|
|
1761
|
+
return lstatSync4(path);
|
|
1762
|
+
} catch {
|
|
1763
|
+
return void 0;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1719
1767
|
// src/commands/doctor.ts
|
|
1720
1768
|
function runDoctor(_args) {
|
|
1721
1769
|
const root = process.cwd();
|
|
@@ -1740,14 +1788,13 @@ function runDoctor(_args) {
|
|
|
1740
1788
|
function collectDoctorIssues(rootDir = process.cwd()) {
|
|
1741
1789
|
const issues = [];
|
|
1742
1790
|
const router = checkRouterIntegrity(rootDir);
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
}
|
|
1791
|
+
const routerIssues = filterCompatibleWindowsHostAdapterIssues(rootDir, router.issues);
|
|
1792
|
+
for (const issue of routerIssues) {
|
|
1793
|
+
issues.push({
|
|
1794
|
+
severity: "error",
|
|
1795
|
+
code: `router:${issue.code}`,
|
|
1796
|
+
message: `${issue.file}: ${issue.message}`
|
|
1797
|
+
});
|
|
1751
1798
|
}
|
|
1752
1799
|
const docs = checkDocs(rootDir);
|
|
1753
1800
|
if (!docs.ok) {
|
|
@@ -1781,7 +1828,7 @@ function collectDoctorIssues(rootDir = process.cwd()) {
|
|
|
1781
1828
|
return issues;
|
|
1782
1829
|
}
|
|
1783
1830
|
function checkLefthook(rootDir) {
|
|
1784
|
-
const path =
|
|
1831
|
+
const path = join11(rootDir, "lefthook.yml");
|
|
1785
1832
|
if (!existsSync8(path)) {
|
|
1786
1833
|
return [
|
|
1787
1834
|
{
|
|
@@ -1828,7 +1875,7 @@ function checkLefthook(rootDir) {
|
|
|
1828
1875
|
return issues;
|
|
1829
1876
|
}
|
|
1830
1877
|
function checkDocsCheckWorkflow(rootDir) {
|
|
1831
|
-
const path =
|
|
1878
|
+
const path = join11(rootDir, ".github/workflows/docs-check.yml");
|
|
1832
1879
|
if (!existsSync8(path)) {
|
|
1833
1880
|
return [
|
|
1834
1881
|
{
|
|
@@ -1865,7 +1912,7 @@ function resolveGitHookPath(rootDir, hookName) {
|
|
|
1865
1912
|
encoding: "utf8"
|
|
1866
1913
|
});
|
|
1867
1914
|
const gitPath = result.status === 0 ? result.stdout.trim() : "";
|
|
1868
|
-
if (!gitPath) return
|
|
1915
|
+
if (!gitPath) return join11(rootDir, ".git/hooks", hookName);
|
|
1869
1916
|
return isAbsolute2(gitPath) ? gitPath : resolve4(rootDir, gitPath);
|
|
1870
1917
|
}
|
|
1871
1918
|
|
|
@@ -1905,11 +1952,11 @@ function runFind(args2) {
|
|
|
1905
1952
|
|
|
1906
1953
|
// src/commands/init.ts
|
|
1907
1954
|
import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "node:fs";
|
|
1908
|
-
import { join as
|
|
1955
|
+
import { join as join13 } from "node:path";
|
|
1909
1956
|
|
|
1910
1957
|
// src/core/templates.ts
|
|
1911
1958
|
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync10, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1912
|
-
import { join as
|
|
1959
|
+
import { join as join12 } from "node:path";
|
|
1913
1960
|
var TEMPLATE_FILES = {
|
|
1914
1961
|
decision: "adr.md",
|
|
1915
1962
|
spec: "spec.md",
|
|
@@ -2117,18 +2164,18 @@ var DEFAULT_TEMPLATES = {
|
|
|
2117
2164
|
function loadTemplate(rootDir, type) {
|
|
2118
2165
|
const file = TEMPLATE_FILES[type];
|
|
2119
2166
|
if (!file) throw new Error(`No template file mapped for type: ${type}`);
|
|
2120
|
-
const path =
|
|
2167
|
+
const path = join12(rootDir, "docs/governance/templates", file);
|
|
2121
2168
|
if (existsSync9(path)) return readFileSync10(path, "utf8");
|
|
2122
2169
|
const fallback = DEFAULT_TEMPLATES[file];
|
|
2123
2170
|
if (fallback) return fallback;
|
|
2124
2171
|
throw new Error(`Template file is missing: docs/governance/templates/${file}`);
|
|
2125
2172
|
}
|
|
2126
2173
|
function ensureDefaultTemplates(rootDir) {
|
|
2127
|
-
const templatesDir =
|
|
2174
|
+
const templatesDir = join12(rootDir, "docs/governance/templates");
|
|
2128
2175
|
mkdirSync3(templatesDir, { recursive: true });
|
|
2129
2176
|
let created = 0;
|
|
2130
2177
|
for (const [file, content] of Object.entries(DEFAULT_TEMPLATES)) {
|
|
2131
|
-
const path =
|
|
2178
|
+
const path = join12(templatesDir, file);
|
|
2132
2179
|
if (existsSync9(path)) continue;
|
|
2133
2180
|
writeFileSync4(path, content);
|
|
2134
2181
|
created++;
|
|
@@ -2184,7 +2231,7 @@ function runInit(args2) {
|
|
|
2184
2231
|
];
|
|
2185
2232
|
let created = 0;
|
|
2186
2233
|
for (const dir of dirs) {
|
|
2187
|
-
const abs =
|
|
2234
|
+
const abs = join13(root, dir);
|
|
2188
2235
|
if (!existsSync10(abs)) {
|
|
2189
2236
|
mkdirSync4(abs, { recursive: true });
|
|
2190
2237
|
created++;
|
|
@@ -2192,7 +2239,7 @@ function runInit(args2) {
|
|
|
2192
2239
|
}
|
|
2193
2240
|
}
|
|
2194
2241
|
for (const dir of ["docs/specs/completed", "docs/plans/completed", "docs/archive"]) {
|
|
2195
|
-
const keep =
|
|
2242
|
+
const keep = join13(root, dir, ".gitkeep");
|
|
2196
2243
|
if (!existsSync10(keep)) writeFileSync5(keep, "");
|
|
2197
2244
|
}
|
|
2198
2245
|
const templatesCreated = ensureDefaultTemplates(root);
|
|
@@ -2241,7 +2288,7 @@ function runLinks() {
|
|
|
2241
2288
|
|
|
2242
2289
|
// src/commands/migrate.ts
|
|
2243
2290
|
import { existsSync as existsSync11, readFileSync as readFileSync11 } from "node:fs";
|
|
2244
|
-
import { join as
|
|
2291
|
+
import { join as join14 } from "node:path";
|
|
2245
2292
|
var PROFILE_ROUTES = {
|
|
2246
2293
|
"engineering-runtime": "docs/governance/agents-routing/engineering-runtime-v1.1.md",
|
|
2247
2294
|
"doc-only": "docs/governance/agents-routing/doc-only-v1.1.md"
|
|
@@ -2278,10 +2325,10 @@ function checkMigrationReadiness(rootDir, profile) {
|
|
|
2278
2325
|
issues.push(`${issue.file}: ${issue.code}: ${issue.message}`);
|
|
2279
2326
|
}
|
|
2280
2327
|
const route = PROFILE_ROUTES[profile];
|
|
2281
|
-
if (!existsSync11(
|
|
2328
|
+
if (!existsSync11(join14(rootDir, route))) {
|
|
2282
2329
|
issues.push(`missing selected profile route: ${route}`);
|
|
2283
2330
|
}
|
|
2284
|
-
const agentsPath =
|
|
2331
|
+
const agentsPath = join14(rootDir, "AGENTS.md");
|
|
2285
2332
|
if (existsSync11(agentsPath) && !readFileSync11(agentsPath, "utf8").includes(route)) {
|
|
2286
2333
|
issues.push(`AGENTS.md must name selected profile route: ${route}`);
|
|
2287
2334
|
}
|
|
@@ -2330,7 +2377,7 @@ function readFlag(args2, name) {
|
|
|
2330
2377
|
|
|
2331
2378
|
// src/commands/new.ts
|
|
2332
2379
|
import { existsSync as existsSync12, mkdirSync as mkdirSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
2333
|
-
import { dirname as dirname5, join as
|
|
2380
|
+
import { dirname as dirname5, join as join15 } from "node:path";
|
|
2334
2381
|
function runNew(args2) {
|
|
2335
2382
|
const positional = args2.filter((a) => !a.startsWith("--"));
|
|
2336
2383
|
const owner = readFlag2(args2, "--owner") ?? "human";
|
|
@@ -2356,7 +2403,7 @@ function runNew(args2) {
|
|
|
2356
2403
|
console.error(err.message);
|
|
2357
2404
|
return 1;
|
|
2358
2405
|
}
|
|
2359
|
-
const absPath =
|
|
2406
|
+
const absPath = join15(root, plan.filePath);
|
|
2360
2407
|
if (existsSync12(absPath) && !force) {
|
|
2361
2408
|
console.error(`File already exists: ${plan.filePath}. Use --force to overwrite.`);
|
|
2362
2409
|
return 1;
|
|
@@ -2412,9 +2459,11 @@ function slugToTitle(slug) {
|
|
|
2412
2459
|
|
|
2413
2460
|
// src/commands/router-check.ts
|
|
2414
2461
|
function runRouterCheck() {
|
|
2415
|
-
const
|
|
2416
|
-
|
|
2417
|
-
|
|
2462
|
+
const root = process.cwd();
|
|
2463
|
+
const result = checkRouterIntegrity(root);
|
|
2464
|
+
const issues = filterCompatibleWindowsHostAdapterIssues(root, result.issues);
|
|
2465
|
+
if (issues.length > 0) {
|
|
2466
|
+
for (const issue of issues) {
|
|
2418
2467
|
console.error(`${issue.file}: ${issue.code}: ${issue.message}`);
|
|
2419
2468
|
}
|
|
2420
2469
|
return 1;
|
|
@@ -2441,7 +2490,7 @@ function runScan(args2) {
|
|
|
2441
2490
|
|
|
2442
2491
|
// src/commands/supersede.ts
|
|
2443
2492
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
|
|
2444
|
-
import { join as
|
|
2493
|
+
import { join as join16 } from "node:path";
|
|
2445
2494
|
function runSupersede(args2) {
|
|
2446
2495
|
const [oldId, newId] = args2;
|
|
2447
2496
|
if (!oldId || !newId) {
|
|
@@ -2477,14 +2526,14 @@ function runSupersede(args2) {
|
|
|
2477
2526
|
return 1;
|
|
2478
2527
|
}
|
|
2479
2528
|
const today = todayIso();
|
|
2480
|
-
const oldPath =
|
|
2529
|
+
const oldPath = join16(root, oldRec.path);
|
|
2481
2530
|
let oldContent = readFileSync12(oldPath, "utf8");
|
|
2482
2531
|
oldContent = updateFrontmatterField(oldContent, "status", "superseded");
|
|
2483
2532
|
oldContent = updateFrontmatterField(oldContent, "canonical", "false");
|
|
2484
2533
|
oldContent = updateFrontmatterField(oldContent, "superseded_by", newId);
|
|
2485
2534
|
oldContent = updateFrontmatterField(oldContent, "last_reviewed", today);
|
|
2486
2535
|
writeFileSync7(oldPath, oldContent);
|
|
2487
|
-
const newPath =
|
|
2536
|
+
const newPath = join16(root, newRec.path);
|
|
2488
2537
|
let newContent = readFileSync12(newPath, "utf8");
|
|
2489
2538
|
newContent = appendToFrontmatterList(newContent, "supersedes", newId === oldId ? "" : oldId);
|
|
2490
2539
|
newContent = updateFrontmatterField(newContent, "last_reviewed", today);
|