@lumerahq/cli 0.12.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -146,6 +146,42 @@ var ApiClient = class {
146
146
  method: "DELETE"
147
147
  });
148
148
  }
149
+ // Agents
150
+ async listAgents() {
151
+ const result = await this.request("/api/agents?limit=100");
152
+ return result.agents || [];
153
+ }
154
+ async createAgent(def) {
155
+ return this.request("/api/agents", {
156
+ method: "POST",
157
+ body: JSON.stringify(def)
158
+ });
159
+ }
160
+ async updateAgent(id, def) {
161
+ return this.request(`/api/agents/${id}`, {
162
+ method: "PATCH",
163
+ body: JSON.stringify(def)
164
+ });
165
+ }
166
+ async deleteAgent(id) {
167
+ await this.request(`/api/agents/${id}`, {
168
+ method: "DELETE"
169
+ });
170
+ }
171
+ // Agent Skills (for slug-to-ID resolution)
172
+ async listAgentSkills() {
173
+ const result = await this.request("/api/lm_agent_skills?limit=100");
174
+ return result.skills || [];
175
+ }
176
+ // Agent Invoke
177
+ async invokeAgent(agentId, message, sessionId) {
178
+ const body = { message };
179
+ if (sessionId) body.session_id = sessionId;
180
+ return this.request(`/api/agents/${agentId}/invoke`, {
181
+ method: "POST",
182
+ body: JSON.stringify(body)
183
+ });
184
+ }
149
185
  };
150
186
  function createApiClient(token, baseUrl) {
151
187
  return new ApiClient(token, baseUrl);
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  createApiClient,
6
6
  loadEnv
7
- } from "./chunk-UGFGRGNP.js";
7
+ } from "./chunk-7ZGIC6F7.js";
8
8
  import {
9
9
  getToken
10
10
  } from "./chunk-NDLYGKS6.js";
package/dist/index.js CHANGED
@@ -139,7 +139,7 @@ ${pc.dim("Resource Commands:")}
139
139
 
140
140
  ${pc.dim("Development:")}
141
141
  ${pc.cyan("dev")} Start dev server
142
- ${pc.cyan("run")} <target> Run script or trigger automation
142
+ ${pc.cyan("run")} <target> Run script, trigger automation, or invoke agent
143
143
 
144
144
  ${pc.dim("Project:")}
145
145
  ${pc.cyan("init")} [name] Scaffold a new project
@@ -167,6 +167,7 @@ ${pc.dim("Resource Types:")}
167
167
  collections Data collections (schemas)
168
168
  automations Background Python scripts
169
169
  hooks Collection lifecycle handlers
170
+ agents AI agents with skills and prompts
170
171
  app Frontend application
171
172
 
172
173
  ${pc.dim("Examples:")}
@@ -177,6 +178,7 @@ ${pc.dim("Examples:")}
177
178
  lumera show collections/users # Show collection details
178
179
  lumera run scripts/seed.py # Run a script
179
180
  lumera run automations/sync # Trigger automation
181
+ lumera run agents/support "Hello" # Invoke an agent
180
182
  lumera dev # Start dev server
181
183
 
182
184
  ${pc.dim("Documentation:")}
