@farming-labs/docs 0.2.87 → 0.2.89

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.
@@ -1,6 +1,7 @@
1
1
  import { An as normalizeAgentFramework, Cn as findDocsAudienceMdxTags, En as resolveDocsAudienceMdxContent, Nn as normalizeAgentVersion, kn as agentVersionConstraintsOverlap } from "./agent-CTOUI2BK.mjs";
2
2
  import { _ as hasStructuredPageAgentContract, v as normalizePageAgentFrontmatter } from "./markdown-sections-7OoA7ylx.mjs";
3
3
  import { t as extractCodeBlocksFromMarkdown } from "./code-blocks-0wjOsqdJ.mjs";
4
+ import { isMap, isScalar, isSeq, parseDocument } from "yaml";
4
5
  import { existsSync, lstatSync, readFileSync, readdirSync } from "node:fs";
5
6
  import path from "node:path";
6
7
 
@@ -39,6 +40,7 @@ const DEFAULT_DOCS_COMMANDS = [
39
40
  "cloud deploy",
40
41
  "cloud preview",
41
42
  "mcp",
43
+ "skills scaffold",
42
44
  "agent compact",
43
45
  "agent export",
44
46
  "agents generate",
@@ -519,7 +521,7 @@ function analyzePage(page) {
519
521
  sourcePath: page.sourcePath,
520
522
  route: page.route
521
523
  });
