@lumerahq/cli 0.19.3-dev.0 → 0.19.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/README.md +5 -3
- package/dist/chunk-H357NP7T.js +77 -0
- package/dist/{chunk-GKI2HQJC.js → chunk-JKXLKK5I.js} +14 -1
- package/dist/chunk-P5HFNAVN.js +280 -0
- package/dist/{chunk-53NOF33P.js → chunk-SU26C4GL.js} +9 -49
- package/dist/{deps-ULTIIDYK.js → deps-EC3VRNN7.js} +4 -2
- package/dist/{dev-5JMHMS4U.js → dev-R43VQCZD.js} +9 -2
- package/dist/index.js +13 -13
- package/dist/{init-37XOMJLU.js → init-TDIQAOG4.js} +29 -9
- package/dist/{register-JJUMS4FI.js → register-JFJADKAJ.js} +1 -1
- package/dist/{resources-4IUZYKGX.js → resources-OP7EECKZ.js} +20 -92
- package/dist/{run-5ZOSPBGO.js → run-EJP5WCQU.js} +1 -1
- package/dist/{templates-M3RDNDDY.js → templates-LNUOTNLN.js} +2 -3
- package/package.json +1 -1
- package/templates/default/.agents/skills/.gitkeep +0 -0
- package/templates/default/AGENTS.md +151 -0
- package/templates/default/README.md +18 -0
- package/templates/default/_gitignore +14 -0
- package/templates/default/architecture.md +29 -0
- package/templates/default/biome.json +38 -0
- package/templates/default/components.json +21 -0
- package/templates/default/icon.svg +29 -0
- package/templates/default/index.html +16 -0
- package/templates/default/package.json +53 -0
- package/templates/default/platform/automations/.gitkeep +0 -0
- package/templates/default/platform/collections/.gitkeep +0 -0
- package/templates/default/platform/hooks/.gitkeep +0 -0
- package/templates/default/pyproject.toml +14 -0
- package/templates/default/scripts/.gitkeep +0 -0
- package/templates/default/src/components/layout.tsx +11 -0
- package/templates/default/src/lib/auth.ts +9 -0
- package/templates/default/src/lib/queries.ts +17 -0
- package/templates/default/src/lib/utils.ts +6 -0
- package/templates/default/src/main.tsx +130 -0
- package/templates/default/src/routes/__root.tsx +10 -0
- package/templates/default/src/routes/index.tsx +87 -0
- package/templates/default/src/styles.css +128 -0
- package/templates/default/template.json +7 -0
- package/templates/default/tsconfig.json +22 -0
- package/templates/default/vite.config.ts +28 -0
- package/dist/chunk-OQW5E7UT.js +0 -159
- package/dist/chunk-XDTWVFPE.js +0 -120
package/README.md
CHANGED
|
@@ -51,24 +51,26 @@ For CI/CD or scripted environments, use `-y` (or `--yes`) flag:
|
|
|
51
51
|
lumera init my-app -y # Creates ./my-app
|
|
52
52
|
lumera init my-app -y --dir ./apps # Creates ./apps
|
|
53
53
|
lumera init my-app -y --force # Overwrites if directory exists
|
|
54
|
-
lumera init my-app -y --install
|
|
54
|
+
lumera init my-app -y --no-install # Skip pnpm install
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
### Init Options
|
|
58
58
|
|
|
59
59
|
| Flag | Short | Description |
|
|
60
60
|
|------|-------|-------------|
|
|
61
|
+
| `--template <name>` | `-t` | Template to use (currently bundled: `default`) |
|
|
61
62
|
| `--yes` | `-y` | Non-interactive mode (project name required) |
|
|
62
63
|
| `--dir <path>` | `-d` | Target directory (defaults to project name) |
|
|
63
64
|
| `--force` | `-f` | Overwrite existing directory without prompting |
|
|
64
|
-
| `--install` |
|
|
65
|
+
| `--no-install` | | Skip dependency installation |
|
|
66
|
+
| `--open` | `-o` | Open project in editor after scaffolding |
|
|
65
67
|
| `--help` | `-h` | Show help |
|
|
66
68
|
|
|
67
69
|
### CI/CD Example
|
|
68
70
|
|
|
69
71
|
```bash
|
|
70
72
|
# Full non-interactive setup
|
|
71
|
-
lumera init my-app -y -f
|
|
73
|
+
lumera init my-app -y -f
|
|
72
74
|
```
|
|
73
75
|
|
|
74
76
|
## Authentication
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// src/lib/templates.ts
|
|
2
|
+
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
function getBundledTemplatesDir() {
|
|
6
|
+
if (process.env.LUMERA_TEMPLATES_DIR) {
|
|
7
|
+
return process.env.LUMERA_TEMPLATES_DIR;
|
|
8
|
+
}
|
|
9
|
+
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const candidates = [
|
|
11
|
+
// Built package: dist/*.js -> templates/
|
|
12
|
+
join(moduleDir, "..", "templates"),
|
|
13
|
+
// Source/dev execution: src/lib/*.ts -> templates/
|
|
14
|
+
join(moduleDir, "..", "..", "templates")
|
|
15
|
+
];
|
|
16
|
+
return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0];
|
|
17
|
+
}
|
|
18
|
+
function parseTemplateRef(input) {
|
|
19
|
+
const atIndex = input.lastIndexOf("@");
|
|
20
|
+
if (atIndex > 0) {
|
|
21
|
+
return {
|
|
22
|
+
name: input.slice(0, atIndex),
|
|
23
|
+
ref: input.slice(atIndex + 1)
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return { name: input, ref: null };
|
|
27
|
+
}
|
|
28
|
+
function listTemplates(baseDir) {
|
|
29
|
+
if (!existsSync(baseDir)) return [];
|
|
30
|
+
const templates = [];
|
|
31
|
+
for (const entry of readdirSync(baseDir, { withFileTypes: true })) {
|
|
32
|
+
if (!entry.isDirectory()) continue;
|
|
33
|
+
const metaPath = join(baseDir, entry.name, "template.json");
|
|
34
|
+
if (!existsSync(metaPath)) continue;
|
|
35
|
+
try {
|
|
36
|
+
const raw = JSON.parse(readFileSync(metaPath, "utf-8"));
|
|
37
|
+
if (!raw.name || !raw.title || !raw.description || !raw.category) {
|
|
38
|
+
console.warn(`Warning: Skipping template "${entry.name}" \u2014 template.json is missing required fields (name, title, description, category)`);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
templates.push(raw);
|
|
42
|
+
} catch {
|
|
43
|
+
console.warn(`Warning: Skipping template "${entry.name}" \u2014 invalid template.json`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return templates.sort((a, b) => {
|
|
47
|
+
if (a.name === "default") return -1;
|
|
48
|
+
if (b.name === "default") return 1;
|
|
49
|
+
return a.title.localeCompare(b.title);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async function resolveTemplate(nameWithRef) {
|
|
53
|
+
const { name, ref } = parseTemplateRef(nameWithRef);
|
|
54
|
+
const templatesDir = getBundledTemplatesDir();
|
|
55
|
+
const available = listTemplates(templatesDir).map((t) => t.name).join(", ");
|
|
56
|
+
if (ref) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Template refs are no longer downloaded by the CLI. Use one of the bundled templates: ${available || "none"}`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const dir = join(templatesDir, name);
|
|
62
|
+
if (!existsSync(dir) || !existsSync(join(dir, "template.json"))) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`Template "${name}" not found. Available: ${available || "none"}
|
|
65
|
+
Templates location: ${templatesDir}`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
return dir;
|
|
69
|
+
}
|
|
70
|
+
async function listAllTemplates() {
|
|
71
|
+
return listTemplates(getBundledTemplatesDir());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
resolveTemplate,
|
|
76
|
+
listAllTemplates
|
|
77
|
+
};
|
|
@@ -74,6 +74,13 @@ var ApiClient = class {
|
|
|
74
74
|
return response.json();
|
|
75
75
|
}
|
|
76
76
|
// Collections
|
|
77
|
+
async getMe() {
|
|
78
|
+
return this.request("/api/me");
|
|
79
|
+
}
|
|
80
|
+
async isProjectPermissionsModeEnabled() {
|
|
81
|
+
const me = await this.getMe();
|
|
82
|
+
return me.user?.feature_flags?.project_permissions_mode === true;
|
|
83
|
+
}
|
|
77
84
|
async listCollections() {
|
|
78
85
|
const result = await this.request("/api/pb/collections");
|
|
79
86
|
return result.items;
|
|
@@ -302,7 +309,13 @@ var ApiClient = class {
|
|
|
302
309
|
updated: rec.updated
|
|
303
310
|
};
|
|
304
311
|
}
|
|
305
|
-
|
|
312
|
+
async listProjectResourceShares(projectExternalId, direction = "all") {
|
|
313
|
+
const qs = direction && direction !== "all" ? `?direction=${encodeURIComponent(direction)}` : "";
|
|
314
|
+
return this.request(
|
|
315
|
+
`/api/projects/${encodeURIComponent(projectExternalId)}/resource-shares${qs}`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
// Project manifest — legacy collection list for project_deps.json.
|
|
306
319
|
async getProjectManifest(externalId) {
|
|
307
320
|
return this.request(`/api/pb/projects/${encodeURIComponent(externalId)}/manifest`);
|
|
308
321
|
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import {
|
|
2
|
+
loadEnv
|
|
3
|
+
} from "./chunk-2CR762KB.js";
|
|
4
|
+
import {
|
|
5
|
+
createApiClient
|
|
6
|
+
} from "./chunk-JKXLKK5I.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, readdirSync } from "fs";
|
|
15
|
+
import { join } from "path";
|
|
16
|
+
var LEGACY_DEPS_FILE = "platform/project_deps.json";
|
|
17
|
+
var SHARED_COLLECTIONS_DIR = "platform/collections/shared";
|
|
18
|
+
function loadLegacyDeps(projectRoot) {
|
|
19
|
+
const depsPath = join(projectRoot, LEGACY_DEPS_FILE);
|
|
20
|
+
if (!existsSync(depsPath)) return null;
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(readFileSync(depsPath, "utf-8"));
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function sharedCollectionsDir(projectRoot) {
|
|
28
|
+
return join(projectRoot, SHARED_COLLECTIONS_DIR);
|
|
29
|
+
}
|
|
30
|
+
function safeShareFilenamePart(value) {
|
|
31
|
+
return value.trim().replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+|_+$/g, "") || "unknown";
|
|
32
|
+
}
|
|
33
|
+
function shareCollectionName(share) {
|
|
34
|
+
return share.object_name || share.object_display_name || share.object_id;
|
|
35
|
+
}
|
|
36
|
+
function shareFileName(share) {
|
|
37
|
+
const source = safeShareFilenamePart(share.source_project.external_id || share.source_project.name || "source");
|
|
38
|
+
const collection = safeShareFilenamePart(shareCollectionName(share));
|
|
39
|
+
return `${source}__${collection}.json`;
|
|
40
|
+
}
|
|
41
|
+
function readSharedCollectionFile(path) {
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function loadSharedCollectionDeps(projectRoot) {
|
|
49
|
+
const dir = sharedCollectionsDir(projectRoot);
|
|
50
|
+
if (!existsSync(dir)) return [];
|
|
51
|
+
const deps2 = [];
|
|
52
|
+
for (const entry of readdirSync(dir)) {
|
|
53
|
+
if (!entry.endsWith(".json")) continue;
|
|
54
|
+
const filePath = join(dir, entry);
|
|
55
|
+
const dep = readSharedCollectionFile(filePath);
|
|
56
|
+
if (dep) deps2.push({ file: entry, dep });
|
|
57
|
+
}
|
|
58
|
+
return deps2.sort((a, b) => a.file.localeCompare(b.file));
|
|
59
|
+
}
|
|
60
|
+
async function projectPermissionsModeEnabled(api) {
|
|
61
|
+
try {
|
|
62
|
+
return await api.isProjectPermissionsModeEnabled();
|
|
63
|
+
} catch {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function declarationForShare(share, existing) {
|
|
68
|
+
return {
|
|
69
|
+
...existing ?? {},
|
|
70
|
+
source_project: share.source_project.external_id,
|
|
71
|
+
collection: shareCollectionName(share),
|
|
72
|
+
privilege: share.privilege,
|
|
73
|
+
reason: typeof existing?.reason === "string" ? existing.reason : ""
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function listIncomingCollectionShares(api, projectExternalId) {
|
|
77
|
+
const result = await api.listProjectResourceShares(projectExternalId, "incoming");
|
|
78
|
+
return (result.shares ?? []).filter((share) => share.object_type === "collection").sort((a, b) => {
|
|
79
|
+
const bySource = a.source_project.external_id.localeCompare(b.source_project.external_id);
|
|
80
|
+
if (bySource !== 0) return bySource;
|
|
81
|
+
return shareCollectionName(a).localeCompare(shareCollectionName(b));
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async function syncResourceShareDeps(projectRoot, api, projectExternalId, opts) {
|
|
85
|
+
let shares;
|
|
86
|
+
try {
|
|
87
|
+
shares = await listIncomingCollectionShares(api, projectExternalId);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
if (!opts.quiet) {
|
|
90
|
+
console.log(pc.red(" \u2717"), `Failed to list incoming resource shares \u2014 ${e}`);
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
if (shares.length === 0) {
|
|
95
|
+
if (!opts.quiet) console.log(pc.dim(" No incoming resource shares."));
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
const dir = sharedCollectionsDir(projectRoot);
|
|
99
|
+
const missing = [];
|
|
100
|
+
if (opts.write) {
|
|
101
|
+
mkdirSync(dir, { recursive: true });
|
|
102
|
+
}
|
|
103
|
+
for (const share of shares) {
|
|
104
|
+
const fileName = shareFileName(share);
|
|
105
|
+
const filePath = join(dir, fileName);
|
|
106
|
+
const exists = existsSync(filePath);
|
|
107
|
+
if (!opts.write) {
|
|
108
|
+
if (!exists) missing.push(fileName);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const existing = exists ? readSharedCollectionFile(filePath) ?? void 0 : void 0;
|
|
112
|
+
const declaration = declarationForShare(share, existing);
|
|
113
|
+
writeFileSync(filePath, JSON.stringify(declaration, null, 2) + "\n");
|
|
114
|
+
if (!opts.quiet) {
|
|
115
|
+
const action = exists ? pc.yellow("\u21BB") : pc.green("+");
|
|
116
|
+
console.log(` ${action} collections/shared/${fileName}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (!opts.write && missing.length > 0) {
|
|
120
|
+
if (!opts.quiet) {
|
|
121
|
+
console.log(pc.yellow(` \u26A0 ${missing.length} incoming resource share${missing.length === 1 ? "" : "s"} not synced locally.`));
|
|
122
|
+
for (const file of missing) console.log(pc.dim(` collections/shared/${file}`));
|
|
123
|
+
console.log(pc.dim(` Run ${pc.cyan("lumera deps sync")} to write shared resource declarations.`));
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
if (!opts.quiet && !opts.write) {
|
|
128
|
+
console.log(pc.green(" \u2713"), "Incoming resource shares are synced locally.");
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
async function syncLegacyDeps(projectRoot, api, quiet = false) {
|
|
133
|
+
const deps2 = loadLegacyDeps(projectRoot);
|
|
134
|
+
if (!deps2 || !deps2.dependencies || Object.keys(deps2.dependencies).length === 0) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
let allOk = true;
|
|
138
|
+
for (const [depProject, config] of Object.entries(deps2.dependencies)) {
|
|
139
|
+
try {
|
|
140
|
+
const manifest = await api.getProjectManifest(depProject);
|
|
141
|
+
const remoteNames = new Set(manifest.collections.map((c) => c.name));
|
|
142
|
+
for (const col of config.collections) {
|
|
143
|
+
if (remoteNames.has(col)) {
|
|
144
|
+
if (!quiet) console.log(pc.green(" \u2713"), `${depProject}/${col}`);
|
|
145
|
+
} else {
|
|
146
|
+
if (!quiet) console.log(pc.red(" \u2717"), `${depProject}/${col} \u2014 not found in project manifest`);
|
|
147
|
+
allOk = false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} catch (e) {
|
|
151
|
+
if (!quiet) console.log(pc.red(" \u2717"), `${depProject}: failed to fetch manifest \u2014 ${e}`);
|
|
152
|
+
allOk = false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return allOk;
|
|
156
|
+
}
|
|
157
|
+
async function projectResourceDepsEnabled(projectRoot) {
|
|
158
|
+
const root = projectRoot ?? findProjectRoot();
|
|
159
|
+
loadEnv(root);
|
|
160
|
+
const appName = getAppName(root);
|
|
161
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
162
|
+
return projectPermissionsModeEnabled(api);
|
|
163
|
+
}
|
|
164
|
+
async function syncDeps(projectRoot, options = {}) {
|
|
165
|
+
const root = projectRoot ?? findProjectRoot();
|
|
166
|
+
loadEnv(root);
|
|
167
|
+
const appName = getAppName(root);
|
|
168
|
+
const api = createApiClient(void 0, void 0, appName);
|
|
169
|
+
const flagOn = await projectPermissionsModeEnabled(api);
|
|
170
|
+
const quiet = options.quiet === true;
|
|
171
|
+
const write = options.write === true;
|
|
172
|
+
if (flagOn) {
|
|
173
|
+
return syncResourceShareDeps(root, api, appName, { write, quiet });
|
|
174
|
+
}
|
|
175
|
+
if (options.legacyWhenDisabled === false) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
return syncLegacyDeps(root, api, quiet);
|
|
179
|
+
}
|
|
180
|
+
async function deps(args) {
|
|
181
|
+
const sub = args[0];
|
|
182
|
+
const projectRoot = findProjectRoot();
|
|
183
|
+
loadEnv(projectRoot);
|
|
184
|
+
let cachedFlagOn;
|
|
185
|
+
async function flagOn() {
|
|
186
|
+
if (cachedFlagOn !== void 0) return cachedFlagOn;
|
|
187
|
+
cachedFlagOn = await projectResourceDepsEnabled(projectRoot);
|
|
188
|
+
return cachedFlagOn;
|
|
189
|
+
}
|
|
190
|
+
if (sub === "sync") {
|
|
191
|
+
const enabled = await flagOn();
|
|
192
|
+
console.log();
|
|
193
|
+
console.log(pc.cyan(pc.bold(" Deps Sync")));
|
|
194
|
+
console.log(pc.dim(enabled ? " Syncing incoming resource shares into platform/collections/shared..." : " Verifying legacy cross-project dependencies..."));
|
|
195
|
+
console.log();
|
|
196
|
+
const ok = await syncDeps(projectRoot, { write: enabled });
|
|
197
|
+
if (!ok) {
|
|
198
|
+
console.log();
|
|
199
|
+
console.log(pc.red(enabled ? " Some resource-share dependencies could not be synced." : " Some dependencies could not be resolved."));
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
console.log();
|
|
203
|
+
console.log(pc.green(enabled ? " Resource shares synced." : " All dependencies verified."));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (sub === "list") {
|
|
207
|
+
if (await flagOn()) {
|
|
208
|
+
const sharedDeps = loadSharedCollectionDeps(projectRoot);
|
|
209
|
+
if (sharedDeps.length === 0) {
|
|
210
|
+
console.log(pc.dim(" No shared collection declarations in platform/collections/shared"));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
console.log();
|
|
214
|
+
console.log(pc.cyan(pc.bold(" Shared Collection Dependencies")));
|
|
215
|
+
console.log();
|
|
216
|
+
for (const { file, dep } of sharedDeps) {
|
|
217
|
+
const source = dep.source_project ?? "unknown-source";
|
|
218
|
+
const collection = dep.collection ?? "unknown-table";
|
|
219
|
+
const privilege = dep.privilege ?? "collection.read";
|
|
220
|
+
console.log(` ${pc.bold(file)}`);
|
|
221
|
+
console.log(` ${source}/${collection} ${pc.dim(`(${privilege})`)}`);
|
|
222
|
+
}
|
|
223
|
+
console.log();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const depsData = loadLegacyDeps(projectRoot);
|
|
227
|
+
if (!depsData || Object.keys(depsData.dependencies).length === 0) {
|
|
228
|
+
console.log(pc.dim(" No dependencies declared in platform/project_deps.json"));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
console.log();
|
|
232
|
+
console.log(pc.cyan(pc.bold(" Project Dependencies")));
|
|
233
|
+
console.log();
|
|
234
|
+
for (const [depProject, config] of Object.entries(depsData.dependencies)) {
|
|
235
|
+
console.log(` ${pc.bold(depProject)}`);
|
|
236
|
+
for (const col of config.collections) {
|
|
237
|
+
console.log(` \u2022 ${col}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
console.log();
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (sub === "init") {
|
|
244
|
+
if (await flagOn()) {
|
|
245
|
+
const dir = sharedCollectionsDir(projectRoot);
|
|
246
|
+
mkdirSync(dir, { recursive: true });
|
|
247
|
+
console.log(pc.green(" \u2713"), "Created platform/collections/shared/");
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const depsPath = join(projectRoot, LEGACY_DEPS_FILE);
|
|
251
|
+
if (existsSync(depsPath)) {
|
|
252
|
+
console.log(pc.yellow(" platform/project_deps.json already exists."));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const platformDir = join(projectRoot, "platform");
|
|
256
|
+
mkdirSync(platformDir, { recursive: true });
|
|
257
|
+
const initial = { dependencies: {} };
|
|
258
|
+
writeFileSync(depsPath, JSON.stringify(initial, null, 2) + "\n");
|
|
259
|
+
console.log(pc.green(" \u2713"), "Created platform/project_deps.json");
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
console.log(`
|
|
263
|
+
${pc.bold("lumera deps")} \u2014 manage cross-project dependencies
|
|
264
|
+
|
|
265
|
+
${pc.bold("Commands:")}
|
|
266
|
+
sync Sync dependencies. With project permissions on, writes incoming
|
|
267
|
+
resource shares to platform/collections/shared/*.json
|
|
268
|
+
list Show declared dependencies
|
|
269
|
+
init Create dependency storage for the current feature mode
|
|
270
|
+
|
|
271
|
+
${pc.bold("Project permissions mode:")} platform/collections/shared/*.json
|
|
272
|
+
${pc.bold("Legacy mode:")} platform/project_deps.json
|
|
273
|
+
`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export {
|
|
277
|
+
projectResourceDepsEnabled,
|
|
278
|
+
syncDeps,
|
|
279
|
+
deps
|
|
280
|
+
};
|
|
@@ -137,59 +137,19 @@ function isPortInUse(port, host = "127.0.0.1") {
|
|
|
137
137
|
});
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
|
-
function commandAvailable(command) {
|
|
141
|
-
try {
|
|
142
|
-
execSync(`${command} --version`, { stdio: "ignore" });
|
|
143
|
-
return true;
|
|
144
|
-
} catch {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
function parsePackageManagerSpecifier(value) {
|
|
149
|
-
const raw = (value || "").trim();
|
|
150
|
-
if (!raw) return void 0;
|
|
151
|
-
const name = raw.split("@")[0];
|
|
152
|
-
return ["bun", "pnpm", "yarn", "npm"].includes(name) ? name : void 0;
|
|
153
|
-
}
|
|
154
|
-
function packageManagerFromPackageJson(projectRoot) {
|
|
155
|
-
try {
|
|
156
|
-
const pkg = JSON.parse(readFileSync(resolve(projectRoot, "package.json"), "utf-8"));
|
|
157
|
-
return parsePackageManagerSpecifier(pkg.packageManager);
|
|
158
|
-
} catch {
|
|
159
|
-
return void 0;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
function runnerForPackageManager(pm) {
|
|
163
|
-
if (pm === "pnpm") return ["pnpm", "exec"];
|
|
164
|
-
if (pm === "bun") return ["bunx"];
|
|
165
|
-
if (pm === "yarn") return ["yarn"];
|
|
166
|
-
return ["npx"];
|
|
167
|
-
}
|
|
168
140
|
function detectRunner(projectRoot) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return runnerForPackageManager(requested);
|
|
141
|
+
if (existsSync(resolve(projectRoot, "bun.lockb")) || existsSync(resolve(projectRoot, "bun.lock"))) {
|
|
142
|
+
return ["bunx"];
|
|
172
143
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return runnerForPackageManager(declared);
|
|
144
|
+
if (existsSync(resolve(projectRoot, "pnpm-lock.yaml"))) {
|
|
145
|
+
return ["pnpm", "exec"];
|
|
176
146
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
{ pm: "npm", file: "package-lock.json" }
|
|
183
|
-
];
|
|
184
|
-
for (const { pm, file } of lockfileManagers) {
|
|
185
|
-
const runner = runnerForPackageManager(pm);
|
|
186
|
-
if (existsSync(resolve(projectRoot, file)) && commandAvailable(runner[0])) return runner;
|
|
187
|
-
}
|
|
188
|
-
for (const pm of ["pnpm", "bun", "yarn", "npm"]) {
|
|
189
|
-
const runner = runnerForPackageManager(pm);
|
|
190
|
-
if (commandAvailable(runner[0])) return runner;
|
|
147
|
+
try {
|
|
148
|
+
execSync("pnpm --version", { stdio: "ignore" });
|
|
149
|
+
return ["pnpm", "exec"];
|
|
150
|
+
} catch {
|
|
151
|
+
return ["bunx"];
|
|
191
152
|
}
|
|
192
|
-
return ["npx"];
|
|
193
153
|
}
|
|
194
154
|
function getParentOrigin(apiUrl) {
|
|
195
155
|
return apiUrl.replace(/\/api\/?$/, "").replace(/\/$/, "");
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deps,
|
|
3
|
+
projectResourceDepsEnabled,
|
|
3
4
|
syncDeps
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-P5HFNAVN.js";
|
|
5
6
|
import "./chunk-2CR762KB.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-JKXLKK5I.js";
|
|
7
8
|
import "./chunk-ZH3NVYEQ.js";
|
|
8
9
|
import "./chunk-FJFIWC7G.js";
|
|
9
10
|
import "./chunk-PNKVD2UK.js";
|
|
10
11
|
export {
|
|
11
12
|
deps,
|
|
13
|
+
projectResourceDepsEnabled,
|
|
12
14
|
syncDeps
|
|
13
15
|
};
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dev
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SU26C4GL.js";
|
|
4
|
+
import {
|
|
5
|
+
projectResourceDepsEnabled,
|
|
6
|
+
syncDeps
|
|
7
|
+
} from "./chunk-P5HFNAVN.js";
|
|
4
8
|
import {
|
|
5
9
|
loadEnv
|
|
6
10
|
} from "./chunk-2CR762KB.js";
|
|
7
11
|
import {
|
|
8
12
|
createApiClient
|
|
9
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-JKXLKK5I.js";
|
|
10
14
|
import {
|
|
11
15
|
findProjectRoot,
|
|
12
16
|
getApiUrl,
|
|
@@ -121,6 +125,9 @@ async function dev2(args) {
|
|
|
121
125
|
const appName = getAppName(projectRoot);
|
|
122
126
|
const appTitle = getAppTitle(projectRoot);
|
|
123
127
|
const apiUrl = getApiUrl();
|
|
128
|
+
if (await projectResourceDepsEnabled(projectRoot)) {
|
|
129
|
+
await syncDeps(projectRoot, { write: true, quiet: true, legacyWhenDisabled: false });
|
|
130
|
+
}
|
|
124
131
|
if (!flags["skip-setup"]) {
|
|
125
132
|
const fresh = await isFreshProject(projectRoot);
|
|
126
133
|
if (fresh) {
|
package/dist/index.js
CHANGED
|
@@ -219,42 +219,42 @@ async function main() {
|
|
|
219
219
|
switch (command) {
|
|
220
220
|
// Resource commands
|
|
221
221
|
case "plan":
|
|
222
|
-
await import("./resources-
|
|
222
|
+
await import("./resources-OP7EECKZ.js").then((m) => m.plan(args.slice(1)));
|
|
223
223
|
break;
|
|
224
224
|
case "apply":
|
|
225
|
-
await import("./resources-
|
|
225
|
+
await import("./resources-OP7EECKZ.js").then((m) => m.apply(args.slice(1)));
|
|
226
226
|
break;
|
|
227
227
|
case "pull":
|
|
228
|
-
await import("./resources-
|
|
228
|
+
await import("./resources-OP7EECKZ.js").then((m) => m.pull(args.slice(1)));
|
|
229
229
|
break;
|
|
230
230
|
case "destroy":
|
|
231
|
-
await import("./resources-
|
|
231
|
+
await import("./resources-OP7EECKZ.js").then((m) => m.destroy(args.slice(1)));
|
|
232
232
|
break;
|
|
233
233
|
case "list":
|
|
234
|
-
await import("./resources-
|
|
234
|
+
await import("./resources-OP7EECKZ.js").then((m) => m.list(args.slice(1)));
|
|
235
235
|
break;
|
|
236
236
|
case "show":
|
|
237
|
-
await import("./resources-
|
|
237
|
+
await import("./resources-OP7EECKZ.js").then((m) => m.show(args.slice(1)));
|
|
238
238
|
break;
|
|
239
239
|
case "diff":
|
|
240
|
-
await import("./resources-
|
|
240
|
+
await import("./resources-OP7EECKZ.js").then((m) => m.diff(args.slice(1)));
|
|
241
241
|
break;
|
|
242
242
|
// Development
|
|
243
243
|
case "dev":
|
|
244
|
-
await import("./dev-
|
|
244
|
+
await import("./dev-R43VQCZD.js").then((m) => m.dev(args.slice(1)));
|
|
245
245
|
break;
|
|
246
246
|
case "run":
|
|
247
|
-
await import("./run-
|
|
247
|
+
await import("./run-EJP5WCQU.js").then((m) => m.run(args.slice(1)));
|
|
248
248
|
break;
|
|
249
249
|
// Project
|
|
250
250
|
case "init":
|
|
251
|
-
await import("./init-
|
|
251
|
+
await import("./init-TDIQAOG4.js").then((m) => m.init(args.slice(1)));
|
|
252
252
|
break;
|
|
253
253
|
case "register":
|
|
254
|
-
await import("./register-
|
|
254
|
+
await import("./register-JFJADKAJ.js").then((m) => m.register(args.slice(1)));
|
|
255
255
|
break;
|
|
256
256
|
case "templates":
|
|
257
|
-
await import("./templates-
|
|
257
|
+
await import("./templates-LNUOTNLN.js").then((m) => m.templates(subcommand, args.slice(2)));
|
|
258
258
|
break;
|
|
259
259
|
case "status":
|
|
260
260
|
await import("./status-X7WQYX2L.js").then((m) => m.status(args.slice(1)));
|
|
@@ -268,7 +268,7 @@ async function main() {
|
|
|
268
268
|
break;
|
|
269
269
|
// Dependencies
|
|
270
270
|
case "deps":
|
|
271
|
-
await import("./deps-
|
|
271
|
+
await import("./deps-EC3VRNN7.js").then((m) => m.deps(args.slice(1)));
|
|
272
272
|
break;
|
|
273
273
|
// Auth
|
|
274
274
|
case "login":
|