@lumerahq/cli 0.18.2 → 0.18.4
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/{chunk-XTRDJLIA.js → chunk-2I2VXPJK.js} +20 -38
- package/dist/{chunk-ILO2IR2G.js → chunk-G7427W43.js} +10 -3
- package/dist/chunk-YIQRLXEN.js +120 -0
- package/dist/deps-K54NOIZY.js +12 -0
- package/dist/{dev-RNV6CJQI.js → dev-62JXNDN3.js} +2 -2
- package/dist/index.js +16 -11
- package/dist/{init-YUZQ54HZ.js → init-ZDOPG3KN.js} +5 -5
- package/dist/{register-MLXJNMNR.js → register-COESODY2.js} +1 -1
- package/dist/{resources-6SJR45CY.js → resources-CMY4IRUS.js} +77 -31
- package/dist/{run-2VKKOCHR.js → run-6ULEFGHJ.js} +8 -5
- package/package.json +1 -1
|
@@ -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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
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
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dev
|
|
3
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
219
|
+
await import("./resources-CMY4IRUS.js").then((m) => m.plan(args.slice(1)));
|
|
219
220
|
break;
|
|
220
221
|
case "apply":
|
|
221
|
-
await import("./resources-
|
|
222
|
+
await import("./resources-CMY4IRUS.js").then((m) => m.apply(args.slice(1)));
|
|
222
223
|
break;
|
|
223
224
|
case "pull":
|
|
224
|
-
await import("./resources-
|
|
225
|
+
await import("./resources-CMY4IRUS.js").then((m) => m.pull(args.slice(1)));
|
|
225
226
|
break;
|
|
226
227
|
case "destroy":
|
|
227
|
-
await import("./resources-
|
|
228
|
+
await import("./resources-CMY4IRUS.js").then((m) => m.destroy(args.slice(1)));
|
|
228
229
|
break;
|
|
229
230
|
case "list":
|
|
230
|
-
await import("./resources-
|
|
231
|
+
await import("./resources-CMY4IRUS.js").then((m) => m.list(args.slice(1)));
|
|
231
232
|
break;
|
|
232
233
|
case "show":
|
|
233
|
-
await import("./resources-
|
|
234
|
+
await import("./resources-CMY4IRUS.js").then((m) => m.show(args.slice(1)));
|
|
234
235
|
break;
|
|
235
236
|
case "diff":
|
|
236
|
-
await import("./resources-
|
|
237
|
+
await import("./resources-CMY4IRUS.js").then((m) => m.diff(args.slice(1)));
|
|
237
238
|
break;
|
|
238
239
|
// Development
|
|
239
240
|
case "dev":
|
|
240
|
-
await import("./dev-
|
|
241
|
+
await import("./dev-62JXNDN3.js").then((m) => m.dev(args.slice(1)));
|
|
241
242
|
break;
|
|
242
243
|
case "run":
|
|
243
|
-
await import("./run-
|
|
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-
|
|
248
|
+
await import("./init-ZDOPG3KN.js").then((m) => m.init(args.slice(1)));
|
|
248
249
|
break;
|
|
249
250
|
case "register":
|
|
250
|
-
await import("./register-
|
|
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-
|
|
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
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
syncDeps
|
|
3
|
+
} from "./chunk-YIQRLXEN.js";
|
|
1
4
|
import {
|
|
2
5
|
deploy
|
|
3
|
-
} from "./chunk-
|
|
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-
|
|
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");
|
|
@@ -538,7 +553,10 @@ function loadLocalAutomations(platformDir, filterName, appName) {
|
|
|
538
553
|
errors.push(`${entry.name}: duplicate external_id "${config.external_id}" (also defined in ${existingByExtId.automation.name})`);
|
|
539
554
|
continue;
|
|
540
555
|
}
|
|
541
|
-
|
|
556
|
+
let code = readFileSync(mainPath, "utf-8");
|
|
557
|
+
if (appName) {
|
|
558
|
+
code = code.replaceAll("{{app}}", appName);
|
|
559
|
+
}
|
|
542
560
|
automations.push({ automation: config, code });
|
|
543
561
|
} catch (e) {
|
|
544
562
|
errors.push(`${entry.name}: failed to parse config.json - ${e}`);
|
|
@@ -950,7 +968,7 @@ async function applyCollections(api, localCollections) {
|
|
|
950
968
|
}
|
|
951
969
|
return errors;
|
|
952
970
|
}
|
|
953
|
-
async function applyAutomations(api, localAutomations) {
|
|
971
|
+
async function applyAutomations(api, localAutomations, projectId) {
|
|
954
972
|
let errors = 0;
|
|
955
973
|
const remoteAutomations = await api.listAutomations();
|
|
956
974
|
const remoteByExternalId = new Map(remoteAutomations.filter((a) => a.external_id).map((a) => [a.external_id, a]));
|
|
@@ -962,6 +980,9 @@ async function applyAutomations(api, localAutomations) {
|
|
|
962
980
|
description: automation.description,
|
|
963
981
|
code
|
|
964
982
|
};
|
|
983
|
+
if (projectId) {
|
|
984
|
+
payload.project_id = projectId;
|
|
985
|
+
}
|
|
965
986
|
if (automation.inputs?.schema) {
|
|
966
987
|
payload.input_schema = automation.inputs.schema;
|
|
967
988
|
}
|
|
@@ -1059,7 +1080,7 @@ async function setSchedule(api, automationId, schedule, localPresets) {
|
|
|
1059
1080
|
console.log(pc.yellow(` \u26A0 Failed to set schedule: ${e}`));
|
|
1060
1081
|
}
|
|
1061
1082
|
}
|
|
1062
|
-
async function applyHooks(api, localHooks, collections) {
|
|
1083
|
+
async function applyHooks(api, localHooks, collections, projectId) {
|
|
1063
1084
|
let errors = 0;
|
|
1064
1085
|
const remoteHooks = await api.listHooks();
|
|
1065
1086
|
const remoteByExternalId = new Map(remoteHooks.filter((h) => h.external_id).map((h) => [h.external_id, h]));
|
|
@@ -1080,6 +1101,9 @@ async function applyHooks(api, localHooks, collections) {
|
|
|
1080
1101
|
enabled: hook.enabled !== false,
|
|
1081
1102
|
metadata: hook.metadata
|
|
1082
1103
|
};
|
|
1104
|
+
if (projectId) {
|
|
1105
|
+
payload.project_id = projectId;
|
|
1106
|
+
}
|
|
1083
1107
|
try {
|
|
1084
1108
|
if (remote) {
|
|
1085
1109
|
await api.updateHook(remote.id, payload);
|
|
@@ -1115,18 +1139,23 @@ async function applyApp(args) {
|
|
|
1115
1139
|
const distDir = resolve(projectRoot, "dist");
|
|
1116
1140
|
await deploy({ token, appName, appTitle, distDir, apiUrl });
|
|
1117
1141
|
}
|
|
1118
|
-
async function pullCollections(api, platformDir, filterName) {
|
|
1142
|
+
async function pullCollections(api, platformDir, filterName, appName) {
|
|
1119
1143
|
const collectionsDir = join(platformDir, "collections");
|
|
1120
1144
|
mkdirSync(collectionsDir, { recursive: true });
|
|
1121
1145
|
const collections = await api.listCollections();
|
|
1122
1146
|
for (const collection of collections) {
|
|
1123
1147
|
if (collection.system || collection.managed) continue;
|
|
1124
|
-
if (
|
|
1148
|
+
if (appName && collection.name.includes(NAMESPACE_SEPARATOR)) {
|
|
1149
|
+
const prefix = collection.name.split(NAMESPACE_SEPARATOR)[0];
|
|
1150
|
+
if (prefix !== sanitizeSlugForCollectionName(appName)) continue;
|
|
1151
|
+
}
|
|
1152
|
+
const localName = stripNamespacePrefix(collection.name, appName);
|
|
1153
|
+
if (filterName && localName !== filterName && collection.name !== filterName && collection.id !== filterName) {
|
|
1125
1154
|
continue;
|
|
1126
1155
|
}
|
|
1127
1156
|
const localFormat = {
|
|
1128
1157
|
id: collection.id,
|
|
1129
|
-
name:
|
|
1158
|
+
name: localName,
|
|
1130
1159
|
fields: collection.schema.map((field) => {
|
|
1131
1160
|
const localField = {
|
|
1132
1161
|
name: field.name,
|
|
@@ -1148,18 +1177,20 @@ async function pullCollections(api, platformDir, filterName) {
|
|
|
1148
1177
|
return null;
|
|
1149
1178
|
}).filter((idx) => idx !== null)
|
|
1150
1179
|
};
|
|
1151
|
-
const fileName = toSafeFilename(
|
|
1180
|
+
const fileName = toSafeFilename(localName);
|
|
1152
1181
|
const filePath = join(collectionsDir, `${fileName}.json`);
|
|
1153
1182
|
writeFileSync(filePath, JSON.stringify(localFormat, null, 2) + "\n");
|
|
1154
|
-
console.log(pc.green(" \u2713"), `${
|
|
1183
|
+
console.log(pc.green(" \u2713"), `${localName} \u2192 collections/${fileName}.json`);
|
|
1155
1184
|
}
|
|
1156
1185
|
}
|
|
1157
|
-
async function pullAutomations(api, platformDir, filterName) {
|
|
1186
|
+
async function pullAutomations(api, platformDir, filterName, projectId) {
|
|
1158
1187
|
const automationsDir = join(platformDir, "automations");
|
|
1159
1188
|
mkdirSync(automationsDir, { recursive: true });
|
|
1160
1189
|
const automations = await api.listAutomations({ include_code: true });
|
|
1161
1190
|
for (const automation of automations) {
|
|
1162
1191
|
if (!automation.external_id || automation.managed) continue;
|
|
1192
|
+
if (projectId && automation.project_id && automation.project_id !== projectId) continue;
|
|
1193
|
+
if (!projectId && automation.project_id) continue;
|
|
1163
1194
|
if (filterName && automation.external_id !== filterName && automation.name !== filterName) {
|
|
1164
1195
|
continue;
|
|
1165
1196
|
}
|
|
@@ -1202,19 +1233,21 @@ async function pullAutomations(api, platformDir, filterName) {
|
|
|
1202
1233
|
console.log(pc.green(" \u2713"), `${automation.name} \u2192 automations/${dirName}/`);
|
|
1203
1234
|
}
|
|
1204
1235
|
}
|
|
1205
|
-
async function pullHooks(api, platformDir, filterName) {
|
|
1236
|
+
async function pullHooks(api, platformDir, filterName, appName, projectId) {
|
|
1206
1237
|
const hooksDir = join(platformDir, "hooks");
|
|
1207
1238
|
mkdirSync(hooksDir, { recursive: true });
|
|
1208
1239
|
const hooks = await api.listHooks();
|
|
1209
1240
|
for (const hook of hooks) {
|
|
1210
1241
|
if (!hook.external_id) continue;
|
|
1242
|
+
if (projectId && hook.project_id && hook.project_id !== projectId) continue;
|
|
1243
|
+
if (!projectId && hook.project_id) continue;
|
|
1211
1244
|
if (filterName && hook.external_id !== filterName) {
|
|
1212
1245
|
continue;
|
|
1213
1246
|
}
|
|
1214
1247
|
const fileName = `${hook.external_id.replace(/[^a-zA-Z0-9_-]/g, "_")}.js`;
|
|
1215
1248
|
const content = `export const config = {
|
|
1216
1249
|
external_id: '${hook.external_id}',
|
|
1217
|
-
collection: '${hook.collection_name}',
|
|
1250
|
+
collection: '${stripNamespacePrefix(hook.collection_name, appName)}',
|
|
1218
1251
|
trigger: '${hook.event}',
|
|
1219
1252
|
enabled: ${hook.enabled},
|
|
1220
1253
|
};
|
|
@@ -1263,8 +1296,12 @@ function loadLocalAgents(platformDir, filterName, appName) {
|
|
|
1263
1296
|
errors.push(`${entry.name}: missing name in config.json`);
|
|
1264
1297
|
continue;
|
|
1265
1298
|
}
|
|
1266
|
-
|
|
1267
|
-
|
|
1299
|
+
let systemPrompt = readFileSync(promptPath, "utf-8");
|
|
1300
|
+
let policyScript = existsSync(policyPath) ? readFileSync(policyPath, "utf-8") : "";
|
|
1301
|
+
if (appName) {
|
|
1302
|
+
systemPrompt = systemPrompt.replaceAll("{{app}}", appName);
|
|
1303
|
+
policyScript = policyScript.replaceAll("{{app}}", appName);
|
|
1304
|
+
}
|
|
1268
1305
|
agents.push({ agent: config, systemPrompt, policyScript });
|
|
1269
1306
|
} catch (e) {
|
|
1270
1307
|
errors.push(`${entry.name}: failed to parse config.json - ${e}`);
|
|
@@ -1308,6 +1345,7 @@ async function planAgents(api, localAgents, projectId) {
|
|
|
1308
1345
|
if ((remote.model || "") !== (agent.model || "")) diffs.push("model");
|
|
1309
1346
|
if ((remote.policy_script || "").trim() !== (policyScript || "").trim()) diffs.push("policy_script");
|
|
1310
1347
|
if ((remote.policy_enabled || false) !== (agent.policy_enabled || false)) diffs.push("policy_enabled");
|
|
1348
|
+
if ((remote.policy_description || "") !== (agent.policy_description || "")) diffs.push("policy_description");
|
|
1311
1349
|
const localSkillIds = (agent.skills || []).map((s) => skillSlugToId.get(s) || s).sort();
|
|
1312
1350
|
const remoteSkillIds = [...remote.skill_ids || []].sort();
|
|
1313
1351
|
if (localSkillIds.join(",") !== remoteSkillIds.join(",")) {
|
|
@@ -1369,7 +1407,8 @@ async function applyAgents(api, localAgents, projectId) {
|
|
|
1369
1407
|
model: agent.model || "",
|
|
1370
1408
|
skill_ids: skillIds,
|
|
1371
1409
|
policy_script: policyScript || "",
|
|
1372
|
-
policy_enabled: agent.policy_enabled || false
|
|
1410
|
+
policy_enabled: agent.policy_enabled || false,
|
|
1411
|
+
policy_description: agent.policy_description || ""
|
|
1373
1412
|
};
|
|
1374
1413
|
try {
|
|
1375
1414
|
if (remote) {
|
|
@@ -1433,7 +1472,7 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
|
|
|
1433
1472
|
if (!filterType || filterType === "collections") {
|
|
1434
1473
|
const localCollections = loadLocalCollections(platformDir);
|
|
1435
1474
|
const remoteCollections = await api.listCollections();
|
|
1436
|
-
const remoteByName = new Map(remoteCollections.filter((c) => !c.system && !c.managed).map((c) => [c.name, c]));
|
|
1475
|
+
const remoteByName = new Map(remoteCollections.filter((c) => !c.system && !c.managed).map((c) => [stripNamespacePrefix(c.name, appName), c]));
|
|
1437
1476
|
const localNames = new Set(localCollections.map((c) => c.name));
|
|
1438
1477
|
for (const local of localCollections) {
|
|
1439
1478
|
const remote = remoteByName.get(local.name);
|
|
@@ -1456,8 +1495,13 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
|
|
|
1456
1495
|
}
|
|
1457
1496
|
for (const remote of remoteCollections) {
|
|
1458
1497
|
if (remote.system || remote.managed) continue;
|
|
1459
|
-
if (
|
|
1460
|
-
|
|
1498
|
+
if (appName && remote.name.includes(NAMESPACE_SEPARATOR)) {
|
|
1499
|
+
const prefix = remote.name.split(NAMESPACE_SEPARATOR)[0];
|
|
1500
|
+
if (prefix !== sanitizeSlugForCollectionName(appName)) continue;
|
|
1501
|
+
}
|
|
1502
|
+
const stripped = stripNamespacePrefix(remote.name, appName);
|
|
1503
|
+
if (!localNames.has(stripped)) {
|
|
1504
|
+
results.push({ name: stripped, type: "collections", status: "remote-only" });
|
|
1461
1505
|
}
|
|
1462
1506
|
}
|
|
1463
1507
|
}
|
|
@@ -1981,8 +2025,8 @@ async function plan(args) {
|
|
|
1981
2025
|
const projectRoot = findProjectRoot();
|
|
1982
2026
|
loadEnv(projectRoot);
|
|
1983
2027
|
const platformDir = getPlatformDir();
|
|
1984
|
-
const api = createApiClient();
|
|
1985
2028
|
const appName = getAppName(projectRoot);
|
|
2029
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
1986
2030
|
const projectId = getProjectId(projectRoot);
|
|
1987
2031
|
const positionalArgs = args.filter((a) => !a.startsWith("-"));
|
|
1988
2032
|
const { type, name } = parseResource(positionalArgs[0]);
|
|
@@ -1990,6 +2034,7 @@ async function plan(args) {
|
|
|
1990
2034
|
console.log(pc.cyan(pc.bold(" Plan")));
|
|
1991
2035
|
console.log(pc.dim(" Comparing local files to remote state..."));
|
|
1992
2036
|
console.log();
|
|
2037
|
+
await syncDeps(projectRoot);
|
|
1993
2038
|
const allChanges = [];
|
|
1994
2039
|
let collections;
|
|
1995
2040
|
try {
|
|
@@ -2079,8 +2124,8 @@ async function apply(args) {
|
|
|
2079
2124
|
const projectRoot = findProjectRoot();
|
|
2080
2125
|
loadEnv(projectRoot);
|
|
2081
2126
|
const platformDir = getPlatformDir();
|
|
2082
|
-
const api = createApiClient();
|
|
2083
2127
|
const appName = getAppName(projectRoot);
|
|
2128
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2084
2129
|
const projectId = getProjectId(projectRoot);
|
|
2085
2130
|
const positionalArgs = args.filter((a) => !a.startsWith("-"));
|
|
2086
2131
|
const { type, name } = parseResource(positionalArgs[0]);
|
|
@@ -2096,6 +2141,7 @@ async function apply(args) {
|
|
|
2096
2141
|
console.log();
|
|
2097
2142
|
return;
|
|
2098
2143
|
}
|
|
2144
|
+
await syncDeps(projectRoot);
|
|
2099
2145
|
let collections;
|
|
2100
2146
|
try {
|
|
2101
2147
|
const remoteCollections = await api.listCollections();
|
|
@@ -2192,12 +2238,12 @@ async function apply(args) {
|
|
|
2192
2238
|
}
|
|
2193
2239
|
if (localAutomations.length > 0) {
|
|
2194
2240
|
console.log(pc.bold(" Automations:"));
|
|
2195
|
-
totalErrors += await applyAutomations(api, localAutomations);
|
|
2241
|
+
totalErrors += await applyAutomations(api, localAutomations, projectId);
|
|
2196
2242
|
console.log();
|
|
2197
2243
|
}
|
|
2198
2244
|
if (localHooks.length > 0) {
|
|
2199
2245
|
console.log(pc.bold(" Hooks:"));
|
|
2200
|
-
totalErrors += await applyHooks(api, localHooks, collections);
|
|
2246
|
+
totalErrors += await applyHooks(api, localHooks, collections, projectId);
|
|
2201
2247
|
console.log();
|
|
2202
2248
|
}
|
|
2203
2249
|
if (localAgents.length > 0) {
|
|
@@ -2234,8 +2280,8 @@ async function pull(args) {
|
|
|
2234
2280
|
const projectRoot = findProjectRoot();
|
|
2235
2281
|
loadEnv(projectRoot);
|
|
2236
2282
|
const platformDir = getPlatformDir();
|
|
2237
|
-
const api = createApiClient();
|
|
2238
2283
|
const appName = getAppName(projectRoot);
|
|
2284
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2239
2285
|
const projectId = getProjectId(projectRoot);
|
|
2240
2286
|
const { type, name } = parseResource(filteredArgs[0]);
|
|
2241
2287
|
if (!force) {
|
|
@@ -2293,17 +2339,17 @@ async function pull(args) {
|
|
|
2293
2339
|
console.log();
|
|
2294
2340
|
if (!type || type === "collections") {
|
|
2295
2341
|
console.log(pc.bold(" Collections:"));
|
|
2296
|
-
await pullCollections(api, platformDir, name || void 0);
|
|
2342
|
+
await pullCollections(api, platformDir, name || void 0, appName);
|
|
2297
2343
|
console.log();
|
|
2298
2344
|
}
|
|
2299
2345
|
if (!type || type === "automations") {
|
|
2300
2346
|
console.log(pc.bold(" Automations:"));
|
|
2301
|
-
await pullAutomations(api, platformDir, name || void 0);
|
|
2347
|
+
await pullAutomations(api, platformDir, name || void 0, projectId);
|
|
2302
2348
|
console.log();
|
|
2303
2349
|
}
|
|
2304
2350
|
if (!type || type === "hooks") {
|
|
2305
2351
|
console.log(pc.bold(" Hooks:"));
|
|
2306
|
-
await pullHooks(api, platformDir, name || void 0);
|
|
2352
|
+
await pullHooks(api, platformDir, name || void 0, appName, projectId);
|
|
2307
2353
|
console.log();
|
|
2308
2354
|
}
|
|
2309
2355
|
if (!type || type === "agents") {
|
|
@@ -2322,8 +2368,8 @@ async function destroy(args) {
|
|
|
2322
2368
|
const projectRoot = findProjectRoot();
|
|
2323
2369
|
loadEnv(projectRoot);
|
|
2324
2370
|
const platformDir = getPlatformDir();
|
|
2325
|
-
const api = createApiClient();
|
|
2326
2371
|
const appName = getAppName(projectRoot);
|
|
2372
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2327
2373
|
const projectId = getProjectId(projectRoot);
|
|
2328
2374
|
const { type, name } = parseResource(args[0]);
|
|
2329
2375
|
const skipConfirm = args.includes("--confirm");
|
|
@@ -2346,8 +2392,8 @@ async function list(args) {
|
|
|
2346
2392
|
const projectRoot = findProjectRoot();
|
|
2347
2393
|
loadEnv(projectRoot);
|
|
2348
2394
|
const platformDir = getPlatformDir();
|
|
2349
|
-
const api = createApiClient();
|
|
2350
2395
|
const appName = getAppName(projectRoot);
|
|
2396
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2351
2397
|
const projectId = getProjectId(projectRoot);
|
|
2352
2398
|
const showAll = args.includes("--all");
|
|
2353
2399
|
const positionalArgs = args.filter((a) => !a.startsWith("--"));
|
|
@@ -2427,8 +2473,8 @@ async function show(args) {
|
|
|
2427
2473
|
const projectRoot = findProjectRoot();
|
|
2428
2474
|
loadEnv(projectRoot);
|
|
2429
2475
|
const platformDir = getPlatformDir();
|
|
2430
|
-
const api = createApiClient();
|
|
2431
2476
|
const appName = getAppName(projectRoot);
|
|
2477
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2432
2478
|
const projectId = getProjectId(projectRoot);
|
|
2433
2479
|
const { type, name } = parseResource(args[0]);
|
|
2434
2480
|
if (!type) {
|
|
@@ -2487,8 +2533,8 @@ async function diff(args) {
|
|
|
2487
2533
|
const projectRoot = findProjectRoot();
|
|
2488
2534
|
loadEnv(projectRoot);
|
|
2489
2535
|
const platformDir = getPlatformDir();
|
|
2490
|
-
const api = createApiClient();
|
|
2491
2536
|
const appName = getAppName(projectRoot);
|
|
2537
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2492
2538
|
const projectId = getProjectId(projectRoot);
|
|
2493
2539
|
const { type, name } = parseResource(args[0]);
|
|
2494
2540
|
if (!type || !name) {
|
|
@@ -3,10 +3,11 @@ import {
|
|
|
3
3
|
} from "./chunk-2CR762KB.js";
|
|
4
4
|
import {
|
|
5
5
|
createApiClient
|
|
6
|
-
} from "./chunk-
|
|
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
|
|
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
|
|
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);
|