olakai-cli 0.1.1 → 0.1.3

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/dist/index.js CHANGED
@@ -157,6 +157,425 @@ async function getCurrentUser() {
157
157
  }
158
158
  return await response.json();
159
159
  }
160
+ async function listAgents(options) {
161
+ const token = getValidToken();
162
+ if (!token) {
163
+ throw new Error("Not logged in. Run 'olakai login' first.");
164
+ }
165
+ const params = new URLSearchParams();
166
+ if (options?.includeKpis) {
167
+ params.set("includeKpis", "true");
168
+ }
169
+ const url = `${getBaseUrl()}/api/config/agents${params.toString() ? `?${params}` : ""}`;
170
+ const response = await fetch(url, {
171
+ headers: {
172
+ Authorization: `Bearer ${token}`
173
+ }
174
+ });
175
+ if (!response.ok) {
176
+ if (response.status === 401) {
177
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
178
+ }
179
+ const error = await response.json();
180
+ throw new Error(error.error || "Failed to list agents");
181
+ }
182
+ const data = await response.json();
183
+ return data.agents;
184
+ }
185
+ async function getAgent(id) {
186
+ const token = getValidToken();
187
+ if (!token) {
188
+ throw new Error("Not logged in. Run 'olakai login' first.");
189
+ }
190
+ const response = await fetch(`${getBaseUrl()}/api/config/agents/${id}`, {
191
+ headers: {
192
+ Authorization: `Bearer ${token}`
193
+ }
194
+ });
195
+ if (!response.ok) {
196
+ if (response.status === 401) {
197
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
198
+ }
199
+ if (response.status === 404) {
200
+ throw new Error("Agent not found");
201
+ }
202
+ const error = await response.json();
203
+ throw new Error(error.error || "Failed to get agent");
204
+ }
205
+ return await response.json();
206
+ }
207
+ async function createAgent(payload) {
208
+ const token = getValidToken();
209
+ if (!token) {
210
+ throw new Error("Not logged in. Run 'olakai login' first.");
211
+ }
212
+ const response = await fetch(`${getBaseUrl()}/api/config/agents`, {
213
+ method: "POST",
214
+ headers: {
215
+ Authorization: `Bearer ${token}`,
216
+ "Content-Type": "application/json"
217
+ },
218
+ body: JSON.stringify(payload)
219
+ });
220
+ if (!response.ok) {
221
+ if (response.status === 401) {
222
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
223
+ }
224
+ if (response.status === 409) {
225
+ throw new Error("An agent with this name already exists");
226
+ }
227
+ const error = await response.json();
228
+ throw new Error(error.error || "Failed to create agent");
229
+ }
230
+ return await response.json();
231
+ }
232
+ async function updateAgent(id, payload) {
233
+ const token = getValidToken();
234
+ if (!token) {
235
+ throw new Error("Not logged in. Run 'olakai login' first.");
236
+ }
237
+ const response = await fetch(`${getBaseUrl()}/api/config/agents/${id}`, {
238
+ method: "PUT",
239
+ headers: {
240
+ Authorization: `Bearer ${token}`,
241
+ "Content-Type": "application/json"
242
+ },
243
+ body: JSON.stringify(payload)
244
+ });
245
+ if (!response.ok) {
246
+ if (response.status === 401) {
247
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
248
+ }
249
+ if (response.status === 404) {
250
+ throw new Error("Agent not found");
251
+ }
252
+ if (response.status === 409) {
253
+ throw new Error("An agent with this name already exists");
254
+ }
255
+ const error = await response.json();
256
+ throw new Error(error.error || "Failed to update agent");
257
+ }
258
+ return await response.json();
259
+ }
260
+ async function deleteAgent(id) {
261
+ const token = getValidToken();
262
+ if (!token) {
263
+ throw new Error("Not logged in. Run 'olakai login' first.");
264
+ }
265
+ const response = await fetch(`${getBaseUrl()}/api/config/agents/${id}`, {
266
+ method: "DELETE",
267
+ headers: {
268
+ Authorization: `Bearer ${token}`
269
+ }
270
+ });
271
+ if (!response.ok) {
272
+ if (response.status === 401) {
273
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
274
+ }
275
+ if (response.status === 404) {
276
+ throw new Error("Agent not found");
277
+ }
278
+ const error = await response.json();
279
+ throw new Error(error.error || "Failed to delete agent");
280
+ }
281
+ }
282
+ async function listWorkflows(options) {
283
+ const token = getValidToken();
284
+ if (!token) {
285
+ throw new Error("Not logged in. Run 'olakai login' first.");
286
+ }
287
+ const params = new URLSearchParams();
288
+ if (options?.includeAgents) {
289
+ params.set("includeAgents", "true");
290
+ }
291
+ if (options?.includeInactive) {
292
+ params.set("includeInactive", "true");
293
+ }
294
+ const url = `${getBaseUrl()}/api/config/workflows${params.toString() ? `?${params}` : ""}`;
295
+ const response = await fetch(url, {
296
+ headers: {
297
+ Authorization: `Bearer ${token}`
298
+ }
299
+ });
300
+ if (!response.ok) {
301
+ if (response.status === 401) {
302
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
303
+ }
304
+ const error = await response.json();
305
+ throw new Error(error.error || "Failed to list workflows");
306
+ }
307
+ const data = await response.json();
308
+ return data.workflows;
309
+ }
310
+ async function getWorkflow(id) {
311
+ const token = getValidToken();
312
+ if (!token) {
313
+ throw new Error("Not logged in. Run 'olakai login' first.");
314
+ }
315
+ const response = await fetch(`${getBaseUrl()}/api/config/workflows/${id}`, {
316
+ headers: {
317
+ Authorization: `Bearer ${token}`
318
+ }
319
+ });
320
+ if (!response.ok) {
321
+ if (response.status === 401) {
322
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
323
+ }
324
+ if (response.status === 404) {
325
+ throw new Error("Workflow not found");
326
+ }
327
+ const error = await response.json();
328
+ throw new Error(error.error || "Failed to get workflow");
329
+ }
330
+ return await response.json();
331
+ }
332
+ async function createWorkflow(payload) {
333
+ const token = getValidToken();
334
+ if (!token) {
335
+ throw new Error("Not logged in. Run 'olakai login' first.");
336
+ }
337
+ const response = await fetch(`${getBaseUrl()}/api/config/workflows`, {
338
+ method: "POST",
339
+ headers: {
340
+ Authorization: `Bearer ${token}`,
341
+ "Content-Type": "application/json"
342
+ },
343
+ body: JSON.stringify(payload)
344
+ });
345
+ if (!response.ok) {
346
+ if (response.status === 401) {
347
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
348
+ }
349
+ if (response.status === 409) {
350
+ throw new Error("A workflow with this name already exists");
351
+ }
352
+ const error = await response.json();
353
+ throw new Error(error.error || "Failed to create workflow");
354
+ }
355
+ return await response.json();
356
+ }
357
+ async function updateWorkflow(id, payload) {
358
+ const token = getValidToken();
359
+ if (!token) {
360
+ throw new Error("Not logged in. Run 'olakai login' first.");
361
+ }
362
+ const response = await fetch(`${getBaseUrl()}/api/config/workflows/${id}`, {
363
+ method: "PUT",
364
+ headers: {
365
+ Authorization: `Bearer ${token}`,
366
+ "Content-Type": "application/json"
367
+ },
368
+ body: JSON.stringify(payload)
369
+ });
370
+ if (!response.ok) {
371
+ if (response.status === 401) {
372
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
373
+ }
374
+ if (response.status === 404) {
375
+ throw new Error("Workflow not found");
376
+ }
377
+ if (response.status === 409) {
378
+ throw new Error("A workflow with this name already exists");
379
+ }
380
+ const error = await response.json();
381
+ throw new Error(error.error || "Failed to update workflow");
382
+ }
383
+ return await response.json();
384
+ }
385
+ async function deleteWorkflow(id) {
386
+ const token = getValidToken();
387
+ if (!token) {
388
+ throw new Error("Not logged in. Run 'olakai login' first.");
389
+ }
390
+ const response = await fetch(`${getBaseUrl()}/api/config/workflows/${id}`, {
391
+ method: "DELETE",
392
+ headers: {
393
+ Authorization: `Bearer ${token}`
394
+ }
395
+ });
396
+ if (!response.ok) {
397
+ if (response.status === 401) {
398
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
399
+ }
400
+ if (response.status === 404) {
401
+ throw new Error("Workflow not found");
402
+ }
403
+ const error = await response.json();
404
+ throw new Error(error.error || "Failed to delete workflow");
405
+ }
406
+ }
407
+ async function listKpis(options) {
408
+ const token = getValidToken();
409
+ if (!token) {
410
+ throw new Error("Not logged in. Run 'olakai login' first.");
411
+ }
412
+ const params = new URLSearchParams();
413
+ if (options?.agentId) {
414
+ params.set("agentId", options.agentId);
415
+ }
416
+ if (options?.includeInactive) {
417
+ params.set("includeInactive", "true");
418
+ }
419
+ const url = `${getBaseUrl()}/api/config/kpis${params.toString() ? `?${params}` : ""}`;
420
+ const response = await fetch(url, {
421
+ headers: {
422
+ Authorization: `Bearer ${token}`
423
+ }
424
+ });
425
+ if (!response.ok) {
426
+ if (response.status === 401) {
427
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
428
+ }
429
+ const error = await response.json();
430
+ throw new Error(error.error || "Failed to list KPIs");
431
+ }
432
+ const data = await response.json();
433
+ return data.kpiDefinitions;
434
+ }
435
+ async function getKpi(id) {
436
+ const token = getValidToken();
437
+ if (!token) {
438
+ throw new Error("Not logged in. Run 'olakai login' first.");
439
+ }
440
+ const response = await fetch(`${getBaseUrl()}/api/config/kpis/${id}`, {
441
+ headers: {
442
+ Authorization: `Bearer ${token}`
443
+ }
444
+ });
445
+ if (!response.ok) {
446
+ if (response.status === 401) {
447
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
448
+ }
449
+ if (response.status === 404) {
450
+ throw new Error("KPI definition not found");
451
+ }
452
+ const error = await response.json();
453
+ throw new Error(error.error || "Failed to get KPI");
454
+ }
455
+ return await response.json();
456
+ }
457
+ async function createKpi(payload) {
458
+ const token = getValidToken();
459
+ if (!token) {
460
+ throw new Error("Not logged in. Run 'olakai login' first.");
461
+ }
462
+ const response = await fetch(`${getBaseUrl()}/api/config/kpis`, {
463
+ method: "POST",
464
+ headers: {
465
+ Authorization: `Bearer ${token}`,
466
+ "Content-Type": "application/json"
467
+ },
468
+ body: JSON.stringify(payload)
469
+ });
470
+ if (!response.ok) {
471
+ if (response.status === 401) {
472
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
473
+ }
474
+ if (response.status === 409) {
475
+ throw new Error("A KPI definition with this name already exists");
476
+ }
477
+ const error = await response.json();
478
+ throw new Error(error.error || "Failed to create KPI");
479
+ }
480
+ return await response.json();
481
+ }
482
+ async function updateKpi(id, payload) {
483
+ const token = getValidToken();
484
+ if (!token) {
485
+ throw new Error("Not logged in. Run 'olakai login' first.");
486
+ }
487
+ const response = await fetch(`${getBaseUrl()}/api/config/kpis/${id}`, {
488
+ method: "PUT",
489
+ headers: {
490
+ Authorization: `Bearer ${token}`,
491
+ "Content-Type": "application/json"
492
+ },
493
+ body: JSON.stringify(payload)
494
+ });
495
+ if (!response.ok) {
496
+ if (response.status === 401) {
497
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
498
+ }
499
+ if (response.status === 404) {
500
+ throw new Error("KPI definition not found");
501
+ }
502
+ if (response.status === 409) {
503
+ throw new Error("A KPI definition with this name already exists");
504
+ }
505
+ const error = await response.json();
506
+ throw new Error(error.error || "Failed to update KPI");
507
+ }
508
+ return await response.json();
509
+ }
510
+ async function deleteKpi(id) {
511
+ const token = getValidToken();
512
+ if (!token) {
513
+ throw new Error("Not logged in. Run 'olakai login' first.");
514
+ }
515
+ const response = await fetch(`${getBaseUrl()}/api/config/kpis/${id}`, {
516
+ method: "DELETE",
517
+ headers: {
518
+ Authorization: `Bearer ${token}`
519
+ }
520
+ });
521
+ if (!response.ok) {
522
+ if (response.status === 401) {
523
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
524
+ }
525
+ if (response.status === 404) {
526
+ throw new Error("KPI definition not found");
527
+ }
528
+ const error = await response.json();
529
+ throw new Error(error.error || "Failed to delete KPI");
530
+ }
531
+ }
532
+ async function getKpiContextVariables(agentId) {
533
+ const token = getValidToken();
534
+ if (!token) {
535
+ throw new Error("Not logged in. Run 'olakai login' first.");
536
+ }
537
+ const params = new URLSearchParams();
538
+ if (agentId) {
539
+ params.set("agentId", agentId);
540
+ }
541
+ const url = `${getBaseUrl()}/api/config/kpis/context-variables${params.toString() ? `?${params}` : ""}`;
542
+ const response = await fetch(url, {
543
+ headers: {
544
+ Authorization: `Bearer ${token}`
545
+ }
546
+ });
547
+ if (!response.ok) {
548
+ if (response.status === 401) {
549
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
550
+ }
551
+ const error = await response.json();
552
+ throw new Error(error.error || "Failed to get context variables");
553
+ }
554
+ const data = await response.json();
555
+ return data.contextVariables;
556
+ }
557
+ async function validateKpiFormula(formula, agentId) {
558
+ const token = getValidToken();
559
+ if (!token) {
560
+ throw new Error("Not logged in. Run 'olakai login' first.");
561
+ }
562
+ const response = await fetch(`${getBaseUrl()}/api/config/kpis/validate`, {
563
+ method: "POST",
564
+ headers: {
565
+ Authorization: `Bearer ${token}`,
566
+ "Content-Type": "application/json"
567
+ },
568
+ body: JSON.stringify({ formula, agentId })
569
+ });
570
+ if (!response.ok) {
571
+ if (response.status === 401) {
572
+ throw new Error("Session expired. Run 'olakai login' to authenticate again.");
573
+ }
574
+ const error = await response.json();
575
+ throw new Error(error.error || "Failed to validate formula");
576
+ }
577
+ return await response.json();
578
+ }
160
579
 
