@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,829 @@
1
+ "use strict";
2
+ /**
3
+ * Search and Query Commands
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.searchCommand = void 0;
40
+ const commander_1 = require("commander");
41
+ const client_1 = require("../api/client");
42
+ const colors = __importStar(require("./colors"));
43
+ const colors_1 = require("./colors");
44
+ const help_formatter_1 = require("./help-formatter");
45
+ const config_1 = require("../lib/config");
46
+ const terminal_images_1 = require("../lib/terminal-images");
47
+ const nodePath = __importStar(require("path"));
48
+ /**
49
+ * Format grounding strength for display (ADR-044)
50
+ * This is the fallback when grounding_display is not available.
51
+ */
52
+ function formatGroundingStrength(grounding) {
53
+ const groundingValue = grounding.toFixed(3);
54
+ const percentValue = grounding * 100;
55
+ // Use ā‰ˆ symbol when value is very close to zero but not exactly zero
56
+ const groundingPercent = (Math.abs(percentValue) < 0.1 && percentValue !== 0)
57
+ ? `ā‰ˆ${percentValue >= 0 ? '0' : '-0'}`
58
+ : percentValue.toFixed(0);
59
+ if (grounding >= 0.7) {
60
+ return colors.status.success(`āœ“ Strong (${groundingValue}, ${groundingPercent}%)`);
61
+ }
62
+ else if (grounding >= 0.3) {
63
+ return colors.status.warning(`⚔ Moderate (${groundingValue}, ${groundingPercent}%)`);
64
+ }
65
+ else if (grounding >= 0) {
66
+ return colors.status.dim(`ā—Æ Weak (${groundingValue}, ${groundingPercent}%)`);
67
+ }
68
+ else if (grounding >= -0.3) {
69
+ return colors.status.warning(`⚠ Negative (${groundingValue}, ${groundingPercent}%)`);
70
+ }
71
+ else {
72
+ return colors.status.error(`āœ— Contradicted (${groundingValue}, ${groundingPercent}%)`);
73
+ }
74
+ }
75
+ /**
76
+ * Format grounding with confidence-awareness (grounding Ɨ confidence two-dimensional model)
77
+ *
78
+ * Uses grounding_display when available (categorical label from API).
79
+ * Includes numeric confidence_score alongside the label for quantitative insight.
80
+ * Falls back to raw grounding score display for backwards compatibility.
81
+ *
82
+ * The grounding_display labels come from a 3Ɨ3 matrix:
83
+ * | Grounding Ɨ Confidence | Display |
84
+ * |------------------------|---------|
85
+ * | Positive + Confident | "Well-supported" |
86
+ * | Positive + Tentative | "Some support (limited data)" |
87
+ * | Positive + Insufficient| "Possibly supported (needs exploration)" |
88
+ * | Neutral + Confident | "Balanced perspectives" |
89
+ * | Neutral + Tentative | "Unclear" |
90
+ * | Neutral + Insufficient | "Unexplored" |
91
+ * | Negative + Confident | "Contested" |
92
+ * | Negative + Tentative | "Possibly contested" |
93
+ * | Negative + Insufficient| "Unknown (needs exploration)" |
94
+ */
95
+ function formatGroundingWithConfidence(grounding, groundingDisplay, confidenceLevel, confidenceScore = null) {
96
+ // Format confidence score as percentage if available
97
+ const confScoreStr = confidenceScore !== undefined && confidenceScore !== null
98
+ ? ` [${(confidenceScore * 100).toFixed(0)}% conf]`
99
+ : '';
100
+ // If we have a grounding_display label from the API, use it with appropriate styling
101
+ if (groundingDisplay) {
102
+ // Style based on the label content
103
+ if (groundingDisplay.includes('Well-supported')) {
104
+ return colors.status.success(`āœ“ ${groundingDisplay}`) + colors.status.dim(confScoreStr);
105
+ }
106
+ else if (groundingDisplay.includes('Contested')) {
107
+ return colors.status.error(`āœ— ${groundingDisplay}`) + colors.status.dim(confScoreStr);
108
+ }
109
+ else if (groundingDisplay.includes('Unexplored') || groundingDisplay.includes('Unknown')) {
110
+ return colors.status.dim(`ā—Æ ${groundingDisplay}${confScoreStr}`);
111
+ }
112
+ else if (groundingDisplay.includes('limited data') || groundingDisplay.includes('needs exploration')) {
113
+ return colors.status.warning(`⚔ ${groundingDisplay}`) + colors.status.dim(confScoreStr);
114
+ }
115
+ else if (groundingDisplay.includes('Balanced')) {
116
+ return colors.status.dim(`◐ ${groundingDisplay}${confScoreStr}`);
117
+ }
118
+ else {
119
+ // Default styling for other labels
120
+ return colors.status.dim(`ā—Æ ${groundingDisplay}${confScoreStr}`);
121
+ }
122
+ }
123
+ // Fall back to raw grounding score display if available
124
+ if (grounding !== undefined && grounding !== null) {
125
+ return formatGroundingStrength(grounding);
126
+ }
127
+ // No grounding information available
128
+ return colors.status.dim('ā—Æ Unexplored');
129
+ }
130
+ /**
131
+ * Format diversity score for display (ADR-063)
132
+ */
133
+ function formatDiversity(diversity, relatedCount) {
134
+ const diversityPercent = (diversity * 100).toFixed(1);
135
+ if (diversity > 0.6) {
136
+ return colors.status.success(`🌐 Very High (${diversityPercent}%, ${relatedCount} concepts)`);
137
+ }
138
+ else if (diversity > 0.4) {
139
+ return colors.status.success(`🌐 High (${diversityPercent}%, ${relatedCount} concepts)`);
140
+ }
141
+ else if (diversity > 0.2) {
142
+ return colors.status.warning(`◐ Moderate (${diversityPercent}%, ${relatedCount} concepts)`);
143
+ }
144
+ else if (diversity > 0.1) {
145
+ return colors.status.dim(`ā—‘ Low (${diversityPercent}%, ${relatedCount} concepts)`);
146
+ }
147
+ else {
148
+ return colors.status.error(`ā—Æ Very Low (${diversityPercent}%, ${relatedCount} concepts)`);
149
+ }
150
+ }
151
+ /**
152
+ * Format authenticated diversity for display (ADR-044 + ADR-063)
153
+ */
154
+ function formatAuthenticatedDiversity(authDiv) {
155
+ const percent = (Math.abs(authDiv) * 100).toFixed(1);
156
+ if (authDiv > 0.3) {
157
+ return colors.status.success(`āœ… +${percent}% (diverse support)`);
158
+ }
159
+ else if (authDiv > 0) {
160
+ return colors.status.dim(`āœ“ +${percent}% (some support)`);
161
+ }
162
+ else if (authDiv > -0.3) {
163
+ return colors.status.warning(`⚠ ${percent}% (weak contradiction)`);
164
+ }
165
+ else {
166
+ return colors.status.error(`āŒ ${percent}% (diverse contradiction)`);
167
+ }
168
+ }
169
+ const queryCommand = (0, help_formatter_1.setCommandHelp)(new commander_1.Command('query'), 'Search concepts by semantic similarity', 'Search for concepts using vector similarity (embeddings) - use specific phrases for best results')
170
+ .showHelpAfterError()
171
+ .argument('<query>', 'Natural language search query (2-3 words work best)')
172
+ .option('-l, --limit <number>', 'Maximum number of results to return', '10')
173
+ .option('--min-similarity <number>', 'Minimum similarity score (0.0-1.0, default 0.7=70%, lower to 0.5 for broader matches)', '0.7')
174
+ .option('--no-evidence', 'Hide evidence quotes (shown by default)')
175
+ .option('--no-images', 'Hide inline image display (shown by default if chafa installed)')
176
+ .option('--no-grounding', 'Disable grounding strength calculation (ADR-044 probabilistic truth convergence) for faster results')
177
+ .option('--no-diversity', 'Disable semantic diversity calculation (ADR-063 authenticity signal) for faster results')
178
+ .option('--diversity-hops <number>', 'Maximum traversal depth for diversity (1-3, default 2)', '2')
179
+ .option('--download <directory>', 'Download images to specified directory instead of displaying inline')
180
+ .option('--json', 'Output raw JSON instead of formatted text for scripting')
181
+ .option('--save-artifact', 'Save result as persistent artifact (ADR-083)')
182
+ .action(async (query, options) => {
183
+ try {
184
+ const client = (0, client_1.createClientFromEnv)();
185
+ const config = (0, config_1.getConfig)();
186
+ // Use config defaults, allow CLI flags to override
187
+ // Commander.js --no-evidence flag sets options.evidence to false
188
+ const includeEvidence = options.evidence !== undefined ? options.evidence : config.getSearchShowEvidence();
189
+ const shouldShowImages = options.images !== undefined ? options.images : config.getSearchShowImages();
190
+ const includeGrounding = options.grounding !== false; // Default: true
191
+ const includeDiversity = options.diversity !== false; // Default: true
192
+ const result = await client.searchConcepts({
193
+ query,
194
+ limit: parseInt(options.limit),
195
+ min_similarity: parseFloat(options.minSimilarity),
196
+ include_evidence: includeEvidence,
197
+ include_grounding: includeGrounding,
198
+ include_diversity: includeDiversity,
199
+ diversity_max_hops: parseInt(options.diversityHops)
200
+ });
201
+ // JSON output mode
202
+ if (options.json) {
203
+ console.log(JSON.stringify(result, null, 2));
204
+ return;
205
+ }
206
+ console.log('\n' + (0, colors_1.separator)());
207
+ console.log(colors.ui.title(`šŸ” Searching for: ${query}`));
208
+ console.log((0, colors_1.separator)());
209
+ console.log(colors.status.success(`\nāœ“ Found ${result.count} concepts:\n`));
210
+ for (const [i, concept] of result.results.entries()) {
211
+ const scoreColor = (0, colors_1.getConceptColor)(concept.score);
212
+ console.log(colors.ui.bullet('ā—') + ' ' + colors.concept.label(`${i + 1}. ${concept.label}`));
213
+ if (concept.description) {
214
+ console.log(` ${colors.status.dim(concept.description)}`);
215
+ }
216
+ console.log(` ${colors.ui.key('ID:')} ${colors.concept.id(concept.concept_id)}`);
217
+ console.log(` ${colors.ui.key('Similarity:')} ${(0, colors_1.coloredPercentage)(concept.score)}`);
218
+ console.log(` ${colors.ui.key('Documents:')} ${colors.evidence.document(concept.documents.join(', '))}`);
219
+ console.log(` ${colors.ui.key('Evidence:')} ${colors.evidence.count(String(concept.evidence_count))} instances`);
220
+ // Display grounding with confidence-awareness (ADR-044 + grounding Ɨ confidence model)
221
+ if (concept.grounding_strength !== undefined || concept.grounding_display) {
222
+ console.log(` ${colors.ui.key('Grounding:')} ${formatGroundingWithConfidence(concept.grounding_strength, concept.grounding_display, concept.confidence_level, concept.confidence_score)}`);
223
+ }
224
+ // Display diversity if available (ADR-063)
225
+ if (concept.diversity_score !== undefined && concept.diversity_score !== null && concept.diversity_related_count !== undefined) {
226
+ console.log(` ${colors.ui.key('Diversity:')} ${formatDiversity(concept.diversity_score, concept.diversity_related_count)}`);
227
+ }
228
+ // Display authenticated diversity if available (ADR-044 + ADR-063)
229
+ if (concept.authenticated_diversity !== undefined && concept.authenticated_diversity !== null) {
230
+ console.log(` ${colors.ui.key('Authenticated:')} ${formatAuthenticatedDiversity(concept.authenticated_diversity)}`);
231
+ }
232
+ // Display sample evidence if requested
233
+ if (includeEvidence && concept.sample_evidence && concept.sample_evidence.length > 0) {
234
+ console.log(` ${colors.ui.key('Sample Evidence:')}`);
235
+ for (const [idx, inst] of concept.sample_evidence.entries()) {
236
+ const truncatedQuote = inst.quote.length > 100
237
+ ? inst.quote.substring(0, 100) + '...'
238
+ : inst.quote;
239
+ console.log(` ${colors.ui.bullet(`${idx + 1}.`)} ${colors.evidence.document(inst.document)} ${colors.evidence.paragraph(`(para ${inst.paragraph})`)}`);
240
+ console.log(` ${colors.evidence.quote(`"${truncatedQuote}"`)}`);
241
+ // ADR-057: Handle images if available
242
+ if (inst.has_image && inst.source_id) {
243
+ const downloadDir = options.download;
244
+ if (downloadDir) {
245
+ // Download mode
246
+ try {
247
+ console.log(colors.status.dim(` šŸ“„ Downloading image from ${inst.source_id}...`));
248
+ const imageBuffer = await client.getSourceImage(inst.source_id);
249
+ const extension = (0, terminal_images_1.detectImageFormat)(imageBuffer);
250
+ const filename = `${inst.source_id}${extension}`;
251
+ const outputPath = nodePath.join(downloadDir, filename);
252
+ if ((0, terminal_images_1.saveImageToFile)(imageBuffer, outputPath)) {
253
+ console.log(colors.status.success(` āœ“ Saved to ${outputPath}`));
254
+ }
255
+ }
256
+ catch (error) {
257
+ console.log(colors.status.error(` āœ— Failed to download image: ${error.message}`));
258
+ }
259
+ }
260
+ else if (shouldShowImages && config.isChafaEnabled()) {
261
+ // Display mode
262
+ if ((0, terminal_images_1.isChafaAvailable)()) {
263
+ try {
264
+ console.log(colors.status.dim(` šŸ–¼ļø Displaying image from ${inst.source_id}...`));
265
+ const imageBuffer = await client.getSourceImage(inst.source_id);
266
+ const extension = (0, terminal_images_1.detectImageFormat)(imageBuffer);
267
+ await (0, terminal_images_1.displayImageBufferWithChafa)(imageBuffer, extension, {
268
+ width: config.getChafaWidth(),
269
+ scale: config.getChafaScale(),
270
+ align: config.getChafaAlign(),
271
+ colors: config.getChafaColors()
272
+ });
273
+ }
274
+ catch (error) {
275
+ console.log(colors.status.error(` āœ— Failed to display image: ${error.message}`));
276
+ }
277
+ }
278
+ else {
279
+ console.log(colors.status.warning(` šŸ–¼ļø Image available (source: ${inst.source_id})`));
280
+ (0, terminal_images_1.printChafaInstallInstructions)();
281
+ }
282
+ }
283
+ else {
284
+ // Just indicate image is available
285
+ console.log(colors.status.dim(` šŸ–¼ļø Image available (use --show-images to display or --download <dir> to save)`));
286
+ }
287
+ }
288
+ }
289
+ }
290
+ console.log();
291
+ }
292
+ // Show hint if additional results available below threshold
293
+ if (result.below_threshold_count && result.below_threshold_count > 0 && result.suggested_threshold) {
294
+ const thresholdPercent = (result.suggested_threshold * 100).toFixed(0);
295
+ console.log(colors.status.warning(`šŸ’” ${result.below_threshold_count} additional concept${result.below_threshold_count > 1 ? 's' : ''} available at ${thresholdPercent}% threshold`));
296
+ console.log(colors.status.dim(` Try: kg search query "${query}" --min-similarity ${result.suggested_threshold}\n`));
297
+ }
298
+ // ADR-083: Save result as artifact if requested
299
+ if (options.saveArtifact && result.count > 0) {
300
+ try {
301
+ const artifactResult = await client.createArtifact({
302
+ artifact_type: 'search_result',
303
+ representation: 'cli',
304
+ name: `Search: "${query}" (${result.count} results)`,
305
+ parameters: {
306
+ query,
307
+ limit: parseInt(options.limit),
308
+ min_similarity: parseFloat(options.minSimilarity),
309
+ include_evidence: includeEvidence,
310
+ include_grounding: includeGrounding,
311
+ include_diversity: includeDiversity,
312
+ diversity_max_hops: parseInt(options.diversityHops)
313
+ },
314
+ payload: result
315
+ });
316
+ console.log(colors.status.success(`āœ“ Artifact saved: ${artifactResult.id}`));
317
+ console.log(colors.status.dim(` View: kg artifact show ${artifactResult.id}`));
318
+ }
319
+ catch (artifactError) {
320
+ console.error(colors.status.error(`āœ— Failed to save artifact: ${artifactError.message}`));
321
+ }
322
+ }
323
+ }
324
+ catch (error) {
325
+ console.error(colors.status.error('āœ— Search failed'));
326
+ console.error(colors.status.error(error.response?.data?.detail || error.message));
327
+ process.exit(1);
328
+ }
329
+ });
330
+ const showCommand = (0, help_formatter_1.setCommandHelp)(new commander_1.Command('show'), 'Get full details for a concept', 'Get comprehensive details for a concept: all evidence, relationships, sources, and grounding strength')
331
+ .alias('details') // backwards compatibility
332
+ .showHelpAfterError()
333
+ .argument('<concept-id>', 'Concept ID to retrieve (from search results)')
334
+ .option('--no-grounding', 'Disable grounding strength calculation (ADR-044 probabilistic truth convergence) for faster results')
335
+ .option('--json', 'Output raw JSON instead of formatted text for scripting')
336
+ .action(async (conceptId, options) => {
337
+ try {
338
+ const client = (0, client_1.createClientFromEnv)();
339
+ const includeGrounding = options.grounding !== false; // Default: true
340
+ const concept = await client.getConceptDetails(conceptId, includeGrounding);
341
+ // JSON output mode
342
+ if (options.json) {
343
+ console.log(JSON.stringify(concept, null, 2));
344
+ return;
345
+ }
346
+ console.log('\n' + (0, colors_1.separator)());
347
+ console.log(colors.ui.title(`šŸ“Š Concept Details: ${concept.label}`));
348
+ console.log((0, colors_1.separator)());
349
+ console.log(`\n${colors.ui.key('ID:')} ${colors.concept.id(concept.concept_id)}`);
350
+ if (concept.description) {
351
+ console.log(`${colors.ui.key('Description:')} ${colors.status.dim(concept.description)}`);
352
+ }
353
+ console.log(`${colors.ui.key('Search Terms:')} ${colors.concept.searchTerms(concept.search_terms.join(', '))}`);
354
+ console.log(`${colors.ui.key('Documents:')} ${colors.evidence.document(concept.documents.join(', '))}`);
355
+ // Display grounding with confidence-awareness (ADR-044 + grounding Ɨ confidence model)
356
+ if (concept.grounding_strength !== undefined || concept.grounding_display) {
357
+ console.log(`${colors.ui.key('Grounding:')} ${formatGroundingWithConfidence(concept.grounding_strength, concept.grounding_display, concept.confidence_level, concept.confidence_score)}`);
358
+ }
359
+ console.log('\n' + colors.ui.header(`Evidence (${concept.instances.length} instances)`));
360
+ console.log((0, colors_1.separator)(80, '─'));
361
+ concept.instances.forEach((inst, i) => {
362
+ console.log(`\n${colors.ui.bullet(`${i + 1}.`)} ${colors.evidence.document(inst.document)} ${colors.evidence.paragraph(`(para ${inst.paragraph})`)}`);
363
+ console.log(` ${colors.evidence.quote(`"${inst.quote}"`)}`);
364
+ });
365
+ if (concept.relationships.length > 0) {
366
+ console.log('\n' + colors.ui.header(`Relationships (${concept.relationships.length})`));
367
+ console.log((0, colors_1.separator)(80, '─'));
368
+ concept.relationships.forEach(rel => {
369
+ const relColor = (0, colors_1.getRelationshipColor)(rel.rel_type);
370
+ const confidence = rel.confidence ? ` ${colors.status.dim(`[${(rel.confidence * 100).toFixed(0)}%]`)}` : '';
371
+ console.log(` ${colors.path.arrow('→')} ${relColor(rel.rel_type)} ${colors.path.arrow('→')} ${colors.concept.label(rel.to_label)} ${colors.concept.id(`(${rel.to_id})`)}${confidence}`);
372
+ });
373
+ }
374
+ else {
375
+ console.log('\n' + colors.status.warning('⚠ No outgoing relationships'));
376
+ }
377
+ console.log();
378
+ }
379
+ catch (error) {
380
+ console.error(colors.status.error('āœ— Failed to get concept details'));
381
+ console.error(colors.status.error(error.response?.data?.detail || error.message));
382
+ process.exit(1);
383
+ }
384
+ });
385
+ const relatedCommand = (0, help_formatter_1.setCommandHelp)(new commander_1.Command('related'), 'Find related concepts by graph traversal', 'Find concepts related through graph traversal (breadth-first search) - groups results by distance')
386
+ .showHelpAfterError()
387
+ .argument('<concept-id>', 'Starting concept ID for traversal')
388
+ .option('-d, --depth <number>', 'Maximum traversal depth in hops (1-2 fast, 3-4 moderate, 5 slow)', '2')
389
+ .option('-t, --types <types...>', 'Filter by relationship types (IMPLIES, ENABLES, SUPPORTS, etc. - see kg vocab list)')
390
+ .option('--include-epistemic <statuses...>', 'Only include relationships with these epistemic statuses (ADR-065): AFFIRMATIVE, CONTESTED, CONTRADICTORY, HISTORICAL')
391
+ .option('--exclude-epistemic <statuses...>', 'Exclude relationships with these epistemic statuses (ADR-065)')
392
+ .option('--json', 'Output raw JSON instead of formatted text for scripting')
393
+ .action(async (conceptId, options) => {
394
+ try {
395
+ const client = (0, client_1.createClientFromEnv)();
396
+ const result = await client.findRelatedConcepts({
397
+ concept_id: conceptId,
398
+ max_depth: parseInt(options.depth),
399
+ relationship_types: options.types,
400
+ // ADR-065: Epistemic status filtering
401
+ include_epistemic_status: options.includeEpistemic,
402
+ exclude_epistemic_status: options.excludeEpistemic
403
+ });
404
+ // JSON output mode
405
+ if (options.json) {
406
+ console.log(JSON.stringify(result, null, 2));
407
+ return;
408
+ }
409
+ console.log('\n' + (0, colors_1.separator)());
410
+ console.log(colors.ui.title(`šŸ”— Related Concepts from: ${conceptId}`));
411
+ console.log(`${colors.ui.key('Max depth:')} ${colors.path.distance(String(result.max_depth))}`);
412
+ console.log((0, colors_1.separator)());
413
+ console.log(colors.status.success(`\nāœ“ Found ${result.count} related concepts:\n`));
414
+ let currentDistance = -1;
415
+ result.results.forEach(concept => {
416
+ if (concept.distance !== currentDistance) {
417
+ currentDistance = concept.distance;
418
+ console.log('\n' + colors.path.distance(`Distance ${currentDistance}:`));
419
+ }
420
+ console.log(` ${colors.ui.bullet('ā—')} ${colors.concept.label(concept.label)} ${colors.concept.id(`(${concept.concept_id})`)}`);
421
+ // Color-code the path by relationship types
422
+ const coloredPath = concept.path_types.map(type => (0, colors_1.getRelationshipColor)(type)(type)).join(colors.path.arrow(' → '));
423
+ console.log(` ${colors.ui.key('Path:')} ${coloredPath}`);
424
+ });
425
+ console.log();
426
+ }
427
+ catch (error) {
428
+ console.error(colors.status.error('āœ— Failed to find related concepts'));
429
+ console.error(colors.status.error(error.response?.data?.detail || error.message));
430
+ process.exit(1);
431
+ }
432
+ });
433
+ const connectCommand = (0, help_formatter_1.setCommandHelp)(new commander_1.Command('connect'), 'Find paths between two concepts', 'Find shortest path between two concepts using IDs or semantic phrase matching')
434
+ .showHelpAfterError()
435
+ .argument('<from>', 'Starting concept (exact ID or descriptive phrase - e.g., "licensing issues" not "licensing")')
436
+ .argument('<to>', 'Target concept (exact ID or descriptive phrase - use 2-3 word phrases for best results)')
437
+ .option('--max-hops <number>', 'Maximum path length', '5')
438
+ .option('--min-similarity <number>', 'Semantic similarity threshold for phrase matching (default 50% - lower for broader matches)', '0.5')
439
+ .option('--no-evidence', 'Hide evidence quotes (shown by default)')
440
+ .option('--no-images', 'Hide inline image display (shown by default if chafa installed)')
441
+ .option('--no-grounding', 'Disable grounding strength calculation (faster)')
442
+ .option('--download <directory>', 'Download images to specified directory instead of displaying inline')
443
+ .option('--json', 'Output raw JSON instead of formatted text')
444
+ .option('--include-epistemic <statuses...>', 'Only include relationships with these epistemic statuses (ADR-065): AFFIRMATIVE, CONTESTED, CONTRADICTORY, HISTORICAL')
445
+ .option('--exclude-epistemic <statuses...>', 'Exclude relationships with these epistemic statuses (ADR-065)')
446
+ .addHelpText('after', `
447
+ Examples:
448
+ $ kg search connect concept-id-123 concept-id-456
449
+ $ kg search connect "licensing issues" "AGE benefits"
450
+ $ kg search connect "Apache AGE" "graph database" --min-similarity 0.3
451
+ $ kg search connect "my concept" "another concept" --show-evidence
452
+ $ kg search connect "concept-a" "concept-b" --include-epistemic AFFIRMATIVE
453
+ $ kg search connect "concept-a" "concept-b" --exclude-epistemic HISTORICAL INSUFFICIENT_DATA
454
+
455
+ Notes:
456
+ - Generic single words ("features", "issues") may not match well
457
+ - Use specific 2-3 word phrases for better semantic matching
458
+ - Lower --min-similarity (e.g., 0.3) to find weaker concept matches
459
+ - Error messages suggest threshold adjustments when near-misses exist
460
+ - Use --include-epistemic to filter by relationship confidence level (ADR-065)
461
+ `)
462
+ .action(async (from, to, options) => {
463
+ try {
464
+ const client = (0, client_1.createClientFromEnv)();
465
+ const config = (0, config_1.getConfig)();
466
+ // Use config defaults, allow CLI flags to override
467
+ const includeEvidence = options.evidence !== undefined ? options.evidence : config.getSearchShowEvidence();
468
+ const shouldShowImages = options.images !== undefined ? options.images : config.getSearchShowImages();
469
+ const includeGrounding = options.grounding !== false; // Default: true
470
+ // Auto-detect if using concept IDs (contain hyphens/underscores) or natural language
471
+ const isFromId = from.includes('-') || from.includes('_');
472
+ const isToId = to.includes('-') || to.includes('_');
473
+ let result;
474
+ let fromLabel = from;
475
+ let toLabel = to;
476
+ if (isFromId && isToId) {
477
+ // Both are concept IDs - use ID-based search
478
+ result = await client.findConnection({
479
+ from_id: from,
480
+ to_id: to,
481
+ max_hops: parseInt(options.maxHops),
482
+ include_evidence: includeEvidence,
483
+ include_grounding: includeGrounding,
484
+ // ADR-065: Epistemic status filtering
485
+ include_epistemic_status: options.includeEpistemic,
486
+ exclude_epistemic_status: options.excludeEpistemic
487
+ });
488
+ }
489
+ else {
490
+ // At least one is a natural language query - use search-based
491
+ result = await client.findConnectionBySearch({
492
+ from_query: from,
493
+ to_query: to,
494
+ max_hops: parseInt(options.maxHops),
495
+ threshold: parseFloat(options.minSimilarity),
496
+ include_evidence: includeEvidence,
497
+ include_grounding: includeGrounding,
498
+ // ADR-065: Epistemic status filtering
499
+ include_epistemic_status: options.includeEpistemic,
500
+ exclude_epistemic_status: options.excludeEpistemic
501
+ });
502
+ // Update labels with matched concepts
503
+ if (result.from_concept) {
504
+ fromLabel = `${result.from_concept.label} (matched: "${from}")`;
505
+ }
506
+ if (result.to_concept) {
507
+ toLabel = `${result.to_concept.label} (matched: "${to}")`;
508
+ }
509
+ }
510
+ // JSON output mode
511
+ if (options.json) {
512
+ console.log(JSON.stringify(result, null, 2));
513
+ return;
514
+ }
515
+ console.log('\n' + (0, colors_1.separator)());
516
+ console.log(colors.ui.title('šŸŒ‰ Finding Connection'));
517
+ console.log((0, colors_1.separator)());
518
+ console.log(` ${colors.ui.key('From:')} ${colors.concept.label(fromLabel)}`);
519
+ if ('from_similarity' in result && result.from_similarity) {
520
+ console.log(` ${colors.ui.key('Match:')} ${(0, colors_1.coloredPercentage)(result.from_similarity)}`);
521
+ }
522
+ console.log(` ${colors.ui.key('To:')} ${colors.concept.label(toLabel)}`);
523
+ if ('to_similarity' in result && result.to_similarity) {
524
+ console.log(` ${colors.ui.key('Match:')} ${(0, colors_1.coloredPercentage)(result.to_similarity)}`);
525
+ }
526
+ console.log(` ${colors.ui.key('Max hops:')} ${colors.path.hop(String(result.max_hops))}\n`);
527
+ if (result.count === 0) {
528
+ console.log(colors.status.warning(`⚠ No connection found within ${result.max_hops} hops`));
529
+ }
530
+ else {
531
+ console.log(colors.status.success(`āœ“ Found ${result.count} path(s):\n`));
532
+ for (const [i, path] of result.paths.entries()) {
533
+ console.log(colors.path.distance(`Path ${i + 1}`) + colors.status.dim(` (${path.hops} hops):`));
534
+ for (const [j, node] of path.nodes.entries()) {
535
+ console.log(` ${colors.path.node(node.label)} ${colors.concept.id(`(${node.id})`)}`);
536
+ if (node.description) {
537
+ console.log(` ${colors.status.dim(node.description)}`);
538
+ }
539
+ // Display grounding with confidence-awareness (ADR-044 + grounding Ɨ confidence model)
540
+ if (includeGrounding && (node.grounding_strength !== undefined || node.grounding_display)) {
541
+ console.log(` ${colors.ui.key('Grounding:')} ${formatGroundingWithConfidence(node.grounding_strength, node.grounding_display, node.confidence_level, node.confidence_score)}`);
542
+ }
543
+ // Display sample evidence if requested
544
+ if (includeEvidence && node.sample_evidence && node.sample_evidence.length > 0) {
545
+ console.log(` ${colors.ui.key('Evidence:')}`);
546
+ for (const [idx, inst] of node.sample_evidence.entries()) {
547
+ const truncatedQuote = inst.quote.length > 80
548
+ ? inst.quote.substring(0, 80) + '...'
549
+ : inst.quote;
550
+ console.log(` ${colors.ui.bullet(`${idx + 1}.`)} ${colors.evidence.document(inst.document)} ${colors.evidence.paragraph(`(para ${inst.paragraph})`)}`);
551
+ console.log(` ${colors.evidence.quote(`"${truncatedQuote}"`)}`);
552
+ // ADR-057: Handle images if available
553
+ if (inst.has_image && inst.source_id) {
554
+ const downloadDir = options.download;
555
+ if (downloadDir) {
556
+ // Download mode
557
+ try {
558
+ console.log(colors.status.dim(` šŸ“„ Downloading image from ${inst.source_id}...`));
559
+ const imageBuffer = await client.getSourceImage(inst.source_id);
560
+ const extension = (0, terminal_images_1.detectImageFormat)(imageBuffer);
561
+ const filename = `${inst.source_id}${extension}`;
562
+ const outputPath = nodePath.join(downloadDir, filename);
563
+ if ((0, terminal_images_1.saveImageToFile)(imageBuffer, outputPath)) {
564
+ console.log(colors.status.success(` āœ“ Saved to ${outputPath}`));
565
+ }
566
+ }
567
+ catch (error) {
568
+ console.log(colors.status.error(` āœ— Failed to download image: ${error.message}`));
569
+ }
570
+ }
571
+ else if (shouldShowImages && config.isChafaEnabled()) {
572
+ // Display mode
573
+ if ((0, terminal_images_1.isChafaAvailable)()) {
574
+ try {
575
+ console.log(colors.status.dim(` šŸ–¼ļø Displaying image from ${inst.source_id}...`));
576
+ const imageBuffer = await client.getSourceImage(inst.source_id);
577
+ const extension = (0, terminal_images_1.detectImageFormat)(imageBuffer);
578
+ await (0, terminal_images_1.displayImageBufferWithChafa)(imageBuffer, extension, {
579
+ width: config.getChafaWidth(),
580
+ scale: config.getChafaScale(),
581
+ align: config.getChafaAlign(),
582
+ colors: config.getChafaColors()
583
+ });
584
+ }
585
+ catch (error) {
586
+ console.log(colors.status.error(` āœ— Failed to display image: ${error.message}`));
587
+ }
588
+ }
589
+ else {
590
+ console.log(colors.status.warning(` šŸ–¼ļø Image available (source: ${inst.source_id})`));
591
+ (0, terminal_images_1.printChafaInstallInstructions)();
592
+ }
593
+ }
594
+ else {
595
+ // Just indicate image is available
596
+ console.log(colors.status.dim(` šŸ–¼ļø Image available (use --show-images to display or --download <dir> to save)`));
597
+ }
598
+ }
599
+ }
600
+ }
601
+ if (j < path.relationships.length) {
602
+ const relType = path.relationships[j];
603
+ const relColor = (0, colors_1.getRelationshipColor)(relType);
604
+ console.log(` ${colors.path.arrow('↓')} ${relColor(relType)}`);
605
+ }
606
+ }
607
+ console.log();
608
+ }
609
+ }
610
+ console.log((0, colors_1.separator)());
611
+ }
612
+ catch (error) {
613
+ console.error(colors.status.error('āœ— Failed to find connection'));
614
+ console.error(colors.status.error(error.response?.data?.detail || error.message));
615
+ process.exit(1);
616
+ }
617
+ });
618
+ const sourcesCommand = (0, help_formatter_1.setCommandHelp)(new commander_1.Command('sources'), 'Search source text by semantic similarity', 'Search source documents directly using embeddings - returns matched text with related concepts (ADR-068)')
619
+ .showHelpAfterError()
620
+ .argument('<query>', 'Search query text (searches source embeddings, not concept embeddings)')
621
+ .option('-l, --limit <number>', 'Maximum number of sources to return', '10')
622
+ .option('--min-similarity <number>', 'Minimum similarity score (0.0-1.0, default 0.7)', '0.7')
623
+ .option('-o, --ontology <name>', 'Filter by ontology/document name')
624
+ .option('--no-concepts', 'Hide concepts extracted from matched sources (shown by default)')
625
+ .option('--no-full-text', 'Hide full source text (shown by default)')
626
+ .option('--json', 'Output raw JSON instead of formatted text for scripting')
627
+ .action(async (query, options) => {
628
+ try {
629
+ const client = (0, client_1.createClientFromEnv)();
630
+ const includeConcepts = options.concepts !== false; // Default: true
631
+ const includeFullText = options.fullText !== false; // Default: true
632
+ const result = await client.searchSources({
633
+ query,
634
+ limit: parseInt(options.limit),
635
+ min_similarity: parseFloat(options.minSimilarity),
636
+ ontology: options.ontology,
637
+ include_concepts: includeConcepts,
638
+ include_full_text: includeFullText
639
+ });
640
+ // JSON output mode
641
+ if (options.json) {
642
+ console.log(JSON.stringify(result, null, 2));
643
+ return;
644
+ }
645
+ console.log('\n' + (0, colors_1.separator)());
646
+ console.log(colors.ui.title(`šŸ“„ Source Search: ${query}`));
647
+ console.log((0, colors_1.separator)());
648
+ console.log(colors.status.success(`\nāœ“ Found ${result.count} source(s):\n`));
649
+ for (const [i, source] of result.results.entries()) {
650
+ console.log(colors.ui.bullet('ā—') + ' ' + colors.concept.label(`${i + 1}. ${source.document} (para ${source.paragraph})`));
651
+ console.log(` ${colors.ui.key('Source ID:')} ${colors.concept.id(source.source_id)}`);
652
+ console.log(` ${colors.ui.key('Similarity:')} ${(0, colors_1.coloredPercentage)(source.similarity)}`);
653
+ if (source.is_stale) {
654
+ console.log(` ${colors.status.warning('⚠ Stale embedding (source text changed)')}`);
655
+ }
656
+ // Display matched chunk
657
+ console.log(` ${colors.ui.key('Matched chunk:')} ${colors.evidence.paragraph(`[${source.matched_chunk.start_offset}:${source.matched_chunk.end_offset}]`)}`);
658
+ const truncatedChunk = source.matched_chunk.chunk_text.length > 150
659
+ ? source.matched_chunk.chunk_text.substring(0, 150) + '...'
660
+ : source.matched_chunk.chunk_text;
661
+ console.log(` ${colors.evidence.quote(`"${truncatedChunk}"`)}`);
662
+ // Display full text if requested
663
+ if (includeFullText && source.full_text) {
664
+ console.log(` ${colors.ui.key('Full text:')}`);
665
+ const truncatedText = source.full_text.length > 200
666
+ ? source.full_text.substring(0, 200) + '...'
667
+ : source.full_text;
668
+ console.log(` ${colors.status.dim(truncatedText)}`);
669
+ }
670
+ // Display concepts extracted from this source
671
+ if (includeConcepts && source.concepts && source.concepts.length > 0) {
672
+ console.log(` ${colors.ui.key('Concepts:')} ${colors.status.dim(`(${source.concepts.length} extracted)`)}`);
673
+ for (const concept of source.concepts.slice(0, 5)) { // Show max 5 concepts
674
+ console.log(` ${colors.ui.bullet('→')} ${colors.concept.label(concept.label)} ${colors.concept.id(`(${concept.concept_id})`)}`);
675
+ if (concept.description) {
676
+ console.log(` ${colors.status.dim(concept.description)}`);
677
+ }
678
+ }
679
+ if (source.concepts.length > 5) {
680
+ console.log(` ${colors.status.dim(`... and ${source.concepts.length - 5} more`)}`);
681
+ }
682
+ }
683
+ console.log();
684
+ }
685
+ }
686
+ catch (error) {
687
+ console.error(colors.status.error('\nāœ— Source search failed'));
688
+ if (error.response) {
689
+ // API returned error response
690
+ const status = error.response.status;
691
+ const detail = error.response.data?.detail || 'Unknown error';
692
+ console.error(colors.status.warning(`\nAPI Error (${status}): ${detail}`));
693
+ if (status === 500 && detail.includes('embedding')) {
694
+ console.error(colors.status.dim('\nšŸ’” Suggestion: Check embedding provider configuration:'));
695
+ console.error(colors.status.dim(' kg admin embedding list'));
696
+ }
697
+ else if (status === 404) {
698
+ console.error(colors.status.dim('\nšŸ’” Suggestion: Verify API endpoint exists (may need to update CLI)'));
699
+ }
700
+ else if (status === 401 || status === 403) {
701
+ console.error(colors.status.dim('\nšŸ’” Suggestion: Check authentication:'));
702
+ console.error(colors.status.dim(' kg login'));
703
+ }
704
+ }
705
+ else if (error.request) {
706
+ // No response received
707
+ console.error(colors.status.warning('\nNo response from API server'));
708
+ console.error(colors.status.dim('\nšŸ’” Suggestion: Check API is running:'));
709
+ console.error(colors.status.dim(' kg health'));
710
+ }
711
+ else {
712
+ // Request setup error
713
+ console.error(colors.status.warning(`\n${error.message}`));
714
+ }
715
+ process.exit(1);
716
+ }
717
+ });
718
+ // Configure colored help for all search subcommands
719
+ [queryCommand, showCommand, relatedCommand, connectCommand, sourcesCommand].forEach(help_formatter_1.configureColoredHelp);
720
+ exports.searchCommand = (0, help_formatter_1.setCommandHelp)(new commander_1.Command('search'), 'Search and explore the knowledge graph', 'Search and explore the knowledge graph using vector similarity, graph traversal, and path finding')
721
+ .showHelpAfterError('(add --help for additional information)')
722
+ .showSuggestionAfterError()
723
+ // Allow direct search: kg search <term> (shortcut for kg search query <term>)
724
+ .argument('[query]', 'Search query (shortcut for: kg search query <term>)')
725
+ .option('-l, --limit <number>', 'Maximum number of results to return', '10')
726
+ .option('--min-similarity <number>', 'Minimum similarity score (0.0-1.0)', '0.7')
727
+ .option('--json', 'Output raw JSON instead of formatted text')
728
+ .option('--save-artifact', 'Save result as persistent artifact (ADR-083)')
729
+ .action(async (query, options, command) => {
730
+ // If no query provided and no subcommand matched, show help
731
+ if (!query) {
732
+ command.help();
733
+ return;
734
+ }
735
+ // Check if query matches a subcommand name - if so, Commander already handled it
736
+ const subcommandNames = ['query', 'details', 'related', 'connect', 'sources'];
737
+ if (subcommandNames.includes(query)) {
738
+ // This shouldn't happen as Commander routes subcommands, but safety check
739
+ return;
740
+ }
741
+ // Delegate to query action for direct search shortcut
742
+ try {
743
+ const client = (0, client_1.createClientFromEnv)();
744
+ const config = (0, config_1.getConfig)();
745
+ const result = await client.searchConcepts({
746
+ query,
747
+ limit: parseInt(options.limit),
748
+ min_similarity: parseFloat(options.minSimilarity),
749
+ include_evidence: config.getSearchShowEvidence(),
750
+ include_grounding: true,
751
+ include_diversity: true,
752
+ diversity_max_hops: 2
753
+ });
754
+ // JSON output mode
755
+ if (options.json) {
756
+ console.log(JSON.stringify(result, null, 2));
757
+ return;
758
+ }
759
+ console.log('\n' + (0, colors_1.separator)());
760
+ console.log(colors.ui.title(`šŸ” Searching for: ${query}`));
761
+ console.log((0, colors_1.separator)());
762
+ console.log(colors.status.success(`\nāœ“ Found ${result.count} concepts:\n`));
763
+ for (const [i, concept] of result.results.entries()) {
764
+ console.log(colors.ui.bullet('ā—') + ' ' + colors.concept.label(`${i + 1}. ${concept.label}`));
765
+ if (concept.description) {
766
+ console.log(` ${colors.status.dim(concept.description)}`);
767
+ }
768
+ console.log(` ${colors.ui.key('ID:')} ${colors.concept.id(concept.concept_id)}`);
769
+ console.log(` ${colors.ui.key('Similarity:')} ${(0, colors_1.coloredPercentage)(concept.score)}`);
770
+ console.log(` ${colors.ui.key('Documents:')} ${colors.evidence.document(concept.documents.join(', '))}`);
771
+ console.log(` ${colors.ui.key('Evidence:')} ${colors.evidence.count(String(concept.evidence_count))} instances`);
772
+ // Display grounding with confidence-awareness
773
+ if (concept.grounding_strength !== undefined || concept.grounding_display) {
774
+ console.log(` ${colors.ui.key('Grounding:')} ${formatGroundingWithConfidence(concept.grounding_strength, concept.grounding_display, concept.confidence_level, concept.confidence_score)}`);
775
+ }
776
+ // Display diversity if available
777
+ if (concept.diversity_score !== undefined && concept.diversity_score !== null && concept.diversity_related_count !== undefined) {
778
+ console.log(` ${colors.ui.key('Diversity:')} ${formatDiversity(concept.diversity_score, concept.diversity_related_count)}`);
779
+ }
780
+ // Display authenticated diversity if available
781
+ if (concept.authenticated_diversity !== undefined && concept.authenticated_diversity !== null) {
782
+ console.log(` ${colors.ui.key('Authenticated:')} ${formatAuthenticatedDiversity(concept.authenticated_diversity)}`);
783
+ }
784
+ console.log();
785
+ }
786
+ // Show hint if additional results available below threshold
787
+ if (result.below_threshold_count && result.below_threshold_count > 0 && result.suggested_threshold) {
788
+ const thresholdPercent = (result.suggested_threshold * 100).toFixed(0);
789
+ console.log(colors.status.warning(`šŸ’” ${result.below_threshold_count} additional concept${result.below_threshold_count > 1 ? 's' : ''} available at ${thresholdPercent}% threshold`));
790
+ console.log(colors.status.dim(` Try: kg search "${query}" --min-similarity ${result.suggested_threshold}\n`));
791
+ }
792
+ // ADR-083: Save result as artifact if requested
793
+ if (options.saveArtifact && result.count > 0) {
794
+ try {
795
+ const artifactResult = await client.createArtifact({
796
+ artifact_type: 'search_result',
797
+ representation: 'cli',
798
+ name: `Search: "${query}" (${result.count} results)`,
799
+ parameters: {
800
+ query,
801
+ limit: parseInt(options.limit),
802
+ min_similarity: parseFloat(options.minSimilarity),
803
+ include_evidence: config.getSearchShowEvidence(),
804
+ include_grounding: true,
805
+ include_diversity: true,
806
+ diversity_max_hops: 2
807
+ },
808
+ payload: result
809
+ });
810
+ console.log(colors.status.success(`āœ“ Artifact saved: ${artifactResult.id}`));
811
+ console.log(colors.status.dim(` View: kg artifact show ${artifactResult.id}`));
812
+ }
813
+ catch (artifactError) {
814
+ console.error(colors.status.error(`āœ— Failed to save artifact: ${artifactError.message}`));
815
+ }
816
+ }
817
+ }
818
+ catch (error) {
819
+ console.error(colors.status.error('āœ— Search failed'));
820
+ console.error(colors.status.error(error.response?.data?.detail || error.message));
821
+ process.exit(1);
822
+ }
823
+ })
824
+ .addCommand(queryCommand)
825
+ .addCommand(showCommand)
826
+ .addCommand(relatedCommand)
827
+ .addCommand(connectCommand)
828
+ .addCommand(sourcesCommand);
829
+ //# sourceMappingURL=search.js.map