@lumerahq/cli 0.14.0 → 0.15.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.
package/dist/index.js
CHANGED
|
@@ -212,25 +212,25 @@ async function main() {
|
|
|
212
212
|
switch (command) {
|
|
213
213
|
// Resource commands
|
|
214
214
|
case "plan":
|
|
215
|
-
await import("./resources-
|
|
215
|
+
await import("./resources-BFT7V6UR.js").then((m) => m.plan(args.slice(1)));
|
|
216
216
|
break;
|
|
217
217
|
case "apply":
|
|
218
|
-
await import("./resources-
|
|
218
|
+
await import("./resources-BFT7V6UR.js").then((m) => m.apply(args.slice(1)));
|
|
219
219
|
break;
|
|
220
220
|
case "pull":
|
|
221
|
-
await import("./resources-
|
|
221
|
+
await import("./resources-BFT7V6UR.js").then((m) => m.pull(args.slice(1)));
|
|
222
222
|
break;
|
|
223
223
|
case "destroy":
|
|
224
|
-
await import("./resources-
|
|
224
|
+
await import("./resources-BFT7V6UR.js").then((m) => m.destroy(args.slice(1)));
|
|
225
225
|
break;
|
|
226
226
|
case "list":
|
|
227
|
-
await import("./resources-
|
|
227
|
+
await import("./resources-BFT7V6UR.js").then((m) => m.list(args.slice(1)));
|
|
228
228
|
break;
|
|
229
229
|
case "show":
|
|
230
|
-
await import("./resources-
|
|
230
|
+
await import("./resources-BFT7V6UR.js").then((m) => m.show(args.slice(1)));
|
|
231
231
|
break;
|
|
232
232
|
case "diff":
|
|
233
|
-
await import("./resources-
|
|
233
|
+
await import("./resources-BFT7V6UR.js").then((m) => m.diff(args.slice(1)));
|
|
234
234
|
break;
|
|
235
235
|
// Development
|
|
236
236
|
case "dev":
|
|
@@ -125,12 +125,14 @@ ${pc.dim("Resources:")}
|
|
|
125
125
|
app Deploy the frontend app
|
|
126
126
|
|
|
127
127
|
${pc.dim("Options:")}
|
|
128
|
+
--yes, -y Skip confirmation prompt (for CI/CD)
|
|
128
129
|
--skip-build Skip build step when applying app
|
|
129
130
|
|
|
130
131
|
${pc.dim("Examples:")}
|
|
131
|
-
lumera apply # Apply everything
|
|
132
|
+
lumera apply # Apply everything (shows plan, asks to confirm)
|
|
132
133
|
lumera apply collections # Apply all collections
|
|
133
134
|
lumera apply collections/users # Apply single collection
|
|
135
|
+
lumera apply agents -y # Apply agents without confirmation
|
|
134
136
|
lumera apply app # Deploy frontend
|
|
135
137
|
lumera apply app --skip-build # Deploy without rebuilding
|
|
136
138
|
`);
|
|
@@ -482,6 +484,30 @@ function mapFieldType(type) {
|
|
|
482
484
|
};
|
|
483
485
|
return typeMap[type] || type;
|
|
484
486
|
}
|
|
487
|
+
function fieldsDiffer(local, remote) {
|
|
488
|
+
if (mapFieldType(local.type) !== remote.type) return true;
|
|
489
|
+
if ((local.required || false) !== (remote.required || false)) return true;
|
|
490
|
+
const opts = remote.options || {};
|
|
491
|
+
if (local.type === "select") {
|
|
492
|
+
const localValues = [...local.values || []].sort();
|
|
493
|
+
const remoteValues = [...opts.values || []].sort();
|
|
494
|
+
if (localValues.join(",") !== remoteValues.join(",")) return true;
|
|
495
|
+
const localMultiple = local.multiple || false;
|
|
496
|
+
const remoteMaxSelect = opts.maxSelect || 1;
|
|
497
|
+
if (localMultiple && remoteMaxSelect <= 1) return true;
|
|
498
|
+
if (!localMultiple && remoteMaxSelect > 1) return true;
|
|
499
|
+
}
|
|
500
|
+
if (local.type === "relation") {
|
|
501
|
+
if (local.collection && local.collection !== opts.collectionId) return true;
|
|
502
|
+
const localMultiple = local.multiple || false;
|
|
503
|
+
const remoteMaxSelect = opts.maxSelect || 1;
|
|
504
|
+
if (localMultiple && remoteMaxSelect <= 1) return true;
|
|
505
|
+
if (!localMultiple && remoteMaxSelect > 1) return true;
|
|
506
|
+
}
|
|
507
|
+
if (local.min !== void 0 && local.min !== opts.min) return true;
|
|
508
|
+
if (local.max !== void 0 && local.max !== opts.max) return true;
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
485
511
|
async function planCollections(api, localCollections) {
|
|
486
512
|
const changes = [];
|
|
487
513
|
const remoteCollections = await api.listCollections();
|
|
@@ -509,10 +535,20 @@ async function planCollections(api, localCollections) {
|
|
|
509
535
|
const remoteFieldMap = new Map(remote.schema.map((f) => [f.name, f]));
|
|
510
536
|
const added = [...localFieldNames].filter((n) => !remoteFieldNames.has(n));
|
|
511
537
|
const removed = [...remoteFieldNames].filter((n) => !localFieldNames.has(n));
|
|
512
|
-
|
|
538
|
+
const modified = [];
|
|
539
|
+
for (const name of localFieldNames) {
|
|
540
|
+
if (!remoteFieldNames.has(name)) continue;
|
|
541
|
+
const localField = localFieldMap.get(name);
|
|
542
|
+
const remoteField = remoteFieldMap.get(name);
|
|
543
|
+
if (fieldsDiffer(localField, remoteField)) {
|
|
544
|
+
modified.push(name);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (added.length > 0 || removed.length > 0 || modified.length > 0) {
|
|
513
548
|
const details = [];
|
|
514
549
|
if (added.length > 0) details.push(`+${added.length} field${added.length > 1 ? "s" : ""}`);
|
|
515
550
|
if (removed.length > 0) details.push(`-${removed.length} field${removed.length > 1 ? "s" : ""}`);
|
|
551
|
+
if (modified.length > 0) details.push(`~${modified.length} field${modified.length > 1 ? "s" : ""} (${modified.join(", ")})`);
|
|
516
552
|
const fieldDetails = [];
|
|
517
553
|
for (const name of added) {
|
|
518
554
|
const f = localFieldMap.get(name);
|
|
@@ -967,6 +1003,17 @@ async function planAgents(api, localAgents) {
|
|
|
967
1003
|
const remoteByExternalId = new Map(
|
|
968
1004
|
remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
|
|
969
1005
|
);
|
|
1006
|
+
let skillSlugToId = /* @__PURE__ */ new Map();
|
|
1007
|
+
let skillIdToSlug = /* @__PURE__ */ new Map();
|
|
1008
|
+
const hasSkillRefs = localAgents.some((a) => a.agent.skills && a.agent.skills.length > 0) || remoteAgents.some((a) => a.skill_ids && a.skill_ids.length > 0);
|
|
1009
|
+
if (hasSkillRefs) {
|
|
1010
|
+
try {
|
|
1011
|
+
const skills = await api.listAgentSkills();
|
|
1012
|
+
skillSlugToId = new Map(skills.map((s) => [s.slug, s.id]));
|
|
1013
|
+
skillIdToSlug = new Map(skills.map((s) => [s.id, s.slug]));
|
|
1014
|
+
} catch {
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
970
1017
|
for (const { agent, systemPrompt, policyScript } of localAgents) {
|
|
971
1018
|
const remote = remoteByExternalId.get(agent.external_id);
|
|
972
1019
|
if (!remote) {
|
|
@@ -979,6 +1026,16 @@ async function planAgents(api, localAgents) {
|
|
|
979
1026
|
if ((remote.model || "") !== (agent.model || "")) diffs.push("model");
|
|
980
1027
|
if ((remote.policy_script || "").trim() !== (policyScript || "").trim()) diffs.push("policy_script");
|
|
981
1028
|
if ((remote.policy_enabled || false) !== (agent.policy_enabled || false)) diffs.push("policy_enabled");
|
|
1029
|
+
const localSkillIds = (agent.skills || []).map((s) => skillSlugToId.get(s) || s).sort();
|
|
1030
|
+
const remoteSkillIds = [...remote.skill_ids || []].sort();
|
|
1031
|
+
if (localSkillIds.join(",") !== remoteSkillIds.join(",")) {
|
|
1032
|
+
const addedSlugs = localSkillIds.filter((id) => !remoteSkillIds.includes(id)).map((id) => skillIdToSlug.get(id) || id);
|
|
1033
|
+
const removedSlugs = remoteSkillIds.filter((id) => !localSkillIds.includes(id)).map((id) => skillIdToSlug.get(id) || id);
|
|
1034
|
+
const parts = [];
|
|
1035
|
+
if (addedSlugs.length) parts.push(`+${addedSlugs.join(", +")}`);
|
|
1036
|
+
if (removedSlugs.length) parts.push(`-${removedSlugs.join(", -")}`);
|
|
1037
|
+
diffs.push(`skills (${parts.join(", ")})`);
|
|
1038
|
+
}
|
|
982
1039
|
if (diffs.length > 0) {
|
|
983
1040
|
const textDiffs = [];
|
|
984
1041
|
if (diffs.includes("system_prompt")) {
|
|
@@ -1739,11 +1796,12 @@ async function apply(args) {
|
|
|
1739
1796
|
const platformDir = getPlatformDir();
|
|
1740
1797
|
const api = createApiClient();
|
|
1741
1798
|
const appName = getAppName(projectRoot);
|
|
1742
|
-
const { type, name } = parseResource(args[0]);
|
|
1743
|
-
|
|
1744
|
-
console.log(pc.cyan(pc.bold(" Apply")));
|
|
1745
|
-
console.log();
|
|
1799
|
+
const { type, name } = parseResource(args.filter((a) => a !== "--yes" && a !== "-y")[0]);
|
|
1800
|
+
const autoConfirm = args.includes("--yes") || args.includes("-y") || !!process.env.CI;
|
|
1746
1801
|
if (type === "app") {
|
|
1802
|
+
console.log();
|
|
1803
|
+
console.log(pc.cyan(pc.bold(" Apply")));
|
|
1804
|
+
console.log();
|
|
1747
1805
|
console.log(pc.bold(" App:"));
|
|
1748
1806
|
await applyApp(args);
|
|
1749
1807
|
console.log();
|
|
@@ -1752,77 +1810,131 @@ async function apply(args) {
|
|
|
1752
1810
|
return;
|
|
1753
1811
|
}
|
|
1754
1812
|
let collections;
|
|
1755
|
-
let totalErrors = 0;
|
|
1756
|
-
if (!type || type === "collections") {
|
|
1757
|
-
const localCollections = loadLocalCollections(platformDir, name || void 0);
|
|
1758
|
-
if (localCollections.length > 0) {
|
|
1759
|
-
console.log(pc.bold(" Collections:"));
|
|
1760
|
-
totalErrors += await applyCollections(api, localCollections);
|
|
1761
|
-
console.log();
|
|
1762
|
-
} else if (name) {
|
|
1763
|
-
console.log(pc.red(` Collection "${name}" not found locally`));
|
|
1764
|
-
process.exit(1);
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
1813
|
try {
|
|
1768
1814
|
const remoteCollections = await api.listCollections();
|
|
1769
1815
|
collections = new Map(remoteCollections.map((c) => [c.name, c.id]));
|
|
1770
|
-
for (const c of remoteCollections)
|
|
1771
|
-
collections.set(c.id, c.id);
|
|
1772
|
-
}
|
|
1816
|
+
for (const c of remoteCollections) collections.set(c.id, c.id);
|
|
1773
1817
|
} catch {
|
|
1774
1818
|
collections = /* @__PURE__ */ new Map();
|
|
1775
1819
|
}
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
const localHooks = loadLocalHooks(platformDir, name || void 0, appName);
|
|
1789
|
-
if (localHooks.length > 0) {
|
|
1790
|
-
console.log(pc.bold(" Hooks:"));
|
|
1791
|
-
totalErrors += await applyHooks(api, localHooks, collections);
|
|
1792
|
-
console.log();
|
|
1793
|
-
} else if (name) {
|
|
1794
|
-
console.log(pc.red(` Hook "${name}" not found locally`));
|
|
1795
|
-
process.exit(1);
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
if (!type || type === "agents") {
|
|
1799
|
-
const localAgents = loadLocalAgents(platformDir, name || void 0, appName);
|
|
1800
|
-
if (localAgents.length > 0) {
|
|
1801
|
-
console.log(pc.bold(" Agents:"));
|
|
1802
|
-
totalErrors += await applyAgents(api, localAgents);
|
|
1820
|
+
const allChanges = [];
|
|
1821
|
+
const localCollections = !type || type === "collections" ? loadLocalCollections(platformDir, name || void 0) : [];
|
|
1822
|
+
const localAutomations = !type || type === "automations" ? loadLocalAutomations(platformDir, name || void 0, appName) : [];
|
|
1823
|
+
const localHooks = !type || type === "hooks" ? loadLocalHooks(platformDir, name || void 0, appName) : [];
|
|
1824
|
+
const localAgents = !type || type === "agents" ? loadLocalAgents(platformDir, name || void 0, appName) : [];
|
|
1825
|
+
if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections));
|
|
1826
|
+
if (localAutomations.length > 0) allChanges.push(...await planAutomations(api, localAutomations));
|
|
1827
|
+
if (localHooks.length > 0) allChanges.push(...await planHooks(api, localHooks, collections));
|
|
1828
|
+
if (localAgents.length > 0) allChanges.push(...await planAgents(api, localAgents));
|
|
1829
|
+
if (name) {
|
|
1830
|
+
const hasLocal = localCollections.length > 0 || localAutomations.length > 0 || localHooks.length > 0 || localAgents.length > 0;
|
|
1831
|
+
if (!hasLocal) {
|
|
1803
1832
|
console.log();
|
|
1804
|
-
|
|
1805
|
-
console.log(pc.red(` Agent "${name}" not found locally`));
|
|
1833
|
+
console.log(pc.red(` Resource "${name}" not found locally`));
|
|
1806
1834
|
process.exit(1);
|
|
1807
1835
|
}
|
|
1808
1836
|
}
|
|
1837
|
+
let willDeployApp = false;
|
|
1809
1838
|
if (!type) {
|
|
1810
1839
|
try {
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
console.log(pc.bold(" App:"));
|
|
1814
|
-
await applyApp(args);
|
|
1815
|
-
console.log();
|
|
1840
|
+
if (existsSync(join(projectRoot, "dist")) || existsSync(join(projectRoot, "src"))) {
|
|
1841
|
+
willDeployApp = true;
|
|
1816
1842
|
}
|
|
1817
1843
|
} catch {
|
|
1818
1844
|
}
|
|
1819
1845
|
}
|
|
1846
|
+
if (allChanges.length === 0 && !willDeployApp) {
|
|
1847
|
+
console.log();
|
|
1848
|
+
console.log(pc.green(" \u2713 Nothing to apply \u2014 local and remote are in sync."));
|
|
1849
|
+
console.log();
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
console.log();
|
|
1853
|
+
console.log(pc.cyan(pc.bold(" Apply")));
|
|
1854
|
+
console.log();
|
|
1855
|
+
const creates = allChanges.filter((c) => c.type === "create");
|
|
1856
|
+
const updates = allChanges.filter((c) => c.type === "update");
|
|
1857
|
+
if (allChanges.length > 0) {
|
|
1858
|
+
console.log(pc.bold(" Plan:"));
|
|
1859
|
+
for (const change of allChanges) {
|
|
1860
|
+
const icon = change.type === "create" ? "+" : "~";
|
|
1861
|
+
const color = change.type === "create" ? pc.green : pc.yellow;
|
|
1862
|
+
const details = change.details ? ` (${change.details})` : "";
|
|
1863
|
+
console.log(` ${color(icon)} ${change.resource}: ${change.name}${pc.dim(details)}`);
|
|
1864
|
+
}
|
|
1865
|
+
if (willDeployApp) console.log(` ${pc.blue("\u25CF")} app: frontend build + deploy`);
|
|
1866
|
+
console.log();
|
|
1867
|
+
const parts = [];
|
|
1868
|
+
if (creates.length > 0) parts.push(pc.green(`${creates.length} create`));
|
|
1869
|
+
if (updates.length > 0) parts.push(pc.yellow(`${updates.length} update`));
|
|
1870
|
+
if (willDeployApp) parts.push(pc.blue("1 app deploy"));
|
|
1871
|
+
console.log(` ${parts.join(", ")}`);
|
|
1872
|
+
console.log();
|
|
1873
|
+
} else if (willDeployApp) {
|
|
1874
|
+
console.log(pc.dim(" No infrastructure changes \u2014 deploying app only."));
|
|
1875
|
+
console.log();
|
|
1876
|
+
}
|
|
1877
|
+
if (!autoConfirm && allChanges.length > 0) {
|
|
1878
|
+
const { confirm } = await prompts({
|
|
1879
|
+
type: "confirm",
|
|
1880
|
+
name: "confirm",
|
|
1881
|
+
message: " Proceed with apply?",
|
|
1882
|
+
initial: true
|
|
1883
|
+
});
|
|
1884
|
+
if (!confirm) {
|
|
1885
|
+
console.log(pc.dim(" Cancelled."));
|
|
1886
|
+
console.log();
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1889
|
+
console.log();
|
|
1890
|
+
}
|
|
1891
|
+
let totalErrors = 0;
|
|
1892
|
+
let totalCreated = 0;
|
|
1893
|
+
let totalUpdated = 0;
|
|
1894
|
+
let totalSkipped = 0;
|
|
1895
|
+
if (localCollections.length > 0) {
|
|
1896
|
+
console.log(pc.bold(" Collections:"));
|
|
1897
|
+
totalErrors += await applyCollections(api, localCollections);
|
|
1898
|
+
console.log();
|
|
1899
|
+
}
|
|
1900
|
+
try {
|
|
1901
|
+
const remoteCollections = await api.listCollections();
|
|
1902
|
+
collections = new Map(remoteCollections.map((c) => [c.name, c.id]));
|
|
1903
|
+
for (const c of remoteCollections) collections.set(c.id, c.id);
|
|
1904
|
+
} catch {
|
|
1905
|
+
}
|
|
1906
|
+
if (localAutomations.length > 0) {
|
|
1907
|
+
console.log(pc.bold(" Automations:"));
|
|
1908
|
+
totalErrors += await applyAutomations(api, localAutomations);
|
|
1909
|
+
console.log();
|
|
1910
|
+
}
|
|
1911
|
+
if (localHooks.length > 0) {
|
|
1912
|
+
console.log(pc.bold(" Hooks:"));
|
|
1913
|
+
totalErrors += await applyHooks(api, localHooks, collections);
|
|
1914
|
+
console.log();
|
|
1915
|
+
}
|
|
1916
|
+
if (localAgents.length > 0) {
|
|
1917
|
+
console.log(pc.bold(" Agents:"));
|
|
1918
|
+
totalErrors += await applyAgents(api, localAgents);
|
|
1919
|
+
console.log();
|
|
1920
|
+
}
|
|
1921
|
+
if (willDeployApp) {
|
|
1922
|
+
console.log(pc.bold(" App:"));
|
|
1923
|
+
await applyApp(args);
|
|
1924
|
+
console.log();
|
|
1925
|
+
}
|
|
1926
|
+
totalCreated = creates.length;
|
|
1927
|
+
totalUpdated = updates.length;
|
|
1820
1928
|
if (totalErrors > 0) {
|
|
1821
|
-
console.log(pc.red(`
|
|
1929
|
+
console.log(pc.red(` \u2717 ${totalErrors} error${totalErrors > 1 ? "s" : ""} during apply.`));
|
|
1822
1930
|
console.log();
|
|
1823
1931
|
process.exit(1);
|
|
1824
1932
|
}
|
|
1825
|
-
|
|
1933
|
+
const summary = [];
|
|
1934
|
+
if (totalCreated > 0) summary.push(pc.green(`${totalCreated} created`));
|
|
1935
|
+
if (totalUpdated > 0) summary.push(pc.yellow(`${totalUpdated} updated`));
|
|
1936
|
+
if (willDeployApp) summary.push(pc.blue("app deployed"));
|
|
1937
|
+
console.log(pc.green(" \u2713 Done!") + (summary.length > 0 ? ` ${pc.dim("\u2014")} ${summary.join(", ")}` : ""));
|
|
1826
1938
|
console.log();
|
|
1827
1939
|
}
|
|
1828
1940
|
async function pull(args) {
|