@farming-labs/docs 0.2.106 → 0.2.107

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.
@@ -40,6 +40,7 @@ const DEFAULT_COMPRESSION_BASE_URL = "https://api.farming-labs.dev";
40
40
  const DEFAULT_COMPRESSION_MODEL = "docs-cloud-compress-v1";
41
41
  const DEFAULT_COMPRESSION_AGGRESSIVENESS = .3;
42
42
  const DEFAULT_DOCS_CLOUD_API_KEY_ENV = "DOCS_CLOUD_API_KEY";
43
+ const MAX_COMPRESSION_INPUT_CHARACTERS = 2e5;
43
44
  const INDEX_PAGE_BASENAMES = new Set([
44
45
  "index",
45
46
  "page",
@@ -76,6 +77,10 @@ function parseAgentCompactArgs(argv) {
76
77
  parsed.dryRun = true;
77
78
  continue;
78
79
  }
80
+ if (arg === "--check") {
81
+ parsed.check = true;
82
+ continue;
83
+ }
79
84
  if (arg === "--changed") {
80
85
  parsed.changed = true;
81
86
  continue;
@@ -414,7 +419,7 @@ function inspectAgentCompactionState(page, target, defaults) {
414
419
  tokenBudget
415
420
  };
416
421
  }
417
- function protectForCompression(input) {
422
+ function protectForCompression(input, protectInlineCode = true) {
418
423
  const segments = [];
419
424
  const stash = (value) => {
420
425
  const token = `__DOCS_SAFE_${segments.length}__`;
@@ -424,14 +429,21 @@ function protectForCompression(input) {
424
429
  let result = input;
425
430
  result = result.replace(/```[\s\S]*?```/g, stash);
426
431
  result = result.replace(/\[[^\]]+\]\([^)]+\)/g, stash);
427
- result = result.replace(/`[^`\n]+`/g, stash);
432
+ if (protectInlineCode) result = result.replace(/`[^`\n]+`/g, stash);
428
433
  result = result.replace(/^(URL|Description|Related):[^\n]*$/gm, stash);
429
434
  result = result.replace(/https?:\/\/[^\s)]+/g, stash);
430
435
  for (let index = 0; index < segments.length; index += 1) result = result.replace(`__DOCS_SAFE_${index}__`, `<docs_safe>${segments[index]}</docs_safe>`);
431
436
  return result;
432
437
  }
438
+ function buildCompressionInput(input) {
439
+ const fullyProtected = protectForCompression(input);
440
+ if (fullyProtected.length <= MAX_COMPRESSION_INPUT_CHARACTERS) return fullyProtected;
441
+ const withoutInlineCodeProtection = protectForCompression(input, false);
442
+ if (withoutInlineCodeProtection.length <= MAX_COMPRESSION_INPUT_CHARACTERS) return withoutInlineCodeProtection;
443
+ throw new Error(`Docs Cloud compression input is ${withoutInlineCodeProtection.length} characters after adaptive protection; the maximum is ${MAX_COMPRESSION_INPUT_CHARACTERS}. Split or shorten the source page before compacting it.`);
444
+ }
433
445
  function sanitizeCompressedOutput(output) {
434
- return output.replace(/<\/?docs_safe>/g, "");
446
+ return output.replace(/<\/?docs_safe>/g, "").replace(/[ \t]+$/gm, "");
435
447
  }
436
448
  async function compressDocument(input, options) {
437
449
  const apiKey = resolveCompressionApiKey(options.apiKey, options.apiKeyEnv);
@@ -440,7 +452,7 @@ async function compressDocument(input, options) {
440
452
  if (aggressiveness < 0 || aggressiveness > 1) throw new Error("Aggressiveness must be between 0.0 and 1.0.");
441
453
  const payload = {
442
454
  model: options.model ?? DEFAULT_COMPRESSION_MODEL,
443
- input: protectForCompression(input),
455
+ input: buildCompressionInput(input),
444
456
  compression_settings: {
445
457
  aggressiveness,
446
458
  ...options.maxOutputTokens !== void 0 ? { max_output_tokens: options.maxOutputTokens } : {},
@@ -515,7 +527,8 @@ async function compactAgentDocs(options = {}) {
515
527
  if (resolvedOptions.all && resolvedOptions.pages && resolvedOptions.pages.length > 0) throw new Error("Use either --all or specific page arguments, not both.");
516
528
  if (resolvedOptions.includeMissing && !resolvedOptions.stale) throw new Error("Use --include-missing together with --stale.");
517
529
  const requestedPages = resolvedOptions.pages?.filter((value) => value.trim().length > 0) ?? [];
518
- 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.");
530
+ if (resolvedOptions.check && (resolvedOptions.all || resolvedOptions.stale || resolvedOptions.changed || resolvedOptions.includeMissing || resolvedOptions.dryRun || requestedPages.length > 0)) throw new Error("Use --check by itself; it inspects every compactable docs page without writing.");
531
+ if (!resolvedOptions.all && requestedPages.length === 0 && !resolvedOptions.stale && !resolvedOptions.changed && !resolvedOptions.check) throw new Error("Pass --all, --changed, --stale, or at least one docs page slug/path to compact.");
519
532
  const pages = await createFilesystemDocsMcpSource({
520
533
  rootDir,
521
534
  entry,
@@ -523,7 +536,7 @@ async function compactAgentDocs(options = {}) {
523
536
  siteTitle
524
537
  }).getPages();
525
538
  if (pages.length === 0) throw new Error(`No docs content was found under ${contentDir}.`);
526
- 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);
539
+ const selectedPages = resolveSelectedPages(pages, scanDocsPageTargets(rootDir, contentDir, entry), entry, requestedPages, resolvedOptions.all === true || resolvedOptions.check === true || resolvedOptions.stale === true && requestedPages.length === 0 || resolvedOptions.changed === true && requestedPages.length === 0);
527
540
  const filteredPages = resolvedOptions.changed ? filterChangedPages(rootDir, contentDir, selectedPages) : selectedPages;
528
541
  if (filteredPages.length === 0) {
529
542
  if (resolvedOptions.changed) {
@@ -532,6 +545,27 @@ async function compactAgentDocs(options = {}) {
532
545
  }
533
546
  throw new Error("No compactable docs pages matched the request.");
534
547
  }
548
+ if (resolvedOptions.check) {
549
+ let fresh = 0;
550
+ let stale = 0;
551
+ let modified = 0;
552
+ let unknown = 0;
553
+ let requiredMissing = 0;
554
+ let optionalMissing = 0;
555
+ for (const { page, target } of filteredPages) {
556
+ const state = inspectAgentCompactionState(page, target, resolvedOptions);
557
+ if (state.status === "fresh") fresh += 1;
558
+ else if (state.status === "stale") stale += 1;
559
+ else if (state.status === "modified" || state.status === "stale-modified") modified += 1;
560
+ else if (state.status === "unknown") unknown += 1;
561
+ else if (state.tokenBudget !== void 0) requiredMissing += 1;
562
+ else optionalMissing += 1;
563
+ }
564
+ const summary = `${fresh} fresh, ${stale} stale, ${modified} modified, ${unknown} unknown, ${requiredMissing} required missing, and ${optionalMissing} optional missing`;
565
+ if (stale > 0 || requiredMissing > 0) throw new Error(`Agent compaction freshness check failed: ${summary}. Run docs agent compact --stale --include-missing, then review generated changes.`);
566
+ console.log(pc.green(`Agent compaction freshness check passed: ${summary}.`));
567
+ return;
568
+ }
535
569
  let created = 0;
536
570
  let overwritten = 0;
537
571
  let processed = 0;
@@ -598,6 +632,7 @@ ${pc.dim("Examples:")}
598
632
  ${pc.cyan("npx @farming-labs/docs@latest agent compact --changed")}
599
633
  ${pc.cyan("npx @farming-labs/docs@latest agent compact --stale")}
600
634
  ${pc.cyan("npx @farming-labs/docs@latest agent compact --stale --include-missing")}
635
+ ${pc.cyan("npx @farming-labs/docs@latest agent compact --check")}
601
636
 
602
637
  ${pc.dim("Per-page override:")}
603
638
  Add ${pc.cyan("agent.tokenBudget")} to a page frontmatter block to override the compact output target for that page.
@@ -608,6 +643,7 @@ ${pc.dim("Options:")}
608
643
  ${pc.cyan("--changed")} Compact only docs pages changed in the current git working tree
609
644
  ${pc.cyan("--stale")} Re-compact only stale generated agent.md files
610
645
  ${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")}
646
+ ${pc.cyan("--check")} Check generated agent.md freshness without an API key, network request, or file write
611
647
  ${pc.cyan("--config <path>")} Use a custom docs config path instead of ${pc.dim("docs.config.ts[x]")}
612
648
  ${pc.cyan("--api-key <key>")} Use an API key directly; prefer ${pc.dim("cloud.apiKey.env")}
613
649
  ${pc.cyan("--api-key-env <name>")} Env var name for the Docs Cloud API key; prefer ${pc.dim("cloud.apiKey.env")}
@@ -11,5 +11,6 @@ declare function parseCommandAlias(rawCommand?: string): {
11
11
  };
12
12
  /** Parse flags like --template next, --name my-docs, --theme concrete, --entry docs, --framework astro (exported for tests). */
13
13
  declare function parseFlags(argv: string[]): Record<string, string | boolean | undefined>;
14
+ declare function printAgentHelp(): void;
14
15
  //#endregion
15
- export { formatCliError, parseCommandAlias, parseFlags };
16
+ export { formatCliError, parseCommandAlias, parseFlags, printAgentHelp };
@@ -154,7 +154,8 @@ async function main() {
154
154
  } else if (parsedCommand.command === "mcp") {
155
155
  const { runMcp } = await import("../mcp-DsjWxF7g.mjs");
156
156
  await runMcp(mcpOptions);
157
- } else if (parsedCommand.command === "agent" && subcommand === "feedback") {
157
+ } else if (parsedCommand.command === "agent" && (subcommand === "--help" || subcommand === "-h")) printAgentHelp();
158
+ else if (parsedCommand.command === "agent" && subcommand === "feedback") {
158
159
  const { parseAgentFeedbackImproveArgs, printAgentFeedbackImproveHelp, runAgentFeedbackImprove } = await import("../feedback-DWVUMrxy.mjs");
159
160
  const feedbackOptions = parseAgentFeedbackImproveArgs(args.slice(2));
160
161
  if (feedbackOptions.help) {
@@ -179,7 +180,7 @@ async function main() {
179
180
  }
180
181
  await runAgentMaintenancePropose(proposeOptions);
181
182
  } else if (parsedCommand.command === "agent" && subcommand === "compact") {
182
- const { compactAgentDocs, parseAgentCompactArgs, printAgentCompactHelp } = await import("../agent-CaCWThBY.mjs").then((n) => n.t);
183
+ const { compactAgentDocs, parseAgentCompactArgs, printAgentCompactHelp } = await import("../agent-B0eRMIyt.mjs").then((n) => n.t);
183
184
  const agentCompactOptions = parseAgentCompactArgs(args.slice(2));
184
185
  if (agentCompactOptions.help) {
185
186
  printAgentCompactHelp();
@@ -197,16 +198,7 @@ async function main() {
197
198
  } else if (parsedCommand.command === "agent") {
198
199
  console.error(pc.red(`Unknown agent subcommand: ${subcommand ?? "(missing)"}`));
199
200
  console.error();
200
- const { printAgentCompactHelp } = await import("../agent-CaCWThBY.mjs").then((n) => n.t);
201
- const { printAgentExportHelp } = await import("../agent-export-GcTZPLfB.mjs");
202
- const { printAgentFeedbackImproveHelp } = await import("../feedback-DWVUMrxy.mjs");
203
- const { printAgentFeedbackEvaluationsHelp } = await import("../feedback-evals-k0sFDdms.mjs");
204
- const { printAgentMaintenanceProposeHelp } = await import("../propose-DJOiHu9Y.mjs");
205
- printAgentCompactHelp();
206
- printAgentExportHelp();
207
- printAgentFeedbackImproveHelp();
208
- printAgentFeedbackEvaluationsHelp();
209
- printAgentMaintenanceProposeHelp();
201
+ printAgentHelp();
210
202
  process.exit(1);
211
203
  } else if (parsedCommand.command === "agents" && subcommand === "generate") {
212
204
  const { generateAgents, parseAgentsGenerateArgs, printAgentsGenerateHelp } = await import("../agents-e1SYT64z.mjs");
@@ -240,7 +232,7 @@ async function main() {
240
232
  printSkillScaffoldHelp();
241
233
  process.exit(1);
242
234
  } else if (parsedCommand.command === "doctor") {
243
- const { parseDoctorArgs, printDoctorHelp, runDoctor } = await import("../doctor-CtK1CRPj.mjs");
235
+ const { parseDoctorArgs, printDoctorHelp, runDoctor } = await import("../doctor-CPGUlDVt.mjs");
244
236
  const doctorOptions = parseDoctorArgs(args.slice(1));
245
237
  if (doctorOptions.help) {
246
238
  printDoctorHelp();
@@ -248,7 +240,7 @@ async function main() {
248
240
  }
249
241
  await runDoctor(doctorOptions);
250
242
  } else if (parsedCommand.command === "review") {
251
- const { parseReviewArgs, printReviewHelp, runReview } = await import("../review-XI9FXeos.mjs");
243
+ const { parseReviewArgs, printReviewHelp, runReview } = await import("../review-BvjSFiD_.mjs");
252
244
  const reviewOptions = parseReviewArgs(args.slice(1));
253
245
  if (reviewOptions.help) {
254
246
  printReviewHelp();
@@ -334,6 +326,22 @@ async function main() {
334
326
  process.exit(1);
335
327
  }
336
328
  }
329
+ function printAgentHelp() {
330
+ console.log(`${pc.bold("docs agent")} — Agent documentation utilities
331
+
332
+ Usage:
333
+ docs agent <command> [options]
334
+
335
+ Commands:
336
+ ${pc.cyan("compact")} Generate or refresh page-level ${pc.dim("agent.md")} files
337
+ ${pc.cyan("export")} Export or check a static Agent Bundle
338
+ ${pc.cyan("feedback")} Cluster recurring agent feedback into improvement drafts
339
+ ${pc.cyan("feedback-evals")} Create reviewed evaluation candidates and regression baselines
340
+ ${pc.cyan("propose")} Combine recurring signals into maintenance proposals
341
+
342
+ Run ${pc.cyan("docs agent <command> --help")} for command-specific options.
343
+ `);
344
+ }
337
345
  function printHelp() {
338
346
  console.log(`
339
347
  ${pc.bold("@farming-labs/docs")} — Documentation framework CLI
@@ -415,6 +423,7 @@ ${pc.dim("Options for agent compact:")}
415
423
  ${pc.cyan("agent compact --all")} Compact every folder-based docs page
416
424
  ${pc.cyan("agent compact --changed")} Compact only docs pages changed in the current git working tree
417
425
  ${pc.cyan("agent compact --stale")} Refresh only stale generated ${pc.dim("agent.md")} files
426
+ ${pc.cyan("agent compact --check")} Fail when generated ${pc.dim("agent.md")} files are stale or required files are missing
418
427
  ${pc.cyan("--page <slug|path>")} Repeatable explicit page flag; positional page args work too
419
428
  ${pc.cyan("--include-missing")} With ${pc.cyan("--stale")}, also create explicit or token-budget pages missing ${pc.dim("agent.md")}
420
429
  ${pc.cyan("--api-key <key>")} Use an API key directly; prefer ${pc.dim("cloud.apiKey.env")}
@@ -550,4 +559,4 @@ main().catch((err) => {
550
559
  });
551
560
 
552
561
  //#endregion
553
- export { formatCliError, parseCommandAlias, parseFlags };
562
+ export { formatCliError, parseCommandAlias, parseFlags, printAgentHelp };
@@ -1,4 +1,4 @@
1
- import { i as scanDocsPageTargets, n as compactAgentDocs, r as inspectAgentCompactionState } from "./agent-CaCWThBY.mjs";
1
+ import { i as scanDocsPageTargets, n as compactAgentDocs, r as inspectAgentCompactionState } from "./agent-B0eRMIyt.mjs";
2
2
  import { f as PAGE_AGENT_CONTRACT_FIELDS } from "./markdown-sections-BKy4labo.mjs";
3
3
  import { d as httpLinkHeaderHasTargetRelation, f as AGENT_SKILL_ARCHIVE_MAX_UNCOMPRESSED_BYTES, p as readAgentSkillDocumentFromTar } from "./prompt-references-1Wce71c7.mjs";
4
4
  import { A as buildDocsAgentDiscoverySpec, At as DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE, F as buildDocsMcpEndpointCandidates, Gn as getDocsMcpProtectedResourceMetadataRoutes, Jn as isDocsMcpOAuthScopeToken, Lt as resolveDocsSitemapConfig, M as buildDocsConfigMap, Qn as normalizeDocsMcpAuthorizationServerUrls, S as DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE, T as DOCS_CONFIG_MAP_TOP_LEVEL_KEYS, Un as DEFAULT_MCP_WELL_KNOWN_ROUTE, Vn as DEFAULT_MCP_PUBLIC_ROUTE, c as DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, cr as resolveDocsOkfTrustMetadata, h as DEFAULT_LLMS_FULL_TXT_ROUTE, i as DEFAULT_AGENT_FEEDBACK_ROUTE, jt as DEFAULT_SITEMAP_XML_ROUTE, kt as DEFAULT_SITEMAP_MD_ROUTE, l as DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE, mn as resolveAskAISearchRequestConfig, n as DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE, sr as resolveDocsOkfConfig, t as DEFAULT_AGENTS_MD_ROUTE, v as DEFAULT_LLMS_TXT_ROUTE, x as DEFAULT_SKILL_MD_ROUTE } from "./agent-DCTGj6J7.mjs";
@@ -16,7 +16,7 @@ import "./code-blocks-D90CCJFs.mjs";
16
16
  import "./server.mjs";
17
17
  import { _ as resolveDocsContentDir, d as readNavTitle, g as resolveDocsConfigPath, h as readTopLevelStringProperty, l as readBooleanProperty, r as extractTopLevelConfigObject, s as loadDocsConfigModuleResultWithProjectEnv, t as extractNestedObjectLiteral, v as resolveDocsProjectRoot } from "./config-DrZ3fXgf.mjs";
18
18
  import { t as detectFramework } from "./utils-Cc1SrVza.mjs";
19
- import { i as createAgentUsefulnessPagesFromMcp, n as analyzeAgentSurfaceDrift, r as analyzeAgentUsefulness, t as resolveGoldenEvaluationInput } from "./golden-evaluations-De4KwoYr.mjs";
19
+ import { i as createAgentUsefulnessPagesFromMcp, n as analyzeAgentSurfaceDrift, r as analyzeAgentUsefulness, t as resolveGoldenEvaluationInput } from "./golden-evaluations-Bnlljxq3.mjs";
20
20
  import { t as analyzeConfiguredAgentSkillsProgressiveDisclosure } from "./agent-skills-progressive-disclosure-DL-q4JZo.mjs";
21
21
  import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
22
22
  import path from "node:path";
@@ -43,6 +43,9 @@ const DEFAULT_DOCS_COMMANDS = [
43
43
  "skills scaffold",
44
44
  "agent compact",
45
45
  "agent export",
46
+ "agent feedback",
47
+ "agent feedback-evals",
48
+ "agent propose",
46
49
  "agents generate",
47
50
  "doctor",
48
51
  "review",
@@ -9,7 +9,7 @@ import { createFilesystemDocsMcpSource, getDocsConfigSchema, resolveDocsMcpConfi
9
9
  import "./code-blocks-D90CCJFs.mjs";
10
10
  import { _ as resolveDocsContentDir, g as resolveDocsConfigPath, h as readTopLevelStringProperty, s as loadDocsConfigModuleResultWithProjectEnv } from "./config-DrZ3fXgf.mjs";
11
11
  import { t as detectFramework } from "./utils-Cc1SrVza.mjs";
12
- import { a as extractAgentBlocks, i as createAgentUsefulnessPagesFromMcp, n as analyzeAgentSurfaceDrift, r as analyzeAgentUsefulness, t as resolveGoldenEvaluationInput } from "./golden-evaluations-De4KwoYr.mjs";
12
+ import { a as extractAgentBlocks, i as createAgentUsefulnessPagesFromMcp, n as analyzeAgentSurfaceDrift, r as analyzeAgentUsefulness, t as resolveGoldenEvaluationInput } from "./golden-evaluations-Bnlljxq3.mjs";
13
13
  import { t as analyzeConfiguredAgentSkillsProgressiveDisclosure } from "./agent-skills-progressive-disclosure-DL-q4JZo.mjs";
14
14
  import matter from "gray-matter";
15
15
  import { existsSync, lstatSync, readFileSync, readdirSync } from "node:fs";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/docs",
3
- "version": "0.2.106",
3
+ "version": "0.2.107",
4
4
  "description": "Modern, flexible MDX-based docs framework — core types, config, and CLI",
5
5
  "keywords": [
6
6
  "docs",