@agentforge-ai/cli 0.4.2 → 0.5.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.
Files changed (67) hide show
  1. package/dist/default/README.md +81 -81
  2. package/dist/default/convex/agents.ts +204 -0
  3. package/dist/default/convex/apiKeys.ts +133 -0
  4. package/dist/default/convex/cronJobs.ts +224 -0
  5. package/dist/default/convex/files.ts +103 -0
  6. package/dist/default/convex/folders.ts +110 -0
  7. package/dist/default/convex/heartbeat.ts +371 -0
  8. package/dist/default/convex/logs.ts +66 -0
  9. package/dist/default/convex/mastraIntegration.ts +184 -0
  10. package/dist/default/convex/mcpConnections.ts +127 -0
  11. package/dist/default/convex/messages.ts +90 -0
  12. package/dist/default/convex/projects.ts +114 -0
  13. package/dist/default/convex/sessions.ts +174 -0
  14. package/dist/default/convex/settings.ts +79 -0
  15. package/dist/default/convex/skills.ts +178 -0
  16. package/dist/default/convex/threads.ts +100 -0
  17. package/dist/default/convex/usage.ts +195 -0
  18. package/dist/default/convex/vault.ts +383 -0
  19. package/dist/default/dashboard/app/main.tsx +7 -3
  20. package/dist/default/dashboard/app/routes/agents.tsx +103 -161
  21. package/dist/default/dashboard/app/routes/chat.tsx +163 -317
  22. package/dist/default/dashboard/app/routes/connections.tsx +247 -386
  23. package/dist/default/dashboard/app/routes/cron.tsx +127 -286
  24. package/dist/default/dashboard/app/routes/files.tsx +184 -167
  25. package/dist/default/dashboard/app/routes/index.tsx +63 -96
  26. package/dist/default/dashboard/app/routes/projects.tsx +106 -225
  27. package/dist/default/dashboard/app/routes/sessions.tsx +87 -253
  28. package/dist/default/dashboard/app/routes/settings.tsx +316 -532
  29. package/dist/default/dashboard/app/routes/skills.tsx +329 -216
  30. package/dist/default/dashboard/app/routes/usage.tsx +107 -150
  31. package/dist/default/dashboard/tsconfig.json +3 -2
  32. package/dist/default/dashboard/vite.config.ts +6 -0
  33. package/dist/index.js +279 -50
  34. package/dist/index.js.map +1 -1
  35. package/package.json +1 -1
  36. package/templates/default/README.md +81 -81
  37. package/templates/default/convex/agents.ts +204 -0
  38. package/templates/default/convex/apiKeys.ts +133 -0
  39. package/templates/default/convex/cronJobs.ts +224 -0
  40. package/templates/default/convex/files.ts +103 -0
  41. package/templates/default/convex/folders.ts +110 -0
  42. package/templates/default/convex/heartbeat.ts +371 -0
  43. package/templates/default/convex/logs.ts +66 -0
  44. package/templates/default/convex/mastraIntegration.ts +184 -0
  45. package/templates/default/convex/mcpConnections.ts +127 -0
  46. package/templates/default/convex/messages.ts +90 -0
  47. package/templates/default/convex/projects.ts +114 -0
  48. package/templates/default/convex/sessions.ts +174 -0
  49. package/templates/default/convex/settings.ts +79 -0
  50. package/templates/default/convex/skills.ts +178 -0
  51. package/templates/default/convex/threads.ts +100 -0
  52. package/templates/default/convex/usage.ts +195 -0
  53. package/templates/default/convex/vault.ts +383 -0
  54. package/templates/default/dashboard/app/main.tsx +7 -3
  55. package/templates/default/dashboard/app/routes/agents.tsx +103 -161
  56. package/templates/default/dashboard/app/routes/chat.tsx +163 -317
  57. package/templates/default/dashboard/app/routes/connections.tsx +247 -386
  58. package/templates/default/dashboard/app/routes/cron.tsx +127 -286
  59. package/templates/default/dashboard/app/routes/files.tsx +184 -167
  60. package/templates/default/dashboard/app/routes/index.tsx +63 -96
  61. package/templates/default/dashboard/app/routes/projects.tsx +106 -225
  62. package/templates/default/dashboard/app/routes/sessions.tsx +87 -253
  63. package/templates/default/dashboard/app/routes/settings.tsx +316 -532
  64. package/templates/default/dashboard/app/routes/skills.tsx +329 -216
  65. package/templates/default/dashboard/app/routes/usage.tsx +107 -150
  66. package/templates/default/dashboard/tsconfig.json +3 -2
  67. package/templates/default/dashboard/vite.config.ts +6 -0
package/dist/index.js CHANGED
@@ -1,4 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
2
8
 
3
9
  // src/index.ts
4
10
  import { Command } from "commander";
@@ -295,11 +301,22 @@ async function deployProject(options) {
295
301
  }
296
302
 
297
303
  // src/lib/convex-client.ts
298
- import { ConvexHttpClient } from "convex/browser";
299
304
  import fs4 from "fs-extra";
300
305
  import path4 from "path";
