kennel 0.2.24 → 0.2.26

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.
Files changed (88) hide show
  1. package/dist/cli/dispatch.js +2 -2
  2. package/dist/cli/usage.js +7 -1
  3. package/dist/core/api-client.js +1 -2
  4. package/dist/core/command.js +1 -1
  5. package/dist/core/core-folders.js +6 -2
  6. package/dist/core/runtime.js +30 -4657
  7. package/dist/mcp/install-page.d.ts +1 -1
  8. package/dist/mcp/install-page.js +419 -4
  9. package/dist/package/preview.d.ts +4 -0
  10. package/dist/package/preview.js +790 -4990
  11. package/dist/site/hot-viewer.js +1 -1
  12. package/dist/site/kinds.d.ts +1 -1
  13. package/dist/site/kinds.js +2 -59
  14. package/dist/site/terminal.d.ts +9 -1
  15. package/dist/site/terminal.js +162 -20
  16. package/package.json +5 -5
  17. package/web/assets/{abnfDiagram-VRR7QNED-aRemVX7f.js → abnfDiagram-VRR7QNED-CIyEzNaJ.js} +1 -1
  18. package/web/assets/{arc-BpDsnNTf.js → arc-Dba3y3eW.js} +1 -1
  19. package/web/assets/{architectureDiagram-ZJ3FMSHR-DNXHQddP.js → architectureDiagram-ZJ3FMSHR-DjFjO3tR.js} +1 -1
  20. package/web/assets/ask-tray-PMT6VVXN-ButKBzsY.js +23 -0
  21. package/web/assets/{blockDiagram-677ZJIJ3-CF4H4upo.js → blockDiagram-677ZJIJ3-C8ZQgtnK.js} +1 -1
  22. package/web/assets/{c4Diagram-LMCZKHZV-BPWUnjtx.js → c4Diagram-LMCZKHZV-DhWn2tZm.js} +1 -1
  23. package/web/assets/channel-BuqSObVl.js +1 -0
  24. package/web/assets/{chunk-2Q5K7J3B-DGsa7uv7.js → chunk-2Q5K7J3B-BEkPxYAB.js} +1 -1
  25. package/web/assets/{chunk-32BRIVSS-BRfic3W2.js → chunk-32BRIVSS-BZ0ofM9m.js} +1 -1
  26. package/web/assets/{chunk-5VM5RSS4-L2h7hliu.js → chunk-5VM5RSS4-CTgBiom0.js} +1 -1
  27. package/web/assets/{chunk-EX3LRPZG-BPgD_fgx.js → chunk-EX3LRPZG-B7lDJEfz.js} +1 -1
  28. package/web/assets/{chunk-JWPE2WC7-CckCaqu_.js → chunk-JWPE2WC7-DotlQGla.js} +1 -1
  29. package/web/assets/{chunk-MOJQB5TN-zyGgx-VW.js → chunk-MOJQB5TN-BSlB5ICN.js} +1 -1
  30. package/web/assets/{chunk-RYQCIY6F-Drzpg5IG.js → chunk-RYQCIY6F-BbDvgRvj.js} +1 -1
  31. package/web/assets/{chunk-V7JOEXUC-Di4ESKz-.js → chunk-V7JOEXUC-CqC2yHBO.js} +1 -1
  32. package/web/assets/{chunk-VR4S4FIN-C5lQtDI1.js → chunk-VR4S4FIN-18aLOCVw.js} +1 -1
  33. package/web/assets/{chunk-XXDRQBXY-Cell0ft2.js → chunk-XXDRQBXY-uulB67ep.js} +1 -1
  34. package/web/assets/classDiagram-OUVF2IWQ-xfk1LZB_.js +1 -0
  35. package/web/assets/classDiagram-v2-EOCWNBFH-xfk1LZB_.js +1 -0
  36. package/web/assets/{cose-bilkent-JH36ORCC-CiKtOFxl.js → cose-bilkent-JH36ORCC-C8yqL7ml.js} +1 -1
  37. package/web/assets/{cynefin-VYW2F7L2-B75MWf5b.js → cynefin-VYW2F7L2-D-wd85t1.js} +1 -1
  38. package/web/assets/{cynefinDiagram-TSTJHNR4-BmNVkSWW.js → cynefinDiagram-TSTJHNR4-rrV6rLov.js} +1 -1
  39. package/web/assets/{dagre-VKFMJZFB-BcM1Wqu5.js → dagre-VKFMJZFB-BxwiLhMr.js} +1 -1
  40. package/web/assets/{diagram-FQU43EPY-BiBWrxa8.js → diagram-FQU43EPY-8sr7lcj4.js} +1 -1
  41. package/web/assets/{diagram-G47NLZAW-Cfxukr7T.js → diagram-G47NLZAW-BQIU_Mie.js} +1 -1
  42. package/web/assets/{diagram-NH7WQ7WH-C83VkBYW.js → diagram-NH7WQ7WH-Bt-xVbVq.js} +1 -1
  43. package/web/assets/{diagram-OA4YK3LP-Oj0uj6CX.js → diagram-OA4YK3LP-p-i-3cps.js} +1 -1
  44. package/web/assets/{diagram-WEI45ONY-DhbL0nvt.js → diagram-WEI45ONY-E6t6-_mU.js} +1 -1
  45. package/web/assets/{ebnfDiagram-CCIWWBDH-D4JYp1UC.js → ebnfDiagram-CCIWWBDH-DCszfyU3.js} +1 -1
  46. package/web/assets/{entity-search-page-G6QEQNXT-UKzUU5id.js → entity-search-page-G6QEQNXT-D6cvoqrF.js} +1 -1
  47. package/web/assets/{erDiagram-Q63AITRT-C-oyRt9s.js → erDiagram-Q63AITRT-C4gBewIM.js} +1 -1
  48. package/web/assets/{flowDiagram-23GEKE2U-0Tplj9FK.js → flowDiagram-23GEKE2U-BEyFAV-g.js} +1 -1
  49. package/web/assets/{ganttDiagram-NO4QXBWP-wgh2e0B_.js → ganttDiagram-NO4QXBWP-Bat5BF2x.js} +1 -1
  50. package/web/assets/{gitGraphDiagram-IHSO6WYX-D6z9qDXa.js → gitGraphDiagram-IHSO6WYX-CGZs8b5E.js} +1 -1
  51. package/web/assets/index-DmJQJIC1.js +451 -0
  52. package/web/assets/{index-BGwTWQMJ.css → index-tpV2etC4.css} +1 -1
  53. package/web/assets/{infoDiagram-FWYZ7A6U-D3o7el5X.js → infoDiagram-FWYZ7A6U-Cglwuazb.js} +1 -1
  54. package/web/assets/{ishikawaDiagram-FXEZZL3T-CM0QyWYH.js → ishikawaDiagram-FXEZZL3T-C95-Gz9z.js} +1 -1
  55. package/web/assets/{journeyDiagram-5HDEW3XC-fmIoh0h6.js → journeyDiagram-5HDEW3XC-C055Trr6.js} +1 -1
  56. package/web/assets/{kanban-definition-HUTT4EX6-aEtqsiWf.js → kanban-definition-HUTT4EX6-CznSv3_t.js} +1 -1
  57. package/web/assets/{linear-aJ-2UZO5.js → linear-CnWGyi6E.js} +1 -1
  58. package/web/assets/{linked-session-header-M7WY6IGF-CltMJZiX.js → linked-session-header-M7WY6IGF-BFioq_q7.js} +1 -1
  59. package/web/assets/{mermaid.core-CL9g6xVu.js → mermaid.core-BIJiZKob.js} +4 -4
  60. package/web/assets/{mindmap-definition-LN4V7U3C-CtQo0XrW.js → mindmap-definition-LN4V7U3C-k97sTi1e.js} +1 -1
  61. package/web/assets/{pegDiagram-2B236MQR-ecu1L_3A.js → pegDiagram-2B236MQR-C-4ETzyd.js} +1 -1
  62. package/web/assets/{pieDiagram-ENE6RG2P-CdCKg3Cn.js → pieDiagram-ENE6RG2P-CH8gYIx3.js} +1 -1
  63. package/web/assets/{plugin-host-modules-Dz_BPJRS.js → plugin-host-modules-BI0aGGBk.js} +2 -2
  64. package/web/assets/{project-search-dialog-HJFGW4DG-CKtXc-UP.js → project-search-dialog-HJFGW4DG-DC6mBFkm.js} +1 -1
  65. package/web/assets/{project-search-page-NKQEBGPF-CMzuYEeM.js → project-search-page-NKQEBGPF-B0OxN-l5.js} +1 -1
  66. package/web/assets/{quadrantDiagram-ABIIQ3AL-Bt8r5TlW.js → quadrantDiagram-ABIIQ3AL-BFV2fyQY.js} +1 -1
  67. package/web/assets/{railroadDiagram-RFXS5EU6-DrWDVEVi.js → railroadDiagram-RFXS5EU6-Dxj8XtW1.js} +1 -1
  68. package/web/assets/{requirementDiagram-TGXJPOKE-Ewjwpo6V.js → requirementDiagram-TGXJPOKE-Drb3A2JL.js} +1 -1
  69. package/web/assets/{sankeyDiagram-HTMAVEWB-CJCMHuzX.js → sankeyDiagram-HTMAVEWB-DP7Lyg91.js} +1 -1
  70. package/web/assets/{selection-popup-532EHNCZ-py5aCy1E.js → selection-popup-532EHNCZ-C8EBNgOw.js} +1 -1
  71. package/web/assets/{sequenceDiagram-DBY2YBRQ-Chj-4L6Q.js → sequenceDiagram-DBY2YBRQ-6qzKd9e_.js} +1 -1
  72. package/web/assets/{sizeCapture-X5ZJPWSS-BguWhDIF.js → sizeCapture-X5ZJPWSS-DhCU_-w6.js} +1 -1
  73. package/web/assets/{stateDiagram-2N3HPSRC-BWisWMpK.js → stateDiagram-2N3HPSRC-C_BN15Uj.js} +1 -1
  74. package/web/assets/{stateDiagram-v2-6OUMAXLB-AiBXToz-.js → stateDiagram-v2-6OUMAXLB-DtNCoZjH.js} +1 -1
  75. package/web/assets/{swimlanes-5IMT3BWC-CxVQ97_C.js → swimlanes-5IMT3BWC-CW-FMmDB.js} +2 -2
  76. package/web/assets/swimlanesDiagram-G3AALYLV-Cak69Ty7.js +8 -0
  77. package/web/assets/{timeline-definition-FHXFAJF6-CCbI0InF.js → timeline-definition-FHXFAJF6-VX8Kq-Hg.js} +1 -1
  78. package/web/assets/{vennDiagram-L72KCM5P-mA5yKpJj.js → vennDiagram-L72KCM5P-DU3qCuRJ.js} +1 -1
  79. package/web/assets/{wardleyDiagram-EHGQE667-1Epw2EsU.js → wardleyDiagram-EHGQE667-CAA7wYyD.js} +1 -1
  80. package/web/assets/{xychartDiagram-FW5EYKEG-DM1CMD-p.js → xychartDiagram-FW5EYKEG-B-GbIjdQ.js} +1 -1
  81. package/web/index.html +2 -2
  82. package/README.md +0 -317
  83. package/web/assets/ask-tray-PMT6VVXN-HMPARq3A.js +0 -23
  84. package/web/assets/channel-CEZ4sDYU.js +0 -1
  85. package/web/assets/classDiagram-OUVF2IWQ-CjxqMQn2.js +0 -1
  86. package/web/assets/classDiagram-v2-EOCWNBFH-CjxqMQn2.js +0 -1
  87. package/web/assets/index-D_Fcgs3V.js +0 -451
  88. package/web/assets/swimlanesDiagram-G3AALYLV-DliPmGmf.js +0 -8
