@agentskit/doc-bridge 1.2.6 → 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/CHANGELOG.md +8 -0
- package/README.md +9 -3
- package/action.yml +1 -1
- package/dist/cli/program.js +344 -130
- package/dist/cli/program.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +3 -1
- package/dist/config/index.js.map +1 -1
- package/dist/{index-DGI9TBLE.d.ts → index-DAeq_OIi.d.ts} +22 -22
- package/dist/index.d.ts +7 -4
- package/dist/index.js +320 -105
- package/dist/index.js.map +1 -1
- package/docs/POSITIONING.md +1 -1
- package/docs/examples.md +4 -0
- package/docs/getting-started.md +1 -1
- package/docs/landing/index.html +1 -1
- package/docs/qa/vitepress-starlight-adapters.md +19 -0
- package/docs/spec/config-v1.md +33 -2
- package/examples/nextra-only.config.ts +17 -0
- package/examples/nx-monorepo.config.ts +11 -0
- package/examples/starlight-only.config.ts +17 -0
- package/examples/vitepress-only.config.ts +19 -0
- package/mcpb/manifest.json +1 -1
- package/package.json +4 -2
- package/src/config/schema.ts +3 -1
- package/src/index-builder/build-handoffs.ts +2 -0
- package/src/index-builder/build-index.ts +7 -1
- package/src/index-builder/human-adapters/index.ts +6 -0
- package/src/index-builder/human-adapters/nextra.ts +43 -0
- package/src/index-builder/human-adapters/starlight.ts +40 -0
- package/src/index-builder/human-adapters/vitepress.ts +43 -0
- package/src/index-builder/plugins/nx.ts +161 -0
- package/src/index-builder/plugins/pnpm-monorepo.ts +1 -0
- package/src/index-builder/watch-index.ts +11 -2
- package/src/index.ts +1 -0
- package/src/version.ts +1 -1
package/dist/cli/program.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/cli/program.ts
|
|
2
|
-
import { existsSync as
|
|
3
|
-
import { dirname as
|
|
2
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync4 } from "fs";
|
|
3
|
+
import { dirname as dirname8, resolve as resolve13 } from "path";
|
|
4
4
|
import { createInterface } from "readline/promises";
|
|
5
5
|
|
|
6
6
|
// src/config/load-config.ts
|
|
@@ -333,6 +333,8 @@ var HumanCorpusPluginIdSchema = z.enum([
|
|
|
333
333
|
"docusaurus",
|
|
334
334
|
"mkdocs",
|
|
335
335
|
"vitepress",
|
|
336
|
+
"starlight",
|
|
337
|
+
"nextra",
|
|
336
338
|
"custom"
|
|
337
339
|
]);
|
|
338
340
|
var AgentCorpusConfigSchema = z.object({
|
|
@@ -372,7 +374,7 @@ var OwnershipEntrySchema = z.object({
|
|
|
372
374
|
humanDoc: z.string().min(1).max(512).optional()
|
|
373
375
|
}).strict();
|
|
374
376
|
var RoutingConfigSchema = z.object({
|
|
375
|
-
plugin: z.enum(["pnpm-monorepo", "npm-workspaces", "yarn-workspaces", "pattern-files", "custom"]).optional(),
|
|
377
|
+
plugin: z.enum(["pnpm-monorepo", "npm-workspaces", "yarn-workspaces", "nx", "pattern-files", "custom"]).optional(),
|
|
376
378
|
options: z.object({
|
|
377
379
|
packages: z.array(z.string().min(1).max(256)).max(128).optional(),
|
|
378
380
|
/** Infer ownership from corpus paths/frontmatter (default true). */
|
|
@@ -665,8 +667,8 @@ var projectRootFromConfigPath = (configFilePath, projectRootField) => {
|
|
|
665
667
|
};
|
|
666
668
|
|
|
667
669
|
// src/conformance/documentation-standard-v1.ts
|
|
668
|
-
import { existsSync as
|
|
669
|
-
import { isAbsolute as
|
|
670
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8, realpathSync as realpathSync6, statSync as statSync3 } from "fs";
|
|
671
|
+
import { isAbsolute as isAbsolute4, relative as relative4, resolve as resolve6, sep as sep5 } from "path";
|
|
670
672
|
|
|
671
673
|
// src/conformance/ecosystem-contract.ts
|
|
672
674
|
import { z as z2 } from "zod";
|
|
@@ -841,8 +843,8 @@ var parseCanonicalEcosystemContract = (manifestInput, claimsInput) => {
|
|
|
841
843
|
};
|
|
842
844
|
|
|
843
845
|
// src/index-builder/build-index.ts
|
|
844
|
-
import { mkdirSync, readFileSync as
|
|
845
|
-
import { dirname as
|
|
846
|
+
import { mkdirSync, readFileSync as readFileSync7, writeFileSync } from "fs";
|
|
847
|
+
import { dirname as dirname4, join as join7 } from "path";
|
|
846
848
|
|
|
847
849
|
// src/lib/paths.ts
|
|
848
850
|
import { existsSync as existsSync2, realpathSync } from "fs";
|
|
@@ -1111,17 +1113,17 @@ var scanAgentCorpus = (root, config) => {
|
|
|
1111
1113
|
};
|
|
1112
1114
|
});
|
|
1113
1115
|
};
|
|
1114
|
-
var guessAgentDocForPackage = (corpus,
|
|
1116
|
+
var guessAgentDocForPackage = (corpus, packageId2) => {
|
|
1115
1117
|
const candidates = [
|
|
1116
|
-
(doc) => frontmatterString(doc.frontmatter, "package") ===
|
|
1117
|
-
(doc) => doc.id ===
|
|
1118
|
-
(doc) => doc.relPath.endsWith(`/packages/${
|
|
1119
|
-
(doc) => doc.relPath.endsWith(`/packages/${
|
|
1120
|
-
(doc) => doc.relPath.endsWith(`/packages/${
|
|
1121
|
-
(doc) => doc.relPath.endsWith(`/packages/${
|
|
1122
|
-
(doc) => doc.relPath.endsWith(`/${
|
|
1123
|
-
(doc) => doc.relPath.endsWith(`/${
|
|
1124
|
-
(doc) => doc.relPath.includes(`/packages/${
|
|
1118
|
+
(doc) => frontmatterString(doc.frontmatter, "package") === packageId2,
|
|
1119
|
+
(doc) => doc.id === packageId2,
|
|
1120
|
+
(doc) => doc.relPath.endsWith(`/packages/${packageId2}.md`),
|
|
1121
|
+
(doc) => doc.relPath.endsWith(`/packages/${packageId2}.mdx`),
|
|
1122
|
+
(doc) => doc.relPath.endsWith(`/packages/${packageId2}/index.md`),
|
|
1123
|
+
(doc) => doc.relPath.endsWith(`/packages/${packageId2}/index.mdx`),
|
|
1124
|
+
(doc) => doc.relPath.endsWith(`/${packageId2}.md`),
|
|
1125
|
+
(doc) => doc.relPath.endsWith(`/${packageId2}.mdx`),
|
|
1126
|
+
(doc) => doc.relPath.includes(`/packages/${packageId2}/`)
|
|
1125
1127
|
];
|
|
1126
1128
|
for (const match of candidates) {
|
|
1127
1129
|
const hit = corpus.find(match);
|
|
@@ -1213,7 +1215,8 @@ var collectPackages = (config, discovered, corpus) => {
|
|
|
1213
1215
|
byId.set(pkg.id, {
|
|
1214
1216
|
id: pkg.id,
|
|
1215
1217
|
path: existing.path || pkg.path,
|
|
1216
|
-
...pkg.name ? { name: pkg.name } : existing.name ? { name: existing.name } : {}
|
|
1218
|
+
...pkg.name ? { name: pkg.name } : existing.name ? { name: existing.name } : {},
|
|
1219
|
+
...pkg.checks ? { checks: pkg.checks } : existing.checks ? { checks: existing.checks } : {}
|
|
1217
1220
|
});
|
|
1218
1221
|
}
|
|
1219
1222
|
const seeds = [
|
|
@@ -1232,24 +1235,24 @@ var collectPackages = (config, discovered, corpus) => {
|
|
|
1232
1235
|
}
|
|
1233
1236
|
return [...byId.values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
1234
1237
|
};
|
|
1235
|
-
var resolveHumanDoc = (
|
|
1238
|
+
var resolveHumanDoc = (packageId2, override, fmHuman, humanDocs = {}) => {
|
|
1236
1239
|
if (override) return override;
|
|
1237
1240
|
if (fmHuman) return fmHuman;
|
|
1238
|
-
if (humanDocs[
|
|
1241
|
+
if (humanDocs[packageId2]) return humanDocs[packageId2];
|
|
1239
1242
|
const aliases = [
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
`packages/${
|
|
1245
|
-
`reference/packages/${
|
|
1246
|
-
`packages/${
|
|
1243
|
+
packageId2,
|
|
1244
|
+
packageId2.replace(/^@[^/]+\//, ""),
|
|
1245
|
+
packageId2.replace(/^os-/, ""),
|
|
1246
|
+
packageId2.replace(/-pattern$/, ""),
|
|
1247
|
+
`packages/${packageId2}`,
|
|
1248
|
+
`reference/packages/${packageId2}`,
|
|
1249
|
+
`packages/${packageId2}/index`
|
|
1247
1250
|
];
|
|
1248
1251
|
for (const alias of aliases) {
|
|
1249
1252
|
if (humanDocs[alias]) return humanDocs[alias];
|
|
1250
1253
|
}
|
|
1251
1254
|
for (const [key, url] of Object.entries(humanDocs)) {
|
|
1252
|
-
if (key ===
|
|
1255
|
+
if (key === packageId2 || key.endsWith(`/${packageId2}`) || key.endsWith(`/${packageId2}/index`) || key.endsWith(`-${packageId2}`)) {
|
|
1253
1256
|
return url;
|
|
1254
1257
|
}
|
|
1255
1258
|
}
|
|
@@ -1273,7 +1276,7 @@ var buildLookup = (config, packages, corpus, indexOutFile, humanDocs = {}, root
|
|
|
1273
1276
|
const purpose = override?.purpose ?? fm?.purpose;
|
|
1274
1277
|
const path = override?.path ?? fm?.path ?? pkg.path;
|
|
1275
1278
|
const checks = [
|
|
1276
|
-
...override?.checks ?? fm?.checks ?? defaultChecksForTarget(root, {
|
|
1279
|
+
...override?.checks ?? fm?.checks ?? pkg.checks ?? defaultChecksForTarget(root, {
|
|
1277
1280
|
packageId: pkg.id,
|
|
1278
1281
|
packagePath: path,
|
|
1279
1282
|
...pkg.name ? { packageName: pkg.name } : {},
|
|
@@ -1347,7 +1350,7 @@ var buildLookup = (config, packages, corpus, indexOutFile, humanDocs = {}, root
|
|
|
1347
1350
|
};
|
|
1348
1351
|
|
|
1349
1352
|
// src/version.ts
|
|
1350
|
-
var PACKAGE_VERSION = "1.
|
|
1353
|
+
var PACKAGE_VERSION = "1.3.0";
|
|
1351
1354
|
|
|
1352
1355
|
// src/index-builder/capabilities.ts
|
|
1353
1356
|
var renderCapabilitiesJson = (config, index, paths) => {
|
|
@@ -1604,6 +1607,38 @@ var fumadocsAdapter = {
|
|
|
1604
1607
|
}
|
|
1605
1608
|
};
|
|
1606
1609
|
|
|
1610
|
+
// src/index-builder/human-adapters/nextra.ts
|
|
1611
|
+
var nextraRecordId = (relPath, raw) => {
|
|
1612
|
+
const frontmatter = parseFrontmatter2(raw);
|
|
1613
|
+
return frontmatter.package ?? frontmatter.module ?? frontmatter.id ?? (routeSlug(relPath) || "index");
|
|
1614
|
+
};
|
|
1615
|
+
var isIndexPage = (path) => /(^|[/\\])index\.mdx?$/i.test(path);
|
|
1616
|
+
var resolveRouteCollisions = (records) => {
|
|
1617
|
+
const byUrl = /* @__PURE__ */ new Map();
|
|
1618
|
+
for (const record of records) {
|
|
1619
|
+
const normalized = { ...record, url: record.url || "/" };
|
|
1620
|
+
const indexPage = isIndexPage(record.path);
|
|
1621
|
+
const existing = byUrl.get(normalized.url);
|
|
1622
|
+
if (!existing || indexPage || !existing.indexPage) {
|
|
1623
|
+
byUrl.set(normalized.url, { record: normalized, indexPage });
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
return [...byUrl.values()].map(({ record }) => record);
|
|
1627
|
+
};
|
|
1628
|
+
var nextraAdapter = {
|
|
1629
|
+
plugin: "nextra",
|
|
1630
|
+
scan: ({ root, config }) => {
|
|
1631
|
+
const contentDir = optionString(config.options, ["contentDir", "docsDir", "root"]);
|
|
1632
|
+
if (!contentDir) return [];
|
|
1633
|
+
return resolveRouteCollisions(
|
|
1634
|
+
scanMarkdownDocs(root, contentDir, {
|
|
1635
|
+
idForDoc: nextraRecordId,
|
|
1636
|
+
urlPrefix: optionString(config.options, ["urlPrefix", "contentDirBasePath"]) ?? "/"
|
|
1637
|
+
})
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
};
|
|
1641
|
+
|
|
1607
1642
|
// src/index-builder/human-adapters/plain-markdown.ts
|
|
1608
1643
|
var plainMarkdownAdapter = {
|
|
1609
1644
|
plugin: "plain-markdown",
|
|
@@ -1613,11 +1648,73 @@ var plainMarkdownAdapter = {
|
|
|
1613
1648
|
}
|
|
1614
1649
|
};
|
|
1615
1650
|
|
|
1651
|
+
// src/index-builder/human-adapters/starlight.ts
|
|
1652
|
+
import { slug as githubSlug } from "github-slugger";
|
|
1653
|
+
var isStarlightPage = (relPath, raw) => {
|
|
1654
|
+
if (relPath.split("/").some((part) => part.startsWith(".") || part.startsWith("_"))) return false;
|
|
1655
|
+
return parseFrontmatter2(raw).draft !== "true";
|
|
1656
|
+
};
|
|
1657
|
+
var starlightFileSlug = (relPath) => routeSlug(relPath).split("/").map((part) => githubSlug(part)).filter(Boolean).join("/");
|
|
1658
|
+
var starlightSlug = (relPath, raw) => {
|
|
1659
|
+
const slug2 = parseFrontmatter2(raw).slug;
|
|
1660
|
+
return slug2 ? slug2.replace(/^\/+|\/+$/g, "") : starlightFileSlug(relPath);
|
|
1661
|
+
};
|
|
1662
|
+
var starlightAdapter = {
|
|
1663
|
+
plugin: "starlight",
|
|
1664
|
+
scan: ({ root, config }) => {
|
|
1665
|
+
const contentDir = optionString(config.options, ["contentDir", "docsDir", "root"]);
|
|
1666
|
+
if (!contentDir) return [];
|
|
1667
|
+
return scanMarkdownDocs(root, contentDir, {
|
|
1668
|
+
includeRelPath: isStarlightPage,
|
|
1669
|
+
slugForDoc: starlightSlug,
|
|
1670
|
+
urlPrefix: config.options?.urlPrefix
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
};
|
|
1674
|
+
|
|
1675
|
+
// src/index-builder/human-adapters/vitepress.ts
|
|
1676
|
+
import { minimatch } from "minimatch";
|
|
1677
|
+
var isVitePressPage = (relPath) => !relPath.split("/").some((part) => part === ".vitepress" || part.startsWith("."));
|
|
1678
|
+
var srcExcludePatterns = (value) => {
|
|
1679
|
+
if (value === void 0) return [];
|
|
1680
|
+
if (!Array.isArray(value) || value.length > 64) {
|
|
1681
|
+
throw new Error("VitePress srcExclude must be an array of at most 64 glob patterns.");
|
|
1682
|
+
}
|
|
1683
|
+
return value.map((pattern) => {
|
|
1684
|
+
if (typeof pattern !== "string" || !pattern || pattern.length > 256 || pattern.includes("\0")) {
|
|
1685
|
+
throw new Error("Each VitePress srcExclude pattern must be a non-empty string up to 256 characters.");
|
|
1686
|
+
}
|
|
1687
|
+
return pattern;
|
|
1688
|
+
});
|
|
1689
|
+
};
|
|
1690
|
+
var isExcluded = (relPath, patterns) => patterns.some((pattern) => minimatch(relPath, pattern, { dot: true }));
|
|
1691
|
+
var vitepressSlug = (relPath, cleanUrls) => {
|
|
1692
|
+
const slug2 = routeSlug(relPath);
|
|
1693
|
+
if (cleanUrls || /(?:^|\/)index\.mdx?$/.test(relPath)) return slug2;
|
|
1694
|
+
return `${slug2}.html`;
|
|
1695
|
+
};
|
|
1696
|
+
var vitepressAdapter = {
|
|
1697
|
+
plugin: "vitepress",
|
|
1698
|
+
scan: ({ root, config }) => {
|
|
1699
|
+
const docsDir = optionString(config.options, ["docsDir", "root", "srcDir"]);
|
|
1700
|
+
if (!docsDir) return [];
|
|
1701
|
+
const srcExclude = srcExcludePatterns(config.options?.srcExclude);
|
|
1702
|
+
return scanMarkdownDocs(root, docsDir, {
|
|
1703
|
+
includeRelPath: (relPath) => isVitePressPage(relPath) && !isExcluded(relPath, srcExclude),
|
|
1704
|
+
slugForDoc: (relPath) => vitepressSlug(relPath, config.options?.cleanUrls === true),
|
|
1705
|
+
urlPrefix: config.options?.urlPrefix
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1708
|
+
};
|
|
1709
|
+
|
|
1616
1710
|
// src/index-builder/human-adapters/index.ts
|
|
1617
1711
|
var ADAPTERS = [
|
|
1618
1712
|
plainMarkdownAdapter,
|
|
1619
1713
|
fumadocsAdapter,
|
|
1620
|
-
docusaurusAdapter
|
|
1714
|
+
docusaurusAdapter,
|
|
1715
|
+
vitepressAdapter,
|
|
1716
|
+
starlightAdapter,
|
|
1717
|
+
nextraAdapter
|
|
1621
1718
|
];
|
|
1622
1719
|
var humanConfigs = (config) => {
|
|
1623
1720
|
const human = config.corpus.human;
|
|
@@ -1652,12 +1749,121 @@ var scanHumanDocRecords = (root, config) => {
|
|
|
1652
1749
|
};
|
|
1653
1750
|
var scanHumanDocs = (root, config) => Object.fromEntries(scanHumanDocRecords(root, config).map((doc) => [doc.id, doc.url]));
|
|
1654
1751
|
|
|
1752
|
+
// src/index-builder/plugins/nx.ts
|
|
1753
|
+
import { existsSync as existsSync6, lstatSync as lstatSync2, readFileSync as readFileSync5, realpathSync as realpathSync5 } from "fs";
|
|
1754
|
+
import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute3, relative as relative3, resolve as resolve5, sep as sep4 } from "path";
|
|
1755
|
+
var NX_SCAN_SKIP = /* @__PURE__ */ new Set([
|
|
1756
|
+
"node_modules",
|
|
1757
|
+
".git",
|
|
1758
|
+
".nx",
|
|
1759
|
+
"dist",
|
|
1760
|
+
"coverage",
|
|
1761
|
+
".doc-bridge"
|
|
1762
|
+
]);
|
|
1763
|
+
var NX_PROJECT_NAME = /^(?:@[A-Za-z0-9._-]+\/)?[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
1764
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1765
|
+
var readJsonRecord = (path) => {
|
|
1766
|
+
try {
|
|
1767
|
+
const parsed = JSON.parse(readFileSync5(path, "utf8"));
|
|
1768
|
+
return isRecord(parsed) ? parsed : void 0;
|
|
1769
|
+
} catch {
|
|
1770
|
+
return void 0;
|
|
1771
|
+
}
|
|
1772
|
+
};
|
|
1773
|
+
var safeProjectPath = (root, manifestDir, declaredRoot) => {
|
|
1774
|
+
const candidate = typeof declaredRoot === "string" ? resolve5(root, declaredRoot) : manifestDir;
|
|
1775
|
+
const rel = toPosix(relative3(root, candidate)) || ".";
|
|
1776
|
+
if (isAbsolute3(rel) || rel === ".." || rel.startsWith("../")) return void 0;
|
|
1777
|
+
try {
|
|
1778
|
+
if (!lstatSync2(candidate).isDirectory()) return void 0;
|
|
1779
|
+
const canonicalRoot = realpathSync5.native(root);
|
|
1780
|
+
const canonicalCandidate = realpathSync5.native(candidate);
|
|
1781
|
+
const canonicalRel = relative3(canonicalRoot, canonicalCandidate);
|
|
1782
|
+
if (isAbsolute3(canonicalRel) || canonicalRel === ".." || canonicalRel.startsWith(`..${sep4}`)) {
|
|
1783
|
+
return void 0;
|
|
1784
|
+
}
|
|
1785
|
+
} catch {
|
|
1786
|
+
return void 0;
|
|
1787
|
+
}
|
|
1788
|
+
return rel;
|
|
1789
|
+
};
|
|
1790
|
+
var packageId = (name) => name.startsWith("@") ? name.split("/").at(-1) ?? name : name;
|
|
1791
|
+
var commandPrefix = (root) => {
|
|
1792
|
+
const manager = detectPackageManager(root);
|
|
1793
|
+
if (manager === "pnpm") return "pnpm exec nx run";
|
|
1794
|
+
if (manager === "yarn") return "yarn nx run";
|
|
1795
|
+
if (manager === "bun") return "bunx nx run";
|
|
1796
|
+
return "npx nx run";
|
|
1797
|
+
};
|
|
1798
|
+
var inferredChecks = (root, config, projectName2, targets) => {
|
|
1799
|
+
const prefix = commandPrefix(root);
|
|
1800
|
+
const strict = (config.gates?.preset ?? "minimal") !== "minimal";
|
|
1801
|
+
const checks = [
|
|
1802
|
+
...targets.has("test") ? [`${prefix} ${projectName2}:test`] : [],
|
|
1803
|
+
...strict && targets.has("lint") ? [`${prefix} ${projectName2}:lint`] : []
|
|
1804
|
+
];
|
|
1805
|
+
return checks.length ? checks : void 0;
|
|
1806
|
+
};
|
|
1807
|
+
var discoverNxProjects = (root, config) => {
|
|
1808
|
+
if (!existsSync6(resolve5(root, "nx.json"))) return [];
|
|
1809
|
+
const manifests = walkFiles(root, {
|
|
1810
|
+
extensions: ["project.json", "package.json"],
|
|
1811
|
+
skipDirs: NX_SCAN_SKIP,
|
|
1812
|
+
maxFiles: 1e4
|
|
1813
|
+
});
|
|
1814
|
+
const projects = /* @__PURE__ */ new Map();
|
|
1815
|
+
for (const manifest of manifests) {
|
|
1816
|
+
const json = readJsonRecord(manifest);
|
|
1817
|
+
if (!json) continue;
|
|
1818
|
+
const manifestDir = dirname3(manifest);
|
|
1819
|
+
const manifestName = basename2(manifest);
|
|
1820
|
+
const isProjectJson = manifestName === "project.json";
|
|
1821
|
+
if (!isProjectJson && manifestName !== "package.json") continue;
|
|
1822
|
+
const nx = json.nx;
|
|
1823
|
+
if (!isProjectJson && !isRecord(nx)) continue;
|
|
1824
|
+
const path = safeProjectPath(root, manifestDir, isProjectJson ? json.root : void 0);
|
|
1825
|
+
if (!path) continue;
|
|
1826
|
+
const projectPackage = isProjectJson ? readJsonRecord(resolve5(root, path, "package.json")) : void 0;
|
|
1827
|
+
const projectName2 = typeof json.name === "string" ? json.name : typeof projectPackage?.name === "string" ? projectPackage.name : basename2(path === "." ? root : path);
|
|
1828
|
+
if (!NX_PROJECT_NAME.test(projectName2)) continue;
|
|
1829
|
+
const targets = /* @__PURE__ */ new Set();
|
|
1830
|
+
const targetRecord = isProjectJson ? json.targets : isRecord(nx) ? nx.targets : void 0;
|
|
1831
|
+
if (isRecord(targetRecord)) {
|
|
1832
|
+
for (const target of Object.keys(targetRecord)) targets.add(target);
|
|
1833
|
+
}
|
|
1834
|
+
if (!isProjectJson && isRecord(json.scripts)) {
|
|
1835
|
+
for (const script of Object.keys(json.scripts)) targets.add(script);
|
|
1836
|
+
}
|
|
1837
|
+
const id = packageId(projectName2);
|
|
1838
|
+
const rank = isProjectJson ? 2 : 1;
|
|
1839
|
+
const existing = projects.get(id);
|
|
1840
|
+
if (existing && existing.path !== path) {
|
|
1841
|
+
throw new Error(
|
|
1842
|
+
`Nx project identity collision for "${id}": "${existing.name ?? id}" at "${existing.path}" and "${projectName2}" at "${path}". Use unique Nx project names.`
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
const mergedTargets = [.../* @__PURE__ */ new Set([...existing?.targets ?? [], ...targets])];
|
|
1846
|
+
const projectJsonWins = rank >= (existing?.rank ?? 0);
|
|
1847
|
+
const resolvedName = projectJsonWins ? projectName2 : existing?.name ?? projectName2;
|
|
1848
|
+
const checks = inferredChecks(root, config, resolvedName, new Set(mergedTargets));
|
|
1849
|
+
projects.set(id, {
|
|
1850
|
+
id,
|
|
1851
|
+
path,
|
|
1852
|
+
name: resolvedName,
|
|
1853
|
+
...checks ? { checks } : {},
|
|
1854
|
+
rank: projectJsonWins ? rank : existing?.rank ?? rank,
|
|
1855
|
+
targets: mergedTargets
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
return [...projects.values()].sort((a, b) => a.id.localeCompare(b.id)).map(({ rank: _rank, targets: _targets, ...project }) => project);
|
|
1859
|
+
};
|
|
1860
|
+
|
|
1655
1861
|
// src/index-builder/plugins/pnpm-monorepo.ts
|
|
1656
|
-
import { existsSync as
|
|
1657
|
-
import { basename as
|
|
1862
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
1863
|
+
import { basename as basename3, join as join6 } from "path";
|
|
1658
1864
|
|
|
1659
1865
|
// src/lib/glob-expand.ts
|
|
1660
|
-
import { existsSync as
|
|
1866
|
+
import { existsSync as existsSync7, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
1661
1867
|
import { join as join5 } from "path";
|
|
1662
1868
|
var expandWorkspaceGlobs = (root, patterns) => {
|
|
1663
1869
|
const dirs = /* @__PURE__ */ new Set();
|
|
@@ -1665,12 +1871,12 @@ var expandWorkspaceGlobs = (root, patterns) => {
|
|
|
1665
1871
|
const normalized = toPosix(pattern).replace(/\/$/, "");
|
|
1666
1872
|
if (!normalized.includes("*")) {
|
|
1667
1873
|
const abs = join5(root, normalized);
|
|
1668
|
-
if (
|
|
1874
|
+
if (existsSync7(abs)) dirs.add(toPosix(abs));
|
|
1669
1875
|
continue;
|
|
1670
1876
|
}
|
|
1671
1877
|
const star = normalized.indexOf("*");
|
|
1672
1878
|
const base = join5(root, normalized.slice(0, star).replace(/\/$/, ""));
|
|
1673
|
-
if (!
|
|
1879
|
+
if (!existsSync7(base)) continue;
|
|
1674
1880
|
for (const name of readdirSync2(base)) {
|
|
1675
1881
|
const abs = join5(base, name);
|
|
1676
1882
|
try {
|
|
@@ -1705,9 +1911,9 @@ var parsePnpmWorkspace = (yaml) => {
|
|
|
1705
1911
|
};
|
|
1706
1912
|
var readPackageJson = (dir) => {
|
|
1707
1913
|
const file = join6(dir, "package.json");
|
|
1708
|
-
if (!
|
|
1914
|
+
if (!existsSync8(file)) return null;
|
|
1709
1915
|
try {
|
|
1710
|
-
return JSON.parse(
|
|
1916
|
+
return JSON.parse(readFileSync6(file, "utf8"));
|
|
1711
1917
|
} catch {
|
|
1712
1918
|
return null;
|
|
1713
1919
|
}
|
|
@@ -1717,8 +1923,8 @@ var discoverPnpmPackages = (root, config) => {
|
|
|
1717
1923
|
let patterns = explicit;
|
|
1718
1924
|
if (!patterns?.length) {
|
|
1719
1925
|
const workspaceFile = join6(root, "pnpm-workspace.yaml");
|
|
1720
|
-
if (
|
|
1721
|
-
patterns = parsePnpmWorkspace(
|
|
1926
|
+
if (existsSync8(workspaceFile)) {
|
|
1927
|
+
patterns = parsePnpmWorkspace(readFileSync6(workspaceFile, "utf8"));
|
|
1722
1928
|
}
|
|
1723
1929
|
}
|
|
1724
1930
|
if (!patterns?.length) return [];
|
|
@@ -1728,7 +1934,7 @@ var discoverPnpmPackages = (root, config) => {
|
|
|
1728
1934
|
const pkg = readPackageJson(abs);
|
|
1729
1935
|
if (!pkg) continue;
|
|
1730
1936
|
const rel = toPosix(abs.replace(`${toPosix(root)}/`, ""));
|
|
1731
|
-
const folderId =
|
|
1937
|
+
const folderId = basename3(abs);
|
|
1732
1938
|
const id = pkg.name?.startsWith("@") ? pkg.name.split("/").pop() ?? folderId : pkg.name ?? folderId;
|
|
1733
1939
|
out.push({ id, path: rel, ...pkg.name ? { name: pkg.name } : {} });
|
|
1734
1940
|
}
|
|
@@ -1739,7 +1945,7 @@ var discoverPnpmPackages = (root, config) => {
|
|
|
1739
1945
|
var projectName = (root, config) => {
|
|
1740
1946
|
if (config.project?.name) return config.project.name;
|
|
1741
1947
|
try {
|
|
1742
|
-
const pkg = JSON.parse(
|
|
1948
|
+
const pkg = JSON.parse(readFileSync7(join7(root, "package.json"), "utf8"));
|
|
1743
1949
|
if (pkg.name) return pkg.name;
|
|
1744
1950
|
} catch {
|
|
1745
1951
|
}
|
|
@@ -1747,7 +1953,7 @@ var projectName = (root, config) => {
|
|
|
1747
1953
|
};
|
|
1748
1954
|
var existingGeneratedAt = (indexPath, contentHash) => {
|
|
1749
1955
|
try {
|
|
1750
|
-
const index = JSON.parse(
|
|
1956
|
+
const index = JSON.parse(readFileSync7(indexPath, "utf8"));
|
|
1751
1957
|
return index.contentHash === contentHash && typeof index.generatedAt === "string" ? index.generatedAt : void 0;
|
|
1752
1958
|
} catch {
|
|
1753
1959
|
return void 0;
|
|
@@ -1762,7 +1968,7 @@ var buildDocBridgeIndex = (opts) => {
|
|
|
1762
1968
|
const corpus = scanAgentCorpus(root, config);
|
|
1763
1969
|
const knowledge = corpus.map(({ absPath: _a, relPath: _r, frontmatter: _f, ...entry }) => entry);
|
|
1764
1970
|
const shouldDiscover = config.routing?.plugin === "pnpm-monorepo" || Boolean(config.routing?.options?.packages?.length) || config.routing?.plugin === "npm-workspaces" || config.routing?.plugin === "yarn-workspaces";
|
|
1765
|
-
const discovered = shouldDiscover ? discoverPnpmPackages(root, config) : [];
|
|
1971
|
+
const discovered = config.routing?.plugin === "nx" ? discoverNxProjects(root, config) : shouldDiscover ? discoverPnpmPackages(root, config) : [];
|
|
1766
1972
|
const packages = collectPackages(config, discovered, corpus);
|
|
1767
1973
|
const humanDocs = scanHumanDocs(root, config);
|
|
1768
1974
|
const { lookup, handoffs } = buildLookup(config, packages, corpus, outFile, humanDocs, root);
|
|
@@ -1784,7 +1990,7 @@ var buildDocBridgeIndex = (opts) => {
|
|
|
1784
1990
|
lookup
|
|
1785
1991
|
};
|
|
1786
1992
|
if (write) {
|
|
1787
|
-
mkdirSync(
|
|
1993
|
+
mkdirSync(dirname4(indexPath), { recursive: true });
|
|
1788
1994
|
writeFileSync(indexPath, `${JSON.stringify(index, null, 2)}
|
|
1789
1995
|
`, "utf8");
|
|
1790
1996
|
}
|
|
@@ -1807,7 +2013,7 @@ var buildDocBridgeIndex = (opts) => {
|
|
|
1807
2013
|
const capabilitiesOut = config.index?.capabilities?.outFile ?? ".doc-bridge/capabilities.json";
|
|
1808
2014
|
capabilitiesPath = join7(root, capabilitiesOut);
|
|
1809
2015
|
if (write) {
|
|
1810
|
-
mkdirSync(
|
|
2016
|
+
mkdirSync(dirname4(capabilitiesPath), { recursive: true });
|
|
1811
2017
|
writeFileSync(
|
|
1812
2018
|
capabilitiesPath,
|
|
1813
2019
|
renderCapabilitiesJson(config, index, {
|
|
@@ -1831,15 +2037,15 @@ var DOCUMENTATION_STANDARD_V1_ID = "documentation-standard-v1";
|
|
|
1831
2037
|
var DOCUMENTATION_STANDARD_V1_STATUS = "stable";
|
|
1832
2038
|
var MAX_TEXT_EVIDENCE_BYTES = 4 * 1024 * 1024;
|
|
1833
2039
|
var safePath = (root, path) => {
|
|
1834
|
-
const rootAbs =
|
|
1835
|
-
const unresolved =
|
|
1836
|
-
const unresolvedRel =
|
|
1837
|
-
if (
|
|
1838
|
-
if (!
|
|
2040
|
+
const rootAbs = realpathSync6.native(resolve6(root));
|
|
2041
|
+
const unresolved = resolve6(rootAbs, path);
|
|
2042
|
+
const unresolvedRel = relative4(rootAbs, unresolved);
|
|
2043
|
+
if (isAbsolute4(unresolvedRel) || unresolvedRel === ".." || unresolvedRel.startsWith(`..${sep5}`)) return void 0;
|
|
2044
|
+
if (!existsSync9(unresolved)) return unresolved;
|
|
1839
2045
|
try {
|
|
1840
|
-
const abs =
|
|
1841
|
-
const rel =
|
|
1842
|
-
return !
|
|
2046
|
+
const abs = realpathSync6.native(unresolved);
|
|
2047
|
+
const rel = relative4(rootAbs, abs);
|
|
2048
|
+
return !isAbsolute4(rel) && rel !== ".." && !rel.startsWith(`..${sep5}`) ? abs : void 0;
|
|
1843
2049
|
} catch {
|
|
1844
2050
|
return void 0;
|
|
1845
2051
|
}
|
|
@@ -1853,7 +2059,7 @@ var fileEvidence = (root, path, options) => {
|
|
|
1853
2059
|
evidence: { path, detail: "Path escapes the project root." }
|
|
1854
2060
|
};
|
|
1855
2061
|
}
|
|
1856
|
-
if (!
|
|
2062
|
+
if (!existsSync9(abs)) {
|
|
1857
2063
|
return { exists: false, content: "", evidence: { path, detail: "File does not exist." } };
|
|
1858
2064
|
}
|
|
1859
2065
|
try {
|
|
@@ -1868,7 +2074,7 @@ var fileEvidence = (root, path, options) => {
|
|
|
1868
2074
|
return {
|
|
1869
2075
|
exists: true,
|
|
1870
2076
|
content: "",
|
|
1871
|
-
evidence: { path: toPosix(
|
|
2077
|
+
evidence: { path: toPosix(relative4(resolve6(root), abs)) || ".", detail: "File exists and is non-empty." }
|
|
1872
2078
|
};
|
|
1873
2079
|
}
|
|
1874
2080
|
if (stat.size > MAX_TEXT_EVIDENCE_BYTES) {
|
|
@@ -1878,12 +2084,12 @@ var fileEvidence = (root, path, options) => {
|
|
|
1878
2084
|
evidence: { path, detail: `Text evidence exceeds ${MAX_TEXT_EVIDENCE_BYTES} bytes.` }
|
|
1879
2085
|
};
|
|
1880
2086
|
}
|
|
1881
|
-
const content =
|
|
2087
|
+
const content = readFileSync8(abs, "utf8");
|
|
1882
2088
|
return {
|
|
1883
2089
|
exists: content.trim().length > 0,
|
|
1884
2090
|
content,
|
|
1885
2091
|
evidence: {
|
|
1886
|
-
path: toPosix(
|
|
2092
|
+
path: toPosix(relative4(resolve6(root), abs)) || ".",
|
|
1887
2093
|
detail: content.trim().length > 0 ? "File exists and is non-empty." : "File is empty."
|
|
1888
2094
|
}
|
|
1889
2095
|
};
|
|
@@ -1918,7 +2124,7 @@ var humanDocsRule = (root, config) => {
|
|
|
1918
2124
|
passed: docs.length > 0,
|
|
1919
2125
|
message: docs.length > 0 ? `Found ${docs.length} human document(s).` : "No human documentation was discovered.",
|
|
1920
2126
|
evidence: docs.slice(0, 10).map((doc) => ({
|
|
1921
|
-
path: toPosix(
|
|
2127
|
+
path: toPosix(relative4(resolve6(root), doc.path)),
|
|
1922
2128
|
detail: `Human route: ${doc.url}`
|
|
1923
2129
|
})),
|
|
1924
2130
|
remediation: {
|
|
@@ -1929,10 +2135,10 @@ var humanDocsRule = (root, config) => {
|
|
|
1929
2135
|
};
|
|
1930
2136
|
var llmsRule = (root, config, options) => {
|
|
1931
2137
|
const llmsPath = config.index?.llmsTxt?.outFile ?? "llms.txt";
|
|
1932
|
-
const llmsKey = safePath(root, llmsPath) ??
|
|
2138
|
+
const llmsKey = safePath(root, llmsPath) ?? resolve6(root, llmsPath);
|
|
1933
2139
|
const rawSources = /* @__PURE__ */ new Map();
|
|
1934
2140
|
for (const path of options.rawSources ?? []) {
|
|
1935
|
-
const key = safePath(root, path) ??
|
|
2141
|
+
const key = safePath(root, path) ?? resolve6(root, path);
|
|
1936
2142
|
if (key !== llmsKey && !rawSources.has(key)) rawSources.set(key, path);
|
|
1937
2143
|
}
|
|
1938
2144
|
const paths = [llmsPath, ...rawSources.values()];
|
|
@@ -2184,8 +2390,8 @@ var formatDocumentationStandardText = (report) => [
|
|
|
2184
2390
|
];
|
|
2185
2391
|
|
|
2186
2392
|
// src/federation/llms.ts
|
|
2187
|
-
import { existsSync as
|
|
2188
|
-
import { resolve as
|
|
2393
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
2394
|
+
import { resolve as resolve7 } from "path";
|
|
2189
2395
|
|
|
2190
2396
|
// src/query/search.ts
|
|
2191
2397
|
var tokenize = (value) => value.toLowerCase().split(/[^a-z0-9@/_-]+/).filter((t) => t.length >= 2);
|
|
@@ -2314,9 +2520,9 @@ var defaultFetchText = async (url) => {
|
|
|
2314
2520
|
var sourceText = async (root, source, fetchText) => {
|
|
2315
2521
|
try {
|
|
2316
2522
|
if (/^https?:\/\//.test(source)) return await fetchText(source);
|
|
2317
|
-
const path =
|
|
2318
|
-
if (!
|
|
2319
|
-
return
|
|
2523
|
+
const path = resolve7(root, source);
|
|
2524
|
+
if (!existsSync10(path)) return null;
|
|
2525
|
+
return readFileSync9(path, "utf8");
|
|
2320
2526
|
} catch {
|
|
2321
2527
|
return null;
|
|
2322
2528
|
}
|
|
@@ -2401,11 +2607,11 @@ var retrieveHybridChunks = async (root, config, index, query, options = {}) => {
|
|
|
2401
2607
|
};
|
|
2402
2608
|
|
|
2403
2609
|
// src/gates/run-gates.ts
|
|
2404
|
-
import { readFileSync as
|
|
2610
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
2405
2611
|
|
|
2406
2612
|
// src/query/load-index.ts
|
|
2407
|
-
import { existsSync as
|
|
2408
|
-
import { join as join8, resolve as
|
|
2613
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
|
|
2614
|
+
import { join as join8, resolve as resolve8 } from "path";
|
|
2409
2615
|
|
|
2410
2616
|
// src/schemas/agent-handoff.ts
|
|
2411
2617
|
import { z as z3 } from "zod";
|
|
@@ -2621,8 +2827,8 @@ var IndexNotFoundError = class extends Error {
|
|
|
2621
2827
|
var indexFilePath = (root, config) => join8(root, config.index?.outFile ?? ".doc-bridge/index.json");
|
|
2622
2828
|
var loadDocBridgeIndex = (root, config) => {
|
|
2623
2829
|
const path = indexFilePath(root, config);
|
|
2624
|
-
if (!
|
|
2625
|
-
const raw = JSON.parse(
|
|
2830
|
+
if (!existsSync11(path)) throw new IndexNotFoundError(path);
|
|
2831
|
+
const raw = JSON.parse(readFileSync10(path, "utf8"));
|
|
2626
2832
|
return parseDocBridgeIndex(raw);
|
|
2627
2833
|
};
|
|
2628
2834
|
|
|
@@ -2697,7 +2903,7 @@ var runOkfTypeGate = (root, config) => {
|
|
|
2697
2903
|
const required = config.corpus.agent.okf?.requireType ?? config.gates?.preset === "strict";
|
|
2698
2904
|
if (!required) return { id: "okf-type", ok: true, message: "OKF type frontmatter not required" };
|
|
2699
2905
|
const allowed = config.corpus.agent.okf?.allowedTypes;
|
|
2700
|
-
const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({ path: doc.path, type: frontmatterType(
|
|
2906
|
+
const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({ path: doc.path, type: frontmatterType(readFileSync11(doc.absPath, "utf8")) })).filter((doc) => !doc.type || allowed && !allowed.includes(doc.type));
|
|
2701
2907
|
if (bad.length) {
|
|
2702
2908
|
return {
|
|
2703
2909
|
id: "okf-type",
|
|
@@ -2724,10 +2930,10 @@ var DOCS_STYLE_RULES = {
|
|
|
2724
2930
|
"playbook-okf-soft": ["title", "no-stale-wording"],
|
|
2725
2931
|
"title-only": ["title"]
|
|
2726
2932
|
};
|
|
2727
|
-
var
|
|
2933
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2728
2934
|
var docsStyleOptions = (config) => {
|
|
2729
2935
|
const raw = config.gates?.options?.["docs-style"];
|
|
2730
|
-
if (!
|
|
2936
|
+
if (!isRecord2(raw)) {
|
|
2731
2937
|
if (config.gates?.preset === "playbook") {
|
|
2732
2938
|
return { profile: "playbook-okf-soft", required: DOCS_STYLE_RULES["playbook-okf-soft"] };
|
|
2733
2939
|
}
|
|
@@ -2771,7 +2977,7 @@ var runDocsStyleGate = (root, config) => {
|
|
|
2771
2977
|
}
|
|
2772
2978
|
const bad = scanAgentCorpus(root, config).filter((doc) => doc.path !== config.corpus.agent.index).map((doc) => ({
|
|
2773
2979
|
path: doc.path,
|
|
2774
|
-
missing: missingStyleRules(
|
|
2980
|
+
missing: missingStyleRules(readFileSync11(doc.absPath, "utf8"), required)
|
|
2775
2981
|
})).filter((doc) => doc.missing.length > 0);
|
|
2776
2982
|
if (bad.length) {
|
|
2777
2983
|
return {
|
|
@@ -3056,7 +3262,7 @@ var resolveIntelligenceRuntime = async (config) => {
|
|
|
3056
3262
|
var defaultVectorStorePath = (root) => join9(root, ".doc-bridge", "vectors");
|
|
3057
3263
|
|
|
3058
3264
|
// src/intelligence/rag.ts
|
|
3059
|
-
import { readFileSync as
|
|
3265
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
3060
3266
|
import { join as join10 } from "path";
|
|
3061
3267
|
var loadDocuments = (root, index, sources) => {
|
|
3062
3268
|
const includeAgent = sources.includes("agent") || sources.length === 0;
|
|
@@ -3066,7 +3272,7 @@ var loadDocuments = (root, index, sources) => {
|
|
|
3066
3272
|
const abs = join10(root, entry.path);
|
|
3067
3273
|
let content = "";
|
|
3068
3274
|
try {
|
|
3069
|
-
content =
|
|
3275
|
+
content = readFileSync12(abs, "utf8");
|
|
3070
3276
|
} catch {
|
|
3071
3277
|
content = [entry.title, entry.description].filter(Boolean).join("\n\n");
|
|
3072
3278
|
}
|
|
@@ -3219,15 +3425,15 @@ var startInkChat = async (root, config, index) => {
|
|
|
3219
3425
|
};
|
|
3220
3426
|
|
|
3221
3427
|
// src/memory/ingest.ts
|
|
3222
|
-
import { existsSync as
|
|
3428
|
+
import { existsSync as existsSync12, readFileSync as readFileSync13 } from "fs";
|
|
3223
3429
|
import { join as join11 } from "path";
|
|
3224
3430
|
var memoryFact = (raw, id) => firstParagraph(raw) ?? firstHeading(raw) ?? id;
|
|
3225
3431
|
var relativePath = (root, abs) => toPosix(abs).replace(`${toPosix(root)}/`, "");
|
|
3226
3432
|
var ingestMarkdownDir = (root, dir, source, confidence) => {
|
|
3227
|
-
if (!
|
|
3433
|
+
if (!existsSync12(dir)) return [];
|
|
3228
3434
|
return walkFiles(dir, { extensions: [".md", ".mdc"] }).map((abs) => {
|
|
3229
3435
|
const rel = relativePath(root, abs);
|
|
3230
|
-
const raw =
|
|
3436
|
+
const raw = readFileSync13(abs, "utf8");
|
|
3231
3437
|
const id = slugFromPath(rel);
|
|
3232
3438
|
return {
|
|
3233
3439
|
schemaVersion: 1,
|
|
@@ -3332,7 +3538,7 @@ var draftMemoryPromotion = (classifications) => {
|
|
|
3332
3538
|
|
|
3333
3539
|
// src/memory/github-pr.ts
|
|
3334
3540
|
import { execFileSync, spawnSync } from "child_process";
|
|
3335
|
-
import { existsSync as
|
|
3541
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
3336
3542
|
import { join as join12 } from "path";
|
|
3337
3543
|
var run = (cmd, args, cwd) => {
|
|
3338
3544
|
const result = spawnSync(cmd, [...args], { cwd, encoding: "utf8" });
|
|
@@ -3380,7 +3586,7 @@ var promoteMemoryToGithubPr = (root, draft, options = {}) => {
|
|
|
3380
3586
|
message: `Wrote draft to ${relDraft}. Run the printed git/gh commands to open a draft PR.`
|
|
3381
3587
|
};
|
|
3382
3588
|
}
|
|
3383
|
-
if (!
|
|
3589
|
+
if (!existsSync13(join12(root, ".git"))) {
|
|
3384
3590
|
return {
|
|
3385
3591
|
ok: false,
|
|
3386
3592
|
dryRun: false,
|
|
@@ -3483,22 +3689,23 @@ ${auth.out}`
|
|
|
3483
3689
|
};
|
|
3484
3690
|
|
|
3485
3691
|
// src/index-builder/watch-index.ts
|
|
3486
|
-
import { existsSync as
|
|
3487
|
-
import { dirname as
|
|
3692
|
+
import { existsSync as existsSync14, watch } from "fs";
|
|
3693
|
+
import { dirname as dirname5, resolve as resolve9 } from "path";
|
|
3488
3694
|
var WATCH_PATTERN = /\.(md|mdx|json|ya?ml|mdc)$/i;
|
|
3695
|
+
var NX_MANIFEST_PATTERN = /(^|[/\\])(project|package)\.json$/i;
|
|
3489
3696
|
var collectWatchRoots = (root, config, configPath) => {
|
|
3490
3697
|
const roots = /* @__PURE__ */ new Set();
|
|
3491
|
-
roots.add(
|
|
3698
|
+
roots.add(resolve9(root, config.corpus.agent.root));
|
|
3492
3699
|
const humanSources = config.corpus.human ? Array.isArray(config.corpus.human) ? config.corpus.human : [config.corpus.human] : [];
|
|
3493
3700
|
for (const source of humanSources) {
|
|
3494
3701
|
const humanOpts = source.options ?? {};
|
|
3495
|
-
for (const key of ["contentDir", "docsDir", "root"]) {
|
|
3702
|
+
for (const key of ["contentDir", "docsDir", "root", "srcDir"]) {
|
|
3496
3703
|
const value = humanOpts[key];
|
|
3497
|
-
if (typeof value === "string" && value.length) roots.add(
|
|
3704
|
+
if (typeof value === "string" && value.length) roots.add(resolve9(root, value));
|
|
3498
3705
|
}
|
|
3499
3706
|
}
|
|
3500
|
-
if (configPath) roots.add(
|
|
3501
|
-
return [...roots].filter((dir) =>
|
|
3707
|
+
if (configPath) roots.add(dirname5(resolve9(configPath)));
|
|
3708
|
+
return [...roots].filter((dir) => existsSync14(dir));
|
|
3502
3709
|
};
|
|
3503
3710
|
var watchDocBridgeIndex = (opts) => {
|
|
3504
3711
|
const debounceMs = opts.debounceMs ?? 350;
|
|
@@ -3539,8 +3746,15 @@ var watchDocBridgeIndex = (opts) => {
|
|
|
3539
3746
|
rebuild();
|
|
3540
3747
|
});
|
|
3541
3748
|
}
|
|
3542
|
-
const
|
|
3543
|
-
if (
|
|
3749
|
+
const nxRoot = resolve9(opts.root);
|
|
3750
|
+
if (opts.config.routing?.plugin === "nx" && existsSync14(nxRoot)) {
|
|
3751
|
+
watch(nxRoot, { recursive: true }, (_event, filename) => {
|
|
3752
|
+
if (!filename || !NX_MANIFEST_PATTERN.test(filename)) return;
|
|
3753
|
+
rebuild();
|
|
3754
|
+
});
|
|
3755
|
+
}
|
|
3756
|
+
const configDir = resolve9(opts.root);
|
|
3757
|
+
if (existsSync14(configDir)) {
|
|
3544
3758
|
watch(configDir, (_event, filename) => {
|
|
3545
3759
|
if (!filename || !/doc-bridge\.config/.test(filename)) return;
|
|
3546
3760
|
rebuild();
|
|
@@ -3716,15 +3930,15 @@ var docBridgePatternPayload = () => ({
|
|
|
3716
3930
|
});
|
|
3717
3931
|
|
|
3718
3932
|
// src/cli/demo.ts
|
|
3719
|
-
import { cpSync, existsSync as
|
|
3933
|
+
import { cpSync, existsSync as existsSync16, mkdtempSync, readFileSync as readFileSync15, rmSync } from "fs";
|
|
3720
3934
|
import { tmpdir } from "os";
|
|
3721
|
-
import { dirname as
|
|
3935
|
+
import { dirname as dirname7, join as join15, resolve as resolve11 } from "path";
|
|
3722
3936
|
import { fileURLToPath } from "url";
|
|
3723
3937
|
|
|
3724
3938
|
// src/mcp/install.ts
|
|
3725
|
-
import { existsSync as
|
|
3939
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync3, readFileSync as readFileSync14, writeFileSync as writeFileSync3 } from "fs";
|
|
3726
3940
|
import { homedir } from "os";
|
|
3727
|
-
import { dirname as
|
|
3941
|
+
import { dirname as dirname6, join as join14, resolve as resolve10 } from "path";
|
|
3728
3942
|
var SERVER_NAME = "ak-docs";
|
|
3729
3943
|
var mcpServerEntry = (root) => ({
|
|
3730
3944
|
command: "npx",
|
|
@@ -3732,26 +3946,26 @@ var mcpServerEntry = (root) => ({
|
|
|
3732
3946
|
cwd: root
|
|
3733
3947
|
});
|
|
3734
3948
|
var readJson = (path) => {
|
|
3735
|
-
if (!
|
|
3949
|
+
if (!existsSync15(path)) return {};
|
|
3736
3950
|
try {
|
|
3737
|
-
const parsed = JSON.parse(
|
|
3951
|
+
const parsed = JSON.parse(readFileSync14(path, "utf8"));
|
|
3738
3952
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
3739
3953
|
} catch {
|
|
3740
3954
|
return {};
|
|
3741
3955
|
}
|
|
3742
3956
|
};
|
|
3743
3957
|
var writeJson = (path, value) => {
|
|
3744
|
-
mkdirSync3(
|
|
3958
|
+
mkdirSync3(dirname6(path), { recursive: true });
|
|
3745
3959
|
writeFileSync3(path, `${JSON.stringify(value, null, 2)}
|
|
3746
3960
|
`, "utf8");
|
|
3747
3961
|
};
|
|
3748
3962
|
var resolveTargetPath = (target, root) => {
|
|
3749
|
-
if (target === "cursor") return
|
|
3963
|
+
if (target === "cursor") return resolve10(root, ".cursor", "mcp.json");
|
|
3750
3964
|
return join14(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
3751
3965
|
};
|
|
3752
3966
|
var installMcpConfig = (root, target) => {
|
|
3753
3967
|
const configPath = resolveTargetPath(target, root);
|
|
3754
|
-
const created = !
|
|
3968
|
+
const created = !existsSync15(configPath);
|
|
3755
3969
|
const existing = readJson(configPath);
|
|
3756
3970
|
const servers = existing.mcpServers && typeof existing.mcpServers === "object" && !Array.isArray(existing.mcpServers) ? { ...existing.mcpServers } : {};
|
|
3757
3971
|
servers[SERVER_NAME] = mcpServerEntry(root);
|
|
@@ -3776,7 +3990,7 @@ var installMcpConfig = (root, target) => {
|
|
|
3776
3990
|
var mcpSnippet = (root) => JSON.stringify({ mcpServers: { [SERVER_NAME]: mcpServerEntry(root) } }, null, 2);
|
|
3777
3991
|
|
|
3778
3992
|
// src/cli/demo.ts
|
|
3779
|
-
var packageRoot =
|
|
3993
|
+
var packageRoot = resolve11(dirname7(fileURLToPath(import.meta.url)), "..", "..");
|
|
3780
3994
|
var fixturePath = (fixture) => {
|
|
3781
3995
|
if (fixture === "monorepo") {
|
|
3782
3996
|
return join15(packageRoot, "examples", "demo-monorepo");
|
|
@@ -3797,10 +4011,10 @@ var formatHandoffText = (handoff) => {
|
|
|
3797
4011
|
var runDemo = (root, config, fixture = "example", options = {}) => {
|
|
3798
4012
|
const targetPackage = fixture === "monorepo" ? "auth" : "example";
|
|
3799
4013
|
const fixtureDir = fixturePath(fixture);
|
|
3800
|
-
if (options.copyFixture &&
|
|
4014
|
+
if (options.copyFixture && existsSync16(fixtureDir)) {
|
|
3801
4015
|
for (const rel of ["doc-bridge.config.json", "docs", "packages", "pnpm-workspace.yaml", "package.json"]) {
|
|
3802
4016
|
const src = join15(fixtureDir, rel);
|
|
3803
|
-
if (!
|
|
4017
|
+
if (!existsSync16(src)) continue;
|
|
3804
4018
|
const dest = join15(root, rel);
|
|
3805
4019
|
cpSync(src, dest, { recursive: true });
|
|
3806
4020
|
}
|
|
@@ -3859,11 +4073,11 @@ var withDemoWorkspace = (fixture, fn) => {
|
|
|
3859
4073
|
const dir = mkdtempSync(join15(tmpdir(), "ak-docs-demo-"));
|
|
3860
4074
|
try {
|
|
3861
4075
|
const fixtureDir = fixturePath(fixture);
|
|
3862
|
-
if (!
|
|
4076
|
+
if (!existsSync16(fixtureDir)) {
|
|
3863
4077
|
throw new Error(`Demo fixture "${fixture}" not found at ${fixtureDir}`);
|
|
3864
4078
|
}
|
|
3865
4079
|
cpSync(fixtureDir, dir, { recursive: true });
|
|
3866
|
-
const config = JSON.parse(
|
|
4080
|
+
const config = JSON.parse(readFileSync15(join15(dir, "doc-bridge.config.json"), "utf8"));
|
|
3867
4081
|
return fn(dir, config);
|
|
3868
4082
|
} finally {
|
|
3869
4083
|
rmSync(dir, { recursive: true, force: true });
|
|
@@ -4074,8 +4288,8 @@ var formatDoctorText = (report) => {
|
|
|
4074
4288
|
};
|
|
4075
4289
|
|
|
4076
4290
|
// src/mcp/server.ts
|
|
4077
|
-
import { readFileSync as
|
|
4078
|
-
import { relative as
|
|
4291
|
+
import { readFileSync as readFileSync16, realpathSync as realpathSync7 } from "fs";
|
|
4292
|
+
import { relative as relative5, resolve as resolve12 } from "path";
|
|
4079
4293
|
import { z as z6, ZodError } from "zod";
|
|
4080
4294
|
var MCP_TOOLS = [
|
|
4081
4295
|
{
|
|
@@ -4197,12 +4411,12 @@ var findDocPath = (index, args) => {
|
|
|
4197
4411
|
return doc.path;
|
|
4198
4412
|
};
|
|
4199
4413
|
var resolveDocPath = (root, relPath) => {
|
|
4200
|
-
const rootAbs =
|
|
4201
|
-
const unresolved =
|
|
4202
|
-
const unresolvedRel =
|
|
4414
|
+
const rootAbs = realpathSync7.native(root);
|
|
4415
|
+
const unresolved = resolve12(rootAbs, relPath);
|
|
4416
|
+
const unresolvedRel = relative5(rootAbs, unresolved);
|
|
4203
4417
|
if (unresolvedRel.startsWith("..")) throw new Error("doc.get path escapes project root");
|
|
4204
|
-
const abs =
|
|
4205
|
-
const rel =
|
|
4418
|
+
const abs = realpathSync7.native(unresolved);
|
|
4419
|
+
const rel = relative5(rootAbs, abs);
|
|
4206
4420
|
if (rel.startsWith("..")) throw new Error("doc.get path escapes project root");
|
|
4207
4421
|
return abs;
|
|
4208
4422
|
};
|
|
@@ -4236,7 +4450,7 @@ var handleMcpRequest = (ctx, request) => {
|
|
|
4236
4450
|
}
|
|
4237
4451
|
if (name === "doc.get") {
|
|
4238
4452
|
const relPath = findDocPath(index(), parseToolArgs("doc.get", DocGetArgsSchema, args));
|
|
4239
|
-
return textResult(
|
|
4453
|
+
return textResult(readFileSync16(resolveDocPath(ctx.root, relPath), "utf8"));
|
|
4240
4454
|
}
|
|
4241
4455
|
if (name === "gate.status") return textResult(runGates(ctx.root, ctx.config));
|
|
4242
4456
|
if (name === "retriever.query") {
|
|
@@ -4505,12 +4719,12 @@ var readIndexedDoc = (root, config, idOrPath) => {
|
|
|
4505
4719
|
const index = loadDocBridgeIndex(root, config);
|
|
4506
4720
|
const entry = index.knowledge.find((doc) => doc.id === idOrPath || doc.path === idOrPath);
|
|
4507
4721
|
if (!entry) throw new Error(`Unknown indexed doc "${idOrPath}". Try: search ${idOrPath}`);
|
|
4508
|
-
const abs =
|
|
4509
|
-
const rootAbs =
|
|
4722
|
+
const abs = resolve13(root, entry.path);
|
|
4723
|
+
const rootAbs = resolve13(root);
|
|
4510
4724
|
if (abs !== rootAbs && !abs.startsWith(`${rootAbs}/`)) {
|
|
4511
4725
|
throw new Error(`Indexed doc escapes project root: ${entry.path}`);
|
|
4512
4726
|
}
|
|
4513
|
-
return
|
|
4727
|
+
return readFileSync17(abs, "utf8");
|
|
4514
4728
|
};
|
|
4515
4729
|
var runAskRepl = async (root, config) => {
|
|
4516
4730
|
const index = loadDocBridgeIndex(root, config);
|
|
@@ -4586,8 +4800,8 @@ var diagnosticNextCommands = (config, result) => {
|
|
|
4586
4800
|
];
|
|
4587
4801
|
};
|
|
4588
4802
|
var writeIfMissing = (path, contents) => {
|
|
4589
|
-
if (
|
|
4590
|
-
mkdirSync5(
|
|
4803
|
+
if (existsSync17(path)) return false;
|
|
4804
|
+
mkdirSync5(dirname8(path), { recursive: true });
|
|
4591
4805
|
writeFileSync4(path, contents, "utf8");
|
|
4592
4806
|
return true;
|
|
4593
4807
|
};
|
|
@@ -4691,7 +4905,7 @@ var scaffoldWorkspaceDocs = (root, config) => {
|
|
|
4691
4905
|
const created = [];
|
|
4692
4906
|
const skipped = [];
|
|
4693
4907
|
for (const pkg of discoverPnpmPackages(root, config)) {
|
|
4694
|
-
const path =
|
|
4908
|
+
const path = resolve13(root, config.corpus.agent.root, "packages", `${pkg.id}.md`);
|
|
4695
4909
|
if (writeIfMissing(path, workspaceDocDraft(pkg.id, pkg.path))) created.push(path);
|
|
4696
4910
|
else skipped.push(path);
|
|
4697
4911
|
}
|
|
@@ -4701,11 +4915,11 @@ var bootstrapAgentDocs = (root, config) => {
|
|
|
4701
4915
|
const created = [];
|
|
4702
4916
|
const skipped = [];
|
|
4703
4917
|
for (const doc of scanHumanDocRecords(root, config)) {
|
|
4704
|
-
const raw =
|
|
4918
|
+
const raw = readFileSync17(doc.path, "utf8");
|
|
4705
4919
|
const body = raw.replace(/^---\n[\s\S]*?\n---\n?/, "");
|
|
4706
4920
|
const title = firstHeading(body) ?? doc.id;
|
|
4707
4921
|
const description = firstParagraph(body);
|
|
4708
|
-
const draftPath =
|
|
4922
|
+
const draftPath = resolve13(root, config.corpus.agent.root, "human", `${doc.id}.md`);
|
|
4709
4923
|
const draft = [
|
|
4710
4924
|
"---",
|
|
4711
4925
|
"type: knowledge",
|
|
@@ -4769,8 +4983,8 @@ var runCli = (argv) => {
|
|
|
4769
4983
|
return 1;
|
|
4770
4984
|
}
|
|
4771
4985
|
try {
|
|
4772
|
-
const abs =
|
|
4773
|
-
const raw =
|
|
4986
|
+
const abs = resolve13(file);
|
|
4987
|
+
const raw = readFileSync17(abs, "utf8");
|
|
4774
4988
|
const handoff = parseAgentHandoff(JSON.parse(raw));
|
|
4775
4989
|
writeJson2({ ok: true, handoff });
|
|
4776
4990
|
return 0;
|
|
@@ -4783,10 +4997,10 @@ var runCli = (argv) => {
|
|
|
4783
4997
|
if (command === "init") {
|
|
4784
4998
|
const root = process.cwd();
|
|
4785
4999
|
const withDemo = flags.has("--demo") || !flags.has("--no-demo");
|
|
4786
|
-
const configFile =
|
|
4787
|
-
const docsIndex =
|
|
4788
|
-
const exampleDoc =
|
|
4789
|
-
const agentsMd =
|
|
5000
|
+
const configFile = resolve13(root, configPath ?? "doc-bridge.config.json");
|
|
5001
|
+
const docsIndex = resolve13(root, "docs/for-agents/INDEX.md");
|
|
5002
|
+
const exampleDoc = resolve13(root, "docs/for-agents/packages/example.md");
|
|
5003
|
+
const agentsMd = resolve13(root, "AGENTS.md");
|
|
4790
5004
|
const configWritten = writeIfMissing(configFile, initConfigContents(configFile, withDemo));
|
|
4791
5005
|
const indexWritten = writeIfMissing(
|
|
4792
5006
|
docsIndex,
|
|
@@ -4794,7 +5008,7 @@ var runCli = (argv) => {
|
|
|
4794
5008
|
);
|
|
4795
5009
|
const exampleWritten = withDemo ? writeIfMissing(exampleDoc, exampleAgentDoc) : false;
|
|
4796
5010
|
const agentsWritten = writeIfMissing(agentsMd, agentsMdSnippet);
|
|
4797
|
-
if (withDemo) writeIfMissing(
|
|
5011
|
+
if (withDemo) writeIfMissing(resolve13(root, "src/.gitkeep"), "");
|
|
4798
5012
|
const scaffold = flags.has("--scaffold-workspaces") ? scaffoldWorkspaceDocs(root, loadProject(configFile).config) : void 0;
|
|
4799
5013
|
writeJson2({
|
|
4800
5014
|
ok: true,
|
|
@@ -5037,8 +5251,8 @@ var runCli = (argv) => {
|
|
|
5037
5251
|
const { config, root } = loadProject(configPath);
|
|
5038
5252
|
const report = runDoctor(root, config);
|
|
5039
5253
|
if (flags.has("--write-badge")) {
|
|
5040
|
-
const badgePath =
|
|
5041
|
-
mkdirSync5(
|
|
5254
|
+
const badgePath = resolve13(root, ".doc-bridge", "coverage-badge.json");
|
|
5255
|
+
mkdirSync5(dirname8(badgePath), { recursive: true });
|
|
5042
5256
|
writeFileSync4(badgePath, `${formatDoctorBadgeJson(report.badge)}
|
|
5043
5257
|
`, "utf8");
|
|
5044
5258
|
}
|