522
- const shellCommands = collectPageCommands(page, agent, projectedSource);
524
+ const shellCommands = collectPageCommands(page, agent);
523
525
  return {
524
526
  page,
525
527
  agent,
@@ -698,7 +700,8 @@ function analyzeCommand(options) {
698
700
  findings.push(commandFinding(options, {
699
701
  code: "command-cwd-outside-root",
700
702
  severity: "error",
701
- message: `Command working directory resolves outside the project root: ${commandCwd}`
703
+ message: `Command working directory resolves outside the project root: ${commandCwd}`,
704
+ proposedCorrection: `Set cwd to an existing project-relative directory inside the docs project instead of ${JSON.stringify(commandCwd)}.`
702
705
  }));
703
706
  return commandAnalysis(findings);
704
707
  }
@@ -706,7 +709,8 @@ function analyzeCommand(options) {
706
709
  findings.push(commandFinding(options, {
707
710
  code: "command-cwd-missing",
708
711
  severity: "error",
709
- message: `Command working directory does not exist: ${commandCwd}`
712
+ message: `Command working directory does not exist: ${commandCwd}`,
713
+ proposedCorrection: `Create ${JSON.stringify(commandCwd)} or change cwd to an existing project-relative directory.`
710
714
  }));
711
715
  return commandAnalysis(findings);
712
716
  }
@@ -714,7 +718,8 @@ function analyzeCommand(options) {
714
718
  findings.push(commandFinding(options, {
715
719
  code: "command-unverified",
716
720
  severity: "suggestion",
717
- message: "Compound commands, redirections, and shell expansions are not executed or inferred; this command is unverified."
721
+ message: "Compound commands, redirections, and shell expansions are not executed or inferred; this command is unverified.",
722
+ proposedCorrection: "Split the shell expression into one independently verifiable command per line and document any redirection or expansion as a separate step."
718
723
  }));
719
724
  return commandAnalysis(findings);
720
725
  }
@@ -724,7 +729,8 @@ function analyzeCommand(options) {
724
729
  if (commandPackageManager && expectedPackageManager && commandPackageManager !== expectedPackageManager) findings.push(commandFinding(options, {
725
730
  code: "command-package-manager-mismatch",
726
731
  severity: "warning",
727
- message: `Command uses ${commandPackageManager}, but ${expectedPackageManager} is expected for this project or code block.`
732
+ message: `Command uses ${commandPackageManager}, but ${expectedPackageManager} is expected for this project or code block.`,
733
+ proposedCorrection: `Rewrite this command using ${expectedPackageManager}, or explicitly mark the example as a ${commandPackageManager} alternative when that is intentional.`
728
734
  }));
729
735
  const workspaceSelection = readWorkspaceSelection(tokens, commandPackageManager);
730
736
  const workspaceResolution = resolveWorkspaceSelection(workspaceSelection, options.packageManifests, options.rootDir, options.workspaceRoot);
@@ -733,7 +739,8 @@ function analyzeCommand(options) {
733
739
  findings.push(commandFinding(options, {
734
740
  code: "command-unverified",
735
741
  severity: "suggestion",
736
- message: `Workspace selector could not be resolved statically (${selectors}); this command is unverified.`
742
+ message: `Workspace selector could not be resolved statically (${selectors}); this command is unverified.`,
743
+ proposedCorrection: "Replace the selector with an exact workspace package name or path declared by the nearest workspace manifest."
737
744
  }));
738
745
  }
739
746
  const script = readPackageScript(tokens);
@@ -742,13 +749,15 @@ function analyzeCommand(options) {
742
749
  if (workspaceResolution.status === "none" && packageJsons.length === 0) findings.push(commandFinding(options, {
743
750
  code: "command-unverified",
744
751
  severity: "suggestion",
745
- message: `No package.json could be found for package script "${script}"; this command is unverified.`
752
+ message: `No package.json could be found for package script "${script}"; this command is unverified.`,
753
+ proposedCorrection: "Set cwd to the package that owns this script, or add a package.json with the documented script."
746
754
  }));
747
755
  for (const packageJson of packageJsons) if (packageJson.scripts.has(script)) verificationEstablished = true;
748
756
  else findings.push(commandFinding(options, {
749
757
  code: "command-script-missing",
750
758
  severity: "error",
751
- message: `Command references package script "${script}", but that script is not defined in ${packageJson.relativePath}.`
759
+ message: `Command references package script "${script}", but that script is not defined in ${packageJson.relativePath}.`,
760
+ proposedCorrection: `Add a ${JSON.stringify(script)} script to ${packageJson.relativePath}, or replace the command with an existing script from that file.`
752
761
  }));
753
762
  }
754
763
  const docsCommand = readDocsCommand(tokens);
@@ -756,13 +765,15 @@ function analyzeCommand(options) {
756
765
  else findings.push(commandFinding(options, {
757
766
  code: "command-cli-unknown",
758
767
  severity: "error",
759
- message: `Command references an unknown docs CLI command: docs ${docsCommand}`
768
+ message: `Command references an unknown docs CLI command: docs ${docsCommand}`,
769
+ proposedCorrection: `Replace "docs ${docsCommand}" with the intended supported command listed by "docs --help".`
760
770
  }));
761
771
  if (isStaticallyKnownPackageManagerCommand(tokens) || isVersionProbe(tokens) || isStaticallyValidCurlCommand(tokens) || isStaticallyValidShellBuiltin(tokens, resolvedCwd, options.rootDir) || isStaticallyValidAgentToolCommand(tokens)) verificationEstablished = true;
762
772
  if (!verificationEstablished && findings.length === 0) findings.push(commandFinding(options, {
763
773
  code: "command-unverified",
764
774
  severity: "suggestion",
765
- message: "Command form could not be verified statically; this command is unverified."
775
+ message: "Command form could not be verified statically; this command is unverified.",
776
+ proposedCorrection: "Use a documented package-manager or docs CLI command, or configure explicit executable-example validation for this command."
766
777
  }));
767
778
  return commandAnalysis(findings);
768
779
  }
@@ -780,16 +791,97 @@ function commandAnalysis(findings) {
780
791
  status: "healthy"
781
792
  };
782
793
  }
783
- function collectPageCommands(page, agent, projectedSource) {
794
+ function collectContractCommandLocations(source) {
795
+ const empty = () => ({
796
+ commands: [],
797
+ verification: []
798
+ });
799
+ const opening = source.match(/^---[^\S\r\n]*\r?\n/);
800
+ if (!opening) return empty();
801
+ const frontmatterOffset = opening[0].length;
802
+ const remainder = source.slice(frontmatterOffset);
803
+ const closing = /(?:^|\r?\n)---[^\S\r\n]*(?:\r?\n|$)/.exec(remainder);
804
+ if (!closing) return empty();
805
+ try {
806
+ const document = parseDocument(remainder.slice(0, closing.index), { uniqueKeys: true });
807
+ if (document.errors.length > 0 || !isMap(document.contents)) return empty();
808
+ const agent = document.contents.get("agent", true);
809
+ if (!isMap(agent)) return empty();
810
+ return {
811
+ commands: collectContractSequenceLocations(agent.get("commands", true), source, frontmatterOffset),
812
+ verification: collectContractSequenceLocations(agent.get("verification", true), source, frontmatterOffset)
813
+ };
814
+ } catch {
815
+ return empty();
816
+ }
817
+ }
818
+ function collectContractSequenceLocations(value, source, frontmatterOffset) {
819
+ if (!isSeq(value)) return [];
820
+ const locations = [];
821
+ for (const item of value.items) {
822
+ const run = isScalar(item) ? item : isMap(item) ? item.get("run", true) : void 0;
823
+ if (!isScalar(run) || typeof run.value !== "string") continue;
824
+ const location = contractScalarLocation(run, source, frontmatterOffset);
825
+ if (location) locations.push(location);
826
+ }
827
+ return locations;
828
+ }
829
+ function contractScalarLocation(scalar, source, frontmatterOffset) {
830
+ const relativeOffset = scalar.range?.[0];
831
+ if (typeof scalar.value !== "string" || relativeOffset === void 0) return void 0;
832
+ const absoluteOffset = frontmatterOffset + relativeOffset;
833
+ return {
834
+ run: scalar.value,
835
+ line: source.slice(0, absoluteOffset).split(/\r?\n/).length
836
+ };
837
+ }
838
+ function claimContractCommandLine(locations, command, claimedLines) {
839
+ const location = locations.find((candidate) => candidate.run === command && !claimedLines.has(candidate.line));
840
+ if (!location) return void 0;
841
+ claimedLines.add(location.line);
842
+ return location.line;
843
+ }
844
+ function preserveLineBreaksOnly(value) {
845
+ return value.replace(/[^\r\n]/g, " ");
846
+ }
847
+ /** Agent projection used for command discovery that keeps original source line numbers stable. */
848
+ function projectAgentCommandSource(source) {
849
+ const tags = findDocsAudienceMdxTags(source);
850
+ if (tags.length === 0) return source;
851
+ const scopes = [];
852
+ let output = "";
853
+ let cursor = 0;
854
+ const visible = () => scopes.every((scope) => scope.only !== "human");
855
+ for (const tag of tags) {
856
+ const activeScope = scopes.at(-1);
857
+ if (tag.closing && activeScope?.name !== tag.name) continue;
858
+ const content = source.slice(cursor, tag.index);
859
+ output += visible() ? content : preserveLineBreaksOnly(content);
860
+ output += preserveLineBreaksOnly(source.slice(tag.index, tag.end));
861
+ cursor = tag.end;
862
+ if (tag.closing) scopes.pop();
863
+ else if (!tag.selfClosing) scopes.push({
864
+ name: tag.name,
865
+ only: tag.only
866
+ });
867
+ }
868
+ const remaining = source.slice(cursor);
869
+ output += visible() ? remaining : preserveLineBreaksOnly(remaining);
870
+ return output;
871
+ }
872
+ function collectPageCommands(page, agent) {
784
873
  const commands = [];
785
- for (const command of agent?.commands ?? []) commands.push(normalizeAgentCommand(command, page.sourcePath));
874
+ const contractLocations = collectContractCommandLocations(page.source);
875
+ const claimedContractLines = /* @__PURE__ */ new Set();
876
+ for (const command of agent?.commands ?? []) commands.push(normalizeAgentCommand(command, page.sourcePath, claimContractCommandLine(contractLocations.commands, typeof command === "string" ? command : command.run, claimedContractLines)));
786
877
  for (const verification of agent?.verification ?? []) if (typeof verification !== "string" && verification.run) commands.push({
787
878
  run: verification.run,
879
+ line: claimContractCommandLine(contractLocations.verification, verification.run, claimedContractLines),
788
880
  sourcePath: page.sourcePath,
789
881
  source: "contract"
790
882
  });
791
- collectMarkdownCommands(commands, projectedSource, page.sourcePath);
792
- if (page.agentSource) collectMarkdownCommands(commands, page.agentSource, page.agentSourcePath ?? page.sourcePath);
883
+ collectMarkdownCommands(commands, projectAgentCommandSource(page.source), page.sourcePath);
884
+ if (page.agentSource) collectMarkdownCommands(commands, projectAgentCommandSource(page.agentSource), page.agentSourcePath ?? page.sourcePath);
793
885
  return dedupeCommands(commands);
794
886
  }
795
887
  function collectMarkdownCommands(commands, source, sourcePath) {
@@ -801,30 +893,54 @@ function collectMarkdownCommands(commands, source, sourcePath) {
801
893
  for (const block of blocks) {
802
894
  if (!/^(?:bash|console|sh|shell|zsh)$/i.test(block.language ?? "")) continue;
803
895
  for (const command of shellLines(block.code, block.language)) commands.push({
804
- run: command,
805
- line: block.lineStart,
896
+ run: command.run,
897
+ line: block.lineStart + 1 + command.lineOffset,
806
898
  sourcePath,
807
899
  packageManagerHint: block.packageManager,
808
900
  source: "fence"
809
901
  });
810
902
  }
811
903
  }
812
- function normalizeAgentCommand(command, sourcePath) {
904
+ function normalizeAgentCommand(command, sourcePath, line) {
905
+ const run = typeof command === "string" ? command : command.run;
813
906
  return typeof command === "string" ? {
814
- run: command,
907
+ run,
908
+ line,
815
909
  sourcePath,
816
910
  source: "contract"
817
911
  } : {
818
- run: command.run,
912
+ run,
819
913
  cwd: command.cwd,
914
+ line,
820
915
  sourcePath,
821
916
  source: "contract"
822
917
  };
823
918
  }
824
919
  function shellLines(code, language) {
825
- const lines = code.replace(/\\\s*\r?\n\s*/g, " ").split(/\r?\n/);
826
- const promptedConsole = language?.toLowerCase() === "console" && lines.some((line) => /^(?:\$|>)\s+/.test(line.trim()));
827
- return lines.map((line) => line.trim()).filter((line) => !promptedConsole || /^(?:\$|>)\s+/.test(line)).map((line) => line.replace(/^(?:\$|>)\s+/, "")).filter((line) => Boolean(line) && !line.startsWith("#") && !/^\w+=\S+$/.test(line));
920
+ const logicalLines = [];
921
+ let pending;
922
+ for (const [lineOffset, physicalLine] of code.split(/\r?\n/).entries()) {
923
+ const trimmed = physicalLine.trim();
924
+ if (!pending) pending = {
925
+ run: "",
926
+ lineOffset
927
+ };
928
+ const continued = /\\\s*$/.test(trimmed);
929
+ const segment = continued ? trimmed.replace(/\\\s*$/, "").trimEnd() : trimmed;
930
+ pending.run = `${pending.run}${pending.run && segment ? " " : ""}${segment}`;
931
+ if (continued) continue;
932
+ logicalLines.push(pending);
933
+ pending = void 0;
934
+ }
935
+ if (pending) logicalLines.push(pending);
936
+ const promptedConsole = language?.toLowerCase() === "console" && logicalLines.some((line) => /^(?:\$|>)\s+/.test(line.run.trim()));
937
+ return logicalLines.map((line) => ({
938
+ ...line,
939
+ run: line.run.trim()
940
+ })).filter((line) => !promptedConsole || /^(?:\$|>)\s+/.test(line.run)).map((line) => ({
941
+ ...line,
942
+ run: line.run.replace(/^(?:\$|>)\s+/, "")
943
+ })).filter((line) => Boolean(line.run) && !line.run.startsWith("#") && !/^\w+=\S+$/.test(line.run));
828
944
  }
829
945
  function dedupeCommands(commands) {
830
946
  const seen = /* @__PURE__ */ new Set();
@@ -1,5 +1,5 @@
1
1
  import { a as devInstallCommand, c as fileExists, d as readFileSafe, f as spawnAndWaitFor, i as detectPackageManagerFromProject, l as formatPackageManagerDetection, n as detectGlobalCssFiles, o as exec, p as writeFileSafe, r as detectNextAppDir, t as detectFramework, u as installCommand } from "./utils-DpiIioYb.mjs";
2
- import { $ as svelteDocsLayoutServerTemplate, A as injectTanstackVitePlugins, B as nuxtGlobalCssTemplate, C as injectDocsAgentSkillsVitePlugin, Ct as tsconfigTemplate, D as injectSvelteCssImport, E as injectRootProviderIntoLayout, F as nextLocaleDocPageTemplate, G as nuxtServerDocsPublicMiddlewareTemplate, H as nuxtQuickstartPageTemplate, I as nextLocalizedPageTemplate, J as quickstartPageTemplate, K as nuxtWelcomePageTemplate, L as nuxtConfigTemplate, M as nextApiReferencePageTemplate, N as nextConfigMergedTemplate, O as injectSvelteDocsPublicHook, P as nextConfigTemplate, Q as svelteDocsConfigTemplate, R as nuxtDocsConfigTemplate, S as injectCssImport, St as tanstackWelcomePageTemplate, T as injectNuxtCssImport, U as nuxtServerApiDocsRouteTemplate, V as nuxtInstallationPageTemplate, W as nuxtServerApiReferenceRouteTemplate, X as svelteApiReferenceRouteTemplate, Y as rootLayoutTemplate, Z as svelteDocsApiRouteTemplate, _ as getAstroAdapterPkg, _t as tanstackDocsServerTemplate, a as astroDocsIndexTemplate, at as svelteInstallationPageTemplate, b as injectAstroCssImport, bt as tanstackRootRouteTemplate, c as astroDocsServerTemplate, ct as svelteViteConfigTemplate, d as astroQuickstartPageTemplate, dt as tanstackApiReferenceRouteTemplate, et as svelteDocsLayoutTemplate, f as astroWelcomePageTemplate, ft as tanstackDocsCatchAllRouteTemplate, g as docsLayoutTemplate, gt as tanstackDocsPublicRouteTemplate, h as docsConfigTemplate, ht as tanstackDocsIndexRouteTemplate, i as astroDocsConfigTemplate, it as svelteGlobalCssTemplate, j as installationPageTemplate, k as injectTanstackRootProviderIntoRoute, l as astroGlobalCssTemplate, lt as svelteWelcomePageTemplate, m as customThemeTsTemplate, mt as tanstackDocsFunctionsTemplate, n as astroApiRouteTemplate, nt as svelteDocsPublicHookTemplate, o as astroDocsMiddlewareTemplate, ot as svelteQuickstartPageTemplate, p as customThemeCssTemplate, pt as tanstackDocsConfigTemplate, q as postcssConfigTemplate, r as astroConfigTemplate, rt as svelteDocsServerTemplate, s as astroDocsPageTemplate, st as svelteRootLayoutTemplate, t as astroApiReferenceRouteTemplate, tt as svelteDocsPageTemplate, u as astroInstallationPageTemplate, ut as tanstackApiDocsRouteTemplate, v as globalCssTemplate, vt as tanstackInstallationPageTemplate, w as injectNuxtAgentSkillsPlugin, wt as welcomePageTemplate, x as injectAstroDocsMiddleware, xt as tanstackViteConfigTemplate, y as injectAstroAgentSkillsPlugin, yt as tanstackQuickstartPageTemplate, z as nuxtDocsPageTemplate } from "./templates-C6avM0U3.mjs";
2
+ import { $ as svelteDocsLayoutServerTemplate, A as injectTanstackVitePlugins, B as nuxtGlobalCssTemplate, C as injectDocsAgentSkillsVitePlugin, Ct as tsconfigTemplate, D as injectSvelteCssImport, E as injectRootProviderIntoLayout, F as nextLocaleDocPageTemplate, G as nuxtServerDocsPublicMiddlewareTemplate, H as nuxtQuickstartPageTemplate, I as nextLocalizedPageTemplate, J as quickstartPageTemplate, K as nuxtWelcomePageTemplate, L as nuxtConfigTemplate, M as nextApiReferencePageTemplate, N as nextConfigMergedTemplate, O as injectSvelteDocsPublicHook, P as nextConfigTemplate, Q as svelteDocsConfigTemplate, R as nuxtDocsConfigTemplate, S as injectCssImport, St as tanstackWelcomePageTemplate, T as injectNuxtCssImport, U as nuxtServerApiDocsRouteTemplate, V as nuxtInstallationPageTemplate, W as nuxtServerApiReferenceRouteTemplate, X as svelteApiReferenceRouteTemplate, Y as rootLayoutTemplate, Z as svelteDocsApiRouteTemplate, _ as getAstroAdapterPkg, _t as tanstackDocsServerTemplate, a as astroDocsIndexTemplate, at as svelteInstallationPageTemplate, b as injectAstroCssImport, bt as tanstackRootRouteTemplate, c as astroDocsServerTemplate, ct as svelteViteConfigTemplate, d as astroQuickstartPageTemplate, dt as tanstackApiReferenceRouteTemplate, et as svelteDocsLayoutTemplate, f as astroWelcomePageTemplate, ft as tanstackDocsCatchAllRouteTemplate, g as docsLayoutTemplate, gt as tanstackDocsPublicRouteTemplate, h as docsConfigTemplate, ht as tanstackDocsIndexRouteTemplate, i as astroDocsConfigTemplate, it as svelteGlobalCssTemplate, j as installationPageTemplate, k as injectTanstackRootProviderIntoRoute, l as astroGlobalCssTemplate, lt as svelteWelcomePageTemplate, m as customThemeTsTemplate, mt as tanstackDocsFunctionsTemplate, n as astroApiRouteTemplate, nt as svelteDocsPublicHookTemplate, o as astroDocsMiddlewareTemplate, ot as svelteQuickstartPageTemplate, p as customThemeCssTemplate, pt as tanstackDocsConfigTemplate, q as postcssConfigTemplate, r as astroConfigTemplate, rt as svelteDocsServerTemplate, s as astroDocsPageTemplate, st as svelteRootLayoutTemplate, t as astroApiReferenceRouteTemplate, tt as svelteDocsPageTemplate, u as astroInstallationPageTemplate, ut as tanstackApiDocsRouteTemplate, v as globalCssTemplate, vt as tanstackInstallationPageTemplate, w as injectNuxtAgentSkillsPlugin, wt as welcomePageTemplate, x as injectAstroDocsMiddleware, xt as tanstackViteConfigTemplate, y as injectAstroAgentSkillsPlugin, yt as tanstackQuickstartPageTemplate, z as nuxtDocsPageTemplate } from "./templates-Co7I_Okv.mjs";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import pc from "picocolors";
@@ -188,7 +188,7 @@ async function configureDocsCloudOnboarding(options) {
188
188
  enabled = cloudAnswer;
189
189
  }
190
190
  if (!enabled) return;
191
- const { initCloudConfig } = await import("./cloud-pdNC-tyj.mjs");
191
+ const { initCloudConfig } = await import("./cloud-DwhH_b_q.mjs");
192
192
  printDocsCloudOnboardingInstructions(await initCloudConfig({
193
193
  rootDir: options.rootDir,
194
194
  configPath: getDocsCloudConfigPathForFramework(options.framework)
@@ -443,6 +443,11 @@ async function init(options = {}) {
443
443
  label: "Ledger",
444
444
  hint: "Stripe Docs-inspired product docs shell with navy code panels"
445
445
  },
446
+ {
447
+ value: "shadcn",
448
+ label: "Shadcn Docs",
449
+ hint: "Compact neutral shell inspired by the shadcn/ui documentation"
450
+ },
446
451
  {
447
452
  value: "greentree",
448
453
  label: "GreenTree",
@@ -1117,6 +1122,7 @@ function scaffoldSvelteKit(cwd, cfg, globalCssRelPath, write, skipped, written)
1117
1122
  darkbold: "darkbold",
1118
1123
  shiny: "shiny",
1119
1124
  ledger: "ledger",
1125
+ shadcn: "shadcn",
1120
1126
  greentree: "greentree",
1121
1127
  concrete: "concrete",
1122
1128
  "command-grid": "command-grid",
@@ -1184,6 +1190,7 @@ function scaffoldAstro(cwd, cfg, globalCssRelPath, write, skipped, written) {
1184
1190
  darkbold: "darkbold",
1185
1191
  shiny: "shiny",
1186
1192
  ledger: "ledger",
1193
+ shadcn: "shadcn",
1187
1194
  greentree: "greentree",
1188
1195
  concrete: "concrete",
1189
1196
  "command-grid": "command-grid",
@@ -1238,6 +1245,7 @@ function scaffoldNuxt(cwd, cfg, globalCssRelPath, write, skipped, written) {
1238
1245
  darkbold: "darkbold",
1239
1246
  shiny: "shiny",
1240
1247
  ledger: "ledger",
1248
+ shadcn: "shadcn",
1241
1249
  greentree: "greentree",
1242
1250
  concrete: "concrete",
1243
1251
  "command-grid": "command-grid",
@@ -9,7 +9,7 @@ import "./agent-evals-DCptRrdP.mjs";
9
9
  import { createFilesystemDocsMcpSource, resolveDocsMcpConfig, runDocsMcpStdio } from "./mcp.mjs";
10
10
  import "./code-blocks-0wjOsqdJ.mjs";
11
11
  import "./server.mjs";
12
- import { _ as resolveDocsContentDir, d as readNavTitle, g as resolveDocsConfigPath, i as hasTopLevelProperty, l as readBooleanProperty, n as extractObjectLiteral, o as loadDocsConfigModuleResult, p as readStringProperty, t as extractNestedObjectLiteral } from "./config-Wcdj-D0a.mjs";
12
+ import { _ as resolveDocsContentDir, d as readNavTitle, g as resolveDocsConfigPath, i as hasTopLevelProperty, l as readBooleanProperty, n as extractObjectLiteral, o as loadDocsConfigModuleResult, p as readStringProperty, t as extractNestedObjectLiteral } from "./config-BtxaQTPP.mjs";
13
13
  import { existsSync, readFileSync } from "node:fs";
14
14
  import path from "node:path";
15
15
  import pc from "picocolors";
package/dist/mcp.mjs CHANGED
@@ -13,6 +13,9 @@ import * as z from "zod/v4";
13
13
  //#region src/mcp.ts
14
14
  const DEFAULT_MCP_VERSION = "0.0.0";
15
15
  const DEFAULT_MCP_NAME = "@farming-labs/docs";
16
+ const DOCS_MCP_DISCOVERY_CACHE_TTL_MS = 300 * 1e3;
17
+ const DOCS_MCP_LIST_CACHE_TTL_MS = 300 * 1e3;
18
+ const DOCS_MCP_RESOURCE_CACHE_TTL_MS = 60 * 1e3;
16
19
  const DEFAULT_MCP_CONTEXT_TOKEN_BUDGET = 4e3;
17
20
  const MIN_MCP_CONTEXT_TOKEN_BUDGET = 256;
18
21
  const MAX_MCP_CONTEXT_TOKEN_BUDGET = 32e3;
@@ -2625,7 +2628,7 @@ function durationMs(startedAt) {
2625
2628
  }
2626
2629
  function createDocsMcpContentChangeMonitor(options) {
2627
2630
  let context;
2628
- let generation;
2631
+ let state;
2629
2632
  let timer;
2630
2633
  let running = false;
2631
2634
  let closed = false;
@@ -2636,11 +2639,14 @@ function createDocsMcpContentChangeMonitor(options) {
2636
2639
  if (closed || context === void 0 || options.isActive?.() === false) return;
2637
2640
  running = true;
2638
2641
  try {
2639
- const nextGeneration = await options.readGeneration(context);
2640
- if (generation && nextGeneration !== generation) {
2641
- generation = nextGeneration;
2642
- await options.notify();
2643
- } else generation = nextGeneration;
2642
+ const nextState = await options.readState(context);
2643
+ const previousState = state;
2644
+ state = nextState;
2645
+ if (previousState && nextState.indexGeneration !== previousState.indexGeneration) await options.notify({
2646
+ context,
2647
+ previous: previousState,
2648
+ current: nextState
2649
+ });
2644
2650
  } catch {} finally {
2645
2651
  running = false;
2646
2652
  schedule();
@@ -2657,9 +2663,9 @@ function createDocsMcpContentChangeMonitor(options) {
2657
2663
  timer = void 0;
2658
2664
  }
2659
2665
  try {
2660
- generation = await options.readGeneration(nextContext);
2666
+ state = await options.readState(nextContext);
2661
2667
  } catch {
2662
- generation = void 0;
2668
+ state = void 0;
2663
2669
  }
2664
2670
  schedule();
2665
2671
  },
@@ -2817,10 +2823,36 @@ async function createDocsMcpServer(options) {
2817
2823
  });
2818
2824
  const contentChangesEnabled = resolveDocsContentChangesConfig(options.contentChanges).enabled && resolved.tools.listContentChanges !== false;
2819
2825
  const contentChangeHydrationEnabled = contentChangesEnabled && resolved.tools.hydrateContentChanges !== false;
2826
+ const cacheScope = options.requestContext?.auth ? "private" : "public";
2820
2827
  const server = new McpServer({
2821
2828
  name: resolved.name,
2822
2829
  version: resolved.version
2823
- });
2830
+ }, { cacheHints: {
2831
+ "server/discover": {
2832
+ ttlMs: DOCS_MCP_DISCOVERY_CACHE_TTL_MS,
2833
+ cacheScope
2834
+ },
2835
+ "tools/list": {
2836
+ ttlMs: DOCS_MCP_LIST_CACHE_TTL_MS,
2837
+ cacheScope
2838
+ },
2839
+ "prompts/list": {
2840
+ ttlMs: DOCS_MCP_LIST_CACHE_TTL_MS,
2841
+ cacheScope
2842
+ },
2843
+ "resources/list": {
2844
+ ttlMs: DOCS_MCP_LIST_CACHE_TTL_MS,
2845
+ cacheScope
2846
+ },
2847
+ "resources/templates/list": {
2848
+ ttlMs: DOCS_MCP_LIST_CACHE_TTL_MS,
2849
+ cacheScope
2850
+ },
2851
+ "resources/read": {
2852
+ ttlMs: DOCS_MCP_RESOURCE_CACHE_TTL_MS,
2853
+ cacheScope
2854
+ }
2855
+ } });
2824
2856
  installDocsMcpSdkRegistrationPagination(server, protocolScope);
2825
2857
  if (contentChangesEnabled) server.server.registerCapabilities({ resources: { subscribe: true } });
2826
2858
  const registerResource = (name, uri, metadata, callback) => {
@@ -4511,22 +4543,35 @@ function createDocsMcpHttpHandler(options) {
4511
4543
  });
4512
4544
  const configuredPollInterval = options.contentChangePollIntervalMs;
4513
4545
  const contentChangePollIntervalMs = typeof configuredPollInterval === "number" && Number.isFinite(configuredPollInterval) && configuredPollInterval >= 10 ? Math.floor(configuredPollInterval) : DEFAULT_DOCS_MCP_CONTENT_CHANGE_POLL_INTERVAL_MS;
4514
- async function readMonitoredGeneration(context) {
4546
+ async function readMonitoredState(context) {
4515
4547
  const locale = options.source.resolveLocale?.(void 0, context);
4516
4548
  const pages = dedupePages(await options.source.getPages(locale, context));
4517
- return (await contentChangeFeed.resolve({
4549
+ const result = await contentChangeFeed.resolve({
4518
4550
  pages: toSearchSourcePages(pages),
4519
4551
  search: options.search,
4520
4552
  audience: "agent",
4521
4553
  locale,
4522
4554
  baseUrl: options.source.baseUrl ?? (context.request ? new URL(context.request.url).origin : void 0),
4523
4555
  ...context.request ? { request: context.request.clone() } : {}
4524
- })).indexGeneration;
4556
+ });
4557
+ return {
4558
+ indexGeneration: result.indexGeneration,
4559
+ resourceUris: [
4560
+ "docs://navigation",
4561
+ DOCS_MCP_CONTENT_CHANGES_CURRENT_URI,
4562
+ `docs://changes/${result.indexGeneration}`,
4563
+ ...pages.map((page) => toPageResourceUri(page.url))
4564
+ ]
4565
+ };
4525
4566
  }
4526
4567
  const contentChangeMonitor = createDocsMcpContentChangeMonitor({
4527
4568
  pollIntervalMs: contentChangePollIntervalMs,
4528
- readGeneration: readMonitoredGeneration,
4529
- notify: () => mcpHandler.notify.resourceUpdated(DOCS_MCP_CONTENT_CHANGES_CURRENT_URI),
4569
+ readState: readMonitoredState,
4570
+ notify: ({ previous, current }) => {
4571
+ mcpHandler.notify.resourcesChanged();
4572
+ const affectedUris = new Set([...previous.resourceUris, ...current.resourceUris]);
4573
+ for (const uri of affectedUris) mcpHandler.notify.resourceUpdated(uri);
4574
+ },
4530
4575
  isActive: () => eventBus.listenerCount > 0,
4531
4576
  unrefTimer: true
4532
4577
  });
@@ -4659,21 +4704,34 @@ async function runDocsMcpStdio(options) {
4659
4704
  requestContext
4660
4705
  });
4661
4706
  if (!contentChangesEnabled) return server;
4662
- const readGeneration = async () => {
4707
+ const readState = async () => {
4663
4708
  const locale = options.source.resolveLocale?.(void 0, requestContext);
4664
4709
  const pages = dedupePages(await options.source.getPages(locale, requestContext));
4665
- return (await contentChangeFeed.resolve({
4710
+ const result = await contentChangeFeed.resolve({
4666
4711
  pages: toSearchSourcePages(pages),
4667
4712
  search: options.search,
4668
4713
  audience: "agent",
4669
4714
  locale,
4670
4715
  baseUrl: options.source.baseUrl
4671
- })).indexGeneration;
4716
+ });
4717
+ return {
4718
+ indexGeneration: result.indexGeneration,
4719
+ resourceUris: [
4720
+ "docs://navigation",
4721
+ DOCS_MCP_CONTENT_CHANGES_CURRENT_URI,
4722
+ `docs://changes/${result.indexGeneration}`,
4723
+ ...pages.map((page) => toPageResourceUri(page.url))
4724
+ ]
4725
+ };
4672
4726
  };
4673
4727
  const monitor = createDocsMcpContentChangeMonitor({
4674
4728
  pollIntervalMs,
4675
- readGeneration: () => readGeneration(),
4676
- notify: () => server.server.sendResourceUpdated({ uri: DOCS_MCP_CONTENT_CHANGES_CURRENT_URI })
4729
+ readState: () => readState(),
4730
+ notify: async ({ previous, current }) => {
4731
+ await server.server.sendResourceListChanged();
4732
+ const affectedUris = new Set([...previous.resourceUris, ...current.resourceUris]);
4733
+ for (const uri of affectedUris) await server.server.sendResourceUpdated({ uri });
4734
+ }
4677
4735
  });
4678
4736
  await monitor.start(requestContext);
4679
4737
  const closeServer = server.close.bind(server);
@@ -7,9 +7,9 @@ import "./agent-skills-server-CwmzAzf_.mjs";
7
7
  import { c as resolveDocsReviewConfig, o as ensureDocsReviewWorkflow, s as readDocsReviewConfigFromSource, t as runDocsGoldenTasks } from "./agent-evals-DCptRrdP.mjs";
8
8
  import { createFilesystemDocsMcpSource, getDocsConfigSchema, resolveDocsMcpConfig } from "./mcp.mjs";
9
9
  import "./code-blocks-0wjOsqdJ.mjs";
10
- import { _ as resolveDocsContentDir, g as resolveDocsConfigPath, h as readTopLevelStringProperty, s as loadDocsConfigModuleResultWithProjectEnv } from "./config-Wcdj-D0a.mjs";
10
+ import { _ as resolveDocsContentDir, g as resolveDocsConfigPath, h as readTopLevelStringProperty, s as loadDocsConfigModuleResultWithProjectEnv } from "./config-BtxaQTPP.mjs";
11
11
  import { t as detectFramework } from "./utils-DpiIioYb.mjs";
12
- import { a as extractAgentBlocks, i as createAgentUsefulnessPagesFromMcp, n as analyzeAgentSurfaceDrift, r as analyzeAgentUsefulness, t as resolveGoldenEvaluationInput } from "./golden-evaluations-CNDwoUOe.mjs";
12
+ import { a as extractAgentBlocks, i as createAgentUsefulnessPagesFromMcp, n as analyzeAgentSurfaceDrift, r as analyzeAgentUsefulness, t as resolveGoldenEvaluationInput } from "./golden-evaluations-DyeYD50F.mjs";
13
13
  import { t as analyzeConfiguredAgentSkillsProgressiveDisclosure } from "./agent-skills-progressive-disclosure-BVvj7nM8.mjs";
14
14
  import matter from "gray-matter";
15
15
  import { existsSync, lstatSync, readFileSync, readdirSync } from "node:fs";
@@ -2,7 +2,7 @@ import "./agent-CTOUI2BK.mjs";
2
2
  import "./markdown-sections-7OoA7ylx.mjs";
3
3
  import "./standards-discovery-Ckx0tN7B.mjs";
4
4
  import { c as renderDocsRobotsGeneratedBlock, f as upsertDocsRobotsGeneratedBlock, i as DOCS_ROBOTS_GENERATED_BLOCK_START, r as DOCS_ROBOTS_GENERATED_BLOCK_END, u as resolveDocsRobotsConfig } from "./robots-DaU38DZw.mjs";
5
- import { a as loadDocsConfigModule, g as resolveDocsConfigPath, h as readTopLevelStringProperty, l as readBooleanProperty, m as readTopLevelBooleanProperty, p as readStringProperty, t as extractNestedObjectLiteral } from "./config-Wcdj-D0a.mjs";
5
+ import { a as loadDocsConfigModule, g as resolveDocsConfigPath, h as readTopLevelStringProperty, l as readBooleanProperty, m as readTopLevelBooleanProperty, p as readStringProperty, t as extractNestedObjectLiteral } from "./config-BtxaQTPP.mjs";
6
6
  import { t as detectFramework } from "./utils-DpiIioYb.mjs";
7
7
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
8
  import path from "node:path";
@@ -10,7 +10,7 @@ import "./agent-evals-DCptRrdP.mjs";
10
10
  import { createFilesystemDocsMcpSource } from "./mcp.mjs";
11
11
  import "./code-blocks-0wjOsqdJ.mjs";
12
12
  import "./server.mjs";
13
- import { _ as resolveDocsContentDir, c as loadProjectEnv, g as resolveDocsConfigPath, h as readTopLevelStringProperty, s as loadDocsConfigModuleResultWithProjectEnv } from "./config-Wcdj-D0a.mjs";
13
+ import { _ as resolveDocsContentDir, c as loadProjectEnv, g as resolveDocsConfigPath, h as readTopLevelStringProperty, s as loadDocsConfigModuleResultWithProjectEnv } from "./config-BtxaQTPP.mjs";
14
14
  import { readFileSync } from "node:fs";
15
15
  import path from "node:path";
16
16
  import pc from "picocolors";
@@ -8,7 +8,7 @@ import "./agent-evals-DCptRrdP.mjs";
8
8
  import { createFilesystemDocsMcpSource } from "./mcp.mjs";
9
9
  import "./code-blocks-0wjOsqdJ.mjs";
10
10
  import "./server.mjs";
11
- import { _ as resolveDocsContentDir, a as loadDocsConfigModule, d as readNavTitle, g as resolveDocsConfigPath, h as readTopLevelStringProperty, l as readBooleanProperty, p as readStringProperty, t as extractNestedObjectLiteral } from "./config-Wcdj-D0a.mjs";
11
+ import { _ as resolveDocsContentDir, a as loadDocsConfigModule, d as readNavTitle, g as resolveDocsConfigPath, h as readTopLevelStringProperty, l as readBooleanProperty, p as readStringProperty, t as extractNestedObjectLiteral } from "./config-BtxaQTPP.mjs";
12
12
  import { t as detectFramework } from "./utils-DpiIioYb.mjs";
13
13
  import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
14
14
  import path from "node:path";
@@ -9,7 +9,7 @@ import "./agent-evals-DCptRrdP.mjs";
9
9
  import { createFilesystemDocsMcpSource } from "./mcp.mjs";
10
10
  import "./code-blocks-0wjOsqdJ.mjs";
11
11
  import "./server.mjs";
12
- import { _ as resolveDocsContentDir, a as loadDocsConfigModule, d as readNavTitle, g as resolveDocsConfigPath, h as readTopLevelStringProperty, p as readStringProperty, t as extractNestedObjectLiteral } from "./config-Wcdj-D0a.mjs";
12
+ import { _ as resolveDocsContentDir, a as loadDocsConfigModule, d as readNavTitle, g as resolveDocsConfigPath, h as readTopLevelStringProperty, p as readStringProperty, t as extractNestedObjectLiteral } from "./config-BtxaQTPP.mjs";
13
13
  import { n as estimateAgentSkillInstructionTokens, r as resolveDocsAgentSkillsProgressiveDisclosureConfig } from "./agent-skills-progressive-disclosure-BVvj7nM8.mjs";
14
14
  import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
15
15
  import path from "node:path";
@@ -58,6 +58,14 @@ const THEME_INFO = {
58
58
  nuxtImport: "@farming-labs/nuxt-theme/ledger",
59
59
  nextCssImport: "ledger"
60
60
  },
61
+ shadcn: {
62
+ factory: "shadcn",
63
+ nextImport: "@farming-labs/theme/shadcn",
64
+ svelteImport: "@farming-labs/svelte-theme/shadcn",
65
+ astroImport: "@farming-labs/astro-theme/shadcn",
66
+ nuxtImport: "@farming-labs/nuxt-theme/shadcn",
67
+ nextCssImport: "shadcn"
68
+ },
61
69
  greentree: {
62
70
  factory: "greentree",
63
71
  nextImport: "@farming-labs/theme/greentree",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/docs",
3
- "version": "0.2.87",
3
+ "version": "0.2.89",
4
4
  "description": "Modern, flexible MDX-based docs framework — core types, config, and CLI",
5
5
  "keywords": [
6
6
  "docs",
@@ -16,7 +16,8 @@
16
16
  "docs": "./dist/cli/index.mjs"
17
17
  },
18
18
  "files": [
19
- "dist"
19
+ "dist",
20
+ "styles"
20
21
  ],
21
22
  "type": "module",
22
23
  "main": "./dist/index.mjs",
@@ -67,7 +68,8 @@
67
68
  "types": "./dist/mcp.d.mts",
68
69
  "import": "./dist/mcp.mjs",
69
70
  "default": "./dist/mcp.mjs"
70
- }
71
+ },
72
+ "./styles/themes/shadcn.css": "./styles/themes/shadcn.css"
71
73
  },
72
74
  "dependencies": {
73
75
  "@clack/prompts": "^0.9.1",