@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.
- package/dist/{auth-YQXLYQZZ.js → auth-KFXSNCJB.js} +1 -1
- package/dist/chunk-2CR762KB.js +18 -0
- package/dist/chunk-BHYDYR75.js +33 -0
- package/dist/{chunk-RWPUF6L7.js → chunk-ILO2IR2G.js} +62 -20
- package/dist/{chunk-FZPONF23.js → chunk-XLZ2LQNO.js} +36 -3
- package/dist/{chunk-WZMAQXDY.js → chunk-ZH3NVYEQ.js} +15 -1
- package/dist/{dev-NN766QJW.js → dev-RNV6CJQI.js} +5 -3
- package/dist/index.js +21 -16
- package/dist/{init-ZI3FZSRE.js → init-35S7YVGF.js} +72 -74
- package/dist/{migrate-MW5Q2HS6.js → migrate-NCZKP7FM.js} +1 -1
- package/dist/register-MLXJNMNR.js +71 -0
- package/dist/{resources-26TZX2XU.js → resources-64MEBAL5.js} +36 -25
- package/dist/{run-WD5CKV3S.js → run-2VKKOCHR.js} +5 -3
- package/dist/{skills-6TSSUJYR.js → skills-4UZIEFMP.js} +4 -2
- package/dist/{status-ZFEEIK4O.js → status-EW5I7QAU.js} +1 -1
- package/package.json +1 -1
|
@@ -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-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
218
|
+
await import("./resources-64MEBAL5.js").then((m) => m.plan(args.slice(1)));
|
|
217
219
|
break;
|
|
218
220
|
case "apply":
|
|
219
|
-
await import("./resources-
|
|
221
|
+
await import("./resources-64MEBAL5.js").then((m) => m.apply(args.slice(1)));
|
|
220
222
|
break;
|
|
221
223
|
case "pull":
|
|
222
|
-
await import("./resources-
|
|
224
|
+
await import("./resources-64MEBAL5.js").then((m) => m.pull(args.slice(1)));
|
|
223
225
|
break;
|
|
224
226
|
case "destroy":
|
|
225
|
-
await import("./resources-
|
|
227
|
+
await import("./resources-64MEBAL5.js").then((m) => m.destroy(args.slice(1)));
|
|
226
228
|
break;
|
|
227
229
|
case "list":
|
|
228
|
-
await import("./resources-
|
|
230
|
+
await import("./resources-64MEBAL5.js").then((m) => m.list(args.slice(1)));
|
|
229
231
|
break;
|
|
230
232
|
case "show":
|
|
231
|
-
await import("./resources-
|
|
233
|
+
await import("./resources-64MEBAL5.js").then((m) => m.show(args.slice(1)));
|
|
232
234
|
break;
|
|
233
235
|
case "diff":
|
|
234
|
-
await import("./resources-
|
|
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-
|
|
240
|
+
await import("./dev-RNV6CJQI.js").then((m) => m.dev(args.slice(1)));
|
|
239
241
|
break;
|
|
240
242
|
case "run":
|
|
241
|
-
await import("./run-
|
|
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-
|
|
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-
|
|
256
|
+
await import("./status-EW5I7QAU.js").then((m) => m.status(args.slice(1)));
|
|
252
257
|
break;
|
|
253
258
|
case "migrate":
|
|
254
|
-
await import("./migrate-
|
|
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-
|
|
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-
|
|
267
|
+
await import("./auth-KFXSNCJB.js").then((m) => m.login(args.slice(1)));
|
|
263
268
|
break;
|
|
264
269
|
case "logout":
|
|
265
|
-
await import("./auth-
|
|
270
|
+
await import("./auth-KFXSNCJB.js").then((m) => m.logout(args.slice(1)));
|
|
266
271
|
break;
|
|
267
272
|
case "whoami":
|
|
268
|
-
await import("./auth-
|
|
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-
|
|
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
|
|
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
|
-
|
|
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(
|
|
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(
|
|
138
|
+
console.log(pc.green(" \u2713"), pc.dim(`Opened in ${editor}`));
|
|
160
139
|
} catch {
|
|
161
|
-
console.log(
|
|
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
|
-
${
|
|
178
|
+
${pc.dim("Usage:")}
|
|
200
179
|
lumera init [name] [options]
|
|
201
180
|
|
|
202
|
-
${
|
|
181
|
+
${pc.dim("Description:")}
|
|
203
182
|
Scaffold a new Lumera project from a template.
|
|
204
183
|
|
|
205
|
-
${
|
|
206
|
-
--template, -t <name> Template to use (run ${
|
|
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
|
-
${
|
|
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(
|
|
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(
|
|
235
|
-
console.log(
|
|
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} ${
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
320
|
-
console.log(
|
|
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(
|
|
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(
|
|
319
|
+
console.log(pc.dim(` Creating ${projectName} from template ${pc.cyan(templateName)}...`));
|
|
341
320
|
} else {
|
|
342
|
-
console.log(
|
|
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(
|
|
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(
|
|
347
|
+
stopGit(pc.green("\u2713") + pc.dim(" Git repository initialized with initial commit"));
|
|
369
348
|
} else {
|
|
370
|
-
stopGit(
|
|
349
|
+
stopGit(pc.yellow("\u26A0") + pc.dim(" Failed to initialize git repository"));
|
|
371
350
|
}
|
|
372
351
|
} else {
|
|
373
|
-
console.log(
|
|
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(
|
|
358
|
+
stopUv(pc.green("\u2713") + pc.dim(" uv installed successfully"));
|
|
380
359
|
uvAvailable = true;
|
|
381
360
|
} else {
|
|
382
|
-
stopUv(
|
|
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(
|
|
367
|
+
stopVenv(pc.green("\u2713") + pc.dim(" Python venv created (.venv/) with lumera SDK"));
|
|
389
368
|
} else {
|
|
390
|
-
stopVenv(
|
|
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(
|
|
376
|
+
stopInstall(pc.green("\u2713") + pc.dim(" Dependencies installed"));
|
|
398
377
|
} catch {
|
|
399
|
-
stopInstall(
|
|
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(
|
|
385
|
+
stopSkills(pc.yellow("\u26A0") + pc.dim(` Installed ${installed} skills (${failed} failed)`));
|
|
407
386
|
} else {
|
|
408
|
-
stopSkills(
|
|
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(
|
|
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(
|
|
419
|
+
console.log(pc.green(pc.bold(" Done!")), "Next steps:");
|
|
425
420
|
console.log();
|
|
426
|
-
console.log(
|
|
421
|
+
console.log(pc.cyan(` cd ${directory}`));
|
|
427
422
|
if (!opts.install) {
|
|
428
|
-
console.log(
|
|
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(
|
|
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);
|
|
@@ -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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
10
|
-
import "./chunk-
|
|
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));
|