@@ -208,29 +210,29 @@ async function main() {
208
210
  switch (command) {
209
211
  // Resource commands
210
212
  case "plan":
211
- await import("./resources-4AP5AXH5.js").then((m) => m.plan(args.slice(1)));
213
+ await import("./resources-PKLA2XDG.js").then((m) => m.plan(args.slice(1)));
212
214
  break;
213
215
  case "apply":
214
- await import("./resources-4AP5AXH5.js").then((m) => m.apply(args.slice(1)));
216
+ await import("./resources-PKLA2XDG.js").then((m) => m.apply(args.slice(1)));
215
217
  break;
216
218
  case "pull":
217
- await import("./resources-4AP5AXH5.js").then((m) => m.pull(args.slice(1)));
219
+ await import("./resources-PKLA2XDG.js").then((m) => m.pull(args.slice(1)));
218
220
  break;
219
221
  case "destroy":
220
- await import("./resources-4AP5AXH5.js").then((m) => m.destroy(args.slice(1)));
222
+ await import("./resources-PKLA2XDG.js").then((m) => m.destroy(args.slice(1)));
221
223
  break;
222
224
  case "list":
223
- await import("./resources-4AP5AXH5.js").then((m) => m.list(args.slice(1)));
225
+ await import("./resources-PKLA2XDG.js").then((m) => m.list(args.slice(1)));
224
226
  break;
225
227
  case "show":
226
- await import("./resources-4AP5AXH5.js").then((m) => m.show(args.slice(1)));
228
+ await import("./resources-PKLA2XDG.js").then((m) => m.show(args.slice(1)));
227
229
  break;
228
230
  // Development
229
231
  case "dev":
230
- await import("./dev-IFEYXWVJ.js").then((m) => m.dev(args.slice(1)));
232
+ await import("./dev-LNH47WSS.js").then((m) => m.dev(args.slice(1)));
231
233
  break;
232
234
  case "run":
233
- await import("./run-PBM4WOJT.js").then((m) => m.run(args.slice(1)));
235
+ await import("./run-3UBV3SVA.js").then((m) => m.run(args.slice(1)));
234
236
  break;
235
237
  // Project
236
238
  case "init":
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  createApiClient,
6
6
  loadEnv
7
- } from "./chunk-UGFGRGNP.js";
7
+ } from "./chunk-7ZGIC6F7.js";
8
8
  import {
9
9
  getToken
10
10
  } from "./chunk-NDLYGKS6.js";
