@mikado-ai/cli 0.1.0
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.
- package/README.md +229 -0
- package/dist/chunk-5RICPX62.js +94 -0
- package/dist/chunk-6RKQ24OP.js +94 -0
- package/dist/chunk-DC4BEVL3.js +94 -0
- package/dist/chunk-L27HHHAB.js +95 -0
- package/dist/chunk-TJ7OWJIM.js +94 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +597 -0
- package/dist/mcp.d.ts +4 -0
- package/dist/mcp.js +208 -0
- package/package.json +54 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
MikadoClient,
|
|
4
|
+
pollJob
|
|
5
|
+
} from "./chunk-L27HHHAB.js";
|
|
6
|
+
|
|
7
|
+
// src/index.ts
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
|
|
10
|
+
// src/commands/auth.ts
|
|
11
|
+
import { createInterface } from "readline";
|
|
12
|
+
import chalk2 from "chalk";
|
|
13
|
+
|
|
14
|
+
// src/core/auth.ts
|
|
15
|
+
import { homedir } from "os";
|
|
16
|
+
import { join } from "path";
|
|
17
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
18
|
+
function getConfigPath() {
|
|
19
|
+
return join(homedir(), ".mikado", "config.json");
|
|
20
|
+
}
|
|
21
|
+
function loadConfig() {
|
|
22
|
+
const envApiKey = process.env.MIKADO_API_KEY;
|
|
23
|
+
const envUrl = process.env.MIKADO_URL;
|
|
24
|
+
if (envApiKey && envUrl) {
|
|
25
|
+
return {
|
|
26
|
+
api_key: envApiKey,
|
|
27
|
+
base_url: envUrl
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const configPath = getConfigPath();
|
|
31
|
+
if (!existsSync(configPath)) {
|
|
32
|
+
if (envApiKey && existsSync(configPath)) {
|
|
33
|
+
try {
|
|
34
|
+
const fileConfig = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
35
|
+
return {
|
|
36
|
+
api_key: envApiKey,
|
|
37
|
+
base_url: fileConfig.base_url || envUrl || "https://mikadoai.app"
|
|
38
|
+
};
|
|
39
|
+
} catch {
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
46
|
+
return {
|
|
47
|
+
api_key: envApiKey || config.api_key,
|
|
48
|
+
base_url: envUrl || config.base_url
|
|
49
|
+
};
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw new Error(`Failed to read config file at ${configPath}: ${error}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function saveConfig(config) {
|
|
55
|
+
const configPath = getConfigPath();
|
|
56
|
+
const configDir = join(homedir(), ".mikado");
|
|
57
|
+
if (!existsSync(configDir)) {
|
|
58
|
+
mkdirSync(configDir, { recursive: true, mode: 448 });
|
|
59
|
+
}
|
|
60
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/output/human.ts
|
|
64
|
+
import chalk from "chalk";
|
|
65
|
+
function formatDuration(ms) {
|
|
66
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
67
|
+
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
68
|
+
const minutes = Math.floor(ms / 6e4);
|
|
69
|
+
const seconds = Math.floor(ms % 6e4 / 1e3);
|
|
70
|
+
return `${minutes}m ${seconds}s`;
|
|
71
|
+
}
|
|
72
|
+
function renderWhoami(response) {
|
|
73
|
+
console.log(chalk.green(`
|
|
74
|
+
\u2713 Authenticated as "${response.organization_name}" (${response.key_prefix}...)`));
|
|
75
|
+
console.log(` Key name: ${response.key_name}`);
|
|
76
|
+
console.log();
|
|
77
|
+
}
|
|
78
|
+
function renderJobStatus(job) {
|
|
79
|
+
const statusColors = {
|
|
80
|
+
PENDING: chalk.gray,
|
|
81
|
+
IN_PROGRESS: chalk.yellow,
|
|
82
|
+
SUCCESS: chalk.green,
|
|
83
|
+
FAILED: chalk.red,
|
|
84
|
+
RETRY: chalk.yellow,
|
|
85
|
+
CANCELLED: chalk.gray
|
|
86
|
+
};
|
|
87
|
+
const colorFn = statusColors[job.status] || chalk.white;
|
|
88
|
+
const statusIcon = job.status === "SUCCESS" ? "\u2713" : job.status === "FAILED" ? "\u2717" : "\u25D0";
|
|
89
|
+
console.log(`
|
|
90
|
+
Job: ${job.job_id}`);
|
|
91
|
+
console.log(` Status: ${statusIcon} ${colorFn(job.status)}`);
|
|
92
|
+
if (job.elapsed_ms) {
|
|
93
|
+
console.log(` Duration: ${formatDuration(job.elapsed_ms)}`);
|
|
94
|
+
}
|
|
95
|
+
if (job.entity_id) {
|
|
96
|
+
console.log(` Conversation: ${job.entity_id}`);
|
|
97
|
+
}
|
|
98
|
+
if (job.error_message) {
|
|
99
|
+
console.log(` Error: ${chalk.red(job.error_message)}`);
|
|
100
|
+
}
|
|
101
|
+
if (job.conversation_summary) {
|
|
102
|
+
const s = job.conversation_summary;
|
|
103
|
+
console.log(` Insights: ${s.insight_count} generated`);
|
|
104
|
+
if (s.sentiment) {
|
|
105
|
+
console.log(` Sentiment: ${s.sentiment.toLowerCase()} (${s.sentiment_score?.toFixed(2) ?? "N/A"})`);
|
|
106
|
+
}
|
|
107
|
+
if (s.outcome) {
|
|
108
|
+
console.log(` Outcome: ${s.outcome}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
console.log();
|
|
112
|
+
}
|
|
113
|
+
function renderSubmitResult(conversation) {
|
|
114
|
+
console.log(chalk.bold.green("\n\u2713 Processing Complete\n"));
|
|
115
|
+
const meta = [];
|
|
116
|
+
if (conversation.provider) meta.push(`Provider: ${conversation.provider.toLowerCase()}`);
|
|
117
|
+
if (conversation.analytics.duration_ms) meta.push(`Duration: ${formatDuration(conversation.analytics.duration_ms)}`);
|
|
118
|
+
if (conversation.analytics.turn_count) meta.push(`Turns: ${conversation.analytics.turn_count}`);
|
|
119
|
+
if (meta.length > 0) {
|
|
120
|
+
console.log(` ${meta.join(" | ")}`);
|
|
121
|
+
}
|
|
122
|
+
if (conversation.analytics.sentiment) {
|
|
123
|
+
const score = conversation.analytics.sentiment_score?.toFixed(2) ?? "";
|
|
124
|
+
console.log(` Sentiment: ${conversation.analytics.sentiment.toLowerCase()} (${score})`);
|
|
125
|
+
}
|
|
126
|
+
if (conversation.analytics.outcome_result) {
|
|
127
|
+
console.log(` Outcome: ${conversation.analytics.outcome_result}`);
|
|
128
|
+
}
|
|
129
|
+
if (conversation.participants.length > 0) {
|
|
130
|
+
console.log(chalk.bold("\n Participants:"));
|
|
131
|
+
conversation.participants.forEach((p) => {
|
|
132
|
+
const name = p.name || p.id;
|
|
133
|
+
const role = p.role ? ` (${p.role})` : "";
|
|
134
|
+
console.log(` - ${name}${role} [${p.type}]`);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (conversation.insights.length > 0) {
|
|
138
|
+
console.log(chalk.bold("\n Insights:"));
|
|
139
|
+
conversation.insights.forEach((insight) => {
|
|
140
|
+
const name = insight.template_name || "Unnamed";
|
|
141
|
+
const scoreStr = insight.total_score != null ? ` \u2014 Score: ${insight.total_score}` : "";
|
|
142
|
+
const labels = insight.labels?.map((l) => l.value).join(", ");
|
|
143
|
+
const labelStr = labels ? ` (${labels})` : "";
|
|
144
|
+
console.log(` ${chalk.cyan(name)}${scoreStr}${labelStr}`);
|
|
145
|
+
if (insight.summary) {
|
|
146
|
+
console.log(` ${insight.summary}`);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (conversation.processing.processing_time_ms) {
|
|
151
|
+
console.log(`
|
|
152
|
+
Processed in ${formatDuration(conversation.processing.processing_time_ms)}`);
|
|
153
|
+
}
|
|
154
|
+
console.log(`
|
|
155
|
+
Conversation: ${conversation.id}`);
|
|
156
|
+
console.log();
|
|
157
|
+
}
|
|
158
|
+
function renderCampaigns(response) {
|
|
159
|
+
if (response.campaigns.length === 0) {
|
|
160
|
+
console.log(chalk.gray("\n No active campaigns found.\n"));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
console.log();
|
|
164
|
+
const idWidth = 10;
|
|
165
|
+
const nameWidth = Math.max(...response.campaigns.map((c) => c.name.length), 4) + 2;
|
|
166
|
+
const statusWidth = 10;
|
|
167
|
+
const templatesWidth = 10;
|
|
168
|
+
const convsWidth = 14;
|
|
169
|
+
console.log(
|
|
170
|
+
chalk.bold(" " + "ID".padEnd(idWidth)) + chalk.bold("Name".padEnd(nameWidth)) + chalk.bold("Status".padEnd(statusWidth)) + chalk.bold("Templates".padEnd(templatesWidth)) + chalk.bold("Conversations")
|
|
171
|
+
);
|
|
172
|
+
response.campaigns.forEach((c) => {
|
|
173
|
+
const statusColor = c.status === "ACTIVE" ? chalk.green : chalk.gray;
|
|
174
|
+
console.log(
|
|
175
|
+
` ${c.short_id.padEnd(idWidth)}${chalk.cyan(c.name.padEnd(nameWidth))}${statusColor(c.status.padEnd(statusWidth))}${String(c.template_count).padEnd(templatesWidth)}${c.conversation_count}`
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
console.log();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/output/json.ts
|
|
182
|
+
function outputJson(data) {
|
|
183
|
+
console.log(JSON.stringify(data, null, 2));
|
|
184
|
+
}
|
|
185
|
+
function errorJson(message, code) {
|
|
186
|
+
const error = {
|
|
187
|
+
error: message,
|
|
188
|
+
...code && { code }
|
|
189
|
+
};
|
|
190
|
+
console.error(JSON.stringify(error, null, 2));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/commands/auth.ts
|
|
194
|
+
async function prompt(question) {
|
|
195
|
+
const rl = createInterface({
|
|
196
|
+
input: process.stdin,
|
|
197
|
+
output: process.stdout
|
|
198
|
+
});
|
|
199
|
+
return new Promise((resolve) => {
|
|
200
|
+
rl.question(question, (answer) => {
|
|
201
|
+
rl.close();
|
|
202
|
+
resolve(answer.trim());
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
async function promptSecret(question) {
|
|
207
|
+
return new Promise((resolve) => {
|
|
208
|
+
process.stdout.write(question);
|
|
209
|
+
const stdin = process.stdin;
|
|
210
|
+
const wasRaw = stdin.isRaw;
|
|
211
|
+
if (stdin.isTTY) {
|
|
212
|
+
stdin.setRawMode(true);
|
|
213
|
+
}
|
|
214
|
+
stdin.resume();
|
|
215
|
+
stdin.setEncoding("utf-8");
|
|
216
|
+
let input = "";
|
|
217
|
+
const onData = (chunk) => {
|
|
218
|
+
for (const char of chunk) {
|
|
219
|
+
if (char === "\n" || char === "\r" || char === "") {
|
|
220
|
+
stdin.removeListener("data", onData);
|
|
221
|
+
if (stdin.isTTY) {
|
|
222
|
+
stdin.setRawMode(wasRaw ?? false);
|
|
223
|
+
}
|
|
224
|
+
stdin.pause();
|
|
225
|
+
process.stdout.write("\n");
|
|
226
|
+
resolve(input);
|
|
227
|
+
return;
|
|
228
|
+
} else if (char === "") {
|
|
229
|
+
process.exit(1);
|
|
230
|
+
} else if (char === "\x7F" || char === "\b") {
|
|
231
|
+
if (input.length > 0) {
|
|
232
|
+
input = input.slice(0, -1);
|
|
233
|
+
process.stdout.write("\b \b");
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
input += char;
|
|
237
|
+
process.stdout.write("*");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
stdin.on("data", onData);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
async function authCommand(options) {
|
|
245
|
+
let apiKey = options.key;
|
|
246
|
+
let baseUrl = options.url;
|
|
247
|
+
if (!apiKey || !baseUrl) {
|
|
248
|
+
console.log(chalk2.bold("\nMikado AI CLI Authentication Setup\n"));
|
|
249
|
+
if (!apiKey) {
|
|
250
|
+
apiKey = await promptSecret("API Key: ");
|
|
251
|
+
}
|
|
252
|
+
if (!baseUrl) {
|
|
253
|
+
const defaultUrl = "https://mikadoai.app";
|
|
254
|
+
const urlInput = await prompt(`Base URL [${defaultUrl}]: `);
|
|
255
|
+
baseUrl = urlInput || defaultUrl;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (!apiKey) {
|
|
259
|
+
if (options.json) {
|
|
260
|
+
errorJson("API key is required", "MISSING_API_KEY");
|
|
261
|
+
} else {
|
|
262
|
+
console.error(chalk2.red("Error: API key is required"));
|
|
263
|
+
}
|
|
264
|
+
process.exit(2);
|
|
265
|
+
}
|
|
266
|
+
if (!baseUrl) {
|
|
267
|
+
baseUrl = "https://mikadoai.app";
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
const client = new MikadoClient({ apiKey, baseUrl });
|
|
271
|
+
const whoami = await client.whoami();
|
|
272
|
+
saveConfig({
|
|
273
|
+
api_key: apiKey,
|
|
274
|
+
base_url: baseUrl
|
|
275
|
+
});
|
|
276
|
+
if (options.json) {
|
|
277
|
+
outputJson({
|
|
278
|
+
success: true,
|
|
279
|
+
...whoami
|
|
280
|
+
});
|
|
281
|
+
} else {
|
|
282
|
+
console.log(chalk2.green("\n\u2713 Authentication successful!"));
|
|
283
|
+
renderWhoami(whoami);
|
|
284
|
+
console.log(chalk2.gray(`Config saved to ~/.mikado/config.json`));
|
|
285
|
+
}
|
|
286
|
+
} catch (error) {
|
|
287
|
+
if (options.json) {
|
|
288
|
+
errorJson(error instanceof Error ? error.message : "Authentication failed", "AUTH_FAILED");
|
|
289
|
+
} else {
|
|
290
|
+
console.error(chalk2.red("\n\u2717 Authentication failed:"));
|
|
291
|
+
console.error(chalk2.red(` ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
292
|
+
}
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/commands/submit.ts
|
|
298
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
299
|
+
import chalk3 from "chalk";
|
|
300
|
+
import ora from "ora";
|
|
301
|
+
async function readInput(filePath) {
|
|
302
|
+
if (filePath === "-") {
|
|
303
|
+
return new Promise((resolve, reject) => {
|
|
304
|
+
let data = "";
|
|
305
|
+
process.stdin.setEncoding("utf-8");
|
|
306
|
+
process.stdin.on("data", (chunk) => {
|
|
307
|
+
data += chunk;
|
|
308
|
+
});
|
|
309
|
+
process.stdin.on("end", () => resolve(data));
|
|
310
|
+
process.stdin.on("error", reject);
|
|
311
|
+
});
|
|
312
|
+
} else {
|
|
313
|
+
return readFileSync2(filePath, "utf-8");
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async function submitCommand(filePath, options) {
|
|
317
|
+
const config = loadConfig();
|
|
318
|
+
if (!config) {
|
|
319
|
+
if (options.json) {
|
|
320
|
+
errorJson("Not authenticated. Run: mikado auth", "NOT_AUTHENTICATED");
|
|
321
|
+
} else {
|
|
322
|
+
console.error(chalk3.red("Error: Not authenticated"));
|
|
323
|
+
console.error(chalk3.yellow("Run: mikado auth"));
|
|
324
|
+
}
|
|
325
|
+
process.exit(1);
|
|
326
|
+
}
|
|
327
|
+
const client = new MikadoClient({
|
|
328
|
+
apiKey: config.api_key,
|
|
329
|
+
baseUrl: config.base_url
|
|
330
|
+
});
|
|
331
|
+
let content;
|
|
332
|
+
try {
|
|
333
|
+
content = await readInput(filePath);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
if (options.json) {
|
|
336
|
+
errorJson(
|
|
337
|
+
`Failed to read file: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
338
|
+
"FILE_READ_ERROR"
|
|
339
|
+
);
|
|
340
|
+
} else {
|
|
341
|
+
console.error(chalk3.red("Error: Failed to read file"));
|
|
342
|
+
console.error(chalk3.red(` ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
343
|
+
}
|
|
344
|
+
process.exit(2);
|
|
345
|
+
}
|
|
346
|
+
if (!content || content.trim().length === 0) {
|
|
347
|
+
if (options.json) {
|
|
348
|
+
errorJson("File is empty", "EMPTY_FILE");
|
|
349
|
+
} else {
|
|
350
|
+
console.error(chalk3.red("Error: File is empty"));
|
|
351
|
+
}
|
|
352
|
+
process.exit(2);
|
|
353
|
+
}
|
|
354
|
+
let submitResult;
|
|
355
|
+
try {
|
|
356
|
+
submitResult = await client.submit(content, {
|
|
357
|
+
campaign: options.campaign,
|
|
358
|
+
filename: filePath !== "-" ? filePath : void 0
|
|
359
|
+
});
|
|
360
|
+
} catch (error) {
|
|
361
|
+
if (options.json) {
|
|
362
|
+
errorJson(
|
|
363
|
+
`Failed to submit: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
364
|
+
"SUBMIT_FAILED"
|
|
365
|
+
);
|
|
366
|
+
} else {
|
|
367
|
+
console.error(chalk3.red("Error: Failed to submit transcript"));
|
|
368
|
+
console.error(chalk3.red(` ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
369
|
+
}
|
|
370
|
+
process.exit(1);
|
|
371
|
+
}
|
|
372
|
+
if (!options.wait) {
|
|
373
|
+
if (options.json) {
|
|
374
|
+
outputJson(submitResult);
|
|
375
|
+
} else {
|
|
376
|
+
console.log(chalk3.green("\u2713 Submitted successfully"));
|
|
377
|
+
console.log(` Job ID: ${submitResult.job_id}`);
|
|
378
|
+
console.log(` Conversation: ${submitResult.conversation_id}`);
|
|
379
|
+
console.log(` Status: ${submitResult.status}`);
|
|
380
|
+
console.log();
|
|
381
|
+
console.log(chalk3.gray("Check status with: mikado status " + submitResult.job_id));
|
|
382
|
+
}
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const spinner = options.json ? null : ora("Processing transcript...").start();
|
|
386
|
+
const timeoutMs = options.timeout ? options.timeout * 1e3 : 3e5;
|
|
387
|
+
try {
|
|
388
|
+
const finalStatus = await pollJob(client, submitResult.job_id, {
|
|
389
|
+
timeout: timeoutMs,
|
|
390
|
+
onUpdate: (status) => {
|
|
391
|
+
if (spinner) {
|
|
392
|
+
const statusText = status.status.toLowerCase();
|
|
393
|
+
spinner.text = `Processing transcript... (${statusText})`;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
if (spinner) {
|
|
398
|
+
spinner.stop();
|
|
399
|
+
}
|
|
400
|
+
if (finalStatus.status === "FAILED") {
|
|
401
|
+
if (options.json) {
|
|
402
|
+
errorJson(
|
|
403
|
+
finalStatus.error_message || "Processing failed",
|
|
404
|
+
"PROCESSING_FAILED"
|
|
405
|
+
);
|
|
406
|
+
} else {
|
|
407
|
+
console.error(chalk3.red("\n\u2717 Processing failed:"));
|
|
408
|
+
console.error(chalk3.red(` ${finalStatus.error_message || "Unknown error"}`));
|
|
409
|
+
}
|
|
410
|
+
process.exit(3);
|
|
411
|
+
}
|
|
412
|
+
const conversation = await client.getConversation(submitResult.conversation_id);
|
|
413
|
+
if (options.json) {
|
|
414
|
+
outputJson(conversation);
|
|
415
|
+
} else {
|
|
416
|
+
renderSubmitResult(conversation);
|
|
417
|
+
}
|
|
418
|
+
} catch (error) {
|
|
419
|
+
if (spinner) {
|
|
420
|
+
spinner.fail("Processing failed");
|
|
421
|
+
}
|
|
422
|
+
if (error instanceof Error && error.message.includes("timed out")) {
|
|
423
|
+
if (options.json) {
|
|
424
|
+
errorJson("Processing timed out", "TIMEOUT");
|
|
425
|
+
} else {
|
|
426
|
+
console.error(chalk3.red("\n\u2717 Processing timed out"));
|
|
427
|
+
console.error(chalk3.yellow(` Check status later with: mikado status ${submitResult.job_id}`));
|
|
428
|
+
}
|
|
429
|
+
process.exit(4);
|
|
430
|
+
} else {
|
|
431
|
+
if (options.json) {
|
|
432
|
+
errorJson(
|
|
433
|
+
error instanceof Error ? error.message : "Unknown error",
|
|
434
|
+
"POLLING_FAILED"
|
|
435
|
+
);
|
|
436
|
+
} else {
|
|
437
|
+
console.error(chalk3.red("\n\u2717 Error:"));
|
|
438
|
+
console.error(chalk3.red(` ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
439
|
+
}
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// src/commands/status.ts
|
|
446
|
+
import chalk4 from "chalk";
|
|
447
|
+
async function statusCommand(jobId, options) {
|
|
448
|
+
const config = loadConfig();
|
|
449
|
+
if (!config) {
|
|
450
|
+
if (options.json) {
|
|
451
|
+
errorJson("Not authenticated. Run: mikado auth", "NOT_AUTHENTICATED");
|
|
452
|
+
} else {
|
|
453
|
+
console.error(chalk4.red("Error: Not authenticated"));
|
|
454
|
+
console.error(chalk4.yellow("Run: mikado auth"));
|
|
455
|
+
}
|
|
456
|
+
process.exit(1);
|
|
457
|
+
}
|
|
458
|
+
const client = new MikadoClient({
|
|
459
|
+
apiKey: config.api_key,
|
|
460
|
+
baseUrl: config.base_url
|
|
461
|
+
});
|
|
462
|
+
try {
|
|
463
|
+
const status = await client.getJobStatus(jobId);
|
|
464
|
+
if (options.json) {
|
|
465
|
+
outputJson(status);
|
|
466
|
+
} else {
|
|
467
|
+
renderJobStatus(status);
|
|
468
|
+
}
|
|
469
|
+
} catch (error) {
|
|
470
|
+
if (options.json) {
|
|
471
|
+
errorJson(
|
|
472
|
+
error instanceof Error ? error.message : "Failed to fetch job status",
|
|
473
|
+
"STATUS_FAILED"
|
|
474
|
+
);
|
|
475
|
+
} else {
|
|
476
|
+
console.error(chalk4.red("Error: Failed to fetch job status"));
|
|
477
|
+
console.error(chalk4.red(` ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
478
|
+
}
|
|
479
|
+
process.exit(1);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/commands/result.ts
|
|
484
|
+
import chalk5 from "chalk";
|
|
485
|
+
async function resultCommand(conversationId, options) {
|
|
486
|
+
const config = loadConfig();
|
|
487
|
+
if (!config) {
|
|
488
|
+
if (options.json) {
|
|
489
|
+
errorJson("Not authenticated. Run: mikado auth", "NOT_AUTHENTICATED");
|
|
490
|
+
} else {
|
|
491
|
+
console.error(chalk5.red("Error: Not authenticated"));
|
|
492
|
+
console.error(chalk5.yellow("Run: mikado auth"));
|
|
493
|
+
}
|
|
494
|
+
process.exit(1);
|
|
495
|
+
}
|
|
496
|
+
const client = new MikadoClient({
|
|
497
|
+
apiKey: config.api_key,
|
|
498
|
+
baseUrl: config.base_url
|
|
499
|
+
});
|
|
500
|
+
try {
|
|
501
|
+
const conversation = await client.getConversation(conversationId);
|
|
502
|
+
if (options.json) {
|
|
503
|
+
outputJson(conversation);
|
|
504
|
+
} else {
|
|
505
|
+
renderSubmitResult(conversation);
|
|
506
|
+
}
|
|
507
|
+
} catch (error) {
|
|
508
|
+
if (options.json) {
|
|
509
|
+
errorJson(
|
|
510
|
+
error instanceof Error ? error.message : "Failed to fetch conversation",
|
|
511
|
+
"RESULT_FAILED"
|
|
512
|
+
);
|
|
513
|
+
} else {
|
|
514
|
+
console.error(chalk5.red("Error: Failed to fetch conversation"));
|
|
515
|
+
console.error(chalk5.red(` ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
516
|
+
}
|
|
517
|
+
process.exit(1);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// src/commands/campaigns.ts
|
|
522
|
+
import chalk6 from "chalk";
|
|
523
|
+
async function campaignsCommand(options) {
|
|
524
|
+
const config = loadConfig();
|
|
525
|
+
if (!config) {
|
|
526
|
+
if (options.json) {
|
|
527
|
+
errorJson("Not authenticated. Run: mikado auth", "NOT_AUTHENTICATED");
|
|
528
|
+
} else {
|
|
529
|
+
console.error(chalk6.red("Error: Not authenticated"));
|
|
530
|
+
console.error(chalk6.yellow("Run: mikado auth"));
|
|
531
|
+
}
|
|
532
|
+
process.exit(1);
|
|
533
|
+
}
|
|
534
|
+
const client = new MikadoClient({
|
|
535
|
+
apiKey: config.api_key,
|
|
536
|
+
baseUrl: config.base_url
|
|
537
|
+
});
|
|
538
|
+
try {
|
|
539
|
+
const campaigns = await client.listCampaigns();
|
|
540
|
+
if (options.json) {
|
|
541
|
+
outputJson(campaigns);
|
|
542
|
+
} else {
|
|
543
|
+
renderCampaigns(campaigns);
|
|
544
|
+
}
|
|
545
|
+
} catch (error) {
|
|
546
|
+
if (options.json) {
|
|
547
|
+
errorJson(
|
|
548
|
+
error instanceof Error ? error.message : "Failed to fetch campaigns",
|
|
549
|
+
"CAMPAIGNS_FAILED"
|
|
550
|
+
);
|
|
551
|
+
} else {
|
|
552
|
+
console.error(chalk6.red("Error: Failed to fetch campaigns"));
|
|
553
|
+
console.error(chalk6.red(` ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
554
|
+
}
|
|
555
|
+
process.exit(1);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// src/index.ts
|
|
560
|
+
var program = new Command();
|
|
561
|
+
program.name("mikado").description("Mikado CLI - conversation data extraction").version("0.1.0");
|
|
562
|
+
program.option("--json", "Output results in JSON format");
|
|
563
|
+
program.command("auth").description("Authenticate with Mikado API").option("--key <api-key>", "API key (or use MIKADO_API_KEY env var)").option("--url <base-url>", "Base URL (default: https://mikadoai.app)").action(async (options) => {
|
|
564
|
+
await authCommand({
|
|
565
|
+
key: options.key,
|
|
566
|
+
url: options.url,
|
|
567
|
+
json: program.opts().json
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
program.command("submit <file>").description('Submit a transcript file for processing (use "-" to read from stdin)').option("-c, --campaign <id>", "Target campaign (short_id, UUID, or name)").option("--no-wait", "Do not wait for processing to complete").option("--timeout <seconds>", "Polling timeout in seconds (default: 300)", parseInt).action(async (file, options) => {
|
|
571
|
+
await submitCommand(file, {
|
|
572
|
+
campaign: options.campaign,
|
|
573
|
+
wait: options.wait,
|
|
574
|
+
timeout: options.timeout,
|
|
575
|
+
json: program.opts().json
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
program.command("status <job-id>").description("Check the status of a processing job").action(async (jobId) => {
|
|
579
|
+
await statusCommand(jobId, {
|
|
580
|
+
json: program.opts().json
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
program.command("result <conversation-id>").description("Get full results for a completed conversation").action(async (conversationId) => {
|
|
584
|
+
await resultCommand(conversationId, {
|
|
585
|
+
json: program.opts().json
|
|
586
|
+
});
|
|
587
|
+
});
|
|
588
|
+
program.command("campaigns").description("List available campaigns").action(async () => {
|
|
589
|
+
await campaignsCommand({
|
|
590
|
+
json: program.opts().json
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
program.command("mcp").description("Start MCP stdio server (requires MIKADO_API_KEY env var)").action(async () => {
|
|
594
|
+
const { startMcpServer } = await import("./mcp.js");
|
|
595
|
+
await startMcpServer();
|
|
596
|
+
});
|
|
597
|
+
program.parse();
|
package/dist/mcp.d.ts
ADDED