@lumerahq/cli 0.19.4 → 0.19.6

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.
@@ -137,19 +137,59 @@ function isPortInUse(port, host = "127.0.0.1") {
137
137
  });
138
138
  });
139
139
  }
140
- function detectRunner(projectRoot) {
141
- if (existsSync(resolve(projectRoot, "bun.lockb")) || existsSync(resolve(projectRoot, "bun.lock"))) {
142
- return ["bunx"];
143
- }
144
- if (existsSync(resolve(projectRoot, "pnpm-lock.yaml"))) {
145
- return ["pnpm", "exec"];
140
+ function commandAvailable(command) {
141
+ try {
142
+ execSync(`${command} --version`, { stdio: "ignore" });
143
+ return true;
144
+ } catch {
145
+ return false;
146
146
  }
147
+ }
148
+ function parsePackageManagerSpecifier(value) {
149
+ const raw = (value || "").trim();
150
+ if (!raw) return void 0;
151
+ const name = raw.split("@")[0];
152
+ return ["bun", "pnpm", "yarn", "npm"].includes(name) ? name : void 0;
153
+ }
154
+ function packageManagerFromPackageJson(projectRoot) {
147
155
  try {
148
- execSync("pnpm --version", { stdio: "ignore" });
149
- return ["pnpm", "exec"];
156
+ const pkg = JSON.parse(readFileSync(resolve(projectRoot, "package.json"), "utf-8"));
157
+ return parsePackageManagerSpecifier(pkg.packageManager);
150
158
  } catch {
151
- return ["bunx"];
159
+ return void 0;
160
+ }
161
+ }
162
+ function runnerForPackageManager(pm) {
163
+ if (pm === "pnpm") return ["pnpm", "exec"];
164
+ if (pm === "bun") return ["bunx"];
165
+ if (pm === "yarn") return ["yarn"];
166
+ return ["npx"];
167
+ }
168
+ function detectRunner(projectRoot) {
169
+ const requested = parsePackageManagerSpecifier(process.env.LUMERA_PACKAGE_MANAGER);
170
+ if (requested && commandAvailable(runnerForPackageManager(requested)[0])) {
171
+ return runnerForPackageManager(requested);
172
+ }
173
+ const declared = packageManagerFromPackageJson(projectRoot);
174
+ if (declared && commandAvailable(runnerForPackageManager(declared)[0])) {
175
+ return runnerForPackageManager(declared);
176
+ }
177
+ const lockfileManagers = [
178
+ { pm: "pnpm", file: "pnpm-lock.yaml" },
179
+ { pm: "bun", file: "bun.lockb" },
180
+ { pm: "bun", file: "bun.lock" },
181
+ { pm: "yarn", file: "yarn.lock" },
182
+ { pm: "npm", file: "package-lock.json" }
183
+ ];
184
+ for (const { pm, file } of lockfileManagers) {
185
+ const runner = runnerForPackageManager(pm);
186
+ if (existsSync(resolve(projectRoot, file)) && commandAvailable(runner[0])) return runner;
187
+ }
188
+ for (const pm of ["pnpm", "bun", "yarn", "npm"]) {
189
+ const runner = runnerForPackageManager(pm);
190
+ if (commandAvailable(runner[0])) return runner;
152
191
  }
192
+ return ["npx"];
153
193
  }
154
194
  function getParentOrigin(apiUrl) {
155
195
  return apiUrl.replace(/\/api\/?$/, "").replace(/\/$/, "");
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  createApiClient,
6
6
  isApiErrorStatus
7
- } from "./chunk-UH5X43VV.js";
7
+ } from "./chunk-WY6UMJNI.js";
8
8
  import {
9
9
  findProjectRoot,
10
10
  getAppName
@@ -117,6 +117,7 @@ var ApiClient = class {
117
117
  const qs = new URLSearchParams();
118
118
  if (params?.external_id) qs.set("external_id", params.external_id);
119
119
  if (params?.include_code) qs.set("include_code", "true");
120
+ if (params?.project_id) qs.set("project_id", params.project_id);
120
121
  qs.set("limit", "100");
121
122
  const all = [];
122
123
  let offset = 0;
@@ -179,6 +180,7 @@ var ApiClient = class {
179
180
  const query = new URLSearchParams();
180
181
  if (params?.collection_id) query.set("collection_id", params.collection_id);
181
182
  if (params?.external_id) query.set("external_id", params.external_id);
183
+ if (params?.project_id) query.set("project_id", params.project_id);
182
184
  const queryString = query.toString();
183
185
  const path = queryString ? `/api/pb/hooks?${queryString}` : "/api/pb/hooks";
184
186
  const result = await this.request(path);
@@ -2,9 +2,9 @@ import {
2
2
  deps,
3
3
  projectResourceDepsEnabled,
4
4
  syncDeps
5
- } from "./chunk-5T22627H.js";
5
+ } from "./chunk-RUJRTLHA.js";
6
6
  import "./chunk-2CR762KB.js";
7
- import "./chunk-UH5X43VV.js";
7
+ import "./chunk-WY6UMJNI.js";
8
8
  import "./chunk-ZH3NVYEQ.js";
9
9
  import "./chunk-FJFIWC7G.js";
10
10
  import "./chunk-PNKVD2UK.js";
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  dev
3
- } from "./chunk-SU26C4GL.js";
3
+ } from "./chunk-53NOF33P.js";
4
4
  import {
5
5
  projectResourceDepsEnabled,
6
6
  syncDeps
7
- } from "./chunk-5T22627H.js";
7
+ } from "./chunk-RUJRTLHA.js";
8
8
  import {
9
9
  loadEnv
10
10
  } from "./chunk-2CR762KB.js";
