@lumerahq/cli 0.11.1 → 0.13.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.
|
@@ -3,6 +3,13 @@ import {
|
|
|
3
3
|
} from "./chunk-NDLYGKS6.js";
|
|
4
4
|
|
|
5
5
|
// src/lib/api.ts
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { dirname, join } from "path";
|
|
9
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
var __dirname = dirname(__filename);
|
|
11
|
+
var pkg = JSON.parse(readFileSync(join(__dirname, "../../package.json"), "utf-8"));
|
|
12
|
+
var CLI_USER_AGENT = `lumera-cli/${pkg.version}`;
|
|
6
13
|
var ApiClient = class {
|
|
7
14
|
baseUrl;
|
|
8
15
|
token;
|
|
@@ -20,6 +27,7 @@ var ApiClient = class {
|
|
|
20
27
|
const headers = {
|
|
21
28
|
"Content-Type": "application/json",
|
|
22
29
|
Authorization: `Bearer ${this.token}`,
|
|
30
|
+
"User-Agent": CLI_USER_AGENT,
|
|
23
31
|
...options.headers
|
|
24
32
|
};
|
|
25
33
|
const response = await fetch(url, {
|
|
@@ -138,6 +146,42 @@ var ApiClient = class {
|
|
|
138
146
|
method: "DELETE"
|
|
139
147
|
});
|
|
140
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
|
+
}
|
|
141
185
|
};
|
|
142
186
|
function createApiClient(token, baseUrl) {
|
|
143
187
|
return new ApiClient(token, baseUrl);
|
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
|
|
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-
|
|
213
|
+
await import("./resources-JDUZSI43.js").then((m) => m.plan(args.slice(1)));
|
|
212
214
|
break;
|
|
213
215
|
case "apply":
|
|
214
|
-
await import("./resources-
|
|
216
|
+
await import("./resources-JDUZSI43.js").then((m) => m.apply(args.slice(1)));
|
|
215
217
|
break;
|
|
216
218
|
case "pull":
|
|
217
|
-
await import("./resources-
|
|
219
|
+
await import("./resources-JDUZSI43.js").then((m) => m.pull(args.slice(1)));
|
|
218
220
|
break;
|
|
219
221
|
case "destroy":
|
|
220
|
-
await import("./resources-
|
|
222
|
+
await import("./resources-JDUZSI43.js").then((m) => m.destroy(args.slice(1)));
|
|
221
223
|
break;
|
|
222
224
|
case "list":
|
|
223
|
-
await import("./resources-
|
|
225
|
+
await import("./resources-JDUZSI43.js").then((m) => m.list(args.slice(1)));
|
|
224
226
|
break;
|
|
225
227
|
case "show":
|
|
226
|
-
await import("./resources-
|
|
228
|
+
await import("./resources-JDUZSI43.js").then((m) => m.show(args.slice(1)));
|
|
227
229
|
break;
|
|
228
230
|
// Development
|
|
229
231
|
case "dev":
|
|
230
|
-
await import("./dev-
|
|
232
|
+
await import("./dev-LNH47WSS.js").then((m) => m.dev(args.slice(1)));
|
|
231
233
|
break;
|
|
232
234
|
case "run":
|
|
233
|
-
await import("./run-
|
|
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-
|
|
7
|
+
} from "./chunk-7ZGIC6F7.js";
|
|
8
8
|
import {
|
|
9
9
|
getToken
|
|
10
10
|
} from "./chunk-NDLYGKS6.js";
|
|
@@ -35,6 +35,8 @@ ${pc.dim("Resources:")}
|
|
|
35
35
|
automations Plan only automations
|
|
36
36
|
automations/<name> Plan single automation
|
|
37
37
|
hooks Plan only hooks
|
|
38
|
+
agents Plan only agents
|
|
39
|
+
agents/<name> Plan single agent
|
|
38
40
|
app Plan app deployment
|
|
39
41
|
|
|
40
42
|
${pc.dim("Examples:")}
|
|
@@ -58,6 +60,8 @@ ${pc.dim("Resources:")}
|
|
|
58
60
|
automations Apply only automations
|
|
59
61
|
automations/<name> Apply single automation
|
|
60
62
|
hooks Apply only hooks
|
|
63
|
+
agents Apply only agents
|
|
64
|
+
agents/<name> Apply single agent
|
|
61
65
|
app Deploy the frontend app
|
|
62
66
|
|
|
63
67
|
${pc.dim("Options:")}
|
|
@@ -86,6 +90,8 @@ ${pc.dim("Resources:")}
|
|
|
86
90
|
automations Pull only automations
|
|
87
91
|
automations/<name> Pull single automation
|
|
88
92
|
hooks Pull only hooks
|
|
93
|
+
agents Pull only agents
|
|
94
|
+
agents/<name> Pull single agent
|
|
89
95
|
|
|
90
96
|
${pc.dim("Examples:")}
|
|
91
97
|
lumera pull # Pull all resources
|
|
@@ -108,6 +114,8 @@ ${pc.dim("Resources:")}
|
|
|
108
114
|
automations Destroy only automations
|
|
109
115
|
automations/<name> Destroy single automation
|
|
110
116
|
hooks Destroy only hooks
|
|
117
|
+
agents Destroy only agents
|
|
118
|
+
agents/<name> Destroy single agent
|
|
111
119
|
app Delete app registration
|
|
112
120
|
|
|
113
121
|
${pc.dim("Options:")}
|
|
@@ -133,6 +141,7 @@ ${pc.dim("Types:")}
|
|
|
133
141
|
collections List only collections
|
|
134
142
|
automations List only automations
|
|
135
143
|
hooks List only hooks
|
|
144
|
+
agents List only agents
|
|
136
145
|
|
|
137
146
|
${pc.dim("Options:")}
|
|
138
147
|
--all Include remote-only resources
|
|
@@ -155,6 +164,7 @@ ${pc.dim("Resources:")}
|
|
|
155
164
|
collections/<name> Show collection details
|
|
156
165
|
automations/<name> Show automation details
|
|
157
166
|
hooks/<name> Show hook details
|
|
167
|
+
agents/<name> Show agent details
|
|
158
168
|
app Show app details
|
|
159
169
|
|
|
160
170
|
${pc.dim("Examples:")}
|
|
@@ -170,7 +180,7 @@ function parseResource(resourcePath) {
|
|
|
170
180
|
const parts = resourcePath.split("/");
|
|
171
181
|
const type = parts[0];
|
|
172
182
|
const name = parts.slice(1).join("/") || null;
|
|
173
|
-
if (!["collections", "automations", "hooks", "app"].includes(type)) {
|
|
183
|
+
if (!["collections", "automations", "hooks", "agents", "app"].includes(type)) {
|
|
174
184
|
return { type: null, name: null };
|
|
175
185
|
}
|
|
176
186
|
return { type, name };
|
|
@@ -823,6 +833,165 @@ ${hook.script.split("\n").map((line) => " " + line).join("\n")}
|
|
|
823
833
|
console.log(pc.green(" \u2713"), `${hook.name} \u2192 hooks/${fileName}`);
|
|
824
834
|
}
|
|
825
835
|
}
|
|
836
|
+
function loadLocalAgents(platformDir, filterName, appName) {
|
|
837
|
+
const agentsDir = join(platformDir, "agents");
|
|
838
|
+
if (!existsSync(agentsDir)) return [];
|
|
839
|
+
const agents = [];
|
|
840
|
+
const errors = [];
|
|
841
|
+
for (const entry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
842
|
+
if (!entry.isDirectory()) continue;
|
|
843
|
+
const agentDir = join(agentsDir, entry.name);
|
|
844
|
+
const configPath = join(agentDir, "config.json");
|
|
845
|
+
const promptPath = join(agentDir, "system_prompt.md");
|
|
846
|
+
if (!existsSync(configPath)) {
|
|
847
|
+
errors.push(`${entry.name}: missing config.json`);
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
850
|
+
if (!existsSync(promptPath)) {
|
|
851
|
+
errors.push(`${entry.name}: missing system_prompt.md`);
|
|
852
|
+
continue;
|
|
853
|
+
}
|
|
854
|
+
try {
|
|
855
|
+
const config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
856
|
+
if (filterName && config.external_id !== filterName && config.name !== filterName && entry.name !== filterName) {
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
if (!config.external_id) {
|
|
860
|
+
if (appName) {
|
|
861
|
+
config.external_id = `${appName}:${entry.name}`;
|
|
862
|
+
} else {
|
|
863
|
+
errors.push(`${entry.name}: missing external_id in config.json`);
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (!config.name) {
|
|
868
|
+
errors.push(`${entry.name}: missing name in config.json`);
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
const systemPrompt = readFileSync(promptPath, "utf-8");
|
|
872
|
+
agents.push({ agent: config, systemPrompt });
|
|
873
|
+
} catch (e) {
|
|
874
|
+
errors.push(`${entry.name}: failed to parse config.json - ${e}`);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
if (errors.length > 0) {
|
|
878
|
+
console.log(pc.red(" Agent errors:"));
|
|
879
|
+
for (const err of errors) {
|
|
880
|
+
console.log(pc.red(` \u2717 ${err}`));
|
|
881
|
+
}
|
|
882
|
+
throw new Error(`Found ${errors.length} agent error(s)`);
|
|
883
|
+
}
|
|
884
|
+
return agents;
|
|
885
|
+
}
|
|
886
|
+
async function planAgents(api, localAgents) {
|
|
887
|
+
const changes = [];
|
|
888
|
+
const remoteAgents = await api.listAgents();
|
|
889
|
+
const remoteByExternalId = new Map(
|
|
890
|
+
remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
|
|
891
|
+
);
|
|
892
|
+
for (const { agent, systemPrompt } of localAgents) {
|
|
893
|
+
const remote = remoteByExternalId.get(agent.external_id);
|
|
894
|
+
if (!remote) {
|
|
895
|
+
changes.push({ type: "create", resource: "agent", id: agent.external_id, name: agent.name });
|
|
896
|
+
} else {
|
|
897
|
+
const diffs = [];
|
|
898
|
+
if (remote.name !== agent.name) diffs.push("name");
|
|
899
|
+
if ((remote.description || "") !== (agent.description || "")) diffs.push("description");
|
|
900
|
+
if ((remote.system_prompt || "").trim() !== systemPrompt.trim()) diffs.push("system_prompt");
|
|
901
|
+
if (diffs.length > 0) {
|
|
902
|
+
changes.push({ type: "update", resource: "agent", id: agent.external_id, name: agent.name, details: `changed: ${diffs.join(", ")}` });
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return changes;
|
|
907
|
+
}
|
|
908
|
+
async function applyAgents(api, localAgents) {
|
|
909
|
+
let errors = 0;
|
|
910
|
+
const remoteAgents = await api.listAgents();
|
|
911
|
+
const remoteByExternalId = new Map(
|
|
912
|
+
remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
|
|
913
|
+
);
|
|
914
|
+
let skillMap = /* @__PURE__ */ new Map();
|
|
915
|
+
const hasSkillRefs = localAgents.some((a) => a.agent.skills && a.agent.skills.length > 0);
|
|
916
|
+
if (hasSkillRefs) {
|
|
917
|
+
try {
|
|
918
|
+
const skills = await api.listAgentSkills();
|
|
919
|
+
skillMap = new Map(skills.map((s) => [s.slug, s.id]));
|
|
920
|
+
} catch (e) {
|
|
921
|
+
console.log(pc.yellow(` \u26A0 Could not fetch skills for resolution: ${e}`));
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
for (const { agent, systemPrompt } of localAgents) {
|
|
925
|
+
const remote = remoteByExternalId.get(agent.external_id);
|
|
926
|
+
const skillIds = [];
|
|
927
|
+
if (agent.skills) {
|
|
928
|
+
for (const slug of agent.skills) {
|
|
929
|
+
const id = skillMap.get(slug);
|
|
930
|
+
if (id) {
|
|
931
|
+
skillIds.push(id);
|
|
932
|
+
} else {
|
|
933
|
+
console.log(pc.yellow(` \u26A0 Skill "${slug}" not found, skipping`));
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
const payload = {
|
|
938
|
+
external_id: agent.external_id,
|
|
939
|
+
name: agent.name,
|
|
940
|
+
description: agent.description || "",
|
|
941
|
+
system_prompt: systemPrompt,
|
|
942
|
+
skill_ids: skillIds
|
|
943
|
+
};
|
|
944
|
+
try {
|
|
945
|
+
if (remote) {
|
|
946
|
+
await api.updateAgent(remote.id, payload);
|
|
947
|
+
console.log(pc.green(" \u2713"), `${agent.name} (updated)`);
|
|
948
|
+
} else {
|
|
949
|
+
await api.createAgent(payload);
|
|
950
|
+
console.log(pc.green(" \u2713"), `${agent.name} (created)`);
|
|
951
|
+
}
|
|
952
|
+
} catch (e) {
|
|
953
|
+
console.log(pc.red(" \u2717"), `${agent.name}: ${e}`);
|
|
954
|
+
errors++;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
return errors;
|
|
958
|
+
}
|
|
959
|
+
async function pullAgents(api, platformDir, filterName) {
|
|
960
|
+
const agentsDir = join(platformDir, "agents");
|
|
961
|
+
mkdirSync(agentsDir, { recursive: true });
|
|
962
|
+
const agents = await api.listAgents();
|
|
963
|
+
let skillIdToSlug = /* @__PURE__ */ new Map();
|
|
964
|
+
try {
|
|
965
|
+
const skills = await api.listAgentSkills();
|
|
966
|
+
skillIdToSlug = new Map(skills.map((s) => [s.id, s.slug]));
|
|
967
|
+
} catch {
|
|
968
|
+
}
|
|
969
|
+
for (const agent of agents) {
|
|
970
|
+
if (!agent.external_id || agent.managed) continue;
|
|
971
|
+
if (filterName && agent.external_id !== filterName && agent.name !== filterName) {
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
const dirName = agent.external_id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
975
|
+
const agentDir = join(agentsDir, dirName);
|
|
976
|
+
mkdirSync(agentDir, { recursive: true });
|
|
977
|
+
const skillSlugs = [];
|
|
978
|
+
if (agent.skill_ids) {
|
|
979
|
+
for (const id of agent.skill_ids) {
|
|
980
|
+
const slug = skillIdToSlug.get(id);
|
|
981
|
+
if (slug) skillSlugs.push(slug);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
const config = {
|
|
985
|
+
external_id: agent.external_id,
|
|
986
|
+
name: agent.name
|
|
987
|
+
};
|
|
988
|
+
if (agent.description) config.description = agent.description;
|
|
989
|
+
if (skillSlugs.length > 0) config.skills = skillSlugs;
|
|
990
|
+
writeFileSync(join(agentDir, "config.json"), JSON.stringify(config, null, 2) + "\n");
|
|
991
|
+
writeFileSync(join(agentDir, "system_prompt.md"), agent.system_prompt || "");
|
|
992
|
+
console.log(pc.green(" \u2713"), `${agent.name} \u2192 agents/${dirName}/`);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
826
995
|
async function listResources(api, platformDir, filterType, appName) {
|
|
827
996
|
const results = [];
|
|
828
997
|
if (!filterType || filterType === "collections") {
|
|
@@ -907,6 +1076,32 @@ async function listResources(api, platformDir, filterType, appName) {
|
|
|
907
1076
|
}
|
|
908
1077
|
}
|
|
909
1078
|
}
|
|
1079
|
+
if (!filterType || filterType === "agents") {
|
|
1080
|
+
const localAgents = loadLocalAgents(platformDir, void 0, appName);
|
|
1081
|
+
const remoteAgents = await api.listAgents();
|
|
1082
|
+
const remoteByExternalId = new Map(remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a]));
|
|
1083
|
+
const localIds = new Set(localAgents.map((a) => a.agent.external_id));
|
|
1084
|
+
for (const { agent, systemPrompt } of localAgents) {
|
|
1085
|
+
const remote = remoteByExternalId.get(agent.external_id);
|
|
1086
|
+
if (!remote) {
|
|
1087
|
+
results.push({ name: agent.name, type: "agents", status: "local-only" });
|
|
1088
|
+
} else {
|
|
1089
|
+
const promptChanged = (remote.system_prompt || "").trim() !== systemPrompt.trim();
|
|
1090
|
+
const nameChanged = remote.name !== agent.name;
|
|
1091
|
+
if (promptChanged || nameChanged) {
|
|
1092
|
+
results.push({ name: agent.name, type: "agents", status: "changed", details: promptChanged ? "system_prompt" : "name" });
|
|
1093
|
+
} else {
|
|
1094
|
+
results.push({ name: agent.name, type: "agents", status: "synced" });
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
for (const remote of remoteAgents) {
|
|
1099
|
+
if (!remote.external_id || remote.managed) continue;
|
|
1100
|
+
if (!localIds.has(remote.external_id)) {
|
|
1101
|
+
results.push({ name: remote.name, type: "agents", status: "remote-only" });
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
910
1105
|
return results;
|
|
911
1106
|
}
|
|
912
1107
|
function planCollectionDelete(collections, platformDir) {
|
|
@@ -1016,6 +1211,20 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
|
|
|
1016
1211
|
}
|
|
1017
1212
|
}
|
|
1018
1213
|
}
|
|
1214
|
+
if (!resourceType || resourceType === "agents") {
|
|
1215
|
+
try {
|
|
1216
|
+
const localAgents = loadLocalAgents(platformDir, resourceName || void 0, appName);
|
|
1217
|
+
const remoteAgents = await api.listAgents();
|
|
1218
|
+
const remoteByExternalId = new Map(remoteAgents.filter((a) => a.external_id).map((a) => [a.external_id, a]));
|
|
1219
|
+
for (const { agent } of localAgents) {
|
|
1220
|
+
const remote = remoteByExternalId.get(agent.external_id);
|
|
1221
|
+
if (remote) {
|
|
1222
|
+
toDelete.push({ type: "agent", id: agent.external_id, name: agent.name, remoteId: remote.id });
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
} catch {
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1019
1228
|
if (toDelete.length === 0) {
|
|
1020
1229
|
console.log(pc.green(" \u2713 No resources found to delete"));
|
|
1021
1230
|
return;
|
|
@@ -1038,10 +1247,20 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
|
|
|
1038
1247
|
return;
|
|
1039
1248
|
}
|
|
1040
1249
|
}
|
|
1250
|
+
const agents = toDelete.filter((r) => r.type === "agent");
|
|
1041
1251
|
const hooks = toDelete.filter((r) => r.type === "hook");
|
|
1042
1252
|
const automations = toDelete.filter((r) => r.type === "automation");
|
|
1043
1253
|
const collections = toDelete.filter((r) => r.type === "collection");
|
|
1044
1254
|
let errors = 0;
|
|
1255
|
+
for (const resource of agents) {
|
|
1256
|
+
try {
|
|
1257
|
+
await api.deleteAgent(resource.remoteId);
|
|
1258
|
+
console.log(pc.green(" \u2713"), `Deleted agent: ${resource.name}`);
|
|
1259
|
+
} catch (e) {
|
|
1260
|
+
console.log(pc.red(" \u2717"), `Failed to delete agent ${resource.name}: ${e}`);
|
|
1261
|
+
errors++;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1045
1264
|
for (const resource of hooks) {
|
|
1046
1265
|
try {
|
|
1047
1266
|
await api.deleteHook(resource.remoteId);
|
|
@@ -1250,6 +1469,43 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
|
|
|
1250
1469
|
console.log(` Trigger: ${local?.hook.trigger || remote?.event}`);
|
|
1251
1470
|
console.log(` Enabled: ${local?.hook.enabled !== false || remote?.enabled}`);
|
|
1252
1471
|
console.log();
|
|
1472
|
+
} else if (resourceType === "agents") {
|
|
1473
|
+
const localAgents = loadLocalAgents(platformDir, resourceName, appName);
|
|
1474
|
+
const remoteAgents = await api.listAgents();
|
|
1475
|
+
const local = localAgents[0];
|
|
1476
|
+
const remote = remoteAgents.find((a) => a.external_id === resourceName || a.name === resourceName);
|
|
1477
|
+
if (!local && !remote) {
|
|
1478
|
+
console.log(pc.red(` Agent "${resourceName}" not found`));
|
|
1479
|
+
process.exit(1);
|
|
1480
|
+
}
|
|
1481
|
+
console.log();
|
|
1482
|
+
console.log(pc.bold(` Agent: ${local?.agent.name || remote?.name}`));
|
|
1483
|
+
console.log();
|
|
1484
|
+
if (local && remote) {
|
|
1485
|
+
const promptChanged = (remote.system_prompt || "").trim() !== local.systemPrompt.trim();
|
|
1486
|
+
const nameChanged = remote.name !== local.agent.name;
|
|
1487
|
+
const descChanged = (remote.description || "") !== (local.agent.description || "");
|
|
1488
|
+
if (promptChanged || nameChanged || descChanged) {
|
|
1489
|
+
console.log(` Status: ${pc.yellow("changed")}`);
|
|
1490
|
+
} else {
|
|
1491
|
+
console.log(` Status: ${pc.green("synced")}`);
|
|
1492
|
+
}
|
|
1493
|
+
} else if (local) {
|
|
1494
|
+
console.log(` Status: ${pc.yellow("local only")}`);
|
|
1495
|
+
} else {
|
|
1496
|
+
console.log(` Status: ${pc.cyan("remote only")}`);
|
|
1497
|
+
}
|
|
1498
|
+
if (local?.agent.external_id || remote?.external_id) {
|
|
1499
|
+
console.log(` External ID: ${local?.agent.external_id || remote?.external_id}`);
|
|
1500
|
+
}
|
|
1501
|
+
if (local?.agent.description || remote?.description) {
|
|
1502
|
+
console.log(` Description: ${local?.agent.description || remote?.description}`);
|
|
1503
|
+
}
|
|
1504
|
+
if (local?.agent.skills?.length || remote?.skill_ids?.length) {
|
|
1505
|
+
const skills = local?.agent.skills || remote?.skill_ids || [];
|
|
1506
|
+
console.log(` Skills: ${skills.join(", ")}`);
|
|
1507
|
+
}
|
|
1508
|
+
console.log();
|
|
1253
1509
|
} else if (resourceType === "app") {
|
|
1254
1510
|
const projectRoot = findProjectRoot();
|
|
1255
1511
|
loadEnv(projectRoot);
|
|
@@ -1325,6 +1581,13 @@ async function plan(args) {
|
|
|
1325
1581
|
allChanges.push(...changes);
|
|
1326
1582
|
}
|
|
1327
1583
|
}
|
|
1584
|
+
if (!type || type === "agents") {
|
|
1585
|
+
const localAgents = loadLocalAgents(platformDir, name || void 0, appName);
|
|
1586
|
+
if (localAgents.length > 0) {
|
|
1587
|
+
const changes = await planAgents(api, localAgents);
|
|
1588
|
+
allChanges.push(...changes);
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1328
1591
|
if (allChanges.length === 0) {
|
|
1329
1592
|
console.log(pc.green(" \u2713 No changes detected"));
|
|
1330
1593
|
console.log();
|
|
@@ -1416,6 +1679,17 @@ async function apply(args) {
|
|
|
1416
1679
|
process.exit(1);
|
|
1417
1680
|
}
|
|
1418
1681
|
}
|
|
1682
|
+
if (!type || type === "agents") {
|
|
1683
|
+
const localAgents = loadLocalAgents(platformDir, name || void 0, appName);
|
|
1684
|
+
if (localAgents.length > 0) {
|
|
1685
|
+
console.log(pc.bold(" Agents:"));
|
|
1686
|
+
totalErrors += await applyAgents(api, localAgents);
|
|
1687
|
+
console.log();
|
|
1688
|
+
} else if (name) {
|
|
1689
|
+
console.log(pc.red(` Agent "${name}" not found locally`));
|
|
1690
|
+
process.exit(1);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1419
1693
|
if (!type) {
|
|
1420
1694
|
try {
|
|
1421
1695
|
const projectRoot2 = findProjectRoot();
|
|
@@ -1463,6 +1737,11 @@ async function pull(args) {
|
|
|
1463
1737
|
await pullHooks(api, platformDir, name || void 0);
|
|
1464
1738
|
console.log();
|
|
1465
1739
|
}
|
|
1740
|
+
if (!type || type === "agents") {
|
|
1741
|
+
console.log(pc.bold(" Agents:"));
|
|
1742
|
+
await pullAgents(api, platformDir, name || void 0);
|
|
1743
|
+
console.log();
|
|
1744
|
+
}
|
|
1466
1745
|
console.log(pc.green(" Done!"));
|
|
1467
1746
|
console.log();
|
|
1468
1747
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createApiClient,
|
|
3
3
|
loadEnv
|
|
4
|
-
} from "./chunk-
|
|
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
|
|
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 {
|