@aaronsb/kg-cli 0.6.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 (266) hide show
  1. package/README.md +112 -0
  2. package/dist/api/client.d.ts +867 -0
  3. package/dist/api/client.d.ts.map +1 -0
  4. package/dist/api/client.js +1362 -0
  5. package/dist/api/client.js.map +1 -0
  6. package/dist/cli/admin/backup.d.ts +9 -0
  7. package/dist/cli/admin/backup.d.ts.map +1 -0
  8. package/dist/cli/admin/backup.js +363 -0
  9. package/dist/cli/admin/backup.js.map +1 -0
  10. package/dist/cli/admin/index.d.ts +7 -0
  11. package/dist/cli/admin/index.d.ts.map +1 -0
  12. package/dist/cli/admin/index.js +52 -0
  13. package/dist/cli/admin/index.js.map +1 -0
  14. package/dist/cli/admin/scheduler.d.ts +7 -0
  15. package/dist/cli/admin/scheduler.d.ts.map +1 -0
  16. package/dist/cli/admin/scheduler.js +125 -0
  17. package/dist/cli/admin/scheduler.js.map +1 -0
  18. package/dist/cli/admin/status.d.ts +7 -0
  19. package/dist/cli/admin/status.d.ts.map +1 -0
  20. package/dist/cli/admin/status.js +134 -0
  21. package/dist/cli/admin/status.js.map +1 -0
  22. package/dist/cli/admin/utils.d.ts +34 -0
  23. package/dist/cli/admin/utils.d.ts.map +1 -0
  24. package/dist/cli/admin/utils.js +441 -0
  25. package/dist/cli/admin/utils.js.map +1 -0
  26. package/dist/cli/ai-config/embedding.d.ts +11 -0
  27. package/dist/cli/ai-config/embedding.d.ts.map +1 -0
  28. package/dist/cli/ai-config/embedding.js +598 -0
  29. package/dist/cli/ai-config/embedding.js.map +1 -0
  30. package/dist/cli/ai-config/extraction.d.ts +11 -0
  31. package/dist/cli/ai-config/extraction.d.ts.map +1 -0
  32. package/dist/cli/ai-config/extraction.js +206 -0
  33. package/dist/cli/ai-config/extraction.js.map +1 -0
  34. package/dist/cli/ai-config/index.d.ts +21 -0
  35. package/dist/cli/ai-config/index.d.ts.map +1 -0
  36. package/dist/cli/ai-config/index.js +27 -0
  37. package/dist/cli/ai-config/index.js.map +1 -0
  38. package/dist/cli/ai-config/keys.d.ts +11 -0
  39. package/dist/cli/ai-config/keys.d.ts.map +1 -0
  40. package/dist/cli/ai-config/keys.js +182 -0
  41. package/dist/cli/ai-config/keys.js.map +1 -0
  42. package/dist/cli/ai-config/utils.d.ts +13 -0
  43. package/dist/cli/ai-config/utils.d.ts.map +1 -0
  44. package/dist/cli/ai-config/utils.js +84 -0
  45. package/dist/cli/ai-config/utils.js.map +1 -0
  46. package/dist/cli/artifact.d.ts +8 -0
  47. package/dist/cli/artifact.d.ts.map +1 -0
  48. package/dist/cli/artifact.js +296 -0
  49. package/dist/cli/artifact.js.map +1 -0
  50. package/dist/cli/auth-admin.d.ts +11 -0
  51. package/dist/cli/auth-admin.d.ts.map +1 -0
  52. package/dist/cli/auth-admin.js +415 -0
  53. package/dist/cli/auth-admin.js.map +1 -0
  54. package/dist/cli/colors.d.ts +105 -0
  55. package/dist/cli/colors.d.ts.map +1 -0
  56. package/dist/cli/colors.js +164 -0
  57. package/dist/cli/colors.js.map +1 -0
  58. package/dist/cli/commands.d.ts +6 -0
  59. package/dist/cli/commands.d.ts.map +1 -0
  60. package/dist/cli/commands.js +164 -0
  61. package/dist/cli/commands.js.map +1 -0
  62. package/dist/cli/config.d.ts +6 -0
  63. package/dist/cli/config.d.ts.map +1 -0
  64. package/dist/cli/config.js +694 -0
  65. package/dist/cli/config.js.map +1 -0
  66. package/dist/cli/curve-viz.d.ts +89 -0
  67. package/dist/cli/curve-viz.d.ts.map +1 -0
  68. package/dist/cli/curve-viz.js +228 -0
  69. package/dist/cli/curve-viz.js.map +1 -0
  70. package/dist/cli/database.d.ts +6 -0
  71. package/dist/cli/database.d.ts.map +1 -0
  72. package/dist/cli/database.js +324 -0
  73. package/dist/cli/database.js.map +1 -0
  74. package/dist/cli/document.d.ts +6 -0
  75. package/dist/cli/document.d.ts.map +1 -0
  76. package/dist/cli/document.js +458 -0
  77. package/dist/cli/document.js.map +1 -0
  78. package/dist/cli/group.d.ts +8 -0
  79. package/dist/cli/group.d.ts.map +1 -0
  80. package/dist/cli/group.js +174 -0
  81. package/dist/cli/group.js.map +1 -0
  82. package/dist/cli/health.d.ts +6 -0
  83. package/dist/cli/health.d.ts.map +1 -0
  84. package/dist/cli/health.js +34 -0
  85. package/dist/cli/health.js.map +1 -0
  86. package/dist/cli/help-formatter.d.ts +16 -0
  87. package/dist/cli/help-formatter.d.ts.map +1 -0
  88. package/dist/cli/help-formatter.js +248 -0
  89. package/dist/cli/help-formatter.js.map +1 -0
  90. package/dist/cli/help.d.ts +9 -0
  91. package/dist/cli/help.d.ts.map +1 -0
  92. package/dist/cli/help.js +227 -0
  93. package/dist/cli/help.js.map +1 -0
  94. package/dist/cli/ingest.d.ts +6 -0
  95. package/dist/cli/ingest.d.ts.map +1 -0
  96. package/dist/cli/ingest.js +722 -0
  97. package/dist/cli/ingest.js.map +1 -0
  98. package/dist/cli/jobs.d.ts +6 -0
  99. package/dist/cli/jobs.d.ts.map +1 -0
  100. package/dist/cli/jobs.js +663 -0
  101. package/dist/cli/jobs.js.map +1 -0
  102. package/dist/cli/login.d.ts +21 -0
  103. package/dist/cli/login.d.ts.map +1 -0
  104. package/dist/cli/login.js +221 -0
  105. package/dist/cli/login.js.map +1 -0
  106. package/dist/cli/logout.d.ts +16 -0
  107. package/dist/cli/logout.d.ts.map +1 -0
  108. package/dist/cli/logout.js +141 -0
  109. package/dist/cli/logout.js.map +1 -0
  110. package/dist/cli/mcp-config.d.ts +10 -0
  111. package/dist/cli/mcp-config.d.ts.map +1 -0
  112. package/dist/cli/mcp-config.js +358 -0
  113. package/dist/cli/mcp-config.js.map +1 -0
  114. package/dist/cli/oauth.d.ts +15 -0
  115. package/dist/cli/oauth.d.ts.map +1 -0
  116. package/dist/cli/oauth.js +296 -0
  117. package/dist/cli/oauth.js.map +1 -0
  118. package/dist/cli/ontology.d.ts +6 -0
  119. package/dist/cli/ontology.d.ts.map +1 -0
  120. package/dist/cli/ontology.js +231 -0
  121. package/dist/cli/ontology.js.map +1 -0
  122. package/dist/cli/polarity.d.ts +6 -0
  123. package/dist/cli/polarity.d.ts.map +1 -0
  124. package/dist/cli/polarity.js +295 -0
  125. package/dist/cli/polarity.js.map +1 -0
  126. package/dist/cli/projection.d.ts +8 -0
  127. package/dist/cli/projection.d.ts.map +1 -0
  128. package/dist/cli/projection.js +297 -0
  129. package/dist/cli/projection.js.map +1 -0
  130. package/dist/cli/query-def.d.ts +8 -0
  131. package/dist/cli/query-def.d.ts.map +1 -0
  132. package/dist/cli/query-def.js +163 -0
  133. package/dist/cli/query-def.js.map +1 -0
  134. package/dist/cli/rbac.d.ts +12 -0
  135. package/dist/cli/rbac.d.ts.map +1 -0
  136. package/dist/cli/rbac.js +615 -0
  137. package/dist/cli/rbac.js.map +1 -0
  138. package/dist/cli/search.d.ts +6 -0
  139. package/dist/cli/search.d.ts.map +1 -0
  140. package/dist/cli/search.js +829 -0
  141. package/dist/cli/search.js.map +1 -0
  142. package/dist/cli/source.d.ts +6 -0
  143. package/dist/cli/source.d.ts.map +1 -0
  144. package/dist/cli/source.js +202 -0
  145. package/dist/cli/source.js.map +1 -0
  146. package/dist/cli/verb-router.d.ts +25 -0
  147. package/dist/cli/verb-router.d.ts.map +1 -0
  148. package/dist/cli/verb-router.js +415 -0
  149. package/dist/cli/verb-router.js.map +1 -0
  150. package/dist/cli/vocabulary/config.d.ts +7 -0
  151. package/dist/cli/vocabulary/config.d.ts.map +1 -0
  152. package/dist/cli/vocabulary/config.js +201 -0
  153. package/dist/cli/vocabulary/config.js.map +1 -0
  154. package/dist/cli/vocabulary/consolidate.d.ts +8 -0
  155. package/dist/cli/vocabulary/consolidate.d.ts.map +1 -0
  156. package/dist/cli/vocabulary/consolidate.js +192 -0
  157. package/dist/cli/vocabulary/consolidate.js.map +1 -0
  158. package/dist/cli/vocabulary/embeddings.d.ts +9 -0
  159. package/dist/cli/vocabulary/embeddings.d.ts.map +1 -0
  160. package/dist/cli/vocabulary/embeddings.js +205 -0
  161. package/dist/cli/vocabulary/embeddings.js.map +1 -0
  162. package/dist/cli/vocabulary/epistemic.d.ts +7 -0
  163. package/dist/cli/vocabulary/epistemic.d.ts.map +1 -0
  164. package/dist/cli/vocabulary/epistemic.js +315 -0
  165. package/dist/cli/vocabulary/epistemic.js.map +1 -0
  166. package/dist/cli/vocabulary/index.d.ts +7 -0
  167. package/dist/cli/vocabulary/index.d.ts.map +1 -0
  168. package/dist/cli/vocabulary/index.js +45 -0
  169. package/dist/cli/vocabulary/index.js.map +1 -0
  170. package/dist/cli/vocabulary/profiles.d.ts +7 -0
  171. package/dist/cli/vocabulary/profiles.d.ts.map +1 -0
  172. package/dist/cli/vocabulary/profiles.js +171 -0
  173. package/dist/cli/vocabulary/profiles.js.map +1 -0
  174. package/dist/cli/vocabulary/similarity.d.ts +9 -0
  175. package/dist/cli/vocabulary/similarity.d.ts.map +1 -0
  176. package/dist/cli/vocabulary/similarity.js +199 -0
  177. package/dist/cli/vocabulary/similarity.js.map +1 -0
  178. package/dist/cli/vocabulary/status.d.ts +8 -0
  179. package/dist/cli/vocabulary/status.d.ts.map +1 -0
  180. package/dist/cli/vocabulary/status.js +280 -0
  181. package/dist/cli/vocabulary/status.js.map +1 -0
  182. package/dist/cli/vocabulary/sync.d.ts +7 -0
  183. package/dist/cli/vocabulary/sync.d.ts.map +1 -0
  184. package/dist/cli/vocabulary/sync.js +111 -0
  185. package/dist/cli/vocabulary/sync.js.map +1 -0
  186. package/dist/index.d.ts +9 -0
  187. package/dist/index.d.ts.map +1 -0
  188. package/dist/index.js +16 -0
  189. package/dist/index.js.map +1 -0
  190. package/dist/lib/auth/auth-client.d.ts +247 -0
  191. package/dist/lib/auth/auth-client.d.ts.map +1 -0
  192. package/dist/lib/auth/auth-client.js +305 -0
  193. package/dist/lib/auth/auth-client.js.map +1 -0
  194. package/dist/lib/auth/challenge.d.ts +39 -0
  195. package/dist/lib/auth/challenge.d.ts.map +1 -0
  196. package/dist/lib/auth/challenge.js +125 -0
  197. package/dist/lib/auth/challenge.js.map +1 -0
  198. package/dist/lib/auth/client-credentials-flow.d.ts +58 -0
  199. package/dist/lib/auth/client-credentials-flow.d.ts.map +1 -0
  200. package/dist/lib/auth/client-credentials-flow.js +118 -0
  201. package/dist/lib/auth/client-credentials-flow.js.map +1 -0
  202. package/dist/lib/auth/device-flow.d.ts +75 -0
  203. package/dist/lib/auth/device-flow.d.ts.map +1 -0
  204. package/dist/lib/auth/device-flow.js +177 -0
  205. package/dist/lib/auth/device-flow.js.map +1 -0
  206. package/dist/lib/auth/index.d.ts +14 -0
  207. package/dist/lib/auth/index.d.ts.map +1 -0
  208. package/dist/lib/auth/index.js +34 -0
  209. package/dist/lib/auth/index.js.map +1 -0
  210. package/dist/lib/auth/oauth-types.d.ts +69 -0
  211. package/dist/lib/auth/oauth-types.d.ts.map +1 -0
  212. package/dist/lib/auth/oauth-types.js +10 -0
  213. package/dist/lib/auth/oauth-types.js.map +1 -0
  214. package/dist/lib/auth/oauth-utils.d.ts +51 -0
  215. package/dist/lib/auth/oauth-utils.d.ts.map +1 -0
  216. package/dist/lib/auth/oauth-utils.js +110 -0
  217. package/dist/lib/auth/oauth-utils.js.map +1 -0
  218. package/dist/lib/auth/token-manager.d.ts +87 -0
  219. package/dist/lib/auth/token-manager.d.ts.map +1 -0
  220. package/dist/lib/auth/token-manager.js +139 -0
  221. package/dist/lib/auth/token-manager.js.map +1 -0
  222. package/dist/lib/auth/token-refresh.d.ts +63 -0
  223. package/dist/lib/auth/token-refresh.d.ts.map +1 -0
  224. package/dist/lib/auth/token-refresh.js +141 -0
  225. package/dist/lib/auth/token-refresh.js.map +1 -0
  226. package/dist/lib/config.d.ts +286 -0
  227. package/dist/lib/config.d.ts.map +1 -0
  228. package/dist/lib/config.js +537 -0
  229. package/dist/lib/config.js.map +1 -0
  230. package/dist/lib/job-stream.d.ts +53 -0
  231. package/dist/lib/job-stream.d.ts.map +1 -0
  232. package/dist/lib/job-stream.js +153 -0
  233. package/dist/lib/job-stream.js.map +1 -0
  234. package/dist/lib/mcp-allowlist.d.ts +101 -0
  235. package/dist/lib/mcp-allowlist.d.ts.map +1 -0
  236. package/dist/lib/mcp-allowlist.js +340 -0
  237. package/dist/lib/mcp-allowlist.js.map +1 -0
  238. package/dist/lib/table-example.d.ts +7 -0
  239. package/dist/lib/table-example.d.ts.map +1 -0
  240. package/dist/lib/table-example.js +105 -0
  241. package/dist/lib/table-example.js.map +1 -0
  242. package/dist/lib/table.d.ts +95 -0
  243. package/dist/lib/table.d.ts.map +1 -0
  244. package/dist/lib/table.js +263 -0
  245. package/dist/lib/table.js.map +1 -0
  246. package/dist/lib/terminal-images.d.ts +66 -0
  247. package/dist/lib/terminal-images.d.ts.map +1 -0
  248. package/dist/lib/terminal-images.js +268 -0
  249. package/dist/lib/terminal-images.js.map +1 -0
  250. package/dist/mcp/formatters.d.ts +100 -0
  251. package/dist/mcp/formatters.d.ts.map +1 -0
  252. package/dist/mcp/formatters.js +1411 -0
  253. package/dist/mcp/formatters.js.map +1 -0
  254. package/dist/mcp-server.d.ts +9 -0
  255. package/dist/mcp-server.d.ts.map +1 -0
  256. package/dist/mcp-server.js +1810 -0
  257. package/dist/mcp-server.js.map +1 -0
  258. package/dist/types/index.d.ts +742 -0
  259. package/dist/types/index.d.ts.map +1 -0
  260. package/dist/types/index.js +6 -0
  261. package/dist/types/index.js.map +1 -0
  262. package/dist/version.d.ts +10 -0
  263. package/dist/version.d.ts.map +1 -0
  264. package/dist/version.js +13 -0
  265. package/dist/version.js.map +1 -0
  266. package/package.json +84 -0