@@ -18,8 +18,19 @@ import {
18
18
  // src/commands/resources.ts
19
19
  import pc from "picocolors";
20
20
  import prompts from "prompts";
21
+ import { execFileSync, execSync } from "child_process";
21
22
  import { existsSync, readdirSync, readFileSync, writeFileSync, mkdirSync } from "fs";
22
23
  import { join, resolve } from "path";
24
+ function detectPackageManager() {
25
+ for (const pm of ["bun", "pnpm", "yarn", "npm"]) {
26
+ try {
27
+ execFileSync(pm, ["--version"], { stdio: "ignore" });
28
+ return pm;
29
+ } catch {
30
+ }
31
+ }
32
+ return "npm";
33
+ }
23
34
  function showPlanHelp() {
24
35
  console.log(`
25
36
  ${pc.dim("Usage:")}
@@ -35,6 +46,8 @@ ${pc.dim("Resources:")}
35
46
  automations Plan only automations
36
47
  automations/<name> Plan single automation
37
48
  hooks Plan only hooks
49
+ agents Plan only agents
50
+ agents/<name> Plan single agent
38
51
  app Plan app deployment
39
52
 
40
53
  ${pc.dim("Examples:")}
@@ -58,6 +71,8 @@ ${pc.dim("Resources:")}
58
71
  automations Apply only automations
59
72
  automations/<name> Apply single automation
60
73
  hooks Apply only hooks
74
+ agents Apply only agents
75
+ agents/<name> Apply single agent
61
76
  app Deploy the frontend app
62
77
 
63
78
  ${pc.dim("Options:")}
@@ -86,6 +101,8 @@ ${pc.dim("Resources:")}
86
101
  automations Pull only automations
87
102
  automations/<name> Pull single automation
88
103
  hooks Pull only hooks
104
+ agents Pull only agents
105
+ agents/<name> Pull single agent
89
106
 
90
107
  ${pc.dim("Examples:")}
91
108
  lumera pull # Pull all resources
@@ -108,6 +125,8 @@ ${pc.dim("Resources:")}
108
125
  automations Destroy only automations
109
126
  automations/<name> Destroy single automation
110
127
  hooks Destroy only hooks
128
+ agents Destroy only agents
129
+ agents/<name> Destroy single agent
111
130
  app Delete app registration
112
131
 
113
132
  ${pc.dim("Options:")}
@@ -133,6 +152,7 @@ ${pc.dim("Types:")}
133
152
  collections List only collections
134
153
  automations List only automations
135
154
  hooks List only hooks
155
+ agents List only agents
136
156
 
137
157
  ${pc.dim("Options:")}
138
158
  --all Include remote-only resources
@@ -155,6 +175,7 @@ ${pc.dim("Resources:")}
155
175
  collections/<name> Show collection details
156
176
  automations/<name> Show automation details
157
177
  hooks/<name> Show hook details
178
+ agents/<name> Show agent details
158
179
  app Show app details
159
180
 
160
181
  ${pc.dim("Examples:")}
@@ -170,7 +191,7 @@ function parseResource(resourcePath) {
170
191
  const parts = resourcePath.split("/");
171
192
  const type = parts[0];
172
193
  const name = parts.slice(1).join("/") || null;
173
- if (!["collections", "automations", "hooks", "app"].includes(type)) {
194
+ if (!["collections", "automations", "hooks", "agents", "app"].includes(type)) {
174
195
  return { type: null, name: null };
175
196
  }
176
197
  return { type, name };
@@ -701,9 +722,9 @@ async function applyApp(args) {
701
722
  const apiUrl = getApiUrl();
702
723
  if (!skipBuild) {
703
724
  console.log(pc.dim(" Building..."));
704
- const { execSync } = await import("child_process");
705
725
  try {
706
- execSync("pnpm build", { cwd: projectRoot, stdio: "inherit" });
726
+ const pm = detectPackageManager();
727
+ execSync(`${pm} run build`, { cwd: projectRoot, stdio: "inherit" });
707
728
  } catch {
708
729
  throw new Error("Build failed");
709
730
  }
@@ -823,6 +844,165 @@ ${hook.script.split("\n").map((line) => " " + line).join("\n")}
823
844
  console.log(pc.green(" \u2713"), `${hook.name} \u2192 hooks/${fileName}`);
824
845
  }
825
846
  }
847
+ function loadLocalAgents(platformDir, filterName, appName) {
848
+ const agentsDir = join(platformDir, "agents");
849
+ if (!existsSync(agentsDir)) return [];
850
+ const agents = [];
851
+ const errors = [];
852
+ for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
853
+ if (!entry.isDirectory()) continue;
854
+ const agentDir = join(agentsDir, entry.name);
855
+ const configPath = join(agentDir, "config.json");
856
+ const promptPath = join(agentDir, "system_prompt.md");
857
+ if (!existsSync(configPath)) {
858
+ errors.push(`${entry.name}: missing config.json`);
859
+ continue;
860
+ }
861
+ if (!existsSync(promptPath)) {
862
+ errors.push(`${entry.name}: missing system_prompt.md`);
863
+ continue;
864
+ }
865
+ try {
866
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
867
+ if (filterName && config.external_id !== filterName && config.name !== filterName && entry.name !== filterName) {
868
+ continue;
869
+ }
870
+ if (!config.external_id) {
871
+ if (appName) {
872
+ config.external_id = `${appName}:${entry.name}`;
873
+ } else {
874
+ errors.push(`${entry.name}: missing external_id in config.json`);
875
+ continue;
876
+ }
877
+ }
878
+ if (!config.name) {
879
+ errors.push(`${entry.name}: missing name in config.json`);
880
+ continue;
881
+ }
882
+ const systemPrompt = readFileSync(promptPath, "utf-8");
883
+ agents.push({ agent: config, systemPrompt });
884
+ } catch (e) {
885
+ errors.push(`${entry.name}: failed to parse config.json - ${e}`);
886
+ }
887
+ }
888
+ if (errors.length > 0) {
889
+ console.log(pc.red(" Agent errors:"));
890
+ for (const err of errors) {
891
+ console.log(pc.red(` \u2717 ${err}`));
892
+ }
893
+ throw new Error(`Found ${errors.length} agent error(s)`);
894
+ }
895
+ return agents;
896
+ }
897
+ async function planAgents(api, localAgents) {
898
+ const changes = [];
899
+ const remoteAgents = await api.listAgents();
900
+ const remoteByExternalId = new Map(
901
+ remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
902
+ );
903
+ for (const { agent, systemPrompt } of localAgents) {
904
+ const remote = remoteByExternalId.get(agent.external_id);
905
+ if (!remote) {
906
+ changes.push({ type: "create", resource: "agent", id: agent.external_id, name: agent.name });
907
+ } else {
908
+ const diffs = [];
909
+ if (remote.name !== agent.name) diffs.push("name");
910
+ if ((remote.description || "") !== (agent.description || "")) diffs.push("description");
911
+ if ((remote.system_prompt || "").trim() !== systemPrompt.trim()) diffs.push("system_prompt");
912
+ if (diffs.length > 0) {
913
+ changes.push({ type: "update", resource: "agent", id: agent.external_id, name: agent.name, details: `changed: ${diffs.join(", ")}` });
914
+ }
915
+ }
916
+ }
917
+ return changes;
918
+ }
919
+ async function applyAgents(api, localAgents) {
920
+ let errors = 0;
921
+ const remoteAgents = await api.listAgents();
922
+ const remoteByExternalId = new Map(
923
+ remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
924
+ );
925
+ let skillMap = /* @__PURE__ */ new Map();
926
+ const hasSkillRefs = localAgents.some((a) => a.agent.skills && a.agent.skills.length > 0);
927
+ if (hasSkillRefs) {
928
+ try {
929
+ const skills = await api.listAgentSkills();
930
+ skillMap = new Map(skills.map((s) => [s.slug, s.id]));
931
+ } catch (e) {
932
+ console.log(pc.yellow(` \u26A0 Could not fetch skills for resolution: ${e}`));
933
+ }
934
+ }
935
+ for (const { agent, systemPrompt } of localAgents) {
936
+ const remote = remoteByExternalId.get(agent.external_id);
937
+ const skillIds = [];
938
+ if (agent.skills) {
939
+ for (const slug of agent.skills) {
940
+ const id = skillMap.get(slug);
941
+ if (id) {
942
+ skillIds.push(id);
943
+ } else {
944
+ console.log(pc.yellow(` \u26A0 Skill "${slug}" not found, skipping`));
945
+ }
946
+ }
947
+ }
948
+ const payload = {
949
+ external_id: agent.external_id,
950
+ name: agent.name,
951
+ description: agent.description || "",
952
+ system_prompt: systemPrompt,
953
+ skill_ids: skillIds
954
+ };
955
+ try {
956
+ if (remote) {
957
+ await api.updateAgent(remote.id, payload);
958
+ console.log(pc.green(" \u2713"), `${agent.name} (updated)`);
959
+ } else {
960
+ await api.createAgent(payload);
961
+ console.log(pc.green(" \u2713"), `${agent.name} (created)`);
962
+ }
963
+ } catch (e) {
964
+ console.log(pc.red(" \u2717"), `${agent.name}: ${e}`);
965
+ errors++;
966
+ }
967
+ }
968
+ return errors;
969
+ }
970
+ async function pullAgents(api, platformDir, filterName) {
971
+ const agentsDir = join(platformDir, "agents");
972
+ mkdirSync(agentsDir, { recursive: true });
973
+ const agents = await api.listAgents();
974
+ let skillIdToSlug = /* @__PURE__ */ new Map();
975
+ try {
976
+ const skills = await api.listAgentSkills();
977
+ skillIdToSlug = new Map(skills.map((s) => [s.id, s.slug]));
978
+ } catch {
979
+ }
980
+ for (const agent of agents) {
981
+ if (!agent.external_id || agent.managed) continue;
982
+ if (filterName && agent.external_id !== filterName && agent.name !== filterName) {
983
+ continue;
984
+ }
985
+ const dirName = agent.external_id.replace(/[^a-zA-Z0-9_-]/g, "_");
986
+ const agentDir = join(agentsDir, dirName);
987
+ mkdirSync(agentDir, { recursive: true });
988
+ const skillSlugs = [];
989
+ if (agent.skill_ids) {
990
+ for (const id of agent.skill_ids) {
991
+ const slug = skillIdToSlug.get(id);
992
+ if (slug) skillSlugs.push(slug);
993
+ }
994
+ }
995
+ const config = {
996
+ external_id: agent.external_id,
997
+ name: agent.name
998
+ };
999
+ if (agent.description) config.description = agent.description;
1000
+ if (skillSlugs.length > 0) config.skills = skillSlugs;
1001
+ writeFileSync(join(agentDir, "config.json"), JSON.stringify(config, null, 2) + "\n");
1002
+ writeFileSync(join(agentDir, "system_prompt.md"), agent.system_prompt || "");
1003
+ console.log(pc.green(" \u2713"), `${agent.name} \u2192 agents/${dirName}/`);
1004
+ }
1005
+ }
826
1006
  async function listResources(api, platformDir, filterType, appName) {
827
1007
  const results = [];
828
1008
  if (!filterType || filterType === "collections") {
@@ -907,6 +1087,32 @@ async function listResources(api, platformDir, filterType, appName) {
907
1087
  }
908
1088
  }
909
1089
  }
1090
+ if (!filterType || filterType === "agents") {
1091
+ const localAgents = loadLocalAgents(platformDir, void 0, appName);
1092
+ const remoteAgents = await api.listAgents();
1093
+ const remoteByExternalId = new Map(remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a]));
1094
+ const localIds = new Set(localAgents.map((a) => a.agent.external_id));
1095
+ for (const { agent, systemPrompt } of localAgents) {
1096
+ const remote = remoteByExternalId.get(agent.external_id);
1097
+ if (!remote) {
1098
+ results.push({ name: agent.name, type: "agents", status: "local-only" });
1099
+ } else {
1100
+ const promptChanged = (remote.system_prompt || "").trim() !== systemPrompt.trim();
1101
+ const nameChanged = remote.name !== agent.name;
1102
+ if (promptChanged || nameChanged) {
1103
+ results.push({ name: agent.name, type: "agents", status: "changed", details: promptChanged ? "system_prompt" : "name" });
1104
+ } else {
1105
+ results.push({ name: agent.name, type: "agents", status: "synced" });
1106
+ }
1107
+ }
1108
+ }
1109
+ for (const remote of remoteAgents) {
1110
+ if (!remote.external_id || remote.managed) continue;
1111
+ if (!localIds.has(remote.external_id)) {
1112
+ results.push({ name: remote.name, type: "agents", status: "remote-only" });
1113
+ }
1114
+ }
1115
+ }
910
1116
  return results;
911
1117
  }
912
1118
  function planCollectionDelete(collections, platformDir) {
@@ -1016,6 +1222,20 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
1016
1222
  }
1017
1223
  }
1018
1224
  }
1225
+ if (!resourceType || resourceType === "agents") {
1226
+ try {
1227
+ const localAgents = loadLocalAgents(platformDir, resourceName || void 0, appName);
1228
+ const remoteAgents = await api.listAgents();
1229
+ const remoteByExternalId = new Map(remoteAgents.filter((a) => a.external_id).map((a) => [a.external_id, a]));
1230
+ for (const { agent } of localAgents) {
1231
+ const remote = remoteByExternalId.get(agent.external_id);
1232
+ if (remote) {
1233
+ toDelete.push({ type: "agent", id: agent.external_id, name: agent.name, remoteId: remote.id });
1234
+ }
1235
+ }
1236
+ } catch {
1237
+ }
1238
+ }
1019
1239
  if (toDelete.length === 0) {
1020
1240
  console.log(pc.green(" \u2713 No resources found to delete"));
1021
1241
  return;
@@ -1038,10 +1258,20 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
1038
1258
  return;
1039
1259
  }
1040
1260
  }
1261
+ const agents = toDelete.filter((r) => r.type === "agent");
1041
1262
  const hooks = toDelete.filter((r) => r.type === "hook");
1042
1263
  const automations = toDelete.filter((r) => r.type === "automation");
1043
1264
  const collections = toDelete.filter((r) => r.type === "collection");
1044
1265
  let errors = 0;
1266
+ for (const resource of agents) {
1267
+ try {
1268
+ await api.deleteAgent(resource.remoteId);
1269
+ console.log(pc.green(" \u2713"), `Deleted agent: ${resource.name}`);
1270
+ } catch (e) {
1271
+ console.log(pc.red(" \u2717"), `Failed to delete agent ${resource.name}: ${e}`);
1272
+ errors++;
1273
+ }
1274
+ }
1045
1275
  for (const resource of hooks) {
1046
1276
  try {
1047
1277
  await api.deleteHook(resource.remoteId);
@@ -1250,6 +1480,43 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
1250
1480
  console.log(` Trigger: ${local?.hook.trigger || remote?.event}`);
1251
1481
  console.log(` Enabled: ${local?.hook.enabled !== false || remote?.enabled}`);
1252
1482
  console.log();
1483
+ } else if (resourceType === "agents") {
1484
+ const localAgents = loadLocalAgents(platformDir, resourceName, appName);
1485
+ const remoteAgents = await api.listAgents();
1486
+ const local = localAgents[0];
1487
+ const remote = remoteAgents.find((a) => a.external_id === resourceName || a.name === resourceName);
1488
+ if (!local && !remote) {
1489
+ console.log(pc.red(` Agent "${resourceName}" not found`));
1490
+ process.exit(1);
1491
+ }
1492
+ console.log();
1493
+ console.log(pc.bold(` Agent: ${local?.agent.name || remote?.name}`));
1494
+ console.log();
1495
+ if (local && remote) {
1496
+ const promptChanged = (remote.system_prompt || "").trim() !== local.systemPrompt.trim();
1497
+ const nameChanged = remote.name !== local.agent.name;
1498
+ const descChanged = (remote.description || "") !== (local.agent.description || "");
1499
+ if (promptChanged || nameChanged || descChanged) {
1500
+ console.log(` Status: ${pc.yellow("changed")}`);
1501
+ } else {
1502
+ console.log(` Status: ${pc.green("synced")}`);
1503
+ }
1504
+ } else if (local) {
1505
+ console.log(` Status: ${pc.yellow("local only")}`);
1506
+ } else {
1507
+ console.log(` Status: ${pc.cyan("remote only")}`);
1508
+ }
1509
+ if (local?.agent.external_id || remote?.external_id) {
1510
+ console.log(` External ID: ${local?.agent.external_id || remote?.external_id}`);
1511
+ }
1512
+ if (local?.agent.description || remote?.description) {
1513
+ console.log(` Description: ${local?.agent.description || remote?.description}`);
1514
+ }
1515
+ if (local?.agent.skills?.length || remote?.skill_ids?.length) {
1516
+ const skills = local?.agent.skills || remote?.skill_ids || [];
1517
+ console.log(` Skills: ${skills.join(", ")}`);
1518
+ }
1519
+ console.log();
1253
1520
  } else if (resourceType === "app") {
1254
1521
  const projectRoot = findProjectRoot();
1255
1522
  loadEnv(projectRoot);
@@ -1325,6 +1592,13 @@ async function plan(args) {
1325
1592
  allChanges.push(...changes);
1326
1593
  }
1327
1594
  }
1595
+ if (!type || type === "agents") {
1596
+ const localAgents = loadLocalAgents(platformDir, name || void 0, appName);
1597
+ if (localAgents.length > 0) {
1598
+ const changes = await planAgents(api, localAgents);
1599
+ allChanges.push(...changes);
1600
+ }
1601
+ }
1328
1602
  if (allChanges.length === 0) {
1329
1603
  console.log(pc.green(" \u2713 No changes detected"));
1330
1604
  console.log();
@@ -1416,6 +1690,17 @@ async function apply(args) {
1416
1690
  process.exit(1);
1417
1691
  }
1418
1692
  }
1693
+ if (!type || type === "agents") {
1694
+ const localAgents = loadLocalAgents(platformDir, name || void 0, appName);
1695
+ if (localAgents.length > 0) {
1696
+ console.log(pc.bold(" Agents:"));
1697
+ totalErrors += await applyAgents(api, localAgents);
1698
+ console.log();
1699
+ } else if (name) {
1700
+ console.log(pc.red(` Agent "${name}" not found locally`));
1701
+ process.exit(1);
1702
+ }
1703
+ }
1419
1704
  if (!type) {
1420
1705
  try {
1421
1706
  const projectRoot2 = findProjectRoot();
@@ -1463,6 +1748,11 @@ async function pull(args) {
1463
1748
  await pullHooks(api, platformDir, name || void 0);
1464
1749
  console.log();
1465
1750
  }
1751
+ if (!type || type === "agents") {
1752
+ console.log(pc.bold(" Agents:"));
1753
+ await pullAgents(api, platformDir, name || void 0);
1754
+ console.log();
1755
+ }
1466
1756
  console.log(pc.green(" Done!"));
1467
1757
  console.log();
1468
1758
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createApiClient,
3
3
  loadEnv
4
- } from "./chunk-UGFGRGNP.js";
4
+ } from "./chunk-7ZGIC6F7.js";
5
5
  import {
6
6
  getToken
7
7
  } from "./chunk-NDLYGKS6.js";
@@ -21,16 +21,18 @@ ${pc.dim("Usage:")}
21
21
  lumera run <target> [options]
22
22
 
23
23
  ${pc.dim("Description:")}
24
- Run a script locally or trigger an automation on the platform.
24
+ Run a script locally, trigger an automation, or invoke an agent.
25
25
 
26
26
  ${pc.dim("Targets:")}
27
27
  scripts/<name>.py Run a Python script locally using uv
28
28
  automations/<name> Trigger an automation run on the platform
29
+ agents/<name> "msg" Invoke an agent on the platform
29
30
 
30
31
  ${pc.dim("Options:")}
31
32
  --local Run automation code locally instead of on platform
32
33
  --preset <name> Use a specific preset when triggering automation
33
34
  --input <json> Pass JSON input to the automation
35
+ --session <id> Use a specific session for agent invocation
34
36
  --help, -h Show this help
35
37
 
36
38
  ${pc.dim("Examples:")}
@@ -38,6 +40,7 @@ ${pc.dim("Examples:")}
38
40
  lumera run automations/sync # Trigger automation on platform
39
41
  lumera run automations/sync --preset daily
40
42
  lumera run automations/sync --local # Run automation code locally
43
+ lumera run agents/support "Hello" # Invoke an agent
41
44
 
42
45
  ${pc.dim("Notes:")}
43
46
  - Scripts can declare dependencies using PEP 723 inline metadata
@@ -48,6 +51,7 @@ ${pc.dim("Notes:")}
48
51
  function parseFlags(args) {
49
52
  const flags = {};
50
53
  let target = "";
54
+ const positionalArgs = [];
51
55
  for (let i = 0; i < args.length; i++) {
52
56
  const arg = args[i];
53
57
  if (arg.startsWith("--")) {
@@ -61,9 +65,11 @@ function parseFlags(args) {
61
65
  }
62
66
  } else if (!target) {
63
67
  target = arg;
68
+ } else {
69
+ positionalArgs.push(arg);
64
70
  }
65
71
  }
66
- return { target, flags };
72
+ return { target, flags, positionalArgs };
67
73
  }
68
74
  async function runScript(scriptPath, projectRoot) {
69
75
  const fullScriptPath = resolve(projectRoot, scriptPath);
@@ -226,12 +232,65 @@ async function runAutomationLocally(automationName, projectRoot, flags) {
226
232
  process.on("SIGINT", () => uv.kill("SIGINT"));
227
233
  process.on("SIGTERM", () => uv.kill("SIGTERM"));
228
234
  }
235
+ async function invokeAgent(agentName, message, flags) {
236
+ if (!message) {
237
+ console.error(pc.red(" Message is required."));
238
+ console.error(pc.dim(' Usage: lumera run agents/<name> "Your message here"'));
239
+ process.exit(1);
240
+ }
241
+ const api = createApiClient();
242
+ console.log();
243
+ console.log(pc.cyan(pc.bold(" Invoke Agent")));
244
+ console.log();
245
+ const agents = await api.listAgents();
246
+ const agent = agents.find(
247
+ (a) => a.external_id === agentName || a.name === agentName
248
+ );
249
+ if (!agent) {
250
+ console.error(pc.red(` Agent "${agentName}" not found on platform.`));
251
+ console.error(pc.dim(" Run `lumera list agents` to see available agents."));
252
+ process.exit(1);
253
+ }
254
+ console.log(pc.dim(` Agent: ${agent.name}`));
255
+ const sessionId = flags.session ? String(flags.session) : void 0;
256
+ if (sessionId) {
257
+ console.log(pc.dim(` Session: ${sessionId}`));
258
+ }
259
+ console.log();
260
+ try {
261
+ const result = await api.invokeAgent(
262
+ agent.external_id || agent.id,
263
+ message,
264
+ sessionId
265
+ );
266
+ if (result.success) {
267
+ console.log(result.output);
268
+ } else {
269
+ console.error(pc.red(` Agent error: ${result.error}`));
270
+ process.exit(1);
271
+ }
272
+ if (result.tool_calls && result.tool_calls.length > 0) {
273
+ console.log();
274
+ console.log(pc.dim(` Tool calls: ${result.tool_calls.length}`));
275
+ for (const tc of result.tool_calls) {
276
+ console.log(pc.dim(` - ${tc.tool} (${tc.success ? "ok" : "failed"})`));
277
+ }
278
+ }
279
+ if (result.session_id) {
280
+ console.log(pc.dim(` Session: ${result.session_id}`));
281
+ }
282
+ } catch (e) {
283
+ console.error(pc.red(` Failed to invoke agent: ${e}`));
284
+ process.exit(1);
285
+ }
286
+ console.log();
287
+ }
229
288
  async function run(args) {
230
289
  if (args.includes("--help") || args.includes("-h") || args.length === 0) {
231
290
  showHelp();
232
291
  process.exit(args.length === 0 ? 1 : 0);
233
292
  }
234
- const { target, flags } = parseFlags(args);
293
+ const { target, flags, positionalArgs } = parseFlags(args);
235
294
  let projectRoot;
236
295
  try {
237
296
  projectRoot = findProjectRoot();
@@ -248,6 +307,12 @@ async function run(args) {
248
307
  }
249
308
  return;
250
309
  }
310
+ if (target.startsWith("agents/")) {
311
+ const agentName = target.replace("agents/", "");
312
+ const message = positionalArgs.join(" ") || void 0;
313
+ await invokeAgent(agentName, message, flags);
314
+ return;
315
+ }
251
316
  await runScript(target, projectRoot);
252
317
  }
253
318
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumerahq/cli",
3
- "version": "0.12.0",
3
+ "version": "0.13.1",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {