@lumerahq/cli 0.15.1 → 0.16.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.
@@ -3,7 +3,7 @@ import {
3
3
  getCredentials,
4
4
  getTokenSource,
5
5
  init_auth
6
- } from "./chunk-WZMAQXDY.js";
6
+ } from "./chunk-ZH3NVYEQ.js";
7
7
  import "./chunk-PNKVD2UK.js";
8
8
 
9
9
  // src/commands/auth.ts
@@ -0,0 +1,18 @@
1
+ // src/lib/env.ts
2
+ import { config } from "dotenv";
3
+ import { existsSync } from "fs";
4
+ import { resolve } from "path";
5
+ function loadEnv(cwd = process.cwd()) {
6
+ const envPath = resolve(cwd, ".env");
7
+ const envLocalPath = resolve(cwd, ".env.local");
8
+ if (existsSync(envPath)) {
9
+ config({ path: envPath });
10
+ }
11
+ if (existsSync(envLocalPath)) {
12
+ config({ path: envLocalPath, override: true });
13
+ }
14
+ }
15
+
16
+ export {
17
+ loadEnv
18
+ };
@@ -0,0 +1,33 @@
1
+ // src/lib/spinner.ts
2
+ import pc from "picocolors";
3
+ var frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
4
+ function spinner(message) {
5
+ if (!process.stdout.isTTY) {
6
+ process.stdout.write(` ${message}
7
+ `);
8
+ return (doneMessage) => {
9
+ if (doneMessage) {
10
+ process.stdout.write(` ${doneMessage}
11
+ `);
12
+ }
13
+ };
14
+ }
15
+ let i = 0;
16
+ const interval = setInterval(() => {
17
+ const frame = frames[i % frames.length];
18
+ process.stdout.write(`\r ${pc.cyan(frame)} ${message}`);
19
+ i++;
20
+ }, 80);
21
+ return (doneMessage) => {
22
+ clearInterval(interval);
23
+ process.stdout.write(`\r${" ".repeat(message.length + 10)}\r`);
24
+ if (doneMessage) {
25
+ process.stdout.write(` ${doneMessage}
26
+ `);
27
+ }
28
+ };
29
+ }
30
+
31
+ export {
32
+ spinner
33
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getToken,
3
3
  init_auth
4
- } from "./chunk-WZMAQXDY.js";
4
+ } from "./chunk-ZH3NVYEQ.js";
5
5
 
6
6
  // src/lib/api.ts
7
7
  init_auth();
@@ -158,8 +158,10 @@ var ApiClient = class {
158
158
  });
159
159
  }
160
160
  // Agents
161
- async listAgents() {
162
- const result = await this.request("/api/agents?limit=100");
161
+ async listAgents(opts) {
162
+ const params = new URLSearchParams({ limit: "100" });
163
+ if (opts?.project_id) params.set("project_id", opts.project_id);
164
+ const result = await this.request(`/api/agents?${params}`);
163
165
  return result.agents || [];
164
166
  }
165
167
  async createAgent(def) {
@@ -193,27 +195,67 @@ var ApiClient = class {
193
195
  body: JSON.stringify(body)
194
196
  });
195
197
  }
198
+ // Projects — register/lookup via PocketBase records API
199
+ async registerProject(name, externalId) {
200
+ const extId = externalId || name;
201
+ const filterParam = encodeURIComponent(JSON.stringify({ name }));
202
+ const searchRes = await this.request(
203
+ `/api/pb/collections/lm_projects/records?filter=${filterParam}`
204
+ );
205
+ const existing = searchRes.items?.[0];
206
+ if (existing) {
207
+ return {
208
+ id: existing.id,
209
+ name: existing.name,
210
+ external_id: existing.external_id,
211
+ template: existing.template,
212
+ status: existing.status,
213
+ owner_id: existing.owner_id,
214
+ created: existing.created,
215
+ updated: existing.updated
216
+ };
217
+ }
218
+ const rec = await this.request(
219
+ "/api/pb/collections/lm_projects/records",
220
+ {
221
+ method: "POST",
222
+ body: JSON.stringify({ name, external_id: extId })
223
+ }
224
+ );
225
+ return {
226
+ id: rec.id,
227
+ name: rec.name,
228
+ external_id: rec.external_id,
229
+ template: rec.template,
230
+ status: rec.status,
231
+ owner_id: rec.owner_id,
232
+ created: rec.created,
233
+ updated: rec.updated
234
+ };
235
+ }
236
+ async getProjectByName(name) {
237
+ const filterParam = encodeURIComponent(JSON.stringify({ name }));
238
+ const res = await this.request(
239
+ `/api/pb/collections/lm_projects/records?filter=${filterParam}`
240
+ );
241
+ const rec = res.items?.[0];
242
+ if (!rec) return null;
243
+ return {
244
+ id: rec.id,
245
+ name: rec.name,
246
+ external_id: rec.external_id,
247
+ template: rec.template,
248
+ status: rec.status,
249
+ owner_id: rec.owner_id,
250
+ created: rec.created,
251
+ updated: rec.updated
252
+ };
253
+ }
196
254
  };
197
255
  function createApiClient(token, baseUrl) {
198
256
  return new ApiClient(token, baseUrl);
199
257
  }
200
258
 
201
- // src/lib/env.ts
202
- import { config } from "dotenv";
203
- import { existsSync } from "fs";
204
- import { resolve as resolve2 } from "path";
205
- function loadEnv(cwd = process.cwd()) {
206
- const envPath = resolve2(cwd, ".env");
207
- const envLocalPath = resolve2(cwd, ".env.local");
208
- if (existsSync(envPath)) {
209
- config({ path: envPath });
210
- }
211
- if (existsSync(envLocalPath)) {
212
- config({ path: envLocalPath, override: true });
213
- }
214
- }
215
-
216
259
  export {
217
- createApiClient,
218
- loadEnv
260
+ createApiClient
219
261
  };
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  getBaseUrl
3
- } from "./chunk-WZMAQXDY.js";
3
+ } from "./chunk-ZH3NVYEQ.js";
4
4
 
5
5
  // src/lib/skills.ts
6
6
  import { createHash } from "crypto";
7
- import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "fs";
8
- import { join } from "path";
7
+ import { existsSync, mkdirSync, readdirSync, readFileSync, symlinkSync, lstatSync, writeFileSync } from "fs";
8
+ import { join, relative } from "path";
9
9
  import pc from "picocolors";
10
10
  function slugToFilename(slug) {
11
11
  const normalizedSlug = slug.startsWith("lumera-") ? slug : `lumera-${slug}`;
@@ -69,6 +69,37 @@ function parseSkillSummary(content) {
69
69
  }
70
70
  return { title, summary: summaryLines.join(" ") };
71
71
  }
72
+ function ensureSkillSymlinks(projectRoot) {
73
+ const canonicalDir = join(projectRoot, ".claude", "skills");
74
+ if (!existsSync(canonicalDir)) return;
75
+ const symlinks = [
76
+ {
77
+ dir: join(projectRoot, ".pi"),
78
+ link: join(projectRoot, ".pi", "skills"),
79
+ target: relative(join(projectRoot, ".pi"), canonicalDir)
80
+ },
81
+ {
82
+ dir: join(projectRoot, ".agents"),
83
+ link: join(projectRoot, ".agents", "skills"),
84
+ target: relative(join(projectRoot, ".agents"), canonicalDir)
85
+ }
86
+ ];
87
+ for (const { dir, link, target } of symlinks) {
88
+ mkdirSync(dir, { recursive: true });
89
+ if (existsSync(link)) {
90
+ try {
91
+ const stat = lstatSync(link);
92
+ if (stat.isSymbolicLink()) continue;
93
+ } catch {
94
+ }
95
+ continue;
96
+ }
97
+ try {
98
+ symlinkSync(target, link);
99
+ } catch {
100
+ }
101
+ }
102
+ }
72
103
  async function installAllSkills(targetDir, options) {
73
104
  const verbose = options?.verbose ?? false;
74
105
  const skills = await fetchSkillsList();
@@ -99,6 +130,7 @@ async function installAllSkills(targetDir, options) {
99
130
  failed++;
100
131
  }
101
132
  }
133
+ ensureSkillSymlinks(targetDir);
102
134
  return { installed, failed };
103
135
  }
104
136
  var SKILLS_START_MARKER = "<!-- LUMERA_SKILLS_START -->";
@@ -146,6 +178,7 @@ export {
146
178
  fetchSkillsList,
147
179
  fetchSkillContent,
148
180
  getLocalSkills,
181
+ ensureSkillSymlinks,
149
182
  installAllSkills,
150
183
  syncClaudeMd
151
184
  };
@@ -89,7 +89,7 @@ var init_auth = __esm({
89
89
  });
90
90
 
91
91
  // src/lib/config.ts
92
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
92
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
93
93
  import { resolve, join as join2 } from "path";
94
94
  function findProjectRoot(startDir = process.cwd()) {
95
95
  let dir = startDir;
@@ -129,6 +129,18 @@ function detectProjectVersion(projectRoot) {
129
129
  }
130
130
  return 1;
131
131
  }