11
11
  import {
12
12
  createApiClient
13
- } from "./chunk-UH5X43VV.js";
13
+ } from "./chunk-WY6UMJNI.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-RHF2MDF7.js").then((m) => m.plan(args.slice(1)));
222
+ await import("./resources-P7WAHOHR.js").then((m) => m.plan(args.slice(1)));
223
223
  break;
224
224
  case "apply":
225
- await import("./resources-RHF2MDF7.js").then((m) => m.apply(args.slice(1)));
225
+ await import("./resources-P7WAHOHR.js").then((m) => m.apply(args.slice(1)));
226
226
  break;
227
227
  case "pull":
228
- await import("./resources-RHF2MDF7.js").then((m) => m.pull(args.slice(1)));
228
+ await import("./resources-P7WAHOHR.js").then((m) => m.pull(args.slice(1)));
229
229
  break;
230
230
  case "destroy":
231
- await import("./resources-RHF2MDF7.js").then((m) => m.destroy(args.slice(1)));
231
+ await import("./resources-P7WAHOHR.js").then((m) => m.destroy(args.slice(1)));
232
232
  break;
233
233
  case "list":
234
- await import("./resources-RHF2MDF7.js").then((m) => m.list(args.slice(1)));
234
+ await import("./resources-P7WAHOHR.js").then((m) => m.list(args.slice(1)));
235
235
  break;
236
236
  case "show":
237
- await import("./resources-RHF2MDF7.js").then((m) => m.show(args.slice(1)));
237
+ await import("./resources-P7WAHOHR.js").then((m) => m.show(args.slice(1)));
238
238
  break;
239
239
  case "diff":
240
- await import("./resources-RHF2MDF7.js").then((m) => m.diff(args.slice(1)));
240
+ await import("./resources-P7WAHOHR.js").then((m) => m.diff(args.slice(1)));
241
241
  break;
242
242
  // Development
243
243
  case "dev":
244
- await import("./dev-JLSTLIMZ.js").then((m) => m.dev(args.slice(1)));
244
+ await import("./dev-YYMFCXZ5.js").then((m) => m.dev(args.slice(1)));
245
245
  break;
246
246
  case "run":
247
- await import("./run-XJLB4AFD.js").then((m) => m.run(args.slice(1)));
247
+ await import("./run-C23KZI4Z.js").then((m) => m.run(args.slice(1)));
248
248
  break;
249
249
  // Project
250
250
  case "init":
251
- await import("./init-CBZAIERZ.js").then((m) => m.init(args.slice(1)));
251
+ await import("./init-7YWMMTBF.js").then((m) => m.init(args.slice(1)));
252
252
  break;
253
253
  case "register":
