@lumerahq/cli 0.18.1 → 0.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-E4XMWX7N.js → resources-IJ2VFUG5.js} +93 -40
- 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-IJ2VFUG5.js").then((m) => m.plan(args.slice(1)));
|
|
219
220
|
break;
|
|
220
221
|
case "apply":
|
|
221
|
-
await import("./resources-
|
|
222
|
+
await import("./resources-IJ2VFUG5.js").then((m) => m.apply(args.slice(1)));
|
|
222
223
|
break;
|
|
223
224
|
case "pull":
|
|
224
|
-
await import("./resources-
|
|
225
|
+
await import("./resources-IJ2VFUG5.js").then((m) => m.pull(args.slice(1)));
|
|
225
226
|
break;
|
|
226
227
|
case "destroy":
|
|
227
|
-
await import("./resources-
|
|
228
|
+
await import("./resources-IJ2VFUG5.js").then((m) => m.destroy(args.slice(1)));
|
|
228
229
|
break;
|
|
229
230
|
case "list":
|
|
230
|
-
await import("./resources-
|
|
231
|
+
await import("./resources-IJ2VFUG5.js").then((m) => m.list(args.slice(1)));
|
|
231
232
|
break;
|
|
232
233
|
case "show":
|
|
233
|
-
await import("./resources-
|
|
234
|
+
await import("./resources-IJ2VFUG5.js").then((m) => m.show(args.slice(1)));
|
|
234
235
|
break;
|
|
235
236
|
case "diff":
|
|
236
|
-
await import("./resources-
|
|
237
|
+
await import("./resources-IJ2VFUG5.js").then((m) => m.diff(args.slice(1)));
|
|
237
238
|
break;
|
|
238
239
|
// Development
|
|
239
240
|
case "dev":
|
|
240
|
-
await import("./dev-
|
|
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");
|
|
@@ -950,7 +965,7 @@ async function applyCollections(api, localCollections) {
|
|
|
950
965
|
}
|
|
951
966
|
return errors;
|
|
952
967
|
}
|
|
953
|
-
async function applyAutomations(api, localAutomations) {
|
|
968
|
+
async function applyAutomations(api, localAutomations, projectId) {
|
|
954
969
|
let errors = 0;
|
|
955
970
|
const remoteAutomations = await api.listAutomations();
|
|
956
971
|
const remoteByExternalId = new Map(remoteAutomations.filter((a) => a.external_id).map((a) => [a.external_id, a]));
|
|
@@ -962,6 +977,9 @@ async function applyAutomations(api, localAutomations) {
|
|
|
962
977
|
description: automation.description,
|
|
963
978
|
code
|
|
964
979
|
};
|
|
980
|
+
if (projectId) {
|
|
981
|
+
payload.project_id = projectId;
|
|
982
|
+
}
|
|
965
983
|
if (automation.inputs?.schema) {
|
|
966
984
|
payload.input_schema = automation.inputs.schema;
|
|
967
985
|
}
|
|
@@ -976,15 +994,27 @@ async function applyAutomations(api, localAutomations) {
|
|
|
976
994
|
automationId = created.id;
|
|
977
995
|
console.log(pc.green(" \u2713"), `${automation.name} (created)`);
|
|
978
996
|
}
|
|
979
|
-
|
|
980
|
-
|
|
997
|
+
const localPresets = automation.inputs?.presets;
|
|
998
|
+
if (localPresets) {
|
|
999
|
+
await syncPresets(api, automationId, localPresets);
|
|
981
1000
|
}
|
|
982
1001
|
if (automation.schedule) {
|
|
983
|
-
await setSchedule(api, automationId, automation.schedule,
|
|
1002
|
+
await setSchedule(api, automationId, automation.schedule, localPresets || {});
|
|
984
1003
|
} else if (remote?.schedule) {
|
|
985
1004
|
await api.updateAutomation(automationId, { schedule: "", schedule_tz: "" });
|
|
986
1005
|
console.log(pc.dim(` Cleared schedule`));
|
|
987
1006
|
}
|
|
1007
|
+
if (localPresets) {
|
|
1008
|
+
const current = await api.getAutomation(automationId).catch(() => null);
|
|
1009
|
+
if (current) {
|
|
1010
|
+
await deleteStalePresets(
|
|
1011
|
+
api,
|
|
1012
|
+
automationId,
|
|
1013
|
+
localPresets,
|
|
1014
|
+
current.schedule_preset_id ? /* @__PURE__ */ new Set([current.schedule_preset_id]) : /* @__PURE__ */ new Set()
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
988
1018
|
} catch (e) {
|
|
989
1019
|
console.log(pc.red(" \u2717"), `${automation.name}: ${e}`);
|
|
990
1020
|
errors++;
|
|
@@ -995,9 +1025,6 @@ async function applyAutomations(api, localAutomations) {
|
|
|
995
1025
|
async function syncPresets(api, automationId, localPresets) {
|
|
996
1026
|
const remotePresets = await api.listPresets(automationId);
|
|
997
1027
|
const remoteByName = new Map(remotePresets.map((p) => [p.name, p]));
|
|
998
|
-
const localPresetNames = new Set(
|
|
999
|
-
Object.entries(localPresets).map(([key, preset]) => preset.label || key)
|
|
1000
|
-
);
|
|
1001
1028
|
for (const [presetKey, preset] of Object.entries(localPresets)) {
|
|
1002
1029
|
const presetName = preset.label || presetKey;
|
|
1003
1030
|
const existing = remoteByName.get(presetName);
|
|
@@ -1013,14 +1040,21 @@ async function syncPresets(api, automationId, localPresets) {
|
|
|
1013
1040
|
console.log(pc.yellow(` \u26A0 Failed to sync preset ${presetName}: ${e}`));
|
|
1014
1041
|
}
|
|
1015
1042
|
}
|
|
1043
|
+
}
|
|
1044
|
+
async function deleteStalePresets(api, automationId, localPresets, preservePresetIds = /* @__PURE__ */ new Set()) {
|
|
1045
|
+
const remotePresets = await api.listPresets(automationId);
|
|
1046
|
+
const localPresetNames = new Set(
|
|
1047
|
+
Object.entries(localPresets).map(([key, preset]) => preset.label || key)
|
|
1048
|
+
);
|
|
1016
1049
|
for (const remote of remotePresets) {
|
|
1017
|
-
if (
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1050
|
+
if (localPresetNames.has(remote.name) || preservePresetIds.has(remote.id)) {
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
try {
|
|
1054
|
+
await api.deletePreset(remote.id);
|
|
1055
|
+
console.log(pc.dim(` Deleted preset: ${remote.name}`));
|
|
1056
|
+
} catch (e) {
|
|
1057
|
+
console.log(pc.yellow(` \u26A0 Failed to delete preset ${remote.name}: ${e}`));
|
|
1024
1058
|
}
|
|
1025
1059
|
}
|
|
1026
1060
|
}
|
|
@@ -1043,7 +1077,7 @@ async function setSchedule(api, automationId, schedule, localPresets) {
|
|
|
1043
1077
|
console.log(pc.yellow(` \u26A0 Failed to set schedule: ${e}`));
|
|
1044
1078
|
}
|
|
1045
1079
|
}
|
|
1046
|
-
async function applyHooks(api, localHooks, collections) {
|
|
1080
|
+
async function applyHooks(api, localHooks, collections, projectId) {
|
|
1047
1081
|
let errors = 0;
|
|
1048
1082
|
const remoteHooks = await api.listHooks();
|
|
1049
1083
|
const remoteByExternalId = new Map(remoteHooks.filter((h) => h.external_id).map((h) => [h.external_id, h]));
|
|
@@ -1064,6 +1098,9 @@ async function applyHooks(api, localHooks, collections) {
|
|
|
1064
1098
|
enabled: hook.enabled !== false,
|
|
1065
1099
|
metadata: hook.metadata
|
|
1066
1100
|
};
|
|
1101
|
+
if (projectId) {
|
|
1102
|
+
payload.project_id = projectId;
|
|
1103
|
+
}
|
|
1067
1104
|
try {
|
|
1068
1105
|
if (remote) {
|
|
1069
1106
|
await api.updateHook(remote.id, payload);
|
|
@@ -1099,18 +1136,23 @@ async function applyApp(args) {
|
|
|
1099
1136
|
const distDir = resolve(projectRoot, "dist");
|
|
1100
1137
|
await deploy({ token, appName, appTitle, distDir, apiUrl });
|
|
1101
1138
|
}
|
|
1102
|
-
async function pullCollections(api, platformDir, filterName) {
|
|
1139
|
+
async function pullCollections(api, platformDir, filterName, appName) {
|
|
1103
1140
|
const collectionsDir = join(platformDir, "collections");
|
|
1104
1141
|
mkdirSync(collectionsDir, { recursive: true });
|
|
1105
1142
|
const collections = await api.listCollections();
|
|
1106
1143
|
for (const collection of collections) {
|
|
1107
1144
|
if (collection.system || collection.managed) continue;
|
|
1108
|
-
if (
|
|
1145
|
+
if (appName && collection.name.includes(NAMESPACE_SEPARATOR)) {
|
|
1146
|
+
const prefix = collection.name.split(NAMESPACE_SEPARATOR)[0];
|
|
1147
|
+
if (prefix !== sanitizeSlugForCollectionName(appName)) continue;
|
|
1148
|
+
}
|
|
1149
|
+
const localName = stripNamespacePrefix(collection.name, appName);
|
|
1150
|
+
if (filterName && localName !== filterName && collection.name !== filterName && collection.id !== filterName) {
|
|
1109
1151
|
continue;
|
|
1110
1152
|
}
|
|
1111
1153
|
const localFormat = {
|
|
1112
1154
|
id: collection.id,
|
|
1113
|
-
name:
|
|
1155
|
+
name: localName,
|
|
1114
1156
|
fields: collection.schema.map((field) => {
|
|
1115
1157
|
const localField = {
|
|
1116
1158
|
name: field.name,
|
|
@@ -1132,18 +1174,20 @@ async function pullCollections(api, platformDir, filterName) {
|
|
|
1132
1174
|
return null;
|
|
1133
1175
|
}).filter((idx) => idx !== null)
|
|
1134
1176
|
};
|
|
1135
|
-
const fileName = toSafeFilename(
|
|
1177
|
+
const fileName = toSafeFilename(localName);
|
|
1136
1178
|
const filePath = join(collectionsDir, `${fileName}.json`);
|
|
1137
1179
|
writeFileSync(filePath, JSON.stringify(localFormat, null, 2) + "\n");
|
|
1138
|
-
console.log(pc.green(" \u2713"), `${
|
|
1180
|
+
console.log(pc.green(" \u2713"), `${localName} \u2192 collections/${fileName}.json`);
|
|
1139
1181
|
}
|
|
1140
1182
|
}
|
|
1141
|
-
async function pullAutomations(api, platformDir, filterName) {
|
|
1183
|
+
async function pullAutomations(api, platformDir, filterName, projectId) {
|
|
1142
1184
|
const automationsDir = join(platformDir, "automations");
|
|
1143
1185
|
mkdirSync(automationsDir, { recursive: true });
|
|
1144
1186
|
const automations = await api.listAutomations({ include_code: true });
|
|
1145
1187
|
for (const automation of automations) {
|
|
1146
1188
|
if (!automation.external_id || automation.managed) continue;
|
|
1189
|
+
if (projectId && automation.project_id && automation.project_id !== projectId) continue;
|
|
1190
|
+
if (!projectId && automation.project_id) continue;
|
|
1147
1191
|
if (filterName && automation.external_id !== filterName && automation.name !== filterName) {
|
|
1148
1192
|
continue;
|
|
1149
1193
|
}
|
|
@@ -1186,19 +1230,21 @@ async function pullAutomations(api, platformDir, filterName) {
|
|
|
1186
1230
|
console.log(pc.green(" \u2713"), `${automation.name} \u2192 automations/${dirName}/`);
|
|
1187
1231
|
}
|
|
1188
1232
|
}
|
|
1189
|
-
async function pullHooks(api, platformDir, filterName) {
|
|
1233
|
+
async function pullHooks(api, platformDir, filterName, appName, projectId) {
|
|
1190
1234
|
const hooksDir = join(platformDir, "hooks");
|
|
1191
1235
|
mkdirSync(hooksDir, { recursive: true });
|
|
1192
1236
|
const hooks = await api.listHooks();
|
|
1193
1237
|
for (const hook of hooks) {
|
|
1194
1238
|
if (!hook.external_id) continue;
|
|
1239
|
+
if (projectId && hook.project_id && hook.project_id !== projectId) continue;
|
|
1240
|
+
if (!projectId && hook.project_id) continue;
|
|
1195
1241
|
if (filterName && hook.external_id !== filterName) {
|
|
1196
1242
|
continue;
|
|
1197
1243
|
}
|
|
1198
1244
|
const fileName = `${hook.external_id.replace(/[^a-zA-Z0-9_-]/g, "_")}.js`;
|
|
1199
1245
|
const content = `export const config = {
|
|
1200
1246
|
external_id: '${hook.external_id}',
|
|
1201
|
-
collection: '${hook.collection_name}',
|
|
1247
|
+
collection: '${stripNamespacePrefix(hook.collection_name, appName)}',
|
|
1202
1248
|
trigger: '${hook.event}',
|
|
1203
1249
|
enabled: ${hook.enabled},
|
|
1204
1250
|
};
|
|
@@ -1417,7 +1463,7 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
|
|
|
1417
1463
|
if (!filterType || filterType === "collections") {
|
|
1418
1464
|
const localCollections = loadLocalCollections(platformDir);
|
|
1419
1465
|
const remoteCollections = await api.listCollections();
|
|
1420
|
-
const remoteByName = new Map(remoteCollections.filter((c) => !c.system && !c.managed).map((c) => [c.name, c]));
|
|
1466
|
+
const remoteByName = new Map(remoteCollections.filter((c) => !c.system && !c.managed).map((c) => [stripNamespacePrefix(c.name, appName), c]));
|
|
1421
1467
|
const localNames = new Set(localCollections.map((c) => c.name));
|
|
1422
1468
|
for (const local of localCollections) {
|
|
1423
1469
|
const remote = remoteByName.get(local.name);
|
|
@@ -1440,8 +1486,13 @@ async function listResources(api, platformDir, filterType, appName, projectId) {
|
|
|
1440
1486
|
}
|
|
1441
1487
|
for (const remote of remoteCollections) {
|
|
1442
1488
|
if (remote.system || remote.managed) continue;
|
|
1443
|
-
if (
|
|
1444
|
-
|
|
1489
|
+
if (appName && remote.name.includes(NAMESPACE_SEPARATOR)) {
|
|
1490
|
+
const prefix = remote.name.split(NAMESPACE_SEPARATOR)[0];
|
|
1491
|
+
if (prefix !== sanitizeSlugForCollectionName(appName)) continue;
|
|
1492
|
+
}
|
|
1493
|
+
const stripped = stripNamespacePrefix(remote.name, appName);
|
|
1494
|
+
if (!localNames.has(stripped)) {
|
|
1495
|
+
results.push({ name: stripped, type: "collections", status: "remote-only" });
|
|
1445
1496
|
}
|
|
1446
1497
|
}
|
|
1447
1498
|
}
|
|
@@ -1965,8 +2016,8 @@ async function plan(args) {
|
|
|
1965
2016
|
const projectRoot = findProjectRoot();
|
|
1966
2017
|
loadEnv(projectRoot);
|
|
1967
2018
|
const platformDir = getPlatformDir();
|
|
1968
|
-
const api = createApiClient();
|
|
1969
2019
|
const appName = getAppName(projectRoot);
|
|
2020
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
1970
2021
|
const projectId = getProjectId(projectRoot);
|
|
1971
2022
|
const positionalArgs = args.filter((a) => !a.startsWith("-"));
|
|
1972
2023
|
const { type, name } = parseResource(positionalArgs[0]);
|
|
@@ -1974,6 +2025,7 @@ async function plan(args) {
|
|
|
1974
2025
|
console.log(pc.cyan(pc.bold(" Plan")));
|
|
1975
2026
|
console.log(pc.dim(" Comparing local files to remote state..."));
|
|
1976
2027
|
console.log();
|
|
2028
|
+
await syncDeps(projectRoot);
|
|
1977
2029
|
const allChanges = [];
|
|
1978
2030
|
let collections;
|
|
1979
2031
|
try {
|
|
@@ -2063,8 +2115,8 @@ async function apply(args) {
|
|
|
2063
2115
|
const projectRoot = findProjectRoot();
|
|
2064
2116
|
loadEnv(projectRoot);
|
|
2065
2117
|
const platformDir = getPlatformDir();
|
|
2066
|
-
const api = createApiClient();
|
|
2067
2118
|
const appName = getAppName(projectRoot);
|
|
2119
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2068
2120
|
const projectId = getProjectId(projectRoot);
|
|
2069
2121
|
const positionalArgs = args.filter((a) => !a.startsWith("-"));
|
|
2070
2122
|
const { type, name } = parseResource(positionalArgs[0]);
|
|
@@ -2080,6 +2132,7 @@ async function apply(args) {
|
|
|
2080
2132
|
console.log();
|
|
2081
2133
|
return;
|
|
2082
2134
|
}
|
|
2135
|
+
await syncDeps(projectRoot);
|
|
2083
2136
|
let collections;
|
|
2084
2137
|
try {
|
|
2085
2138
|
const remoteCollections = await api.listCollections();
|
|
@@ -2176,12 +2229,12 @@ async function apply(args) {
|
|
|
2176
2229
|
}
|
|
2177
2230
|
if (localAutomations.length > 0) {
|
|
2178
2231
|
console.log(pc.bold(" Automations:"));
|
|
2179
|
-
totalErrors += await applyAutomations(api, localAutomations);
|
|
2232
|
+
totalErrors += await applyAutomations(api, localAutomations, projectId);
|
|
2180
2233
|
console.log();
|
|
2181
2234
|
}
|
|
2182
2235
|
if (localHooks.length > 0) {
|
|
2183
2236
|
console.log(pc.bold(" Hooks:"));
|
|
2184
|
-
totalErrors += await applyHooks(api, localHooks, collections);
|
|
2237
|
+
totalErrors += await applyHooks(api, localHooks, collections, projectId);
|
|
2185
2238
|
console.log();
|
|
2186
2239
|
}
|
|
2187
2240
|
if (localAgents.length > 0) {
|
|
@@ -2218,8 +2271,8 @@ async function pull(args) {
|
|
|
2218
2271
|
const projectRoot = findProjectRoot();
|
|
2219
2272
|
loadEnv(projectRoot);
|
|
2220
2273
|
const platformDir = getPlatformDir();
|
|
2221
|
-
const api = createApiClient();
|
|
2222
2274
|
const appName = getAppName(projectRoot);
|
|
2275
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2223
2276
|
const projectId = getProjectId(projectRoot);
|
|
2224
2277
|
const { type, name } = parseResource(filteredArgs[0]);
|
|
2225
2278
|
if (!force) {
|
|
@@ -2277,17 +2330,17 @@ async function pull(args) {
|
|
|
2277
2330
|
console.log();
|
|
2278
2331
|
if (!type || type === "collections") {
|
|
2279
2332
|
console.log(pc.bold(" Collections:"));
|
|
2280
|
-
await pullCollections(api, platformDir, name || void 0);
|
|
2333
|
+
await pullCollections(api, platformDir, name || void 0, appName);
|
|
2281
2334
|
console.log();
|
|
2282
2335
|
}
|
|
2283
2336
|
if (!type || type === "automations") {
|
|
2284
2337
|
console.log(pc.bold(" Automations:"));
|
|
2285
|
-
await pullAutomations(api, platformDir, name || void 0);
|
|
2338
|
+
await pullAutomations(api, platformDir, name || void 0, projectId);
|
|
2286
2339
|
console.log();
|
|
2287
2340
|
}
|
|
2288
2341
|
if (!type || type === "hooks") {
|
|
2289
2342
|
console.log(pc.bold(" Hooks:"));
|
|
2290
|
-
await pullHooks(api, platformDir, name || void 0);
|
|
2343
|
+
await pullHooks(api, platformDir, name || void 0, appName, projectId);
|
|
2291
2344
|
console.log();
|
|
2292
2345
|
}
|
|
2293
2346
|
if (!type || type === "agents") {
|
|
@@ -2306,8 +2359,8 @@ async function destroy(args) {
|
|
|
2306
2359
|
const projectRoot = findProjectRoot();
|
|
2307
2360
|
loadEnv(projectRoot);
|
|
2308
2361
|
const platformDir = getPlatformDir();
|
|
2309
|
-
const api = createApiClient();
|
|
2310
2362
|
const appName = getAppName(projectRoot);
|
|
2363
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2311
2364
|
const projectId = getProjectId(projectRoot);
|
|
2312
2365
|
const { type, name } = parseResource(args[0]);
|
|
2313
2366
|
const skipConfirm = args.includes("--confirm");
|
|
@@ -2330,8 +2383,8 @@ async function list(args) {
|
|
|
2330
2383
|
const projectRoot = findProjectRoot();
|
|
2331
2384
|
loadEnv(projectRoot);
|
|
2332
2385
|
const platformDir = getPlatformDir();
|
|
2333
|
-
const api = createApiClient();
|
|
2334
2386
|
const appName = getAppName(projectRoot);
|
|
2387
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2335
2388
|
const projectId = getProjectId(projectRoot);
|
|
2336
2389
|
const showAll = args.includes("--all");
|
|
2337
2390
|
const positionalArgs = args.filter((a) => !a.startsWith("--"));
|
|
@@ -2411,8 +2464,8 @@ async function show(args) {
|
|
|
2411
2464
|
const projectRoot = findProjectRoot();
|
|
2412
2465
|
loadEnv(projectRoot);
|
|
2413
2466
|
const platformDir = getPlatformDir();
|
|
2414
|
-
const api = createApiClient();
|
|
2415
2467
|
const appName = getAppName(projectRoot);
|
|
2468
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2416
2469
|
const projectId = getProjectId(projectRoot);
|
|
2417
2470
|
const { type, name } = parseResource(args[0]);
|
|
2418
2471
|
if (!type) {
|
|
@@ -2471,8 +2524,8 @@ async function diff(args) {
|
|
|
2471
2524
|
const projectRoot = findProjectRoot();
|
|
2472
2525
|
loadEnv(projectRoot);
|
|
2473
2526
|
const platformDir = getPlatformDir();
|
|
2474
|
-
const api = createApiClient();
|
|
2475
2527
|
const appName = getAppName(projectRoot);
|
|
2528
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
2476
2529
|
const projectId = getProjectId(projectRoot);
|
|
2477
2530
|
const { type, name } = parseResource(args[0]);
|
|
2478
2531
|
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);
|