132
+ function getProjectId(projectRoot) {
133
+ const pkg = readPackageJson(projectRoot);
134
+ return pkg.lumera?.project_id;
135
+ }
136
+ function setProjectId(projectRoot, projectId) {
137
+ const pkgPath = join2(projectRoot, "package.json");
138
+ const raw = readFileSync2(pkgPath, "utf-8");
139
+ const pkg = JSON.parse(raw);
140
+ if (!pkg.lumera) pkg.lumera = {};
141
+ pkg.lumera.project_id = projectId;
142
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
143
+ }
132
144
  function getBaseUrl() {
133
145
  const envBase = process.env.LUMERA_BASE_URL || process.env.LUMERA_API_URL;
134
146
  if (envBase) {
@@ -158,6 +170,8 @@ export {
158
170
  getAppName,
159
171
  getAppTitle,
160
172
  detectProjectVersion,
173
+ getProjectId,
174
+ setProjectId,
161
175
  getBaseUrl,
162
176
  getApiUrl
163
177
  };
@@ -2,9 +2,11 @@ import {
2
2
  dev
3
3
  } from "./chunk-XTRDJLIA.js";
4
4
  import {
5
- createApiClient,
6
5
  loadEnv
7
- } from "./chunk-RWPUF6L7.js";
6
+ } from "./chunk-2CR762KB.js";
7
+ import {
8
+ createApiClient
9
+ } from "./chunk-ILO2IR2G.js";
8
10
  import {
9
11
  findProjectRoot,
10
12
  getApiUrl,
@@ -12,7 +14,7 @@ import {
12
14
  getAppTitle,
13
15
  getToken,
14
16
  init_auth
15
- } from "./chunk-WZMAQXDY.js";
17
+ } from "./chunk-ZH3NVYEQ.js";
16
18
  import "./chunk-PNKVD2UK.js";
17
19
 
18
20
  // src/commands/dev.ts
package/dist/index.js CHANGED
@@ -86,6 +86,7 @@ var COMMANDS = [
86
86
  "dev",
87
87
  "run",
88
88
  "init",
89
+ "register",
89
90
  "templates",
90
91
  "status",
91
92
  "migrate",
@@ -146,6 +147,7 @@ ${pc.dim("Development:")}
146
147
 
147
148
  ${pc.dim("Project:")}
148
149
  ${pc.cyan("init")} [name] Scaffold a new project
150
+ ${pc.cyan("register")} Register project with Lumera
149
151
  ${pc.cyan("templates list")} List available templates
150
152
  ${pc.cyan("templates validate")} Validate a template directory
151
153
  ${pc.cyan("status")} Show project info
@@ -213,59 +215,62 @@ async function main() {
213
215
  switch (command) {
214
216
  // Resource commands
215
217
  case "plan":
216
- await import("./resources-26TZX2XU.js").then((m) => m.plan(args.slice(1)));
218
+ await import("./resources-64MEBAL5.js").then((m) => m.plan(args.slice(1)));
217
219
  break;
218
220
  case "apply":
219
- await import("./resources-26TZX2XU.js").then((m) => m.apply(args.slice(1)));
221
+ await import("./resources-64MEBAL5.js").then((m) => m.apply(args.slice(1)));
220
222
  break;
221
223
  case "pull":
222
- await import("./resources-26TZX2XU.js").then((m) => m.pull(args.slice(1)));
224
+ await import("./resources-64MEBAL5.js").then((m) => m.pull(args.slice(1)));
223
225
  break;
224
226
  case "destroy":
225
- await import("./resources-26TZX2XU.js").then((m) => m.destroy(args.slice(1)));
227
+ await import("./resources-64MEBAL5.js").then((m) => m.destroy(args.slice(1)));
226
228
  break;
227
229
  case "list":
228
- await import("./resources-26TZX2XU.js").then((m) => m.list(args.slice(1)));
230
+ await import("./resources-64MEBAL5.js").then((m) => m.list(args.slice(1)));
229
231
  break;
230
232
  case "show":
231
- await import("./resources-26TZX2XU.js").then((m) => m.show(args.slice(1)));
233
+ await import("./resources-64MEBAL5.js").then((m) => m.show(args.slice(1)));
232
234
  break;
233
235
  case "diff":
234
- await import("./resources-26TZX2XU.js").then((m) => m.diff(args.slice(1)));
236
+ await import("./resources-64MEBAL5.js").then((m) => m.diff(args.slice(1)));
235
237
  break;
236
238
  // Development
237
239
  case "dev":
238
- await import("./dev-NN766QJW.js").then((m) => m.dev(args.slice(1)));
240
+ await import("./dev-RNV6CJQI.js").then((m) => m.dev(args.slice(1)));
239
241
  break;
240
242
  case "run":
241
- await import("./run-WD5CKV3S.js").then((m) => m.run(args.slice(1)));
243
+ await import("./run-2VKKOCHR.js").then((m) => m.run(args.slice(1)));
242
244
  break;
243
245
  // Project
244
246
  case "init":
245
- await import("./init-ZI3FZSRE.js").then((m) => m.init(args.slice(1)));
247
+ await import("./init-35S7YVGF.js").then((m) => m.init(args.slice(1)));
248
+ break;
249
+ case "register":
250
+ await import("./register-MLXJNMNR.js").then((m) => m.register(args.slice(1)));
246
251
  break;
247
252
  case "templates":
248
253
  await import("./templates-ESFQ4QO4.js").then((m) => m.templates(subcommand, args.slice(2)));
249
254
  break;
250
255
  case "status":
251
- await import("./status-ZFEEIK4O.js").then((m) => m.status(args.slice(1)));
256
+ await import("./status-EW5I7QAU.js").then((m) => m.status(args.slice(1)));
252
257
  break;
253
258
  case "migrate":
254
- await import("./migrate-MW5Q2HS6.js").then((m) => m.migrate(args.slice(1)));
259
+ await import("./migrate-NCZKP7FM.js").then((m) => m.migrate(args.slice(1)));
255
260
  break;
256
261
  // Skills
257
262
  case "skills":
258
- await import("./skills-6TSSUJYR.js").then((m) => m.skills(subcommand, args.slice(2)));
263
+ await import("./skills-4UZIEFMP.js").then((m) => m.skills(subcommand, args.slice(2)));
259
264
  break;
260
265
  // Auth
261
266
  case "login":
262
- await import("./auth-YQXLYQZZ.js").then((m) => m.login(args.slice(1)));
267
+ await import("./auth-KFXSNCJB.js").then((m) => m.login(args.slice(1)));
263
268
  break;
264
269
  case "logout":
265
- await import("./auth-YQXLYQZZ.js").then((m) => m.logout(args.slice(1)));
270
+ await import("./auth-KFXSNCJB.js").then((m) => m.logout(args.slice(1)));
266
271
  break;
267
272
  case "whoami":
268
- await import("./auth-YQXLYQZZ.js").then((m) => m.whoami());
273
+ await import("./auth-KFXSNCJB.js").then((m) => m.whoami());
269
274
  break;
270
275
  // Convenience aliases
271
276
  case "help":
@@ -1,52 +1,31 @@
1
1
  import {
2
2
  installAllSkills,
3
3
  syncClaudeMd
4
- } from "./chunk-FZPONF23.js";
4
+ } from "./chunk-XLZ2LQNO.js";
5
+ import {
6
+ spinner
7
+ } from "./chunk-BHYDYR75.js";
8
+ import {
9
+ createApiClient
10
+ } from "./chunk-ILO2IR2G.js";
5
11
  import {
6
12
  listAllTemplates,
7
13
  resolveTemplate
8
14
  } from "./chunk-CHRKCAIZ.js";
9
- import "./chunk-WZMAQXDY.js";
15
+ import {
16
+ getToken,
17
+ init_auth,
18
+ setProjectId
19
+ } from "./chunk-ZH3NVYEQ.js";
10
20
  import "./chunk-PNKVD2UK.js";
11
21
 
12
22
  // src/commands/init.ts
13
- import pc2 from "picocolors";
23
+ init_auth();
24
+ import pc from "picocolors";
14
25
  import prompts from "prompts";
15
26
  import { execSync } from "child_process";
16
27
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, rmSync } from "fs";
17
28
  import { join, resolve } from "path";
18
-
19
- // src/lib/spinner.ts
20
- import pc from "picocolors";
21
- var frames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
22
- function spinner(message) {
23
- if (!process.stdout.isTTY) {
24
- process.stdout.write(` ${message}
25
- `);
26
- return (doneMessage) => {
27
- if (doneMessage) {
28
- process.stdout.write(` ${doneMessage}
29
- `);
30
- }
31
- };
32
- }
33
- let i = 0;
34
- const interval = setInterval(() => {
35
- const frame = frames[i % frames.length];
36
- process.stdout.write(`\r ${pc.cyan(frame)} ${message}`);
37
- i++;
38
- }, 80);
39
- return (doneMessage) => {
40
- clearInterval(interval);
41
- process.stdout.write(`\r${" ".repeat(message.length + 10)}\r`);
42
- if (doneMessage) {
43
- process.stdout.write(` ${doneMessage}
44
- `);
45
- }
46
- };
47
- }
48
-
49
- // src/commands/init.ts
50
29
  function toTitleCase(str) {
51
30
  return str.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
52
31
  }
@@ -151,14 +130,14 @@ function detectEditor() {
151
130
  function openInEditor(targetDir) {
152
131
  const editor = detectEditor();
153
132
  if (!editor) {
154
- console.log(pc2.yellow(" \u26A0"), pc2.dim("No editor detected. Set VISUAL or EDITOR env var."));
133
+ console.log(pc.yellow(" \u26A0"), pc.dim("No editor detected. Set VISUAL or EDITOR env var."));
155
134
  return;
156
135
  }
157
136
  try {
158
137
  execSync(`${editor} "${targetDir}"`, { stdio: "ignore" });
159
- console.log(pc2.green(" \u2713"), pc2.dim(`Opened in ${editor}`));
138
+ console.log(pc.green(" \u2713"), pc.dim(`Opened in ${editor}`));
160
139
  } catch {
161
- console.log(pc2.yellow(" \u26A0"), pc2.dim(`Failed to open in ${editor}`));
140
+ console.log(pc.yellow(" \u26A0"), pc.dim(`Failed to open in ${editor}`));
162
141
  }
163
142
  }
164
143
  function parseArgs(args) {
@@ -196,14 +175,14 @@ function parseArgs(args) {
196
175
  }
197
176
  function showHelp() {
198
177
  console.log(`
199
- ${pc2.dim("Usage:")}
178
+ ${pc.dim("Usage:")}
200
179
  lumera init [name] [options]
201
180
 
202
- ${pc2.dim("Description:")}
181
+ ${pc.dim("Description:")}
203
182
  Scaffold a new Lumera project from a template.
204
183
 
205
- ${pc2.dim("Options:")}
206
- --template, -t <name> Template to use (run ${pc2.cyan("lumera templates")} to see options)
184
+ ${pc.dim("Options:")}
185
+ --template, -t <name> Template to use (run ${pc.cyan("lumera templates")} to see options)
207
186
  --yes, -y Non-interactive mode (requires project name)
208
187
  --dir, -d <path> Target directory (defaults to project name)
209
188
  --force, -f Overwrite existing directory without prompting
@@ -211,7 +190,7 @@ ${pc2.dim("Options:")}
211
190
  --open, -o Open project in editor after scaffolding
212
191
  --help, -h Show this help
213
192
 
214
- ${pc2.dim("Examples:")}
193
+ ${pc.dim("Examples:")}
215
194
  lumera init my-app # Interactive mode
216
195
  lumera init my-app -t invoice-processing # Use a specific template
217
196
  lumera init my-app -y # Non-interactive (default template)
@@ -225,14 +204,14 @@ async function init(args) {
225
204
  return;
226
205
  }
227
206
  console.log();
228
- console.log(pc2.cyan(pc2.bold(" Create Lumera App")));
207
+ console.log(pc.cyan(pc.bold(" Create Lumera App")));
229
208
  console.log();
230
209
  let projectName = opts.projectName;
231
210
  let directory = opts.directory;
232
211
  const nonInteractive = opts.yes;
233
212
  if (nonInteractive && !projectName) {
234
- console.log(pc2.red(" Error: Project name is required in non-interactive mode"));
235
- console.log(pc2.dim(" Usage: lumera init <name> -y"));
213
+ console.log(pc.red(" Error: Project name is required in non-interactive mode"));
214
+ console.log(pc.dim(" Usage: lumera init <name> -y"));
236
215
  process.exit(1);
237
216
  }
238
217
  let templateName = opts.template;
@@ -247,14 +226,14 @@ async function init(args) {
247
226
  name: "template",
248
227
  message: "Choose a template",
249
228
  choices: available.map((t) => ({
250
- title: `${t.title} ${pc2.dim(`(${t.name})`)}`,
229
+ title: `${t.title} ${pc.dim(`(${t.name})`)}`,
251
230
  description: t.description,
252
231
  value: t.name
253
232
  })),
254
233
  initial: 0
255
234
  });
256
235
  if (!response.template) {
257
- console.log(pc2.red("Cancelled"));
236
+ console.log(pc.red("Cancelled"));
258
237
  process.exit(1);
259
238
  }
260
239
  templateName = response.template;
@@ -283,13 +262,13 @@ async function init(args) {
283
262
  }
284
263
  });
285
264
  if (!response.projectName) {
286
- console.log(pc2.red("Cancelled"));
265
+ console.log(pc.red("Cancelled"));
287
266
  process.exit(1);
288
267
  }
289
268
  projectName = response.projectName;
290
269
  }
291
270
  if (!/^[a-z0-9-]+$/.test(projectName)) {
292
- console.log(pc2.red(" Error: Project name must use lowercase letters, numbers, and hyphens only"));
271
+ console.log(pc.red(" Error: Project name must use lowercase letters, numbers, and hyphens only"));
293
272
  process.exit(1);
294
273
  }
295
274
  if (!directory) {
@@ -303,7 +282,7 @@ async function init(args) {
303
282
  initial: projectName
304
283
  });
305
284
  if (!response.directory) {
306
- console.log(pc2.red("Cancelled"));
285
+ console.log(pc.red("Cancelled"));
307
286
  process.exit(1);
308
287
  }
309
288
  directory = response.directory;
@@ -316,8 +295,8 @@ async function init(args) {
316
295
  if (opts.force) {
317
296
  rmSync(targetDir, { recursive: true });
318
297
  } else {
319
- console.log(pc2.red(` Error: Directory ${directory} already exists`));
320
- console.log(pc2.dim(" Use --force (-f) to overwrite"));
298
+ console.log(pc.red(` Error: Directory ${directory} already exists`));
299
+ console.log(pc.dim(" Use --force (-f) to overwrite"));
321
300
  process.exit(1);
322
301
  }
323
302
  } else {
@@ -328,7 +307,7 @@ async function init(args) {
328
307
  initial: false
329
308
  });
330
309
  if (!overwrite) {
331
- console.log(pc2.red("Cancelled"));
310
+ console.log(pc.red("Cancelled"));
332
311
  process.exit(1);
333
312
  }
334
313
  rmSync(targetDir, { recursive: true });
@@ -337,9 +316,9 @@ async function init(args) {
337
316
  mkdirSync(targetDir, { recursive: true });
338
317
  console.log();
339
318
  if (templateName !== "default") {
340
- console.log(pc2.dim(` Creating ${projectName} from template ${pc2.cyan(templateName)}...`));
319
+ console.log(pc.dim(` Creating ${projectName} from template ${pc.cyan(templateName)}...`));
341
320
  } else {
342
- console.log(pc2.dim(` Creating ${projectName}...`));
321
+ console.log(pc.dim(` Creating ${projectName}...`));
343
322
  }
344
323
  console.log();
345
324
  const templatePkgPath = join(templateDir, "package.json");
@@ -357,7 +336,7 @@ async function init(args) {
357
336
  if (entry.isDirectory()) {
358
337
  listFiles(join(dir, entry.name), relativePath + "/");
359
338
  } else {
360
- console.log(pc2.green(" \u2713"), pc2.dim(relativePath));
339
+ console.log(pc.green(" \u2713"), pc.dim(relativePath));
361
340
  }
362
341
  }
363
342
  }
@@ -365,47 +344,47 @@ async function init(args) {
365
344
  if (isGitInstalled()) {
366
345
  const stopGit = spinner("Initializing git repository...");
367
346
  if (initGitRepo(targetDir, projectName)) {
368
- stopGit(pc2.green("\u2713") + pc2.dim(" Git repository initialized with initial commit"));
347
+ stopGit(pc.green("\u2713") + pc.dim(" Git repository initialized with initial commit"));
369
348
  } else {
370
- stopGit(pc2.yellow("\u26A0") + pc2.dim(" Failed to initialize git repository"));
349
+ stopGit(pc.yellow("\u26A0") + pc.dim(" Failed to initialize git repository"));
371
350
  }
372
351
  } else {
373
- console.log(pc2.yellow(" \u26A0"), pc2.dim("Git not found \u2014 skipping repository initialization"));
352
+ console.log(pc.yellow(" \u26A0"), pc.dim("Git not found \u2014 skipping repository initialization"));
374
353
  }
375
354
  let uvAvailable = isUvInstalled();
376
355
  if (!uvAvailable) {
377
356
  const stopUv = spinner("Installing uv (Python package manager)...");
378
357
  if (installUv()) {
379
- stopUv(pc2.green("\u2713") + pc2.dim(" uv installed successfully"));
358
+ stopUv(pc.green("\u2713") + pc.dim(" uv installed successfully"));
380
359
  uvAvailable = true;
381
360
  } else {
382
- stopUv(pc2.yellow("\u26A0") + pc2.dim(" Failed to install uv \u2014 install manually: https://docs.astral.sh/uv/"));
361
+ stopUv(pc.yellow("\u26A0") + pc.dim(" Failed to install uv \u2014 install manually: https://docs.astral.sh/uv/"));
383
362
  }
384
363
  }
385
364
  if (uvAvailable) {
386
365
  const stopVenv = spinner("Creating Python venv with Lumera SDK...");
387
366
  if (createPythonVenv(targetDir)) {
388
- stopVenv(pc2.green("\u2713") + pc2.dim(" Python venv created (.venv/) with lumera SDK"));
367
+ stopVenv(pc.green("\u2713") + pc.dim(" Python venv created (.venv/) with lumera SDK"));
389
368
  } else {
390
- stopVenv(pc2.yellow("\u26A0") + pc2.dim(" Failed to create Python venv"));
369
+ stopVenv(pc.yellow("\u26A0") + pc.dim(" Failed to create Python venv"));
391
370
  }
392
371
  }
393
372
  if (opts.install) {
394
373
  const stopInstall = spinner("Installing dependencies...");
395
374
  try {
396
375
  execSync("pnpm install", { cwd: targetDir, stdio: "ignore" });
397
- stopInstall(pc2.green("\u2713") + pc2.dim(" Dependencies installed"));
376
+ stopInstall(pc.green("\u2713") + pc.dim(" Dependencies installed"));
398
377
  } catch {
399
- stopInstall(pc2.yellow("\u26A0") + pc2.dim(" Failed to install dependencies"));
378
+ stopInstall(pc.yellow("\u26A0") + pc.dim(" Failed to install dependencies"));
400
379
  }
401
380
  }
402
381
  const stopSkills = spinner("Installing Lumera skills for AI agents...");
403
382
  try {
404
383
  const { installed, failed } = await installAllSkills(targetDir);
405
384
  if (failed > 0) {
406
- stopSkills(pc2.yellow("\u26A0") + pc2.dim(` Installed ${installed} skills (${failed} failed)`));
385
+ stopSkills(pc.yellow("\u26A0") + pc.dim(` Installed ${installed} skills (${failed} failed)`));
407
386
  } else {
408
- stopSkills(pc2.green("\u2713") + pc2.dim(` ${installed} Lumera skills installed`));
387
+ stopSkills(pc.green("\u2713") + pc.dim(` ${installed} Lumera skills installed`));
409
388
  }
410
389
  syncClaudeMd(targetDir);
411
390
  if (isGitInstalled()) {
@@ -418,17 +397,36 @@ async function init(args) {
418
397
  }
419
398
  }
420
399
  } catch (err) {
421
- stopSkills(pc2.yellow("\u26A0") + pc2.dim(` Failed to install skills: ${err}`));
400
+ stopSkills(pc.yellow("\u26A0") + pc.dim(` Failed to install skills: ${err}`));
401
+ }
402
+ let registered = false;
403
+ try {
404
+ const token = getToken(targetDir);
405
+ const api = createApiClient(token);
406
+ const stopRegister = spinner("Registering project on Lumera...");
407
+ try {
408
+ const project = await api.registerProject(projectName);
409
+ setProjectId(targetDir, project.id);
410
+ stopRegister(pc.green("\u2713") + pc.dim(` Project registered (${project.id})`));
411
+ registered = true;
412
+ } catch (e) {
413
+ stopRegister(pc.yellow("\u26A0") + pc.dim(` Could not register project: ${e instanceof Error ? e.message : e}`));
414
+ }
415
+ } catch {
416
+ console.log(pc.yellow(" \u26A0"), pc.dim("Not logged in \u2014 project not registered. Run `lumera login` then `lumera register` to link it."));
422
417
  }
423
418
  console.log();
424
- console.log(pc2.green(pc2.bold(" Done!")), "Next steps:");
419
+ console.log(pc.green(pc.bold(" Done!")), "Next steps:");
425
420
  console.log();
426
- console.log(pc2.cyan(` cd ${directory}`));
421
+ console.log(pc.cyan(` cd ${directory}`));
427
422
  if (!opts.install) {
428
- console.log(pc2.cyan(" pnpm install"));
423
+ console.log(pc.cyan(" pnpm install"));
424
+ }
425
+ if (!registered) {
426
+ console.log(pc.cyan(" lumera login"));
427
+ console.log(pc.cyan(" lumera register"));
429
428
  }
430
- console.log(pc2.cyan(" lumera login"));
431
- console.log(pc2.cyan(" lumera dev"));
429
+ console.log(pc.cyan(" lumera dev"));
432
430
  console.log();
433
431
  if (opts.open) {
434
432
  openInEditor(targetDir);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  detectProjectVersion,
3
3
  findProjectRoot
4
- } from "./chunk-WZMAQXDY.js";
4
+ } from "./chunk-ZH3NVYEQ.js";
5
5
  import "./chunk-PNKVD2UK.js";
6
6
 
7
7
  // src/commands/migrate.ts
@@ -0,0 +1,71 @@
1
+ import {
2
+ loadEnv
3
+ } from "./chunk-2CR762KB.js";
4
+ import {
5
+ spinner
6
+ } from "./chunk-BHYDYR75.js";
7
+ import {
8
+ createApiClient
9
+ } from "./chunk-ILO2IR2G.js";
10
+ import {
11
+ findProjectRoot,
12
+ getAppName,
13
+ getProjectId,
14
+ setProjectId
15
+ } from "./chunk-ZH3NVYEQ.js";
16
+ import "./chunk-PNKVD2UK.js";
17
+
18
+ // src/commands/register.ts
19
+ import pc from "picocolors";
20
+ function showHelp() {
21
+ console.log(`
22
+ ${pc.dim("Usage:")}
23
+ lumera register [options]
24
+
25
+ ${pc.dim("Description:")}
26
+ Register (or re-link) the current project with the Lumera platform.
27
+ Creates an lm_projects record and writes the project ID to package.json.
28
+
29
+ ${pc.dim("Options:")}
30
+ --force, -f Re-register even if project_id already exists in package.json
31
+ --help, -h Show this help
32
+
33
+ ${pc.dim("Examples:")}
34
+ lumera register # Register this project
35
+ lumera register --force # Re-register (update project_id)
36
+ `);
37
+ }
38
+ async function register(args) {
39
+ if (args.includes("--help") || args.includes("-h")) {
40
+ showHelp();
41
+ return;
42
+ }
43
+ const force = args.includes("--force") || args.includes("-f");
44
+ const projectRoot = findProjectRoot();
45
+ loadEnv(projectRoot);
46
+ const appName = getAppName(projectRoot);
47
+ const existingId = getProjectId(projectRoot);
48
+ if (existingId && !force) {
49
+ console.log();
50
+ console.log(pc.green(" \u2713"), `Project already registered: ${pc.dim(existingId)}`);
51
+ console.log(pc.dim(" Use --force to re-register."));
52
+ console.log();
53
+ return;
54
+ }
55
+ const api = createApiClient();
56
+ console.log();
57
+ const stop = spinner(`Registering "${appName}" on Lumera...`);
58
+ try {
59
+ const project = await api.registerProject(appName);
60
+ setProjectId(projectRoot, project.id);
61
+ stop(pc.green("\u2713") + ` Project registered: ${pc.dim(project.id)}`);
62
+ } catch (e) {
63
+ stop(pc.red("\u2717") + ` Failed to register project`);
64
+ console.error(pc.red(` ${e instanceof Error ? e.message : e}`));
65
+ process.exit(1);
66
+ }
67
+ console.log();
68
+ }
69
+ export {
70
+ register
71
+ };
@@ -2,17 +2,20 @@ import {
2
2
  deploy
3
3
  } from "./chunk-XTRDJLIA.js";
4
4
  import {
5
- createApiClient,
6
5
  loadEnv
7
- } from "./chunk-RWPUF6L7.js";
6
+ } from "./chunk-2CR762KB.js";
7
+ import {
8
+ createApiClient
9
+ } from "./chunk-ILO2IR2G.js";
8
10
  import {
9
11
  findProjectRoot,
10
12
  getApiUrl,
11
13
  getAppName,
12
14
  getAppTitle,
15
+ getProjectId,
13
16
  getToken,
14
17
  init_auth
15
- } from "./chunk-WZMAQXDY.js";
18
+ } from "./chunk-ZH3NVYEQ.js";
16
19
  import "./chunk-PNKVD2UK.js";
17
20
 
18
21
  // src/commands/resources.ts
@@ -998,9 +1001,9 @@ function loadLocalAgents(platformDir, filterName, appName) {
998
1001
  }
999
1002
  return agents;
1000
1003
  }
1001
- async function planAgents(api, localAgents) {
1004
+ async function planAgents(api, localAgents, projectId) {
1002
1005
  const changes = [];
1003
- const remoteAgents = await api.listAgents();
1006
+ const remoteAgents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
1004
1007
  const remoteByExternalId = new Map(
1005
1008
  remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
1006
1009
  );
@@ -1051,9 +1054,9 @@ async function planAgents(api, localAgents) {
1051
1054
  }
1052
1055
  return changes;
1053
1056
  }
1054
- async function applyAgents(api, localAgents) {
1057
+ async function applyAgents(api, localAgents, projectId) {
1055
1058
  let errors = 0;
1056
- const remoteAgents = await api.listAgents();
1059
+ const remoteAgents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
1057
1060
  const remoteByExternalId = new Map(
1058
1061
  remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a])
1059
1062
  );
@@ -1095,6 +1098,7 @@ async function applyAgents(api, localAgents) {
1095
1098
  await api.updateAgent(remote.id, payload);
1096
1099
  console.log(pc.green(" \u2713"), `${agent.name} (updated)`);
1097
1100
  } else {
1101
+ if (projectId) payload.project_id = projectId;
1098
1102
  await api.createAgent(payload);
1099
1103
  console.log(pc.green(" \u2713"), `${agent.name} (created)`);
1100
1104
  }
@@ -1105,10 +1109,10 @@ async function applyAgents(api, localAgents) {
1105
1109
  }
1106
1110
  return errors;
1107
1111
  }
1108
- async function pullAgents(api, platformDir, filterName) {
1112
+ async function pullAgents(api, platformDir, filterName, projectId) {
1109
1113
  const agentsDir = join(platformDir, "agents");
1110
1114
  mkdirSync(agentsDir, { recursive: true });
1111
- const agents = await api.listAgents();
1115
+ const agents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
1112
1116
  let skillIdToSlug = /* @__PURE__ */ new Map();
1113
1117
  try {
1114
1118
  const skills = await api.listAgentSkills();
@@ -1146,7 +1150,7 @@ async function pullAgents(api, platformDir, filterName) {
1146
1150
  console.log(pc.green(" \u2713"), `${agent.name} \u2192 agents/${dirName}/`);
1147
1151
  }
1148
1152
  }
1149
- async function listResources(api, platformDir, filterType, appName) {
1153
+ async function listResources(api, platformDir, filterType, appName, projectId) {
1150
1154
  const results = [];
1151
1155
  if (!filterType || filterType === "collections") {
1152
1156
  const localCollections = loadLocalCollections(platformDir);
@@ -1232,7 +1236,7 @@ async function listResources(api, platformDir, filterType, appName) {
1232
1236
  }
1233
1237
  if (!filterType || filterType === "agents") {
1234
1238
  const localAgents = loadLocalAgents(platformDir, void 0, appName);
1235
- const remoteAgents = await api.listAgents();
1239
+ const remoteAgents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
1236
1240
  const remoteByExternalId = new Map(remoteAgents.filter((a) => a.external_id && !a.managed).map((a) => [a.external_id, a]));
1237
1241
  const localIds = new Set(localAgents.map((a) => a.agent.external_id));
1238
1242
  for (const { agent, systemPrompt } of localAgents) {
@@ -1327,7 +1331,7 @@ function planCollectionDelete(collections, platformDir) {
1327
1331
  cycleEdges
1328
1332
  };
1329
1333
  }
1330
- async function destroyResources(api, platformDir, resourceType, resourceName, skipConfirm, forceCycles, appName) {
1334
+ async function destroyResources(api, platformDir, resourceType, resourceName, skipConfirm, forceCycles, appName, projectId) {
1331
1335
  const toDelete = [];
1332
1336
  if (!resourceType || resourceType === "collections") {
1333
1337
  const localCollections = loadLocalCollections(platformDir, resourceName || void 0);
@@ -1368,7 +1372,7 @@ async function destroyResources(api, platformDir, resourceType, resourceName, sk
1368
1372
  if (!resourceType || resourceType === "agents") {
1369
1373
  try {
1370
1374
  const localAgents = loadLocalAgents(platformDir, resourceName || void 0, appName);
1371
- const remoteAgents = await api.listAgents();
1375
+ const remoteAgents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
1372
1376
  const remoteByExternalId = new Map(remoteAgents.filter((a) => a.external_id).map((a) => [a.external_id, a]));
1373
1377
  for (const { agent } of localAgents) {
1374
1378
  const remote = remoteByExternalId.get(agent.external_id);
@@ -1521,7 +1525,7 @@ async function destroyApp(skipConfirm) {
1521
1525
  }
1522
1526
  console.log(pc.green(" \u2713"), `App "${appRecord.name}" deleted from Lumera.`);
1523
1527
  }
1524
- async function showResource(api, platformDir, resourceType, resourceName, appName) {
1528
+ async function showResource(api, platformDir, resourceType, resourceName, appName, projectId) {
1525
1529
  if (resourceType === "collections") {
1526
1530
  const localCollections = loadLocalCollections(platformDir, resourceName);
1527
1531
  const remoteCollections = await api.listCollections();
@@ -1625,7 +1629,7 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
1625
1629
  console.log();
1626
1630
  } else if (resourceType === "agents") {
1627
1631
  const localAgents = loadLocalAgents(platformDir, resourceName, appName);
1628
- const remoteAgents = await api.listAgents();
1632
+ const remoteAgents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
1629
1633
  const local = localAgents[0];
1630
1634
  const remote = remoteAgents.find((a) => a.external_id === resourceName || a.name === resourceName);
1631
1635
  if (!local && !remote) {
@@ -1701,6 +1705,7 @@ async function plan(args) {
1701
1705
  const platformDir = getPlatformDir();
1702
1706
  const api = createApiClient();
1703
1707
  const appName = getAppName(projectRoot);
1708
+ const projectId = getProjectId(projectRoot);
1704
1709
  const { type, name } = parseResource(args[0]);
1705
1710
  console.log();
1706
1711
  console.log(pc.cyan(pc.bold(" Plan")));
@@ -1738,7 +1743,7 @@ async function plan(args) {
1738
1743
  if (!type || type === "agents") {
1739
1744
  const localAgents = loadLocalAgents(platformDir, name || void 0, appName);
1740
1745
  if (localAgents.length > 0) {
1741
- const changes = await planAgents(api, localAgents);
1746
+ const changes = await planAgents(api, localAgents, projectId);
1742
1747
  allChanges.push(...changes);
1743
1748
  }
1744
1749
  }
@@ -1797,6 +1802,7 @@ async function apply(args) {
1797
1802
  const platformDir = getPlatformDir();
1798
1803
  const api = createApiClient();
1799
1804
  const appName = getAppName(projectRoot);
1805
+ const projectId = getProjectId(projectRoot);
1800
1806
  const { type, name } = parseResource(args.filter((a) => a !== "--yes" && a !== "-y")[0]);
1801
1807
  const autoConfirm = args.includes("--yes") || args.includes("-y") || !!process.env.CI;
1802
1808
  if (type === "app") {
@@ -1826,7 +1832,7 @@ async function apply(args) {
1826
1832
  if (localCollections.length > 0) allChanges.push(...await planCollections(api, localCollections));
1827
1833
  if (localAutomations.length > 0) allChanges.push(...await planAutomations(api, localAutomations));
1828
1834
  if (localHooks.length > 0) allChanges.push(...await planHooks(api, localHooks, collections));
1829
- if (localAgents.length > 0) allChanges.push(...await planAgents(api, localAgents));
1835
+ if (localAgents.length > 0) allChanges.push(...await planAgents(api, localAgents, projectId));
1830
1836
  if (name) {
1831
1837
  const hasLocal = localCollections.length > 0 || localAutomations.length > 0 || localHooks.length > 0 || localAgents.length > 0;
1832
1838
  if (!hasLocal) {
@@ -1916,7 +1922,7 @@ async function apply(args) {
1916
1922
  }
1917
1923
  if (localAgents.length > 0) {
1918
1924
  console.log(pc.bold(" Agents:"));
1919
- totalErrors += await applyAgents(api, localAgents);
1925
+ totalErrors += await applyAgents(api, localAgents, projectId);
1920
1926
  console.log();
1921
1927
  }
1922
1928
  if (willDeployApp) {
@@ -1950,6 +1956,7 @@ async function pull(args) {
1950
1956
  const platformDir = getPlatformDir();
1951
1957
  const api = createApiClient();
1952
1958
  const appName = getAppName(projectRoot);
1959
+ const projectId = getProjectId(projectRoot);
1953
1960
  const { type, name } = parseResource(filteredArgs[0]);
1954
1961
  if (!force) {
1955
1962
  const conflicts = [];
@@ -1963,7 +1970,7 @@ async function pull(args) {
1963
1970
  if (!type || type === "agents") {
1964
1971
  const localAgents = loadLocalAgents(platformDir, name || void 0, appName);
1965
1972
  if (localAgents.length > 0) {
1966
- const changes = await planAgents(api, localAgents);
1973
+ const changes = await planAgents(api, localAgents, projectId);
1967
1974
  for (const c of changes) {
1968
1975
  if (c.type === "update") conflicts.push(`agents/${c.name}`);
1969
1976
  }
@@ -2021,7 +2028,7 @@ async function pull(args) {
2021
2028
  }
2022
2029
  if (!type || type === "agents") {
2023
2030
  console.log(pc.bold(" Agents:"));
2024
- await pullAgents(api, platformDir, name || void 0);
2031
+ await pullAgents(api, platformDir, name || void 0, projectId);
2025
2032
  console.log();
2026
2033
  }
2027
2034
  console.log(pc.green(" Done!"));
@@ -2037,6 +2044,7 @@ async function destroy(args) {
2037
2044
  const platformDir = getPlatformDir();
2038
2045
  const api = createApiClient();
2039
2046
  const appName = getAppName(projectRoot);
2047
+ const projectId = getProjectId(projectRoot);
2040
2048
  const { type, name } = parseResource(args[0]);
2041
2049
  const skipConfirm = args.includes("--confirm");
2042
2050
  const forceCycles = args.includes("--force-cycles");
@@ -2046,7 +2054,7 @@ async function destroy(args) {
2046
2054
  if (type === "app") {
2047
2055
  await destroyApp(skipConfirm);
2048
2056
  } else {
2049
- await destroyResources(api, platformDir, type || void 0, name || void 0, skipConfirm, forceCycles, appName);
2057
+ await destroyResources(api, platformDir, type || void 0, name || void 0, skipConfirm, forceCycles, appName, projectId);
2050
2058
  }
2051
2059
  console.log();
2052
2060
  }
@@ -2060,13 +2068,14 @@ async function list(args) {
2060
2068
  const platformDir = getPlatformDir();
2061
2069
  const api = createApiClient();
2062
2070
  const appName = getAppName(projectRoot);
2071
+ const projectId = getProjectId(projectRoot);
2063
2072
  const showAll = args.includes("--all");
2064
2073
  const positionalArgs = args.filter((a) => !a.startsWith("--"));
2065
2074
  const filterType = positionalArgs[0];
2066
2075
  console.log();
2067
2076
  console.log(pc.cyan(pc.bold(" Resources")));
2068
2077
  console.log();
2069
- const allResources = await listResources(api, platformDir, filterType, appName);
2078
+ const allResources = await listResources(api, platformDir, filterType, appName, projectId);
2070
2079
  const remoteOnlyCount = allResources.filter((r) => r.status === "remote-only").length;
2071
2080
  const resources = showAll ? allResources : allResources.filter((r) => r.status !== "remote-only");
2072
2081
  if (resources.length === 0 && remoteOnlyCount === 0) {
@@ -2140,6 +2149,7 @@ async function show(args) {
2140
2149
  const platformDir = getPlatformDir();
2141
2150
  const api = createApiClient();
2142
2151
  const appName = getAppName(projectRoot);
2152
+ const projectId = getProjectId(projectRoot);
2143
2153
  const { type, name } = parseResource(args[0]);
2144
2154
  if (!type) {
2145
2155
  console.log(pc.red(` Invalid resource path: ${args[0]}`));
@@ -2147,13 +2157,13 @@ async function show(args) {
2147
2157
  process.exit(1);
2148
2158
  }
2149
2159
  if (type === "app") {
2150
- await showResource(api, platformDir, "app", "", appName);
2160
+ await showResource(api, platformDir, "app", "", appName, projectId);
2151
2161
  } else if (!name) {
2152
2162
  console.log(pc.red(` Resource name required`));
2153
2163
  console.log(pc.dim(" Use format: <type>/<name> (e.g., collections/users)"));
2154
2164
  process.exit(1);
2155
2165
  } else {
2156
- await showResource(api, platformDir, type, name, appName);
2166
+ await showResource(api, platformDir, type, name, appName, projectId);
2157
2167
  }
2158
2168
  }
2159
2169
  function showDiffHelp() {
@@ -2199,6 +2209,7 @@ async function diff(args) {
2199
2209
  const platformDir = getPlatformDir();
2200
2210
  const api = createApiClient();
2201
2211
  const appName = getAppName(projectRoot);
2212
+ const projectId = getProjectId(projectRoot);
2202
2213
  const { type, name } = parseResource(args[0]);
2203
2214
  if (!type || !name) {
2204
2215
  console.log(pc.red(` Invalid resource path: ${args[0]}`));
@@ -2208,7 +2219,7 @@ async function diff(args) {
2208
2219
  console.log();
2209
2220
  if (type === "agents") {
2210
2221
  const localAgents = loadLocalAgents(platformDir, name, appName);
2211
- const remoteAgents = await api.listAgents();
2222
+ const remoteAgents = await api.listAgents(projectId ? { project_id: projectId } : void 0);
2212
2223
  const local = localAgents[0];
2213
2224
  const localExtId = local?.agent.external_id;
2214
2225
  const remote = remoteAgents.find(
@@ -1,13 +1,15 @@
1
1
  import {
2
- createApiClient,
3
2
  loadEnv
4
- } from "./chunk-RWPUF6L7.js";
3
+ } from "./chunk-2CR762KB.js";
4
+ import {
5
+ createApiClient
6
+ } from "./chunk-ILO2IR2G.js";
5
7
  import {
6
8
  findProjectRoot,
7
9
  getApiUrl,
8
10
  getToken,
9
11
  init_auth
10
- } from "./chunk-WZMAQXDY.js";
12
+ } from "./chunk-ZH3NVYEQ.js";
11
13
  import "./chunk-PNKVD2UK.js";
12
14
 
13
15
  // src/commands/run.ts
@@ -1,4 +1,5 @@
1
1
  import {
2
+ ensureSkillSymlinks,
2
3
  fetchSkillContent,
3
4
  fetchSkillsList,
4
5
  getLocalSkills,
@@ -6,8 +7,8 @@ import {
6
7
  installAllSkills,
7
8
  slugToFilename,
8
9
  syncClaudeMd
9
- } from "./chunk-FZPONF23.js";
10
- import "./chunk-WZMAQXDY.js";
10
+ } from "./chunk-XLZ2LQNO.js";
11
+ import "./chunk-ZH3NVYEQ.js";
11
12
  import "./chunk-PNKVD2UK.js";
12
13
 
13
14
  // src/commands/skills.ts
@@ -358,6 +359,7 @@ async function update(args, flags) {
358
359
  console.log();
359
360
  console.log(pc.green(" \u2713"), `Update complete (${changes.join(", ")})`);
360
361
  syncClaudeMd(projectRoot);
362
+ ensureSkillSymlinks(projectRoot);
361
363
  console.log();
362
364
  } catch (err) {
363
365
  console.log(pc.red(" Error:"), String(err));
@@ -8,7 +8,7 @@ import {
8
8
  getTokenSource,
9
9
  init_auth,
10
10
  readPackageJson
11
- } from "./chunk-WZMAQXDY.js";
11
+ } from "./chunk-ZH3NVYEQ.js";
12
12
  import "./chunk-PNKVD2UK.js";
13
13
 
14
14
  // src/commands/status.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumerahq/cli",
3
- "version": "0.15.1",
3
+ "version": "0.16.0",
4
4
  "description": "CLI for building and deploying Lumera apps",
5
5
  "type": "module",
6
6
  "engines": {