@lumerahq/cli 0.18.2 → 0.18.3

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.
@@ -1,5 +1,6 @@
1
1
  // src/lib/deploy.ts
2
2
  import { execSync, spawn } from "child_process";
3
+ import { createConnection } from "net";
3
4
  import { existsSync, readFileSync } from "fs";
4
5
  import { resolve, dirname } from "path";
5
6
  import archiver from "archiver";
@@ -106,35 +107,22 @@ async function deploy(options) {
106
107
  Deployed! ${result.url}`));
107
108
  return { url: result.url, version };
108
109
  }
109
- async function registerDevApp(apiBase, token, appName, appTitle, appUrl) {
110
- const filterParam = encodeURIComponent(JSON.stringify({ external_id: appName }));
111
- const searchRes = await fetch(
112
- `${apiBase}/pb/collections/lm_custom_apps/records?filter=${filterParam}`,
113
- { headers: { Authorization: `Bearer ${token}` } }
114
- );
115
- if (!searchRes.ok) {
116
- throw new Error(`Failed to check app record: ${await searchRes.text()}`);
117
- }
118
- const existing = (await searchRes.json()).items?.[0];
119
- const appData = {
120
- dev_iframe_url: appUrl
121
- };
122
- if (!existing) {
123
- appData.external_id = appName;
124
- appData.name = appTitle;
125
- }
126
- const endpoint = existing ? `${apiBase}/pb/collections/lm_custom_apps/records/${existing.id}` : `${apiBase}/pb/collections/lm_custom_apps/records`;
127
- const res = await fetch(endpoint, {
128
- method: existing ? "PATCH" : "POST",
129
- headers: {
130
- Authorization: `Bearer ${token}`,
131
- "Content-Type": "application/json"
132
- },
133
- body: JSON.stringify(appData)
110
+ function isPortInUse(port, host = "127.0.0.1") {
111
+ return new Promise((resolve2) => {
112
+ const socket = createConnection({ port, host });
113
+ socket.once("connect", () => {
114
+ socket.destroy();
115
+ resolve2(true);
116
+ });
117
+ socket.once("error", () => {
118
+ socket.destroy();
119
+ resolve2(false);
120
+ });
121
+ socket.setTimeout(1e3, () => {
122
+ socket.destroy();
123
+ resolve2(false);
124
+ });
134
125
  });
135
- if (!res.ok) {
136
- throw new Error(`Failed to register app: ${await res.text()}`);
137
- }
138
126
  }
139
127
  function detectRunner(projectRoot) {
140
128
  if (existsSync(resolve(projectRoot, "bun.lockb")) || existsSync(resolve(projectRoot, "bun.lock"))) {
@@ -161,6 +149,10 @@ async function dev(options) {
161
149
  apiUrl
162
150
  } = options;
163
151
  const projectRoot = process.cwd();
152
+ if (await isPortInUse(port)) {
153
+ console.log(pc.yellow(` Dev server already running on port ${port}, skipping start.`));
154
+ return;
155
+ }
164
156
  console.log();
165
157
  console.log(pc.cyan(pc.bold(` ${appTitle} - Dev Server`)));
166
158
  console.log();
@@ -169,16 +161,6 @@ async function dev(options) {
169
161
  if (host) console.log(pc.dim(` Host: ${host}`));
170
162
  console.log(pc.dim(` URL: ${appUrl}`));
171
163
  console.log();
172
- console.log(pc.dim(" Registering app with Lumera..."));
173
- try {
174
- await registerDevApp(apiUrl, token, appName, appTitle, appUrl);
175
- console.log(pc.green(" \u2713 App registered"));
176
- } catch (err) {
177
- console.log(pc.yellow(" \u26A0 Failed to register app (continuing anyway)"));
178
- if (err instanceof Error) {
179
- console.log(pc.dim(` ${err.message}`));
180
- }
181
- }
182
164
  console.log();
183
165
  console.log(pc.green(" Starting dev server..."));
184
166
  console.log();
@@ -24,8 +24,10 @@ var CLI_USER_AGENT = `lumera-cli/${pkg.version}`;
24
24
  var ApiClient = class {
25
25
  baseUrl;
26
26
  token;
27
- constructor(token, baseUrl) {
27
+ projectExternalId;
28
+ constructor(token, baseUrl, projectExternalId) {
28
29
  this.token = token || getToken();
30
+ this.projectExternalId = projectExternalId;
29
31
  let base = baseUrl || process.env.LUMERA_BASE_URL || "https://app.lumerahq.com";
30
32
  base = base.replace(/\/$/, "");
31
33
  if (base.endsWith("/api")) {
@@ -39,6 +41,7 @@ var ApiClient = class {
39
41
  "Content-Type": "application/json",
40
42
  Authorization: `Bearer ${this.token}`,
41
43
  "User-Agent": CLI_USER_AGENT,
44
+ ...this.projectExternalId ? { "X-Lumera-Project": this.projectExternalId } : {},
42
45
  ...options.headers
43
46
  };
44
47
  const response = await fetch(url, {
@@ -251,9 +254,13 @@ var ApiClient = class {
251
254
  updated: rec.updated
252
255
  };
253
256
  }
257
+ // Project manifest — list public collections for a project
258
+ async getProjectManifest(externalId) {
259
+ return this.request(`/api/pb/projects/${encodeURIComponent(externalId)}/manifest`);
260
+ }
254
261
  };
255
- function createApiClient(token, baseUrl) {
256
- return new ApiClient(token, baseUrl);
262
+ function createApiClient(token, baseUrl, projectExternalId) {
263
+ return new ApiClient(token, baseUrl, projectExternalId);
257
264
  }
258
265
 
259
266
  export {
@@ -0,0 +1,120 @@
1
+ import {
2
+ loadEnv
3
+ } from "./chunk-2CR762KB.js";
4
+ import {
5
+ createApiClient
6
+ } from "./chunk-G7427W43.js";
7
+ import {
8
+ findProjectRoot,
9
+ getAppName
10
+ } from "./chunk-ZH3NVYEQ.js";
11
+
12
+ // src/commands/deps.ts
13
+ import pc from "picocolors";
14
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
15
+ import { join } from "path";
16
+ var DEPS_FILE = "platform/project_deps.json";
17
+ function loadDeps(projectRoot) {
18
+ const depsPath = join(projectRoot, DEPS_FILE);
19
+ if (!existsSync(depsPath)) return null;
20
+ try {
21
+ return JSON.parse(readFileSync(depsPath, "utf-8"));
22
+ } catch {
23
+ return null;
24
+ }
25
+ }
26
+ async function syncDeps(projectRoot) {
27
+ const root = projectRoot ?? findProjectRoot();
28
+ loadEnv(root);
29
+ const deps2 = loadDeps(root);
30
+ if (!deps2 || !deps2.dependencies || Object.keys(deps2.dependencies).length === 0) {
31
+ return true;
32
+ }
33
+ const appName = getAppName(root);
34
+ const api = createApiClient(void 0, void 0, appName);
35
+ let allOk = true;
36
+ for (const [depProject, config] of Object.entries(deps2.dependencies)) {
37
+ try {
38
+ const manifest = await api.getProjectManifest(depProject);
39
+ const remoteNames = new Set(manifest.collections.map((c) => c.name));
40
+ for (const col of config.collections) {
41
+ if (remoteNames.has(col)) {
42
+ console.log(pc.green(" \u2713"), `${depProject}/${col}`);
43
+ } else {
44
+ console.log(pc.red(" \u2717"), `${depProject}/${col} \u2014 not found in project manifest`);
45
+ allOk = false;
46
+ }
47
+ }
48
+ } catch (e) {
49
+ console.log(pc.red(" \u2717"), `${depProject}: failed to fetch manifest \u2014 ${e}`);
50
+ allOk = false;
51
+ }
52
+ }
53
+ return allOk;
54
+ }
55
+ async function deps(args) {
56
+ const sub = args[0];
57
+ const projectRoot = findProjectRoot();
58
+ loadEnv(projectRoot);
59
+ if (sub === "sync") {
60
+ console.log();
61
+ console.log(pc.cyan(pc.bold(" Deps Sync")));
62
+ console.log(pc.dim(" Verifying cross-project dependencies..."));
63
+ console.log();
64
+ const ok = await syncDeps(projectRoot);
65
+ if (!ok) {
66
+ console.log();
67
+ console.log(pc.red(" Some dependencies could not be resolved."));
68
+ process.exit(1);
69
+ }
70
+ console.log();
71
+ console.log(pc.green(" All dependencies verified."));
72
+ return;
73
+ }
74
+ if (sub === "list") {
75
+ const depsData = loadDeps(projectRoot);
76
+ if (!depsData || Object.keys(depsData.dependencies).length === 0) {
77
+ console.log(pc.dim(" No dependencies declared in platform/project_deps.json"));
78
+ return;
79
+ }
80
+ console.log();
81
+ console.log(pc.cyan(pc.bold(" Project Dependencies")));
82
+ console.log();
83
+ for (const [depProject, config] of Object.entries(depsData.dependencies)) {
84
+ console.log(` ${pc.bold(depProject)}`);
85
+ for (const col of config.collections) {
86
+ console.log(` \u2022 ${col}`);
87
+ }
88
+ }
89
+ console.log();
90
+ return;
91
+ }
92
+ if (sub === "init") {
93
+ const depsPath = join(projectRoot, DEPS_FILE);
94
+ if (existsSync(depsPath)) {
95
+ console.log(pc.yellow(" platform/project_deps.json already exists."));
96
+ return;
97
+ }
98
+ const platformDir = join(projectRoot, "platform");
99
+ mkdirSync(platformDir, { recursive: true });
100
+ const initial = { dependencies: {} };
101
+ writeFileSync(depsPath, JSON.stringify(initial, null, 2) + "\n");
102
+ console.log(pc.green(" \u2713"), "Created platform/project_deps.json");
103
+ return;
104
+ }
105
+ console.log(`
106
+ ${pc.bold("lumera deps")} \u2014 manage cross-project dependencies
107
+
108
+ ${pc.bold("Commands:")}
109
+ sync Fetch manifests and verify declared dependencies exist
110
+ list Show declared dependencies
111
+ init Create an empty platform/project_deps.json
112
+
113
+ ${pc.bold("Dependency file:")} platform/project_deps.json
114
+ `);
115
+ }
116
+
117
+ export {
118
+ syncDeps,
119
+ deps
120
+ };
@@ -0,0 +1,12 @@
1
+ import {
2
+ deps,
3
+ syncDeps
4
+ } from "./chunk-YIQRLXEN.js";
5
+ import "./chunk-2CR762KB.js";
6
+ import "./chunk-G7427W43.js";
7
+ import "./chunk-ZH3NVYEQ.js";
8
+ import "./chunk-PNKVD2UK.js";
9
+ export {
10
+ deps,
11
+ syncDeps
12
+ };
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  dev
3
- } from "./chunk-XTRDJLIA.js";
3
+ } from "./chunk-2I2VXPJK.js";
4
4
  import {
5
5
  loadEnv
6
6
  } from "./chunk-2CR762KB.js";
7
7
  import {
8
8
  createApiClient
9
- } from "./chunk-ILO2IR2G.js";
9
+ } from "./chunk-G7427W43.js";
10
10
  import {
11
11
  findProjectRoot,
12
12
  getApiUrl,
package/dist/index.js CHANGED
@@ -91,6 +91,7 @@ var COMMANDS = [
91
91
  "status",
92
92
  "migrate",
93
93
  "skills",
94
+ "deps",
94
95
  "login",
95
96
  "logout",
96
97
  "whoami"
@@ -215,39 +216,39 @@ async function main() {
215
216
  switch (command) {
216
217
  // Resource commands
217
218
  case "plan":
218
- await import("./resources-6SJR45CY.js").then((m) => m.plan(args.slice(1)));
219
+ await import("./resources-IJ2VFUG5.js").then((m) => m.plan(args.slice(1)));
219
220
  break;
220
221
  case "apply":
221
- await import("./resources-6SJR45CY.js").then((m) => m.apply(args.slice(1)));
222
+ await import("./resources-IJ2VFUG5.js").then((m) => m.apply(args.slice(1)));
222
223
  break;
223
224
  case "pull":
224
- await import("./resources-6SJR45CY.js").then((m) => m.pull(args.slice(1)));
225
+ await import("./resources-IJ2VFUG5.js").then((m) => m.pull(args.slice(1)));
225
226
  break;
226
227
  case "destroy":
227
- await import("./resources-6SJR45CY.js").then((m) => m.destroy(args.slice(1)));
228
+ await import("./resources-IJ2VFUG5.js").then((m) => m.destroy(args.slice(1)));
228
229
  break;
229
230
  case "list":
230
- await import("./resources-6SJR45CY.js").then((m) => m.list(args.slice(1)));
231
+ await import("./resources-IJ2VFUG5.js").then((m) => m.list(args.slice(1)));
231
232
  break;
232
233
  case "show":
233
- await import("./resources-6SJR45CY.js").then((m) => m.show(args.slice(1)));
234
+ await import("./resources-IJ2VFUG5.js").then((m) => m.show(args.slice(1)));
234
235
  break;
235
236
  case "diff":
236
- await import("./resources-6SJR45CY.js").then((m) => m.diff(args.slice(1)));
237
+ await import("./resources-IJ2VFUG5.js").then((m) => m.diff(args.slice(1)));
237
238
  break;
238
239
  // Development
239
240
  case "dev":
240
- await import("./dev-RNV6CJQI.js").then((m) => m.dev(args.slice(1)));
241
+ await import("./dev-62JXNDN3.js").then((m) => m.dev(args.slice(1)));
241
242
  break;
242
243
  case "run":
243
- await import("./run-2VKKOCHR.js").then((m) => m.run(args.slice(1)));
244
+ await import("./run-6ULEFGHJ.js").then((m) => m.run(args.slice(1)));
244
245
  break;
245
246
  // Project
246
247
  case "init":
247
- await import("./init-YUZQ54HZ.js").then((m) => m.init(args.slice(1)));
248
+ await import("./init-ZDOPG3KN.js").then((m) => m.init(args.slice(1)));
248
249
  break;
249
250
  case "register":
250
- await import("./register-MLXJNMNR.js").then((m) => m.register(args.slice(1)));
251
+ await import("./register-COESODY2.js").then((m) => m.register(args.slice(1)));
251
252
  break;
252
253
  case "templates":
253
254
  await import("./templates-ESFQ4QO4.js").then((m) => m.templates(subcommand, args.slice(2)));
@@ -262,6 +263,10 @@ async function main() {
262
263
  case "skills":
263
264
  await import("./skills-VY42VAXX.js").then((m) => m.skills(subcommand, args.slice(2)));
264
265
  break;
266
+ // Dependencies
267
+ case "deps":
268
+ await import("./deps-K54NOIZY.js").then((m) => m.deps(args.slice(1)));
269
+ break;
265
270
  // Auth
266
271
  case "login":
267
272
  await import("./auth-KFXSNCJB.js").then((m) => m.login(args.slice(1)));
@@ -7,16 +7,16 @@ import {
7
7
  } from "./chunk-BHYDYR75.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-ILO2IR2G.js";
11
- import {
12
- listAllTemplates,
13
- resolveTemplate
14
- } from "./chunk-CHRKCAIZ.js";
10
+ } from "./chunk-G7427W43.js";
15
11
  import {
16
12
  getToken,
17
13
  init_auth,
18
14
  setProjectId
19
15
  } from "./chunk-ZH3NVYEQ.js";
16
+ import {
17
+ listAllTemplates,
18
+ resolveTemplate
19
+ } from "./chunk-CHRKCAIZ.js";
20
20
  import "./chunk-PNKVD2UK.js";
21
21
 
22
22
  // src/commands/init.ts
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-BHYDYR75.js";
7
7
  import {
8
8
  createApiClient
9
- } from "./chunk-ILO2IR2G.js";
9
+ } from "./chunk-G7427W43.js";
10
10
  import {
11
11
  findProjectRoot,
12
12
  getAppName,
@@ -1,12 +1,15 @@
1
+ import {
2
+ syncDeps
3
+ } from "./chunk-YIQRLXEN.js";
1
4
  import {
2
5
  deploy
3
- } from "./chunk-XTRDJLIA.js";
6
+ } from "./chunk-2I2VXPJK.js";
4
7
  import {
5
8
  loadEnv
6
9
  } from "./chunk-2CR762KB.js";
7
10
  import {
8
11
  createApiClient
9
- } from "./chunk-ILO2IR2G.js";
12
+ } from "./chunk-G7427W43.js";
10
13
  import {
11
14
  findProjectRoot,
12
15
  getApiUrl,
@@ -35,6 +38,18 @@ function detectPackageManager() {
35
38
  }
36
39
  return "npm";
37
40
  }
41
+ var NAMESPACE_SEPARATOR = "__";
42
+ function sanitizeSlugForCollectionName(slug) {
43
+ return slug.replace(/-/g, "_");
44
+ }
45
+ function stripNamespacePrefix(name, appName) {
46
+ if (!appName) return name;
47
+ const prefix = sanitizeSlugForCollectionName(appName) + NAMESPACE_SEPARATOR;
48
+ if (name.startsWith(prefix)) {
49
+ return name.slice(prefix.length);
50
+ }
51
+ return name;
52
+ }
38
53
  function computeLineDiff(oldText, newText) {
39
54
  const oldLines = (oldText || "").trimEnd().split("\n");
40
55
  const newLines = (newText || "").trimEnd().split("\n");
@@ -950,7 +965,7 @@ async function applyCollections(api, localCollections) {
950
965
  }
951
966
  return errors;
952
967
  }
953
- async function applyAutomations(api, localAutomations) {
968
+ async function applyAutomations(api, localAutomations, projectId) {
954
969
  let errors = 0;
955
970
  const remoteAutomations = await api.listAutomations();
956
971
  const remoteByExternalId = new Map(remoteAutomations.filter((a) => a.external_id).map((a) => [a.external_id, a]));
@@ -962,6 +977,9 @@ async function applyAutomations(api, localAutomations) {
962
977
  description: automation.description,
963
978
  code
964
979
  };
980
+ if (projectId) {
981
+ payload.project_id = projectId;
982
+ }
965
983
  if (automation.inputs?.schema) {
966
984
  payload.input_schema = automation.inputs.schema;
967
985
  }
@@ -1059,7 +1077,7 @@ async function setSchedule(api, automationId, schedule, localPresets) {
1059
1077
  console.log(pc.yellow(` \u26A0 Failed to set schedule: ${e}`));
1060
1078
  }
1061
1079
  }
1062
- async function applyHooks(api, localHooks, collections) {
1080
+ async function applyHooks(api, localHooks, collections, projectId) {
1063
1081
  let errors = 0;
1064
1082
  const remoteHooks = await api.listHooks();
1065
1083
  const remoteByExternalId = new Map(remoteHooks.filter((h) => h.external_id).map((h) => [h.external_id, h]));
@@ -1080,6 +1098,9 @@ async function applyHooks(api, localHooks, collections) {
1080
1098
  enabled: hook.enabled !== false,
1081
1099
  metadata: hook.metadata
1082
1100
  };
1101
+ if (projectId) {
1102
+ payload.project_id = projectId;
1103
+ }
1083
1104
  try {
1084
1105
  if (remote) {
1085
1106
  await api.updateHook(remote.id, payload);
@@ -1115,18 +1136,23 @@ async function applyApp(args) {
1115
1136
  const distDir = resolve(projectRoot, "dist");
1116
1137
  await deploy({ token, appName, appTitle, distDir, apiUrl });
1117
1138
  }
1118
- async function pullCollections(api, platformDir, filterName) {
1139
+ async function pullCollections(api, platformDir, filterName, appName) {
1119
1140
  const collectionsDir = join(platformDir, "collections");
1120
1141
  mkdirSync(collectionsDir, { recursive: true });
1121
1142
  const collections = await api.listCollections();
1122
1143
  for (const collection of collections) {
1123
1144
  if (collection.system || collection.managed) continue;
1124
- if (filterName && collection.name !== filterName && collection.id !== filterName) {
1145
+ if (appName && collection.name.includes(NAMESPACE_SEPARATOR)) {
1146
+ const prefix = collection.name.split(NAMESPACE_SEPARATOR)[0];
1147
+ if (prefix !== sanitizeSlugForCollectionName(appName)) continue;
1148
+ }
1149
+ const localName = stripNamespacePrefix(collection.name, appName);
1150
+ if (filterName && localName !== filterName && collection.name !== filterName && collection.id !== filterName) {
1125
1151
  continue;
1126
1152
  }
1127
1153
  const localFormat = {
1128
1154
  id: collection.id,
1129
- name: collection.name,
1155
+ name: localName,
1130
1156
  fields: collection.schema.map((field) => {
1131
1157
  const localField = {
1132
1158
  name: field.name,
@@ -1148,18 +1174,20 @@ async function pullCollections(api, platformDir, filterName) {
1148
1174
  return null;
1149
1175
  }).filter((idx) => idx !== null)
1150
1176
  };
1151
- const fileName = toSafeFilename(collection.name);
1177
+ const fileName = toSafeFilename(localName);
1152
1178
  const filePath = join(collectionsDir, `${fileName}.json`);
1153
1179
  writeFileSync(filePath, JSON.stringify(localFormat, null, 2) + "\n");
1154
- console.log(pc.green(" \u2713"), `${collection.name} \u2192 collections/${fileName}.json`);
1180
+ console.log(pc.green(" \u2713"), `${localName} \u2192 collections/${fileName}.json`);
1155
1181
  }
1156
1182
  }
1157
- async function pullAutomations(api, platformDir, filterName) {
1183
+ async function pullAutomations(api, platformDir, filterName, projectId) {
1158
1184
  const automationsDir = join(platformDir, "automations");
1159
1185
  mkdirSync(automationsDir, { recursive: true });
1160
1186
  const automations = await api.listAutomations({ include_code: true });
1161
1187
  for (const automation of automations) {
1162
1188
  if (!automation.external_id || automation.managed) continue;
1189
+ if (projectId && automation.project_id && automation.project_id !== projectId) continue;
1190
+ if (!projectId && automation.project_id) continue;
1163
1191
  if (filterName && automation.external_id !== filterName && automation.name !== filterName) {
1164
1192
  continue;
1165
1193
  }
@@ -1202,19 +1230,21 @@ async function pullAutomations(api, platformDir, filterName) {
1202
1230
  console.log(pc.green(" \u2713"), `${automation.name} \u2192 automations/${dirName}/`);
1203
1231
  }
1204
1232
  }
1205
- async function pullHooks(api, platformDir, filterName) {
1233
+ async function pullHooks(api, platformDir, filterName, appName, projectId) {
1206
1234
  const hooksDir = join(platformDir, "hooks");
1207
1235
  mkdirSync(hooksDir, { recursive: true });
1208
1236
  const hooks = await api.listHooks();
1209
1237
  for (const hook of hooks) {
1210
1238
  if (!hook.external_id) continue;
1239
+ if (projectId && hook.project_id && hook.project_id !== projectId) continue;
1240
+ if (!projectId && hook.project_id) continue;
1211
1241
  if (filterName && hook.external_id !== filterName) {
1212
1242
  continue;
1213
1243
  }
1214
1244
  const fileName = `${hook.external_id.replace(/[^a-zA-Z0-9_-]/g, "_")}.js`;
1215
1245
  const content = `export const config = {
1216
1246
  external_id: '${hook.external_id}',
1217
- collection: '${hook.collection_name}',
1247
+ collection: '${stripNamespacePrefix(hook.collection_name, appName)}',
1218
1248
  trigger: '${hook.event}',
1219
1249
  enabled: ${hook.enabled},
1220
1250
  };
@@ -1433,7 +1463,7 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
1433
1463
  if (!filterType || filterType === "collections") {
1434
1464
  const localCollections = loadLocalCollections(platformDir);
1435
1465
  const remoteCollections = await api.listCollections();
1436
- const remoteByName = new Map(remoteCollections.filter((c) => !c.system && !c.managed).map((c) => [c.name, c]));
1466
+ const remoteByName = new Map(remoteCollections.filter((c) => !c.system && !c.managed).map((c) => [stripNamespacePrefix(c.name, appName), c]));
1437
1467
  const localNames = new Set(localCollections.map((c) => c.name));
1438
1468
  for (const local of localCollections) {
1439
1469
  const remote = remoteByName.get(local.name);
@@ -1456,8 +1486,13 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
1456
1486
  }
1457
1487
  for (const remote of remoteCollections) {
1458
1488
  if (remote.system || remote.managed) continue;
1459
- if (!localNames.has(remote.name)) {
1460
- results.push({ name: remote.name, type: "collections", status: "remote-only" });
1489
+ if (appName && remote.name.includes(NAMESPACE_SEPARATOR)) {
1490
+ const prefix = remote.name.split(NAMESPACE_SEPARATOR)[0];
1491
+ if (prefix !== sanitizeSlugForCollectionName(appName)) continue;
1492
+ }
1493
+ const stripped = stripNamespacePrefix(remote.name, appName);
1494
+ if (!localNames.has(stripped)) {
1495
+ results.push({ name: stripped, type: "collections", status: "remote-only" });
1461
1496
  }
1462
1497
  }
1463
1498
  }
@@ -1981,8 +2016,8 @@ async function plan(args) {
1981
2016
  const projectRoot = findProjectRoot();
1982
2017
  loadEnv(projectRoot);
1983
2018
  const platformDir = getPlatformDir();
1984
- const api = createApiClient();
1985
2019
  const appName = getAppName(projectRoot);
2020
+ const api = createApiClient(void 0, void 0, appName);
1986
2021
  const projectId = getProjectId(projectRoot);
1987
2022
  const positionalArgs = args.filter((a) => !a.startsWith("-"));
1988
2023
  const { type, name } = parseResource(positionalArgs[0]);
@@ -1990,6 +2025,7 @@ async function plan(args) {
1990
2025
  console.log(pc.cyan(pc.bold(" Plan")));
1991
2026
  console.log(pc.dim(" Comparing local files to remote state..."));
1992
2027
  console.log();
2028
+ await syncDeps(projectRoot);
1993
2029
  const allChanges = [];
1994
2030
  let collections;
1995
2031
  try {
@@ -2079,8 +2115,8 @@ async function apply(args) {
2079
2115
  const projectRoot = findProjectRoot();
2080
2116
  loadEnv(projectRoot);
2081
2117
  const platformDir = getPlatformDir();
2082
- const api = createApiClient();
2083
2118
  const appName = getAppName(projectRoot);
2119
+ const api = createApiClient(void 0, void 0, appName);
2084
2120
  const projectId = getProjectId(projectRoot);
2085
2121
  const positionalArgs = args.filter((a) => !a.startsWith("-"));
2086
2122
  const { type, name } = parseResource(positionalArgs[0]);
@@ -2096,6 +2132,7 @@ async function apply(args) {
2096
2132
  console.log();
2097
2133
  return;
2098
2134
  }
2135
+ await syncDeps(projectRoot);
2099
2136
  let collections;
2100
2137
  try {
2101
2138
  const remoteCollections = await api.listCollections();
@@ -2192,12 +2229,12 @@ async function apply(args) {
2192
2229
  }
2193
2230
  if (localAutomations.length > 0) {
2194
2231
  console.log(pc.bold(" Automations:"));
2195
- totalErrors += await applyAutomations(api, localAutomations);
2232
+ totalErrors += await applyAutomations(api, localAutomations, projectId);
2196
2233
  console.log();
2197
2234
  }
2198
2235
  if (localHooks.length > 0) {
2199
2236
  console.log(pc.bold(" Hooks:"));
2200
- totalErrors += await applyHooks(api, localHooks, collections);
2237
+ totalErrors += await applyHooks(api, localHooks, collections, projectId);
2201
2238
  console.log();
2202
2239
  }
2203
2240
  if (localAgents.length > 0) {
@@ -2234,8 +2271,8 @@ async function pull(args) {
2234
2271
  const projectRoot = findProjectRoot();
2235
2272
  loadEnv(projectRoot);
2236
2273
  const platformDir = getPlatformDir();
2237
- const api = createApiClient();
2238
2274
  const appName = getAppName(projectRoot);
2275
+ const api = createApiClient(void 0, void 0, appName);
2239
2276
  const projectId = getProjectId(projectRoot);
2240
2277
  const { type, name } = parseResource(filteredArgs[0]);
2241
2278
  if (!force) {
@@ -2293,17 +2330,17 @@ async function pull(args) {
2293
2330
  console.log();
2294
2331
  if (!type || type === "collections") {
2295
2332
  console.log(pc.bold(" Collections:"));
2296
- await pullCollections(api, platformDir, name || void 0);
2333
+ await pullCollections(api, platformDir, name || void 0, appName);
2297
2334
  console.log();
2298
2335
  }
2299
2336
  if (!type || type === "automations") {
2300
2337
  console.log(pc.bold(" Automations:"));
2301
- await pullAutomations(api, platformDir, name || void 0);
2338
+ await pullAutomations(api, platformDir, name || void 0, projectId);
2302
2339
  console.log();
2303
2340
  }
2304
2341
  if (!type || type === "hooks") {
2305
2342
  console.log(pc.bold(" Hooks:"));
2306
- await pullHooks(api, platformDir, name || void 0);
2343
+ await pullHooks(api, platformDir, name || void 0, appName, projectId);
2307
2344
  console.log();
2308
2345
  }
2309
2346
  if (!type || type === "agents") {
@@ -2322,8 +2359,8 @@ async function destroy(args) {
2322
2359
  const projectRoot = findProjectRoot();
2323
2360
  loadEnv(projectRoot);
2324
2361
  const platformDir = getPlatformDir();
2325
- const api = createApiClient();
2326
2362
  const appName = getAppName(projectRoot);
2363
+ const api = createApiClient(void 0, void 0, appName);
2327
2364
  const projectId = getProjectId(projectRoot);
2328
2365
  const { type, name } = parseResource(args[0]);
2329
2366
  const skipConfirm = args.includes("--confirm");
@@ -2346,8 +2383,8 @@ async function list(args) {
2346
2383
  const projectRoot = findProjectRoot();
2347
2384
  loadEnv(projectRoot);
2348
2385
  const platformDir = getPlatformDir();
2349
- const api = createApiClient();
2350
2386
  const appName = getAppName(projectRoot);
2387
+ const api = createApiClient(void 0, void 0, appName);
2351
2388
  const projectId = getProjectId(projectRoot);
2352
2389
  const showAll = args.includes("--all");
2353
2390
  const positionalArgs = args.filter((a) => !a.startsWith("--"));
@@ -2427,8 +2464,8 @@ async function show(args) {
2427
2464
  const projectRoot = findProjectRoot();
2428
2465
  loadEnv(projectRoot);
2429
2466
  const platformDir = getPlatformDir();
2430
- const api = createApiClient();
2431
2467
  const appName = getAppName(projectRoot);
2468
+ const api = createApiClient(void 0, void 0, appName);
2432
2469
  const projectId = getProjectId(projectRoot);
2433
2470
  const { type, name } = parseResource(args[0]);
2434
2471
  if (!type) {
@@ -2487,8 +2524,8 @@ async function diff(args) {
2487
2524
  const projectRoot = findProjectRoot();
2488
2525
  loadEnv(projectRoot);
2489
2526
  const platformDir = getPlatformDir();
2490
- const api = createApiClient();
2491
2527
  const appName = getAppName(projectRoot);
2528
+ const api = createApiClient(void 0, void 0, appName);
2492
2529
  const projectId = getProjectId(projectRoot);
2493
2530
  const { type, name } = parseResource(args[0]);
2494
2531
  if (!type || !name) {
@@ -3,10 +3,11 @@ import {
3
3
  } from "./chunk-2CR762KB.js";
4
4
  import {
5
5
  createApiClient
6
- } from "./chunk-ILO2IR2G.js";
6
+ } from "./chunk-G7427W43.js";
7
7
  import {
8
8
  findProjectRoot,
9
9
  getApiUrl,
10
+ getAppName,
10
11
  getToken,
11
12
  init_auth
12
13
  } from "./chunk-ZH3NVYEQ.js";
@@ -115,7 +116,8 @@ async function runScript(scriptPath, projectRoot) {
115
116
  }
116
117
  }
117
118
  async function triggerAutomation(automationName, projectRoot, flags) {
118
- const api = createApiClient();
119
+ const appName = getAppName(projectRoot);
120
+ const api = createApiClient(void 0, void 0, appName);
119
121
  const token = getToken(projectRoot);
120
122
  let apiUrl = getApiUrl().replace(/\/+$/, "").replace(/\/api$/, "");
121
123
  console.log();
@@ -235,13 +237,14 @@ async function runAutomationLocally(automationName, projectRoot, flags) {
235
237
  process.on("SIGINT", () => uv.kill("SIGINT"));
236
238
  process.on("SIGTERM", () => uv.kill("SIGTERM"));
237
239
  }
238
- async function invokeAgent(agentName, message, flags) {
240
+ async function invokeAgent(agentName, message, flags, projectRoot) {
239
241
  if (!message) {
240
242
  console.error(pc.red(" Message is required."));
241
243
  console.error(pc.dim(' Usage: lumera run agents/<name> "Your message here"'));
242
244
  process.exit(1);
243
245
  }
244
- const api = createApiClient();
246
+ const appName = projectRoot ? getAppName(projectRoot) : void 0;
247
+ const api = createApiClient(void 0, void 0, appName);
245
248
  console.log();
246
249
  console.log(pc.cyan(pc.bold(" Invoke Agent")));
247
250
  console.log();
@@ -313,7 +316,7 @@ async function run(args) {
313
316
  if (target.startsWith("agents/")) {
314
317
  const agentName = target.replace("agents/", "");
315
318
  const message = positionalArgs.join(" ") || void 0;
316
- await invokeAgent(agentName, message, flags);
319
+ await invokeAgent(agentName, message, flags, projectRoot);
317
320
  return;
318
321
  }
319
322
  await runScript(target, projectRoot);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumerahq/cli",
3
- "version": "0.18.2",
3
+ "version": "0.18.3",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {