@farming-labs/docs 0.2.103 → 0.2.105
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/dist/{agent-BLHMoVId.mjs → agent-CaCWThBY.mjs} +4 -4
- package/dist/{agent-CFqECAG0.mjs → agent-DCTGj6J7.mjs} +212 -19
- package/dist/{agent-evals-GpcaCbRb.mjs → agent-evals-D-sPJfXz.mjs} +5 -5
- package/dist/{agent-export-oiWxB5aX.mjs → agent-export-GcTZPLfB.mjs} +30 -17
- package/dist/agent-feedback-evaluations-DQCTFegz.mjs +240 -0
- package/dist/agent-feedback-loop-vaC-M1sx.mjs +196 -0
- package/dist/agent-maintenance-CuZ7iAKq.mjs +289 -0
- package/dist/agent-skills-bundle.d.mts +1 -1
- package/dist/{agent-skills-progressive-disclosure-Da9LKEKv.mjs → agent-skills-progressive-disclosure-DL-q4JZo.mjs} +1 -1
- package/dist/{agent-skills-server-CICMh0zv.d.mts → agent-skills-server-D34054x5.d.mts} +2 -2
- package/dist/{agent-skills-server-DFqQyO_V.mjs → agent-skills-server-Ddbf15pY.mjs} +1 -1
- package/dist/agent-skills-vite.d.mts +3 -3
- package/dist/agent-skills-vite.mjs +2 -2
- package/dist/{agents-CtqIUW5I.mjs → agents-e1SYT64z.mjs} +11 -10
- package/dist/{analytics-Bx44lg6d.mjs → analytics-CqfcIBdg.mjs} +1 -1
- package/dist/{analytics-C75BnTEW.d.mts → analytics-aeXwEvQX.d.mts} +1 -1
- package/dist/authoring-Do87QzBd.mjs +41 -0
- package/dist/authoring-mcp-Be7quE5R.mjs +380 -0
- package/dist/browser.d.mts +3 -3
- package/dist/browser.mjs +2 -2
- package/dist/cli/index.mjs +103 -35
- package/dist/client/react.d.mts +1 -1
- package/dist/client/react.mjs +1 -1
- package/dist/{cloud-FNfcbfli.mjs → cloud-Bvof6mET.mjs} +3 -3
- package/dist/{cloud-ask-ai-BmbZVAT5.d.mts → cloud-ask-ai-BqfiQaNZ.d.mts} +1 -1
- package/dist/{cloud-ask-ai-CkCYjf2N.mjs → cloud-ask-ai-CK2qlNns.mjs} +1 -1
- package/dist/{code-blocks-Bel6vDqI.mjs → code-blocks-D90CCJFs.mjs} +1 -1
- package/dist/{codeblocks-jbWuvtJQ.mjs → codeblocks-C911CdyJ.mjs} +2 -2
- package/dist/{agent-lWTq6pgr.d.mts → content-change-hydration-CoYRs3pC.d.mts} +707 -675
- package/dist/{dev-BvbYmTLz.mjs → dev-Bx0JNglW.mjs} +3 -3
- package/dist/docs-cloud-server.d.mts +2 -2
- package/dist/docs-cloud-server.mjs +2 -2
- package/dist/{doctor-Bmm0uY98.mjs → doctor-CtK1CRPj.mjs} +20 -16
- package/dist/{downgrade-Dqm0rJMy.mjs → downgrade-BXmQMkMy.mjs} +2 -2
- package/dist/feedback-DWVUMrxy.mjs +72 -0
- package/dist/feedback-evals-k0sFDdms.mjs +146 -0
- package/dist/{golden-evaluations-K45fcWGW.mjs → golden-evaluations-De4KwoYr.mjs} +3 -3
- package/dist/index.d.mts +236 -9
- package/dist/index.mjs +14 -11
- package/dist/{init-jDQSo-Or.mjs → init-CCV2eRNB.mjs} +3 -3
- package/dist/markdown-rendering.mjs +1 -1
- package/dist/{markdown-sections-7OoA7ylx.mjs → markdown-sections-BKy4labo.mjs} +110 -2
- package/dist/{mcp-CwgKlbIz.mjs → mcp-DsjWxF7g.mjs} +11 -10
- package/dist/mcp.d.mts +20 -5
- package/dist/mcp.mjs +538 -56
- package/dist/{metadata-D4v_R1t5.mjs → metadata-7htr-Xj_.mjs} +1 -1
- package/dist/{content-change-hydration-BsbBXAUi.mjs → openapi-mcp-DQ3xptKo.mjs} +182 -4
- package/dist/openapi-mcp-node-vO3IXVGI.mjs +43 -0
- package/dist/{package-version--oQiHwZj.mjs → package-version-Ci99L0yo.mjs} +1 -1
- package/dist/{prompt-references-DW5vG5zs.mjs → prompt-references-1Wce71c7.mjs} +3 -3
- package/dist/propose-DJOiHu9Y.mjs +73 -0
- package/dist/retrieval-digest-B-SgtXKK.mjs +177 -0
- package/dist/retrieval-digest-DyNRD-mt.d.mts +467 -0
- package/dist/{review-C_5wB0rR.mjs → review-XI9FXeos.mjs} +12 -12
- package/dist/{robots-NQesPX5L.mjs → robots-BOjWB1ky.mjs} +2 -2
- package/dist/{robots-BQ42Y84a.mjs → robots-CzKesbdX.mjs} +6 -6
- package/dist/{search-B5etKU-v.mjs → search-DwAoC9X7.mjs} +12 -11
- package/dist/server.d.mts +47 -264
- package/dist/server.mjs +14 -11
- package/dist/{sidebar-CwZlgyAz.d.mts → sidebar-CJze8SBi.d.mts} +1 -1
- package/dist/{sitemap-DjhxvQP1.mjs → sitemap-DOaJIKJf.mjs} +11 -10
- package/dist/{sitemap-server-B0SiREN0.mjs → sitemap-server-NeVu8W38.mjs} +11 -1
- package/dist/{skills-BFang8vF.mjs → skills-BILSESek.mjs} +11 -10
- package/dist/{standards-discovery-Ckx0tN7B.mjs → standards-discovery-Bpz90VYq.mjs} +2 -177
- package/dist/{standards-discovery-D1Ys4J3h.d.mts → standards-discovery-Xm84bS4M.d.mts} +1 -1
- package/dist/{types-DLLefoU5.d.mts → types-QhYMnKvb.d.mts} +148 -2
- package/dist/{upgrade-kj2crJSk.mjs → upgrade-B92U83xo.mjs} +2 -2
- package/package.json +1 -1
- package/dist/retrieval-digest-DYEsIeCE.d.mts +0 -164
- /package/dist/{audience-exposure-Cw3SA4WE.d.mts → audience-exposure-CkNZNeVX.d.mts} +0 -0
- /package/dist/{cloud-analytics-CSyFE6SS.mjs → cloud-analytics-Ci1yiwD8.mjs} +0 -0
- /package/dist/{config-BaTmjDqD.mjs → config-DrZ3fXgf.mjs} +0 -0
- /package/dist/{errors-DZiNXv5c.mjs → errors-BDmra6mz.mjs} +0 -0
- /package/dist/{i18n-B3BIxShC.mjs → i18n-B1gJ9EW0.mjs} +0 -0
- /package/dist/{sidebar-IcpElOVH.mjs → sidebar-3W51s2sF.mjs} +0 -0
- /package/dist/{templates-kc7jxspR.mjs → templates-DdB4BBGq.mjs} +0 -0
- /package/dist/{utils-DOMeZW9V.mjs → utils-Cc1SrVza.mjs} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as hasStructuredPageAgentContract, v as normalizePageAgentFrontmatter } from "./markdown-sections-
|
|
1
|
+
import { _ as hasStructuredPageAgentContract, v as normalizePageAgentFrontmatter } from "./markdown-sections-BKy4labo.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/metadata.ts
|
|
4
4
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { s as parseDocsMarkdownSections } from "./markdown-sections-BKy4labo.mjs";
|
|
2
|
+
import { $ as isDocsSkillRequest, Fn as createDocsPaginationCursor, Jt as isDocsContentChangesRequest, K as isDocsAgentDiscoveryRequest, Ln as resolveDocsPaginationOffset, Pn as DocsPaginationCursorError, St as resolveDocsSkillFormat, Yt as resolveDocsContentChangesConfig, dt as resolveDocsAgentFeedbackRequest, en as buildDocsRetrievalDigestProjection, ft as resolveDocsAgentsFormat, mt as resolveDocsLlmsTxtRequest, q as isDocsAgentsRequest, ut as resolveDocsAgentFeedbackConfig, vt as resolveDocsMarkdownRequest } from "./agent-DCTGj6J7.mjs";
|
|
3
|
+
import { n as digestDocsRetrievalContent } from "./retrieval-digest-B-SgtXKK.mjs";
|
|
4
4
|
import matter from "gray-matter";
|
|
5
5
|
|
|
6
6
|
//#region src/telemetry.ts
|
|
@@ -605,4 +605,182 @@ function hydrateDocsContentChanges(options) {
|
|
|
605
605
|
}
|
|
606
606
|
|
|
607
607
|
//#endregion
|
|
608
|
-
|
|
608
|
+
//#region src/openapi-mcp.ts
|
|
609
|
+
const HTTP_METHODS = [
|
|
610
|
+
"get",
|
|
611
|
+
"post",
|
|
612
|
+
"put",
|
|
613
|
+
"patch",
|
|
614
|
+
"delete",
|
|
615
|
+
"options",
|
|
616
|
+
"head"
|
|
617
|
+
];
|
|
618
|
+
const OPENAPI_RATE_WINDOW_MS = 6e4;
|
|
619
|
+
const openApiRateWindows = /* @__PURE__ */ new Map();
|
|
620
|
+
function acquireDocsOpenApiMcpBudget(key, config, now = Date.now()) {
|
|
621
|
+
const requestsPerMinute = Math.max(1, config.requestsPerMinute ?? 60);
|
|
622
|
+
const maxConcurrentRequests = Math.max(1, config.maxConcurrentRequests ?? 4);
|
|
623
|
+
let window = openApiRateWindows.get(key);
|
|
624
|
+
if (!window || now - window.startedAt >= OPENAPI_RATE_WINDOW_MS) {
|
|
625
|
+
window = {
|
|
626
|
+
startedAt: now,
|
|
627
|
+
count: 0,
|
|
628
|
+
active: window?.active ?? 0
|
|
629
|
+
};
|
|
630
|
+
openApiRateWindows.set(key, window);
|
|
631
|
+
}
|
|
632
|
+
if (window.count >= requestsPerMinute) throw new Error("OpenAPI MCP rate limit exceeded for this principal and operation.");
|
|
633
|
+
if (window.active >= maxConcurrentRequests) throw new Error("OpenAPI MCP concurrency limit exceeded for this principal and operation.");
|
|
634
|
+
window.count += 1;
|
|
635
|
+
window.active += 1;
|
|
636
|
+
let released = false;
|
|
637
|
+
return () => {
|
|
638
|
+
if (released) return;
|
|
639
|
+
released = true;
|
|
640
|
+
window.active = Math.max(0, window.active - 1);
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
async function readDocsOpenApiMcpResponse(response, maxBytes = 1e6) {
|
|
644
|
+
const limit = Math.max(1, maxBytes);
|
|
645
|
+
if (!response.body) return {
|
|
646
|
+
text: "",
|
|
647
|
+
truncated: false
|
|
648
|
+
};
|
|
649
|
+
const reader = response.body.getReader();
|
|
650
|
+
const chunks = [];
|
|
651
|
+
let used = 0;
|
|
652
|
+
let truncated = false;
|
|
653
|
+
try {
|
|
654
|
+
while (true) {
|
|
655
|
+
const { done, value } = await reader.read();
|
|
656
|
+
if (done) break;
|
|
657
|
+
if (used + value.byteLength > limit) {
|
|
658
|
+
const remaining = limit - used;
|
|
659
|
+
if (remaining > 0) chunks.push(value.subarray(0, remaining));
|
|
660
|
+
used = limit;
|
|
661
|
+
truncated = true;
|
|
662
|
+
await reader.cancel("OpenAPI MCP response byte limit reached");
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
665
|
+
chunks.push(value);
|
|
666
|
+
used += value.byteLength;
|
|
667
|
+
}
|
|
668
|
+
} finally {
|
|
669
|
+
reader.releaseLock();
|
|
670
|
+
}
|
|
671
|
+
const bytes = new Uint8Array(used);
|
|
672
|
+
let offset = 0;
|
|
673
|
+
for (const chunk of chunks) {
|
|
674
|
+
bytes.set(chunk, offset);
|
|
675
|
+
offset += chunk.byteLength;
|
|
676
|
+
}
|
|
677
|
+
return {
|
|
678
|
+
text: new TextDecoder().decode(bytes),
|
|
679
|
+
truncated
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function asRecord(value) {
|
|
683
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
684
|
+
}
|
|
685
|
+
function selectorFor(method, path) {
|
|
686
|
+
return `${method.toUpperCase()} ${path}`;
|
|
687
|
+
}
|
|
688
|
+
function sanitizeToolName(value) {
|
|
689
|
+
return `api_${value.trim().replace(/[^a-zA-Z0-9_-]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 56) || "operation"}`;
|
|
690
|
+
}
|
|
691
|
+
function operationExtensionEnabled(operation) {
|
|
692
|
+
const extension = operation["x-farming-labs-mcp"];
|
|
693
|
+
return extension === true || asRecord(extension)?.enabled === true;
|
|
694
|
+
}
|
|
695
|
+
function normalizeSecurity(value) {
|
|
696
|
+
if (!Array.isArray(value)) return [];
|
|
697
|
+
return value.flatMap((requirement) => {
|
|
698
|
+
const record = asRecord(requirement);
|
|
699
|
+
if (!record) return [];
|
|
700
|
+
const normalized = {};
|
|
701
|
+
for (const [name, scopes] of Object.entries(record)) normalized[name] = Array.isArray(scopes) ? scopes.filter((scope) => typeof scope === "string") : [];
|
|
702
|
+
return [normalized];
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
function normalizeParameters(...values) {
|
|
706
|
+
const parameters = values.flatMap((value) => Array.isArray(value) ? value : []);
|
|
707
|
+
const seen = /* @__PURE__ */ new Set();
|
|
708
|
+
return parameters.flatMap((parameter) => {
|
|
709
|
+
const record = asRecord(parameter);
|
|
710
|
+
if (!record) return [];
|
|
711
|
+
const name = typeof record.name === "string" ? record.name.trim() : "";
|
|
712
|
+
const location = record?.in;
|
|
713
|
+
if (!name || location !== "path" && location !== "query" && location !== "header" && location !== "cookie") return [];
|
|
714
|
+
const key = `${location}:${name}`;
|
|
715
|
+
if (seen.has(key)) return [];
|
|
716
|
+
seen.add(key);
|
|
717
|
+
return [{
|
|
718
|
+
name,
|
|
719
|
+
in: location,
|
|
720
|
+
required: record.required === true || location === "path"
|
|
721
|
+
}];
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
function resolveDocsOpenApiMcpOperations(document, config) {
|
|
725
|
+
if (!config || config.enabled === false) return [];
|
|
726
|
+
const allow = new Set((config.operations ?? []).map((value) => value.trim()).filter(Boolean));
|
|
727
|
+
const paths = asRecord(document.paths) ?? {};
|
|
728
|
+
const securitySchemes = asRecord(asRecord(document.components)?.securitySchemes) ?? {};
|
|
729
|
+
const globalSecurity = normalizeSecurity(document.security);
|
|
730
|
+
const operations = [];
|
|
731
|
+
const names = /* @__PURE__ */ new Set();
|
|
732
|
+
for (const [path, rawPathItem] of Object.entries(paths)) {
|
|
733
|
+
const pathItem = asRecord(rawPathItem);
|
|
734
|
+
if (!pathItem) continue;
|
|
735
|
+
for (const method of HTTP_METHODS) {
|
|
736
|
+
const operation = asRecord(pathItem[method]);
|
|
737
|
+
if (!operation) continue;
|
|
738
|
+
const operationId = typeof operation.operationId === "string" && operation.operationId.trim() ? operation.operationId.trim() : `${method}_${path.replace(/[^a-zA-Z0-9]+/g, "_")}`;
|
|
739
|
+
if (!(allow.has(operationId) || allow.has(selectorFor(method, path)) || operationExtensionEnabled(operation))) continue;
|
|
740
|
+
if (![
|
|
741
|
+
"get",
|
|
742
|
+
"head",
|
|
743
|
+
"options"
|
|
744
|
+
].includes(method) && config.allowMutations !== true) continue;
|
|
745
|
+
const toolName = sanitizeToolName(operationId);
|
|
746
|
+
if (names.has(toolName)) throw new Error(`OpenAPI MCP tool name collision: ${toolName}`);
|
|
747
|
+
names.add(toolName);
|
|
748
|
+
const security = operation.security === void 0 ? globalSecurity : normalizeSecurity(operation.security);
|
|
749
|
+
const usedSchemeNames = new Set(security.flatMap((requirement) => Object.keys(requirement)));
|
|
750
|
+
const usedSecuritySchemes = Object.fromEntries(Object.entries(securitySchemes).filter(([name]) => usedSchemeNames.has(name)));
|
|
751
|
+
operations.push({
|
|
752
|
+
toolName,
|
|
753
|
+
operationId,
|
|
754
|
+
method: method.toUpperCase(),
|
|
755
|
+
path,
|
|
756
|
+
title: typeof operation.summary === "string" && operation.summary.trim() || typeof operation.description === "string" && operation.description.trim() || selectorFor(method, path),
|
|
757
|
+
...typeof operation.description === "string" && operation.description.trim() ? { description: operation.description.trim() } : {},
|
|
758
|
+
parameters: normalizeParameters(pathItem.parameters, operation.parameters),
|
|
759
|
+
security,
|
|
760
|
+
securitySchemes: usedSecuritySchemes,
|
|
761
|
+
readOnly: method === "get" || method === "head",
|
|
762
|
+
destructive: method === "delete",
|
|
763
|
+
idempotent: [
|
|
764
|
+
"GET",
|
|
765
|
+
"HEAD",
|
|
766
|
+
"PUT",
|
|
767
|
+
"DELETE",
|
|
768
|
+
"OPTIONS"
|
|
769
|
+
].includes(method.toUpperCase())
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
return operations.sort((left, right) => left.toolName.localeCompare(right.toolName));
|
|
774
|
+
}
|
|
775
|
+
function resolveDocsOpenApiMcpBaseUrl(document, config) {
|
|
776
|
+
const configured = config.baseUrl?.trim();
|
|
777
|
+
if (configured) return configured;
|
|
778
|
+
const servers = Array.isArray(document.servers) ? document.servers : [];
|
|
779
|
+
for (const server of servers) {
|
|
780
|
+
const url = asRecord(server)?.url;
|
|
781
|
+
if (typeof url === "string" && url.trim()) return url.trim();
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
//#endregion
|
|
786
|
+
export { isLocalDocsTelemetryOrigin as C, inferDocsTelemetryAgentSurface as S, resolveDocsTelemetryConfig as T, emitDocsTelemetryAgentSurfaceEvent as _, DEFAULT_DOCS_CONTENT_CHANGE_HYDRATION_TOKEN_BUDGET as a, emitDocsTelemetryProjectEvent as b, MIN_DOCS_CONTENT_CHANGE_HYDRATION_TOKEN_BUDGET as c, GENERATED_AGENT_PROVENANCE_VERSION as d, hashGeneratedAgentContent as f, stripGeneratedAgentProvenance as g, serializeGeneratedAgentDocument as h, resolveDocsOpenApiMcpOperations as i, hydrateDocsContentChanges as l, parseGeneratedAgentDocument as m, readDocsOpenApiMcpResponse as n, DOCS_CONTENT_CHANGE_HYDRATION_FORMAT as o, normalizeGeneratedAgentContent as p, resolveDocsOpenApiMcpBaseUrl as r, MAX_DOCS_CONTENT_CHANGE_HYDRATION_TOKEN_BUDGET as s, acquireDocsOpenApiMcpBudget as t, GENERATED_AGENT_PROVENANCE_MARKER as u, emitDocsTelemetryEvent as v, normalizeDocsTelemetryOrigin as w, getDocsTelemetryFeatures as x, emitDocsTelemetryMcpToolEvent as y };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { lookup } from "node:dns/promises";
|
|
2
|
+
import { isIP } from "node:net";
|
|
3
|
+
|
|
4
|
+
//#region src/openapi-mcp-node.ts
|
|
5
|
+
function isPrivateIpv4(address) {
|
|
6
|
+
const octets = address.split(".").map(Number);
|
|
7
|
+
if (octets.length !== 4 || octets.some((octet) => !Number.isInteger(octet))) return true;
|
|
8
|
+
const [a, b] = octets;
|
|
9
|
+
return a === 0 || a === 10 || a === 127 || a === 100 && b >= 64 && b <= 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && (b === 0 || b === 168) || a === 198 && (b === 18 || b === 19) || a >= 224;
|
|
10
|
+
}
|
|
11
|
+
function isDocsOpenApiMcpPrivateAddress(address) {
|
|
12
|
+
const normalized = address.trim().toLowerCase().replace(/^\[|\]$/gu, "");
|
|
13
|
+
const family = isIP(normalized);
|
|
14
|
+
if (family === 4) return isPrivateIpv4(normalized);
|
|
15
|
+
if (family !== 6) return true;
|
|
16
|
+
const mappedIpv4 = normalized.match(/^(?:::ffff:)(\d+\.\d+\.\d+\.\d+)$/u)?.[1];
|
|
17
|
+
if (mappedIpv4) return isPrivateIpv4(mappedIpv4);
|
|
18
|
+
return normalized === "::" || normalized === "::1" || normalized.startsWith("fc") || normalized.startsWith("fd") || /^fe[89ab]/u.test(normalized) || normalized.startsWith("ff");
|
|
19
|
+
}
|
|
20
|
+
async function defaultResolveHost(hostname) {
|
|
21
|
+
if (isIP(hostname)) return [hostname];
|
|
22
|
+
return (await lookup(hostname, {
|
|
23
|
+
all: true,
|
|
24
|
+
verbatim: true
|
|
25
|
+
})).map((entry) => entry.address);
|
|
26
|
+
}
|
|
27
|
+
async function validateDocsOpenApiMcpUrl(url, config) {
|
|
28
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && config.allowInsecureHttp)) throw new Error("OpenAPI MCP destinations must use HTTPS unless allowInsecureHttp is enabled.");
|
|
29
|
+
if (url.username || url.password) throw new Error("OpenAPI MCP destinations cannot contain URL credentials.");
|
|
30
|
+
if (config.allowPrivateNetwork) return;
|
|
31
|
+
const hostname = url.hostname.toLowerCase().replace(/^\[|\]$/gu, "");
|
|
32
|
+
if (hostname === "localhost" || hostname.endsWith(".localhost") || hostname.endsWith(".local") || hostname.endsWith(".internal") || hostname === "metadata.google.internal") throw new Error(`OpenAPI MCP blocked private destination: ${hostname}`);
|
|
33
|
+
let addresses;
|
|
34
|
+
try {
|
|
35
|
+
addresses = await (config.resolveHost ?? defaultResolveHost)(hostname);
|
|
36
|
+
} catch {
|
|
37
|
+
throw new Error(`OpenAPI MCP could not safely resolve destination: ${hostname}`);
|
|
38
|
+
}
|
|
39
|
+
if (addresses.length === 0 || addresses.some(isDocsOpenApiMcpPrivateAddress)) throw new Error(`OpenAPI MCP blocked private or unresolved destination: ${hostname}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
export { validateDocsOpenApiMcpUrl as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as detectPackageManagerFromProject, l as formatPackageManagerDetection, t as detectFramework, u as installCommand } from "./utils-
|
|
1
|
+
import { i as detectPackageManagerFromProject, l as formatPackageManagerDetection, t as detectFramework, u as installCommand } from "./utils-Cc1SrVza.mjs";
|
|
2
2
|
import pc from "picocolors";
|
|
3
3
|
import * as p from "@clack/prompts";
|
|
4
4
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { C as DOCS_AGENT_MANIFEST_SCHEMA_MEDIA_TYPE, S as DOCS_AGENT_MANIFEST_FORMAT, T as DOCS_AGENT_MANIFEST_VERSION, f as DEFAULT_AGENT_SKILLS_ROUTE_PREFIX, n as API_CATALOG_MEDIA_TYPE, r as API_CATALOG_PROFILE_URI, t as AGENT_SKILLS_DISCOVERY_SCHEMA_URI, u as DEFAULT_AGENT_SKILLS_INDEX_ROUTE, v as DEFAULT_API_CATALOG_ROUTE, w as DOCS_AGENT_MANIFEST_SCHEMA_URI } from "./standards-discovery-
|
|
1
|
+
import { Un as DEFAULT_MCP_WELL_KNOWN_ROUTE, c as DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, f as DEFAULT_DOCS_CONFIG_ROUTE, 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, m as DEFAULT_DOCS_DIAGNOSTICS_ROUTE, t as DEFAULT_AGENTS_MD_ROUTE, v as DEFAULT_LLMS_TXT_ROUTE, x as DEFAULT_SKILL_MD_ROUTE } from "./agent-DCTGj6J7.mjs";
|
|
2
|
+
import { C as DOCS_AGENT_MANIFEST_SCHEMA_MEDIA_TYPE, S as DOCS_AGENT_MANIFEST_FORMAT, T as DOCS_AGENT_MANIFEST_VERSION, f as DEFAULT_AGENT_SKILLS_ROUTE_PREFIX, n as API_CATALOG_MEDIA_TYPE, r as API_CATALOG_PROFILE_URI, t as AGENT_SKILLS_DISCOVERY_SCHEMA_URI, u as DEFAULT_AGENT_SKILLS_INDEX_ROUTE, v as DEFAULT_API_CATALOG_ROUTE, w as DOCS_AGENT_MANIFEST_SCHEMA_URI } from "./standards-discovery-Bpz90VYq.mjs";
|
|
3
3
|
import { isDocsAgentSkillName, validateDocsAgentSkillFrontmatter } from "./agent-skills-spec.mjs";
|
|
4
|
-
import { n as DEFAULT_ROBOTS_TXT_ROUTE } from "./robots-
|
|
4
|
+
import { n as DEFAULT_ROBOTS_TXT_ROUTE } from "./robots-BOjWB1ky.mjs";
|
|
5
5
|
import matter from "gray-matter";
|
|
6
6
|
|
|
7
7
|
//#region src/define-docs.ts
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { n as analyzeDocsAgentMaintenanceSignals, r as parseDocsAgentMaintenanceSignals } from "./agent-maintenance-CuZ7iAKq.mjs";
|
|
2
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
|
|
6
|
+
//#region src/cli/propose.ts
|
|
7
|
+
function parseAgentMaintenanceProposeArgs(argv) {
|
|
8
|
+
const options = { inputs: [] };
|
|
9
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
10
|
+
const argument = argv[index];
|
|
11
|
+
if (argument === "--write") options.write = true;
|
|
12
|
+
else if (argument === "--json") options.json = true;
|
|
13
|
+
else if (argument === "--help" || argument === "-h") options.help = true;
|
|
14
|
+
else if (argument === "--input" || argument === "--output" || argument === "--min-occurrences") {
|
|
15
|
+
const value = argv[index + 1];
|
|
16
|
+
if (!value || value.startsWith("--")) throw new Error(`${argument} requires a value.`);
|
|
17
|
+
index += 1;
|
|
18
|
+
if (argument === "--input") options.inputs.push(value);
|
|
19
|
+
else if (argument === "--output") options.output = value;
|
|
20
|
+
else {
|
|
21
|
+
const parsed = Number(value);
|
|
22
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 100) throw new Error("--min-occurrences must be an integer from 1 through 100.");
|
|
23
|
+
options.minOccurrences = parsed;
|
|
24
|
+
}
|
|
25
|
+
} else throw new Error(`Unknown agent propose flag: ${argument}`);
|
|
26
|
+
}
|
|
27
|
+
return options;
|
|
28
|
+
}
|
|
29
|
+
function resolveProjectPath(rootDir, value) {
|
|
30
|
+
if (path.isAbsolute(value)) throw new Error("Maintenance paths must be project-relative.");
|
|
31
|
+
const candidate = path.resolve(rootDir, value);
|
|
32
|
+
const relative = path.relative(rootDir, candidate);
|
|
33
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error("Maintenance paths must stay inside the project root.");
|
|
34
|
+
return candidate;
|
|
35
|
+
}
|
|
36
|
+
function writeReport(outputPath, report) {
|
|
37
|
+
mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
38
|
+
const temporaryPath = `${outputPath}.${process.pid}.tmp`;
|
|
39
|
+
writeFileSync(temporaryPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
40
|
+
renameSync(temporaryPath, outputPath);
|
|
41
|
+
}
|
|
42
|
+
async function runAgentMaintenancePropose(options = {}) {
|
|
43
|
+
const rootDir = path.resolve(options.rootDir ?? process.cwd());
|
|
44
|
+
const report = analyzeDocsAgentMaintenanceSignals((options.inputs && options.inputs.length > 0 ? options.inputs : [".farming-labs/agent-feedback-improvements.json"]).flatMap((input) => parseDocsAgentMaintenanceSignals(readFileSync(resolveProjectPath(rootDir, input), "utf8"))), { minOccurrences: options.minOccurrences });
|
|
45
|
+
if (options.write) {
|
|
46
|
+
const outputPath = resolveProjectPath(rootDir, options.output ?? ".farming-labs/agent-maintenance-proposals.json");
|
|
47
|
+
writeReport(outputPath, report);
|
|
48
|
+
if (!options.json) console.log(pc.green(`Wrote ${path.relative(rootDir, outputPath)} with ${report.proposalCount} reviewable proposal${report.proposalCount === 1 ? "" : "s"}.`));
|
|
49
|
+
}
|
|
50
|
+
if (options.json || !options.write) console.log(JSON.stringify(report, null, 2));
|
|
51
|
+
return report;
|
|
52
|
+
}
|
|
53
|
+
function printAgentMaintenanceProposeHelp() {
|
|
54
|
+
console.log(`${pc.bold("docs agent propose")} — turn recurring signals into reviewable maintenance drafts
|
|
55
|
+
|
|
56
|
+
${pc.dim("Usage:")}
|
|
57
|
+
docs agent propose --input .farming-labs/agent-feedback-improvements.json
|
|
58
|
+
docs agent propose --input search-signals.jsonl --input support-signals.json --write
|
|
59
|
+
|
|
60
|
+
${pc.dim("Options:")}
|
|
61
|
+
${pc.cyan("--input <path>")} Repeatable JSON/JSONL signal or feedback report
|
|
62
|
+
${pc.cyan("--min-occurrences <1-100>")} Proposal threshold (default: 2)
|
|
63
|
+
${pc.cyan("--write")} Write the draft-only proposal report
|
|
64
|
+
${pc.cyan("--output <path>")} Output path (default: .farming-labs/agent-maintenance-proposals.json)
|
|
65
|
+
${pc.cyan("--json")} Print JSON when writing
|
|
66
|
+
|
|
67
|
+
Signal sources: agent-feedback, ask-ai, git, issue, mcp, search, support.
|
|
68
|
+
The command never edits documentation, creates issues, publishes branches, or merges changes.
|
|
69
|
+
`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
//#endregion
|
|
73
|
+
export { parseAgentMaintenanceProposeArgs, printAgentMaintenanceProposeHelp, runAgentMaintenancePropose };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
//#region src/retrieval-digest.ts
|
|
2
|
+
const SHA256_INITIAL_STATE = [
|
|
3
|
+
1779033703,
|
|
4
|
+
3144134277,
|
|
5
|
+
1013904242,
|
|
6
|
+
2773480762,
|
|
7
|
+
1359893119,
|
|
8
|
+
2600822924,
|
|
9
|
+
528734635,
|
|
10
|
+
1541459225
|
|
11
|
+
];
|
|
12
|
+
const SHA256_ROUND_CONSTANTS = [
|
|
13
|
+
1116352408,
|
|
14
|
+
1899447441,
|
|
15
|
+
3049323471,
|
|
16
|
+
3921009573,
|
|
17
|
+
961987163,
|
|
18
|
+
1508970993,
|
|
19
|
+
2453635748,
|
|
20
|
+
2870763221,
|
|
21
|
+
3624381080,
|
|
22
|
+
310598401,
|
|
23
|
+
607225278,
|
|
24
|
+
1426881987,
|
|
25
|
+
1925078388,
|
|
26
|
+
2162078206,
|
|
27
|
+
2614888103,
|
|
28
|
+
3248222580,
|
|
29
|
+
3835390401,
|
|
30
|
+
4022224774,
|
|
31
|
+
264347078,
|
|
32
|
+
604807628,
|
|
33
|
+
770255983,
|
|
34
|
+
1249150122,
|
|
35
|
+
1555081692,
|
|
36
|
+
1996064986,
|
|
37
|
+
2554220882,
|
|
38
|
+
2821834349,
|
|
39
|
+
2952996808,
|
|
40
|
+
3210313671,
|
|
41
|
+
3336571891,
|
|
42
|
+
3584528711,
|
|
43
|
+
113926993,
|
|
44
|
+
338241895,
|
|
45
|
+
666307205,
|
|
46
|
+
773529912,
|
|
47
|
+
1294757372,
|
|
48
|
+
1396182291,
|
|
49
|
+
1695183700,
|
|
50
|
+
1986661051,
|
|
51
|
+
2177026350,
|
|
52
|
+
2456956037,
|
|
53
|
+
2730485921,
|
|
54
|
+
2820302411,
|
|
55
|
+
3259730800,
|
|
56
|
+
3345764771,
|
|
57
|
+
3516065817,
|
|
58
|
+
3600352804,
|
|
59
|
+
4094571909,
|
|
60
|
+
275423344,
|
|
61
|
+
430227734,
|
|
62
|
+
506948616,
|
|
63
|
+
659060556,
|
|
64
|
+
883997877,
|
|
65
|
+
958139571,
|
|
66
|
+
1322822218,
|
|
67
|
+
1537002063,
|
|
68
|
+
1747873779,
|
|
69
|
+
1955562222,
|
|
70
|
+
2024104815,
|
|
71
|
+
2227730452,
|
|
72
|
+
2361852424,
|
|
73
|
+
2428436474,
|
|
74
|
+
2756734187,
|
|
75
|
+
3204031479,
|
|
76
|
+
3329325298
|
|
77
|
+
];
|
|
78
|
+
function rotateRight(value, bits) {
|
|
79
|
+
return value >>> bits | value << 32 - bits;
|
|
80
|
+
}
|
|
81
|
+
function normalizeDigestContent(value) {
|
|
82
|
+
return value.replace(/\r\n?/gu, "\n").replace(/^\uFEFF/u, "").trimEnd();
|
|
83
|
+
}
|
|
84
|
+
function toSha256Bytes(value) {
|
|
85
|
+
return typeof value === "string" ? new TextEncoder().encode(value) : value;
|
|
86
|
+
}
|
|
87
|
+
/** Validate the bounded HTTP(S) URL or root-relative URI reference used by provenance. */
|
|
88
|
+
function isDocsRetrievalCanonicalUrl(value) {
|
|
89
|
+
const hasUnsafeCharacter = value.includes("\\") || Array.from(value).some((character) => {
|
|
90
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
91
|
+
return codePoint <= 31 || codePoint === 127;
|
|
92
|
+
});
|
|
93
|
+
if (!value || value !== value.trim() || value.length > 4096 || hasUnsafeCharacter) return false;
|
|
94
|
+
if (/^\/(?!\/)/u.test(value)) try {
|
|
95
|
+
new URL(value, "https://docs.local");
|
|
96
|
+
return true;
|
|
97
|
+
} catch {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const url = new URL(value);
|
|
102
|
+
return (url.protocol === "http:" || url.protocol === "https:") && !url.username && !url.password;
|
|
103
|
+
} catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Hash exact bytes with portable SHA-256 in Node, edge, and browser runtimes. */
|
|
108
|
+
function sha256DocsContent(value) {
|
|
109
|
+
const input = toSha256Bytes(value);
|
|
110
|
+
const paddedLength = Math.ceil((input.length + 9) / 64) * 64;
|
|
111
|
+
const padded = new Uint8Array(paddedLength);
|
|
112
|
+
padded.set(input);
|
|
113
|
+
padded[input.length] = 128;
|
|
114
|
+
const bitLength = input.length * 8;
|
|
115
|
+
const dataView = new DataView(padded.buffer);
|
|
116
|
+
dataView.setUint32(paddedLength - 8, Math.floor(bitLength / 4294967296), false);
|
|
117
|
+
dataView.setUint32(paddedLength - 4, bitLength >>> 0, false);
|
|
118
|
+
const state = Uint32Array.from(SHA256_INITIAL_STATE);
|
|
119
|
+
const words = new Uint32Array(64);
|
|
120
|
+
for (let offset = 0; offset < padded.length; offset += 64) {
|
|
121
|
+
for (let index = 0; index < 16; index += 1) words[index] = dataView.getUint32(offset + index * 4, false);
|
|
122
|
+
for (let index = 16; index < 64; index += 1) {
|
|
123
|
+
const previous15 = words[index - 15];
|
|
124
|
+
const previous2 = words[index - 2];
|
|
125
|
+
const sigma0 = rotateRight(previous15, 7) ^ rotateRight(previous15, 18) ^ previous15 >>> 3;
|
|
126
|
+
const sigma1 = rotateRight(previous2, 17) ^ rotateRight(previous2, 19) ^ previous2 >>> 10;
|
|
127
|
+
words[index] = words[index - 16] + sigma0 + words[index - 7] + sigma1 >>> 0;
|
|
128
|
+
}
|
|
129
|
+
let a = state[0];
|
|
130
|
+
let b = state[1];
|
|
131
|
+
let c = state[2];
|
|
132
|
+
let d = state[3];
|
|
133
|
+
let e = state[4];
|
|
134
|
+
let f = state[5];
|
|
135
|
+
let g = state[6];
|
|
136
|
+
let h = state[7];
|
|
137
|
+
for (let index = 0; index < 64; index += 1) {
|
|
138
|
+
const sum1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
|
|
139
|
+
const choice = e & f ^ ~e & g;
|
|
140
|
+
const temporary1 = h + sum1 + choice + SHA256_ROUND_CONSTANTS[index] + words[index] >>> 0;
|
|
141
|
+
const temporary2 = (rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22)) + (a & b ^ a & c ^ b & c) >>> 0;
|
|
142
|
+
h = g;
|
|
143
|
+
g = f;
|
|
144
|
+
f = e;
|
|
145
|
+
e = d + temporary1 >>> 0;
|
|
146
|
+
d = c;
|
|
147
|
+
c = b;
|
|
148
|
+
b = a;
|
|
149
|
+
a = temporary1 + temporary2 >>> 0;
|
|
150
|
+
}
|
|
151
|
+
state[0] = state[0] + a >>> 0;
|
|
152
|
+
state[1] = state[1] + b >>> 0;
|
|
153
|
+
state[2] = state[2] + c >>> 0;
|
|
154
|
+
state[3] = state[3] + d >>> 0;
|
|
155
|
+
state[4] = state[4] + e >>> 0;
|
|
156
|
+
state[5] = state[5] + f >>> 0;
|
|
157
|
+
state[6] = state[6] + g >>> 0;
|
|
158
|
+
state[7] = state[7] + h >>> 0;
|
|
159
|
+
}
|
|
160
|
+
return Array.from(state, (word) => word.toString(16).padStart(8, "0")).join("");
|
|
161
|
+
}
|
|
162
|
+
/** Hash exact message-content bytes with portable SHA-256. */
|
|
163
|
+
function digestDocsContent(value) {
|
|
164
|
+
return `sha256:${sha256DocsContent(value)}`;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Hash the normalized retrieval projection used by search provenance.
|
|
168
|
+
*
|
|
169
|
+
* The projection removes one leading BOM, normalizes line endings to LF, and trims
|
|
170
|
+
* trailing whitespace. This deliberately differs from HTTP digests over exact bytes.
|
|
171
|
+
*/
|
|
172
|
+
function digestDocsRetrievalContent(value) {
|
|
173
|
+
return digestDocsContent(normalizeDigestContent(value));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
//#endregion
|
|
177
|
+
export { sha256DocsContent as i, digestDocsRetrievalContent as n, isDocsRetrievalCanonicalUrl as r, digestDocsContent as t };
|