@lumerahq/cli 0.19.6 → 0.19.8-dev.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.
@@ -246,6 +246,17 @@ var ApiClient = class {
246
246
  const result = await this.request("/api/lm_agent_skills?limit=100");
247
247
  return result.skills || [];
248
248
  }
249
+ // Resolve a list of refs (slugs or IDs) to skill records. Unlike
250
+ // listAgentSkills, this returns managed skills as well — the caller has
251
+ // already named them, so there is no broad enumeration concern.
252
+ async lookupAgentSkills(refs) {
253
+ if (!refs || refs.length === 0) return [];
254
+ const result = await this.request("/api/lm_agent_skills/lookup", {
255
+ method: "POST",
256
+ body: JSON.stringify({ refs })
257
+ });
258
+ return result.skills || [];
259
+ }
249
260
  // Agent Invoke
250
261
  async invokeAgent(agentId, message, sessionId) {
251
262
  const body = { message };
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  createApiClient,
6
6
  isApiErrorStatus
7
- } from "./chunk-WY6UMJNI.js";
7
+ } from "./chunk-BAQROJO7.js";
8
8
  import {
9
9
  findProjectRoot,
10
10
  getAppName
@@ -2,9 +2,9 @@ import {
2
2
  deps,
3
3
  projectResourceDepsEnabled,
4
4
  syncDeps
5
- } from "./chunk-RUJRTLHA.js";
5
+ } from "./chunk-ZDN32JTT.js";
6
6
  import "./chunk-2CR762KB.js";
7
- import "./chunk-WY6UMJNI.js";
7
+ import "./chunk-BAQROJO7.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-RUJRTLHA.js";
7
+ } from "./chunk-ZDN32JTT.js";
8
8
  import {
9
9
  loadEnv
10
10
  } from "./chunk-2CR762KB.js";
11
11
  import {
12
12
  createApiClient
13
- } from "./chunk-WY6UMJNI.js";
13
+ } from "./chunk-BAQROJO7.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-P7WAHOHR.js").then((m) => m.plan(args.slice(1)));
222
+ await import("./resources-VM42NAMH.js").then((m) => m.plan(args.slice(1)));
223
223
  break;
224
224
  case "apply":
225
- await import("./resources-P7WAHOHR.js").then((m) => m.apply(args.slice(1)));
225
+ await import("./resources-VM42NAMH.js").then((m) => m.apply(args.slice(1)));
226
226
  break;
227
227
  case "pull":
228
- await import("./resources-P7WAHOHR.js").then((m) => m.pull(args.slice(1)));
228
+ await import("./resources-VM42NAMH.js").then((m) => m.pull(args.slice(1)));
229
229
  break;
230
230
  case "destroy":
231
- await import("./resources-P7WAHOHR.js").then((m) => m.destroy(args.slice(1)));
231
+ await import("./resources-VM42NAMH.js").then((m) => m.destroy(args.slice(1)));
232
232
  break;
233
233
  case "list":
234
- await import("./resources-P7WAHOHR.js").then((m) => m.list(args.slice(1)));
234
+ await import("./resources-VM42NAMH.js").then((m) => m.list(args.slice(1)));
235
235
  break;
236
236
  case "show":
237
- await import("./resources-P7WAHOHR.js").then((m) => m.show(args.slice(1)));
237
+ await import("./resources-VM42NAMH.js").then((m) => m.show(args.slice(1)));
238
238
  break;
239
239
  case "diff":
240
- await import("./resources-P7WAHOHR.js").then((m) => m.diff(args.slice(1)));
240
+ await import("./resources-VM42NAMH.js").then((m) => m.diff(args.slice(1)));
241
241
  break;
242
242
  // Development
243
243
  case "dev":
244
- await import("./dev-YYMFCXZ5.js").then((m) => m.dev(args.slice(1)));
244
+ await import("./dev-GNZ22LKP.js").then((m) => m.dev(args.slice(1)));
245
245
  break;
246
246
  case "run":
247
- await import("./run-C23KZI4Z.js").then((m) => m.run(args.slice(1)));
247
+ await import("./run-QRFSRZXJ.js").then((m) => m.run(args.slice(1)));
248
248
  break;
249
249
  // Project
250
250
  case "init":
251
- await import("./init-7YWMMTBF.js").then((m) => m.init(args.slice(1)));
251
+ await import("./init-RS2ET656.js").then((m) => m.init(args.slice(1)));
252
252
  break;
253
253
  case "register":
254
- await import("./register-KJMSMMD6.js").then((m) => m.register(args.slice(1)));
254
+ await import("./register-MLYFAODC.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-73XZXRYP.js").then((m) => m.deps(args.slice(1)));
271
+ await import("./deps-DPB3L3EJ.js").then((m) => m.deps(args.slice(1)));
272
272
  break;
273
273
  // Auth
274
274
  case "login":
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-BHYDYR75.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-WY6UMJNI.js";
10
+ } from "./chunk-BAQROJO7.js";
11
11
  import {
12
12
  getToken,
13
13
  init_auth,
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-BHYDYR75.js";
7
7
  import {
8
8
  createApiClient
9
- } from "./chunk-WY6UMJNI.js";
9
+ } from "./chunk-BAQROJO7.js";
10
10
  import {
11
11
  findProjectRoot,
12
12
  getAppName,
@@ -4,13 +4,13 @@ import {
4
4
  import {
5
5
  projectResourceDepsEnabled,
6
6
  syncDeps
7
- } from "./chunk-RUJRTLHA.js";
7
+ } from "./chunk-ZDN32JTT.js";
8
8
  import {
9
9
  loadEnv
10
10
  } from "./chunk-2CR762KB.js";
11
11
  import {
12
12
  createApiClient
13
- } from "./chunk-WY6UMJNI.js";
13
+ } from "./chunk-BAQROJO7.js";
14
14
  import {
15
15
  findProjectRoot,
16
16
  getApiUrl,
@@ -1847,19 +1847,37 @@ 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
- let skillSlugToId = /* @__PURE__ */ new Map();
1851
- let skillIdToSlug = /* @__PURE__ */ new Map();
1852
- const hasSkillRefs = localAgents.some((a) => a.agent.skills && a.agent.skills.length > 0) || remoteAgents.some((a) => a.skill_ids && a.skill_ids.length > 0);
1853
- if (hasSkillRefs) {
1850
+ const skillSlugToId = /* @__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.listAgentSkills();
1856
- skillSlugToId = new Map(skills.map((s) => [s.slug, s.id]));
1857
- skillIdToSlug = new Map(skills.map((s) => [s.id, s.slug]));
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
+ skillSlugToId.set(s.slug, s.id);
1866
+ } else {
1867
+ blockedRefs.add(s.slug);
1868
+ blockedRefs.add(s.id);
1869
+ }
1870
+ }
1858
1871
  } catch {
1859
1872
  }
1860
1873
  }
1861
1874
  for (const { agent, systemPrompt, policyScript } of localAgents) {
1862
1875
  const remote = remoteByExternalId.get(agent.external_id);
1876
+ for (const ref of agent.skills ?? []) {
1877
+ if (blockedRefs.has(ref)) {
1878
+ console.log(pc2.yellow(` \u26A0 Skill "${ref}" is a Lumera platform skill, only available to Lumera-built agents \u2014 will be skipped on apply`));
1879
+ }
1880
+ }
1863
1881
  if (!remote) {
1864
1882
  changes.push({ type: "create", resource: "agent", id: agent.external_id, name: agent.name });
1865
1883
  } else {
@@ -1871,7 +1889,7 @@ async function planAgents(api, localAgents, projectId) {
1871
1889
  if ((remote.policy_script || "").trim() !== (policyScript || "").trim()) diffs.push("policy_script");
1872
1890
  if ((remote.policy_enabled || false) !== (agent.policy_enabled || false)) diffs.push("policy_enabled");
1873
1891
  if ((remote.policy_description || "") !== (agent.policy_description || "")) diffs.push("policy_description");
1874
- const localSkillIds = (agent.skills || []).map((s) => skillSlugToId.get(s) || s).sort();
1892
+ const localSkillIds = (agent.skills || []).filter((s) => !blockedRefs.has(s)).map((s) => skillSlugToId.get(s) || s).sort();
1875
1893
  const remoteSkillIds = [...remote.skill_ids || []].sort();
1876
1894
  if (localSkillIds.join(",") !== remoteSkillIds.join(",")) {
1877
1895
  const addedSlugs = localSkillIds.filter((id) => !remoteSkillIds.includes(id)).map((id) => skillIdToSlug.get(id) || id);
@@ -1895,32 +1913,48 @@ async function planAgents(api, localAgents, projectId) {
1895
1913
  }
1896
1914
  return changes;
1897
1915
  }
1916
+ var TAG_AVAILABLE_TO_CUSTOM_AGENTS = "available_to_custom_agents";
1917
+ function isAvailableToCustomAgents(skill) {
1918
+ if (!skill.managed) return true;
1919
+ return (skill.tags ?? []).includes(TAG_AVAILABLE_TO_CUSTOM_AGENTS);
1920
+ }
1898
1921
  async function applyAgents(api, localAgents, projectId) {
1899
1922
  let errors = 0;
1900
1923
  const remoteAgents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
1901
1924
  const remoteByExternalId = new Map(
1902
1925
  remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
1903
1926
  );
1904
- let skillMap = /* @__PURE__ */ new Map();
1905
- const hasSkillRefs = localAgents.some((a) => a.agent.skills && a.agent.skills.length > 0);
1906
- if (hasSkillRefs) {
1927
+ const refToId = /* @__PURE__ */ new Map();
1928
+ const blockedRefs = /* @__PURE__ */ new Set();
1929
+ const refs = [...new Set(localAgents.flatMap((a) => a.agent.skills ?? []))];
1930
+ if (refs.length > 0) {
1907
1931
  try {
1908
- const skills = await api.listAgentSkills();
1909
- skillMap = new Map(skills.map((s) => [s.slug, s.id]));
1932
+ const skills = await api.lookupAgentSkills(refs);
1933
+ for (const s of skills) {
1934
+ if (isAvailableToCustomAgents(s)) {
1935
+ refToId.set(s.slug, s.id);
1936
+ refToId.set(s.id, s.id);
1937
+ } else {
1938
+ blockedRefs.add(s.slug);
1939
+ blockedRefs.add(s.id);
1940
+ }
1941
+ }
1910
1942
  } catch (e) {
1911
- console.log(pc2.yellow(` \u26A0 Could not fetch skills for resolution: ${e}`));
1943
+ console.log(pc2.yellow(` \u26A0 Could not resolve skills: ${e}`));
1912
1944
  }
1913
1945
  }
1914
1946
  for (const { agent, systemPrompt, policyScript } of localAgents) {
1915
1947
  const remote = remoteByExternalId.get(agent.external_id);
1916
1948
  const skillIds = [];
1917
1949
  if (agent.skills) {
1918
- for (const slug of agent.skills) {
1919
- const id = skillMap.get(slug);
1950
+ for (const ref of agent.skills) {
1951
+ const id = refToId.get(ref);
1920
1952
  if (id) {
1921
1953
  skillIds.push(id);
1954
+ } else if (blockedRefs.has(ref)) {
1955
+ console.log(pc2.yellow(` \u26A0 Skill "${ref}" is a Lumera platform skill, only available to Lumera-built agents \u2014 skipping`));
1922
1956
  } else {
1923
- console.log(pc2.yellow(` \u26A0 Skill "${slug}" not found, skipping`));
1957
+ console.log(pc2.yellow(` \u26A0 Skill "${ref}" not found, skipping (use the slug, e.g. "using-collections")`));
1924
1958
  }
1925
1959
  }
1926
1960
  }
@@ -1955,11 +1989,14 @@ async function pullAgents(api, platformDir, filterName, projectId) {
1955
1989
  const agentsDir = join2(platformDir, "agents");
1956
1990
  mkdirSync(agentsDir, { recursive: true });
1957
1991
  const agents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
1958
- let skillIdToSlug = /* @__PURE__ */ new Map();
1959
- try {
1960
- const skills = await api.listAgentSkills();
1961
- skillIdToSlug = new Map(skills.map((s) => [s.id, s.slug]));
1962
- } catch {
1992
+ const skillIdToSlug = /* @__PURE__ */ new Map();
1993
+ const pullRefs = [...new Set(agents.flatMap((a) => a.skill_ids ?? []))];
1994
+ if (pullRefs.length > 0) {
1995
+ try {
1996
+ const skills = await api.lookupAgentSkills(pullRefs);
1997
+ for (const s of skills) skillIdToSlug.set(s.id, s.slug);
1998
+ } catch {
1999
+ }
1963
2000
  }
1964
2001
  for (const agent of agents) {
1965
2002
  if (!agent.external_id || agent.managed) continue;
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-2CR762KB.js";
4
4
  import {
5
5
  createApiClient
6
- } from "./chunk-WY6UMJNI.js";
6
+ } from "./chunk-BAQROJO7.js";
7
7
  import {
8
8
  findProjectRoot,
9
9
  getApiUrl,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumerahq/cli",
3
- "version": "0.19.6",
3
+ "version": "0.19.8-dev.0",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {
@@ -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: `git add -A && git commit -m "descriptive message" && git push`. The sandbox is ephemeral — uncommitted work is lost if recycled.
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