@@ -0,0 +1,1362 @@
1
+ "use strict";
2
+ /**
3
+ * Knowledge Graph API Client
4
+ *
5
+ * Wraps HTTP calls to the FastAPI server
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.KnowledgeGraphClient = void 0;
45
+ exports.createClientFromEnv = createClientFromEnv;
46
+ const axios_1 = __importDefault(require("axios"));
47
+ const form_data_1 = __importDefault(require("form-data"));
48
+ const fs = __importStar(require("fs"));
49
+ class KnowledgeGraphClient {
50
+ constructor(config) {
51
+ this.mcpJwtToken = null; // JWT token for MCP server authentication
52
+ this.config = config;
53
+ this.client = axios_1.default.create({
54
+ baseURL: config.baseUrl,
55
+ headers: {
56
+ ...(config.clientId && { 'X-Client-ID': config.clientId }),
57
+ ...(config.apiKey && { 'X-API-Key': config.apiKey }),
58
+ },
59
+ });
60
+ // ADR-054: Add request interceptor for OAuth authentication
61
+ this.client.interceptors.request.use(async (requestConfig) => {
62
+ // Priority 1: Use MCP JWT token if set (for MCP server - legacy)
63
+ if (this.mcpJwtToken) {
64
+ requestConfig.headers.Authorization = `Bearer ${this.mcpJwtToken}`;
65
+ return requestConfig;
66
+ }
67
+ // Priority 2: Get OAuth client credentials from config and fetch fresh access token
68
+ try {
69
+ const { getConfig } = require('../lib/config');
70
+ const { AuthClient } = require('../lib/auth/auth-client');
71
+ const configManager = getConfig();
72
+ // Check for OAuth client credentials (ADR-054)
73
+ const oauthCreds = configManager.getOAuthCredentials();
74
+ if (oauthCreds) {
75
+ // Get fresh access token using client credentials grant
76
+ const authClient = new AuthClient(this.config.baseUrl);
77
+ const tokenResponse = await authClient.getOAuthToken({
78
+ grant_type: 'client_credentials',
79
+ client_id: oauthCreds.client_id,
80
+ client_secret: oauthCreds.client_secret,
81
+ scope: oauthCreds.scopes.join(' ')
82
+ });
83
+ requestConfig.headers.Authorization = `Bearer ${tokenResponse.access_token}`;
84
+ }
85
+ }
86
+ catch (error) {
87
+ // Config not available or OAuth credentials not found - continue without auth
88
+ }
89
+ return requestConfig;
90
+ });
91
+ // ADR-054: Add response interceptor for 401 errors (invalid OAuth token)
92
+ this.client.interceptors.response.use((response) => response, (error) => {
93
+ if (error.response?.status === 401) {
94
+ // Check if we have OAuth credentials
95
+ try {
96
+ const { getConfig } = require('../lib/config');
97
+ const configManager = getConfig();
98
+ if (configManager.isAuthenticated()) {
99
+ // User has OAuth credentials but got 401 - client may be revoked
100
+ console.error('\n\x1b[31m❌ Authentication failed\x1b[0m');
101
+ console.error(' Your OAuth credentials may be invalid or revoked.');
102
+ console.error(' Please login again:');
103
+ console.error(' \x1b[36mkg login\x1b[0m\n');
104
+ }
105
+ }
106
+ catch (e) {
107
+ // Ignore errors from config loading
108
+ }
109
+ }
110
+ return Promise.reject(error);
111
+ });
112
+ }
113
+ /**
114
+ * Set JWT token for MCP server authentication
115
+ *
116
+ * This allows the MCP server to inject a JWT token obtained via automatic login,
117
+ * making authentication transparent to the AI using the MCP tools.
118
+ *
119
+ * @param token JWT access token from login response
120
+ */
121
+ setMcpJwtToken(token) {
122
+ this.mcpJwtToken = token;
123
+ }
124
+ /**
125
+ * Health check
126
+ */
127
+ async health() {
128
+ const response = await this.client.get('/health');
129
+ return response.data;
130
+ }
131
+ /**
132
+ * Get API info
133
+ */
134
+ async info() {
135
+ const response = await this.client.get('/');
136
+ return response.data;
137
+ }
138
+ /**
139
+ * Ingest a document file
140
+ */
141
+ async ingestFile(filePath, request) {
142
+ const form = new form_data_1.default();
143
+ form.append('file', fs.createReadStream(filePath));
144
+ form.append('ontology', request.ontology);
145
+ if (request.filename) {
146
+ form.append('filename', request.filename);
147
+ }
148
+ if (request.force) {
149
+ form.append('force', 'true');
150
+ }
151
+ if (request.auto_approve) {
152
+ form.append('auto_approve', 'true');
153
+ }
154
+ if (request.processing_mode) {
155
+ form.append('processing_mode', request.processing_mode);
156
+ }
157
+ if (request.options) {
158
+ if (request.options.target_words !== undefined) {
159
+ form.append('target_words', String(request.options.target_words));
160
+ }
161
+ if (request.options.min_words !== undefined) {
162
+ form.append('min_words', String(request.options.min_words));
163
+ }
164
+ if (request.options.max_words !== undefined) {
165
+ form.append('max_words', String(request.options.max_words));
166
+ }
167
+ if (request.options.overlap_words !== undefined) {
168
+ form.append('overlap_words', String(request.options.overlap_words));
169
+ }
170
+ }
171
+ // ADR-051: Source provenance metadata
172
+ if (request.source_type) {
173
+ form.append('source_type', request.source_type);
174
+ }
175
+ if (request.source_path) {
176
+ form.append('source_path', request.source_path);
177
+ }
178
+ if (request.source_hostname) {
179
+ form.append('source_hostname', request.source_hostname);
180
+ }
181
+ const response = await this.client.post('/ingest', form, {
182
+ headers: form.getHeaders(),
183
+ });
184
+ return response.data;
185
+ }
186
+ /**
187
+ * Ingest raw text
188
+ */
189
+ async ingestText(text, request) {
190
+ const form = new form_data_1.default();
191
+ form.append('text', text);
192
+ form.append('ontology', request.ontology);
193
+ if (request.filename) {
194
+ form.append('filename', request.filename);
195
+ }
196
+ if (request.force) {
197
+ form.append('force', 'true');
198
+ }
199
+ if (request.auto_approve) {
200
+ form.append('auto_approve', 'true');
201
+ }
202
+ if (request.processing_mode) {
203
+ form.append('processing_mode', request.processing_mode);
204
+ }
205
+ if (request.options?.target_words !== undefined) {
206
+ form.append('target_words', String(request.options.target_words));
207
+ }
208
+ if (request.options?.overlap_words !== undefined) {
209
+ form.append('overlap_words', String(request.options.overlap_words));
210
+ }
211
+ const response = await this.client.post('/ingest/text', form, {
212
+ headers: form.getHeaders(),
213
+ });
214
+ return response.data;
215
+ }
216
+ /**
217
+ * Ingest image (ADR-057)
218
+ */
219
+ async ingestImage(filePath, request) {
220
+ const form = new form_data_1.default();
221
+ form.append('file', fs.createReadStream(filePath));
222
+ form.append('ontology', request.ontology);
223
+ if (request.filename) {
224
+ form.append('filename', request.filename);
225
+ }
226
+ if (request.force) {
227
+ form.append('force', 'true');
228
+ }
229
+ if (request.auto_approve) {
230
+ form.append('auto_approve', 'true');
231
+ }
232
+ if (request.vision_provider) {
233
+ form.append('vision_provider', request.vision_provider);
234
+ }
235
+ if (request.vision_model) {
236
+ form.append('vision_model', request.vision_model);
237
+ }
238
+ if (request.source_type) {
239
+ form.append('source_type', request.source_type);
240
+ }
241
+ if (request.source_path) {
242
+ form.append('source_path', request.source_path);
243
+ }
244
+ if (request.source_hostname) {
245
+ form.append('source_hostname', request.source_hostname);
246
+ }
247
+ const response = await this.client.post('/ingest/image', form, {
248
+ headers: form.getHeaders(),
249
+ });
250
+ return response.data;
251
+ }
252
+ /**
253
+ * Get job status
254
+ */
255
+ async getJob(jobId) {
256
+ const response = await this.client.get(`/jobs/${jobId}`);
257
+ return response.data;
258
+ }
259
+ /**
260
+ * Get job status (alias for getJob)
261
+ */
262
+ async getJobStatus(jobId) {
263
+ return this.getJob(jobId);
264
+ }
265
+ /**
266
+ * List jobs
267
+ */
268
+ async listJobs(status, clientId, limit = 50, offset = 0) {
269
+ const params = { limit, offset };
270
+ if (status) {
271
+ params.status = status;
272
+ }
273
+ if (clientId) {
274
+ params.client_id = clientId;
275
+ }
276
+ const response = await this.client.get('/jobs', { params });
277
+ return response.data;
278
+ }
279
+ /**
280
+ * Cancel a job
281
+ */
282
+ async cancelJob(jobId) {
283
+ const response = await this.client.delete(`/jobs/${jobId}`);
284
+ return response.data;
285
+ }
286
+ /**
287
+ * Clear all jobs (nuclear option - requires confirmation)
288
+ */
289
+ async clearAllJobs(confirm = false) {
290
+ const response = await this.client.delete('/jobs', {
291
+ params: { confirm }
292
+ });
293
+ return response.data;
294
+ }
295
+ /**
296
+ * Approve a job for processing (ADR-014)
297
+ */
298
+ async approveJob(jobId) {
299
+ const response = await this.client.post(`/jobs/${jobId}/approve`);
300
+ return response.data;
301
+ }
302
+ /**
303
+ * Poll job until completion
304
+ *
305
+ * @param jobId Job ID to poll
306
+ * @param onProgress Optional callback for progress updates
307
+ * @param pollInterval Poll interval in ms (default: 2000)
308
+ * @returns Final job status
309
+ */
310
+ async pollJob(jobId, onProgress, pollInterval = 2000) {
311
+ while (true) {
312
+ const job = await this.getJob(jobId);
313
+ if (onProgress) {
314
+ onProgress(job);
315
+ }
316
+ // Check if job is terminal or awaiting approval
317
+ // Stop polling if job needs user action (approval) or is complete
318
+ if (['completed', 'failed', 'cancelled', 'awaiting_approval'].includes(job.status)) {
319
+ return job;
320
+ }
321
+ // Wait before polling again
322
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
323
+ }
324
+ }
325
+ // ========== Query Methods ==========
326
+ /**
327
+ * Search for concepts using semantic similarity
328
+ */
329
+ async searchConcepts(request) {
330
+ const response = await this.client.post('/query/search', request);
331
+ return response.data;
332
+ }
333
+ /**
334
+ * Search source text using semantic similarity (ADR-068 Phase 3)
335
+ */
336
+ async searchSources(request) {
337
+ const response = await this.client.post('/query/sources/search', request);
338
+ return response.data;
339
+ }
340
+ /**
341
+ * Get detailed information about a concept
342
+ */
343
+ async getConceptDetails(conceptId, includeGrounding = false, includeDiversity = false, diversityMaxHops = 2) {
344
+ const response = await this.client.get(`/query/concept/${conceptId}`, {
345
+ params: {
346
+ include_grounding: includeGrounding,
347
+ include_diversity: includeDiversity,
348
+ diversity_max_hops: diversityMaxHops
349
+ }
350
+ });
351
+ return response.data;
352
+ }
353
+ /**
354
+ * Find concepts related through graph traversal
355
+ */
356
+ async findRelatedConcepts(request) {
357
+ const response = await this.client.post('/query/related', request);
358
+ return response.data;
359
+ }
360
+ /**
361
+ * Find shortest paths between two concepts
362
+ */
363
+ async findConnection(request) {
364
+ const response = await this.client.post('/query/connect', request);
365
+ return response.data;
366
+ }
367
+ /**
368
+ * Find shortest paths between concepts using natural language queries
369
+ */
370
+ async findConnectionBySearch(request) {
371
+ const response = await this.client.post('/query/connect-by-search', request);
372
+ return response.data;
373
+ }
374
+ /**
375
+ * Get image for a source node (ADR-057)
376
+ * @param sourceId - Source ID from concept instance
377
+ * @returns Image as Buffer (binary data)
378
+ */
379
+ async getSourceImage(sourceId) {
380
+ const response = await this.client.get(`/sources/${sourceId}/image`, {
381
+ responseType: 'arraybuffer',
382
+ });
383
+ return Buffer.from(response.data);
384
+ }
385
+ /**
386
+ * Get image for a source node as base64 string (ADR-057)
387
+ * Useful for MCP server to return images to Claude
388
+ * @param sourceId - Source ID from concept instance
389
+ * @returns Base64-encoded image string
390
+ */
391
+ async getSourceImageBase64(sourceId) {
392
+ const buffer = await this.getSourceImage(sourceId);
393
+ return buffer.toString('base64');
394
+ }
395
+ /**
396
+ * List source nodes with optional filtering
397
+ * @param options - Filter and pagination options
398
+ * @returns List of sources with metadata
399
+ */
400
+ async listSources(options = {}) {
401
+ const params = new URLSearchParams();
402
+ if (options.ontology)
403
+ params.append('ontology', options.ontology);
404
+ if (options.limit)
405
+ params.append('limit', options.limit.toString());
406
+ if (options.offset)
407
+ params.append('offset', options.offset.toString());
408
+ const response = await this.client.get(`/sources?${params.toString()}`);
409
+ return response.data;
410
+ }
411
+ /**
412
+ * Get original document for a source node (ADR-081)
413
+ * @param sourceId - Source ID from search results or concept details
414
+ * @returns Document content as Buffer (binary data)
415
+ */
416
+ async getSourceDocument(sourceId) {
417
+ const response = await this.client.get(`/sources/${sourceId}/document`, {
418
+ responseType: 'arraybuffer',
419
+ });
420
+ return Buffer.from(response.data);
421
+ }
422
+ /**
423
+ * Get source metadata
424
+ * @param sourceId - Source ID
425
+ * @returns Source metadata including garage_key, content_hash, etc.
426
+ */
427
+ async getSourceMetadata(sourceId) {
428
+ const response = await this.client.get(`/sources/${sourceId}`);
429
+ return response.data;
430
+ }
431
+ // ========== Document Methods (ADR-084) ==========
432
+ /**
433
+ * Search documents using semantic similarity
434
+ * Aggregates chunk-level matches to document level
435
+ */
436
+ async searchDocuments(request) {
437
+ const response = await this.client.post('/query/documents/search', request);
438
+ return response.data;
439
+ }
440
+ /**
441
+ * List documents with optional ontology filter
442
+ */
443
+ async listDocuments(options = {}) {
444
+ const params = new URLSearchParams();
445
+ if (options.ontology)
446
+ params.append('ontology', options.ontology);
447
+ if (options.limit)
448
+ params.append('limit', options.limit.toString());
449
+ if (options.offset)
450
+ params.append('offset', options.offset.toString());
451
+ const response = await this.client.get(`/documents?${params.toString()}`);
452
+ return response.data;
453
+ }
454
+ /**
455
+ * Get document content from Garage
456
+ */
457
+ async getDocumentContent(documentId) {
458
+ const response = await this.client.get(`/documents/${encodeURIComponent(documentId)}/content`);
459
+ return response.data;
460
+ }
461
+ /**
462
+ * Get concepts extracted from a document
463
+ */
464
+ async getDocumentConcepts(documentId) {
465
+ const response = await this.client.get(`/documents/${encodeURIComponent(documentId)}/concepts`);
466
+ return response.data;
467
+ }
468
+ // ========== Database Methods ==========
469
+ /**
470
+ * Get database statistics
471
+ */
472
+ async getDatabaseStats() {
473
+ const response = await this.client.get('/database/stats');
474
+ return response.data;
475
+ }
476
+ /**
477
+ * Get database connection information
478
+ */
479
+ async getDatabaseInfo() {
480
+ const response = await this.client.get('/database/info');
481
+ return response.data;
482
+ }
483
+ /**
484
+ * Check database health
485
+ */
486
+ async getDatabaseHealth() {
487
+ const response = await this.client.get('/database/health');
488
+ return response.data;
489
+ }
490
+ /**
491
+ * Execute a custom cypher query (ADR-048)
492
+ * @param query - openCypher/GQL query string
493
+ * @param params - Optional query parameters
494
+ * @param namespace - Optional namespace: 'concept', 'vocab', or null for raw
495
+ */
496
+ async executeCypherQuery(query, params, namespace) {
497
+ const response = await this.client.post('/database/query', {
498
+ query,
499
+ params: params || null,
500
+ namespace: namespace === undefined ? null : namespace
501
+ });
502
+ return response.data;
503
+ }
504
+ /**
505
+ * Get all graph metrics counters organized by type (ADR-079)
506
+ */
507
+ async getDatabaseCounters() {
508
+ const response = await this.client.get('/database/counters');
509
+ return response.data;
510
+ }
511
+ /**
512
+ * Refresh graph metrics counters from current graph state (ADR-079)
513
+ */
514
+ async refreshDatabaseCounters() {
515
+ const response = await this.client.post('/database/counters/refresh');
516
+ return response.data;
517
+ }
518
+ // ========== Ontology Methods ==========
519
+ /**
520
+ * List all ontologies
521
+ */
522
+ async listOntologies() {
523
+ const response = await this.client.get('/ontology/');
524
+ return response.data;
525
+ }
526
+ /**
527
+ * Get ontology information
528
+ */
529
+ async getOntologyInfo(ontologyName) {
530
+ const response = await this.client.get(`/ontology/${encodeURIComponent(ontologyName)}`);
531
+ return response.data;
532
+ }
533
+ /**
534
+ * List files in an ontology
535
+ */
536
+ async getOntologyFiles(ontologyName) {
537
+ const response = await this.client.get(`/ontology/${encodeURIComponent(ontologyName)}/files`);
538
+ return response.data;
539
+ }
540
+ /**
541
+ * Delete an ontology
542
+ */
543
+ async deleteOntology(ontologyName, force = false) {
544
+ const response = await this.client.delete(`/ontology/${encodeURIComponent(ontologyName)}`, {
545
+ params: { force }
546
+ });
547
+ return response.data;
548
+ }
549
+ /**
550
+ * Rename an ontology
551
+ */
552
+ async renameOntology(oldName, newName) {
553
+ const response = await this.client.post(`/ontology/${encodeURIComponent(oldName)}/rename`, {
554
+ new_name: newName
555
+ });
556
+ return response.data;
557
+ }
558
+ // ========== Admin Methods ==========
559
+ /**
560
+ * Get system status
561
+ */
562
+ async getSystemStatus() {
563
+ const response = await this.client.get('/admin/status');
564
+ return response.data;
565
+ }
566
+ /**
567
+ * List available backup files
568
+ */
569
+ async listBackups() {
570
+ const response = await this.client.get('/admin/backups');
571
+ return response.data;
572
+ }
573
+ /**
574
+ * Create a database backup (ADR-015 Phase 2: Streaming Download)
575
+ *
576
+ * Downloads backup as a stream and saves to specified path.
577
+ * Provides progress callback for tracking download.
578
+ *
579
+ * @param request Backup request (type and optional ontology)
580
+ * @param savePath Where to save the backup file
581
+ * @param onProgress Optional callback for progress updates (bytes downloaded, total bytes, percent)
582
+ * @returns Metadata about the downloaded backup
583
+ */
584
+ async createBackup(request, savePath, onProgress) {
585
+ const response = await this.client.post('/admin/backup', request, {
586
+ responseType: 'stream'
587
+ });
588
+ // Extract filename from Content-Disposition header
589
+ const contentDisposition = response.headers['content-disposition'];
590
+ const filenameMatch = contentDisposition?.match(/filename=(.+)/);
591
+ // Default based on content type (archive is now default)
592
+ const contentType = response.headers['content-type'] || '';
593
+ const defaultFilename = contentType.includes('gzip') ? 'backup.tar.gz' : 'backup.json';
594
+ const filename = filenameMatch ? filenameMatch[1] : defaultFilename;
595
+ // Get content length if available
596
+ const totalBytes = parseInt(response.headers['content-length'] || '0', 10);
597
+ // Create write stream
598
+ const writer = fs.createWriteStream(savePath);
599
+ let downloadedBytes = 0;
600
+ // Pipe response to file with progress tracking
601
+ response.data.on('data', (chunk) => {
602
+ downloadedBytes += chunk.length;
603
+ if (onProgress && totalBytes > 0) {
604
+ const percent = Math.round((downloadedBytes / totalBytes) * 100);
605
+ onProgress(downloadedBytes, totalBytes, percent);
606
+ }
607
+ });
608
+ // Wait for download to complete
609
+ await new Promise((resolve, reject) => {
610
+ response.data.pipe(writer);
611
+ writer.on('finish', resolve);
612
+ writer.on('error', reject);
613
+ response.data.on('error', reject);
614
+ });
615
+ // Rename file to use server-provided filename if different
616
+ // Handle all backup formats: .json, .gexf, .tar.gz
617
+ const finalPath = savePath.replace(/[^/]+(\.json|\.gexf|\.tar\.gz)$/, filename);
618
+ if (finalPath !== savePath && fs.existsSync(savePath)) {
619
+ fs.renameSync(savePath, finalPath);
620
+ }
621
+ return {
622
+ filename,
623
+ path: finalPath,
624
+ size: downloadedBytes
625
+ };
626
+ }
627
+ /**
628
+ * Restore a database backup (ADR-015 Phase 2: Multipart Upload)
629
+ *
630
+ * Uploads backup file as multipart/form-data and queues restore job.
631
+ * Server validates backup, creates checkpoint, then executes restore with progress tracking.
632
+ * Uses OAuth authentication (token from login).
633
+ *
634
+ * @param backupFilePath Path to backup file (.tar.gz archive or .json)
635
+ * @param overwrite Whether to overwrite existing data
636
+ * @param handleExternalDeps How to handle external dependencies ('prune', 'stitch', 'defer')
637
+ * @param onUploadProgress Optional callback for upload progress (bytes uploaded, total bytes, percent)
638
+ * @returns Job ID and initial status for polling restore progress
639
+ */
640
+ async restoreBackup(backupFilePath, overwrite = false, handleExternalDeps = 'prune', onUploadProgress) {
641
+ const form = new form_data_1.default();
642
+ form.append('file', fs.createReadStream(backupFilePath));
643
+ form.append('overwrite', String(overwrite));
644
+ form.append('handle_external_deps', handleExternalDeps);
645
+ const response = await this.client.post('/admin/restore', form, {
646
+ headers: form.getHeaders(),
647
+ onUploadProgress: (progressEvent) => {
648
+ if (onUploadProgress && progressEvent.total) {
649
+ const uploaded = progressEvent.loaded;
650
+ const total = progressEvent.total;
651
+ const percent = Math.round((uploaded / total) * 100);
652
+ onUploadProgress(uploaded, total, percent);
653
+ }
654
+ }
655
+ });
656
+ return response.data;
657
+ }
658
+ /**
659
+ * Reset database (destructive - requires authentication)
660
+ */
661
+ async resetDatabase(request) {
662
+ const response = await this.client.post('/admin/reset', request);
663
+ return response.data;
664
+ }
665
+ /**
666
+ * Get job scheduler status and statistics (ADR-014)
667
+ */
668
+ async getSchedulerStatus() {
669
+ const response = await this.client.get('/admin/scheduler/status');
670
+ return response.data;
671
+ }
672
+ /**
673
+ * Manually trigger job scheduler cleanup (ADR-014)
674
+ */
675
+ async triggerSchedulerCleanup() {
676
+ const response = await this.client.post('/admin/scheduler/cleanup');
677
+ return response.data;
678
+ }
679
+ /**
680
+ * Regenerate embeddings for concept nodes in the graph
681
+ */
682
+ async regenerateConceptEmbeddings(params) {
683
+ const queryParams = new URLSearchParams();
684
+ if (params.only_missing) {
685
+ queryParams.append('only_missing', 'true');
686
+ }
687
+ if (params.ontology) {
688
+ queryParams.append('ontology', params.ontology);
689
+ }
690
+ if (params.limit) {
691
+ queryParams.append('limit', params.limit.toString());
692
+ }
693
+ const url = `/admin/regenerate-concept-embeddings${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
694
+ const response = await this.client.post(url);
695
+ return response.data;
696
+ }
697
+ /**
698
+ * Unified embedding regeneration for all graph text entities (ADR-068 Phase 4).
699
+ *
700
+ * Regenerate embeddings for concepts, sources, or vocabulary (relationship types).
701
+ * Useful for model migrations, fixing missing/corrupted embeddings, or bulk regeneration.
702
+ */
703
+ async regenerateEmbeddings(params) {
704
+ const queryParams = new URLSearchParams();
705
+ queryParams.append('embedding_type', params.embedding_type);
706
+ if (params.only_missing) {
707
+ queryParams.append('only_missing', 'true');
708
+ }
709
+ if (params.only_incompatible) {
710
+ queryParams.append('only_incompatible', 'true');
711
+ }
712
+ if (params.ontology) {
713
+ queryParams.append('ontology', params.ontology);
714
+ }
715
+ if (params.limit) {
716
+ queryParams.append('limit', params.limit.toString());
717
+ }
718
+ const url = `/admin/embedding/regenerate?${queryParams.toString()}`;
719
+ const response = await this.client.post(url);
720
+ return response.data;
721
+ }
722
+ /**
723
+ * Get comprehensive embedding status for all graph text entities.
724
+ *
725
+ * Shows count, percentage, compatibility verification, and hash verification
726
+ * for embeddings across concepts, sources, vocabulary, and images.
727
+ */
728
+ async getEmbeddingStatus(ontology) {
729
+ const queryParams = new URLSearchParams();
730
+ if (ontology) {
731
+ queryParams.append('ontology', ontology);
732
+ }
733
+ const url = `/admin/embedding/status${queryParams.toString() ? '?' + queryParams.toString() : ''}`;
734
+ const response = await this.client.get(url);
735
+ return response.data;
736
+ }
737
+ // ========== RBAC Methods (ADR-028) ==========
738
+ /**
739
+ * List all registered resource types
740
+ */
741
+ async listResources() {
742
+ const response = await this.client.get('/rbac/resources');
743
+ return response.data;
744
+ }
745
+ /**
746
+ * Get a specific resource type
747
+ */
748
+ async getResource(resourceType) {
749
+ const response = await this.client.get(`/rbac/resources/${resourceType}`);
750
+ return response.data;
751
+ }
752
+ /**
753
+ * Register a new resource type
754
+ */
755
+ async createResource(resource) {
756
+ const response = await this.client.post('/rbac/resources', resource);
757
+ return response.data;
758
+ }
759
+ /**
760
+ * Update a resource type
761
+ */
762
+ async updateResource(resourceType, update) {
763
+ const response = await this.client.put(`/rbac/resources/${resourceType}`, update);
764
+ return response.data;
765
+ }
766
+ /**
767
+ * Delete a resource type
768
+ */
769
+ async deleteResource(resourceType) {
770
+ await this.client.delete(`/rbac/resources/${resourceType}`);
771
+ }
772
+ /**
773
+ * List all roles
774
+ */
775
+ async listRoles(includeInactive = false) {
776
+ const response = await this.client.get('/rbac/roles', {
777
+ params: { include_inactive: includeInactive }
778
+ });
779
+ return response.data;
780
+ }
781
+ /**
782
+ * Get a specific role
783
+ */
784
+ async getRole(roleName) {
785
+ const response = await this.client.get(`/rbac/roles/${roleName}`);
786
+ return response.data;
787
+ }
788
+ /**
789
+ * Create a new role
790
+ */
791
+ async createRole(role) {
792
+ const response = await this.client.post('/rbac/roles', role);
793
+ return response.data;
794
+ }
795
+ /**
796
+ * Update a role
797
+ */
798
+ async updateRole(roleName, update) {
799
+ const response = await this.client.put(`/rbac/roles/${roleName}`, update);
800
+ return response.data;
801
+ }
802
+ /**
803
+ * Delete a role
804
+ */
805
+ async deleteRole(roleName) {
806
+ await this.client.delete(`/rbac/roles/${roleName}`);
807
+ }
808
+ /**
809
+ * List permissions (optionally filtered)
810
+ */
811
+ async listPermissions(roleName, resourceType) {
812
+ const params = {};
813
+ if (roleName)
814
+ params.role_name = roleName;
815
+ if (resourceType)
816
+ params.resource_type = resourceType;
817
+ const response = await this.client.get('/rbac/permissions', { params });
818
+ return response.data;
819
+ }
820
+ /**
821
+ * Grant a permission to a role
822
+ */
823
+ async createPermission(permission) {
824
+ const response = await this.client.post('/rbac/permissions', permission);
825
+ return response.data;
826
+ }
827
+ /**
828
+ * Revoke a permission from a role
829
+ */
830
+ async deletePermission(permissionId) {
831
+ await this.client.delete(`/rbac/permissions/${permissionId}`);
832
+ }
833
+ /**
834
+ * List role assignments for a user
835
+ */
836
+ async listUserRoles(userId) {
837
+ const response = await this.client.get(`/rbac/user-roles/${userId}`);
838
+ return response.data;
839
+ }
840
+ /**
841
+ * Assign a role to a user
842
+ */
843
+ async assignUserRole(assignment) {
844
+ const response = await this.client.post('/rbac/user-roles', assignment);
845
+ return response.data;
846
+ }
847
+ /**
848
+ * Revoke a role assignment from a user
849
+ */
850
+ async revokeUserRole(assignmentId) {
851
+ await this.client.delete(`/rbac/user-roles/${assignmentId}`);
852
+ }
853
+ /**
854
+ * Check if a user has a specific permission
855
+ */
856
+ async checkPermission(request) {
857
+ const response = await this.client.post('/rbac/check-permission', request);
858
+ return response.data;
859
+ }
860
+ // ========== Vocabulary Methods (ADR-032) ==========
861
+ /**
862
+ * Get current vocabulary status
863
+ */
864
+ async getVocabularyStatus() {
865
+ const response = await this.client.get('/vocabulary/status');
866
+ return response.data;
867
+ }
868
+ /**
869
+ * List all edge types with statistics
870
+ */
871
+ async listEdgeTypes(includeInactive = false, includeBuiltin = true) {
872
+ const response = await this.client.get('/vocabulary/types', {
873
+ params: {
874
+ include_inactive: includeInactive,
875
+ include_builtin: includeBuiltin
876
+ }
877
+ });
878
+ return response.data;
879
+ }
880
+ /**
881
+ * Manually add a new edge type (curator action)
882
+ */
883
+ async addEdgeType(request) {
884
+ const response = await this.client.post('/vocabulary/types', request);
885
+ return response.data;
886
+ }
887
+ /**
888
+ * Generate vocabulary optimization recommendations
889
+ */
890
+ async getVocabularyRecommendations() {
891
+ const response = await this.client.get('/vocabulary/recommendations');
892
+ return response.data;
893
+ }
894
+ /**
895
+ * Execute all auto-approved recommendations
896
+ */
897
+ async executeAutoRecommendations() {
898
+ const response = await this.client.post('/vocabulary/recommendations/execute');
899
+ return response.data;
900
+ }
901
+ /**
902
+ * Get detailed vocabulary analysis
903
+ */
904
+ async getVocabularyAnalysis() {
905
+ const response = await this.client.get('/vocabulary/analysis');
906
+ return response.data;
907
+ }
908
+ /**
909
+ * Get vocabulary configuration
910
+ */
911
+ async getVocabularyConfig() {
912
+ const response = await this.client.get('/vocabulary/config');
913
+ return response.data;
914
+ }
915
+ /**
916
+ * Get vocabulary configuration details (admin endpoint)
917
+ */
918
+ async getVocabularyConfigDetail() {
919
+ const response = await this.client.get('/admin/vocabulary/config');
920
+ return response.data;
921
+ }
922
+ /**
923
+ * Update vocabulary configuration (admin endpoint)
924
+ */
925
+ async updateVocabularyConfig(config) {
926
+ const response = await this.client.put('/admin/vocabulary/config', config);
927
+ return response.data;
928
+ }
929
+ /**
930
+ * List aggressiveness profiles (admin endpoint)
931
+ */
932
+ async listAggressivenessProfiles() {
933
+ const response = await this.client.get('/admin/vocabulary/profiles');
934
+ return response.data;
935
+ }
936
+ /**
937
+ * Get specific aggressiveness profile (admin endpoint)
938
+ */
939
+ async getAggressivenessProfile(profileName) {
940
+ const response = await this.client.get(`/admin/vocabulary/profiles/${encodeURIComponent(profileName)}`);
941
+ return response.data;
942
+ }
943
+ /**
944
+ * Create custom aggressiveness profile (admin endpoint)
945
+ */
946
+ async createAggressivenessProfile(profile) {
947
+ const response = await this.client.post('/admin/vocabulary/profiles', profile);
948
+ return response.data;
949
+ }
950
+ /**
951
+ * Delete custom aggressiveness profile (admin endpoint)
952
+ */
953
+ async deleteAggressivenessProfile(profileName) {
954
+ const response = await this.client.delete(`/admin/vocabulary/profiles/${encodeURIComponent(profileName)}`);
955
+ return response.data;
956
+ }
957
+ /**
958
+ * Merge two edge types (curator action)
959
+ */
960
+ async mergeEdgeTypes(request) {
961
+ const response = await this.client.post('/vocabulary/merge', request);
962
+ return response.data;
963
+ }
964
+ /**
965
+ * Get category similarity scores for a relationship type (ADR-047)
966
+ */
967
+ async getCategoryScores(relationshipType) {
968
+ const response = await this.client.get(`/vocabulary/category-scores/${encodeURIComponent(relationshipType)}`);
969
+ return response.data;
970
+ }
971
+ /**
972
+ * Refresh category assignments for vocabulary types (ADR-047)
973
+ */
974
+ async refreshCategories(onlyComputed = true) {
975
+ const response = await this.client.post('/vocabulary/refresh-categories', {
976
+ only_computed: onlyComputed
977
+ });
978
+ return response.data;
979
+ }
980
+ /**
981
+ * Generate embeddings for vocabulary types (bulk operation)
982
+ */
983
+ async generateVocabularyEmbeddings(forceRegenerate = false, onlyMissing = true) {
984
+ const response = await this.client.post('/vocabulary/generate-embeddings', {
985
+ force_regenerate: forceRegenerate,
986
+ only_missing: onlyMissing
987
+ });
988
+ return response.data;
989
+ }
990
+ /**
991
+ * Run AITL vocabulary consolidation workflow (ADR-032)
992
+ */
993
+ async consolidateVocabulary(request) {
994
+ const response = await this.client.post('/vocabulary/consolidate', {
995
+ target_size: request.target_size ?? 90,
996
+ batch_size: request.batch_size ?? 1,
997
+ auto_execute_threshold: request.auto_execute_threshold ?? 0.90,
998
+ dry_run: request.dry_run ?? false,
999
+ prune_unused: request.prune_unused ?? true // Default: prune unused types
1000
+ });
1001
+ return response.data;
1002
+ }
1003
+ /**
1004
+ * Measure epistemic status for vocabulary types (ADR-065 Phase 2)
1005
+ */
1006
+ async measureEpistemicStatus(request) {
1007
+ const response = await this.client.post('/vocabulary/epistemic-status/measure', {
1008
+ sample_size: request.sample_size ?? 100,
1009
+ store: request.store ?? true,
1010
+ verbose: request.verbose ?? false
1011
+ });
1012
+ return response.data;
1013
+ }
1014
+ /**
1015
+ * List vocabulary types with epistemic status (ADR-065 Phase 2)
1016
+ */
1017
+ async listEpistemicStatus(statusFilter) {
1018
+ const response = await this.client.get('/vocabulary/epistemic-status', {
1019
+ params: statusFilter ? { status_filter: statusFilter } : {}
1020
+ });
1021
+ return response.data;
1022
+ }
1023
+ /**
1024
+ * Get epistemic status for a specific vocabulary type (ADR-065 Phase 2)
1025
+ */
1026
+ async getEpistemicStatus(relationshipType) {
1027
+ const response = await this.client.get(`/vocabulary/epistemic-status/${encodeURIComponent(relationshipType)}`);
1028
+ return response.data;
1029
+ }
1030
+ /**
1031
+ * Sync missing edge types from graph to vocabulary (ADR-077)
1032
+ */
1033
+ async syncVocabulary(dryRun = true) {
1034
+ const response = await this.client.post('/vocabulary/sync', {
1035
+ dry_run: dryRun
1036
+ });
1037
+ return response.data;
1038
+ }
1039
+ // ========== AI Configuration Methods (ADR-039, ADR-041) ==========
1040
+ /**
1041
+ * Get current embedding configuration (public endpoint)
1042
+ */
1043
+ async getEmbeddingConfig() {
1044
+ const response = await this.client.get('/embedding/config');
1045
+ return response.data;
1046
+ }
1047
+ /**
1048
+ * Get detailed embedding configuration (admin endpoint)
1049
+ */
1050
+ async getEmbeddingConfigDetail() {
1051
+ const response = await this.client.get('/admin/embedding/config');
1052
+ return response.data;
1053
+ }
1054
+ /**
1055
+ * Update embedding configuration (admin endpoint)
1056
+ */
1057
+ async updateEmbeddingConfig(config) {
1058
+ const response = await this.client.post('/admin/embedding/config', config);
1059
+ return response.data;
1060
+ }
1061
+ /**
1062
+ * Hot reload embedding model (admin endpoint)
1063
+ */
1064
+ async reloadEmbeddingModel() {
1065
+ const response = await this.client.post('/admin/embedding/config/reload');
1066
+ return response.data;
1067
+ }
1068
+ /**
1069
+ * List all embedding configurations (admin endpoint)
1070
+ */
1071
+ async listEmbeddingConfigs() {
1072
+ const response = await this.client.get('/admin/embedding/configs');
1073
+ return response.data;
1074
+ }
1075
+ /**
1076
+ * Set protection flags on an embedding config (admin endpoint)
1077
+ */
1078
+ async protectEmbeddingConfig(configId, deleteProtected, changeProtected) {
1079
+ const params = {};
1080
+ if (deleteProtected !== undefined)
1081
+ params.delete_protected = deleteProtected;
1082
+ if (changeProtected !== undefined)
1083
+ params.change_protected = changeProtected;
1084
+ const response = await this.client.post(`/admin/embedding/config/${configId}/protect`, null, { params });
1085
+ return response.data;
1086
+ }
1087
+ /**
1088
+ * Delete an embedding configuration (admin endpoint)
1089
+ */
1090
+ async deleteEmbeddingConfig(configId) {
1091
+ const response = await this.client.delete(`/admin/embedding/config/${configId}`);
1092
+ return response.data;
1093
+ }
1094
+ /**
1095
+ * Activate an embedding configuration with automatic protection management (admin endpoint)
1096
+ */
1097
+ async activateEmbeddingConfig(configId, force) {
1098
+ const params = force ? { force: true } : {};
1099
+ const response = await this.client.post(`/admin/embedding/config/${configId}/activate`, null, { params });
1100
+ return response.data;
1101
+ }
1102
+ /**
1103
+ * Get current extraction configuration (public endpoint)
1104
+ */
1105
+ async getExtractionConfig() {
1106
+ const response = await this.client.get('/extraction/config');
1107
+ return response.data;
1108
+ }
1109
+ /**
1110
+ * Get detailed extraction configuration (admin endpoint)
1111
+ */
1112
+ async getExtractionConfigDetail() {
1113
+ const response = await this.client.get('/admin/extraction/config');
1114
+ return response.data;
1115
+ }
1116
+ /**
1117
+ * Update extraction configuration (admin endpoint)
1118
+ */
1119
+ async updateExtractionConfig(config) {
1120
+ const response = await this.client.post('/admin/extraction/config', config);
1121
+ return response.data;
1122
+ }
1123
+ /**
1124
+ * List API keys with validation status (admin endpoint)
1125
+ */
1126
+ async listApiKeys() {
1127
+ const response = await this.client.get('/admin/keys');
1128
+ return response.data;
1129
+ }
1130
+ /**
1131
+ * Set API key for a provider (admin endpoint)
1132
+ */
1133
+ async setApiKey(provider, apiKey) {
1134
+ const formData = new form_data_1.default();
1135
+ formData.append('api_key', apiKey);
1136
+ const response = await this.client.post(`/admin/keys/${provider}`, formData, {
1137
+ headers: {
1138
+ 'Content-Type': 'multipart/form-data'
1139
+ }
1140
+ });
1141
+ return response.data;
1142
+ }
1143
+ /**
1144
+ * Delete API key for a provider (admin endpoint)
1145
+ */
1146
+ async deleteApiKey(provider) {
1147
+ const response = await this.client.delete(`/admin/keys/${provider}`);
1148
+ return response.data;
1149
+ }
1150
+ /**
1151
+ * Get similar edge types via embedding similarity (ADR-053)
1152
+ */
1153
+ async getSimilarTypes(relationshipType, limit = 10, reverse = false) {
1154
+ const response = await this.client.get(`/vocabulary/similar/${encodeURIComponent(relationshipType)}`, { params: { limit, reverse } });
1155
+ return response.data;
1156
+ }
1157
+ /**
1158
+ * Get detailed vocabulary analysis (ADR-053)
1159
+ */
1160
+ async analyzeVocabularyType(relationshipType) {
1161
+ const response = await this.client.get(`/vocabulary/analyze/${encodeURIComponent(relationshipType)}`);
1162
+ return response.data;
1163
+ }
1164
+ /**
1165
+ * Analyze polarity axis between two concept poles (ADR-070)
1166
+ */
1167
+ async analyzePolarityAxis(request) {
1168
+ const response = await this.client.post('/query/polarity-axis', request);
1169
+ return response.data;
1170
+ }
1171
+ /**
1172
+ * Submit async polarity analysis job with artifact creation (ADR-083)
1173
+ */
1174
+ async submitPolarityJob(request) {
1175
+ const response = await this.client.post('/query/polarity-axis/jobs', request);
1176
+ return response.data;
1177
+ }
1178
+ // ============================================================================
1179
+ // Projection Methods (ADR-078)
1180
+ // ============================================================================
1181
+ /**
1182
+ * Get available projection algorithms
1183
+ */
1184
+ async getProjectionAlgorithms() {
1185
+ const response = await this.client.get('/projection/algorithms');
1186
+ return response.data;
1187
+ }
1188
+ /**
1189
+ * Get cached projection for an ontology
1190
+ */
1191
+ async getProjection(ontology) {
1192
+ const response = await this.client.get(`/projection/${encodeURIComponent(ontology)}`);
1193
+ return response.data;
1194
+ }
1195
+ /**
1196
+ * Regenerate projection for an ontology
1197
+ */
1198
+ async regenerateProjection(ontology, options) {
1199
+ const response = await this.client.post(`/projection/${encodeURIComponent(ontology)}/regenerate`, options || {});
1200
+ return response.data;
1201
+ }
1202
+ /**
1203
+ * Invalidate (delete) cached projection
1204
+ */
1205
+ async invalidateProjection(ontology) {
1206
+ const response = await this.client.delete(`/projection/${encodeURIComponent(ontology)}`);
1207
+ return response.data;
1208
+ }
1209
+ // ============================================================================
1210
+ // Artifact Methods (ADR-083)
1211
+ // ============================================================================
1212
+ /**
1213
+ * List artifacts with optional filtering
1214
+ */
1215
+ async listArtifacts(params) {
1216
+ const response = await this.client.get('/artifacts', { params });
1217
+ return response.data;
1218
+ }
1219
+ /**
1220
+ * Get artifact metadata by ID
1221
+ */
1222
+ async getArtifact(artifactId) {
1223
+ const response = await this.client.get(`/artifacts/${artifactId}`);
1224
+ return response.data;
1225
+ }
1226
+ /**
1227
+ * Get artifact with full payload
1228
+ */
1229
+ async getArtifactPayload(artifactId) {
1230
+ const response = await this.client.get(`/artifacts/${artifactId}/payload`);
1231
+ return response.data;
1232
+ }
1233
+ /**
1234
+ * Create a new artifact
1235
+ */
1236
+ async createArtifact(artifact) {
1237
+ const response = await this.client.post('/artifacts', artifact);
1238
+ return response.data;
1239
+ }
1240
+ /**
1241
+ * Delete an artifact
1242
+ */
1243
+ async deleteArtifact(artifactId) {
1244
+ await this.client.delete(`/artifacts/${artifactId}`);
1245
+ }
1246
+ // ==========================================================================
1247
+ // Groups & Grants Methods (ADR-082)
1248
+ // ==========================================================================
1249
+ /**
1250
+ * List groups
1251
+ */
1252
+ async listGroups(params) {
1253
+ const response = await this.client.get('/groups', { params });
1254
+ return response.data;
1255
+ }
1256
+ /**
1257
+ * Create a group
1258
+ */
1259
+ async createGroup(group) {
1260
+ const response = await this.client.post('/groups', group);
1261
+ return response.data;
1262
+ }
1263
+ /**
1264
+ * List group members
1265
+ */
1266
+ async listGroupMembers(groupId) {
1267
+ const response = await this.client.get(`/groups/${groupId}/members`);
1268
+ return response.data;
1269
+ }
1270
+ /**
1271
+ * Add member to group
1272
+ */
1273
+ async addGroupMember(groupId, userId) {
1274
+ const response = await this.client.post(`/groups/${groupId}/members`, { user_id: userId });
1275
+ return response.data;
1276
+ }
1277
+ /**
1278
+ * Remove member from group
1279
+ */
1280
+ async removeGroupMember(groupId, userId) {
1281
+ await this.client.delete(`/groups/${groupId}/members/${userId}`);
1282
+ }
1283
+ /**
1284
+ * Create a resource grant
1285
+ */
1286
+ async createGrant(grant) {
1287
+ const response = await this.client.post('/grants', grant);
1288
+ return response.data;
1289
+ }
1290
+ /**
1291
+ * List grants for a resource
1292
+ */
1293
+ async listResourceGrants(resourceType, resourceId) {
1294
+ const response = await this.client.get(`/resources/${resourceType}/${resourceId}/grants`);
1295
+ return response.data;
1296
+ }
1297
+ /**
1298
+ * Revoke a grant
1299
+ */
1300
+ async revokeGrant(grantId) {
1301
+ await this.client.delete(`/grants/${grantId}`);
1302
+ }
1303
+ // ==========================================================================
1304
+ // Query Definitions Methods (ADR-083)
1305
+ // ==========================================================================
1306
+ /**
1307
+ * List query definitions
1308
+ */
1309
+ async listQueryDefinitions(params) {
1310
+ const response = await this.client.get('/query-definitions', { params });
1311
+ return response.data;
1312
+ }
1313
+ /**
1314
+ * Get a query definition by ID
1315
+ */
1316
+ async getQueryDefinition(definitionId) {
1317
+ const response = await this.client.get(`/query-definitions/${definitionId}`);
1318
+ return response.data;
1319
+ }
1320
+ /**
1321
+ * Create a query definition
1322
+ */
1323
+ async createQueryDefinition(definition) {
1324
+ const response = await this.client.post('/query-definitions', definition);
1325
+ return response.data;
1326
+ }
1327
+ /**
1328
+ * Update a query definition
1329
+ */
1330
+ async updateQueryDefinition(definitionId, update) {
1331
+ const response = await this.client.put(`/query-definitions/${definitionId}`, update);
1332
+ return response.data;
1333
+ }
1334
+ /**
1335
+ * Delete a query definition
1336
+ */
1337
+ async deleteQueryDefinition(definitionId) {
1338
+ await this.client.delete(`/query-definitions/${definitionId}`);
1339
+ }
1340
+ }
1341
+ exports.KnowledgeGraphClient = KnowledgeGraphClient;
1342
+ /**
1343
+ * Create a client from environment variables and config file
1344
+ * Priority: CLI flags > env vars > config file > defaults
1345
+ */
1346
+ function createClientFromEnv() {
1347
+ // Lazy load config to avoid circular dependencies
1348
+ let config = null;
1349
+ try {
1350
+ const { getConfig } = require('../lib/config');
1351
+ config = getConfig();
1352
+ }
1353
+ catch (e) {
1354
+ // Config not available, use env vars only
1355
+ }
1356
+ return new KnowledgeGraphClient({
1357
+ baseUrl: process.env.KG_API_URL || config?.getApiUrl() || 'http://localhost:8000',
1358
+ clientId: process.env.KG_CLIENT_ID || config?.getClientId(),
1359
+ apiKey: process.env.KG_API_KEY || config?.getApiKey(),
1360
+ });
1361
+ }
1362
+ //# sourceMappingURL=client.js.map