@hiai-gg/docsmint 0.6.8 → 0.7.1

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 (138) hide show
  1. package/README.md +90 -99
  2. package/backend/src/lib/api-keys.ts +14 -6
  3. package/backend/src/lib/lifecycle-service.ts +397 -73
  4. package/dist/backend/index.js +13039 -10865
  5. package/dist/backend-account-runtime-cleanup.js +152 -42
  6. package/dist/backend-api-key-facade.js +207 -61
  7. package/dist/backend-pipeline-cancellation.js +144 -42
  8. package/dist/client.d.ts +12 -2
  9. package/dist/client.js +83 -30
  10. package/dist/frontend/{CategoryDialog-CbXBMBZB.js → CategoryDialog-t_WIvFAG.js} +5 -5
  11. package/dist/frontend/{ConfirmDialog-DgMTQBq4.js → ConfirmDialog-_LlrA--f.js} +3 -3
  12. package/dist/frontend/{CreateSnapshotDialog-FUq-ZfBH.js → CreateSnapshotDialog-DW3PwAt5.js} +4 -4
  13. package/dist/frontend/{DatePicker-D6E-EEtZ.js → DatePicker-CAw0wZZK.js} +9 -9
  14. package/dist/frontend/{DeleteDialog-8k6JYWCx.js → DeleteDialog-L1A3FhMM.js} +1 -1
  15. package/dist/frontend/{FolderNode-DAAn_T8_.js → FolderNode-DzTqitR8.js} +2 -2
  16. package/dist/frontend/{HiAiEditor-DSVG3GNd.js → HiAiEditor-B7MK19_j.js} +7 -7
  17. package/dist/frontend/{SettingsDialog-BDNgf5rv.js → SettingsDialog-CS5L4nnU.js} +13 -13
  18. package/dist/frontend/ShareDialog-CwFa8mlk.js +281 -0
  19. package/dist/frontend/{Sidebar-DX08utdV.js → Sidebar-CDaFFmaQ.js} +18 -17
  20. package/dist/frontend/{TagCreateDialog-Bb0-Vtzh.js → TagCreateDialog-C7Avn2_h.js} +4 -4
  21. package/dist/frontend/api/attachments.js +1 -1
  22. package/dist/frontend/api/settings.js +1 -1
  23. package/dist/frontend/app-shell.js +3 -3
  24. package/dist/frontend/{attachments-B8AuDjno.js → attachments-B2aH3hXF.js} +10 -9
  25. package/dist/frontend/{auth-client-Cygmp1I2.js → auth-client-CnDZwPfp.js} +11 -11
  26. package/dist/frontend/components/category-dialog.js +1 -1
  27. package/dist/frontend/components/create-snapshot-dialog.js +1 -1
  28. package/dist/frontend/components/delete-dialog.js +1 -1
  29. package/dist/frontend/components/editor/compact-editor.js +1 -1
  30. package/dist/frontend/components/editor/document-editor.js +1 -1
  31. package/dist/frontend/components/editor/document-title.js +1 -1
  32. package/dist/frontend/components/editor/markdown-toggle.js +1 -1
  33. package/dist/frontend/components/folder-node.js +1 -1
  34. package/dist/frontend/components/save-as-dialog.js +4 -4
  35. package/dist/frontend/components/settings.js +1 -1
  36. package/dist/frontend/components/share-dialog.d.ts +2 -1
  37. package/dist/frontend/components/share-dialog.js +1 -1
  38. package/dist/frontend/components/sidebar.js +1 -1
  39. package/dist/frontend/components/tag-create-dialog.js +1 -1
  40. package/dist/frontend/components/version-history.js +3 -3
  41. package/dist/frontend/{confirm-dialog-CzmoZw3a.js → confirm-dialog-BW2h2NE8.js} +5 -5
  42. package/dist/frontend/dashboard.js +1008 -998
  43. package/dist/frontend/{db-ByrlYfaI.js → db-Bo1t_76T.js} +1 -1
  44. package/dist/frontend/{dialog-Ce79C9fd.js → dialog-C2iKObEu.js} +7 -7
  45. package/dist/frontend/{dropdown-menu-CJ_7V3N0.js → dropdown-menu-BXIl2E26.js} +12 -12
  46. package/dist/frontend/{floating-layer-anchor-S5RSefGN.js → floating-layer-anchor-BGIndLY-.js} +63 -63
  47. package/dist/frontend/i18n.js +1 -1
  48. package/dist/frontend/{identity-DyWeNzu_.js → identity-Ynrglr5i.js} +1 -1
  49. package/dist/frontend/{input-BWlOML_m.js → input-eHFb2qiL.js} +2 -2
  50. package/dist/frontend/{label-C2HfJNQ2.js → label-_I1iiaNU.js} +2 -2
  51. package/dist/frontend/messages-DTRe4U2V.js +1093 -0
  52. package/dist/frontend/offline/identity.js +1 -1
  53. package/dist/frontend/search.js +3 -3
  54. package/dist/frontend/{select-value-JCAp2PmU.js → select-value-CtMyrvDJ.js} +18 -18
  55. package/dist/frontend/{settings-DSrUl4hW.js → settings-BR48ihB4.js} +6 -23
  56. package/dist/frontend/{textarea-DOAE-h42.js → textarea-2eslfANY.js} +2 -2
  57. package/dist/frontend/{utils-BPDRytUU.js → utils-CDBqTgoV.js} +1 -1
  58. package/dist/frontend-ssr/api/attachments.js +1 -1
  59. package/dist/frontend-ssr/api/settings.js +1 -1
  60. package/dist/frontend-ssr/app-shell.js +3 -3
  61. package/dist/frontend-ssr/assets/{CategoryDialog-QHEv_9N4.js → CategoryDialog-B3MrZUho.js} +5 -5
  62. package/dist/frontend-ssr/assets/{ConfirmDialog-BhAelejz.js → ConfirmDialog-D1BDXXll.js} +3 -3
  63. package/dist/frontend-ssr/assets/{CreateSnapshotDialog-CI8vXXcN.js → CreateSnapshotDialog-NM0n1Whr.js} +4 -4
  64. package/dist/frontend-ssr/assets/{DatePicker-D84cJ-Eq.js → DatePicker-Dcok9XVm.js} +4 -4
  65. package/dist/frontend-ssr/assets/{DeleteDialog-DG9Lm38J.js → DeleteDialog-oHT_p_vG.js} +1 -1
  66. package/dist/frontend-ssr/assets/{FolderNode-kmilhDjO.js → FolderNode-B84NL8Rg.js} +2 -2
  67. package/dist/frontend-ssr/assets/{HiAiEditor-CUOJmKzT.js → HiAiEditor-tU0jmp6L.js} +6 -6
  68. package/dist/frontend-ssr/assets/{SettingsDialog-BjJIiVLc.js → SettingsDialog-Dkp79L1B.js} +13 -13
  69. package/dist/frontend-ssr/assets/{ShareDialog-C9C-XTm4.js → ShareDialog-B1-30sRR.js} +20 -7
  70. package/dist/frontend-ssr/assets/{Sidebar-C2sUfGNk.js → Sidebar-CGp45ngo.js} +14 -13
  71. package/dist/frontend-ssr/assets/{TagCreateDialog-DUPMitlL.js → TagCreateDialog-CGGtYSso.js} +4 -4
  72. package/dist/frontend-ssr/assets/{attachments-Cj3fQyUp.js → attachments-BdkOp8ha.js} +5 -4
  73. package/dist/frontend-ssr/assets/{auth-client-x26kqY8Z.js → auth-client-CojKIzqy.js} +13 -13
  74. package/dist/frontend-ssr/assets/{confirm-dialog-XuyaL8sr.js → confirm-dialog-B-oV5wYk.js} +5 -5
  75. package/dist/frontend-ssr/assets/{db-CnxeO66n.js → db-BhwJPEkn.js} +1 -1
  76. package/dist/frontend-ssr/assets/{dialog-BOV1u6zP.js → dialog-1SB5neow.js} +8 -8
  77. package/dist/frontend-ssr/assets/{dropdown-menu-Dn_vQq9b.js → dropdown-menu-DqoOkdqB.js} +12 -12
  78. package/dist/frontend-ssr/assets/{floating-layer-anchor-BIAu-252.js → floating-layer-anchor-BoiiIEiK.js} +71 -71
  79. package/dist/frontend-ssr/assets/{identity-B3uHoDtf.js → identity-DcMMBKWg.js} +1 -1
  80. package/dist/frontend-ssr/assets/{input-DezGsU3y.js → input-Df-QP3Km.js} +2 -2
  81. package/dist/frontend-ssr/assets/{label-Bj8-TfFN.js → label-CbUOUz6L.js} +2 -2
  82. package/dist/frontend-ssr/assets/{messages-BAQzILs4.js → messages-B1TjVIH8.js} +2 -2
  83. package/dist/frontend-ssr/assets/{select-value-DBhbkNcc.js → select-value-CXEDWrZg.js} +18 -18
  84. package/dist/frontend-ssr/assets/{settings-Bk5Hk9Vq.js → settings-Mp8EuFSn.js} +3 -21
  85. package/dist/frontend-ssr/assets/{textarea-Dev-qSEc.js → textarea-CHh8NuSS.js} +2 -2
  86. package/dist/frontend-ssr/assets/{utils-DtlPPXpJ.js → utils-DtX0ta7y.js} +1 -1
  87. package/dist/frontend-ssr/components/category-dialog.js +1 -1
  88. package/dist/frontend-ssr/components/create-snapshot-dialog.js +1 -1
  89. package/dist/frontend-ssr/components/delete-dialog.js +1 -1
  90. package/dist/frontend-ssr/components/editor/compact-editor.js +1 -1
  91. package/dist/frontend-ssr/components/editor/document-editor.js +1 -1
  92. package/dist/frontend-ssr/components/editor/document-title.js +1 -1
  93. package/dist/frontend-ssr/components/editor/markdown-toggle.js +1 -1
  94. package/dist/frontend-ssr/components/folder-node.js +1 -1
  95. package/dist/frontend-ssr/components/save-as-dialog.js +4 -4
  96. package/dist/frontend-ssr/components/settings.js +1 -1
  97. package/dist/frontend-ssr/components/share-dialog.js +1 -1
  98. package/dist/frontend-ssr/components/sidebar.js +1 -1
  99. package/dist/frontend-ssr/components/tag-create-dialog.js +1 -1
  100. package/dist/frontend-ssr/components/version-history.js +3 -3
  101. package/dist/frontend-ssr/dashboard.js +32 -30
  102. package/dist/frontend-ssr/i18n.js +1 -1
  103. package/dist/frontend-ssr/offline/identity.js +1 -1
  104. package/dist/frontend-ssr/search.js +3 -3
  105. package/dist/index.d.ts +5 -5
  106. package/dist/index.js +2 -2
  107. package/dist/lifecycle-persistent.d.ts +1 -1
  108. package/dist/lifecycle-runtime.js +52659 -338
  109. package/dist/mcp-cli.js +1056 -0
  110. package/dist/mcp-server.d.ts +39 -0
  111. package/dist/mcp-server.js +1053 -0
  112. package/dist/storage-quota.d.ts +5 -1
  113. package/dist/types.d.ts +7 -0
  114. package/dist/workspace.d.ts +11 -2
  115. package/dist/workspace.js +82 -10
  116. package/package.json +7 -13
  117. package/packages/cli/src/index.ts +4 -3
  118. package/packages/db/src/client.ts +56 -5
  119. package/packages/db/src/schema.ts +192 -1
  120. package/packages/db/src/with-tenant.ts +20 -2
  121. package/server.json +42 -5
  122. package/dist/frontend/ShareDialog-2Mty7hm4.js +0 -258
  123. package/dist/frontend/messages-DIovIZrK.js +0 -1093
  124. package/packages/mcp-server/src/capabilities.ts +0 -189
  125. package/packages/mcp-server/src/client.ts +0 -225
  126. package/packages/mcp-server/src/index.ts +0 -8
  127. package/packages/mcp-server/src/server.ts +0 -87
  128. package/packages/mcp-server/src/tools/create-document.ts +0 -34
  129. package/packages/mcp-server/src/tools/create-folder.ts +0 -31
  130. package/packages/mcp-server/src/tools/create-snapshot.ts +0 -27
  131. package/packages/mcp-server/src/tools/export-document.ts +0 -22
  132. package/packages/mcp-server/src/tools/get-document.ts +0 -22
  133. package/packages/mcp-server/src/tools/list-documents.ts +0 -34
  134. package/packages/mcp-server/src/tools/list-folders.ts +0 -26
  135. package/packages/mcp-server/src/tools/search.ts +0 -39
  136. package/packages/mcp-server/src/tools/update-document.ts +0 -38
  137. package/packages/mcp-server/src/tools/version-history.ts +0 -27
  138. package/packages/mcp-server/src/types.ts +0 -126
@@ -1,189 +0,0 @@
1
- import type { McpServer } from '@modelcontextprotocol/server';
2
- import { z } from 'zod';
3
-
4
- import type { HiaiDocsClient } from './client.js';
5
-
6
- export const capabilityCatalog = {
7
- tools: [
8
- 'search_documents',
9
- 'get_document',
10
- 'create_document',
11
- 'update_document',
12
- 'list_documents',
13
- 'list_folders',
14
- 'create_folder',
15
- 'create_snapshot',
16
- 'get_version_history',
17
- 'export_document',
18
- 'list_categories',
19
- 'create_category',
20
- 'list_tags',
21
- 'get_related_documents',
22
- 'search_knowledge_graph',
23
- 'get_document_index_status',
24
- 'refresh_document_index',
25
- ] as const,
26
- prompts: ['organize_workspace', 'research_workspace'] as const,
27
- resources: [
28
- 'docsmint://guide/editor',
29
- 'docsmint://guide/search',
30
- 'docsmint://workspace/catalog',
31
- ] as const,
32
- };
33
-
34
- type TextResult = { content: Array<{ type: 'text'; text: string }> };
35
-
36
- function jsonResult(value: unknown): TextResult {
37
- return { content: [{ type: 'text', text: JSON.stringify(value, null, 2) }] };
38
- }
39
-
40
- export function registerExtendedCapabilities(server: McpServer, client: HiaiDocsClient): void {
41
- server.registerTool(
42
- 'list_categories',
43
- {
44
- description:
45
- 'List categories visible to the API key. Category keys receive only their bound category.',
46
- inputSchema: z.object({}),
47
- },
48
- async () => jsonResult(await client.listCategories())
49
- );
50
- server.registerTool(
51
- 'create_category',
52
- {
53
- description:
54
- 'Create a category. Requires a workspace key with write access; category keys cannot mutate categories.',
55
- inputSchema: z.object({
56
- name: z.string().min(1),
57
- description: z.string().optional(),
58
- }),
59
- },
60
- async (input) => jsonResult(await client.createCategory(input))
61
- );
62
- server.registerTool(
63
- 'list_tags',
64
- {
65
- description: 'List tags visible in the workspace or bound category.',
66
- inputSchema: z.object({}),
67
- },
68
- async () => jsonResult(await client.listTags())
69
- );
70
- server.registerTool(
71
- 'get_related_documents',
72
- {
73
- description: 'Traverse the knowledge graph from one authorized document.',
74
- inputSchema: z.object({
75
- documentId: z.string().min(1),
76
- limit: z.number().int().min(1).max(50).optional(),
77
- }),
78
- },
79
- async ({ documentId, limit }) => jsonResult(await client.getRelatedDocuments(documentId, limit))
80
- );
81
- server.registerTool(
82
- 'search_knowledge_graph',
83
- {
84
- description:
85
- 'Search connected knowledge using authorized seed documents. Category keys may use only documents in their category.',
86
- inputSchema: z.object({
87
- query: z.string().min(1).max(1000),
88
- docIds: z.array(z.string().min(1)).min(1),
89
- limit: z.number().int().min(1).max(50).optional(),
90
- }),
91
- },
92
- async (input) => jsonResult(await client.searchGraph(input))
93
- );
94
- server.registerTool(
95
- 'get_document_index_status',
96
- {
97
- description: 'Read the current indexing and knowledge-pipeline status of a document.',
98
- inputSchema: z.object({ documentId: z.string().min(1) }),
99
- },
100
- async ({ documentId }) => jsonResult(await client.getDocumentIndexStatus(documentId))
101
- );
102
- server.registerTool(
103
- 'refresh_document_index',
104
- {
105
- description: 'Request reindexing after a document or metadata change. Requires write access.',
106
- inputSchema: z.object({ documentId: z.string().min(1) }),
107
- },
108
- async ({ documentId }) => jsonResult(await client.refreshDocumentIndex(documentId))
109
- );
110
-
111
- server.registerPrompt(
112
- 'organize_workspace',
113
- {
114
- description: 'Plan safe document organization using DocsMint categories and folders.',
115
- argsSchema: z.object({
116
- objective: z.string(),
117
- language: z.string().optional(),
118
- }),
119
- },
120
- ({ objective, language }) => ({
121
- messages: [
122
- {
123
- role: 'user',
124
- content: {
125
- type: 'text',
126
- text: `Organize this DocsMint workspace for: ${objective}. Work in ${language ?? 'the document language'}. Inspect categories, folders, tags, and documents before proposing or applying changes. Preserve document content and obey the API key scope.`,
127
- },
128
- },
129
- ],
130
- })
131
- );
132
- server.registerPrompt(
133
- 'research_workspace',
134
- {
135
- description:
136
- 'Research a question with hybrid search and GraphRAG while citing DocsMint document IDs.',
137
- argsSchema: z.object({
138
- question: z.string(),
139
- language: z.string().optional(),
140
- }),
141
- },
142
- ({ question, language }) => ({
143
- messages: [
144
- {
145
- role: 'user',
146
- content: {
147
- type: 'text',
148
- text: `Answer this question from DocsMint: ${question}. Respond in ${language ?? 'the question language'}. Start with hybrid search, use graph traversal only from authorized result documents, and cite document IDs. Distinguish retrieved facts from inference.`,
149
- },
150
- },
151
- ],
152
- })
153
- );
154
-
155
- server.registerResource('editor-guide', 'docsmint://guide/editor', {}, async (uri) => ({
156
- contents: [
157
- {
158
- uri: uri.href,
159
- mimeType: 'text/markdown',
160
- text: '# DocsMint editing rules\n\nRead a document before updating it. Preserve its language, title intent, TipTap/Markdown structure, category, folder, and tags unless the user explicitly requests a change. After content changes, verify index status and request refresh only when needed.',
161
- },
162
- ],
163
- }));
164
- server.registerResource('search-guide', 'docsmint://guide/search', {}, async (uri) => ({
165
- contents: [
166
- {
167
- uri: uri.href,
168
- mimeType: 'text/markdown',
169
- text: '# DocsMint retrieval rules\n\nUse search_documents for normal retrieval. Use get_related_documents or search_knowledge_graph only with document IDs already authorized by the active API key. Keep multilingual queries in their original language and cite document IDs in answers.',
170
- },
171
- ],
172
- }));
173
- server.registerResource('workspace-catalog', 'docsmint://workspace/catalog', {}, async (uri) => {
174
- const [categories, folders, tags] = await Promise.all([
175
- client.listCategories(),
176
- client.listFolders({}),
177
- client.listTags(),
178
- ]);
179
- return {
180
- contents: [
181
- {
182
- uri: uri.href,
183
- mimeType: 'application/json',
184
- text: JSON.stringify({ categories, folders, tags }, null, 2),
185
- },
186
- ],
187
- };
188
- });
189
- }
@@ -1,225 +0,0 @@
1
- /**
2
- * REST client for hiai-docs.
3
- *
4
- * Reads configuration from environment:
5
- * HIAI_DOCS_URL — base URL (default: http://localhost:50700)
6
- * HIAI_DOCS_API_KEY — bearer token for the API
7
- *
8
- * Bun-native. Uses global `fetch`. Throws on non-2xx responses with the
9
- * error message extracted from the response body when possible.
10
- */
11
-
12
- import type { ExportResponse } from "./types.js";
13
-
14
- const DEFAULT_BASE_URL = "http://localhost:50700";
15
-
16
- function readConfig() {
17
- const baseUrl = (process.env.HIAI_DOCS_URL ?? DEFAULT_BASE_URL).replace(
18
- /\/+$/,
19
- "",
20
- );
21
- const apiKey = process.env.HIAI_DOCS_API_KEY ?? "";
22
- return { baseUrl, apiKey };
23
- }
24
-
25
- export class HiaiDocsError extends Error {
26
- constructor(
27
- message: string,
28
- readonly status: number,
29
- readonly body: unknown,
30
- ) {
31
- super(message);
32
- this.name = "HiaiDocsError";
33
- }
34
- }
35
-
36
- type QueryValue = string | number | boolean | string[] | undefined;
37
-
38
- async function request<T>(
39
- method: string,
40
- path: string,
41
- options: { query?: Record<string, QueryValue>; body?: unknown } = {},
42
- ): Promise<T> {
43
- const { baseUrl, apiKey } = readConfig();
44
-
45
- const url = new URL(path.startsWith("/") ? path : `/${path}`, `${baseUrl}/`);
46
- if (options.query) {
47
- for (const [key, value] of Object.entries(options.query)) {
48
- if (value === undefined) continue;
49
- if (Array.isArray(value)) {
50
- if (value.length > 0) url.searchParams.set(key, value.join(","));
51
- } else {
52
- url.searchParams.set(key, String(value));
53
- }
54
- }
55
- }
56
-
57
- const headers: Record<string, string> = {
58
- Accept: "application/json",
59
- };
60
- if (apiKey) {
61
- headers.Authorization = `Bearer ${apiKey}`;
62
- }
63
-
64
- let body: BodyInit | undefined;
65
- if (options.body !== undefined) {
66
- headers["Content-Type"] = "application/json";
67
- body = JSON.stringify(options.body);
68
- }
69
-
70
- const response = await fetch(url, { method, headers, body });
71
-
72
- const contentType = response.headers.get("content-type") ?? "";
73
- const isJson = contentType.includes("application/json");
74
- const payload: unknown = isJson
75
- ? await response.json().catch(() => null)
76
- : await response.text().catch(() => null);
77
-
78
- if (!response.ok) {
79
- const message =
80
- (isJson && payload && typeof payload === "object" && "error" in payload
81
- ? String((payload as { error: unknown }).error)
82
- : typeof payload === "string" && payload.length > 0
83
- ? payload
84
- : `HTTP ${response.status} ${response.statusText}`) ||
85
- `HTTP ${response.status}`;
86
- throw new HiaiDocsError(message, response.status, payload);
87
- }
88
-
89
- return payload as T;
90
- }
91
-
92
- function joinId(...segments: string[]): string {
93
- return segments.map((s) => encodeURIComponent(s)).join("/");
94
- }
95
-
96
- export const client = {
97
- search(params: {
98
- query: string;
99
- folder?: string;
100
- tags?: string[];
101
- limit?: number;
102
- }) {
103
- return request("GET", "/api/search", {
104
- query: {
105
- q: params.query,
106
- folder: params.folder,
107
- tags: params.tags,
108
- limit: params.limit,
109
- },
110
- });
111
- },
112
-
113
- getDocument(id: string) {
114
- return request("GET", `/api/${joinId("documents", id)}`);
115
- },
116
-
117
- createDocument(input: {
118
- title: string;
119
- content?: string;
120
- folderId?: string | null;
121
- categoryId?: string | null;
122
- }) {
123
- return request("POST", "/api/documents", { body: input });
124
- },
125
-
126
- updateDocument(
127
- id: string,
128
- input: {
129
- title?: string;
130
- content?: string;
131
- folderId?: string | null;
132
- categoryId?: string | null;
133
- },
134
- ) {
135
- return request("PATCH", `/api/${joinId("documents", id)}`, { body: input });
136
- },
137
-
138
- listDocuments(params: {
139
- folderId?: string;
140
- tag?: string;
141
- page?: number;
142
- limit?: number;
143
- }) {
144
- return request("GET", "/api/documents", { query: params });
145
- },
146
-
147
- listFolders(params: { parentId?: string }) {
148
- return request("GET", "/api/folders", {
149
- query: { parentId: params.parentId },
150
- });
151
- },
152
-
153
- createFolder(input: {
154
- name: string;
155
- parentId?: string;
156
- categoryId?: string;
157
- }) {
158
- return request("POST", "/api/folders", { body: input });
159
- },
160
-
161
- listCategories() {
162
- return request("GET", "/api/categories");
163
- },
164
-
165
- createCategory(input: { name: string; description?: string }) {
166
- return request("POST", "/api/categories", { body: input });
167
- },
168
-
169
- listTags() {
170
- return request("GET", "/api/tags");
171
- },
172
-
173
- getRelatedDocuments(documentId: string, limit?: number) {
174
- return request("GET", `/api/${joinId("graph", "related", documentId)}`, {
175
- query: { limit },
176
- });
177
- },
178
-
179
- searchGraph(input: { query: string; docIds: string[]; limit?: number }) {
180
- return request("POST", "/api/graph/search", { body: input });
181
- },
182
-
183
- getDocumentIndexStatus(documentId: string) {
184
- return request(
185
- "GET",
186
- `/api/${joinId("documents", documentId, "index-status")}`,
187
- );
188
- },
189
-
190
- refreshDocumentIndex(documentId: string) {
191
- return request(
192
- "POST",
193
- `/api/${joinId("documents", documentId, "index", "refresh")}`,
194
- );
195
- },
196
-
197
- createSnapshot(
198
- documentId: string,
199
- input: { label: string; description?: string },
200
- ) {
201
- return request(
202
- "POST",
203
- `/api/${joinId("documents", documentId, "versions")}`,
204
- { body: input },
205
- );
206
- },
207
-
208
- getVersionHistory(documentId: string, onlySnapshots?: boolean) {
209
- return request(
210
- "GET",
211
- `/api/${joinId("documents", documentId, "versions")}`,
212
- { query: { onlySnapshots } },
213
- );
214
- },
215
-
216
- async exportDocument(id: string): Promise<ExportResponse> {
217
- const markdown = await request<string>(
218
- "GET",
219
- `/api/${joinId("documents", id, "export")}`,
220
- );
221
- return { markdown };
222
- },
223
- };
224
-
225
- export type HiaiDocsClient = typeof client;
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bun
2
- /** DocsMint MCP stdio entry point. */
3
-
4
- import { serveStdio } from '@modelcontextprotocol/server/stdio';
5
-
6
- import { createDocsmintMcpServer } from './server.js';
7
-
8
- serveStdio(() => createDocsmintMcpServer());
@@ -1,87 +0,0 @@
1
- import { McpServer } from '@modelcontextprotocol/server';
2
- import { z, type ZodRawShape } from 'zod';
3
-
4
- import { registerExtendedCapabilities } from './capabilities.js';
5
- import { client as defaultClient, HiaiDocsError, type HiaiDocsClient } from './client.js';
6
- import * as createDocument from './tools/create-document.js';
7
- import * as createFolder from './tools/create-folder.js';
8
- import * as createSnapshot from './tools/create-snapshot.js';
9
- import * as exportDocument from './tools/export-document.js';
10
- import * as getDocument from './tools/get-document.js';
11
- import * as listDocuments from './tools/list-documents.js';
12
- import * as listFolders from './tools/list-folders.js';
13
- import * as search from './tools/search.js';
14
- import * as updateDocument from './tools/update-document.js';
15
- import * as versionHistory from './tools/version-history.js';
16
-
17
- type ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;
18
- interface McpToolResult {
19
- content: Array<{ type: 'text'; text: string }>;
20
- isError?: boolean;
21
- }
22
-
23
- function wrapHandler(
24
- name: string,
25
- handler: ToolHandler
26
- ): (args: Record<string, unknown>) => Promise<McpToolResult> {
27
- return async (args) => {
28
- try {
29
- return {
30
- content: [{ type: 'text', text: JSON.stringify(await handler(args), null, 2) }],
31
- };
32
- } catch (error) {
33
- const message =
34
- error instanceof HiaiDocsError
35
- ? `DocsMint API error (${error.status}): ${error.message}`
36
- : `Tool '${name}' failed: ${error instanceof Error ? error.message : String(error)}`;
37
- return { isError: true, content: [{ type: 'text', text: message }] };
38
- }
39
- };
40
- }
41
-
42
- export function registerDocsmintMcpCapabilities(server: McpServer, client: HiaiDocsClient): void {
43
- const register = <Args>(
44
- name: string,
45
- description: string,
46
- inputSchema: ZodRawShape,
47
- handler: (args: Args) => Promise<unknown>
48
- ): void => {
49
- server.registerTool(
50
- name,
51
- { description, inputSchema: z.object(inputSchema) },
52
- wrapHandler(name, handler as ToolHandler) as never
53
- );
54
- };
55
-
56
- const tools = [
57
- search,
58
- getDocument,
59
- createDocument,
60
- updateDocument,
61
- listDocuments,
62
- listFolders,
63
- createFolder,
64
- createSnapshot,
65
- versionHistory,
66
- exportDocument,
67
- ] as const;
68
- for (const tool of tools) {
69
- register(
70
- tool.definition.name,
71
- tool.definition.description,
72
- tool.definition.inputSchema as ZodRawShape,
73
- tool.createHandler(client) as ToolHandler
74
- );
75
- }
76
- registerExtendedCapabilities(server, client);
77
- }
78
-
79
- export interface CreateDocsmintMcpServerOptions {
80
- client?: HiaiDocsClient;
81
- }
82
-
83
- export function createDocsmintMcpServer(options: CreateDocsmintMcpServerOptions = {}): McpServer {
84
- const server = new McpServer({ name: 'docsmint', version: '0.6.8' });
85
- registerDocsmintMcpCapabilities(server, options.client ?? defaultClient);
86
- return server;
87
- }
@@ -1,34 +0,0 @@
1
- import { z } from 'zod';
2
- import { client, type HiaiDocsClient } from '../client.js';
3
- import type { DocumentDetail } from '../types.js';
4
-
5
- export const definition = {
6
- name: 'create_document',
7
- description:
8
- 'Create a new document. Optionally provide initial markdown content and a folder ID.',
9
- inputSchema: {
10
- title: z.string().describe('Document title.'),
11
- content: z.string().optional().describe('Initial markdown content for the document.'),
12
- folderId: z.string().optional().describe('Optional folder ID to place the document in.'),
13
- categoryId: z
14
- .string()
15
- .optional()
16
- .describe(
17
- 'Optional category ID. Category keys are always rebound to their configured category.'
18
- ),
19
- },
20
- } as const;
21
-
22
- export interface CreateDocumentArgs {
23
- title: string;
24
- content?: string;
25
- folderId?: string;
26
- categoryId?: string;
27
- }
28
-
29
- export const createHandler = (api: HiaiDocsClient) =>
30
- async function createDocument(args: CreateDocumentArgs): Promise<DocumentDetail> {
31
- return (await api.createDocument(args)) as DocumentDetail;
32
- };
33
-
34
- export const handler = createHandler(client);
@@ -1,31 +0,0 @@
1
- import { z } from 'zod';
2
- import { client, type HiaiDocsClient } from '../client.js';
3
- import type { Folder } from '../types.js';
4
-
5
- export const definition = {
6
- name: 'create_folder',
7
- description: 'Create a new folder, optionally nested under a parent folder.',
8
- inputSchema: {
9
- name: z.string().describe('Folder name.'),
10
- parentId: z.string().optional().describe('Optional parent folder ID for nesting.'),
11
- categoryId: z
12
- .string()
13
- .optional()
14
- .describe(
15
- 'Optional category ID. Category keys are always rebound to their configured category.'
16
- ),
17
- },
18
- } as const;
19
-
20
- export interface CreateFolderArgs {
21
- name: string;
22
- parentId?: string;
23
- categoryId?: string;
24
- }
25
-
26
- export const createHandler = (api: HiaiDocsClient) =>
27
- async function createFolder(args: CreateFolderArgs): Promise<Folder> {
28
- return (await api.createFolder(args)) as Folder;
29
- };
30
-
31
- export const handler = createHandler(client);
@@ -1,27 +0,0 @@
1
- import { z } from 'zod';
2
- import { client, type HiaiDocsClient } from '../client.js';
3
- import type { Version } from '../types.js';
4
-
5
- export const definition = {
6
- name: 'create_snapshot',
7
- description: 'Create a named snapshot (labelled version) of a document from its current content.',
8
- inputSchema: {
9
- documentId: z.string().describe('Document ID to snapshot.'),
10
- label: z.string().describe("Short label for the snapshot (e.g. 'v1.0-release')."),
11
- description: z.string().optional().describe('Optional longer description of the snapshot.'),
12
- },
13
- } as const;
14
-
15
- export interface CreateSnapshotArgs {
16
- documentId: string;
17
- label: string;
18
- description?: string;
19
- }
20
-
21
- export const createHandler = (api: HiaiDocsClient) =>
22
- async function createSnapshot(args: CreateSnapshotArgs): Promise<Version> {
23
- const { documentId, ...input } = args;
24
- return (await api.createSnapshot(documentId, input)) as Version;
25
- };
26
-
27
- export const handler = createHandler(client);
@@ -1,22 +0,0 @@
1
- import { z } from 'zod';
2
- import { client, type HiaiDocsClient } from '../client.js';
3
- import type { ExportResponse } from '../types.js';
4
-
5
- export const definition = {
6
- name: 'export_document',
7
- description: 'Export a document as markdown. Returns the rendered markdown content.',
8
- inputSchema: {
9
- id: z.string().describe('Document ID to export.'),
10
- },
11
- } as const;
12
-
13
- export interface ExportDocumentArgs {
14
- id: string;
15
- }
16
-
17
- export const createHandler = (api: HiaiDocsClient) =>
18
- async function exportDocument(args: ExportDocumentArgs): Promise<ExportResponse> {
19
- return (await api.exportDocument(args.id)) as ExportResponse;
20
- };
21
-
22
- export const handler = createHandler(client);
@@ -1,22 +0,0 @@
1
- import { z } from 'zod';
2
- import { client, type HiaiDocsClient } from '../client.js';
3
- import type { DocumentDetail } from '../types.js';
4
-
5
- export const definition = {
6
- name: 'get_document',
7
- description: 'Fetch a single document by ID. Returns full content, metadata, and tags.',
8
- inputSchema: {
9
- id: z.string().describe('Document ID.'),
10
- },
11
- } as const;
12
-
13
- export interface GetDocumentArgs {
14
- id: string;
15
- }
16
-
17
- export const createHandler = (api: HiaiDocsClient) =>
18
- async function getDocument(args: GetDocumentArgs): Promise<DocumentDetail> {
19
- return (await api.getDocument(args.id)) as DocumentDetail;
20
- };
21
-
22
- export const handler = createHandler(client);
@@ -1,34 +0,0 @@
1
- import { z } from 'zod';
2
- import { client, type HiaiDocsClient } from '../client.js';
3
- import type { ListDocumentsResponse } from '../types.js';
4
-
5
- export const definition = {
6
- name: 'list_documents',
7
- description: 'List documents with pagination, optionally filtered by folder or tag.',
8
- inputSchema: {
9
- folderId: z.string().optional().describe('Optional folder ID to filter by.'),
10
- tag: z.string().optional().describe('Optional tag ID to filter by.'),
11
- page: z.number().int().positive().optional().describe('Page number (1-indexed, default 1).'),
12
- limit: z
13
- .number()
14
- .int()
15
- .positive()
16
- .max(100)
17
- .optional()
18
- .describe('Items per page (default 20, max 100).'),
19
- },
20
- } as const;
21
-
22
- export interface ListDocumentsArgs {
23
- folderId?: string;
24
- tag?: string;
25
- page?: number;
26
- limit?: number;
27
- }
28
-
29
- export const createHandler = (api: HiaiDocsClient) =>
30
- async function listDocuments(args: ListDocumentsArgs): Promise<ListDocumentsResponse> {
31
- return (await api.listDocuments(args)) as ListDocumentsResponse;
32
- };
33
-
34
- export const handler = createHandler(client);