@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,663 @@
1
+ "use strict";
2
+ /**
3
+ * Job management 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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
39
+ return (mod && mod.__esModule) ? mod : { "default": mod };
40
+ };
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.jobsCommand = void 0;
43
+ const commander_1 = require("commander");
44
+ const chalk_1 = __importDefault(require("chalk"));
45
+ const client_1 = require("../api/client");
46
+ const colors = __importStar(require("./colors"));
47
+ const table_1 = require("../lib/table");
48
+ const help_formatter_1 = require("./help-formatter");
49
+ exports.jobsCommand = (0, help_formatter_1.setCommandHelp)(new commander_1.Command('job'), 'Manage and monitor ingestion jobs', 'Manage and monitor ingestion jobs through their lifecycle (pending → approval → processing → completed/failed)')
50
+ .alias('jobs') // Plural alias for backwards compatibility
51
+ .showHelpAfterError('(add --help for additional information)')
52
+ .showSuggestionAfterError();
53
+ // Get job status
54
+ exports.jobsCommand
55
+ .command('status <job-id>')
56
+ .description('Get detailed status information for a job (progress, costs, errors) - use --watch to poll until completion')
57
+ .showHelpAfterError()
58
+ .option('-w, --watch', 'Watch job until completion (polls every few seconds)', false)
59
+ .action(async (jobId, options) => {
60
+ try {
61
+ const client = (0, client_1.createClientFromEnv)();
62
+ if (options.watch) {
63
+ // Poll until completion
64
+ console.log(chalk_1.default.blue(`Watching job ${jobId}...`));
65
+ console.log(chalk_1.default.gray('Press Ctrl+C to stop\n'));
66
+ const finalJob = await client.pollJob(jobId, (job) => {
67
+ // Clear line and rewrite
68
+ process.stdout.write('\r\x1b[K'); // Clear line
69
+ if (job.status === 'queued') {
70
+ process.stdout.write(chalk_1.default.yellow(`Status: ${job.status}`));
71
+ }
72
+ else if (job.status === 'processing' && job.progress) {
73
+ const p = job.progress;
74
+ if (p.percent !== undefined) {
75
+ const conceptsTotal = (p.concepts_created || 0) + (p.concepts_linked || 0);
76
+ const hitRate = conceptsTotal > 0 ? Math.round((p.concepts_linked || 0) / conceptsTotal * 100) : 0;
77
+ process.stdout.write(chalk_1.default.blue(`Processing: ${p.percent}% `) +
78
+ chalk_1.default.gray(`(${p.chunks_processed}/${p.chunks_total} chunks) `) +
79
+ chalk_1.default.gray(`| Concepts: ${conceptsTotal} (${hitRate}% reused) `) +
80
+ chalk_1.default.gray(`| Rels: ${p.relationships_created || 0}`));
81
+ }
82
+ else {
83
+ process.stdout.write(chalk_1.default.blue(`Processing: ${p.stage}`));
84
+ }
85
+ }
86
+ });
87
+ console.log(); // New line after polling
88
+ printJobStatus(finalJob);
89
+ }
90
+ else {
91
+ // Single fetch
92
+ const job = await client.getJob(jobId);
93
+ printJobStatus(job);
94
+ }
95
+ }
96
+ catch (error) {
97
+ console.error(chalk_1.default.red('\n✗ Failed to get job status'));
98
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
99
+ process.exit(1);
100
+ }
101
+ });
102
+ // Helper function to display jobs list using Table utility
103
+ async function displayJobsList(status, clientId, limit = 20, fullId = false, offset = 0) {
104
+ const client = (0, client_1.createClientFromEnv)();
105
+ const jobs = await client.listJobs(status, clientId, limit, offset);
106
+ if (jobs.length === 0) {
107
+ console.log(colors.status.dim('\nNo jobs found\n'));
108
+ return;
109
+ }
110
+ // Create table with dynamic configuration
111
+ const table = new table_1.Table({
112
+ columns: [
113
+ {
114
+ header: 'Job ID',
115
+ field: 'job_id',
116
+ type: 'job_id',
117
+ width: fullId ? 38 : 16, // Fixed width - job IDs are consistent length
118
+ truncate: false
119
+ },
120
+ {
121
+ header: 'Source',
122
+ field: (job) => job.source_path || job.filename || '-',
123
+ type: 'text',
124
+ width: 'flex',
125
+ priority: 10, // Highest priority - gets most space
126
+ customFormat: (source, job) => {
127
+ if (!source || source === '-')
128
+ return colors.status.dim('-');
129
+ return source;
130
+ },
131
+ truncate: true
132
+ },
133
+ {
134
+ header: 'User',
135
+ field: 'username',
136
+ type: 'user',
137
+ width: 'auto', // Fit to content
138
+ maxWidth: 12,
139
+ customFormat: (username) => username || 'unknown',
140
+ truncate: true
141
+ },
142
+ {
143
+ header: 'Status',
144
+ field: 'status',
145
+ type: 'text', // Use custom formatting instead of status type
146
+ width: 8, // Fixed width for compact status
147
+ customFormat: (status) => {
148
+ // Compact status - just icons for terminal states
149
+ switch (status) {
150
+ case 'completed': return colors.status.success('✓ done');
151
+ case 'failed': return colors.status.error('✗ fail');
152
+ case 'running': return colors.status.info('⚙ run');
153
+ case 'processing': return colors.status.info('⚙ run');
154
+ case 'approved': return colors.status.success('✓ ok');
155
+ case 'awaiting_approval': return colors.status.warning('⏸ wait');
156
+ case 'pending': return colors.status.dim('○ pend');
157
+ case 'queued': return colors.status.info('⋯ queue');
158
+ case 'cancelled': return colors.status.dim('⊗ stop');
159
+ default: return colors.status.dim(status);
160
+ }
161
+ },
162
+ truncate: false
163
+ },
164
+ {
165
+ header: 'Ontology',
166
+ field: 'ontology',
167
+ type: 'heading',
168
+ width: 'flex',
169
+ priority: 3, // Lower priority than Source
170
+ customFormat: (name) => name || '-',
171
+ truncate: true
172
+ },
173
+ {
174
+ header: 'Created',
175
+ field: 'created_at',
176
+ type: 'timestamp',
177
+ width: 16 // Timestamp is consistent width
178
+ },
179
+ {
180
+ header: '', // No header for progress icon
181
+ field: (job) => job.progress?.percent,
182
+ type: 'progress',
183
+ width: 1, // Just the icon
184
+ customFormat: (percent, job) => {
185
+ // Just icons, no text
186
+ if (job.status === 'completed')
187
+ return '✓';
188
+ if (job.status === 'failed')
189
+ return '✗';
190
+ if (job.status === 'cancelled')
191
+ return '⊗';
192
+ return percent !== undefined && percent < 100 ? '⋯' : ' ';
193
+ },
194
+ truncate: false
195
+ }
196
+ ],
197
+ spacing: 1, // Tighter spacing between columns
198
+ showHeader: true,
199
+ showSeparator: true
200
+ });
201
+ // Render table
202
+ table.print(jobs);
203
+ // Helpful tip
204
+ if (!fullId && jobs.length > 0) {
205
+ console.log(colors.status.dim('Tip: Use --full-id to show complete job IDs\n'));
206
+ }
207
+ }
208
+ // List command with subcommands
209
+ const listCommand = new commander_1.Command('list')
210
+ .description('List recent jobs with optional filtering by status or user - includes subcommands for common filters')
211
+ .option('-s, --status <status>', 'Filter by status (pending|awaiting_approval|approved|queued|processing|completed|failed|cancelled)')
212
+ .option('-c, --client <user-id>', 'Filter by user ID (view specific user\'s jobs)')
213
+ .option('-l, --limit <n>', 'Maximum jobs to return (max: 500, default: 100)', '100')
214
+ .option('-o, --offset <n>', 'Number of jobs to skip for pagination (default: 0)', '0')
215
+ .option('--full-id', 'Show full job IDs without truncation', false)
216
+ .showHelpAfterError()
217
+ .action(async (options) => {
218
+ try {
219
+ const limit = parseInt(options.limit);
220
+ const offset = parseInt(options.offset);
221
+ await displayJobsList(options.status, options.client, limit, options.fullId, offset);
222
+ }
223
+ catch (error) {
224
+ console.error(chalk_1.default.red('✗ Failed to list jobs'));
225
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
226
+ process.exit(1);
227
+ }
228
+ });
229
+ // List subcommands for common filters
230
+ listCommand
231
+ .command('pending')
232
+ .description('List jobs awaiting approval')
233
+ .option('-c, --client <user-id>', 'Filter by user ID')
234
+ .option('-l, --limit <n>', 'Maximum jobs to return', '20')
235
+ .option('--full-id', 'Show full job IDs (no truncation)', false)
236
+ .action(async (options) => {
237
+ try {
238
+ console.log(chalk_1.default.blue('Jobs awaiting approval:\n'));
239
+ await displayJobsList('awaiting_approval', options.client, parseInt(options.limit), options.fullId);
240
+ }
241
+ catch (error) {
242
+ console.error(chalk_1.default.red('✗ Failed to list jobs'));
243
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
244
+ process.exit(1);
245
+ }
246
+ });
247
+ listCommand
248
+ .command('approved')
249
+ .description('List approved jobs (queued or processing)')
250
+ .option('-c, --client <user-id>', 'Filter by user ID')
251
+ .option('-l, --limit <n>', 'Maximum jobs to return', '20')
252
+ .option('--full-id', 'Show full job IDs (no truncation)', false)
253
+ .action(async (options) => {
254
+ try {
255
+ console.log(chalk_1.default.blue('Approved jobs:\n'));
256
+ await displayJobsList('approved', options.client, parseInt(options.limit), options.fullId);
257
+ }
258
+ catch (error) {
259
+ console.error(chalk_1.default.red('✗ Failed to list jobs'));
260
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
261
+ process.exit(1);
262
+ }
263
+ });
264
+ listCommand
265
+ .command('done')
266
+ .description('List completed jobs')
267
+ .option('-c, --client <user-id>', 'Filter by user ID')
268
+ .option('-l, --limit <n>', 'Maximum jobs to return', '20')
269
+ .option('--full-id', 'Show full job IDs (no truncation)', false)
270
+ .action(async (options) => {
271
+ try {
272
+ console.log(chalk_1.default.green('Completed jobs:\n'));
273
+ await displayJobsList('completed', options.client, parseInt(options.limit), options.fullId);
274
+ }
275
+ catch (error) {
276
+ console.error(chalk_1.default.red('✗ Failed to list jobs'));
277
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
278
+ process.exit(1);
279
+ }
280
+ });
281
+ listCommand
282
+ .command('failed')
283
+ .description('List failed jobs')
284
+ .option('-c, --client <user-id>', 'Filter by user ID')
285
+ .option('-l, --limit <n>', 'Maximum jobs to return', '20')
286
+ .option('--full-id', 'Show full job IDs (no truncation)', false)
287
+ .action(async (options) => {
288
+ try {
289
+ console.log(chalk_1.default.red('Failed jobs:\n'));
290
+ await displayJobsList('failed', options.client, parseInt(options.limit), options.fullId);
291
+ }
292
+ catch (error) {
293
+ console.error(chalk_1.default.red('✗ Failed to list jobs'));
294
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
295
+ process.exit(1);
296
+ }
297
+ });
298
+ listCommand
299
+ .command('cancelled')
300
+ .description('List cancelled jobs')
301
+ .option('-c, --client <user-id>', 'Filter by user ID')
302
+ .option('-l, --limit <n>', 'Maximum jobs to return', '20')
303
+ .option('--full-id', 'Show full job IDs (no truncation)', false)
304
+ .action(async (options) => {
305
+ try {
306
+ console.log(chalk_1.default.yellow('Cancelled jobs:\n'));
307
+ await displayJobsList('cancelled', options.client, parseInt(options.limit), options.fullId);
308
+ }
309
+ catch (error) {
310
+ console.error(chalk_1.default.red('✗ Failed to list jobs'));
311
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
312
+ process.exit(1);
313
+ }
314
+ });
315
+ // Add list command to jobs
316
+ exports.jobsCommand.addCommand(listCommand);
317
+ // Approve job(s) (ADR-014)
318
+ const approveCommand = new commander_1.Command('approve')
319
+ .description('Approve jobs for processing (ADR-014 approval workflow) - single job, batch pending, or filter by status')
320
+ .showHelpAfterError();
321
+ // Approve single job
322
+ approveCommand
323
+ .command('job <job-id>')
324
+ .description('Approve a specific job by ID after reviewing cost estimates')
325
+ .action(async (jobId) => {
326
+ try {
327
+ const client = (0, client_1.createClientFromEnv)();
328
+ console.log(chalk_1.default.blue(`Approving job ${jobId}...`));
329
+ const result = await client.approveJob(jobId);
330
+ console.log(chalk_1.default.green('✓ Job approved'));
331
+ console.log(chalk_1.default.gray(` Status: ${result.status}`));
332
+ console.log(chalk_1.default.gray(`\nMonitor: ${chalk_1.default.cyan(`kg jobs status ${jobId} --watch`)}`));
333
+ }
334
+ catch (error) {
335
+ console.error(chalk_1.default.red('✗ Failed to approve job'));
336
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
337
+ process.exit(1);
338
+ }
339
+ });
340
+ // Approve all pending jobs
341
+ approveCommand
342
+ .command('pending')
343
+ .description('Approve all jobs awaiting approval (batch operation with confirmation)')
344
+ .option('-c, --client <user-id>', 'Filter by user ID')
345
+ .option('-l, --limit <n>', 'Maximum jobs to approve (default: 100)', '100')
346
+ .action(async (options) => {
347
+ try {
348
+ const client = (0, client_1.createClientFromEnv)();
349
+ console.log(chalk_1.default.blue('Finding jobs awaiting approval...\n'));
350
+ const jobs = await client.listJobs('awaiting_approval', options.client, parseInt(options.limit));
351
+ if (jobs.length === 0) {
352
+ console.log(chalk_1.default.gray('No pending jobs found'));
353
+ return;
354
+ }
355
+ console.log(chalk_1.default.blue(`Found ${jobs.length} pending job(s):\n`));
356
+ let approved = 0;
357
+ let failed = 0;
358
+ for (const job of jobs) {
359
+ try {
360
+ await client.approveJob(job.job_id);
361
+ console.log(chalk_1.default.green(`✓ Approved: ${job.job_id.substring(0, 12)}... (${job.ontology || 'unknown'})`));
362
+ approved++;
363
+ }
364
+ catch (error) {
365
+ console.log(chalk_1.default.red(`✗ Failed: ${job.job_id.substring(0, 12)}... - ${error.message}`));
366
+ failed++;
367
+ }
368
+ }
369
+ console.log(chalk_1.default.blue(`\nSummary: ${approved} approved, ${failed} failed`));
370
+ console.log(chalk_1.default.gray(`\nMonitor jobs: ${chalk_1.default.cyan('kg jobs list')}`));
371
+ }
372
+ catch (error) {
373
+ console.error(chalk_1.default.red('✗ Failed to approve pending jobs'));
374
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
375
+ process.exit(1);
376
+ }
377
+ });
378
+ // Legacy: approve with ID or filter
379
+ approveCommand
380
+ .command('filter <status>')
381
+ .description('Approve all jobs matching status filter')
382
+ .option('-c, --client <user-id>', 'Filter by user ID')
383
+ .action(async (statusFilter, options) => {
384
+ try {
385
+ const client = (0, client_1.createClientFromEnv)();
386
+ const statusMap = {
387
+ 'pending': 'awaiting_approval',
388
+ 'awaiting': 'awaiting_approval',
389
+ };
390
+ const status = statusMap[statusFilter] || statusFilter;
391
+ console.log(chalk_1.default.blue(`Finding jobs with status: ${status}...\n`));
392
+ const jobs = await client.listJobs(status, options.client, 100);
393
+ if (jobs.length === 0) {
394
+ console.log(chalk_1.default.gray('No jobs found matching filter'));
395
+ return;
396
+ }
397
+ console.log(chalk_1.default.blue(`Found ${jobs.length} job(s). Approving...\n`));
398
+ let approved = 0;
399
+ let failed = 0;
400
+ for (const job of jobs) {
401
+ try {
402
+ await client.approveJob(job.job_id);
403
+ console.log(chalk_1.default.green(`✓ Approved: ${job.job_id.substring(0, 12)}... (${job.ontology || 'unknown'})`));
404
+ approved++;
405
+ }
406
+ catch (error) {
407
+ console.log(chalk_1.default.red(`✗ Failed: ${job.job_id.substring(0, 12)}... - ${error.message}`));
408
+ failed++;
409
+ }
410
+ }
411
+ console.log(chalk_1.default.blue(`\nSummary: ${approved} approved, ${failed} failed`));
412
+ }
413
+ catch (error) {
414
+ console.error(chalk_1.default.red('✗ Failed to approve jobs'));
415
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
416
+ process.exit(1);
417
+ }
418
+ });
419
+ exports.jobsCommand.addCommand(approveCommand);
420
+ // Cancel job(s)
421
+ exports.jobsCommand
422
+ .command('cancel <job-id-or-filter>')
423
+ .description('Cancel a specific job by ID or batch cancel using filters (all, pending, running, queued, approved)')
424
+ .showHelpAfterError()
425
+ .option('-c, --client <user-id>', 'Filter by user ID for batch operations')
426
+ .option('-l, --limit <n>', 'Maximum jobs to cancel for safety (default: 100)', '100')
427
+ .action(async (jobIdOrFilter, options) => {
428
+ try {
429
+ const client = (0, client_1.createClientFromEnv)();
430
+ const limit = parseInt(options.limit);
431
+ // Check if it's a job ID or a status filter
432
+ if (jobIdOrFilter.startsWith('job_')) {
433
+ // Single job cancellation
434
+ console.log(chalk_1.default.blue(`Cancelling job ${jobIdOrFilter}...`));
435
+ const result = await client.cancelJob(jobIdOrFilter);
436
+ if (result.cancelled) {
437
+ console.log(chalk_1.default.green('✓ Job cancelled'));
438
+ }
439
+ else {
440
+ console.log(chalk_1.default.yellow('⚠ Job could not be cancelled'));
441
+ }
442
+ }
443
+ else {
444
+ // Batch cancellation by status filter
445
+ const statusMap = {
446
+ 'all': undefined, // No filter = all jobs
447
+ 'pending': 'awaiting_approval',
448
+ 'awaiting': 'awaiting_approval',
449
+ 'approved': 'approved',
450
+ 'queued': 'queued',
451
+ 'running': 'processing',
452
+ 'processing': 'processing',
453
+ };
454
+ const filter = jobIdOrFilter.toLowerCase();
455
+ // Check if it's a known filter
456
+ if (!(filter in statusMap)) {
457
+ console.error(chalk_1.default.red(`✗ Unknown filter: "${jobIdOrFilter}"`));
458
+ console.error(chalk_1.default.gray('\nSupported filters:'));
459
+ console.error(chalk_1.default.gray(' all - All cancellable jobs'));
460
+ console.error(chalk_1.default.gray(' pending - Jobs awaiting approval'));
461
+ console.error(chalk_1.default.gray(' approved - Approved jobs (not yet started)'));
462
+ console.error(chalk_1.default.gray(' queued - Queued jobs'));
463
+ console.error(chalk_1.default.gray(' running - Currently processing jobs'));
464
+ process.exit(1);
465
+ }
466
+ const status = statusMap[filter];
467
+ const filterDisplay = status || 'all cancellable jobs';
468
+ console.log(chalk_1.default.blue(`Finding ${filterDisplay}...`));
469
+ const jobs = await client.listJobs(status, options.client, limit);
470
+ if (jobs.length === 0) {
471
+ console.log(chalk_1.default.gray(`No jobs found matching filter: ${jobIdOrFilter}`));
472
+ return;
473
+ }
474
+ // Filter to only cancellable statuses (not completed, failed, or already cancelled)
475
+ const cancellableStatuses = ['awaiting_approval', 'approved', 'queued', 'processing'];
476
+ const cancellableJobs = jobs.filter(j => cancellableStatuses.includes(j.status));
477
+ if (cancellableJobs.length === 0) {
478
+ console.log(chalk_1.default.yellow(`Found ${jobs.length} job(s), but none are cancellable`));
479
+ console.log(chalk_1.default.gray('Only jobs in these states can be cancelled: awaiting_approval, approved, queued, processing'));
480
+ return;
481
+ }
482
+ if (cancellableJobs.length < jobs.length) {
483
+ console.log(chalk_1.default.yellow(`Found ${jobs.length} job(s), ${cancellableJobs.length} are cancellable\n`));
484
+ }
485
+ else {
486
+ console.log(chalk_1.default.blue(`Found ${cancellableJobs.length} job(s). Cancelling...\n`));
487
+ }
488
+ let cancelled = 0;
489
+ let failed = 0;
490
+ for (const job of cancellableJobs) {
491
+ try {
492
+ await client.cancelJob(job.job_id);
493
+ console.log(chalk_1.default.yellow(`✓ Cancelled: ${job.job_id.substring(0, 12)}... (${job.status}) - ${job.ontology || 'N/A'}`));
494
+ cancelled++;
495
+ }
496
+ catch (error) {
497
+ const errorMsg = error.response?.data?.detail || error.message || 'Unknown error';
498
+ console.log(chalk_1.default.red(`✗ Failed: ${job.job_id.substring(0, 12)}... - ${errorMsg}`));
499
+ failed++;
500
+ }
501
+ }
502
+ console.log(chalk_1.default.blue(`\nSummary: ${cancelled} cancelled, ${failed} failed`));
503
+ }
504
+ }
505
+ catch (error) {
506
+ console.error(chalk_1.default.red('✗ Failed to cancel job(s)'));
507
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
508
+ process.exit(1);
509
+ }
510
+ });
511
+ // Clear all jobs
512
+ exports.jobsCommand
513
+ .command('clear')
514
+ .description('Clear ALL jobs from database - DESTRUCTIVE operation requiring --confirm flag (use for dev/testing cleanup)')
515
+ .option('--confirm', 'Confirm deletion (REQUIRED for safety)', false)
516
+ .showHelpAfterError()
517
+ .action(async (options) => {
518
+ try {
519
+ if (!options.confirm) {
520
+ console.error(chalk_1.default.red('✗ Confirmation required'));
521
+ console.error(chalk_1.default.yellow('\n⚠️ This will DELETE ALL jobs from the database!'));
522
+ console.error(chalk_1.default.gray('\nTo confirm, run: ') + chalk_1.default.cyan('kg jobs clear --confirm'));
523
+ process.exit(1);
524
+ }
525
+ const client = (0, client_1.createClientFromEnv)();
526
+ console.log(chalk_1.default.yellow('\n⚠️ Clearing ALL jobs from database...'));
527
+ const result = await client.clearAllJobs(true);
528
+ console.log(chalk_1.default.green(`\n✓ ${result.message}`));
529
+ console.log(chalk_1.default.gray(` Jobs deleted: ${result.jobs_deleted}\n`));
530
+ }
531
+ catch (error) {
532
+ console.error(chalk_1.default.red('✗ Failed to clear jobs'));
533
+ console.error(chalk_1.default.red(error.response?.data?.detail || error.message));
534
+ process.exit(1);
535
+ }
536
+ });
537
+ /**
538
+ * Print detailed job status
539
+ */
540
+ function printJobStatus(job) {
541
+ console.log(chalk_1.default.blue('\nJob Status:'));
542
+ console.log(chalk_1.default.gray(` ID: ${job.job_id}`));
543
+ console.log(chalk_1.default.gray(` Type: ${job.job_type}`));
544
+ // Format job status with icons
545
+ let statusDisplay = job.status;
546
+ switch (job.status) {
547
+ case 'completed':
548
+ statusDisplay = colors.status.success('✓ completed');
549
+ break;
550
+ case 'failed':
551
+ statusDisplay = colors.status.error('✗ failed');
552
+ break;
553
+ case 'processing':
554
+ statusDisplay = colors.status.info('⚙ processing');
555
+ break;
556
+ case 'approved':
557
+ statusDisplay = colors.status.success('✓ approved');
558
+ break;
559
+ case 'awaiting_approval':
560
+ statusDisplay = colors.status.warning('⏸ awaiting approval');
561
+ break;
562
+ case 'pending':
563
+ statusDisplay = colors.status.dim('○ pending');
564
+ break;
565
+ case 'queued':
566
+ statusDisplay = colors.status.info('⋯ queued');
567
+ break;
568
+ case 'cancelled':
569
+ statusDisplay = colors.status.dim('⊗ cancelled');
570
+ break;
571
+ default:
572
+ statusDisplay = colors.status.dim(job.status);
573
+ }
574
+ console.log(` Status: ${statusDisplay}`);
575
+ if (job.ontology) {
576
+ console.log(chalk_1.default.gray(` Ontology: ${job.ontology}`));
577
+ }
578
+ console.log(chalk_1.default.gray(` Created: ${new Date(job.created_at).toLocaleString()}`));
579
+ if (job.started_at) {
580
+ console.log(chalk_1.default.gray(` Started: ${new Date(job.started_at).toLocaleString()}`));
581
+ }
582
+ if (job.completed_at) {
583
+ console.log(chalk_1.default.gray(` Completed: ${new Date(job.completed_at).toLocaleString()}`));
584
+ const duration = (new Date(job.completed_at).getTime() - new Date(job.created_at).getTime()) / 1000;
585
+ console.log(chalk_1.default.gray(` Duration: ${duration.toFixed(1)}s`));
586
+ }
587
+ // ADR-014: Show analysis when available
588
+ if (job.analysis) {
589
+ console.log(chalk_1.default.blue('\nPre-Ingestion Analysis:'));
590
+ const a = job.analysis;
591
+ if (a.file_stats) {
592
+ console.log(chalk_1.default.gray(` File: ${a.file_stats.filename} (${a.file_stats.size_human})`));
593
+ console.log(chalk_1.default.gray(` Words: ${a.file_stats.word_count.toLocaleString()}`));
594
+ console.log(chalk_1.default.gray(` Estimated chunks: ~${a.file_stats.estimated_chunks}`));
595
+ }
596
+ if (a.cost_estimate) {
597
+ console.log(chalk_1.default.blue('\n💰 Cost Estimate:'));
598
+ const ce = a.cost_estimate;
599
+ console.log(chalk_1.default.gray(` Extraction (${ce.extraction.model}):`));
600
+ console.log(chalk_1.default.gray(` Tokens: ${ce.extraction.tokens_low.toLocaleString()}-${ce.extraction.tokens_high.toLocaleString()}`));
601
+ console.log(chalk_1.default.gray(` Cost: $${ce.extraction.cost_low.toFixed(2)}-$${ce.extraction.cost_high.toFixed(2)}`));
602
+ console.log(chalk_1.default.gray(` Embeddings (${ce.embeddings.model}):`));
603
+ console.log(chalk_1.default.gray(` Concepts: ${ce.embeddings.concepts_low}-${ce.embeddings.concepts_high}`));
604
+ console.log(chalk_1.default.gray(` Cost: $${ce.embeddings.cost_low.toFixed(2)}-$${ce.embeddings.cost_high.toFixed(2)}`));
605
+ console.log(chalk_1.default.bold(` Total: $${ce.total.cost_low.toFixed(2)}-$${ce.total.cost_high.toFixed(2)}`));
606
+ }
607
+ if (a.warnings && a.warnings.length > 0) {
608
+ console.log(chalk_1.default.yellow('\n⚠️ Warnings:'));
609
+ a.warnings.forEach((w) => console.log(chalk_1.default.yellow(` • ${w}`)));
610
+ }
611
+ if (job.status === 'awaiting_approval') {
612
+ console.log(chalk_1.default.blue('\n📌 Next Steps:'));
613
+ console.log(chalk_1.default.gray(` Approve: kg jobs approve ${job.job_id}`));
614
+ console.log(chalk_1.default.gray(` Cancel: kg jobs cancel ${job.job_id}`));
615
+ }
616
+ }
617
+ if (job.progress) {
618
+ console.log(chalk_1.default.blue('\nProgress:'));
619
+ const p = job.progress;
620
+ if (p.percent !== undefined) {
621
+ console.log(chalk_1.default.gray(` ${p.percent}% complete`));
622
+ }
623
+ if (p.chunks_total) {
624
+ console.log(chalk_1.default.gray(` Chunks: ${p.chunks_processed}/${p.chunks_total}`));
625
+ }
626
+ // Concept statistics
627
+ const conceptsNew = p.concepts_created || 0;
628
+ const conceptsLinked = p.concepts_linked || 0;
629
+ const conceptsTotal = conceptsNew + conceptsLinked;
630
+ if (conceptsTotal > 0) {
631
+ const hitRate = Math.round((conceptsLinked / conceptsTotal) * 100);
632
+ console.log(chalk_1.default.gray(` Concepts: ${conceptsTotal} total (${conceptsNew} new, ${conceptsLinked} reused)`));
633
+ console.log(chalk_1.default.gray(` Hit rate: ${hitRate}% (existing concepts reused)`));
634
+ }
635
+ if (p.instances_created) {
636
+ console.log(chalk_1.default.gray(` Instances: ${p.instances_created}`));
637
+ }
638
+ if (p.relationships_created) {
639
+ console.log(chalk_1.default.gray(` Relationships: ${p.relationships_created}`));
640
+ }
641
+ }
642
+ if (job.result) {
643
+ console.log(chalk_1.default.blue('\nResults:'));
644
+ const r = job.result;
645
+ if (r.stats) {
646
+ console.log(chalk_1.default.gray(` Chunks processed: ${r.stats.chunks_processed}`));
647
+ console.log(chalk_1.default.gray(` Concepts created: ${r.stats.concepts_created}`));
648
+ console.log(chalk_1.default.gray(` Sources created: ${r.stats.sources_created}`));
649
+ console.log(chalk_1.default.gray(` Relationships: ${r.stats.relationships_created}`));
650
+ }
651
+ if (r.cost) {
652
+ console.log(chalk_1.default.blue('\nCost:'));
653
+ console.log(chalk_1.default.gray(` Extraction: ${r.cost.extraction}`));
654
+ console.log(chalk_1.default.gray(` Embeddings: ${r.cost.embeddings}`));
655
+ console.log(chalk_1.default.gray(` Total: ${r.cost.total}`));
656
+ }
657
+ }
658
+ if (job.error) {
659
+ console.log(chalk_1.default.red('\nError:'));
660
+ console.log(chalk_1.default.red(` ${job.error}`));
661
+ }
662
+ }
663
+ //# sourceMappingURL=jobs.js.map