306
+ function safeCwd() {
307
+ try {
308
+ return process.cwd();
309
+ } catch {
310
+ return null;
311
+ }
312
+ }
301
313
  function getConvexUrl() {
302
- const cwd = process.cwd();
314
+ const cwd = safeCwd();
315
+ if (!cwd) {
316
+ throw new Error(
317
+ "Current directory does not exist or is not accessible.\nPlease navigate to a valid AgentForge project directory and try again."
318
+ );
319
+ }
303
320
  const envFiles = [".env.local", ".env", ".env.production"];
304
321
  for (const envFile of envFiles) {
305
322
  const envPath = path4.join(cwd, envFile);
@@ -323,7 +340,8 @@ function getConvexUrl() {
323
340
  "CONVEX_URL not found. Run `npx convex dev` first, or set CONVEX_URL in your .env file."
324
341
  );
325
342
  }
326
- function createClient() {
343
+ async function createClient() {
344
+ const { ConvexHttpClient } = await import("convex/browser");
327
345
  const url = getConvexUrl();
328
346
  return new ConvexHttpClient(url);
329
347
  }
@@ -334,6 +352,10 @@ async function safeCall(fn, errorMessage) {
334
352
  if (error2.message?.includes("CONVEX_URL not found")) {
335
353
  console.error("\n\u274C Not connected to Convex.");
336
354
  console.error(" Run `npx convex dev` in your project directory first.\n");
355
+ } else if (error2.message?.includes("Current directory does not exist")) {
356
+ console.error(`
357
+ \u274C ${error2.message}
358
+ `);
337
359
  } else if (error2.message?.includes("fetch failed") || error2.message?.includes("ECONNREFUSED")) {
338
360
  console.error("\n\u274C Cannot reach Convex deployment.");
339
361
  console.error(" Make sure `npx convex dev` is running.\n");
@@ -424,7 +446,7 @@ function prompt(question) {
424
446
  function registerAgentsCommand(program2) {
425
447
  const agents = program2.command("agents").description("Manage agents");
426
448
  agents.command("list").description("List all agents").option("--active", "Show only active agents").option("--json", "Output as JSON").action(async (opts) => {
427
- const client = createClient();
449
+ const client = await createClient();
428
450
  const result = await safeCall(
429
451
  () => client.query("agents:list", {}),
430
452
  "Failed to list agents"
@@ -460,7 +482,7 @@ function registerAgentsCommand(program2) {
460
482
  }
461
483
  const provider = model.includes(":") ? model.split(":")[0] : "openai";
462
484
  const agentId = name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
463
- const client = createClient();
485
+ const client = await createClient();
464
486
  await safeCall(
465
487
  () => client.mutation("agents:create", {
466
488
  id: agentId,
@@ -475,7 +497,7 @@ function registerAgentsCommand(program2) {
475
497
  success(`Agent "${name}" created with ID: ${agentId}`);
476
498
  });
477
499
  agents.command("inspect").argument("<id>", "Agent ID").description("Show detailed agent information").action(async (id) => {
478
- const client = createClient();
500
+ const client = await createClient();
479
501
  const agent = await safeCall(
480
502
  () => client.query("agents:getByAgentId", { id }),
481
503
  "Failed to fetch agent"
@@ -503,7 +525,7 @@ function registerAgentsCommand(program2) {
503
525
  `);
504
526
  });
505
527
  agents.command("edit").argument("<id>", "Agent ID").option("--name <name>", "New name").option("--model <model>", "New model").option("--instructions <text>", "New instructions").description("Edit an agent").action(async (id, opts) => {
506
- const client = createClient();
528
+ const client = await createClient();
507
529
  const agent = await safeCall(
508
530
  () => client.query("agents:getByAgentId", { id }),
509
531
  "Failed to fetch agent"
@@ -549,7 +571,7 @@ function registerAgentsCommand(program2) {
549
571
  return;
550
572
  }
551
573
  }
552
- const client = createClient();
574
+ const client = await createClient();
553
575
  const agent = await safeCall(
554
576
  () => client.query("agents:getByAgentId", { id }),
555
577
  "Failed to fetch agent"
@@ -565,7 +587,7 @@ function registerAgentsCommand(program2) {
565
587
  success(`Agent "${id}" deleted.`);
566
588
  });
567
589
  agents.command("enable").argument("<id>", "Agent ID").description("Enable an agent").action(async (id) => {
568
- const client = createClient();
590
+ const client = await createClient();
569
591
  const agent = await safeCall(() => client.query("agents:getByAgentId", { id }), "Failed to fetch agent");
570
592
  if (!agent) {
571
593
  error(`Agent "${id}" not found.`);
@@ -575,7 +597,7 @@ function registerAgentsCommand(program2) {
575
597
  success(`Agent "${id}" enabled.`);
576
598
  });
577
599
  agents.command("disable").argument("<id>", "Agent ID").description("Disable an agent").action(async (id) => {
578
- const client = createClient();
600
+ const client = await createClient();
579
601
  const agent = await safeCall(() => client.query("agents:getByAgentId", { id }), "Failed to fetch agent");
580
602
  if (!agent) {
581
603
  error(`Agent "${id}" not found.`);
@@ -590,7 +612,7 @@ function registerAgentsCommand(program2) {
590
612
  import readline2 from "readline";
591
613
  function registerChatCommand(program2) {
592
614
  program2.command("chat").argument("[agent-id]", "Agent ID to chat with").option("-s, --session <id>", "Resume an existing session").description("Start an interactive chat session with an agent").action(async (agentId, opts) => {
593
- const client = createClient();
615
+ const client = await createClient();
594
616
  if (!agentId && !opts.session) {
595
617
  const agents = await safeCall(() => client.query("agents:list", {}), "Failed to list agents");
596
618
  if (!agents || agents.length === 0) {
@@ -683,7 +705,7 @@ function registerChatCommand(program2) {
683
705
  function registerSessionsCommand(program2) {
684
706
  const sessions = program2.command("sessions").description("Manage sessions");
685
707
  sessions.command("list").option("--status <status>", "Filter by status (active, ended)").option("--json", "Output as JSON").description("List all sessions").action(async (opts) => {
686
- const client = createClient();
708
+ const client = await createClient();
687
709
  const result = await safeCall(() => client.query("sessions:list", {}), "Failed to list sessions");
688
710
  if (opts.json) {
689
711
  console.log(JSON.stringify(result, null, 2));
@@ -706,7 +728,7 @@ function registerSessionsCommand(program2) {
706
728
  })));
707
729
  });
708
730
  sessions.command("inspect").argument("<id>", "Session ID").description("Show session details").action(async (id) => {
709
- const client = createClient();
731
+ const client = await createClient();
710
732
  const session = await safeCall(() => client.query("sessions:getById", { id }), "Failed to fetch session");
711
733
  if (!session) {
712
734
  error(`Session "${id}" not found.`);
@@ -717,7 +739,7 @@ function registerSessionsCommand(program2) {
717
739
  details({ ID: s._id, Name: s.name, Agent: s.agentId, Status: s.status, Started: formatDate(s.startedAt), "Last Activity": formatDate(s.lastActivityAt) });
718
740
  });
719
741
  sessions.command("end").argument("<id>", "Session ID").description("End an active session").action(async (id) => {
720
- const client = createClient();
742
+ const client = await createClient();
721
743
  await safeCall(() => client.mutation("sessions:update", { _id: id, status: "ended" }), "Failed to end session");
722
744
  success(`Session "${id}" ended.`);
723
745
  });
@@ -725,7 +747,7 @@ function registerSessionsCommand(program2) {
725
747
  function registerThreadsCommand(program2) {
726
748
  const threads = program2.command("threads").description("Manage conversation threads");
727
749
  threads.command("list").option("--agent <id>", "Filter by agent ID").option("--json", "Output as JSON").description("List all threads").action(async (opts) => {
728
- const client = createClient();
750
+ const client = await createClient();
729
751
  const args = opts.agent ? { agentId: opts.agent } : {};
730
752
  const result = await safeCall(() => client.query("threads:list", args), "Failed to list threads");
731
753
  if (opts.json) {
@@ -747,7 +769,7 @@ function registerThreadsCommand(program2) {
747
769
  })));
748
770
  });
749
771
  threads.command("inspect").argument("<id>", "Thread ID").description("Show thread messages").action(async (id) => {
750
- const client = createClient();
772
+ const client = await createClient();
751
773
  const messages = await safeCall(() => client.query("messages:listByThread", { threadId: id }), "Failed to fetch messages");
752
774
  header(`Thread: ${id}`);
753
775
  const items = messages || [];
@@ -762,7 +784,7 @@ function registerThreadsCommand(program2) {
762
784
  console.log();
763
785
  });
764
786
  threads.command("delete").argument("<id>", "Thread ID").description("Delete a thread and its messages").action(async (id) => {
765
- const client = createClient();
787
+ const client = await createClient();
766
788
  await safeCall(() => client.mutation("threads:remove", { _id: id }), "Failed to delete thread");
767
789
  success(`Thread "${id}" deleted.`);
768
790
  });
@@ -782,7 +804,7 @@ function prompt2(q) {
782
804
  function registerSkillsCommand(program2) {
783
805
  const skills = program2.command("skills").description("Manage agent skills");
784
806
  skills.command("list").option("--installed", "Show only installed skills").option("--json", "Output as JSON").description("List all skills").action(async (opts) => {
785
- const client = createClient();
807
+ const client = await createClient();
786
808
  const result = await safeCall(() => client.query("skills:list", {}), "Failed to list skills");
787
809
  if (opts.json) {
788
810
  console.log(JSON.stringify(result, null, 2));
@@ -894,7 +916,7 @@ Edit \`skills/${name}/config.json\` to customize.
894
916
  info(`Edit skills/${name}/index.ts to implement your tool logic.`);
895
917
  });
896
918
  skills.command("install").argument("<name>", "Skill name to install").description("Install a skill").action(async (name) => {
897
- const client = createClient();
919
+ const client = await createClient();
898
920
  await safeCall(
899
921
  () => client.mutation("skills:create", {
900
922
  name,
@@ -915,7 +937,7 @@ Edit \`skills/${name}/config.json\` to customize.
915
937
  success(`Skill "${name}" removed from disk.`);
916
938
  }
917
939
  }
918
- const client = createClient();
940
+ const client = await createClient();
919
941
  try {
920
942
  const skills2 = await client.query("skills:list", {});
921
943
  const skill = skills2.find((s) => s.name === name);
@@ -961,7 +983,7 @@ function prompt3(q) {
961
983
  function registerCronCommand(program2) {
962
984
  const cron = program2.command("cron").description("Manage cron jobs");
963
985
  cron.command("list").option("--json", "Output as JSON").description("List all cron jobs").action(async (opts) => {
964
- const client = createClient();
986
+ const client = await createClient();
965
987
  const result = await safeCall(() => client.query("cronJobs:list", {}), "Failed to list cron jobs");
966
988
  if (opts.json) {
967
989
  console.log(JSON.stringify(result, null, 2));
@@ -992,7 +1014,7 @@ function registerCronCommand(program2) {
992
1014
  error("All fields are required.");
993
1015
  process.exit(1);
994
1016
  }
995
- const client = createClient();
1017
+ const client = await createClient();
996
1018
  await safeCall(
997
1019
  () => client.mutation("cronJobs:create", { name, schedule, agentId, action, isEnabled: true }),
998
1020
  "Failed to create cron job"
@@ -1000,17 +1022,17 @@ function registerCronCommand(program2) {
1000
1022
  success(`Cron job "${name}" created.`);
1001
1023
  });
1002
1024
  cron.command("delete").argument("<id>", "Cron job ID").description("Delete a cron job").action(async (id) => {
1003
- const client = createClient();
1025
+ const client = await createClient();
1004
1026
  await safeCall(() => client.mutation("cronJobs:remove", { _id: id }), "Failed to delete");
1005
1027
  success(`Cron job "${id}" deleted.`);
1006
1028
  });
1007
1029
  cron.command("enable").argument("<id>", "Cron job ID").description("Enable a cron job").action(async (id) => {
1008
- const client = createClient();
1030
+ const client = await createClient();
1009
1031
  await safeCall(() => client.mutation("cronJobs:update", { _id: id, isEnabled: true }), "Failed");
1010
1032
  success(`Cron job "${id}" enabled.`);
1011
1033
  });
1012
1034
  cron.command("disable").argument("<id>", "Cron job ID").description("Disable a cron job").action(async (id) => {
1013
- const client = createClient();
1035
+ const client = await createClient();
1014
1036
  await safeCall(() => client.mutation("cronJobs:update", { _id: id, isEnabled: false }), "Failed");
1015
1037
  success(`Cron job "${id}" disabled.`);
1016
1038
  });
@@ -1028,7 +1050,7 @@ function prompt4(q) {
1028
1050
  function registerMcpCommand(program2) {
1029
1051
  const mcp = program2.command("mcp").description("Manage MCP connections");
1030
1052
  mcp.command("list").option("--json", "Output as JSON").description("List all MCP connections").action(async (opts) => {
1031
- const client = createClient();
1053
+ const client = await createClient();
1032
1054
  const result = await safeCall(() => client.query("mcpConnections:list", {}), "Failed to list connections");
1033
1055
  if (opts.json) {
1034
1056
  console.log(JSON.stringify(result, null, 2));
@@ -1057,7 +1079,7 @@ function registerMcpCommand(program2) {
1057
1079
  error("All fields required.");
1058
1080
  process.exit(1);
1059
1081
  }
1060
- const client = createClient();
1082
+ const client = await createClient();
1061
1083
  await safeCall(
1062
1084
  () => client.mutation("mcpConnections:create", {
1063
1085
  name,
@@ -1071,13 +1093,13 @@ function registerMcpCommand(program2) {
1071
1093
  success(`MCP connection "${name}" added.`);
1072
1094
  });
1073
1095
  mcp.command("remove").argument("<id>", "Connection ID").description("Remove an MCP connection").action(async (id) => {
1074
- const client = createClient();
1096
+ const client = await createClient();
1075
1097
  await safeCall(() => client.mutation("mcpConnections:remove", { _id: id }), "Failed");
1076
1098
  success(`Connection "${id}" removed.`);
1077
1099
  });
1078
1100
  mcp.command("test").argument("<id>", "Connection ID").description("Test an MCP connection").action(async (id) => {
1079
1101
  info(`Testing connection "${id}"...`);
1080
- const client = createClient();
1102
+ const client = await createClient();
1081
1103
  const conns = await safeCall(() => client.query("mcpConnections:list", {}), "Failed");
1082
1104
  const conn = conns.find((c) => c._id === id || c._id?.endsWith(id));
1083
1105
  if (!conn) {
@@ -1102,12 +1124,12 @@ function registerMcpCommand(program2) {
1102
1124
  }
1103
1125
  });
1104
1126
  mcp.command("enable").argument("<id>", "Connection ID").description("Enable a connection").action(async (id) => {
1105
- const client = createClient();
1127
+ const client = await createClient();
1106
1128
  await safeCall(() => client.mutation("mcpConnections:update", { _id: id, isEnabled: true }), "Failed");
1107
1129
  success(`Connection "${id}" enabled.`);
1108
1130
  });
1109
1131
  mcp.command("disable").argument("<id>", "Connection ID").description("Disable a connection").action(async (id) => {
1110
- const client = createClient();
1132
+ const client = await createClient();
1111
1133
  await safeCall(() => client.mutation("mcpConnections:update", { _id: id, isEnabled: false }), "Failed");
1112
1134
  success(`Connection "${id}" disabled.`);
1113
1135
  });
@@ -1119,7 +1141,7 @@ import path6 from "path";
1119
1141
  function registerFilesCommand(program2) {
1120
1142
  const files = program2.command("files").description("Manage files");
1121
1143
  files.command("list").argument("[folder]", "Folder ID to list files from").option("--json", "Output as JSON").description("List files").action(async (folder, opts) => {
1122
- const client = createClient();
1144
+ const client = await createClient();
1123
1145
  const args = folder ? { folderId: folder } : {};
1124
1146
  const result = await safeCall(() => client.query("files:list", args), "Failed to list files");
1125
1147
  if (opts.json) {
@@ -1165,7 +1187,7 @@ function registerFilesCommand(program2) {
1165
1187
  ".xml": "text/xml"
1166
1188
  };
1167
1189
  const mimeType = mimeTypes[ext] || "application/octet-stream";
1168
- const client = createClient();
1190
+ const client = await createClient();
1169
1191
  await safeCall(
1170
1192
  () => client.mutation("files:create", {
1171
1193
  name,
@@ -1180,13 +1202,13 @@ function registerFilesCommand(program2) {
1180
1202
  info("Note: File content storage requires Convex file storage or R2 integration.");
1181
1203
  });
1182
1204
  files.command("delete").argument("<id>", "File ID").description("Delete a file").action(async (id) => {
1183
- const client = createClient();
1205
+ const client = await createClient();
1184
1206
  await safeCall(() => client.mutation("files:remove", { _id: id }), "Failed to delete file");
1185
1207
  success(`File "${id}" deleted.`);
1186
1208
  });
1187
1209
  const folders = program2.command("folders").description("Manage folders");
1188
1210
  folders.command("list").option("--json", "Output as JSON").description("List all folders").action(async (opts) => {
1189
- const client = createClient();
1211
+ const client = await createClient();
1190
1212
  const result = await safeCall(() => client.query("folders:list", {}), "Failed to list folders");
1191
1213
  if (opts.json) {
1192
1214
  console.log(JSON.stringify(result, null, 2));
@@ -1206,7 +1228,7 @@ function registerFilesCommand(program2) {
1206
1228
  })));
1207
1229
  });
1208
1230
  folders.command("create").argument("<name>", "Folder name").option("--parent <id>", "Parent folder ID").description("Create a folder").action(async (name, opts) => {
1209
- const client = createClient();
1231
+ const client = await createClient();
1210
1232
  await safeCall(
1211
1233
  () => client.mutation("folders:create", { name, parentId: opts.parent }),
1212
1234
  "Failed to create folder"
@@ -1214,7 +1236,7 @@ function registerFilesCommand(program2) {
1214
1236
  success(`Folder "${name}" created.`);
1215
1237
  });
1216
1238
  folders.command("delete").argument("<id>", "Folder ID").description("Delete a folder").action(async (id) => {
1217
- const client = createClient();
1239
+ const client = await createClient();
1218
1240
  await safeCall(() => client.mutation("folders:remove", { _id: id }), "Failed to delete folder");
1219
1241
  success(`Folder "${id}" deleted.`);
1220
1242
  });
@@ -1237,7 +1259,7 @@ function prompt5(q) {
1237
1259
  function registerProjectsCommand(program2) {
1238
1260
  const projects = program2.command("projects").description("Manage projects and workspaces");
1239
1261
  projects.command("list").option("--json", "Output as JSON").description("List all projects").action(async (opts) => {
1240
- const client = createClient();
1262
+ const client = await createClient();
1241
1263
  const result = await safeCall(() => client.query("projects:list", {}), "Failed to list projects");
1242
1264
  if (opts.json) {
1243
1265
  console.log(JSON.stringify(result, null, 2));
@@ -1259,7 +1281,7 @@ function registerProjectsCommand(program2) {
1259
1281
  });
1260
1282
  projects.command("create").argument("<name>", "Project name").option("-d, --description <desc>", "Project description").description("Create a new project").action(async (name, opts) => {
1261
1283
  const description = opts.description || await prompt5("Description (optional): ");
1262
- const client = createClient();
1284
+ const client = await createClient();
1263
1285
  await safeCall(
1264
1286
  () => client.mutation("projects:create", { name, description, status: "active" }),
1265
1287
  "Failed to create project"
@@ -1267,7 +1289,7 @@ function registerProjectsCommand(program2) {
1267
1289
  success(`Project "${name}" created.`);
1268
1290
  });
1269
1291
  projects.command("inspect").argument("<id>", "Project ID").description("Show project details").action(async (id) => {
1270
- const client = createClient();
1292
+ const client = await createClient();
1271
1293
  const projects2 = await safeCall(() => client.query("projects:list", {}), "Failed");
1272
1294
  const project = projects2.find((p) => p._id === id || p._id?.endsWith(id));
1273
1295
  if (!project) {
@@ -1292,12 +1314,12 @@ function registerProjectsCommand(program2) {
1292
1314
  return;
1293
1315
  }
1294
1316
  }
1295
- const client = createClient();
1317
+ const client = await createClient();
1296
1318
  await safeCall(() => client.mutation("projects:remove", { _id: id }), "Failed");
1297
1319
  success(`Project "${id}" deleted.`);
1298
1320
  });
1299
1321
  projects.command("switch").argument("<id>", "Project ID to switch to").description("Set the active project").action(async (id) => {
1300
- const client = createClient();
1322
+ const client = await createClient();
1301
1323
  const projects2 = await safeCall(() => client.query("projects:list", {}), "Failed");
1302
1324
  const project = projects2.find((p) => p._id === id || p._id?.endsWith(id));
1303
1325
  if (!project) {
@@ -1494,7 +1516,7 @@ function promptSecret(q) {
1494
1516
  function registerVaultCommand(program2) {
1495
1517
  const vault = program2.command("vault").description("Manage secrets securely");
1496
1518
  vault.command("list").option("--json", "Output as JSON").description("List all stored secrets (values hidden)").action(async (opts) => {
1497
- const client = createClient();
1519
+ const client = await createClient();
1498
1520
  const result = await safeCall(() => client.query("vault:list", {}), "Failed to list secrets");
1499
1521
  if (opts.json) {
1500
1522
  const safe = (result || []).map((s) => ({ ...s, encryptedValue: void 0 }));
@@ -1523,7 +1545,7 @@ function registerVaultCommand(program2) {
1523
1545
  error("Value is required.");
1524
1546
  process.exit(1);
1525
1547
  }
1526
- const client = createClient();
1548
+ const client = await createClient();
1527
1549
  await safeCall(
1528
1550
  () => client.mutation("vault:store", {
1529
1551
  name,
@@ -1536,7 +1558,7 @@ function registerVaultCommand(program2) {
1536
1558
  success(`Secret "${name}" stored securely.`);
1537
1559
  });
1538
1560
  vault.command("get").argument("<name>", "Secret name").option("--reveal", "Show the actual value (use with caution)").description("Retrieve a secret").action(async (name, opts) => {
1539
- const client = createClient();
1561
+ const client = await createClient();
1540
1562
  const result = await safeCall(() => client.query("vault:list", {}), "Failed");
1541
1563
  const secret = (result || []).find((s) => s.name === name);
1542
1564
  if (!secret) {
@@ -1563,7 +1585,7 @@ function registerVaultCommand(program2) {
1563
1585
  return;
1564
1586
  }
1565
1587
  }
1566
- const client = createClient();
1588
+ const client = await createClient();
1567
1589
  const result = await safeCall(() => client.query("vault:list", {}), "Failed");
1568
1590
  const secret = (result || []).find((s) => s.name === name);
1569
1591
  if (!secret) {
@@ -1574,7 +1596,7 @@ function registerVaultCommand(program2) {
1574
1596
  success(`Secret "${name}" deleted.`);
1575
1597
  });
1576
1598
  vault.command("rotate").argument("<name>", "Secret name").description("Rotate a secret (set a new value)").action(async (name) => {
1577
- const client = createClient();
1599
+ const client = await createClient();
1578
1600
  const result = await safeCall(() => client.query("vault:list", {}), "Failed");
1579
1601
  const secret = (result || []).find((s) => s.name === name);
1580
1602
  if (!secret) {
@@ -1594,6 +1616,212 @@ function registerVaultCommand(program2) {
1594
1616
  });
1595
1617
  }
1596
1618
 
1619
+ // src/commands/keys.ts
1620
+ function safeCall2(fn, msg) {
1621
+ return fn().catch((e) => {
1622
+ error(`${msg}: ${e.message}`);
1623
+ process.exit(1);
1624
+ });
1625
+ }
1626
+ function formatDate4(ts) {
1627
+ return new Date(ts).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
1628
+ }
1629
+ function maskKey(key) {
1630
+ if (key.length <= 12) return key.substring(0, 4) + "****";
1631
+ return key.substring(0, 8) + "..." + key.substring(key.length - 4);
1632
+ }
1633
+ function promptSecret2(question) {
1634
+ return new Promise((resolve2) => {
1635
+ const readline10 = __require("readline");
1636
+ if (process.stdin.isTTY) {
1637
+ process.stdout.write(question);
1638
+ process.stdin.setRawMode(true);
1639
+ process.stdin.resume();
1640
+ process.stdin.setEncoding("utf8");
1641
+ let input = "";
1642
+ const onData = (char) => {
1643
+ if (char === "\n" || char === "\r" || char === "") {
1644
+ process.stdin.setRawMode(false);
1645
+ process.stdin.pause();
1646
+ process.stdin.removeListener("data", onData);
1647
+ process.stdout.write("\n");
1648
+ resolve2(input);
1649
+ } else if (char === "") {
1650
+ process.exit(0);
1651
+ } else if (char === "\x7F" || char === "\b") {
1652
+ if (input.length > 0) {
1653
+ input = input.slice(0, -1);
1654
+ process.stdout.write("\b \b");
1655
+ }
1656
+ } else {
1657
+ input += char;
1658
+ process.stdout.write("*");
1659
+ }
1660
+ };
1661
+ process.stdin.on("data", onData);
1662
+ } else {
1663
+ const rl = readline10.createInterface({ input: process.stdin, output: process.stdout });
1664
+ rl.question(question, (ans) => {
1665
+ rl.close();
1666
+ resolve2(ans.trim());
1667
+ });
1668
+ }
1669
+ });
1670
+ }
1671
+ var PROVIDERS = [
1672
+ { id: "openai", name: "OpenAI", prefix: "sk-" },
1673
+ { id: "anthropic", name: "Anthropic", prefix: "sk-ant-" },
1674
+ { id: "openrouter", name: "OpenRouter", prefix: "sk-or-" },
1675
+ { id: "google", name: "Google AI", prefix: "AIza" },
1676
+ { id: "xai", name: "xAI", prefix: "xai-" },
1677
+ { id: "groq", name: "Groq", prefix: "gsk_" },
1678
+ { id: "together", name: "Together AI", prefix: "" },
1679
+ { id: "perplexity", name: "Perplexity", prefix: "pplx-" }
1680
+ ];
1681
+ function registerKeysCommand(program2) {
1682
+ const keys = program2.command("keys").description("Manage AI provider API keys");
1683
+ keys.command("list").option("--provider <provider>", "Filter by provider").option("--json", "Output as JSON").description("List all configured API keys").action(async (opts) => {
1684
+ const client = await createClient();
1685
+ const result = await safeCall2(
1686
+ () => client.query("apiKeys:list", opts.provider ? { provider: opts.provider } : {}),
1687
+ "Failed to list API keys"
1688
+ );
1689
+ const items = result || [];
1690
+ if (opts.json) {
1691
+ const safe = items.map((k) => ({ ...k, encryptedKey: maskKey(k.encryptedKey) }));
1692
+ console.log(JSON.stringify(safe, null, 2));
1693
+ return;
1694
+ }
1695
+ header("API Keys");
1696
+ if (items.length === 0) {
1697
+ info("No API keys configured.");
1698
+ dim(" Add one with: agentforge keys add <provider> [key]");
1699
+ dim("");
1700
+ dim(" Supported providers:");
1701
+ PROVIDERS.forEach((p) => dim(` ${p.id.padEnd(12)} ${p.name}`));
1702
+ return;
1703
+ }
1704
+ table(items.map((k) => ({
1705
+ Provider: k.provider,
1706
+ Name: k.keyName,
1707
+ Key: maskKey(k.encryptedKey),
1708
+ Active: k.isActive ? "\u2713" : "\u2717",
1709
+ Created: formatDate4(k.createdAt),
1710
+ "Last Used": k.lastUsedAt ? formatDate4(k.lastUsedAt) : "Never"
1711
+ })));
1712
+ });
1713
+ keys.command("add").argument("<provider>", `Provider (${PROVIDERS.map((p) => p.id).join(", ")})`).argument("[key]", "API key value (omit for secure prompt)").option("--name <name>", "Key display name").description("Add an AI provider API key").action(async (provider, key, opts) => {
1714
+ const providerInfo = PROVIDERS.find((p) => p.id === provider);
1715
+ if (!providerInfo) {
1716
+ error(`Unknown provider "${provider}". Supported: ${PROVIDERS.map((p) => p.id).join(", ")}`);
1717
+ process.exit(1);
1718
+ }
1719
+ if (!key) {
1720
+ key = await promptSecret2(`Enter ${providerInfo.name} API key: `);
1721
+ }
1722
+ if (!key) {
1723
+ error("API key is required.");
1724
+ process.exit(1);
1725
+ }
1726
+ if (providerInfo.prefix && !key.startsWith(providerInfo.prefix)) {
1727
+ info(`Warning: ${providerInfo.name} keys typically start with "${providerInfo.prefix}".`);
1728
+ }
1729
+ const keyName = opts.name || `${providerInfo.name} Key`;
1730
+ const client = await createClient();
1731
+ await safeCall2(
1732
+ () => client.mutation("apiKeys:create", {
1733
+ provider,
1734
+ keyName,
1735
+ encryptedKey: key
1736
+ }),
1737
+ "Failed to store API key"
1738
+ );
1739
+ success(`${providerInfo.name} API key "${keyName}" stored successfully.`);
1740
+ });
1741
+ keys.command("remove").argument("<provider>", "Provider name").option("-f, --force", "Skip confirmation").description("Remove an API key").action(async (provider, opts) => {
1742
+ const client = await createClient();
1743
+ const result = await safeCall2(
1744
+ () => client.query("apiKeys:list", { provider }),
1745
+ "Failed to list keys"
1746
+ );
1747
+ const items = result || [];
1748
+ if (items.length === 0) {
1749
+ error(`No API keys found for "${provider}".`);
1750
+ process.exit(1);
1751
+ }
1752
+ const target = items[0];
1753
+ if (!opts.force) {
1754
+ const readline10 = __require("readline");
1755
+ const rl = readline10.createInterface({ input: process.stdin, output: process.stdout });
1756
+ const answer = await new Promise((resolve2) => {
1757
+ rl.question(`Delete "${target.keyName}" for ${provider}? (y/N): `, (ans) => {
1758
+ rl.close();
1759
+ resolve2(ans.trim());
1760
+ });
1761
+ });
1762
+ if (answer.toLowerCase() !== "y") {
1763
+ info("Cancelled.");
1764
+ return;
1765
+ }
1766
+ }
1767
+ await safeCall2(
1768
+ () => client.mutation("apiKeys:remove", { id: target._id }),
1769
+ "Failed to remove API key"
1770
+ );
1771
+ success(`API key "${target.keyName}" removed.`);
1772
+ });
1773
+ keys.command("test").argument("<provider>", "Provider to test").description("Test an API key by making a simple request").action(async (provider) => {
1774
+ const client = await createClient();
1775
+ const result = await safeCall2(
1776
+ () => client.query("apiKeys:getActiveForProvider", { provider }),
1777
+ "Failed to get key"
1778
+ );
1779
+ if (!result) {
1780
+ error(`No active API key for "${provider}". Add one with: agentforge keys add ${provider}`);
1781
+ process.exit(1);
1782
+ }
1783
+ const key = result.encryptedKey;
1784
+ info(`Testing ${provider} API key...`);
1785
+ try {
1786
+ let ok = false;
1787
+ if (provider === "openai") {
1788
+ const res = await fetch("https://api.openai.com/v1/models", { headers: { Authorization: `Bearer ${key}` } });
1789
+ ok = res.ok;
1790
+ } else if (provider === "anthropic") {
1791
+ const res = await fetch("https://api.anthropic.com/v1/messages", {
1792
+ method: "POST",
1793
+ headers: { "x-api-key": key, "anthropic-version": "2023-06-01", "Content-Type": "application/json" },
1794
+ body: JSON.stringify({ model: "claude-3-haiku-20240307", max_tokens: 1, messages: [{ role: "user", content: "hi" }] })
1795
+ });
1796
+ ok = res.ok;
1797
+ } else if (provider === "openrouter") {
1798
+ const res = await fetch("https://openrouter.ai/api/v1/models", { headers: { Authorization: `Bearer ${key}` } });
1799
+ ok = res.ok;
1800
+ } else if (provider === "google") {
1801
+ const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${key}`);
1802
+ ok = res.ok;
1803
+ } else if (provider === "groq") {
1804
+ const res = await fetch("https://api.groq.com/openai/v1/models", { headers: { Authorization: `Bearer ${key}` } });
1805
+ ok = res.ok;
1806
+ } else {
1807
+ info(`No test endpoint configured for "${provider}". Key is stored.`);
1808
+ return;
1809
+ }
1810
+ if (ok) {
1811
+ success(`${provider} API key is valid and working.`);
1812
+ await safeCall2(
1813
+ () => client.mutation("apiKeys:updateLastUsed", { id: result._id }),
1814
+ "Failed to update last used"
1815
+ );
1816
+ } else {
1817
+ error(`${provider} API key returned an error. Check that the key is valid.`);
1818
+ }
1819
+ } catch (e) {
1820
+ error(`Connection failed: ${e.message}`);
1821
+ }
1822
+ });
1823
+ }
1824
+
1597
1825
  // src/commands/status.ts
1598
1826
  import { spawn as spawn2 } from "child_process";
1599
1827
  import path8 from "path";
@@ -1610,7 +1838,7 @@ function registerStatusCommand(program2) {
1610
1838
  checks["Dashboard Dir"] = fs8.existsSync(path8.join(cwd, "dashboard")) ? "\u2714 Found" : "\u2716 Not found";
1611
1839
  checks["Env Config"] = fs8.existsSync(path8.join(cwd, ".env.local")) || fs8.existsSync(path8.join(cwd, ".env")) ? "\u2714 Found" : "\u2716 Not found";
1612
1840
  try {
1613
- const client = createClient();
1841
+ const client = await createClient();
1614
1842
  const agents = await client.query("agents:list", {});
1615
1843
  checks["Convex Connection"] = `\u2714 Connected (${agents?.length || 0} agents)`;
1616
1844
  } catch {
@@ -1720,7 +1948,7 @@ function registerStatusCommand(program2) {
1720
1948
  });
1721
1949
  });
1722
1950
  program2.command("logs").description("Show recent activity logs").option("-n, --lines <count>", "Number of log entries", "20").option("--agent <id>", "Filter by agent ID").option("--json", "Output as JSON").action(async (opts) => {
1723
- const client = createClient();
1951
+ const client = await createClient();
1724
1952
  const args = {};
1725
1953
  if (opts.agent) args.agentId = opts.agent;
1726
1954
  const result = await safeCall(
@@ -1747,7 +1975,7 @@ function registerStatusCommand(program2) {
1747
1975
  console.log();
1748
1976
  });
1749
1977
  program2.command("heartbeat").description("Check and resume pending agent tasks").option("--agent <id>", "Check specific agent").action(async (opts) => {
1750
- const client = createClient();
1978
+ const client = await createClient();
1751
1979
  header("Heartbeat Check");
1752
1980
  const args = {};
1753
1981
  if (opts.agent) args.agentId = opts.agent;
@@ -1813,6 +2041,7 @@ registerFilesCommand(program);
1813
2041
  registerProjectsCommand(program);
1814
2042
  registerConfigCommand(program);
1815
2043
  registerVaultCommand(program);
2044
+ registerKeysCommand(program);
1816
2045
  registerStatusCommand(program);
1817
2046
  program.parse();
1818
2047
  //# sourceMappingURL=index.js.map