254
- await import("./register-N2LF3CCK.js").then((m) => m.register(args.slice(1)));
254
+ await import("./register-KJMSMMD6.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-GCOH3TXL.js").then((m) => m.deps(args.slice(1)));
271
+ await import("./deps-73XZXRYP.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-UH5X43VV.js";
10
+ } from "./chunk-WY6UMJNI.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-UH5X43VV.js";
9
+ } from "./chunk-WY6UMJNI.js";
10
10
  import {
11
11
  findProjectRoot,
12
12
  getAppName,
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  deploy
3
- } from "./chunk-SU26C4GL.js";
3
+ } from "./chunk-53NOF33P.js";
4
4
  import {
5
5
  projectResourceDepsEnabled,
6
6
  syncDeps
7
- } from "./chunk-5T22627H.js";
7
+ } from "./chunk-RUJRTLHA.js";
8
8
  import {
9
9
  loadEnv
10
10
  } from "./chunk-2CR762KB.js";
11
11
  import {
12
12
  createApiClient
13
- } from "./chunk-UH5X43VV.js";
13
+ } from "./chunk-WY6UMJNI.js";
14
14
  import {
15
15
  findProjectRoot,
16
16
  getApiUrl,
@@ -272,13 +272,82 @@ function lintCollectionFiles(projectRoot, platformDir, filterName) {
272
272
  printLintWarnings(issues, projectRoot);
273
273
  throw new Error(`Found ${errors.length} collection lint error(s)`);
274
274
  }
275
- function detectPackageManager() {
276
- for (const pm of ["bun", "pnpm", "yarn", "npm"]) {
277
- try {
278
- execFileSync(pm, ["--version"], { stdio: "ignore" });
279
- return pm;
280
- } catch {
275
+ var PACKAGE_MANAGERS = ["bun", "pnpm", "yarn", "npm"];
276
+ var PACKAGE_MANAGER_VALUE_FLAGS = /* @__PURE__ */ new Set(["--package-manager"]);
277
+ function isPackageManager(value) {
278
+ return PACKAGE_MANAGERS.includes(value);
279
+ }
280
+ function commandAvailable(command) {
281
+ try {
282
+ execFileSync(command, ["--version"], { stdio: "ignore" });
283
+ return true;
284
+ } catch {
285
+ return false;
286
+ }
287
+ }
288
+ function parsePackageManagerSpecifier(value) {
289
+ const raw = (value || "").trim();
290
+ if (!raw) return void 0;
291
+ const name = raw.split("@")[0];
292
+ return isPackageManager(name) ? name : void 0;
293
+ }
294
+ function packageManagerFromPackageJson(projectRoot) {
295
+ try {
296
+ const pkg = JSON.parse(readFileSync2(join2(projectRoot, "package.json"), "utf-8"));
297
+ return parsePackageManagerSpecifier(pkg.packageManager);
298
+ } catch {
299
+ return void 0;
300
+ }
301
+ }
302
+ function getFlagValue(args, name) {
303
+ const long = `--${name}`;
304
+ for (let i = 0; i < args.length; i++) {
305
+ const arg = args[i];
306
+ if (arg === long) {
307
+ const next = args[i + 1];
308
+ return next && !next.startsWith("-") ? next : void 0;
309
+ }
310
+ if (arg.startsWith(`${long}=`)) {
311
+ return arg.slice(long.length + 1);
312
+ }
313
+ }
314
+ return void 0;
315
+ }
316
+ function getPositionalArgs(args) {
317
+ const out = [];
318
+ for (let i = 0; i < args.length; i++) {
319
+ const arg = args[i];
320
+ if (PACKAGE_MANAGER_VALUE_FLAGS.has(arg)) {
321
+ i++;
322
+ continue;
281
323
  }
324
+ if (arg.startsWith("-")) continue;
325
+ out.push(arg);
326
+ }
327
+ return out;
328
+ }
329
+ function detectPackageManager(projectRoot, override) {
330
+ const requested = parsePackageManagerSpecifier(override || process.env.LUMERA_PACKAGE_MANAGER);
331
+ if (requested) {
332
+ if (!commandAvailable(requested)) {
333
+ throw new Error(`Package manager '${requested}' was requested but is not available on PATH`);
334
+ }
335
+ return requested;
336
+ }
337
+ const declared = packageManagerFromPackageJson(projectRoot);
338
+ if (declared && commandAvailable(declared)) return declared;
339
+ const lockfileManagers = [
340
+ { pm: "pnpm", file: "pnpm-lock.yaml" },
341
+ { pm: "bun", file: "bun.lockb" },
342
+ { pm: "bun", file: "bun.lock" },
343
+ { pm: "yarn", file: "yarn.lock" },
344
+ { pm: "npm", file: "package-lock.json" }
345
+ ];
346
+ for (const { pm, file } of lockfileManagers) {
347
+ if (existsSync2(join2(projectRoot, file)) && commandAvailable(pm)) return pm;
348
+ }
349
+ for (const pm of ["pnpm", "bun", "yarn", "npm"]) {
350
+ if (commandAvailable(pm)) return pm;
282
351
  }
283
352
  return "npm";
284
353
  }
@@ -294,6 +363,23 @@ function stripNamespacePrefix(name, appName) {
294
363
  }
295
364
  return name;
296
365
  }
366
+ function buildCollectionIdMap(collections, appName) {
367
+ const result = /* @__PURE__ */ new Map();
368
+ const add = (key, id) => {
369
+ const trimmed = (key || "").trim();
370
+ if (trimmed) result.set(trimmed, id);
371
+ };
372
+ for (const collection of collections) {
373
+ add(collection.id, collection.id);
374
+ add(collection.name, collection.id);
375
+ const stripped = stripNamespacePrefix(collection.name, appName);
376
+ add(stripped, collection.id);
377
+ if (collection.name.includes(NAMESPACE_SEPARATOR)) {
378
+ add(collection.name.split(NAMESPACE_SEPARATOR).slice(1).join(NAMESPACE_SEPARATOR), collection.id);
379
+ }
380
+ }
381
+ return result;
382
+ }
297
383
  function computeLineDiff(oldText, newText) {
298
384
  const oldLines = (oldText || "").trimEnd().split("\n");
299
385
  const newLines = (newText || "").trimEnd().split("\n");
@@ -558,6 +644,9 @@ ${pc2.dim("Resources:")}
558
644
  ${pc2.dim("Options:")}
559
645
  --yes, -y Skip confirmation prompt (for CI/CD)
560
646
  --skip-build Skip build step when applying app
647
+ --no-app Apply resources only; do not build/deploy the app
648
+ --resources-only Alias for --no-app
649
+ --package-manager Package manager for app builds (pnpm, bun, yarn, npm)
561
650
 
562
651
  ${pc2.dim("Examples:")}
563
652
  lumera apply # Apply everything (shows plan, asks to confirm)
@@ -566,6 +655,8 @@ ${pc2.dim("Examples:")}
566
655
  lumera apply agents -y # Apply agents without confirmation
567
656
  lumera apply app # Deploy frontend
568
657
  lumera apply app --skip-build # Deploy without rebuilding
658
+ lumera apply --no-app -y # Apply resources without app build/deploy
659
+ lumera apply app --package-manager pnpm
569
660
  `);
570
661
  }
571
662
  function showPullHelp() {
@@ -974,6 +1065,16 @@ function mapFieldType(type) {
974
1065
  };
975
1066
  return typeMap[type] || type;
976
1067
  }
1068
+ function normalizeConstraintValue(fieldType, value) {
1069
+ if (value === void 0 || value === null) return void 0;
1070
+ if (["text", "email", "url", "editor"].includes(fieldType) && value === 0) {
1071
+ return void 0;
1072
+ }
1073
+ if (fieldType === "date" && value === "") {
1074
+ return void 0;
1075
+ }
1076
+ return value;
1077
+ }
977
1078
  function fieldsDiffer(local, remote) {
978
1079
  if (mapFieldType(local.type) !== remote.type) return true;
979
1080
  if ((local.required || false) !== (remote.required || false)) return true;
@@ -1002,11 +1103,11 @@ function fieldsDiffer(local, remote) {
1002
1103
  const remoteDecimalPrecision = opts.decimalPrecision !== void 0 ? opts.decimalPrecision : 2;
1003
1104
  if (localDecimalPrecision !== remoteDecimalPrecision) return true;
1004
1105
  }
1005
- const localMin = local.min !== void 0 ? local.min : void 0;
1006
- const remoteMin = opts.min !== void 0 ? opts.min : void 0;
1106
+ const localMin = normalizeConstraintValue(local.type, local.min);
1107
+ const remoteMin = normalizeConstraintValue(local.type, opts.min);
1007
1108
  if (localMin !== remoteMin) return true;
1008
- const localMax = local.max !== void 0 ? local.max : void 0;
1009
- const remoteMax = opts.max !== void 0 ? opts.max : void 0;
1109
+ const localMax = normalizeConstraintValue(local.type, local.max);
1110
+ const remoteMax = normalizeConstraintValue(local.type, opts.max);
1010
1111
  if (localMax !== remoteMax) return true;
1011
1112
  return false;
1012
1113
  }
@@ -1100,9 +1201,12 @@ async function planCollections(api, localCollections) {
1100
1201
  }
1101
1202
  return changes;
1102
1203
  }
1103
- async function planAutomations(api, localAutomations) {
1204
+ async function planAutomations(api, localAutomations, projectId) {
1104
1205
  const changes = [];
1105
- const remoteAutomations = await api.listAutomations({ include_code: true });
1206
+ const remoteAutomations = await api.listAutomations({
1207
+ include_code: true,
1208
+ ...projectId ? { project_id: projectId } : {}
1209
+ });
1106
1210
  const remoteByExternalId = new Map(remoteAutomations.filter((a) => a.external_id).map((a) => [a.external_id, a]));
1107
1211
  const remotePresetCache = /* @__PURE__ */ new Map();
1108
1212
  const getRemotePresets = (automationId) => {
@@ -1285,9 +1389,9 @@ async function pullMailboxes(api, platformDir, filterName) {
1285
1389
  console.log(pc2.yellow(` \u26A0 mailbox '${filterName}' not found on remote`));
1286
1390
  }
1287
1391
  }
1288
- async function planHooks(api, localHooks, collections) {
1392
+ async function planHooks(api, localHooks, collections, projectId) {
1289
1393
  const changes = [];
1290
- const remoteHooks = await api.listHooks();
1394
+ const remoteHooks = await api.listHooks(projectId ? { project_id: projectId } : void 0);
1291
1395
  const remoteByExternalId = new Map(remoteHooks.filter((h) => h.external_id).map((h) => [h.external_id, h]));
1292
1396
  for (const { hook, script, fileName } of localHooks) {
1293
1397
  const remote = remoteByExternalId.get(hook.external_id);
@@ -1375,7 +1479,7 @@ async function applyCollections(api, localCollections) {
1375
1479
  }
1376
1480
  async function applyAutomations(api, localAutomations, projectId) {
1377
1481
  let errors = 0;
1378
- const remoteAutomations = await api.listAutomations();
1482
+ const remoteAutomations = await api.listAutomations(projectId ? { project_id: projectId } : void 0);
1379
1483
  const remoteByExternalId = new Map(remoteAutomations.filter((a) => a.external_id).map((a) => [a.external_id, a]));
1380
1484
  for (const { automation, code } of localAutomations) {
1381
1485
  const remote = remoteByExternalId.get(automation.external_id);
@@ -1487,7 +1591,7 @@ async function setSchedule(api, automationId, schedule, localPresets) {
1487
1591
  }
1488
1592
  async function applyHooks(api, localHooks, collections, projectId) {
1489
1593
  let errors = 0;
1490
- const remoteHooks = await api.listHooks();
1594
+ const remoteHooks = await api.listHooks(projectId ? { project_id: projectId } : void 0);
1491
1595
  const remoteByExternalId = new Map(remoteHooks.filter((h) => h.external_id).map((h) => [h.external_id, h]));
1492
1596
  for (const { hook, script, fileName } of localHooks) {
1493
1597
  const remote = remoteByExternalId.get(hook.external_id);
@@ -1535,7 +1639,7 @@ async function applyApp(args) {
1535
1639
  if (!skipBuild) {
1536
1640
  console.log(pc2.dim(" Building..."));
1537
1641
  try {
1538
- const pm = detectPackageManager();
1642
+ const pm = detectPackageManager(projectRoot, getFlagValue(args, "package-manager"));
1539
1643
  execSync(`${pm} run build`, { cwd: projectRoot, stdio: "inherit" });
1540
1644
  } catch {
1541
1645
  throw new Error("Build failed");
@@ -1597,7 +1701,10 @@ async function pullCollections(api, platformDir, filterName, appName) {
1597
1701
  async function pullAutomations(api, platformDir, filterName, projectId) {
1598
1702
  const automationsDir = join2(platformDir, "automations");
1599
1703
  mkdirSync(automationsDir, { recursive: true });
1600
- const automations = await api.listAutomations({ include_code: true });
1704
+ const automations = await api.listAutomations({
1705
+ include_code: true,
1706
+ ...projectId ? { project_id: projectId } : {}
1707
+ });
1601
1708
  for (const automation of automations) {
1602
1709
  if (!automation.external_id || automation.managed) continue;
1603
1710
  if (projectId && automation.project_id && automation.project_id !== projectId) continue;
@@ -1647,7 +1754,7 @@ async function pullAutomations(api, platformDir, filterName, projectId) {
1647
1754
  async function pullHooks(api, platformDir, filterName, appName, projectId) {
1648
1755
  const hooksDir = join2(platformDir, "hooks");
1649
1756
  mkdirSync(hooksDir, { recursive: true });
1650
- const hooks = await api.listHooks();
1757
+ const hooks = await api.listHooks(projectId ? { project_id: projectId } : void 0);
1651
1758
  for (const hook of hooks) {
1652
1759
  if (!hook.external_id) continue;
1653
1760
  if (projectId && hook.project_id && hook.project_id !== projectId) continue;
@@ -1925,7 +2032,10 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
1925
2032
  }
1926
2033
  if (!filterType || filterType === "automations") {
1927
2034
  const localAutomations = loadLocalAutomations(platformDir, void 0, appName);
1928
- const remoteAutomations = await api.listAutomations({ include_code: true });
2035
+ const remoteAutomations = await api.listAutomations({
2036
+ include_code: true,
2037
+ ...projectId ? { project_id: projectId } : {}
2038
+ });
1929
2039
  const remoteByExternalId = new Map(remoteAutomations.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a]));
1930
2040
  const localIds = new Set(localAutomations.map((a) => a.automation.external_id));
1931
2041
  for (const { automation, code } of localAutomations) {
@@ -1951,7 +2061,7 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
1951
2061
  }
1952
2062
  if (!filterType || filterType === "hooks") {
1953
2063
  const localHooks = loadLocalHooks(platformDir, void 0, appName);
1954
- const remoteHooks = await api.listHooks();
2064
+ const remoteHooks = await api.listHooks(projectId ? { project_id: projectId } : void 0);
1955
2065
  const remoteByExternalId = new Map(remoteHooks.filter((h) => h.external_id).map((h) => [h.external_id, h]));
1956
2066
  const localIds = new Set(localHooks.map((h) => h.hook.external_id));
1957
2067
  for (const { hook, script } of localHooks) {
@@ -2111,7 +2221,7 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
2111
2221
  if (!resourceType || resourceType === "automations") {
2112
2222
  try {
2113
2223
  const localAutomations = loadLocalAutomations(platformDir, resourceName || void 0, appName);
2114
- const remoteAutomations = await api.listAutomations();
2224
+ const remoteAutomations = await api.listAutomations(projectId ? { project_id: projectId } : void 0);
2115
2225
  const remoteByExternalId = new Map(remoteAutomations.filter((a) => a.external_id).map((a) => [a.external_id, a]));
2116
2226
  for (const { automation } of localAutomations) {
2117
2227
  const remote = remoteByExternalId.get(automation.external_id);
@@ -2124,7 +2234,7 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
2124
2234
  }
2125
2235
  if (!resourceType || resourceType === "hooks") {
2126
2236
  const localHooks = loadLocalHooks(platformDir, resourceName || void 0, appName);
2127
- const remoteHooks = await api.listHooks();
2237
+ const remoteHooks = await api.listHooks(projectId ? { project_id: projectId } : void 0);
2128
2238
  const remoteByExternalId = new Map(remoteHooks.filter((h) => h.external_id).map((h) => [h.external_id, h]));
2129
2239
  for (const { hook } of localHooks) {
2130
2240
  const remote = remoteByExternalId.get(hook.external_id);
@@ -2365,7 +2475,7 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2365
2475
  console.log();
2366
2476
  } else if (resourceType === "automations") {
2367
2477
  const localAutomations = loadLocalAutomations(platformDir, resourceName, appName);
2368
- const remoteAutomations = await api.listAutomations();
2478
+ const remoteAutomations = await api.listAutomations(projectId ? { project_id: projectId } : void 0);
2369
2479
  const local = localAutomations[0];
2370
2480
  const remote = remoteAutomations.find((a) => a.external_id === resourceName || a.name === resourceName);
2371
2481
  if (!local && !remote) {
@@ -2388,7 +2498,7 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
2388
2498
  console.log();
2389
2499
  } else if (resourceType === "hooks") {
2390
2500
  const localHooks = loadLocalHooks(platformDir, resourceName, appName);
2391
- const remoteHooks = await api.listHooks();
2501
+ const remoteHooks = await api.listHooks(projectId ? { project_id: projectId } : void 0);
2392
2502
  const local = localHooks[0];
2393
2503
  const remote = remoteHooks.find((h) => h.external_id === resourceName);
2394
2504
  if (!local && !remote) {
@@ -2526,7 +2636,7 @@ async function plan(args) {
2526
2636
  let collections;
2527
2637
  try {
2528
2638
  const remoteCollections = await api.listCollections();
2529
- collections = new Map(remoteCollections.map((c) => [c.name, c.id]));
2639
+ collections = buildCollectionIdMap(remoteCollections, appName);
2530
2640
  } catch {
2531
2641
  collections = /* @__PURE__ */ new Map();
2532
2642
  }
@@ -2541,14 +2651,14 @@ async function plan(args) {
2541
2651
  if (!type || type === "automations") {
2542
2652
  localAutomations = loadLocalAutomations(platformDir, name || void 0, appName);
2543
2653
  if (localAutomations.length > 0) {
2544
- const changes = await planAutomations(api, localAutomations);
2654
+ const changes = await planAutomations(api, localAutomations, projectId);
2545
2655
  allChanges.push(...changes);
2546
2656
  }
2547
2657
  }
2548
2658
  if (!type || type === "hooks") {
2549
2659
  const localHooks = loadLocalHooks(platformDir, name || void 0, appName);
2550
2660
  if (localHooks.length > 0) {
2551
- const changes = await planHooks(api, localHooks, collections);
2661
+ const changes = await planHooks(api, localHooks, collections, projectId);
2552
2662
  allChanges.push(...changes);
2553
2663
  }
2554
2664
  }
@@ -2642,9 +2752,13 @@ async function apply(args) {
2642
2752
  const appName = getAppName(projectRoot);
2643
2753
  const api = createApiClient(void 0, void 0, appName);
2644
2754
  const projectId = getProjectId(projectRoot);
2645
- const positionalArgs = args.filter((a) => !a.startsWith("-"));
2755
+ const positionalArgs = getPositionalArgs(args);
2646
2756
  const { type, name } = parseResource(positionalArgs[0]);
2647
2757
  const autoConfirm = args.includes("--yes") || args.includes("-y") || !!process.env.CI;
2758
+ const skipApp = args.includes("--no-app") || args.includes("--resources-only");
2759
+ if (type === "app" && skipApp) {
2760
+ throw new Error("Cannot combine app resource with --no-app / --resources-only");
2761
+ }
2648
2762
  if (type === "app") {
2649
2763
  console.log();
2650
2764
  console.log(pc2.cyan(pc2.bold(" Apply")));
@@ -2663,8 +2777,7 @@ async function apply(args) {
2663
2777
  let collections;
2664
2778
  try {
2665
2779
  const remoteCollections = await api.listCollections();
2666
- collections = new Map(remoteCollections.map((c) => [c.name, c.id]));
2667
- for (const c of remoteCollections) collections.set(c.id, c.id);
2780
+ collections = buildCollectionIdMap(remoteCollections, appName);
2668
2781
  } catch {
2669
2782
  collections = /* @__PURE__ */ new Map();
2670
2783
  }
@@ -2675,8 +2788,8 @@ async function apply(args) {
2675
2788
  const localAgents = !type || type === "agents" ? loadLocalAgents(platformDir, name || void 0, appName) : [];
2676
2789
  const localMailboxes = !type || type === "mailboxes" ? loadLocalMailboxes(platformDir, name || void 0) : [];
2677
2790
  if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections));
2678
- if (localAutomations.length > 0) allChanges.push(...await planAutomations(api, localAutomations));
2679
- if (localHooks.length > 0) allChanges.push(...await planHooks(api, localHooks, collections));
2791
+ if (localAutomations.length > 0) allChanges.push(...await planAutomations(api, localAutomations, projectId));
2792
+ if (localHooks.length > 0) allChanges.push(...await planHooks(api, localHooks, collections, projectId));
2680
2793
  if (localAgents.length > 0) allChanges.push(...await planAgents(api, localAgents, projectId));
2681
2794
  if (localMailboxes.length > 0) allChanges.push(...await planMailboxes(api, localMailboxes));
2682
2795
  if (name) {
@@ -2688,7 +2801,7 @@ async function apply(args) {
2688
2801
  }
2689
2802
  }
2690
2803
  let willDeployApp = false;
2691
- if (!type) {
2804
+ if (!type && !skipApp) {
2692
2805
  try {
2693
2806
  if (existsSync2(join2(projectRoot, "dist")) || existsSync2(join2(projectRoot, "src"))) {
2694
2807
  willDeployApp = true;
@@ -2754,8 +2867,7 @@ async function apply(args) {
2754
2867
  }
2755
2868
  try {
2756
2869
  const remoteCollections = await api.listCollections();
2757
- collections = new Map(remoteCollections.map((c) => [c.name, c.id]));
2758
- for (const c of remoteCollections) collections.set(c.id, c.id);
2870
+ collections = buildCollectionIdMap(remoteCollections, appName);
2759
2871
  } catch {
2760
2872
  }
2761
2873
  if (localAutomations.length > 0) {
@@ -2816,7 +2928,7 @@ async function pull(args) {
2816
2928
  let collections;
2817
2929
  try {
2818
2930
  const remoteCollections = await api.listCollections();
2819
- collections = new Map(remoteCollections.map((c) => [c.name, c.id]));
2931
+ collections = buildCollectionIdMap(remoteCollections, appName);
2820
2932
  } catch {
2821
2933
  collections = /* @__PURE__ */ new Map();
2822
2934
  }
@@ -2832,7 +2944,7 @@ async function pull(args) {
2832
2944
  if (!type || type === "automations") {
2833
2945
  const localAutomations = loadLocalAutomations(platformDir, name || void 0, appName);
2834
2946
  if (localAutomations.length > 0) {
2835
- const changes = await planAutomations(api, localAutomations);
2947
+ const changes = await planAutomations(api, localAutomations, projectId);
2836
2948
  for (const c of changes) {
2837
2949
  if (c.type === "update") conflicts.push(`automations/${c.name}`);
2838
2950
  }
@@ -2841,7 +2953,7 @@ async function pull(args) {
2841
2953
  if (!type || type === "hooks") {
2842
2954
  const localHooks = loadLocalHooks(platformDir, name || void 0, appName);
2843
2955
  if (localHooks.length > 0) {
2844
- const changes = await planHooks(api, localHooks, collections);
2956
+ const changes = await planHooks(api, localHooks, collections, projectId);
2845
2957
  for (const c of changes) {
2846
2958
  if (c.type === "update") conflicts.push(`hooks/${c.name}`);
2847
2959
  }
@@ -3120,7 +3232,10 @@ async function diff(args) {
3120
3232
  }
3121
3233
  } else if (type === "automations") {
3122
3234
  const localAutomations = loadLocalAutomations(platformDir, name, appName);
3123
- const remoteAutomations = await api.listAutomations({ include_code: true });
3235
+ const remoteAutomations = await api.listAutomations({
3236
+ include_code: true,
3237
+ ...projectId ? { project_id: projectId } : {}
3238
+ });
3124
3239
  const local = localAutomations[0];
3125
3240
  const localExtId = local?.automation.external_id;
3126
3241
  const remote = remoteAutomations.find(
@@ -3150,7 +3265,7 @@ async function diff(args) {
3150
3265
  }
3151
3266
  } else if (type === "hooks") {
3152
3267
  const localHooks = loadLocalHooks(platformDir, name, appName);
3153
- const remoteHooks = await api.listHooks();
3268
+ const remoteHooks = await api.listHooks(projectId ? { project_id: projectId } : void 0);
3154
3269
  const local = localHooks[0];
3155
3270
  const localExtId = local?.hook.external_id;
3156
3271
  const remote = remoteHooks.find(
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-2CR762KB.js";
4
4
  import {
5
5
  createApiClient
6
- } from "./chunk-UH5X43VV.js";
6
+ } from "./chunk-WY6UMJNI.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.4",
3
+ "version": "0.19.6",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {
@@ -49,11 +49,11 @@ For detailed technical reference (data models, relationships, design decisions),
49
49
 
50
50
  ### Installing components
51
51
 
52
- Use `bunx` to install shadcn components (the sandbox has `bun`, not `npm`/`npx`):
52
+ Install shadcn components with `pnpm dlx` (the sandbox's default JS package manager):
53
53
 
54
54
  ```bash
55
- bunx shadcn@latest add button card dialog # Install specific components
56
- bunx shadcn@latest add table input label select # Install more as needed
55
+ pnpm dlx shadcn@latest add button card dialog # Install specific components
56
+ pnpm dlx shadcn@latest add table input label select # Install more as needed
57
57
  ```
58
58
 
59
59
  Components install into `src/components/ui/` and are fully editable.