161
580
  // src/commands/login.ts
162
581
  var POLL_INTERVAL_MS = 5e3;
@@ -262,6 +681,633 @@ async function whoamiCommand() {
262
681
  }
263
682
  }
264
683
 
684
+ // src/commands/agents.ts
685
+ function formatAgentTable(agents) {
686
+ if (agents.length === 0) {
687
+ console.log("No agents found.");
688
+ return;
689
+ }
690
+ const headers = ["ID", "NAME", "ROLE", "WORKFLOW", "API KEY"];
691
+ const rows = agents.map((agent) => [
692
+ agent.id.slice(0, 12) + "...",
693
+ agent.name.slice(0, 30),
694
+ agent.role,
695
+ agent.workflowId ? agent.workflowId.slice(0, 12) + "..." : "-",
696
+ agent.apiKey ? agent.apiKey.isActive ? "Active" : "Inactive" : "None"
697
+ ]);
698
+ const widths = headers.map(
699
+ (h, i) => Math.max(h.length, ...rows.map((r) => r[i].length))
700
+ );
701
+ console.log(headers.map((h, i) => h.padEnd(widths[i])).join(" "));
702
+ console.log(widths.map((w) => "-".repeat(w)).join(" "));
703
+ for (const row of rows) {
704
+ console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(" "));
705
+ }
706
+ }
707
+ function formatAgentDetail(agent) {
708
+ console.log(`ID: ${agent.id}`);
709
+ console.log(`Name: ${agent.name}`);
710
+ console.log(`Description: ${agent.description || "-"}`);
711
+ console.log(`Role: ${agent.role}`);
712
+ console.log(`Source: ${agent.source}`);
713
+ console.log(`Category: ${agent.category || "-"}`);
714
+ console.log(`Workflow ID: ${agent.workflowId || "-"}`);
715
+ if (agent.workflow) {
716
+ console.log(`Workflow: ${agent.workflow.name}`);
717
+ }
718
+ console.log("");
719
+ console.log("API Key:");
720
+ if (agent.apiKey) {
721
+ console.log(` ID: ${agent.apiKey.id}`);
722
+ if (agent.apiKey.key) {
723
+ console.log(` Key: ${agent.apiKey.key}`);
724
+ } else {
725
+ console.log(` Key: ${agent.apiKey.keyMasked}`);
726
+ }
727
+ console.log(` Status: ${agent.apiKey.isActive ? "Active" : "Inactive"}`);
728
+ } else {
729
+ console.log(" None");
730
+ }
731
+ if (agent.kpiDefinitions && agent.kpiDefinitions.length > 0) {
732
+ console.log("");
733
+ console.log("KPI Definitions:");
734
+ for (const kpi of agent.kpiDefinitions) {
735
+ console.log(` - ${kpi.name} (${kpi.type})`);
736
+ }
737
+ }
738
+ }
739
+ async function listCommand(options) {
740
+ try {
741
+ const agents = await listAgents({ includeKpis: options.includeKpis });
742
+ if (options.json) {
743
+ console.log(JSON.stringify(agents, null, 2));
744
+ } else {
745
+ formatAgentTable(agents);
746
+ }
747
+ } catch (error) {
748
+ console.error(
749
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
750
+ );
751
+ process.exit(1);
752
+ }
753
+ }
754
+ async function getCommand(id, options) {
755
+ try {
756
+ const agent = await getAgent(id);
757
+ if (options.json) {
758
+ console.log(JSON.stringify(agent, null, 2));
759
+ } else {
760
+ formatAgentDetail(agent);
761
+ }
762
+ } catch (error) {
763
+ console.error(
764
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
765
+ );
766
+ process.exit(1);
767
+ }
768
+ }
769
+ async function createCommand(options) {
770
+ try {
771
+ if (!options.name) {
772
+ console.error("Error: --name is required");
773
+ process.exit(1);
774
+ }
775
+ const agent = await createAgent({
776
+ name: options.name,
777
+ description: options.description || "",
778
+ role: options.role || "WORKER",
779
+ workflowId: options.workflow,
780
+ createApiKey: options.withApiKey || false,
781
+ category: options.category
782
+ });
783
+ if (options.json) {
784
+ console.log(JSON.stringify(agent, null, 2));
785
+ } else {
786
+ console.log("Agent created successfully!");
787
+ console.log("");
788
+ formatAgentDetail(agent);
789
+ if (agent.apiKey?.key) {
790
+ console.log("");
791
+ console.log(
792
+ "IMPORTANT: Save your API key now. It will not be shown again."
793
+ );
794
+ }
795
+ }
796
+ } catch (error) {
797
+ console.error(
798
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
799
+ );
800
+ process.exit(1);
801
+ }
802
+ }
803
+ async function updateCommand(id, options) {
804
+ try {
805
+ const payload = {};
806
+ if (options.name !== void 0) payload.name = options.name;
807
+ if (options.description !== void 0)
808
+ payload.description = options.description;
809
+ if (options.role !== void 0)
810
+ payload.role = options.role;
811
+ if (options.workflow !== void 0) payload.workflowId = options.workflow;
812
+ if (options.category !== void 0) payload.category = options.category;
813
+ if (Object.keys(payload).length === 0) {
814
+ console.error("Error: At least one field to update is required");
815
+ process.exit(1);
816
+ }
817
+ const agent = await updateAgent(id, payload);
818
+ if (options.json) {
819
+ console.log(JSON.stringify(agent, null, 2));
820
+ } else {
821
+ console.log("Agent updated successfully!");
822
+ console.log("");
823
+ formatAgentDetail(agent);
824
+ }
825
+ } catch (error) {
826
+ console.error(
827
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
828
+ );
829
+ process.exit(1);
830
+ }
831
+ }
832
+ async function deleteCommand(id, options) {
833
+ try {
834
+ if (!options.force) {
835
+ console.log("Are you sure you want to delete this agent?");
836
+ console.log("Use --force to confirm deletion.");
837
+ process.exit(1);
838
+ }
839
+ await deleteAgent(id);
840
+ console.log("Agent deleted successfully.");
841
+ } catch (error) {
842
+ console.error(
843
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
844
+ );
845
+ process.exit(1);
846
+ }
847
+ }
848
+ function registerAgentsCommand(program2) {
849
+ const agents = program2.command("agents").description("Manage agents");
850
+ agents.command("list").description("List all agents").option("--json", "Output as JSON").option("--include-kpis", "Include KPI definitions").action(listCommand);
851
+ agents.command("get <id>").description("Get agent details").option("--json", "Output as JSON").action(getCommand);
852
+ agents.command("create").description("Create a new agent").requiredOption("--name <name>", "Agent name").option("--description <description>", "Agent description").option("--role <role>", "Agent role (WORKER or COORDINATOR)", "WORKER").option("--workflow <id>", "Workflow ID to assign").option("--with-api-key", "Create an API key for this agent").option("--category <category>", "Agent category").option("--json", "Output as JSON").action(createCommand);
853
+ agents.command("update <id>").description("Update an agent").option("--name <name>", "Agent name").option("--description <description>", "Agent description").option("--role <role>", "Agent role (WORKER or COORDINATOR)").option("--workflow <id>", "Workflow ID to assign").option("--category <category>", "Agent category").option("--json", "Output as JSON").action(updateCommand);
854
+ agents.command("delete <id>").description("Delete an agent").option("--force", "Skip confirmation").action(deleteCommand);
855
+ }
856
+
857
+ // src/commands/workflows.ts
858
+ function formatWorkflowTable(workflows) {
859
+ if (workflows.length === 0) {
860
+ console.log("No workflows found.");
861
+ return;
862
+ }
863
+ const headers = ["ID", "NAME", "AGENTS", "STATUS"];
864
+ const rows = workflows.map((wf) => [
865
+ wf.id.slice(0, 12) + "...",
866
+ wf.name.slice(0, 30),
867
+ wf.agentCount.toString(),
868
+ wf.isActive ? "Active" : "Inactive"
869
+ ]);
870
+ const widths = headers.map(
871
+ (h, i) => Math.max(h.length, ...rows.map((r) => r[i].length))
872
+ );
873
+ console.log(headers.map((h, i) => h.padEnd(widths[i])).join(" "));
874
+ console.log(widths.map((w) => "-".repeat(w)).join(" "));
875
+ for (const row of rows) {
876
+ console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(" "));
877
+ }
878
+ }
879
+ function formatWorkflowDetail(workflow) {
880
+ console.log(`ID: ${workflow.id}`);
881
+ console.log(`Name: ${workflow.name}`);
882
+ console.log(`Description: ${workflow.description || "-"}`);
883
+ console.log(`Status: ${workflow.isActive ? "Active" : "Inactive"}`);
884
+ console.log(`Agents: ${workflow.agentCount}`);
885
+ if (workflow.createdAt) {
886
+ console.log(`Created: ${new Date(workflow.createdAt).toISOString()}`);
887
+ }
888
+ if (workflow.updatedAt) {
889
+ console.log(`Updated: ${new Date(workflow.updatedAt).toISOString()}`);
890
+ }
891
+ if (workflow.agents && workflow.agents.length > 0) {
892
+ console.log("");
893
+ console.log("Agents:");
894
+ for (const agent of workflow.agents) {
895
+ const apiKeyStatus = agent.apiKey ? agent.apiKey.isActive ? "API Key: Active" : "API Key: Inactive" : "No API Key";
896
+ console.log(` - ${agent.name} (${agent.role}) - ${apiKeyStatus}`);
897
+ }
898
+ }
899
+ }
900
+ async function listCommand2(options) {
901
+ try {
902
+ const workflows = await listWorkflows({
903
+ includeAgents: options.includeAgents,
904
+ includeInactive: options.includeInactive
905
+ });
906
+ if (options.json) {
907
+ console.log(JSON.stringify(workflows, null, 2));
908
+ } else {
909
+ formatWorkflowTable(workflows);
910
+ }
911
+ } catch (error) {
912
+ console.error(
913
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
914
+ );
915
+ process.exit(1);
916
+ }
917
+ }
918
+ async function getCommand2(id, options) {
919
+ try {
920
+ const workflow = await getWorkflow(id);
921
+ if (options.json) {
922
+ console.log(JSON.stringify(workflow, null, 2));
923
+ } else {
924
+ formatWorkflowDetail(workflow);
925
+ }
926
+ } catch (error) {
927
+ console.error(
928
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
929
+ );
930
+ process.exit(1);
931
+ }
932
+ }
933
+ async function createCommand2(options) {
934
+ try {
935
+ if (!options.name) {
936
+ console.error("Error: --name is required");
937
+ process.exit(1);
938
+ }
939
+ const workflow = await createWorkflow({
940
+ name: options.name,
941
+ description: options.description
942
+ });
943
+ if (options.json) {
944
+ console.log(JSON.stringify(workflow, null, 2));
945
+ } else {
946
+ console.log("Workflow created successfully!");
947
+ console.log("");
948
+ formatWorkflowDetail(workflow);
949
+ }
950
+ } catch (error) {
951
+ console.error(
952
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
953
+ );
954
+ process.exit(1);
955
+ }
956
+ }
957
+ async function updateCommand2(id, options) {
958
+ try {
959
+ const payload = {};
960
+ if (options.name !== void 0) payload.name = options.name;
961
+ if (options.description !== void 0)
962
+ payload.description = options.description;
963
+ if (options.active) payload.isActive = true;
964
+ if (options.inactive) payload.isActive = false;
965
+ if (Object.keys(payload).length === 0) {
966
+ console.error("Error: At least one field to update is required");
967
+ process.exit(1);
968
+ }
969
+ const workflow = await updateWorkflow(id, payload);
970
+ if (options.json) {
971
+ console.log(JSON.stringify(workflow, null, 2));
972
+ } else {
973
+ console.log("Workflow updated successfully!");
974
+ console.log("");
975
+ formatWorkflowDetail(workflow);
976
+ }
977
+ } catch (error) {
978
+ console.error(
979
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
980
+ );
981
+ process.exit(1);
982
+ }
983
+ }
984
+ async function deleteCommand2(id, options) {
985
+ try {
986
+ if (!options.force) {
987
+ console.log("Are you sure you want to delete this workflow?");
988
+ console.log("Use --force to confirm deletion.");
989
+ process.exit(1);
990
+ }
991
+ await deleteWorkflow(id);
992
+ console.log("Workflow deleted successfully.");
993
+ } catch (error) {
994
+ console.error(
995
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
996
+ );
997
+ process.exit(1);
998
+ }
999
+ }
1000
+ function registerWorkflowsCommand(program2) {
1001
+ const workflows = program2.command("workflows").description("Manage workflows");
1002
+ workflows.command("list").description("List all workflows").option("--json", "Output as JSON").option("--include-agents", "Include agent details").option("--include-inactive", "Include inactive workflows").action(listCommand2);
1003
+ workflows.command("get <id>").description("Get workflow details").option("--json", "Output as JSON").action(getCommand2);
1004
+ workflows.command("create").description("Create a new workflow").requiredOption("--name <name>", "Workflow name").option("--description <description>", "Workflow description").option("--json", "Output as JSON").action(createCommand2);
1005
+ workflows.command("update <id>").description("Update a workflow").option("--name <name>", "Workflow name").option("--description <description>", "Workflow description").option("--active", "Set workflow as active").option("--inactive", "Set workflow as inactive").option("--json", "Output as JSON").action(updateCommand2);
1006
+ workflows.command("delete <id>").description("Delete a workflow").option("--force", "Skip confirmation").action(deleteCommand2);
1007
+ }
1008
+
1009
+ // src/commands/kpis.ts
1010
+ var AGGREGATION_METHODS = [
1011
+ "SUM",
1012
+ "AVERAGE",
1013
+ "COUNT",
1014
+ "MIN",
1015
+ "MAX",
1016
+ "LATEST"
1017
+ ];
1018
+ var CALCULATOR_IDS = ["formula", "classifier", "llm-data"];
1019
+ function formatKpiTable(kpis) {
1020
+ if (kpis.length === 0) {
1021
+ console.log("No KPI definitions found.");
1022
+ return;
1023
+ }
1024
+ const headers = ["ID", "NAME", "CALCULATOR", "AGGREGATION", "STATUS"];
1025
+ const rows = kpis.map((kpi) => [
1026
+ kpi.id.slice(0, 12) + "...",
1027
+ kpi.name.slice(0, 25),
1028
+ kpi.calculatorId,
1029
+ kpi.defaultAggregationMethod,
1030
+ kpi.isActive ? "Active" : "Inactive"
1031
+ ]);
1032
+ const widths = headers.map(
1033
+ (h, i) => Math.max(h.length, ...rows.map((r) => r[i].length))
1034
+ );
1035
+ console.log(headers.map((h, i) => h.padEnd(widths[i])).join(" "));
1036
+ console.log(widths.map((w) => "-".repeat(w)).join(" "));
1037
+ for (const row of rows) {
1038
+ console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(" "));
1039
+ }
1040
+ }
1041
+ function formatKpiDetail(kpi) {
1042
+ console.log(`ID: ${kpi.id}`);
1043
+ console.log(`Name: ${kpi.name}`);
1044
+ console.log(`Description: ${kpi.description || "-"}`);
1045
+ console.log(`Type: ${kpi.type}`);
1046
+ console.log(`Category: ${kpi.category || "-"}`);
1047
+ console.log(`Agent ID: ${kpi.agentId || "-"}`);
1048
+ console.log(`Calculator: ${kpi.calculatorId}`);
1049
+ console.log(`Aggregation: ${kpi.defaultAggregationMethod}`);
1050
+ console.log(`Unit: ${kpi.unit || "-"}`);
1051
+ console.log(`Status: ${kpi.isActive ? "Active" : "Inactive"}`);
1052
+ if (kpi.calculatorParams) {
1053
+ console.log("");
1054
+ console.log("Calculator Parameters:");
1055
+ console.log(JSON.stringify(kpi.calculatorParams, null, 2));
1056
+ }
1057
+ if (kpi.createdAt) {
1058
+ console.log("");
1059
+ console.log(`Created: ${new Date(kpi.createdAt).toISOString()}`);
1060
+ }
1061
+ if (kpi.updatedAt) {
1062
+ console.log(`Updated: ${new Date(kpi.updatedAt).toISOString()}`);
1063
+ }
1064
+ }
1065
+ function formatContextVariablesTable(variables) {
1066
+ if (variables.length === 0) {
1067
+ console.log("No context variables found.");
1068
+ return;
1069
+ }
1070
+ const headers = ["NAME", "TYPE", "SOURCE", "DESCRIPTION"];
1071
+ const rows = variables.map((v) => [
1072
+ v.name,
1073
+ v.type,
1074
+ v.source,
1075
+ v.description.slice(0, 50)
1076
+ ]);
1077
+ const widths = headers.map(
1078
+ (h, i) => Math.max(h.length, ...rows.map((r) => r[i].length))
1079
+ );
1080
+ console.log(headers.map((h, i) => h.padEnd(widths[i])).join(" "));
1081
+ console.log(widths.map((w) => "-".repeat(w)).join(" "));
1082
+ for (const row of rows) {
1083
+ console.log(row.map((cell, i) => cell.padEnd(widths[i])).join(" "));
1084
+ }
1085
+ }
1086
+ async function listCommand3(options) {
1087
+ try {
1088
+ const kpis = await listKpis({
1089
+ agentId: options.agentId,
1090
+ includeInactive: options.includeInactive
1091
+ });
1092
+ if (options.json) {
1093
+ console.log(JSON.stringify(kpis, null, 2));
1094
+ } else {
1095
+ formatKpiTable(kpis);
1096
+ }
1097
+ } catch (error) {
1098
+ console.error(
1099
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
1100
+ );
1101
+ process.exit(1);
1102
+ }
1103
+ }
1104
+ async function getCommand3(id, options) {
1105
+ try {
1106
+ const kpi = await getKpi(id);
1107
+ if (options.json) {
1108
+ console.log(JSON.stringify(kpi, null, 2));
1109
+ } else {
1110
+ formatKpiDetail(kpi);
1111
+ }
1112
+ } catch (error) {
1113
+ console.error(
1114
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
1115
+ );
1116
+ process.exit(1);
1117
+ }
1118
+ }
1119
+ async function createCommand3(options) {
1120
+ try {
1121
+ if (!options.name) {
1122
+ console.error("Error: --name is required");
1123
+ process.exit(1);
1124
+ }
1125
+ if (!options.calculatorId) {
1126
+ console.error("Error: --calculator-id is required");
1127
+ console.error(`Valid values: ${CALCULATOR_IDS.join(", ")}`);
1128
+ process.exit(1);
1129
+ }
1130
+ if (!CALCULATOR_IDS.includes(options.calculatorId)) {
1131
+ console.error(`Error: Invalid calculator ID "${options.calculatorId}"`);
1132
+ console.error(`Valid values: ${CALCULATOR_IDS.join(", ")}`);
1133
+ process.exit(1);
1134
+ }
1135
+ let calculatorParams;
1136
+ if (options.calculatorId === "formula") {
1137
+ if (!options.formula) {
1138
+ console.error(
1139
+ "Error: --formula is required when calculator-id is 'formula'"
1140
+ );
1141
+ process.exit(1);
1142
+ }
1143
+ calculatorParams = { formula: options.formula };
1144
+ }
1145
+ let aggregation;
1146
+ if (options.aggregation) {
1147
+ const upperAggregation = options.aggregation.toUpperCase();
1148
+ if (!AGGREGATION_METHODS.includes(upperAggregation)) {
1149
+ console.error(`Error: Invalid aggregation method "${options.aggregation}"`);
1150
+ console.error(`Valid values: ${AGGREGATION_METHODS.join(", ")}`);
1151
+ process.exit(1);
1152
+ }
1153
+ aggregation = upperAggregation;
1154
+ }
1155
+ const payload = {
1156
+ name: options.name,
1157
+ calculatorId: options.calculatorId,
1158
+ description: options.description,
1159
+ type: options.type === "PREDEFINED" ? "PREDEFINED" : "USER_DEFINED",
1160
+ category: options.category,
1161
+ agentId: options.agentId,
1162
+ calculatorParams,
1163
+ unit: options.unit,
1164
+ defaultAggregationMethod: aggregation
1165
+ };
1166
+ const kpi = await createKpi(payload);
1167
+ if (options.json) {
1168
+ console.log(JSON.stringify(kpi, null, 2));
1169
+ } else {
1170
+ console.log("KPI definition created successfully!");
1171
+ console.log("");
1172
+ formatKpiDetail(kpi);
1173
+ }
1174
+ } catch (error) {
1175
+ console.error(
1176
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
1177
+ );
1178
+ process.exit(1);
1179
+ }
1180
+ }
1181
+ async function updateCommand3(id, options) {
1182
+ try {
1183
+ const payload = {};
1184
+ if (options.name !== void 0) payload.name = options.name;
1185
+ if (options.description !== void 0)
1186
+ payload.description = options.description;
1187
+ if (options.category !== void 0) payload.category = options.category;
1188
+ if (options.agentId !== void 0) payload.agentId = options.agentId;
1189
+ if (options.calculatorId !== void 0)
1190
+ payload.calculatorId = options.calculatorId;
1191
+ if (options.unit !== void 0) payload.unit = options.unit;
1192
+ if (options.active) payload.isActive = true;
1193
+ if (options.inactive) payload.isActive = false;
1194
+ if (options.formula !== void 0) {
1195
+ payload.calculatorParams = { formula: options.formula };
1196
+ }
1197
+ if (options.aggregation) {
1198
+ const upperAggregation = options.aggregation.toUpperCase();
1199
+ if (!AGGREGATION_METHODS.includes(upperAggregation)) {
1200
+ console.error(`Error: Invalid aggregation method "${options.aggregation}"`);
1201
+ console.error(`Valid values: ${AGGREGATION_METHODS.join(", ")}`);
1202
+ process.exit(1);
1203
+ }
1204
+ payload.defaultAggregationMethod = upperAggregation;
1205
+ }
1206
+ if (Object.keys(payload).length === 0) {
1207
+ console.error("Error: At least one field to update is required");
1208
+ process.exit(1);
1209
+ }
1210
+ const kpi = await updateKpi(id, payload);
1211
+ if (options.json) {
1212
+ console.log(JSON.stringify(kpi, null, 2));
1213
+ } else {
1214
+ console.log("KPI definition updated successfully!");
1215
+ console.log("");
1216
+ formatKpiDetail(kpi);
1217
+ }
1218
+ } catch (error) {
1219
+ console.error(
1220
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
1221
+ );
1222
+ process.exit(1);
1223
+ }
1224
+ }
1225
+ async function deleteCommand3(id, options) {
1226
+ try {
1227
+ if (!options.force) {
1228
+ console.log("Are you sure you want to delete this KPI definition?");
1229
+ console.log("Use --force to confirm deletion.");
1230
+ process.exit(1);
1231
+ }
1232
+ await deleteKpi(id);
1233
+ console.log("KPI definition deleted successfully.");
1234
+ } catch (error) {
1235
+ console.error(
1236
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
1237
+ );
1238
+ process.exit(1);
1239
+ }
1240
+ }
1241
+ async function contextVariablesCommand(options) {
1242
+ try {
1243
+ const variables = await getKpiContextVariables(options.agentId);
1244
+ if (options.json) {
1245
+ console.log(JSON.stringify(variables, null, 2));
1246
+ } else {
1247
+ console.log("Available context variables for KPI formulas:");
1248
+ console.log("");
1249
+ formatContextVariablesTable(variables);
1250
+ console.log("");
1251
+ console.log(
1252
+ "Use these variable names in your formula expressions, e.g.:"
1253
+ );
1254
+ console.log(" IF(PII detected, 1, 0)");
1255
+ console.log(" Documents count * 10");
1256
+ console.log(' IF(CODE detected AND SECRET detected, "high-risk", "normal")');
1257
+ }
1258
+ } catch (error) {
1259
+ console.error(
1260
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
1261
+ );
1262
+ process.exit(1);
1263
+ }
1264
+ }
1265
+ async function validateCommand(options) {
1266
+ try {
1267
+ if (!options.formula) {
1268
+ console.error("Error: --formula is required");
1269
+ process.exit(1);
1270
+ }
1271
+ const result = await validateKpiFormula(options.formula, options.agentId);
1272
+ if (options.json) {
1273
+ console.log(JSON.stringify(result, null, 2));
1274
+ } else {
1275
+ if (result.valid) {
1276
+ console.log("Formula is valid!");
1277
+ console.log(`Result type: ${result.type || "unknown"}`);
1278
+ } else {
1279
+ console.error("Formula is invalid:");
1280
+ console.error(` ${result.error}`);
1281
+ if (result.charIndex !== void 0) {
1282
+ console.error(` Position: character ${result.charIndex}`);
1283
+ }
1284
+ process.exit(1);
1285
+ }
1286
+ }
1287
+ } catch (error) {
1288
+ console.error(
1289
+ `Error: ${error instanceof Error ? error.message : "Unknown error"}`
1290
+ );
1291
+ process.exit(1);
1292
+ }
1293
+ }
1294
+ function registerKpisCommand(program2) {
1295
+ const kpis = program2.command("kpis").description("Manage KPI definitions");
1296
+ kpis.command("list").description("List all KPI definitions").option("--json", "Output as JSON").option("--agent-id <id>", "Filter by agent ID").option("--include-inactive", "Include inactive KPI definitions").action(listCommand3);
1297
+ kpis.command("get <id>").description("Get KPI definition details").option("--json", "Output as JSON").action(getCommand3);
1298
+ kpis.command("create").description("Create a new KPI definition").requiredOption("--name <name>", "KPI name").requiredOption(
1299
+ "--calculator-id <id>",
1300
+ "Calculator type: formula, classifier, or llm-data"
1301
+ ).option("--description <description>", "KPI description").option("--type <type>", "KPI type: PREDEFINED or USER_DEFINED (default)").option("--category <category>", "KPI category for grouping").option("--agent-id <id>", "Associate KPI with a specific agent").option("--formula <formula>", "Formula expression (required for formula calculator)").option("--unit <unit>", 'Display unit (e.g., "ms", "%", "count")').option(
1302
+ "--aggregation <method>",
1303
+ "Default aggregation: SUM, AVERAGE, COUNT, MIN, MAX, LATEST (default)"
1304
+ ).option("--json", "Output as JSON").action(createCommand3);
1305
+ kpis.command("update <id>").description("Update a KPI definition").option("--name <name>", "KPI name").option("--description <description>", "KPI description").option("--category <category>", "KPI category").option("--agent-id <id>", "Associate with agent").option("--calculator-id <id>", "Calculator type").option("--formula <formula>", "Formula expression").option("--unit <unit>", "Display unit").option("--aggregation <method>", "Default aggregation method").option("--active", "Set KPI as active").option("--inactive", "Set KPI as inactive").option("--json", "Output as JSON").action(updateCommand3);
1306
+ kpis.command("delete <id>").description("Delete a KPI definition").option("--force", "Skip confirmation").action(deleteCommand3);
1307
+ kpis.command("context-variables").description("List available context variables for formulas").option("--json", "Output as JSON").option("--agent-id <id>", "Include agent-specific variables").action(contextVariablesCommand);
1308
+ kpis.command("validate").description("Validate a KPI formula expression").requiredOption("--formula <formula>", "Formula expression to validate").option("--agent-id <id>", "Include agent-specific context").option("--json", "Output as JSON").action(validateCommand);
1309
+ }
1310
+
265
1311
  // src/index.ts
266
1312
  var program = new Command();
267
1313
  program.name("olakai").description("Olakai CLI tool").version("0.1.0").option(
@@ -283,5 +1329,8 @@ program.name("olakai").description("Olakai CLI tool").version("0.1.0").option(
283
1329
  program.command("login").description("Log in to Olakai using browser authentication").action(loginCommand);
284
1330
  program.command("logout").description("Log out from Olakai").action(logoutCommand);
285
1331
  program.command("whoami").description("Show current logged-in user").action(whoamiCommand);
1332
+ registerAgentsCommand(program);
1333
+ registerWorkflowsCommand(program);
1334
+ registerKpisCommand(program);
286
1335
  program.parse();
287
1336
  //# sourceMappingURL=index.js.map