@farming-labs/docs 0.1.52 → 0.1.54
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.
|
@@ -9,6 +9,7 @@ import matter from "gray-matter";
|
|
|
9
9
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
10
10
|
import path from "node:path";
|
|
11
11
|
import pc from "picocolors";
|
|
12
|
+
import { execFileSync } from "node:child_process";
|
|
12
13
|
|
|
13
14
|
//#region src/cli/agent.ts
|
|
14
15
|
const DEFAULT_TTC_BASE_URL = "https://api.thetokencompany.com";
|
|
@@ -50,6 +51,10 @@ function parseAgentCompactArgs(argv) {
|
|
|
50
51
|
parsed.dryRun = true;
|
|
51
52
|
continue;
|
|
52
53
|
}
|
|
54
|
+
if (arg === "--changed") {
|
|
55
|
+
parsed.changed = true;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
53
58
|
if (arg === "--stale") {
|
|
54
59
|
parsed.stale = true;
|
|
55
60
|
continue;
|
|
@@ -175,6 +180,62 @@ function resolveCompressionEndpoint(rawBaseUrl) {
|
|
|
175
180
|
if (/\/v1\/compress\/?$/i.test(baseUrl)) return baseUrl.replace(/\/+$/, "");
|
|
176
181
|
return `${baseUrl.replace(/\/+$/, "")}/v1/compress`;
|
|
177
182
|
}
|
|
183
|
+
function runGitCommand(rootDir, args) {
|
|
184
|
+
return execFileSync("git", args, {
|
|
185
|
+
cwd: rootDir,
|
|
186
|
+
encoding: "utf-8"
|
|
187
|
+
}).trim();
|
|
188
|
+
}
|
|
189
|
+
function normalizeGitRelativePath(value) {
|
|
190
|
+
return value.replace(/\\/g, "/").replace(/^\.\/+/, "").replace(/^\/+/, "");
|
|
191
|
+
}
|
|
192
|
+
function listGitChangedFiles(rootDir, contentDir) {
|
|
193
|
+
let gitRoot;
|
|
194
|
+
try {
|
|
195
|
+
gitRoot = runGitCommand(rootDir, ["rev-parse", "--show-toplevel"]);
|
|
196
|
+
} catch {
|
|
197
|
+
throw new Error("Use --changed inside a git repository.");
|
|
198
|
+
}
|
|
199
|
+
const contentDirAbs = path.resolve(rootDir, contentDir);
|
|
200
|
+
const relativeContentDir = normalizeGitRelativePath(path.relative(gitRoot, contentDirAbs));
|
|
201
|
+
if (relativeContentDir.startsWith("../")) throw new Error("Configured contentDir must live inside the current git repository for --changed.");
|
|
202
|
+
const pathspec = relativeContentDir || ".";
|
|
203
|
+
const changedFiles = /* @__PURE__ */ new Set();
|
|
204
|
+
const commands = [
|
|
205
|
+
[
|
|
206
|
+
"diff",
|
|
207
|
+
"--name-only",
|
|
208
|
+
"--",
|
|
209
|
+
pathspec
|
|
210
|
+
],
|
|
211
|
+
[
|
|
212
|
+
"diff",
|
|
213
|
+
"--name-only",
|
|
214
|
+
"--cached",
|
|
215
|
+
"--",
|
|
216
|
+
pathspec
|
|
217
|
+
],
|
|
218
|
+
[
|
|
219
|
+
"ls-files",
|
|
220
|
+
"--others",
|
|
221
|
+
"--exclude-standard",
|
|
222
|
+
"--",
|
|
223
|
+
pathspec
|
|
224
|
+
]
|
|
225
|
+
];
|
|
226
|
+
for (const args of commands) {
|
|
227
|
+
const output = runGitCommand(gitRoot, args);
|
|
228
|
+
if (!output) continue;
|
|
229
|
+
for (const line of output.split("\n")) {
|
|
230
|
+
const normalized = normalizeGitRelativePath(line.trim());
|
|
231
|
+
if (!normalized) continue;
|
|
232
|
+
const absolutePath = path.resolve(gitRoot, normalized);
|
|
233
|
+
const relativeToRoot = normalizeGitRelativePath(path.relative(rootDir, absolutePath));
|
|
234
|
+
if (relativeToRoot && !relativeToRoot.startsWith("../")) changedFiles.add(relativeToRoot);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return changedFiles;
|
|
238
|
+
}
|
|
178
239
|
function resolveCompressionApiKey(explicitApiKey, explicitApiKeyEnv) {
|
|
179
240
|
const candidateKeys = [
|
|
180
241
|
explicitApiKeyEnv,
|
|
@@ -261,6 +322,13 @@ function readCurrentAgentDocument(target) {
|
|
|
261
322
|
if (!target.hasAgentFile || !existsSync(target.agentPath)) return void 0;
|
|
262
323
|
return parseGeneratedAgentDocument(readFileSync(target.agentPath, "utf-8"));
|
|
263
324
|
}
|
|
325
|
+
function shouldCompactChangedAgentFile(target) {
|
|
326
|
+
const currentDocument = readCurrentAgentDocument(target);
|
|
327
|
+
if (!currentDocument) return false;
|
|
328
|
+
if (!currentDocument.provenance) return true;
|
|
329
|
+
if (currentDocument.provenance.sourceKind !== "agent-md") return false;
|
|
330
|
+
return hashGeneratedAgentContent(currentDocument.content) !== currentDocument.provenance.outputHash;
|
|
331
|
+
}
|
|
264
332
|
function resolveSourceKindForCompaction(target, currentDocument) {
|
|
265
333
|
if (!target.hasAgentFile) return "resolved-page";
|
|
266
334
|
if (currentDocument?.provenance?.sourceKind === "resolved-page") return "resolved-page";
|
|
@@ -397,6 +465,15 @@ function resolveSelectedPages(pages, targets, entry, requested, includeAll) {
|
|
|
397
465
|
}
|
|
398
466
|
return resolved;
|
|
399
467
|
}
|
|
468
|
+
function filterChangedPages(rootDir, contentDir, selectedPages) {
|
|
469
|
+
const changedFiles = listGitChangedFiles(rootDir, contentDir);
|
|
470
|
+
return selectedPages.filter(({ target }) => {
|
|
471
|
+
const relativePagePath = normalizeGitRelativePath(path.relative(rootDir, target.pagePath));
|
|
472
|
+
if (changedFiles.has(relativePagePath)) return true;
|
|
473
|
+
const relativeAgentPath = normalizeGitRelativePath(path.relative(rootDir, target.agentPath));
|
|
474
|
+
return changedFiles.has(relativeAgentPath) && shouldCompactChangedAgentFile(target);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
400
477
|
async function compactAgentDocs(options = {}) {
|
|
401
478
|
const rootDir = process.cwd();
|
|
402
479
|
const loadedEnv = loadProjectEnv(rootDir);
|
|
@@ -410,7 +487,7 @@ async function compactAgentDocs(options = {}) {
|
|
|
410
487
|
if (resolvedOptions.all && resolvedOptions.pages && resolvedOptions.pages.length > 0) throw new Error("Use either --all or specific page arguments, not both.");
|
|
411
488
|
if (resolvedOptions.includeMissing && !resolvedOptions.stale) throw new Error("Use --include-missing together with --stale.");
|
|
412
489
|
const requestedPages = resolvedOptions.pages?.filter((value) => value.trim().length > 0) ?? [];
|
|
413
|
-
if (!resolvedOptions.all && requestedPages.length === 0 && !resolvedOptions.stale) throw new Error("Pass --all, --stale, or at least one docs page slug/path to compact.");
|
|
490
|
+
if (!resolvedOptions.all && requestedPages.length === 0 && !resolvedOptions.stale && !resolvedOptions.changed) throw new Error("Pass --all, --changed, --stale, or at least one docs page slug/path to compact.");
|
|
414
491
|
const pages = await createFilesystemDocsMcpSource({
|
|
415
492
|
rootDir,
|
|
416
493
|
entry,
|
|
@@ -418,8 +495,15 @@ async function compactAgentDocs(options = {}) {
|
|
|
418
495
|
siteTitle
|
|
419
496
|
}).getPages();
|
|
420
497
|
if (pages.length === 0) throw new Error(`No docs content was found under ${contentDir}.`);
|
|
421
|
-
const selectedPages = resolveSelectedPages(pages, scanDocsPageTargets(rootDir, contentDir, entry), entry, requestedPages, resolvedOptions.all === true || resolvedOptions.stale === true && requestedPages.length === 0);
|
|
422
|
-
|
|
498
|
+
const selectedPages = resolveSelectedPages(pages, scanDocsPageTargets(rootDir, contentDir, entry), entry, requestedPages, resolvedOptions.all === true || resolvedOptions.stale === true && requestedPages.length === 0 || resolvedOptions.changed === true && requestedPages.length === 0);
|
|
499
|
+
const filteredPages = resolvedOptions.changed ? filterChangedPages(rootDir, contentDir, selectedPages) : selectedPages;
|
|
500
|
+
if (filteredPages.length === 0) {
|
|
501
|
+
if (resolvedOptions.changed) {
|
|
502
|
+
console.log(pc.green("No changed docs pages needed compaction."));
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
throw new Error("No compactable docs pages matched the request.");
|
|
506
|
+
}
|
|
423
507
|
let created = 0;
|
|
424
508
|
let overwritten = 0;
|
|
425
509
|
let processed = 0;
|
|
@@ -428,7 +512,7 @@ async function compactAgentDocs(options = {}) {
|
|
|
428
512
|
let skippedUnknown = 0;
|
|
429
513
|
let skippedMissing = 0;
|
|
430
514
|
const requestedExplicitPages = requestedPages.length > 0;
|
|
431
|
-
for (const { page, target } of
|
|
515
|
+
for (const { page, target } of filteredPages) {
|
|
432
516
|
const state = inspectAgentCompactionState(page, target, resolvedOptions);
|
|
433
517
|
if (resolvedOptions.stale) {
|
|
434
518
|
if (state.status === "fresh") {
|
|
@@ -461,7 +545,7 @@ async function compactAgentDocs(options = {}) {
|
|
|
461
545
|
else created += 1;
|
|
462
546
|
processed += 1;
|
|
463
547
|
}
|
|
464
|
-
if (resolvedOptions.dryRun) processed =
|
|
548
|
+
if (resolvedOptions.dryRun) processed = filteredPages.length - skippedFresh - skippedModified - skippedUnknown - skippedMissing;
|
|
465
549
|
if (resolvedOptions.stale && processed === 0) {
|
|
466
550
|
console.log(pc.green("No stale generated agent.md files needed updates."));
|
|
467
551
|
if (skippedFresh + skippedModified + skippedUnknown + skippedMissing > 0) console.log(pc.dim(`Skipped ${skippedFresh} fresh, ${skippedModified} modified, ${skippedUnknown} unknown, and ${skippedMissing} missing page${skippedFresh + skippedModified + skippedUnknown + skippedMissing === 1 ? "" : "s"}.`));
|
|
@@ -483,6 +567,7 @@ ${pc.dim("Examples:")}
|
|
|
483
567
|
${pc.cyan("npx @farming-labs/docs@latest agent compact /docs/installation")}
|
|
484
568
|
${pc.cyan("npx @farming-labs/docs@latest agent compact --page installation --page configuration")}
|
|
485
569
|
${pc.cyan("npx @farming-labs/docs@latest agent compact --all")}
|
|
570
|
+
${pc.cyan("npx @farming-labs/docs@latest agent compact --changed")}
|
|
486
571
|
${pc.cyan("npx @farming-labs/docs@latest agent compact --stale")}
|
|
487
572
|
${pc.cyan("npx @farming-labs/docs@latest agent compact --stale --include-missing")}
|
|
488
573
|
|
|
@@ -492,6 +577,7 @@ ${pc.dim("Per-page override:")}
|
|
|
492
577
|
${pc.dim("Options:")}
|
|
493
578
|
${pc.cyan("--all")} Compact every folder-based docs page under the configured contentDir
|
|
494
579
|
${pc.cyan("--page <slug|path>")} Add a page explicitly (repeatable); positional page args work too
|
|
580
|
+
${pc.cyan("--changed")} Compact only docs pages changed in the current git working tree
|
|
495
581
|
${pc.cyan("--stale")} Re-compact only stale generated agent.md files
|
|
496
582
|
${pc.cyan("--include-missing")} With ${pc.cyan("--stale")}, also create missing agent.md files for explicit pages or pages that define ${pc.cyan("agent.tokenBudget")}
|
|
497
583
|
${pc.cyan("--config <path>")} Use a custom docs config path instead of ${pc.dim("docs.config.ts[x]")}
|
package/dist/cli/index.mjs
CHANGED
|
@@ -75,7 +75,7 @@ async function main() {
|
|
|
75
75
|
const { runMcp } = await import("../mcp-C-TmMrdw.mjs");
|
|
76
76
|
await runMcp(mcpOptions);
|
|
77
77
|
} else if (parsedCommand.command === "agent" && subcommand === "compact") {
|
|
78
|
-
const { compactAgentDocs, parseAgentCompactArgs, printAgentCompactHelp } = await import("../agent-
|
|
78
|
+
const { compactAgentDocs, parseAgentCompactArgs, printAgentCompactHelp } = await import("../agent-B-6iQbS2.mjs");
|
|
79
79
|
const agentCompactOptions = parseAgentCompactArgs(args.slice(2));
|
|
80
80
|
if (agentCompactOptions.help) {
|
|
81
81
|
printAgentCompactHelp();
|
|
@@ -85,11 +85,11 @@ async function main() {
|
|
|
85
85
|
} else if (parsedCommand.command === "agent") {
|
|
86
86
|
console.error(pc.red(`Unknown agent subcommand: ${subcommand ?? "(missing)"}`));
|
|
87
87
|
console.error();
|
|
88
|
-
const { printAgentCompactHelp } = await import("../agent-
|
|
88
|
+
const { printAgentCompactHelp } = await import("../agent-B-6iQbS2.mjs");
|
|
89
89
|
printAgentCompactHelp();
|
|
90
90
|
process.exit(1);
|
|
91
91
|
} else if (parsedCommand.command === "doctor") {
|
|
92
|
-
const { parseDoctorArgs, printDoctorHelp, runDoctor } = await import("../doctor-
|
|
92
|
+
const { parseDoctorArgs, printDoctorHelp, runDoctor } = await import("../doctor-BiY_aSS1.mjs");
|
|
93
93
|
const doctorOptions = parseDoctorArgs(args.slice(1));
|
|
94
94
|
if (doctorOptions.help) {
|
|
95
95
|
printDoctorHelp();
|
|
@@ -152,6 +152,7 @@ ${pc.dim("Options for mcp:")}
|
|
|
152
152
|
${pc.dim("Options for agent compact:")}
|
|
153
153
|
${pc.cyan("agent compact <page...>")} Compact pages and write sibling ${pc.dim("agent.md")} files
|
|
154
154
|
${pc.cyan("agent compact --all")} Compact every folder-based docs page
|
|
155
|
+
${pc.cyan("agent compact --changed")} Compact only docs pages changed in the current git working tree
|
|
155
156
|
${pc.cyan("agent compact --stale")} Refresh only stale generated ${pc.dim("agent.md")} files
|
|
156
157
|
${pc.cyan("--page <slug|path>")} Repeatable explicit page flag; positional page args work too
|
|
157
158
|
${pc.cyan("--include-missing")} With ${pc.cyan("--stale")}, also create explicit or token-budget pages missing ${pc.dim("agent.md")}
|
|
@@ -3,7 +3,7 @@ import "./api-reference-GDAEzQn1.mjs";
|
|
|
3
3
|
import { createFilesystemDocsMcpSource, resolveDocsMcpConfig } from "./mcp.mjs";
|
|
4
4
|
import "./server.mjs";
|
|
5
5
|
import { a as loadProjectEnv, c as readNavTitle, d as readTopLevelStringProperty, f as resolveDocsConfigPath, i as loadDocsConfigModule, o as readBooleanProperty, p as resolveDocsContentDir, r as extractTopLevelConfigObject, t as extractNestedObjectLiteral } from "./config-Si-yUfM_.mjs";
|
|
6
|
-
import { inspectAgentCompactionState, scanDocsPageTargets } from "./agent-
|
|
6
|
+
import { inspectAgentCompactionState, scanDocsPageTargets } from "./agent-B-6iQbS2.mjs";
|
|
7
7
|
import { t as detectFramework } from "./utils-CpTFbAiS.mjs";
|
|
8
8
|
import { existsSync, lstatSync, readFileSync, readdirSync } from "node:fs";
|
|
9
9
|
import path from "node:path";
|