@lumerahq/cli 0.19.7 → 0.19.8-dev.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.
- package/dist/{chunk-RUJRTLHA.js → chunk-2WDZ3QKS.js} +1 -1
- package/dist/{chunk-WY6UMJNI.js → chunk-SMZESQV2.js} +19 -4
- package/dist/{deps-73XZXRYP.js → deps-53AOYHH2.js} +2 -2
- package/dist/{dev-YYMFCXZ5.js → dev-RENAXSGD.js} +2 -2
- package/dist/index.js +12 -12
- package/dist/{init-7YWMMTBF.js → init-J5BNFCSP.js} +1 -1
- package/dist/{register-KJMSMMD6.js → register-ZYUFXURK.js} +1 -1
- package/dist/{resources-P7WAHOHR.js → resources-EPCEYCFY.js} +82 -25
- package/dist/{run-C23KZI4Z.js → run-XWXUBWWH.js} +1 -1
- package/package.json +1 -1
- package/templates/default/AGENTS.md +21 -1
|
@@ -241,10 +241,25 @@ var ApiClient = class {
|
|
|
241
241
|
method: "DELETE"
|
|
242
242
|
});
|
|
243
243
|
}
|
|
244
|
-
//
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
244
|
+
// Resolve a list of refs (slugs or IDs) to skill records. Chunks
|
|
245
|
+
// requests so callers don't have to think about the server-side
|
|
246
|
+
// per-request cap.
|
|
247
|
+
async lookupAgentSkills(refs) {
|
|
248
|
+
if (!refs || refs.length === 0) return [];
|
|
249
|
+
const CHUNK = 100;
|
|
250
|
+
const chunks = [];
|
|
251
|
+
for (let i = 0; i < refs.length; i += CHUNK) {
|
|
252
|
+
chunks.push(refs.slice(i, i + CHUNK));
|
|
253
|
+
}
|
|
254
|
+
const responses = await Promise.all(
|
|
255
|
+
chunks.map(
|
|
256
|
+
(chunk) => this.request("/api/lm_agent_skills/lookup", {
|
|
257
|
+
method: "POST",
|
|
258
|
+
body: JSON.stringify({ refs: chunk })
|
|
259
|
+
})
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
return responses.flatMap((r) => r.skills || []);
|
|
248
263
|
}
|
|
249
264
|
// Agent Invoke
|
|
250
265
|
async invokeAgent(agentId, message, sessionId) {
|
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
deps,
|
|
3
3
|
projectResourceDepsEnabled,
|
|
4
4
|
syncDeps
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-2WDZ3QKS.js";
|
|
6
6
|
import "./chunk-2CR762KB.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-SMZESQV2.js";
|
|
8
8
|
import "./chunk-ZH3NVYEQ.js";
|
|
9
9
|
import "./chunk-FJFIWC7G.js";
|
|
10
10
|
import "./chunk-PNKVD2UK.js";
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
projectResourceDepsEnabled,
|
|
6
6
|
syncDeps
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2WDZ3QKS.js";
|
|
8
8
|
import {
|
|
9
9
|
loadEnv
|
|
10
10
|
} from "./chunk-2CR762KB.js";
|
|
11
11
|
import {
|
|
12
12
|
createApiClient
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-SMZESQV2.js";
|
|
14
14
|
import {
|
|
15
15
|
findProjectRoot,
|
|
16
16
|
getApiUrl,
|
package/dist/index.js
CHANGED
|
@@ -219,39 +219,39 @@ async function main() {
|
|
|
219
219
|
switch (command) {
|
|
220
220
|
// Resource commands
|
|
221
221
|
case "plan":
|
|
222
|
-
await import("./resources-
|
|
222
|
+
await import("./resources-EPCEYCFY.js").then((m) => m.plan(args.slice(1)));
|
|
223
223
|
break;
|
|
224
224
|
case "apply":
|
|
225
|
-
await import("./resources-
|
|
225
|
+
await import("./resources-EPCEYCFY.js").then((m) => m.apply(args.slice(1)));
|
|
226
226
|
break;
|
|
227
227
|
case "pull":
|
|
228
|
-
await import("./resources-
|
|
228
|
+
await import("./resources-EPCEYCFY.js").then((m) => m.pull(args.slice(1)));
|
|
229
229
|
break;
|
|
230
230
|
case "destroy":
|
|
231
|
-
await import("./resources-
|
|
231
|
+
await import("./resources-EPCEYCFY.js").then((m) => m.destroy(args.slice(1)));
|
|
232
232
|
break;
|
|
233
233
|
case "list":
|
|
234
|
-
await import("./resources-
|
|
234
|
+
await import("./resources-EPCEYCFY.js").then((m) => m.list(args.slice(1)));
|
|
235
235
|
break;
|
|
236
236
|
case "show":
|
|
237
|
-
await import("./resources-
|
|
237
|
+
await import("./resources-EPCEYCFY.js").then((m) => m.show(args.slice(1)));
|
|
238
238
|
break;
|
|
239
239
|
case "diff":
|
|
240
|
-
await import("./resources-
|
|
240
|
+
await import("./resources-EPCEYCFY.js").then((m) => m.diff(args.slice(1)));
|
|
241
241
|
break;
|
|
242
242
|
// Development
|
|
243
243
|
case "dev":
|
|
244
|
-
await import("./dev-
|
|
244
|
+
await import("./dev-RENAXSGD.js").then((m) => m.dev(args.slice(1)));
|
|
245
245
|
break;
|
|
246
246
|
case "run":
|
|
247
|
-
await import("./run-
|
|
247
|
+
await import("./run-XWXUBWWH.js").then((m) => m.run(args.slice(1)));
|
|
248
248
|
break;
|
|
249
249
|
// Project
|
|
250
250
|
case "init":
|
|
251
|
-
await import("./init-
|
|
251
|
+
await import("./init-J5BNFCSP.js").then((m) => m.init(args.slice(1)));
|
|
252
252
|
break;
|
|
253
253
|
case "register":
|
|
254
|
-
await import("./register-
|
|
254
|
+
await import("./register-ZYUFXURK.js").then((m) => m.register(args.slice(1)));
|
|
255
255
|
break;
|
|
256
256
|
case "templates":
|
|
257
257
|
await import("./templates-LNUOTNLN.js").then((m) => m.templates(subcommand, args.slice(2)));
|
|
@@ -268,7 +268,7 @@ async function main() {
|
|
|
268
268
|
break;
|
|
269
269
|
// Dependencies
|
|
270
270
|
case "deps":
|
|
271
|
-
await import("./deps-
|
|
271
|
+
await import("./deps-53AOYHH2.js").then((m) => m.deps(args.slice(1)));
|
|
272
272
|
break;
|
|
273
273
|
// Auth
|
|
274
274
|
case "login":
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
projectResourceDepsEnabled,
|
|
6
6
|
syncDeps
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2WDZ3QKS.js";
|
|
8
8
|
import {
|
|
9
9
|
loadEnv
|
|
10
10
|
} from "./chunk-2CR762KB.js";
|
|
11
11
|
import {
|
|
12
12
|
createApiClient
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-SMZESQV2.js";
|
|
14
14
|
import {
|
|
15
15
|
findProjectRoot,
|
|
16
16
|
getApiUrl,
|
|
@@ -1847,19 +1847,41 @@ async function planAgents(api, localAgents, projectId) {
|
|
|
1847
1847
|
const remoteByExternalId = new Map(
|
|
1848
1848
|
remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
|
|
1849
1849
|
);
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
const
|
|
1853
|
-
|
|
1850
|
+
const refToId = /* @__PURE__ */ new Map();
|
|
1851
|
+
const skillIdToSlug = /* @__PURE__ */ new Map();
|
|
1852
|
+
const blockedRefs = /* @__PURE__ */ new Set();
|
|
1853
|
+
const planRefs = [
|
|
1854
|
+
.../* @__PURE__ */ new Set([
|
|
1855
|
+
...localAgents.flatMap((a) => a.agent.skills ?? []),
|
|
1856
|
+
...remoteAgents.flatMap((a) => a.skill_ids ?? [])
|
|
1857
|
+
])
|
|
1858
|
+
];
|
|
1859
|
+
if (planRefs.length > 0) {
|
|
1854
1860
|
try {
|
|
1855
|
-
const skills = await api.
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1861
|
+
const skills = await api.lookupAgentSkills(planRefs);
|
|
1862
|
+
for (const s of skills) {
|
|
1863
|
+
skillIdToSlug.set(s.id, s.slug);
|
|
1864
|
+
if (isAvailableToCustomAgents(s)) {
|
|
1865
|
+
refToId.set(s.slug, s.id);
|
|
1866
|
+
refToId.set(s.id, s.id);
|
|
1867
|
+
} else {
|
|
1868
|
+
blockedRefs.add(s.slug);
|
|
1869
|
+
blockedRefs.add(s.id);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
} catch (e) {
|
|
1873
|
+
console.log(pc2.yellow(` \u26A0 Could not resolve skills for plan: ${e}`));
|
|
1859
1874
|
}
|
|
1860
1875
|
}
|
|
1861
1876
|
for (const { agent, systemPrompt, policyScript } of localAgents) {
|
|
1862
1877
|
const remote = remoteByExternalId.get(agent.external_id);
|
|
1878
|
+
for (const ref of agent.skills ?? []) {
|
|
1879
|
+
if (blockedRefs.has(ref)) {
|
|
1880
|
+
console.log(pc2.red(` \u2717 Skill "${ref}" is a Lumera platform skill, only available to Lumera-built agents \u2014 apply will fail for this agent`));
|
|
1881
|
+
} else if (!refToId.has(ref)) {
|
|
1882
|
+
console.log(pc2.red(` \u2717 Skill "${ref}" not found \u2014 apply will fail for this agent`));
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1863
1885
|
if (!remote) {
|
|
1864
1886
|
changes.push({ type: "create", resource: "agent", id: agent.external_id, name: agent.name });
|
|
1865
1887
|
} else {
|
|
@@ -1871,7 +1893,7 @@ async function planAgents(api, localAgents, projectId) {
|
|
|
1871
1893
|
if ((remote.policy_script || "").trim() !== (policyScript || "").trim()) diffs.push("policy_script");
|
|
1872
1894
|
if ((remote.policy_enabled || false) !== (agent.policy_enabled || false)) diffs.push("policy_enabled");
|
|
1873
1895
|
if ((remote.policy_description || "") !== (agent.policy_description || "")) diffs.push("policy_description");
|
|
1874
|
-
const localSkillIds = (agent.skills || []).map((s) =>
|
|
1896
|
+
const localSkillIds = (agent.skills || []).map((s) => refToId.get(s)).filter((id) => !!id).sort();
|
|
1875
1897
|
const remoteSkillIds = [...remote.skill_ids || []].sort();
|
|
1876
1898
|
if (localSkillIds.join(",") !== remoteSkillIds.join(",")) {
|
|
1877
1899
|
const addedSlugs = localSkillIds.filter((id) => !remoteSkillIds.includes(id)).map((id) => skillIdToSlug.get(id) || id);
|
|
@@ -1895,35 +1917,65 @@ async function planAgents(api, localAgents, projectId) {
|
|
|
1895
1917
|
}
|
|
1896
1918
|
return changes;
|
|
1897
1919
|
}
|
|
1920
|
+
var TAG_AVAILABLE_TO_CUSTOM_AGENTS = "available_to_custom_agents";
|
|
1921
|
+
function isAvailableToCustomAgents(skill) {
|
|
1922
|
+
if (!skill.managed) return true;
|
|
1923
|
+
return (skill.tags ?? []).includes(TAG_AVAILABLE_TO_CUSTOM_AGENTS);
|
|
1924
|
+
}
|
|
1898
1925
|
async function applyAgents(api, localAgents, projectId) {
|
|
1899
1926
|
let errors = 0;
|
|
1900
1927
|
const remoteAgents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
|
|
1901
1928
|
const remoteByExternalId = new Map(
|
|
1902
1929
|
remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
|
|
1903
1930
|
);
|
|
1904
|
-
|
|
1905
|
-
const
|
|
1906
|
-
|
|
1931
|
+
const refToId = /* @__PURE__ */ new Map();
|
|
1932
|
+
const blockedRefs = /* @__PURE__ */ new Set();
|
|
1933
|
+
const refs = [...new Set(localAgents.flatMap((a) => a.agent.skills ?? []))];
|
|
1934
|
+
if (refs.length > 0) {
|
|
1907
1935
|
try {
|
|
1908
|
-
const skills = await api.
|
|
1909
|
-
|
|
1936
|
+
const skills = await api.lookupAgentSkills(refs);
|
|
1937
|
+
for (const s of skills) {
|
|
1938
|
+
if (isAvailableToCustomAgents(s)) {
|
|
1939
|
+
refToId.set(s.slug, s.id);
|
|
1940
|
+
refToId.set(s.id, s.id);
|
|
1941
|
+
} else {
|
|
1942
|
+
blockedRefs.add(s.slug);
|
|
1943
|
+
blockedRefs.add(s.id);
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1910
1946
|
} catch (e) {
|
|
1911
|
-
console.log(pc2.yellow(` \u26A0 Could not
|
|
1947
|
+
console.log(pc2.yellow(` \u26A0 Could not resolve skills: ${e}`));
|
|
1912
1948
|
}
|
|
1913
1949
|
}
|
|
1914
1950
|
for (const { agent, systemPrompt, policyScript } of localAgents) {
|
|
1915
1951
|
const remote = remoteByExternalId.get(agent.external_id);
|
|
1916
1952
|
const skillIds = [];
|
|
1953
|
+
const blockedForAgent = [];
|
|
1954
|
+
const notFoundForAgent = [];
|
|
1917
1955
|
if (agent.skills) {
|
|
1918
|
-
for (const
|
|
1919
|
-
const id =
|
|
1956
|
+
for (const ref of agent.skills) {
|
|
1957
|
+
const id = refToId.get(ref);
|
|
1920
1958
|
if (id) {
|
|
1921
1959
|
skillIds.push(id);
|
|
1960
|
+
} else if (blockedRefs.has(ref)) {
|
|
1961
|
+
blockedForAgent.push(ref);
|
|
1922
1962
|
} else {
|
|
1923
|
-
|
|
1963
|
+
notFoundForAgent.push(ref);
|
|
1924
1964
|
}
|
|
1925
1965
|
}
|
|
1926
1966
|
}
|
|
1967
|
+
if (blockedForAgent.length > 0 || notFoundForAgent.length > 0) {
|
|
1968
|
+
console.log(pc2.red(" \u2717"), `${agent.name}:`);
|
|
1969
|
+
if (blockedForAgent.length > 0) {
|
|
1970
|
+
console.log(pc2.red(` skills not available for custom agents: ${blockedForAgent.join(", ")}`));
|
|
1971
|
+
}
|
|
1972
|
+
if (notFoundForAgent.length > 0) {
|
|
1973
|
+
console.log(pc2.red(` skills not found: ${notFoundForAgent.join(", ")}`));
|
|
1974
|
+
}
|
|
1975
|
+
console.log(pc2.dim(` pick skills from GET /api/skills (tags includes "available_to_custom_agents")`));
|
|
1976
|
+
errors++;
|
|
1977
|
+
continue;
|
|
1978
|
+
}
|
|
1927
1979
|
const payload = {
|
|
1928
1980
|
external_id: agent.external_id,
|
|
1929
1981
|
name: agent.name,
|
|
@@ -1955,11 +2007,16 @@ async function pullAgents(api, platformDir, filterName, projectId) {
|
|
|
1955
2007
|
const agentsDir = join2(platformDir, "agents");
|
|
1956
2008
|
mkdirSync(agentsDir, { recursive: true });
|
|
1957
2009
|
const agents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
2010
|
+
const skillIdToSlug = /* @__PURE__ */ new Map();
|
|
2011
|
+
const pullRefs = [...new Set(agents.flatMap((a) => a.skill_ids ?? []))];
|
|
2012
|
+
if (pullRefs.length > 0) {
|
|
2013
|
+
try {
|
|
2014
|
+
const skills = await api.lookupAgentSkills(pullRefs);
|
|
2015
|
+
for (const s of skills) skillIdToSlug.set(s.id, s.slug);
|
|
2016
|
+
} catch (e) {
|
|
2017
|
+
console.log(pc2.yellow(` \u26A0 Could not resolve skills for pull: ${e}`));
|
|
2018
|
+
console.log(pc2.yellow(` Pulled configs may omit skills \u2014 review before re-applying.`));
|
|
2019
|
+
}
|
|
1963
2020
|
}
|
|
1964
2021
|
for (const agent of agents) {
|
|
1965
2022
|
if (!agent.external_id || agent.managed) continue;
|
package/package.json
CHANGED
|
@@ -128,7 +128,27 @@ Follow the user's lead. If they tell you exactly what to build, build it. The wo
|
|
|
128
128
|
### Rules
|
|
129
129
|
7. **Code is source of truth** — Edit files in `platform/`, then deploy with `lumera apply`. Don't edit in the Lumera UI.
|
|
130
130
|
8. **Keep docs current** — After each slice, update `architecture.md` with what was built (data models, relationships, hook logic, design decisions). Also update the project description at the top of this file (`AGENTS.md`) so it reflects what the project actually does now — not the original template description.
|
|
131
|
-
9. **Commit and push** — After each slice or significant change
|
|
131
|
+
9. **Commit and push** — After each slice or significant change, stage your changes, create a meaningful commit with both a title and description, then push. The sandbox is ephemeral — uncommitted work is lost if recycled.
|
|
132
|
+
- Use a conventional subject (`feat:`, `fix:`, `chore:`, `docs:`, `test:`) that explains the user-visible change, not just the filenames.
|
|
133
|
+
- Include a body that describes why the change was needed, what you changed, and the main areas covered.
|
|
134
|
+
- Avoid generic messages like `update files`, `changes`, `WIP`, or filename-only summaries.
|
|
135
|
+
- Prefer a HEREDOC so multi-line messages are reliable:
|
|
136
|
+
```bash
|
|
137
|
+
git add -A
|
|
138
|
+
git commit -m "$(cat <<'EOF'
|
|
139
|
+
feat: add invoice approval dashboard
|
|
140
|
+
|
|
141
|
+
Adds the first invoice review slice with a collection schema, seeded
|
|
142
|
+
example data, and a dashboard for approving or rejecting invoices.
|
|
143
|
+
|
|
144
|
+
Covers:
|
|
145
|
+
- invoice collection fields and statuses
|
|
146
|
+
- approval actions in the UI
|
|
147
|
+
- project documentation updates
|
|
148
|
+
EOF
|
|
149
|
+
)"
|
|
150
|
+
git push
|
|
151
|
+
```
|
|
132
152
|
10. **Deploy marker** — When your changes need `lumera apply`, include at the end of your response: `<!-- DEPLOY: short commit message -->`. Skip for frontend-only changes.
|
|
133
153
|
|
|
134
154
|
## File Artifacts
|