@lumerahq/cli 0.18.7 → 0.18.9
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-KFXSNCJB.js → auth-PDTSQN7X.js} +4 -1
- package/dist/{chunk-EOLZMVP4.js → chunk-5EBNGMIE.js} +5 -1
- package/dist/{chunk-W4XQ5TKC.js → chunk-CCP66T22.js} +59 -20
- package/dist/chunk-FJFIWC7G.js +76 -0
- package/dist/{chunk-CHRKCAIZ.js → chunk-OQW5E7UT.js} +7 -3
- package/dist/{chunk-XZ7NOH3I.js → chunk-P44XM3FB.js} +1 -1
- package/dist/{chunk-XGRLKWQK.js → chunk-VWC6RXDA.js} +40 -20
- package/dist/{deps-W2GKWZCE.js → deps-AWWIUASS.js} +3 -2
- package/dist/{dev-EIRGA6Q3.js → dev-VONB7YDG.js} +3 -2
- package/dist/index.js +22 -19
- package/dist/{init-H5SGETMU.js → init-ZKG24YZH.js} +4 -3
- package/dist/{register-U3FGAQ5R.js → register-FRH5EDMD.js} +2 -1
- package/dist/{resources-BSYX7YJ5.js → resources-DQBSDWYG.js} +27 -6
- package/dist/{run-Z6TVKQPV.js → run-RT6ZCUWC.js} +14 -5
- package/dist/{skills-VY42VAXX.js → skills-YWYBMOVO.js} +27 -11
- package/dist/{status-EW5I7QAU.js → status-LP73L4IV.js} +4 -1
- package/dist/{templates-ESFQ4QO4.js → templates-M3RDNDDY.js} +2 -1
- package/package.json +1 -1
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
getTokenSource,
|
|
5
5
|
init_auth
|
|
6
6
|
} from "./chunk-ZH3NVYEQ.js";
|
|
7
|
+
import {
|
|
8
|
+
fetchWithRetry
|
|
9
|
+
} from "./chunk-FJFIWC7G.js";
|
|
7
10
|
import "./chunk-PNKVD2UK.js";
|
|
8
11
|
|
|
9
12
|
// src/commands/auth.ts
|
|
@@ -47,7 +50,7 @@ async function findAvailablePort(startPort) {
|
|
|
47
50
|
async function fetchUserInfo(token) {
|
|
48
51
|
const baseUrl = getBaseUrl();
|
|
49
52
|
try {
|
|
50
|
-
const response = await
|
|
53
|
+
const response = await fetchWithRetry(`${baseUrl}/api/me`, {
|
|
51
54
|
headers: {
|
|
52
55
|
Authorization: `Bearer ${token}`
|
|
53
56
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fetchWithRetry
|
|
3
|
+
} from "./chunk-FJFIWC7G.js";
|
|
4
|
+
|
|
1
5
|
// src/lib/deploy.ts
|
|
2
6
|
import { execSync, spawn } from "child_process";
|
|
3
7
|
import { createConnection } from "net";
|
|
@@ -47,7 +51,7 @@ async function createTarball(distDir) {
|
|
|
47
51
|
}
|
|
48
52
|
async function ensureAppRecord(apiBase, token, appName, appTitle) {
|
|
49
53
|
const filterParam = encodeURIComponent(JSON.stringify({ external_id: appName }));
|
|
50
|
-
const searchRes = await
|
|
54
|
+
const searchRes = await fetchWithRetry(
|
|
51
55
|
`${apiBase}/pb/collections/lm_custom_apps/records?filter=${filterParam}`,
|
|
52
56
|
{ headers: { Authorization: `Bearer ${token}` } }
|
|
53
57
|
);
|
|
@@ -1,25 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getBaseUrl
|
|
3
3
|
} from "./chunk-ZH3NVYEQ.js";
|
|
4
|
+
import {
|
|
5
|
+
fetchWithRetry
|
|
6
|
+
} from "./chunk-FJFIWC7G.js";
|
|
4
7
|
|
|
5
8
|
// src/lib/skills.ts
|
|
6
9
|
import { createHash } from "crypto";
|
|
7
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, symlinkSync, lstatSync, writeFileSync } from "fs";
|
|
10
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, symlinkSync, lstatSync, statSync, writeFileSync } from "fs";
|
|
8
11
|
import { join, relative } from "path";
|
|
9
12
|
import pc from "picocolors";
|
|
13
|
+
function slugToDirName(slug) {
|
|
14
|
+
return slug.replace(/-/g, "_");
|
|
15
|
+
}
|
|
16
|
+
function dirNameToSlug(dirName) {
|
|
17
|
+
return dirName.replace(/_/g, "-");
|
|
18
|
+
}
|
|
10
19
|
function slugToFilename(slug) {
|
|
11
20
|
return `${slug.replace(/-/g, "_")}.md`;
|
|
12
21
|
}
|
|
13
|
-
function filenameToSlug(filename) {
|
|
14
|
-
return filename.replace(/\.md$/, "").replace(/_/g, "-");
|
|
15
|
-
}
|
|
16
22
|
function hashContent(content) {
|
|
17
23
|
return createHash("md5").update(content).digest("hex");
|
|
18
24
|
}
|
|
19
25
|
async function fetchSkillsList() {
|
|
20
26
|
const baseUrl = getBaseUrl();
|
|
21
27
|
const skillsApiUrl = `${baseUrl}/api/public/skills`;
|
|
22
|
-
const listRes = await
|
|
28
|
+
const listRes = await fetchWithRetry(skillsApiUrl);
|
|
23
29
|
if (!listRes.ok) {
|
|
24
30
|
throw new Error(`Failed to fetch skills list: ${listRes.status}`);
|
|
25
31
|
}
|
|
@@ -28,7 +34,7 @@ async function fetchSkillsList() {
|
|
|
28
34
|
async function fetchSkillContent(slug) {
|
|
29
35
|
const baseUrl = getBaseUrl();
|
|
30
36
|
const skillsApiUrl = `${baseUrl}/api/public/skills`;
|
|
31
|
-
const mdRes = await
|
|
37
|
+
const mdRes = await fetchWithRetry(`${skillsApiUrl}/${slug}.md`);
|
|
32
38
|
if (!mdRes.ok) {
|
|
33
39
|
return null;
|
|
34
40
|
}
|
|
@@ -39,11 +45,26 @@ function getLocalSkills(skillsDir) {
|
|
|
39
45
|
if (!existsSync(skillsDir)) {
|
|
40
46
|
return localSkills;
|
|
41
47
|
}
|
|
42
|
-
for (const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
for (const entry of readdirSync(skillsDir)) {
|
|
49
|
+
const fullPath = join(skillsDir, entry);
|
|
50
|
+
const skillFile = join(fullPath, "SKILL.md");
|
|
51
|
+
if (existsSync(skillFile)) {
|
|
52
|
+
try {
|
|
53
|
+
if (statSync(fullPath).isDirectory()) {
|
|
54
|
+
const content = readFileSync(skillFile, "utf-8");
|
|
55
|
+
const slug = dirNameToSlug(entry);
|
|
56
|
+
localSkills.set(slug, hashContent(content));
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (entry.endsWith(".md")) {
|
|
63
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
64
|
+
const slug = entry.replace(/\.md$/, "").replace(/_/g, "-");
|
|
65
|
+
if (!localSkills.has(slug)) {
|
|
66
|
+
localSkills.set(slug, hashContent(content));
|
|
67
|
+
}
|
|
47
68
|
}
|
|
48
69
|
}
|
|
49
70
|
return localSkills;
|
|
@@ -115,10 +136,12 @@ async function installAllSkills(targetDir, options) {
|
|
|
115
136
|
for (const result of results) {
|
|
116
137
|
if (result.status === "fulfilled" && result.value.content) {
|
|
117
138
|
const { skill, content } = result.value;
|
|
118
|
-
const
|
|
119
|
-
|
|
139
|
+
const dirName = slugToDirName(skill.slug);
|
|
140
|
+
const skillDir = join(skillsDir, dirName);
|
|
141
|
+
mkdirSync(skillDir, { recursive: true });
|
|
142
|
+
writeFileSync(join(skillDir, "SKILL.md"), content);
|
|
120
143
|
if (verbose) {
|
|
121
|
-
console.log(pc.green(" \u2713"), pc.dim(
|
|
144
|
+
console.log(pc.green(" \u2713"), pc.dim(`${dirName}/SKILL.md`));
|
|
122
145
|
}
|
|
123
146
|
installed++;
|
|
124
147
|
} else {
|
|
@@ -149,12 +172,27 @@ function syncClaudeMd(projectRoot) {
|
|
|
149
172
|
}
|
|
150
173
|
const skillEntries = [];
|
|
151
174
|
if (existsSync(skillsDir)) {
|
|
152
|
-
for (const
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
175
|
+
for (const entry of readdirSync(skillsDir).sort()) {
|
|
176
|
+
const fullPath = join(skillsDir, entry);
|
|
177
|
+
const skillFile = join(fullPath, "SKILL.md");
|
|
178
|
+
if (existsSync(skillFile)) {
|
|
179
|
+
try {
|
|
180
|
+
if (statSync(fullPath).isDirectory()) {
|
|
181
|
+
const content = readFileSync(skillFile, "utf-8");
|
|
182
|
+
const { title, summary } = parseSkillSummary(content);
|
|
183
|
+
const slug = dirNameToSlug(entry);
|
|
184
|
+
skillEntries.push({ slug, title, summary });
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
} catch {
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (entry.endsWith(".md")) {
|
|
191
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
192
|
+
const { title, summary } = parseSkillSummary(content);
|
|
193
|
+
const slug = entry.replace(/\.md$/, "").replace(/_/g, "-");
|
|
194
|
+
skillEntries.push({ slug, title, summary });
|
|
195
|
+
}
|
|
158
196
|
}
|
|
159
197
|
}
|
|
160
198
|
let generated;
|
|
@@ -172,6 +210,7 @@ ${after}`;
|
|
|
172
210
|
}
|
|
173
211
|
|
|
174
212
|
export {
|
|
213
|
+
slugToDirName,
|
|
175
214
|
slugToFilename,
|
|
176
215
|
hashContent,
|
|
177
216
|
fetchSkillsList,
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// src/lib/http.ts
|
|
2
|
+
var DEFAULT_RETRY_STATUSES = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
3
|
+
var DEFAULT_RETRY_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
4
|
+
function requestMethod(input, init) {
|
|
5
|
+
const method = init?.method || (input instanceof Request ? input.method : "GET");
|
|
6
|
+
return method.toUpperCase();
|
|
7
|
+
}
|
|
8
|
+
function shouldRetryMethod(method, retryMethods) {
|
|
9
|
+
const allowed = new Set((retryMethods || Array.from(DEFAULT_RETRY_METHODS)).map((value) => value.toUpperCase()));
|
|
10
|
+
return allowed.has(method);
|
|
11
|
+
}
|
|
12
|
+
function shouldRetryStatus(status, retryStatuses) {
|
|
13
|
+
const allowed = new Set(retryStatuses || Array.from(DEFAULT_RETRY_STATUSES));
|
|
14
|
+
return allowed.has(status);
|
|
15
|
+
}
|
|
16
|
+
function isAbortError(err) {
|
|
17
|
+
return err instanceof Error && err.name === "AbortError";
|
|
18
|
+
}
|
|
19
|
+
function cloneInput(input) {
|
|
20
|
+
return input instanceof Request ? input.clone() : input;
|
|
21
|
+
}
|
|
22
|
+
function parseRetryAfter(value) {
|
|
23
|
+
if (!value) return null;
|
|
24
|
+
const seconds = Number(value);
|
|
25
|
+
if (!Number.isNaN(seconds)) {
|
|
26
|
+
return Math.max(0, seconds * 1e3);
|
|
27
|
+
}
|
|
28
|
+
const when = Date.parse(value);
|
|
29
|
+
if (!Number.isNaN(when)) {
|
|
30
|
+
return Math.max(0, when - Date.now());
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
function retryDelayMs(attempt, retryAfter) {
|
|
35
|
+
const parsed = parseRetryAfter(retryAfter);
|
|
36
|
+
if (parsed !== null) return Math.min(parsed, 3e4);
|
|
37
|
+
return Math.min(attempt * 1e3, 5e3);
|
|
38
|
+
}
|
|
39
|
+
async function waitForRetry(delayMs) {
|
|
40
|
+
if (delayMs <= 0) return;
|
|
41
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
42
|
+
}
|
|
43
|
+
async function discardResponse(response) {
|
|
44
|
+
try {
|
|
45
|
+
await response.body?.cancel();
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function fetchWithRetry(input, init = {}, options = {}) {
|
|
50
|
+
const attempts = Math.max(1, options.attempts ?? 3);
|
|
51
|
+
const method = requestMethod(input, init);
|
|
52
|
+
const retryableMethod = shouldRetryMethod(method, options.retryMethods);
|
|
53
|
+
let lastError;
|
|
54
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetch(cloneInput(input), init);
|
|
57
|
+
if (!retryableMethod || !shouldRetryStatus(response.status, options.retryStatuses) || attempt === attempts) {
|
|
58
|
+
return response;
|
|
59
|
+
}
|
|
60
|
+
await discardResponse(response);
|
|
61
|
+
await waitForRetry(retryDelayMs(attempt, response.headers.get("Retry-After")));
|
|
62
|
+
continue;
|
|
63
|
+
} catch (err) {
|
|
64
|
+
lastError = err;
|
|
65
|
+
if (!retryableMethod || isAbortError(err) || attempt === attempts) {
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
await waitForRetry(retryDelayMs(attempt, null));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
throw lastError instanceof Error ? lastError : new Error("Request failed");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
fetchWithRetry
|
|
76
|
+
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fetchWithRetry
|
|
3
|
+
} from "./chunk-FJFIWC7G.js";
|
|
4
|
+
|
|
1
5
|
// src/lib/templates.ts
|
|
2
6
|
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "fs";
|
|
3
7
|
import { homedir, tmpdir } from "os";
|
|
@@ -20,7 +24,7 @@ function readCacheMeta() {
|
|
|
20
24
|
}
|
|
21
25
|
async function fetchLatestSha() {
|
|
22
26
|
const url = `https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/commits/${GITHUB_REF}`;
|
|
23
|
-
const res = await
|
|
27
|
+
const res = await fetchWithRetry(url, {
|
|
24
28
|
headers: { Accept: "application/vnd.github.sha" }
|
|
25
29
|
});
|
|
26
30
|
if (!res.ok) throw new Error(`GitHub API error: ${res.status}`);
|
|
@@ -29,7 +33,7 @@ async function fetchLatestSha() {
|
|
|
29
33
|
async function downloadAndExtract(commitSha) {
|
|
30
34
|
const cacheDir = getCacheDir();
|
|
31
35
|
const tarballUrl = `https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/archive/refs/heads/${GITHUB_REF}.tar.gz`;
|
|
32
|
-
const res = await
|
|
36
|
+
const res = await fetchWithRetry(tarballUrl);
|
|
33
37
|
if (!res.ok) throw new Error(`Failed to download templates: ${res.status}`);
|
|
34
38
|
const tmpFile = join(tmpdir(), `lumera-templates-${Date.now()}.tar.gz`);
|
|
35
39
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
@@ -79,7 +83,7 @@ async function ensureRemoteCacheForRef(ref) {
|
|
|
79
83
|
];
|
|
80
84
|
let res = null;
|
|
81
85
|
for (const url of urls) {
|
|
82
|
-
const attempt = await
|
|
86
|
+
const attempt = await fetchWithRetry(url);
|
|
83
87
|
if (attempt.ok) {
|
|
84
88
|
res = attempt;
|
|
85
89
|
break;
|
|
@@ -2,6 +2,9 @@ import {
|
|
|
2
2
|
getToken,
|
|
3
3
|
init_auth
|
|
4
4
|
} from "./chunk-ZH3NVYEQ.js";
|
|
5
|
+
import {
|
|
6
|
+
fetchWithRetry
|
|
7
|
+
} from "./chunk-FJFIWC7G.js";
|
|
5
8
|
|
|
6
9
|
// src/lib/api.ts
|
|
7
10
|
init_auth();
|
|
@@ -44,9 +47,13 @@ var ApiClient = class {
|
|
|
44
47
|
...this.projectExternalId ? { "X-Lumera-Project": this.projectExternalId } : {},
|
|
45
48
|
...options.headers
|
|
46
49
|
};
|
|
47
|
-
const
|
|
50
|
+
const method = (options.method || "GET").toUpperCase();
|
|
51
|
+
const response = await fetchWithRetry(url, {
|
|
48
52
|
...options,
|
|
49
53
|
headers
|
|
54
|
+
}, {
|
|
55
|
+
retryMethods: ["GET", "HEAD"],
|
|
56
|
+
attempts: method === "GET" || method === "HEAD" ? 3 : 1
|
|
50
57
|
});
|
|
51
58
|
if (!response.ok) {
|
|
52
59
|
const text = await response.text();
|
|
@@ -214,30 +221,43 @@ var ApiClient = class {
|
|
|
214
221
|
// Projects — register/lookup via PocketBase records API
|
|
215
222
|
async registerProject(name, externalId) {
|
|
216
223
|
const extId = externalId || name;
|
|
217
|
-
const
|
|
218
|
-
const searchRes = await this.request(
|
|
219
|
-
`/api/pb/collections/lm_projects/records?filter=${filterParam}`
|
|
220
|
-
);
|
|
221
|
-
const existing = searchRes.items?.[0];
|
|
224
|
+
const existing = await this.getProjectByExternalId(extId);
|
|
222
225
|
if (existing) {
|
|
226
|
+
return existing;
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const rec = await this.request(
|
|
230
|
+
"/api/pb/collections/lm_projects/records",
|
|
231
|
+
{
|
|
232
|
+
method: "POST",
|
|
233
|
+
body: JSON.stringify({ name, external_id: extId })
|
|
234
|
+
}
|
|
235
|
+
);
|
|
223
236
|
return {
|
|
224
|
-
id:
|
|
225
|
-
name:
|
|
226
|
-
external_id:
|
|
227
|
-
template:
|
|
228
|
-
status:
|
|
229
|
-
owner_id:
|
|
230
|
-
created:
|
|
231
|
-
updated:
|
|
237
|
+
id: rec.id,
|
|
238
|
+
name: rec.name,
|
|
239
|
+
external_id: rec.external_id,
|
|
240
|
+
template: rec.template,
|
|
241
|
+
status: rec.status,
|
|
242
|
+
owner_id: rec.owner_id,
|
|
243
|
+
created: rec.created,
|
|
244
|
+
updated: rec.updated
|
|
232
245
|
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
method: "POST",
|
|
238
|
-
body: JSON.stringify({ name, external_id: extId })
|
|
246
|
+
} catch (error) {
|
|
247
|
+
const created = await this.getProjectByExternalId(extId);
|
|
248
|
+
if (created) {
|
|
249
|
+
return created;
|
|
239
250
|
}
|
|
251
|
+
throw error;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
async getProjectByExternalId(externalId) {
|
|
255
|
+
const filterParam = encodeURIComponent(JSON.stringify({ external_id: externalId }));
|
|
256
|
+
const res = await this.request(
|
|
257
|
+
`/api/pb/collections/lm_projects/records?filter=${filterParam}`
|
|
240
258
|
);
|
|
259
|
+
const rec = res.items?.[0];
|
|
260
|
+
if (!rec) return null;
|
|
241
261
|
return {
|
|
242
262
|
id: rec.id,
|
|
243
263
|
name: rec.name,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deps,
|
|
3
3
|
syncDeps
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-P44XM3FB.js";
|
|
5
5
|
import "./chunk-2CR762KB.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-VWC6RXDA.js";
|
|
7
7
|
import "./chunk-ZH3NVYEQ.js";
|
|
8
|
+
import "./chunk-FJFIWC7G.js";
|
|
8
9
|
import "./chunk-PNKVD2UK.js";
|
|
9
10
|
export {
|
|
10
11
|
deps,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dev
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5EBNGMIE.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-VWC6RXDA.js";
|
|
10
10
|
import {
|
|
11
11
|
findProjectRoot,
|
|
12
12
|
getApiUrl,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
getToken,
|
|
16
16
|
init_auth
|
|
17
17
|
} from "./chunk-ZH3NVYEQ.js";
|
|
18
|
+
import "./chunk-FJFIWC7G.js";
|
|
18
19
|
import "./chunk-PNKVD2UK.js";
|
|
19
20
|
|
|
20
21
|
// src/commands/dev.ts
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
fetchWithRetry
|
|
4
|
+
} from "./chunk-FJFIWC7G.js";
|
|
2
5
|
import "./chunk-PNKVD2UK.js";
|
|
3
6
|
|
|
4
7
|
// src/index.ts
|
|
@@ -51,7 +54,7 @@ async function checkForUpdate(currentVersion) {
|
|
|
51
54
|
return null;
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
|
-
const res = await
|
|
57
|
+
const res = await fetchWithRetry("https://registry.npmjs.org/@lumerahq/cli/latest");
|
|
55
58
|
if (!res.ok) return null;
|
|
56
59
|
const data = await res.json();
|
|
57
60
|
const latest = data.version;
|
|
@@ -216,66 +219,66 @@ async function main() {
|
|
|
216
219
|
switch (command) {
|
|
217
220
|
// Resource commands
|
|
218
221
|
case "plan":
|
|
219
|
-
await import("./resources-
|
|
222
|
+
await import("./resources-DQBSDWYG.js").then((m) => m.plan(args.slice(1)));
|
|
220
223
|
break;
|
|
221
224
|
case "apply":
|
|
222
|
-
await import("./resources-
|
|
225
|
+
await import("./resources-DQBSDWYG.js").then((m) => m.apply(args.slice(1)));
|
|
223
226
|
break;
|
|
224
227
|
case "pull":
|
|
225
|
-
await import("./resources-
|
|
228
|
+
await import("./resources-DQBSDWYG.js").then((m) => m.pull(args.slice(1)));
|
|
226
229
|
break;
|
|
227
230
|
case "destroy":
|
|
228
|
-
await import("./resources-
|
|
231
|
+
await import("./resources-DQBSDWYG.js").then((m) => m.destroy(args.slice(1)));
|
|
229
232
|
break;
|
|
230
233
|
case "list":
|
|
231
|
-
await import("./resources-
|
|
234
|
+
await import("./resources-DQBSDWYG.js").then((m) => m.list(args.slice(1)));
|
|
232
235
|
break;
|
|
233
236
|
case "show":
|
|
234
|
-
await import("./resources-
|
|
237
|
+
await import("./resources-DQBSDWYG.js").then((m) => m.show(args.slice(1)));
|
|
235
238
|
break;
|
|
236
239
|
case "diff":
|
|
237
|
-
await import("./resources-
|
|
240
|
+
await import("./resources-DQBSDWYG.js").then((m) => m.diff(args.slice(1)));
|
|
238
241
|
break;
|
|
239
242
|
// Development
|
|
240
243
|
case "dev":
|
|
241
|
-
await import("./dev-
|
|
244
|
+
await import("./dev-VONB7YDG.js").then((m) => m.dev(args.slice(1)));
|
|
242
245
|
break;
|
|
243
246
|
case "run":
|
|
244
|
-
await import("./run-
|
|
247
|
+
await import("./run-RT6ZCUWC.js").then((m) => m.run(args.slice(1)));
|
|
245
248
|
break;
|
|
246
249
|
// Project
|
|
247
250
|
case "init":
|
|
248
|
-
await import("./init-
|
|
251
|
+
await import("./init-ZKG24YZH.js").then((m) => m.init(args.slice(1)));
|
|
249
252
|
break;
|
|
250
253
|
case "register":
|
|
251
|
-
await import("./register-
|
|
254
|
+
await import("./register-FRH5EDMD.js").then((m) => m.register(args.slice(1)));
|
|
252
255
|
break;
|
|
253
256
|
case "templates":
|
|
254
|
-
await import("./templates-
|
|
257
|
+
await import("./templates-M3RDNDDY.js").then((m) => m.templates(subcommand, args.slice(2)));
|
|
255
258
|
break;
|
|
256
259
|
case "status":
|
|
257
|
-
await import("./status-
|
|
260
|
+
await import("./status-LP73L4IV.js").then((m) => m.status(args.slice(1)));
|
|
258
261
|
break;
|
|
259
262
|
case "migrate":
|
|
260
263
|
await import("./migrate-NCZKP7FM.js").then((m) => m.migrate(args.slice(1)));
|
|
261
264
|
break;
|
|
262
265
|
// Skills
|
|
263
266
|
case "skills":
|
|
264
|
-
await import("./skills-
|
|
267
|
+
await import("./skills-YWYBMOVO.js").then((m) => m.skills(subcommand, args.slice(2)));
|
|
265
268
|
break;
|
|
266
269
|
// Dependencies
|
|
267
270
|
case "deps":
|
|
268
|
-
await import("./deps-
|
|
271
|
+
await import("./deps-AWWIUASS.js").then((m) => m.deps(args.slice(1)));
|
|
269
272
|
break;
|
|
270
273
|
// Auth
|
|
271
274
|
case "login":
|
|
272
|
-
await import("./auth-
|
|
275
|
+
await import("./auth-PDTSQN7X.js").then((m) => m.login(args.slice(1)));
|
|
273
276
|
break;
|
|
274
277
|
case "logout":
|
|
275
|
-
await import("./auth-
|
|
278
|
+
await import("./auth-PDTSQN7X.js").then((m) => m.logout(args.slice(1)));
|
|
276
279
|
break;
|
|
277
280
|
case "whoami":
|
|
278
|
-
await import("./auth-
|
|
281
|
+
await import("./auth-PDTSQN7X.js").then((m) => m.whoami());
|
|
279
282
|
break;
|
|
280
283
|
// Convenience aliases
|
|
281
284
|
case "help":
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
installAllSkills,
|
|
3
3
|
syncClaudeMd
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-CCP66T22.js";
|
|
5
5
|
import {
|
|
6
6
|
spinner
|
|
7
7
|
} from "./chunk-BHYDYR75.js";
|
|
8
8
|
import {
|
|
9
9
|
createApiClient
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-VWC6RXDA.js";
|
|
11
11
|
import {
|
|
12
12
|
getToken,
|
|
13
13
|
init_auth,
|
|
@@ -16,7 +16,8 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
listAllTemplates,
|
|
18
18
|
resolveTemplate
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-OQW5E7UT.js";
|
|
20
|
+
import "./chunk-FJFIWC7G.js";
|
|
20
21
|
import "./chunk-PNKVD2UK.js";
|
|
21
22
|
|
|
22
23
|
// src/commands/init.ts
|
|
@@ -6,13 +6,14 @@ import {
|
|
|
6
6
|
} from "./chunk-BHYDYR75.js";
|
|
7
7
|
import {
|
|
8
8
|
createApiClient
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VWC6RXDA.js";
|
|
10
10
|
import {
|
|
11
11
|
findProjectRoot,
|
|
12
12
|
getAppName,
|
|
13
13
|
getProjectId,
|
|
14
14
|
setProjectId
|
|
15
15
|
} from "./chunk-ZH3NVYEQ.js";
|
|
16
|
+
import "./chunk-FJFIWC7G.js";
|
|
16
17
|
import "./chunk-PNKVD2UK.js";
|
|
17
18
|
|
|
18
19
|
// src/commands/register.ts
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
syncDeps
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-P44XM3FB.js";
|
|
4
4
|
import {
|
|
5
5
|
deploy
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-5EBNGMIE.js";
|
|
7
7
|
import {
|
|
8
8
|
loadEnv
|
|
9
9
|
} from "./chunk-2CR762KB.js";
|
|
10
10
|
import {
|
|
11
11
|
createApiClient
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-VWC6RXDA.js";
|
|
13
13
|
import {
|
|
14
14
|
findProjectRoot,
|
|
15
15
|
getApiUrl,
|
|
@@ -19,6 +19,9 @@ import {
|
|
|
19
19
|
getToken,
|
|
20
20
|
init_auth
|
|
21
21
|
} from "./chunk-ZH3NVYEQ.js";
|
|
22
|
+
import {
|
|
23
|
+
fetchWithRetry
|
|
24
|
+
} from "./chunk-FJFIWC7G.js";
|
|
22
25
|
import "./chunk-PNKVD2UK.js";
|
|
23
26
|
|
|
24
27
|
// src/commands/resources.ts
|
|
@@ -1868,7 +1871,7 @@ async function destroyApp(skipConfirm) {
|
|
|
1868
1871
|
const appName = getAppName(projectRoot);
|
|
1869
1872
|
let apiUrl = getApiUrl().replace(/\/+$/, "").replace(/\/api$/, "");
|
|
1870
1873
|
const filterParam = encodeURIComponent(JSON.stringify({ external_id: appName }));
|
|
1871
|
-
const searchRes = await
|
|
1874
|
+
const searchRes = await fetchWithRetry(
|
|
1872
1875
|
`${apiUrl}/api/pb/collections/lm_custom_apps/records?filter=${filterParam}`,
|
|
1873
1876
|
{ headers: { Authorization: `Bearer ${token}` } }
|
|
1874
1877
|
);
|
|
@@ -2059,7 +2062,7 @@ async function showResource(api, platformDir, resourceType, resourceName, appNam
|
|
|
2059
2062
|
console.log();
|
|
2060
2063
|
console.log(` External ID: ${appName2}`);
|
|
2061
2064
|
const filterParam = encodeURIComponent(JSON.stringify({ external_id: appName2 }));
|
|
2062
|
-
const searchRes = await
|
|
2065
|
+
const searchRes = await fetchWithRetry(
|
|
2063
2066
|
`${apiUrl}/api/pb/collections/lm_custom_apps/records?filter=${filterParam}`,
|
|
2064
2067
|
{ headers: { Authorization: `Bearer ${token}` } }
|
|
2065
2068
|
);
|
|
@@ -2083,6 +2086,7 @@ async function plan(args) {
|
|
|
2083
2086
|
showPlanHelp();
|
|
2084
2087
|
return;
|
|
2085
2088
|
}
|
|
2089
|
+
const jsonOutput = args.includes("--json");
|
|
2086
2090
|
const projectRoot = findProjectRoot();
|
|
2087
2091
|
loadEnv(projectRoot);
|
|
2088
2092
|
const platformDir = getPlatformDir();
|
|
@@ -2090,7 +2094,7 @@ async function plan(args) {
|
|
|
2090
2094
|
const api = createApiClient(void 0, void 0, appName);
|
|
2091
2095
|
const projectId = getProjectId(projectRoot);
|
|
2092
2096
|
const positionalArgs = args.filter((a) => !a.startsWith("-"));
|
|
2093
|
-
const { type, name } = parseResource(positionalArgs[0]);
|
|
2097
|
+
const { type, name } = parseResource(positionalArgs.filter((a) => a !== "--json")[0]);
|
|
2094
2098
|
console.log();
|
|
2095
2099
|
console.log(pc.cyan(pc.bold(" Plan")));
|
|
2096
2100
|
console.log(pc.dim(" Comparing local files to remote state..."));
|
|
@@ -2133,10 +2137,27 @@ async function plan(args) {
|
|
|
2133
2137
|
}
|
|
2134
2138
|
}
|
|
2135
2139
|
if (allChanges.length === 0) {
|
|
2140
|
+
if (jsonOutput) {
|
|
2141
|
+
console.log(JSON.stringify({ changes: [], warnings: [] }));
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2136
2144
|
console.log(pc.green(" \u2713 No changes detected"));
|
|
2137
2145
|
console.log();
|
|
2138
2146
|
return;
|
|
2139
2147
|
}
|
|
2148
|
+
if (jsonOutput) {
|
|
2149
|
+
const warnings = [];
|
|
2150
|
+
for (const change of allChanges) {
|
|
2151
|
+
if (change.fieldDetails) {
|
|
2152
|
+
const removals = change.fieldDetails.filter((f) => f.action === "-");
|
|
2153
|
+
if (removals.length > 0) {
|
|
2154
|
+
warnings.push(`Collection "${change.name}" will have ${removals.length} field(s) removed.`);
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
console.log(JSON.stringify({ changes: allChanges, warnings }));
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2140
2161
|
console.log(pc.bold(" Changes:"));
|
|
2141
2162
|
console.log();
|
|
2142
2163
|
for (const change of allChanges) {
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-2CR762KB.js";
|
|
4
4
|
import {
|
|
5
5
|
createApiClient
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-VWC6RXDA.js";
|
|
7
7
|
import {
|
|
8
8
|
findProjectRoot,
|
|
9
9
|
getApiUrl,
|
|
@@ -11,10 +11,14 @@ import {
|
|
|
11
11
|
getToken,
|
|
12
12
|
init_auth
|
|
13
13
|
} from "./chunk-ZH3NVYEQ.js";
|
|
14
|
+
import {
|
|
15
|
+
fetchWithRetry
|
|
16
|
+
} from "./chunk-FJFIWC7G.js";
|
|
14
17
|
import "./chunk-PNKVD2UK.js";
|
|
15
18
|
|
|
16
19
|
// src/commands/run.ts
|
|
17
20
|
import pc from "picocolors";
|
|
21
|
+
import { randomUUID } from "crypto";
|
|
18
22
|
import { spawn } from "child_process";
|
|
19
23
|
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
20
24
|
import { resolve, extname, join } from "path";
|
|
@@ -159,17 +163,22 @@ async function triggerAutomation(automationName, projectRoot, flags) {
|
|
|
159
163
|
}
|
|
160
164
|
}
|
|
161
165
|
console.log();
|
|
162
|
-
const
|
|
166
|
+
const externalId = `lumera-cli-run-${randomUUID()}`;
|
|
167
|
+
const response = await fetchWithRetry(`${apiUrl}/api/automation-runs`, {
|
|
163
168
|
method: "POST",
|
|
164
169
|
headers: {
|
|
165
170
|
"Authorization": `Bearer ${token}`,
|
|
166
171
|
"Content-Type": "application/json"
|
|
167
172
|
},
|
|
168
173
|
body: JSON.stringify({
|
|
169
|
-
|
|
170
|
-
inputs
|
|
171
|
-
|
|
174
|
+
automation_id: automation.id,
|
|
175
|
+
inputs,
|
|
176
|
+
trigger: "manual",
|
|
177
|
+
external_id: externalId
|
|
172
178
|
})
|
|
179
|
+
}, {
|
|
180
|
+
attempts: 3,
|
|
181
|
+
retryMethods: ["POST"]
|
|
173
182
|
});
|
|
174
183
|
if (!response.ok) {
|
|
175
184
|
const error = await response.text();
|
|
@@ -5,15 +5,17 @@ import {
|
|
|
5
5
|
getLocalSkills,
|
|
6
6
|
hashContent,
|
|
7
7
|
installAllSkills,
|
|
8
|
+
slugToDirName,
|
|
8
9
|
slugToFilename,
|
|
9
10
|
syncClaudeMd
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-CCP66T22.js";
|
|
11
12
|
import "./chunk-ZH3NVYEQ.js";
|
|
13
|
+
import "./chunk-FJFIWC7G.js";
|
|
12
14
|
import "./chunk-PNKVD2UK.js";
|
|
13
15
|
|
|
14
16
|
// src/commands/skills.ts
|
|
15
17
|
import pc from "picocolors";
|
|
16
|
-
import { existsSync, readdirSync, rmSync, writeFileSync } from "fs";
|
|
18
|
+
import { existsSync, mkdirSync, readdirSync, rmSync, writeFileSync } from "fs";
|
|
17
19
|
import { join, resolve } from "path";
|
|
18
20
|
function findProjectRoot() {
|
|
19
21
|
let dir = process.cwd();
|
|
@@ -214,9 +216,12 @@ async function install(flags) {
|
|
|
214
216
|
console.log(pc.dim(` Fetching skills...`));
|
|
215
217
|
}
|
|
216
218
|
if (force && existsSync(skillsDir)) {
|
|
217
|
-
for (const
|
|
218
|
-
|
|
219
|
-
|
|
219
|
+
for (const entry of readdirSync(skillsDir)) {
|
|
220
|
+
const fullPath = join(skillsDir, entry);
|
|
221
|
+
if (entry.endsWith(".md")) {
|
|
222
|
+
rmSync(fullPath);
|
|
223
|
+
} else {
|
|
224
|
+
rmSync(fullPath, { recursive: true, force: true });
|
|
220
225
|
}
|
|
221
226
|
}
|
|
222
227
|
}
|
|
@@ -334,8 +339,14 @@ async function update(args, flags) {
|
|
|
334
339
|
for (const result of fetchResults) {
|
|
335
340
|
if (result.status !== "fulfilled" || !result.value.content) continue;
|
|
336
341
|
const { skill, content } = result.value;
|
|
337
|
-
const
|
|
338
|
-
|
|
342
|
+
const dirName = slugToDirName(skill.slug);
|
|
343
|
+
const skillDir = join(skillsDir, dirName);
|
|
344
|
+
mkdirSync(skillDir, { recursive: true });
|
|
345
|
+
writeFileSync(join(skillDir, "SKILL.md"), content);
|
|
346
|
+
const legacyFile = join(skillsDir, slugToFilename(skill.slug));
|
|
347
|
+
if (existsSync(legacyFile)) {
|
|
348
|
+
rmSync(legacyFile);
|
|
349
|
+
}
|
|
339
350
|
const isNew = diff.added.includes(skill);
|
|
340
351
|
if (isNew) {
|
|
341
352
|
console.log(pc.green(" +"), `Added ${skill.name}`);
|
|
@@ -344,12 +355,17 @@ async function update(args, flags) {
|
|
|
344
355
|
}
|
|
345
356
|
}
|
|
346
357
|
for (const slug of diff.removed) {
|
|
347
|
-
const
|
|
348
|
-
const
|
|
349
|
-
if (existsSync(
|
|
350
|
-
rmSync(
|
|
358
|
+
const dirName = slugToDirName(slug);
|
|
359
|
+
const dirPath = join(skillsDir, dirName);
|
|
360
|
+
if (existsSync(dirPath)) {
|
|
361
|
+
rmSync(dirPath, { recursive: true, force: true });
|
|
351
362
|
console.log(pc.red(" -"), `Removed ${slug}`);
|
|
352
363
|
}
|
|
364
|
+
const legacyFile = join(skillsDir, slugToFilename(slug));
|
|
365
|
+
if (existsSync(legacyFile)) {
|
|
366
|
+
rmSync(legacyFile);
|
|
367
|
+
console.log(pc.red(" -"), `Removed ${slug} (legacy)`);
|
|
368
|
+
}
|
|
353
369
|
}
|
|
354
370
|
console.log();
|
|
355
371
|
console.log(pc.green(" \u2713"), `Update complete (${changes.join(", ")})`);
|
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
init_auth,
|
|
10
10
|
readPackageJson
|
|
11
11
|
} from "./chunk-ZH3NVYEQ.js";
|
|
12
|
+
import {
|
|
13
|
+
fetchWithRetry
|
|
14
|
+
} from "./chunk-FJFIWC7G.js";
|
|
12
15
|
import "./chunk-PNKVD2UK.js";
|
|
13
16
|
|
|
14
17
|
// src/commands/status.ts
|
|
@@ -19,7 +22,7 @@ init_auth();
|
|
|
19
22
|
async function validateToken(token) {
|
|
20
23
|
const baseUrl = getBaseUrl();
|
|
21
24
|
try {
|
|
22
|
-
const response = await
|
|
25
|
+
const response = await fetchWithRetry(`${baseUrl}/api/me`, {
|
|
23
26
|
headers: { Authorization: `Bearer ${token}` }
|
|
24
27
|
});
|
|
25
28
|
if (!response.ok) {
|