@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.
Files changed (2) hide show
  1. package/dist/cli.js +79 -30
  2. 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 join10, resolve as resolve4 } from "node:path";
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
- if (!router.ok) {
1744
- for (const issue of router.issues) {
1745
- issues.push({
1746
- severity: "error",
1747
- code: `router:${issue.code}`,
1748
- message: `${issue.file}: ${issue.message}`
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 = join10(rootDir, "lefthook.yml");
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 = join10(rootDir, ".github/workflows/docs-check.yml");
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 join10(rootDir, ".git/hooks", hookName);
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 join12 } from "node:path";
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 join11 } from "node:path";
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 = join11(rootDir, "docs/governance/templates", file);
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 = join11(rootDir, "docs/governance/templates");
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 = join11(templatesDir, file);
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 = join12(root, dir);
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 = join12(root, dir, ".gitkeep");
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 join13 } from "node:path";
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(join13(rootDir, route))) {
2328
+ if (!existsSync11(join14(rootDir, route))) {
2282
2329
  issues.push(`missing selected profile route: ${route}`);
2283
2330
  }
2284
- const agentsPath = join13(rootDir, "AGENTS.md");
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 join14 } from "node:path";
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 = join14(root, plan.filePath);
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 result = checkRouterIntegrity(process.cwd());
2416
- if (!result.ok) {
2417
- for (const issue of result.issues) {
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 join15 } from "node:path";
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 = join15(root, oldRec.path);
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 = join15(root, newRec.path);
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pieai/doc-gov",
3
- "version": "0.9.9",
3
+ "version": "0.9.10",
4
4
  "description": "AI-native documentation governance CLI for project docs, agent routing, and lifecycle checks.",
5
5
  "keywords": [
6
6
  "ai-agents",