@@ -1,4 +1,4 @@
1
- import { installPageLink, installPageMarkdownPath, renderInstallPage } from 'kennel-knowledge/install-page';
1
+ import { installPageLink, installPageMarkdownPath, renderInstallPage } from 'kennel-schemas/knowledge/install-page';
2
2
  export { installPageLink, installPageMarkdownPath, renderInstallPage, };
3
3
  export type InstallModel = {
4
4
  description: string;
@@ -1,5 +1,420 @@
1
- import { installPageLink, installPageMarkdownPath, renderInstallPage, writeInstallPage as writeSharedInstallPage, } from 'kennel-knowledge/install-page';
2
- export { installPageLink, installPageMarkdownPath, renderInstallPage, };
3
- export function writeInstallPage(root, config) {
4
- return writeSharedInstallPage(config, root);
1
+ // packages/schemas/src/knowledge/install-page.js
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { dirname, resolve, sep } from "node:path";
4
+ var defaultSources = [
5
+ {
6
+ text: "Claude Code deep links",
7
+ url: "https://code.claude.com/docs/en/deep-links"
8
+ },
9
+ { text: "Claude Code MCP", url: "https://code.claude.com/docs/en/mcp" },
10
+ {
11
+ text: "Codex app deep links",
12
+ url: "https://developers.openai.com/codex/app/commands#deep-links"
13
+ },
14
+ { text: "Codex MCP", url: "https://developers.openai.com/codex/mcp" },
15
+ {
16
+ text: "Cursor deep links",
17
+ url: "https://cursor.com/docs/reference/deeplinks"
18
+ },
19
+ { text: "Cursor MCP", url: "https://cursor.com/docs/mcp" },
20
+ {
21
+ text: "Copilot Studio MCP onboarding",
22
+ url: "https://learn.microsoft.com/en-us/microsoft-copilot-studio/mcp-add-existing-server-to-agent"
23
+ },
24
+ {
25
+ text: "Microsoft 365 agent connectors for MCP",
26
+ url: "https://learn.microsoft.com/en-us/microsoftteams/platform/m365-apps/agent-connectors"
27
+ }
28
+ ];
29
+ function enabledInstallConfig(docsConfig = {}) {
30
+ const install = docsConfig.install;
31
+ if (!install || install.enabled === false)
32
+ return;
33
+ if (install.enabled !== true && !publicMcpEndpoint(docsConfig))
34
+ return;
35
+ return install;
5
36
  }
37
+ function stringValue(value) {
38
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
39
+ }
40
+ function mcpEndpoints(docsConfig = {}) {
41
+ const endpoints = docsConfig.mcp?.endpoints ?? {};
42
+ const installMcp = docsConfig.install?.mcp ?? {};
43
+ return {
44
+ portal: stringValue(endpoints.portal),
45
+ protected: stringValue(installMcp.protectedUrl) ?? stringValue(endpoints.protected),
46
+ public: stringValue(installMcp.publicUrl) ?? stringValue(endpoints.public)
47
+ };
48
+ }
49
+ function publicMcpEndpoint(docsConfig = {}) {
50
+ return mcpEndpoints(docsConfig).public;
51
+ }
52
+ function installPageMarkdownPath(docsConfig = {}) {
53
+ const install = enabledInstallConfig(docsConfig);
54
+ const configuredPath = install?.path ?? "install.md";
55
+ const path = String(configuredPath).replace(/^\/+/, "");
56
+ if (!path || path.split("/").includes("..")) {
57
+ throw new Error(`Invalid install.path: ${configuredPath}`);
58
+ }
59
+ return path.endsWith(".md") ? path : `${path}.md`;
60
+ }
61
+ function installPageLink(docsConfig = {}) {
62
+ const markdownPath = installPageMarkdownPath(docsConfig).replace(/(^|\/)index\.md$/, "$1").replace(/\.md$/, "");
63
+ return `/${markdownPath}`;
64
+ }
65
+ function codeBlock(language, source) {
66
+ return [`\`\`\`${language}`, source, "```"].join(`
67
+ `);
68
+ }
69
+ function list(items = []) {
70
+ return items.map((item) => ` - \`${item}\``).join(`
71
+ `);
72
+ }
73
+ function frontmatter(title, description) {
74
+ return [
75
+ "---",
76
+ `title: ${JSON.stringify(title)}`,
77
+ `description: ${JSON.stringify(description)}`,
78
+ "---"
79
+ ].join(`
80
+ `);
81
+ }
82
+ function escapeHtmlAttribute(value) {
83
+ return String(value).replace(/&/g, "&").replace(/"/g, """);
84
+ }
85
+ function normalizeBasePath(base) {
86
+ if (typeof base !== "string" || !base.trim() || base === "/")
87
+ return "/";
88
+ return `/${base.replace(/^\/+|\/+$/g, "")}/`;
89
+ }
90
+ function publicSiteUrl(docsConfig = {}) {
91
+ const publication = docsConfig.publication ?? {};
92
+ const domains = publication.domains ?? {};
93
+ const url = docsConfig.url ?? docsConfig.siteUrl ?? publication.url ?? domains.primary ?? publication.hostname ?? docsConfig.hostname;
94
+ if (typeof url !== "string" || !url.trim())
95
+ return;
96
+ const trimmed = url.trim().replace(/\/+$/, "");
97
+ return /^https?:\/\//.test(trimmed) ? trimmed : `https://${trimmed}`;
98
+ }
99
+ function publicMcpSiteUrl(docsConfig = {}) {
100
+ const publicUrl = publicMcpEndpoint(docsConfig);
101
+ if (typeof publicUrl !== "string" || !publicUrl.trim())
102
+ return;
103
+ try {
104
+ return new URL(publicUrl).origin;
105
+ } catch {
106
+ return;
107
+ }
108
+ }
109
+ function installMarkdownUrl(docsConfig = {}) {
110
+ const siteUrl = publicMcpSiteUrl(docsConfig) ?? publicSiteUrl(docsConfig);
111
+ if (!siteUrl)
112
+ return;
113
+ return `${siteUrl}${normalizeBasePath(docsConfig.base)}${installPageMarkdownPath(docsConfig).replace(/^\/+/, "")}`;
114
+ }
115
+ function appGuideUrl(baseUrl, client) {
116
+ if (!baseUrl)
117
+ return;
118
+ const fragment = client === "Claude Code" ? "claude-code" : client.toLowerCase();
119
+ return `${String(baseUrl).replace(/#.*$/, "")}#${fragment}`;
120
+ }
121
+ function repositoryPrompt(config, displayName, remoteUrl) {
122
+ return config.setupPrompt ?? [
123
+ `Set up the ${displayName} MCP server from this repository.`,
124
+ "Read mcp/README.md, run npm install and npm run build in mcp/, then configure this local stdio MCP server for this client.",
125
+ `Use the Git remote ${remoteUrl}.`
126
+ ].join(" ");
127
+ }
128
+ function quickStartPrompt(quickStart = {}, mcp = {}, client = "Codex") {
129
+ const promptKey = client === "Claude Code" ? "claudePrompt" : client === "Cursor" ? "cursorPrompt" : "codexPrompt";
130
+ if (quickStart[promptKey])
131
+ return String(quickStart[promptKey]);
132
+ if (quickStart.prompt)
133
+ return String(quickStart.prompt);
134
+ const setupStep = client === "Claude Code" ? `Run: claude mcp add --transport http ${mcp.serverName} ${mcp.publicUrl}` : client === "Cursor" ? `Add hosted MCP server ${mcp.serverName}: ${mcp.publicUrl}` : `Run: codex mcp add ${mcp.serverName} --url ${mcp.publicUrl}`;
135
+ const guideUrl = appGuideUrl(mcp.installMarkdownUrl, client);
136
+ return [
137
+ `Set up ${mcp.displayName} in ${client}.`,
138
+ guideUrl ? `Guide: ${guideUrl}` : undefined,
139
+ setupStep,
140
+ `Verify tools; search ${mcp.displayName} for "${client} MCP setup". If blocked, give the next command.`
141
+ ].filter(Boolean).join(`
142
+ `);
143
+ }
144
+ function quickStartCard({ href, label, icon, color }) {
145
+ return [
146
+ `<a href="${escapeHtmlAttribute(href)}" style="display:flex;flex:1 1 0;min-width:180px;gap:12px;align-items:center;justify-content:center;min-height:64px;border:1px solid var(--vp-c-brand-1);border-radius:8px;padding:12px 16px;text-decoration:none;color:var(--vp-c-text-1);background:var(--vp-c-bg-soft);cursor:pointer;font-weight:700;transition:border-color .15s ease,background-color .15s ease,transform .15s ease;">`,
147
+ ` <span aria-hidden="true" style="display:grid;place-items:center;flex:0 0 auto;width:34px;height:34px;border-radius:8px;background:var(--vp-c-bg);color:${color};">${icon}</span>`,
148
+ ` <span>${label}</span>`,
149
+ "</a>"
150
+ ].join(`
151
+ `);
152
+ }
153
+ function quickStartSection(quickStart = {}, mcp = {}) {
154
+ if (quickStart.enabled === false)
155
+ return [];
156
+ const codexPrompt = quickStartPrompt(quickStart, mcp, "Codex");
157
+ const claudePrompt = quickStartPrompt(quickStart, mcp, "Claude Code");
158
+ const cursorPrompt = quickStartPrompt(quickStart, mcp, "Cursor");
159
+ const codexUrl = `codex://new?prompt=${encodeURIComponent(codexPrompt)}`;
160
+ const claudeUrl = `claude://claude.ai/new?q=${encodeURIComponent(claudePrompt)}`;
161
+ const cursorUrl = `cursor://anysphere.cursor-deeplink/prompt?text=${encodeURIComponent(cursorPrompt)}`;
162
+ const codexIcon = '<svg width="28" height="28" viewBox="0 0 24 24" role="img" aria-label="OpenAI"><path fill="currentColor" d="M22.282 9.821a6 6 0 0 0-.516-4.91a6.05 6.05 0 0 0-6.51-2.9A6.065 6.065 0 0 0 4.981 4.18a6 6 0 0 0-3.998 2.9a6.05 6.05 0 0 0 .743 7.097a5.98 5.98 0 0 0 .51 4.911a6.05 6.05 0 0 0 6.515 2.9A6 6 0 0 0 13.26 24a6.06 6.06 0 0 0 5.772-4.206a6 6 0 0 0 3.997-2.9a6.06 6.06 0 0 0-.747-7.073M13.26 22.43a4.48 4.48 0 0 1-2.876-1.04l.141-.081l4.779-2.758a.8.8 0 0 0 .392-.681v-6.737l2.02 1.168a.07.07 0 0 1 .038.052v5.583a4.504 4.504 0 0 1-4.494 4.494M3.6 18.304a4.47 4.47 0 0 1-.535-3.014l.142.085l4.783 2.759a.77.77 0 0 0 .78 0l5.843-3.369v2.332a.08.08 0 0 1-.033.062L9.74 19.95a4.5 4.5 0 0 1-6.14-1.646M2.34 7.896a4.5 4.5 0 0 1 2.366-1.973V11.6a.77.77 0 0 0 .388.677l5.815 3.354l-2.02 1.168a.08.08 0 0 1-.071 0l-4.83-2.786A4.504 4.504 0 0 1 2.34 7.872zm16.597 3.855l-5.833-3.387L15.119 7.2a.08.08 0 0 1 .071 0l4.83 2.791a4.494 4.494 0 0 1-.676 8.105v-5.678a.79.79 0 0 0-.407-.667m2.01-3.023l-.141-.085l-4.774-2.782a.78.78 0 0 0-.785 0L9.409 9.23V6.897a.07.07 0 0 1 .028-.061l4.83-2.787a4.5 4.5 0 0 1 6.68 4.66zm-12.64 4.135l-2.02-1.164a.08.08 0 0 1-.038-.057V6.075a4.5 4.5 0 0 1 7.375-3.453l-.142.08L8.704 5.46a.8.8 0 0 0-.393.681zm1.097-2.365l2.602-1.5l2.607 1.5v2.999l-2.597 1.5l-2.607-1.5Z"/></svg>';
163
+ const claudeIcon = '<svg width="28" height="28" viewBox="0 0 24 24" role="img" aria-label="Claude"><path fill="currentColor" d="m4.714 15.956l4.718-2.648l.079-.23l-.08-.128h-.23l-.79-.048l-2.695-.073l-2.337-.097l-2.265-.122l-.57-.121l-.535-.704l.055-.353l.48-.321l.685.06l1.518.104l2.277.157l1.651.098l2.447.255h.389l.054-.158l-.133-.097l-.103-.098l-2.356-1.596l-2.55-1.688l-1.336-.972l-.722-.491L2 6.223l-.158-1.008l.656-.722l.88.06l.224.061l.893.686l1.906 1.476l2.49 1.833l.364.304l.146-.104l.018-.072l-.164-.274l-1.354-2.446l-1.445-2.49l-.644-1.032l-.17-.619a3 3 0 0 1-.103-.729L6.287.133L6.7 0l.995.134l.42.364l.619 1.415L9.735 4.14l1.555 3.03l.455.898l.243.832l.09.255h.159V9.01l.127-1.706l.237-2.095l.23-2.695l.08-.76l.376-.91l.747-.492l.583.28l.48.685l-.067.444l-.286 1.851l-.558 2.903l-.365 1.942h.213l.243-.242l.983-1.306l1.652-2.064l.728-.82l.85-.904l.547-.431h1.032l.759 1.129l-.34 1.166l-1.063 1.347l-.88 1.142l-1.263 1.7l-.79 1.36l.074.11l.188-.02l2.853-.606l1.542-.28l1.84-.315l.832.388l.09.395l-.327.807l-1.967.486l-2.307.462l-3.436.813l-.043.03l.049.061l1.548.146l.662.036h1.62l3.018.225l.79.522l.473.638l-.08.485l-1.213.62l-1.64-.389l-3.825-.91l-1.31-.329h-.183v.11l1.093 1.068l2.003 1.81l2.508 2.33l.127.578l-.321.455l-.34-.049l-2.204-1.657l-.85-.747l-1.925-1.62h-.127v.17l.443.649l2.343 3.521l.122 1.08l-.17.353l-.607.213l-.668-.122l-1.372-1.924l-1.415-2.168l-1.141-1.943l-.14.08l-.674 7.254l-.316.37l-.728.28l-.607-.461l-.322-.747l.322-1.476l.388-1.924l.316-1.53l.285-1.9l.17-.632l-.012-.042l-.14.018l-1.432 1.967l-2.18 2.945l-1.724 1.845l-.413.164l-.716-.37l.066-.662l.401-.589l2.386-3.036l1.439-1.882l.929-1.086l-.006-.158h-.055L4.138 18.56l-1.13.146l-.485-.456l.06-.746l.231-.243l1.907-1.312Z"/></svg>';
164
+ const cards = [
165
+ quickStartCard({
166
+ href: codexUrl,
167
+ label: quickStart.codexLabel ?? "OpenAI Codex",
168
+ icon: codexIcon,
169
+ color: "#111111"
170
+ }),
171
+ quickStartCard({
172
+ href: claudeUrl,
173
+ label: quickStart.claudeLabel ?? "Claude Code",
174
+ icon: claudeIcon,
175
+ color: "#D97757"
176
+ }),
177
+ quickStartCard({
178
+ href: cursorUrl,
179
+ label: quickStart.cursorLabel ?? "Cursor",
180
+ icon: '<svg width="28" height="28" viewBox="0 0 24 24" role="img" aria-label="Cursor"><path fill="currentColor" d="M12 2 3 7.25v9.5L12 22l9-5.25v-9.5zm0 2.32 6.98 4.07-4.17 2.44L12 9.19 9.19 10.83 5.02 8.39zm-7 5.8 4 2.34v4.65l-4-2.34zm6 9.28v-4.66l1 .59 1-.59v4.66l-1 .58zm3-2.29v-4.65l4-2.34v4.65zm-.99-5.25L12 12.45l-1.01-.59L12 11.27z"/></svg>',
181
+ color: "#111111"
182
+ })
183
+ ];
184
+ const layoutStyle = cards.length >= 4 ? "display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:20px 0;" : "display:flex;flex-wrap:wrap;gap:12px;margin:20px 0;";
185
+ return [
186
+ "## AI Quick Start",
187
+ "",
188
+ `<div class="ai-quick-start" style="${layoutStyle}">`,
189
+ ...cards,
190
+ "</div>"
191
+ ];
192
+ }
193
+ function cloudflarePortalSection(portal = {}, mcp = {}) {
194
+ if (portal.enabled === false || !portal.url)
195
+ return [];
196
+ const serverId = portal.serverId ?? mcp.serverName;
197
+ const upstreamUrl = portal.upstreamUrl ?? mcp.publicUrl;
198
+ const portalId = portal.portalId ?? `${serverId}-portal`;
199
+ const hostname = portal.hostname ?? new URL(portal.url).hostname;
200
+ const gatewayCname = portal.gatewayCname ?? "gateway.agents.cloudflare.com";
201
+ return [
202
+ "## Cloudflare Managed Portal",
203
+ "",
204
+ "Cloudflare MCP server portals are managed under **Zero Trust** > **Access controls** > **AI controls**. They require a dedicated hostname that points at Cloudflare's MCP portal gateway, then expose MCP at `/mcp`.",
205
+ "",
206
+ "Target portal:",
207
+ "",
208
+ codeBlock("text", portal.url),
209
+ "",
210
+ "Upstream MCP server:",
211
+ "",
212
+ codeBlock("text", upstreamUrl),
213
+ "",
214
+ "Cloudflare setup:",
215
+ "",
216
+ `1. Add an MCP server with server ID \`${serverId}\`, authentication \`${portal.authentication ?? "Unauthenticated"}\`, and HTTP URL \`${upstreamUrl}\`.`,
217
+ `2. Create an MCP server portal with portal ID \`${portalId}\`, hostname \`${hostname}\`, and include the \`${serverId}\` server.`,
218
+ `3. Create a proxied CNAME for \`${hostname}\` pointing to \`${gatewayCname}\` if the portal was created through the API or Terraform.`,
219
+ `4. Add Access policies for the portal and for the \`${serverId}\` MCP server entry so allowed users can see the server in the portal.`,
220
+ "",
221
+ "Equivalent Cloudflare API endpoints:",
222
+ "",
223
+ codeBlock("text", [
224
+ "POST /accounts/{account_id}/access/ai-controls/mcp/servers",
225
+ "POST /accounts/{account_id}/access/ai-controls/mcp/portals"
226
+ ].join(`
227
+ `)),
228
+ "",
229
+ portal.accessNote ?? "Use a Cloudflare token with Zero Trust Access/AI Controls write access before provisioning the managed portal.",
230
+ "",
231
+ "For Claude or other MCP clients that need browser-based portal auth, Cloudflare recommends `mcp-remote`:",
232
+ "",
233
+ codeBlock("json", JSON.stringify({
234
+ mcpServers: {
235
+ [serverId]: {
236
+ command: "npx",
237
+ args: ["-y", "mcp-remote@latest", portal.url]
238
+ }
239
+ }
240
+ }, null, 2))
241
+ ];
242
+ }
243
+ function codexSection(mcp) {
244
+ return [
245
+ "## Codex",
246
+ "",
247
+ "Add the hosted MCP server:",
248
+ "",
249
+ codeBlock("bash", `codex mcp add ${mcp.serverName} --url ${mcp.publicUrl}`),
250
+ "",
251
+ `Restart Codex Desktop or open a new thread, then run \`/mcp\` to confirm \`${mcp.serverName}\` is connected.`
252
+ ];
253
+ }
254
+ function claudeSection(mcp) {
255
+ return [
256
+ "## Claude Code",
257
+ "",
258
+ "Add the hosted MCP server:",
259
+ "",
260
+ codeBlock("bash", `claude mcp add --transport http ${mcp.serverName} ${mcp.publicUrl}`),
261
+ "",
262
+ "Restart Claude Code or open a new session. The tools should appear as:",
263
+ "",
264
+ codeBlock("text", mcp.tools.map((tool) => `mcp__${mcp.serverName}__${tool}`).join(`
265
+ `))
266
+ ];
267
+ }
268
+ function microsoftSection(mcp) {
269
+ return [
270
+ "## Microsoft Teams and Copilot",
271
+ "",
272
+ "Use the same public MCP endpoint for Microsoft 365 Copilot and Teams agent experiments:",
273
+ "",
274
+ codeBlock("text", mcp.publicUrl),
275
+ "",
276
+ "Fastest Copilot Studio path:",
277
+ "",
278
+ "1. Open the target agent in Copilot Studio.",
279
+ "2. Go to **Tools**.",
280
+ "3. Select **Add a tool** > **New tool** > **Model Context Protocol**.",
281
+ "4. Enter:",
282
+ ` - Server name: \`${mcp.displayName}\``,
283
+ ` - Server description: \`${mcp.description}\``,
284
+ ` - Server URL: \`${mcp.publicUrl}\``,
285
+ " - Authentication: `None`",
286
+ "5. Create the tool, add the MCP tools to the agent, then test with: `Search Example Docs for MCP setup.`",
287
+ "",
288
+ "Teams / Microsoft 365 Copilot agent path:",
289
+ "",
290
+ "1. Use Microsoft 365 Agents Toolkit in VS Code.",
291
+ "2. Create a new declarative agent.",
292
+ "3. Add an action and choose **Start with an MCP server**.",
293
+ `4. Enter \`${mcp.publicUrl}\`.`,
294
+ "5. Select the tools to expose, usually:",
295
+ list(mcp.tools),
296
+ "6. Test locally through Microsoft 365 Copilot, then package and publish the agent to Teams/Microsoft 365 through the tenant approval flow.",
297
+ "",
298
+ `Do not use \`${mcp.protectedUrl}\` for Copilot or Teams unless the Microsoft connector is configured with Cloudflare Access service-token headers. Without that, Microsoft clients receive the Cloudflare Access login redirect instead of MCP JSON-RPC.`
299
+ ];
300
+ }
301
+ function localRepositorySection(repository = {}, mcp = {}) {
302
+ if (repository.enabled === false || !repository.remoteUrl || !repository.localPath)
303
+ return [];
304
+ const prompt = repositoryPrompt(repository, mcp.displayName, repository.remoteUrl);
305
+ const codexUrl = `codex://new?originUrl=${encodeURIComponent(repository.remoteUrl)}&prompt=${encodeURIComponent(prompt)}`;
306
+ const claudeUrl = `claude-cli://open?cwd=${encodeURIComponent(repository.localPath)}&q=${encodeURIComponent(prompt)}`;
307
+ const configuredServerDirectory = repository.localServerDirectory ?? "mcp";
308
+ const serverDirectory = String(configuredServerDirectory).startsWith("/") ? String(configuredServerDirectory) : `${String(repository.localPath).replace(/\/+$/, "")}/${String(configuredServerDirectory).replace(/^\/+/, "")}`;
309
+ const localServerCommand = repository.localServerCommand ?? `node ${serverDirectory}/dist/server.js`;
310
+ return [
311
+ "## Local Repository Setup",
312
+ "",
313
+ "Use these links only when you want to open the Git-backed repository in an agent and configure the local MCP server from `mcp/`.",
314
+ "",
315
+ `- [Open in Codex](${codexUrl}): uses Codex \`originUrl\` matching to find a local workspace with the \`${repository.remoteUrl}\` remote.`,
316
+ `- [Open in Claude Code](${claudeUrl}): uses Claude Code \`cwd\` matching for this local clone. Claude Code's \`repo=\` deeplink is GitHub \`owner/name\` based, so use \`cwd=\` for non-GitHub repositories.`,
317
+ "",
318
+ "If the clone is not present locally:",
319
+ "",
320
+ codeBlock("bash", `git clone ${repository.remoteUrl}.git ${repository.localPath}`),
321
+ "",
322
+ "Configure the local stdio MCP server:",
323
+ "",
324
+ codeBlock("bash", [
325
+ `claude mcp add --transport stdio ${mcp.serverName} -- ${localServerCommand}`,
326
+ `codex mcp add ${mcp.serverName} -- ${localServerCommand}`
327
+ ].join(`
328
+ `))
329
+ ];
330
+ }
331
+ function sourceSection(sources = defaultSources) {
332
+ if (!sources.length)
333
+ return [];
334
+ return [
335
+ `Sources checked: ${sources.map((source) => `[${source.text}](${source.url})`).join(", ")}.`
336
+ ];
337
+ }
338
+ function renderInstallPage(docsConfig = {}) {
339
+ const install = enabledInstallConfig(docsConfig);
340
+ if (!install)
341
+ return;
342
+ const endpoints = mcpEndpoints(docsConfig);
343
+ const coreMcp = docsConfig.mcp ?? {};
344
+ const installMcp = install.mcp ?? {};
345
+ const mcp = {
346
+ serverName: installMcp.serverName ?? coreMcp.serverName ?? docsConfig.name ?? "index",
347
+ displayName: installMcp.displayName ?? install.title ?? docsConfig.title ?? "Index",
348
+ publicUrl: endpoints.public,
349
+ protectedUrl: endpoints.protected,
350
+ description: installMcp.description ?? docsConfig.description ?? "",
351
+ tools: installMcp.tools ?? [],
352
+ installMarkdownUrl: installMarkdownUrl(docsConfig)
353
+ };
354
+ if (!mcp.publicUrl) {
355
+ throw new Error("mcp.endpoints.public or install.mcp.publicUrl is required when install is enabled");
356
+ }
357
+ const title = install.title ?? "Install";
358
+ const description = install.description ?? `Connect ${mcp.displayName} MCP to Codex, Claude, Microsoft Teams, and Copilot.`;
359
+ const lines = [
360
+ frontmatter(title, description),
361
+ "",
362
+ `# ${title}`,
363
+ "",
364
+ ...quickStartSection(install.quickStart, mcp),
365
+ "",
366
+ "Use the public Cloudflare MCP endpoint when you want an agent to use this knowledge base without Git credentials or a local clone.",
367
+ "",
368
+ codeBlock("text", mcp.publicUrl),
369
+ "",
370
+ mcp.protectedUrl ? `The custom domain is protected by Cloudflare Access, so use \`${mcp.publicUrl}\` for no-creds agent setup.` : undefined,
371
+ ...cloudflarePortalSection({
372
+ url: endpoints.portal,
373
+ upstreamUrl: endpoints.public,
374
+ ...install.cloudflarePortal
375
+ }, mcp),
376
+ "",
377
+ ...codexSection(mcp),
378
+ "",
379
+ ...claudeSection(mcp),
380
+ "",
381
+ ...microsoftSection(mcp),
382
+ "",
383
+ ...localRepositorySection(install.repository, mcp),
384
+ "",
385
+ ...sourceSection(install.sources ?? defaultSources),
386
+ ""
387
+ ];
388
+ return `${lines.filter((line) => line !== undefined).join(`
389
+ `).replace(/\n{3,}/g, `
390
+
391
+ `)}
392
+ `;
393
+ }
394
+ function writeInstallPage(docsConfig = {}, docsRoot = process.cwd()) {
395
+ const source = renderInstallPage(docsConfig);
396
+ if (!source)
397
+ return;
398
+ const root = resolve(docsRoot);
399
+ const targetPath = resolve(root, installPageMarkdownPath(docsConfig));
400
+ if (targetPath !== root && !targetPath.startsWith(`${root}${sep}`)) {
401
+ throw new Error(`install.path must resolve inside docsRoot: ${targetPath}`);
402
+ }
403
+ if (existsSync(targetPath) && readFileSync(targetPath, "utf8") === source) {
404
+ return targetPath;
405
+ }
406
+ mkdirSync(dirname(targetPath), { recursive: true });
407
+ writeFileSync(targetPath, source);
408
+ return targetPath;
409
+ }
410
+
411
+ // packages/cli/src/mcp/install-page.ts
412
+ function writeInstallPage2(root, config) {
413
+ return writeInstallPage(config, root);
414
+ }
415
+ export {
416
+ installPageLink,
417
+ installPageMarkdownPath,
418
+ renderInstallPage,
419
+ writeInstallPage2 as writeInstallPage
420
+ };
@@ -7,3 +7,7 @@
7
7
  * sources, while staying type-checked against that source of truth.
8
8
  */
9
9
  export declare function share(input: string[]): Promise<void>;
10
+ export declare function startLanShare(target: {
11
+ root: string;
12
+ target?: string;
13
+ }): Promise<import("kennel-preview/terminal").PreviewShare>;