@lumerahq/cli 0.33.2 → 0.34.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/{project-O7ZZQXFN.js → chunk-2EHJH2QU.js} +13 -9
- package/dist/chunk-5FGDEZSJ.js +12 -0
- package/dist/{chunk-3MAALYAP.js → chunk-P6GDSHYC.js} +84 -204
- package/dist/chunk-UGAIWMQV.js +26 -0
- package/dist/{chunk-BCSUKRDA.js → chunk-XZ5VCTGY.js} +4 -10
- package/dist/{dev-CGQTW7TN.js → dev-24PCZUAT.js} +5 -1
- package/dist/{functions-BAJ3PCNO.js → functions-5OOHGQT7.js} +2 -1
- package/dist/index.js +11 -11
- package/dist/{migrate-NEG3HKH4.js → migrate-DHNR3ESM.js} +111 -2
- package/dist/project-ISKXDHGJ.js +13 -0
- package/dist/{resources-IY3XSYJH.js → resources-IGHWATTH.js} +8 -4
- package/package.json +3 -2
- package/templates/default/AGENTS.md +3 -2
- package/templates/default/pyproject.toml +5 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
RELEASE_SDK_REQUIREMENT,
|
|
3
2
|
findFunctionsProjectRoot
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import
|
|
3
|
+
} from "./chunk-XZ5VCTGY.js";
|
|
4
|
+
import {
|
|
5
|
+
RELEASE_SDK_REQUIREMENT
|
|
6
|
+
} from "./chunk-5FGDEZSJ.js";
|
|
6
7
|
|
|
7
8
|
// src/commands/project.ts
|
|
8
9
|
import { spawn } from "child_process";
|
|
@@ -13,6 +14,7 @@ var RELEASE_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
13
14
|
"inspect",
|
|
14
15
|
"contract-test",
|
|
15
16
|
"deploy",
|
|
17
|
+
"deploy-project",
|
|
16
18
|
"deploy-runtime"
|
|
17
19
|
]);
|
|
18
20
|
function showHelp() {
|
|
@@ -22,12 +24,13 @@ ${pc.dim("Usage:")}
|
|
|
22
24
|
lumera project release inspect <archive> [--expected-digest <sha256>]
|
|
23
25
|
lumera project release contract-test <archive> [--mode api|function|all]
|
|
24
26
|
lumera project release deploy <archive> --project <project-id>
|
|
27
|
+
lumera project release deploy-project --project <project-id>
|
|
25
28
|
lumera project release deploy-runtime <release-id> --project <project-id>
|
|
26
29
|
|
|
27
30
|
${pc.dim("Description:")}
|
|
28
31
|
Build, verify, and contract-test immutable Python 3.13/Linux/ARM64 project
|
|
29
|
-
releases.
|
|
30
|
-
|
|
32
|
+
releases. deploy-project builds, uploads, and activates the complete project
|
|
33
|
+
runtime used by App APIs, Functions, and Automations.
|
|
31
34
|
`);
|
|
32
35
|
}
|
|
33
36
|
function buildReleaseRunnerArgs(command, args, projectRoot) {
|
|
@@ -48,11 +51,11 @@ function buildReleaseRunnerArgs(command, args, projectRoot) {
|
|
|
48
51
|
...args
|
|
49
52
|
];
|
|
50
53
|
}
|
|
51
|
-
async function runReleaseRunner(runnerArgs, projectRoot, spawnRunner = (command, args, options) => spawn(command, args, options)) {
|
|
54
|
+
async function runReleaseRunner(runnerArgs, projectRoot, spawnRunner = (command, args, options) => spawn(command, args, options), environment = process.env) {
|
|
52
55
|
return await new Promise((resolvePromise, reject) => {
|
|
53
56
|
const child = spawnRunner("uv", runnerArgs, {
|
|
54
57
|
cwd: projectRoot,
|
|
55
|
-
env:
|
|
58
|
+
env: environment,
|
|
56
59
|
shell: false,
|
|
57
60
|
stdio: ["inherit", "pipe", "inherit"]
|
|
58
61
|
});
|
|
@@ -116,8 +119,9 @@ async function project(subcommand, args, dependencies = {}) {
|
|
|
116
119
|
process.exitCode = 1;
|
|
117
120
|
}
|
|
118
121
|
}
|
|
122
|
+
|
|
119
123
|
export {
|
|
120
124
|
buildReleaseRunnerArgs,
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
runReleaseRunner,
|
|
126
|
+
project
|
|
123
127
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/lib/functions-sdk.ts
|
|
2
|
+
var FUNCTIONS_SDK_VERSION_RANGE = ">=0.45.0,<0.46.0";
|
|
3
|
+
var FUNCTIONS_SDK_COMPATIBILITY_RANGE = ">=0.34.0,<0.46.0";
|
|
4
|
+
var FUNCTIONS_SDK_REQUIREMENT = `lumera[functions]${FUNCTIONS_SDK_COMPATIBILITY_RANGE}`;
|
|
5
|
+
var DEFAULT_FUNCTIONS_SDK_REQUIREMENT = `lumera[functions]${FUNCTIONS_SDK_VERSION_RANGE}`;
|
|
6
|
+
var RELEASE_SDK_REQUIREMENT = `lumera[release]${FUNCTIONS_SDK_VERSION_RANGE}`;
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
FUNCTIONS_SDK_REQUIREMENT,
|
|
10
|
+
DEFAULT_FUNCTIONS_SDK_REQUIREMENT,
|
|
11
|
+
RELEASE_SDK_REQUIREMENT
|
|
12
|
+
};
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseProjectTOML,
|
|
3
|
+
projectConfigTable
|
|
4
|
+
} from "./chunk-UGAIWMQV.js";
|
|
5
|
+
import {
|
|
6
|
+
buildReleaseRunnerArgs,
|
|
7
|
+
runReleaseRunner
|
|
8
|
+
} from "./chunk-2EHJH2QU.js";
|
|
1
9
|
import {
|
|
2
10
|
userContextHeaders
|
|
3
11
|
} from "./chunk-W57NUJFJ.js";
|
|
@@ -8,168 +16,10 @@ import {
|
|
|
8
16
|
// src/lib/deploy.ts
|
|
9
17
|
import { execSync, spawn } from "child_process";
|
|
10
18
|
import { createConnection } from "net";
|
|
11
|
-
import { existsSync
|
|
12
|
-
import { resolve
|
|
13
|
-
import archiver2 from "archiver";
|
|
14
|
-
import pc from "picocolors";
|
|
15
|
-
|
|
16
|
-
// src/lib/app-runtime-deploy.ts
|
|
17
|
-
import { execFileSync } from "child_process";
|
|
18
|
-
import {
|
|
19
|
-
cpSync,
|
|
20
|
-
existsSync,
|
|
21
|
-
mkdtempSync,
|
|
22
|
-
rmSync
|
|
23
|
-
} from "fs";
|
|
24
|
-
import { tmpdir } from "os";
|
|
25
|
-
import { basename, join, relative, resolve, sep } from "path";
|
|
19
|
+
import { existsSync, readFileSync } from "fs";
|
|
20
|
+
import { resolve, dirname } from "path";
|
|
26
21
|
import archiver from "archiver";
|
|
27
|
-
|
|
28
|
-
var APP_RUNTIME_PYTHON_VERSION = "3.13";
|
|
29
|
-
var APP_RUNTIME_PYTHON_PLATFORM = "aarch64-manylinux_2_34";
|
|
30
|
-
var MAX_APP_RUNTIME_ZIP_BYTES = 45 * 1024 * 1024;
|
|
31
|
-
var APP_RUNTIME_TARGET_ARGS = [
|
|
32
|
-
"--python-version",
|
|
33
|
-
APP_RUNTIME_PYTHON_VERSION,
|
|
34
|
-
"--python-platform",
|
|
35
|
-
APP_RUNTIME_PYTHON_PLATFORM
|
|
36
|
-
];
|
|
37
|
-
var EXCLUDED_SOURCE_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
38
|
-
".git",
|
|
39
|
-
".venv",
|
|
40
|
-
"venv",
|
|
41
|
-
"__pycache__",
|
|
42
|
-
".pytest_cache",
|
|
43
|
-
".ruff_cache",
|
|
44
|
-
".lambda-build",
|
|
45
|
-
"build",
|
|
46
|
-
"dist"
|
|
47
|
-
]);
|
|
48
|
-
function resolveAppRuntimeDirectory(projectRoot) {
|
|
49
|
-
const runtimeDir = resolve(projectRoot, APP_RUNTIME_RELATIVE_DIR);
|
|
50
|
-
if (!existsSync(runtimeDir)) return void 0;
|
|
51
|
-
if (!existsSync(join(runtimeDir, "server.py"))) {
|
|
52
|
-
throw new Error(`App API directory exists but is missing ${join(APP_RUNTIME_RELATIVE_DIR, "server.py")}`);
|
|
53
|
-
}
|
|
54
|
-
return runtimeDir;
|
|
55
|
-
}
|
|
56
|
-
function shouldCopyRuntimeSource(runtimeDir, sourcePath) {
|
|
57
|
-
const sourceRelativePath = relative(runtimeDir, sourcePath);
|
|
58
|
-
if (!sourceRelativePath) return true;
|
|
59
|
-
const segments = sourceRelativePath.split(sep);
|
|
60
|
-
if (segments.some((segment) => EXCLUDED_SOURCE_DIRECTORIES.has(segment))) return false;
|
|
61
|
-
if (segments.some((segment) => segment === ".env" || segment.startsWith(".env."))) return false;
|
|
62
|
-
const name = basename(sourcePath);
|
|
63
|
-
if (name === "lambda.zip") return false;
|
|
64
|
-
return !name.endsWith(".pyc") && !name.endsWith(".pyo");
|
|
65
|
-
}
|
|
66
|
-
function copyRuntimeSources(runtimeDir, buildDir) {
|
|
67
|
-
cpSync(runtimeDir, buildDir, {
|
|
68
|
-
recursive: true,
|
|
69
|
-
filter: (candidate) => shouldCopyRuntimeSource(runtimeDir, candidate)
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
function ensureUVAvailable(runCommand) {
|
|
73
|
-
try {
|
|
74
|
-
runCommand("uv", ["--version"], { stdio: "ignore" });
|
|
75
|
-
} catch (error) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
"uv is required to package App APIs. Install uv: https://docs.astral.sh/uv/",
|
|
78
|
-
{ cause: error }
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
async function createZip(directory) {
|
|
83
|
-
return new Promise((resolveZip, reject) => {
|
|
84
|
-
const chunks = [];
|
|
85
|
-
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
86
|
-
archive.on("data", (chunk) => chunks.push(chunk));
|
|
87
|
-
archive.on("end", () => resolveZip(Buffer.concat(chunks)));
|
|
88
|
-
archive.on("error", reject);
|
|
89
|
-
archive.directory(directory, false);
|
|
90
|
-
archive.finalize();
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
async function packageAppRuntime(runtimeDir, options = {}) {
|
|
94
|
-
if (!existsSync(join(runtimeDir, "server.py"))) {
|
|
95
|
-
throw new Error(`App API must contain server.py at ${join(runtimeDir, "server.py")}`);
|
|
96
|
-
}
|
|
97
|
-
const requirementsPath = join(runtimeDir, "requirements.txt");
|
|
98
|
-
const pyprojectPath = join(runtimeDir, "pyproject.toml");
|
|
99
|
-
if (!existsSync(requirementsPath) && !existsSync(pyprojectPath)) {
|
|
100
|
-
throw new Error("App API must contain requirements.txt or pyproject.toml");
|
|
101
|
-
}
|
|
102
|
-
const buildDir = mkdtempSync(join(tmpdir(), "lumera-app-runtime-"));
|
|
103
|
-
const runCommand = options.runCommand ?? execFileSync;
|
|
104
|
-
try {
|
|
105
|
-
ensureUVAvailable(runCommand);
|
|
106
|
-
let installRequirementsPath = requirementsPath;
|
|
107
|
-
let generatedRequirements = false;
|
|
108
|
-
if (!existsSync(requirementsPath)) {
|
|
109
|
-
installRequirementsPath = join(buildDir, "requirements.generated.txt");
|
|
110
|
-
generatedRequirements = true;
|
|
111
|
-
runCommand(
|
|
112
|
-
"uv",
|
|
113
|
-
[
|
|
114
|
-
"pip",
|
|
115
|
-
"compile",
|
|
116
|
-
"pyproject.toml",
|
|
117
|
-
...APP_RUNTIME_TARGET_ARGS,
|
|
118
|
-
"-o",
|
|
119
|
-
installRequirementsPath
|
|
120
|
-
],
|
|
121
|
-
{
|
|
122
|
-
cwd: runtimeDir,
|
|
123
|
-
stdio: "inherit"
|
|
124
|
-
}
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
runCommand("uv", [
|
|
128
|
-
"pip",
|
|
129
|
-
"install",
|
|
130
|
-
"--target",
|
|
131
|
-
buildDir,
|
|
132
|
-
...APP_RUNTIME_TARGET_ARGS,
|
|
133
|
-
"--only-binary=:all:",
|
|
134
|
-
"-r",
|
|
135
|
-
installRequirementsPath
|
|
136
|
-
], { stdio: "inherit" });
|
|
137
|
-
if (generatedRequirements) {
|
|
138
|
-
rmSync(installRequirementsPath, { force: true });
|
|
139
|
-
}
|
|
140
|
-
copyRuntimeSources(runtimeDir, buildDir);
|
|
141
|
-
const lambdaZip = await createZip(buildDir);
|
|
142
|
-
if (lambdaZip.length > MAX_APP_RUNTIME_ZIP_BYTES) {
|
|
143
|
-
throw new Error(
|
|
144
|
-
`App API package is too large (${lambdaZip.length} bytes > ${MAX_APP_RUNTIME_ZIP_BYTES}); remove heavy dependencies or split the app`
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
return lambdaZip;
|
|
148
|
-
} finally {
|
|
149
|
-
rmSync(buildDir, { recursive: true, force: true });
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
async function deployAppRuntime(options) {
|
|
153
|
-
const formData = new FormData();
|
|
154
|
-
formData.append("lambda_zip", new Blob([new Uint8Array(options.lambdaZip)]), "lambda.zip");
|
|
155
|
-
formData.append("version", options.version);
|
|
156
|
-
const res = await fetchWithRetry(`${options.apiUrl}/app-runtimes/current-project/deploy`, {
|
|
157
|
-
method: "POST",
|
|
158
|
-
headers: {
|
|
159
|
-
Authorization: `Bearer ${options.token}`,
|
|
160
|
-
"X-Lumera-Client": "lumera-cli",
|
|
161
|
-
"X-Lumera-Project": options.projectExternalId,
|
|
162
|
-
...userContextHeaders()
|
|
163
|
-
},
|
|
164
|
-
body: formData
|
|
165
|
-
});
|
|
166
|
-
if (!res.ok) {
|
|
167
|
-
throw new Error(`App API deploy failed: ${await res.text()}`);
|
|
168
|
-
}
|
|
169
|
-
await res.arrayBuffer();
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// src/lib/deploy.ts
|
|
22
|
+
import pc from "picocolors";
|
|
173
23
|
function formatTimestampVersion(date = /* @__PURE__ */ new Date()) {
|
|
174
24
|
const pad = (value) => String(value).padStart(2, "0");
|
|
175
25
|
return [
|
|
@@ -183,7 +33,7 @@ function formatTimestampVersion(date = /* @__PURE__ */ new Date()) {
|
|
|
183
33
|
].join("") + "Z";
|
|
184
34
|
}
|
|
185
35
|
function resolveVersion(cwd, gitRelease = resolveGitReleaseState(cwd)) {
|
|
186
|
-
const pkgPath =
|
|
36
|
+
const pkgPath = resolve(cwd, "package.json");
|
|
187
37
|
try {
|
|
188
38
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
189
39
|
if (pkg?.version && pkg.version !== "0.0.0") return String(pkg.version);
|
|
@@ -195,13 +45,13 @@ function resolveVersion(cwd, gitRelease = resolveGitReleaseState(cwd)) {
|
|
|
195
45
|
function resolveUIVersion(cwd) {
|
|
196
46
|
try {
|
|
197
47
|
const installed = JSON.parse(
|
|
198
|
-
readFileSync(
|
|
48
|
+
readFileSync(resolve(cwd, "node_modules/@lumerahq/ui/package.json"), "utf-8")
|
|
199
49
|
);
|
|
200
50
|
if (installed?.version) return String(installed.version);
|
|
201
51
|
} catch {
|
|
202
52
|
}
|
|
203
53
|
try {
|
|
204
|
-
const pkg = JSON.parse(readFileSync(
|
|
54
|
+
const pkg = JSON.parse(readFileSync(resolve(cwd, "package.json"), "utf-8"));
|
|
205
55
|
const spec = pkg?.dependencies?.["@lumerahq/ui"] ?? pkg?.devDependencies?.["@lumerahq/ui"];
|
|
206
56
|
if (!spec) return "none";
|
|
207
57
|
const cleaned = String(spec).replace(/^[\^~>=<\s]+/, "");
|
|
@@ -237,53 +87,84 @@ function resolveGitReleaseState(cwd) {
|
|
|
237
87
|
}
|
|
238
88
|
}
|
|
239
89
|
async function createTarball(distDir) {
|
|
240
|
-
return new Promise((
|
|
90
|
+
return new Promise((resolve2, reject) => {
|
|
241
91
|
const chunks = [];
|
|
242
|
-
const archive =
|
|
92
|
+
const archive = archiver("tar", { gzip: true });
|
|
243
93
|
archive.on("data", (chunk) => chunks.push(chunk));
|
|
244
|
-
archive.on("end", () =>
|
|
94
|
+
archive.on("end", () => resolve2(Buffer.concat(chunks)));
|
|
245
95
|
archive.on("error", reject);
|
|
246
96
|
archive.directory(distDir, false);
|
|
247
97
|
archive.finalize();
|
|
248
98
|
});
|
|
249
99
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
100
|
+
function resolveConfiguredProjectRuntime(projectRoot) {
|
|
101
|
+
const legacyPath = resolve(projectRoot, "app-api", "lambda");
|
|
102
|
+
if (existsSync(legacyPath)) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
"Legacy app-api/lambda deployment has been retired. Run `lumera migrate app-api`, commit the migrated project, and deploy again."
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
const configPath = resolve(projectRoot, "pyproject.toml");
|
|
108
|
+
if (!existsSync(configPath)) return { kind: "none" };
|
|
109
|
+
const document = parseProjectTOML(readFileSync(configPath, "utf8"));
|
|
110
|
+
const release = projectConfigTable(document, "tool", "lumera", "release");
|
|
111
|
+
const functions = projectConfigTable(document, "tool", "lumera", "functions");
|
|
112
|
+
const rawEntrypoint = release["app-entrypoint"];
|
|
113
|
+
if (rawEntrypoint !== void 0 && (typeof rawEntrypoint !== "string" || !rawEntrypoint.trim())) {
|
|
114
|
+
throw new Error("tool.lumera.release.app-entrypoint must be module:attribute");
|
|
115
|
+
}
|
|
116
|
+
const modules = functions.modules ?? [];
|
|
117
|
+
if (!Array.isArray(modules) || !modules.every((module) => typeof module === "string")) {
|
|
118
|
+
throw new Error("tool.lumera.functions.modules must be a string array");
|
|
264
119
|
}
|
|
265
|
-
|
|
120
|
+
const entrypoint = typeof rawEntrypoint === "string" ? rawEntrypoint.trim() : void 0;
|
|
121
|
+
const hasFunctions = modules.length > 0;
|
|
122
|
+
if (entrypoint || hasFunctions) {
|
|
123
|
+
return { kind: "release", appEntrypoint: entrypoint };
|
|
124
|
+
}
|
|
125
|
+
return { kind: "none" };
|
|
266
126
|
}
|
|
267
127
|
function resolveDeploymentVersion(projectRoot, gitRelease, explicitVersion) {
|
|
268
128
|
return explicitVersion || process.env.LUMERA_APP_VERSION?.trim() || resolveVersion(projectRoot, gitRelease);
|
|
269
129
|
}
|
|
270
|
-
async function
|
|
271
|
-
console.log(pc.cyan("Deploying
|
|
272
|
-
await
|
|
273
|
-
|
|
130
|
+
async function deployProjectRuntime(options) {
|
|
131
|
+
console.log(pc.cyan("Deploying project runtime..."));
|
|
132
|
+
const result = await runReleaseRunner(
|
|
133
|
+
buildReleaseRunnerArgs(
|
|
134
|
+
"deploy-project",
|
|
135
|
+
["--project", options.projectExternalId],
|
|
136
|
+
options.projectRoot
|
|
137
|
+
),
|
|
138
|
+
options.projectRoot,
|
|
139
|
+
void 0,
|
|
140
|
+
{
|
|
141
|
+
...process.env,
|
|
142
|
+
LUMERA_BASE_URL: options.apiUrl,
|
|
143
|
+
LUMERA_TOKEN: options.token
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
if (result.code !== 0 || !result.envelope.ok) {
|
|
147
|
+
const error = result.envelope.error;
|
|
148
|
+
throw new Error(error?.message || "Project runtime deployment failed");
|
|
149
|
+
}
|
|
150
|
+
console.log(pc.green("Project runtime deployed!"));
|
|
274
151
|
}
|
|
275
152
|
async function deployAppAPI(options) {
|
|
276
153
|
const gitRelease = resolveGitReleaseState(options.projectRoot);
|
|
277
154
|
assertDeployableGitRelease(gitRelease);
|
|
278
|
-
const
|
|
155
|
+
const runtime = resolveConfiguredProjectRuntime(options.projectRoot);
|
|
156
|
+
if (runtime.kind === "none" || !runtime.appEntrypoint) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
"App API not found. Configure tool.lumera.release.app-entrypoint."
|
|
159
|
+
);
|
|
160
|
+
}
|
|
279
161
|
const version = resolveDeploymentVersion(options.projectRoot, gitRelease, options.version);
|
|
280
162
|
console.log(pc.dim(`Version: ${version}`));
|
|
281
|
-
await
|
|
163
|
+
await deployProjectRuntime({
|
|
282
164
|
apiUrl: options.apiUrl,
|
|
283
165
|
token: options.token,
|
|
284
166
|
projectExternalId: options.appName,
|
|
285
|
-
|
|
286
|
-
lambdaZip
|
|
167
|
+
projectRoot: options.projectRoot
|
|
287
168
|
});
|
|
288
169
|
return version;
|
|
289
170
|
}
|
|
@@ -319,13 +200,13 @@ async function deploy(options) {
|
|
|
319
200
|
accessLevel,
|
|
320
201
|
skipAppAPI
|
|
321
202
|
} = options;
|
|
322
|
-
if (!
|
|
203
|
+
if (!existsSync(distDir)) {
|
|
323
204
|
throw new Error(`dist directory not found: ${distDir}`);
|
|
324
205
|
}
|
|
325
206
|
const projectDir = dirname(distDir);
|
|
326
207
|
const gitRelease = resolveGitReleaseState(projectDir);
|
|
327
208
|
assertDeployableGitRelease(gitRelease);
|
|
328
|
-
const
|
|
209
|
+
const projectRuntime = skipAppAPI ? { kind: "none" } : resolveConfiguredProjectRuntime(projectDir);
|
|
329
210
|
console.log(pc.dim("Ensuring app record..."));
|
|
330
211
|
await ensureAppRecord(apiUrl, token, appName, appTitle, accessLevel);
|
|
331
212
|
console.log(pc.cyan(`Preparing ${appTitle}...`));
|
|
@@ -339,13 +220,12 @@ async function deploy(options) {
|
|
|
339
220
|
if (gitRelease.sha) formData.append("git_sha", gitRelease.sha);
|
|
340
221
|
const uiVersion = resolveUIVersion(projectDir);
|
|
341
222
|
if (uiVersion) formData.append("ui_version", uiVersion);
|
|
342
|
-
if (
|
|
343
|
-
await
|
|
223
|
+
if (projectRuntime.kind !== "none") {
|
|
224
|
+
await deployProjectRuntime({
|
|
344
225
|
apiUrl,
|
|
345
226
|
token,
|
|
346
227
|
projectExternalId: appName,
|
|
347
|
-
|
|
348
|
-
lambdaZip
|
|
228
|
+
projectRoot: projectDir
|
|
349
229
|
});
|
|
350
230
|
}
|
|
351
231
|
console.log(pc.cyan(`Deploying ${appTitle} frontend...`));
|
|
@@ -391,19 +271,19 @@ async function registerDevApp(apiBase, token, appName, appTitle, appUrl) {
|
|
|
391
271
|
}
|
|
392
272
|
}
|
|
393
273
|
function isPortInUse(port, host = "127.0.0.1") {
|
|
394
|
-
return new Promise((
|
|
274
|
+
return new Promise((resolve2) => {
|
|
395
275
|
const socket = createConnection({ port, host });
|
|
396
276
|
socket.once("connect", () => {
|
|
397
277
|
socket.destroy();
|
|
398
|
-
|
|
278
|
+
resolve2(true);
|
|
399
279
|
});
|
|
400
280
|
socket.once("error", () => {
|
|
401
281
|
socket.destroy();
|
|
402
|
-
|
|
282
|
+
resolve2(false);
|
|
403
283
|
});
|
|
404
284
|
socket.setTimeout(1e3, () => {
|
|
405
285
|
socket.destroy();
|
|
406
|
-
|
|
286
|
+
resolve2(false);
|
|
407
287
|
});
|
|
408
288
|
});
|
|
409
289
|
}
|
|
@@ -423,7 +303,7 @@ function parsePackageManagerSpecifier(value) {
|
|
|
423
303
|
}
|
|
424
304
|
function packageManagerFromPackageJson(projectRoot) {
|
|
425
305
|
try {
|
|
426
|
-
const pkg = JSON.parse(readFileSync(
|
|
306
|
+
const pkg = JSON.parse(readFileSync(resolve(projectRoot, "package.json"), "utf-8"));
|
|
427
307
|
return parsePackageManagerSpecifier(pkg.packageManager);
|
|
428
308
|
} catch {
|
|
429
309
|
return void 0;
|
|
@@ -453,7 +333,7 @@ function detectRunner(projectRoot) {
|
|
|
453
333
|
];
|
|
454
334
|
for (const { pm, file } of lockfileManagers) {
|
|
455
335
|
const runner = runnerForPackageManager(pm);
|
|
456
|
-
if (
|
|
336
|
+
if (existsSync(resolve(projectRoot, file)) && commandAvailable(runner[0])) return runner;
|
|
457
337
|
}
|
|
458
338
|
for (const pm of ["pnpm", "bun", "yarn", "npm"]) {
|
|
459
339
|
const runner = runnerForPackageManager(pm);
|
|
@@ -506,8 +386,8 @@ async function dev(options) {
|
|
|
506
386
|
);
|
|
507
387
|
const runner = detectRunner(projectRoot);
|
|
508
388
|
const viteArgs = ["vite", "--port", String(port), "--strictPort"];
|
|
509
|
-
const sandboxConfig =
|
|
510
|
-
if (
|
|
389
|
+
const sandboxConfig = resolve(projectRoot, "vite.sandbox.config.ts");
|
|
390
|
+
if (existsSync(sandboxConfig)) {
|
|
511
391
|
viteArgs.push("--config", "vite.sandbox.config.ts");
|
|
512
392
|
}
|
|
513
393
|
if (host) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/lib/project-runtime-config.ts
|
|
2
|
+
import { parse } from "smol-toml";
|
|
3
|
+
function parseProjectTOML(source) {
|
|
4
|
+
try {
|
|
5
|
+
return parse(source);
|
|
6
|
+
} catch (error) {
|
|
7
|
+
throw new Error(`Invalid pyproject.toml: ${error instanceof Error ? error.message : String(error)}`);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function projectConfigTable(document, ...path) {
|
|
11
|
+
let table = document;
|
|
12
|
+
for (let index = 0; index < path.length; index++) {
|
|
13
|
+
const value = table[path[index]];
|
|
14
|
+
if (value === void 0) return {};
|
|
15
|
+
if (value === null || typeof value !== "object" || Array.isArray(value) || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
|
|
16
|
+
throw new Error(`pyproject.toml ${path.slice(0, index + 1).join(".")} must be a table`);
|
|
17
|
+
}
|
|
18
|
+
table = value;
|
|
19
|
+
}
|
|
20
|
+
return table;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
parseProjectTOML,
|
|
25
|
+
projectConfigTable
|
|
26
|
+
};
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FUNCTIONS_SDK_REQUIREMENT
|
|
3
|
+
} from "./chunk-5FGDEZSJ.js";
|
|
4
|
+
|
|
1
5
|
// src/commands/functions.ts
|
|
2
6
|
import { spawn } from "child_process";
|
|
3
7
|
import { existsSync } from "fs";
|
|
4
8
|
import { join, resolve } from "path";
|
|
5
9
|
import pc from "picocolors";
|
|
6
|
-
|
|
7
|
-
// src/lib/functions-sdk.ts
|
|
8
|
-
var FUNCTIONS_SDK_VERSION_RANGE = ">=0.43.0,<0.44.0";
|
|
9
|
-
var FUNCTIONS_SDK_COMPATIBILITY_RANGE = ">=0.34.0,<0.44.0";
|
|
10
|
-
var FUNCTIONS_SDK_REQUIREMENT = `lumera[functions]${FUNCTIONS_SDK_COMPATIBILITY_RANGE}`;
|
|
11
|
-
var DEFAULT_FUNCTIONS_SDK_REQUIREMENT = `lumera[functions]${FUNCTIONS_SDK_VERSION_RANGE}`;
|
|
12
|
-
var RELEASE_SDK_REQUIREMENT = `lumera[release]${FUNCTIONS_SDK_VERSION_RANGE}`;
|
|
13
|
-
|
|
14
|
-
// src/commands/functions.ts
|
|
15
10
|
var SUPPORTED_SUBCOMMANDS = /* @__PURE__ */ new Set(["list", "inspect", "invoke", "test"]);
|
|
16
11
|
var FUNCTIONS_RUNNER_PROTOCOL_VERSION = 1;
|
|
17
12
|
function errorMessage(error, fallback) {
|
|
@@ -223,7 +218,6 @@ async function functions(subcommand, args, dependencies = {}) {
|
|
|
223
218
|
}
|
|
224
219
|
|
|
225
220
|
export {
|
|
226
|
-
RELEASE_SDK_REQUIREMENT,
|
|
227
221
|
emitFunctionCliFailure,
|
|
228
222
|
findFunctionsProjectRoot,
|
|
229
223
|
buildFunctionRunnerArgs,
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
dev
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-P6GDSHYC.js";
|
|
4
|
+
import "./chunk-UGAIWMQV.js";
|
|
5
|
+
import "./chunk-2EHJH2QU.js";
|
|
6
|
+
import "./chunk-XZ5VCTGY.js";
|
|
7
|
+
import "./chunk-5FGDEZSJ.js";
|
|
4
8
|
import {
|
|
5
9
|
syncDeps
|
|
6
10
|
} from "./chunk-5JNNUIVJ.js";
|
package/dist/index.js
CHANGED
|
@@ -242,40 +242,40 @@ async function main() {
|
|
|
242
242
|
switch (command) {
|
|
243
243
|
// Resource commands
|
|
244
244
|
case "plan":
|
|
245
|
-
await import("./resources-
|
|
245
|
+
await import("./resources-IGHWATTH.js").then((m) => m.plan(args.slice(1)));
|
|
246
246
|
break;
|
|
247
247
|
case "apply":
|
|
248
|
-
await import("./resources-
|
|
248
|
+
await import("./resources-IGHWATTH.js").then((m) => m.apply(args.slice(1)));
|
|
249
249
|
break;
|
|
250
250
|
case "pull":
|
|
251
|
-
await import("./resources-
|
|
251
|
+
await import("./resources-IGHWATTH.js").then((m) => m.pull(args.slice(1)));
|
|
252
252
|
break;
|
|
253
253
|
case "destroy":
|
|
254
|
-
await import("./resources-
|
|
254
|
+
await import("./resources-IGHWATTH.js").then((m) => m.destroy(args.slice(1)));
|
|
255
255
|
break;
|
|
256
256
|
case "list":
|
|
257
|
-
await import("./resources-
|
|
257
|
+
await import("./resources-IGHWATTH.js").then((m) => m.list(args.slice(1)));
|
|
258
258
|
break;
|
|
259
259
|
case "show":
|
|
260
|
-
await import("./resources-
|
|
260
|
+
await import("./resources-IGHWATTH.js").then((m) => m.show(args.slice(1)));
|
|
261
261
|
break;
|
|
262
262
|
case "diff":
|
|
263
|
-
await import("./resources-
|
|
263
|
+
await import("./resources-IGHWATTH.js").then((m) => m.diff(args.slice(1)));
|
|
264
264
|
break;
|
|
265
265
|
// Development
|
|
266
266
|
case "dev":
|
|
267
|
-
await import("./dev-
|
|
267
|
+
await import("./dev-24PCZUAT.js").then((m) => m.dev(args.slice(1)));
|
|
268
268
|
break;
|
|
269
269
|
case "run":
|
|
270
270
|
await import("./run-4XFA5ZDJ.js").then((m) => m.run(args.slice(1)));
|
|
271
271
|
break;
|
|
272
272
|
case "functions":
|
|
273
|
-
await import("./functions-
|
|
273
|
+
await import("./functions-5OOHGQT7.js").then(
|
|
274
274
|
(m) => m.functions(subcommand, args.slice(2))
|
|
275
275
|
);
|
|
276
276
|
break;
|
|
277
277
|
case "project":
|
|
278
|
-
await import("./project-
|
|
278
|
+
await import("./project-ISKXDHGJ.js").then(
|
|
279
279
|
(m) => m.project(subcommand, args.slice(2))
|
|
280
280
|
);
|
|
281
281
|
break;
|
|
@@ -293,7 +293,7 @@ async function main() {
|
|
|
293
293
|
await import("./status-NPNIY3QP.js").then((m) => m.status(args.slice(1)));
|
|
294
294
|
break;
|
|
295
295
|
case "migrate":
|
|
296
|
-
await import("./migrate-
|
|
296
|
+
await import("./migrate-DHNR3ESM.js").then((m) => m.migrate(args.slice(1)));
|
|
297
297
|
break;
|
|
298
298
|
// Skills
|
|
299
299
|
case "skills":
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseProjectTOML,
|
|
3
|
+
projectConfigTable
|
|
4
|
+
} from "./chunk-UGAIWMQV.js";
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_FUNCTIONS_SDK_REQUIREMENT
|
|
7
|
+
} from "./chunk-5FGDEZSJ.js";
|
|
1
8
|
import {
|
|
2
9
|
detectProjectVersion,
|
|
3
10
|
findProjectRoot
|
|
@@ -6,12 +13,15 @@ import "./chunk-PNKVD2UK.js";
|
|
|
6
13
|
|
|
7
14
|
// src/commands/migrate.ts
|
|
8
15
|
import pc from "picocolors";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
16
|
+
import { execFileSync } from "child_process";
|
|
17
|
+
import { existsSync, mkdirSync, renameSync, readdirSync, readFileSync, writeFileSync, rmSync, rmdirSync } from "fs";
|
|
18
|
+
import { join, resolve } from "path";
|
|
19
|
+
import { stringify } from "smol-toml";
|
|
11
20
|
function showHelp() {
|
|
12
21
|
console.log(`
|
|
13
22
|
${pc.dim("Usage:")}
|
|
14
23
|
lumera migrate [options]
|
|
24
|
+
lumera migrate app-api [--dry-run]
|
|
15
25
|
|
|
16
26
|
${pc.dim("Description:")}
|
|
17
27
|
Upgrade legacy project structure (v0) to the current structure (v1).
|
|
@@ -24,8 +34,103 @@ ${pc.dim("Options:")}
|
|
|
24
34
|
${pc.dim("Examples:")}
|
|
25
35
|
lumera migrate # Migrate to v1 structure
|
|
26
36
|
lumera migrate --dry-run # Preview migration changes
|
|
37
|
+
lumera migrate app-api # Move a ZIP App API into the project release
|
|
27
38
|
`);
|
|
28
39
|
}
|
|
40
|
+
function addReleaseAppEntrypoint(pyproject, projectRoot) {
|
|
41
|
+
const document = parseProjectTOML(pyproject);
|
|
42
|
+
const release = projectConfigTable(document, "tool", "lumera", "release");
|
|
43
|
+
const functions = projectConfigTable(document, "tool", "lumera", "functions");
|
|
44
|
+
if (release["app-entrypoint"] !== void 0) {
|
|
45
|
+
throw new Error("pyproject.toml already defines a release app-entrypoint");
|
|
46
|
+
}
|
|
47
|
+
for (const [section, config] of [["release", release], ["functions", functions]]) {
|
|
48
|
+
const source = config["source-root"];
|
|
49
|
+
if (source !== void 0 && (typeof source !== "string" || !source.trim() || resolve(projectRoot, source) !== resolve(projectRoot, "platform"))) {
|
|
50
|
+
throw new Error(`Cannot migrate App API: tool.lumera.${section}.source-root must resolve to platform. Align the source roots before migrating.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const tool = document.tool ??= {};
|
|
54
|
+
const lumera = tool.lumera ??= {};
|
|
55
|
+
lumera.release = {
|
|
56
|
+
...release,
|
|
57
|
+
"source-root": "platform",
|
|
58
|
+
"app-entrypoint": "app.server:app",
|
|
59
|
+
"runtime-abi": release["runtime-abi"] ?? "1.0"
|
|
60
|
+
};
|
|
61
|
+
return stringify(document);
|
|
62
|
+
}
|
|
63
|
+
function rewriteAppImports(source, modules) {
|
|
64
|
+
let rewritten = source;
|
|
65
|
+
for (const moduleName of modules) {
|
|
66
|
+
const escaped = moduleName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
67
|
+
rewritten = rewritten.replace(
|
|
68
|
+
new RegExp(`^(\\s*)import\\s+${escaped}(\\s*(?:#.*)?)$`, "gm"),
|
|
69
|
+
`$1from app import ${moduleName}$2`
|
|
70
|
+
);
|
|
71
|
+
rewritten = rewritten.replace(
|
|
72
|
+
new RegExp(`^(\\s*)from\\s+${escaped}\\s+import\\s+`, "gm"),
|
|
73
|
+
`$1from app.${moduleName} import `
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return rewritten;
|
|
77
|
+
}
|
|
78
|
+
function migrateAppAPI(projectRoot, dryRun) {
|
|
79
|
+
const legacyDir = join(projectRoot, "app-api", "lambda");
|
|
80
|
+
const destination = join(projectRoot, "platform", "app");
|
|
81
|
+
const pyprojectPath = join(projectRoot, "pyproject.toml");
|
|
82
|
+
if (!existsSync(join(legacyDir, "server.py"))) {
|
|
83
|
+
throw new Error("Legacy App API not found at app-api/lambda/server.py");
|
|
84
|
+
}
|
|
85
|
+
if (existsSync(destination)) {
|
|
86
|
+
throw new Error("platform/app already exists; resolve it before migrating the ZIP App API");
|
|
87
|
+
}
|
|
88
|
+
if (!existsSync(pyprojectPath)) {
|
|
89
|
+
throw new Error("pyproject.toml is required for a project release");
|
|
90
|
+
}
|
|
91
|
+
addReleaseAppEntrypoint(readFileSync(pyprojectPath, "utf8"), projectRoot);
|
|
92
|
+
console.log(pc.bold("App API migration plan:"));
|
|
93
|
+
console.log(pc.yellow(" \u2192 app-api/lambda/ \u2192 platform/app/"));
|
|
94
|
+
console.log(pc.blue(" \u270E rewrite local Python imports as app package imports"));
|
|
95
|
+
console.log(pc.blue(" \u270E merge requirements.txt into pyproject.toml and uv.lock"));
|
|
96
|
+
console.log(pc.blue(' \u270E configure app-entrypoint = "app.server:app"'));
|
|
97
|
+
if (dryRun) {
|
|
98
|
+
console.log(pc.dim("\nDry run - no changes made."));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const requirements = join(legacyDir, "requirements.txt");
|
|
102
|
+
if (existsSync(requirements) && readFileSync(requirements, "utf8").trim()) {
|
|
103
|
+
execFileSync("uv", ["add", "-r", requirements], { cwd: projectRoot, stdio: "inherit" });
|
|
104
|
+
}
|
|
105
|
+
execFileSync("uv", ["add", DEFAULT_FUNCTIONS_SDK_REQUIREMENT], {
|
|
106
|
+
cwd: projectRoot,
|
|
107
|
+
stdio: "inherit"
|
|
108
|
+
});
|
|
109
|
+
mkdirSync(join(projectRoot, "platform"), { recursive: true });
|
|
110
|
+
renameSync(legacyDir, destination);
|
|
111
|
+
rmSync(join(destination, "requirements.txt"), { force: true });
|
|
112
|
+
if (!existsSync(join(destination, "__init__.py"))) {
|
|
113
|
+
writeFileSync(join(destination, "__init__.py"), "", "utf8");
|
|
114
|
+
}
|
|
115
|
+
const modules = new Set(
|
|
116
|
+
readdirSync(destination, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".py")).map((entry) => entry.name.slice(0, -3)).filter((name) => name !== "__init__")
|
|
117
|
+
);
|
|
118
|
+
for (const entry of readdirSync(destination, { withFileTypes: true })) {
|
|
119
|
+
if (!entry.isFile() || !entry.name.endsWith(".py")) continue;
|
|
120
|
+
const path = join(destination, entry.name);
|
|
121
|
+
writeFileSync(path, rewriteAppImports(readFileSync(path, "utf8"), modules), "utf8");
|
|
122
|
+
}
|
|
123
|
+
writeFileSync(
|
|
124
|
+
pyprojectPath,
|
|
125
|
+
addReleaseAppEntrypoint(readFileSync(pyprojectPath, "utf8"), projectRoot),
|
|
126
|
+
"utf8"
|
|
127
|
+
);
|
|
128
|
+
const legacyParent = join(projectRoot, "app-api");
|
|
129
|
+
if (readdirSync(legacyParent).length === 0) {
|
|
130
|
+
rmdirSync(legacyParent);
|
|
131
|
+
}
|
|
132
|
+
console.log(pc.green("\nApp API migration complete. Review imports and paths relative to the project root, commit the migrated project, then run `lumera apply app`."));
|
|
133
|
+
}
|
|
29
134
|
async function migrate(args) {
|
|
30
135
|
if (args.includes("--help") || args.includes("-h")) {
|
|
31
136
|
showHelp();
|
|
@@ -39,6 +144,10 @@ async function migrate(args) {
|
|
|
39
144
|
console.error(pc.red("Not in a Lumera project directory."));
|
|
40
145
|
process.exit(1);
|
|
41
146
|
}
|
|
147
|
+
if (args[0] === "app-api") {
|
|
148
|
+
migrateAppAPI(projectRoot, dryRun);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
42
151
|
const version = detectProjectVersion(projectRoot);
|
|
43
152
|
if (version === 1) {
|
|
44
153
|
console.log(pc.green("Project is already using v1 structure."));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildReleaseRunnerArgs,
|
|
3
|
+
project,
|
|
4
|
+
runReleaseRunner
|
|
5
|
+
} from "./chunk-2EHJH2QU.js";
|
|
6
|
+
import "./chunk-XZ5VCTGY.js";
|
|
7
|
+
import "./chunk-5FGDEZSJ.js";
|
|
8
|
+
import "./chunk-PNKVD2UK.js";
|
|
9
|
+
export {
|
|
10
|
+
buildReleaseRunnerArgs,
|
|
11
|
+
project,
|
|
12
|
+
runReleaseRunner
|
|
13
|
+
};
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
deploy,
|
|
3
3
|
deployAppAPI
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-P6GDSHYC.js";
|
|
5
|
+
import "./chunk-UGAIWMQV.js";
|
|
6
|
+
import "./chunk-2EHJH2QU.js";
|
|
7
|
+
import "./chunk-XZ5VCTGY.js";
|
|
8
|
+
import "./chunk-5FGDEZSJ.js";
|
|
5
9
|
import {
|
|
6
10
|
syncDeps
|
|
7
11
|
} from "./chunk-5JNNUIVJ.js";
|
|
@@ -1563,8 +1567,8 @@ ${pc2.dim("Resources:")}
|
|
|
1563
1567
|
|
|
1564
1568
|
${pc2.dim("Options:")}
|
|
1565
1569
|
--yes, -y Skip confirmation prompt (for CI/CD)
|
|
1566
|
-
--skip-build Skip the frontend build; still
|
|
1567
|
-
--skip-app-api Publish only the frontend
|
|
1570
|
+
--skip-build Skip the frontend build; still deploy the project runtime
|
|
1571
|
+
--skip-app-api Publish only the frontend without deploying the project runtime
|
|
1568
1572
|
--no-app Apply resources only; do not build/deploy the app
|
|
1569
1573
|
--resources-only Alias for --no-app
|
|
1570
1574
|
--package-manager Package manager for app builds (pnpm, bun, yarn, npm)
|
|
@@ -1576,7 +1580,7 @@ ${pc2.dim("Examples:")}
|
|
|
1576
1580
|
lumera apply agents -y # Apply agents without confirmation
|
|
1577
1581
|
lumera apply app # Deploy frontend and App API
|
|
1578
1582
|
lumera apply app-api # Deploy only the App API
|
|
1579
|
-
lumera apply app --skip-build # Reuse dist;
|
|
1583
|
+
lumera apply app --skip-build # Reuse dist; deploy the project runtime
|
|
1580
1584
|
lumera apply app --skip-app-api # Deploy only the frontend
|
|
1581
1585
|
lumera apply --no-app -y # Apply resources without app build/deploy
|
|
1582
1586
|
lumera apply app --package-manager pnpm
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumerahq/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.3",
|
|
4
4
|
"description": "CLI for building and deploying Lumera apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"dotenv": "^16.4.7",
|
|
26
26
|
"open": "^10.1.0",
|
|
27
27
|
"picocolors": "^1.1.1",
|
|
28
|
-
"prompts": "^2.4.2"
|
|
28
|
+
"prompts": "^2.4.2",
|
|
29
|
+
"smol-toml": "^1.9.0"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@types/archiver": "^6.0.3",
|
|
@@ -27,8 +27,9 @@ Keep critical safety rules and user preferences that apply to every task here.
|
|
|
27
27
|
- Read only relevant topics when needed; search if necessary. Do not load every
|
|
28
28
|
topic or use automatic file imports.
|
|
29
29
|
- Organize by topic, not turn or date. Update existing notes, merge duplicates,
|
|
30
|
-
and remove outdated material.
|
|
31
|
-
|
|
30
|
+
and remove outdated material. Update memory at most once per turn, after the
|
|
31
|
+
work is done, and say in one sentence what was noted. Keep memory files in
|
|
32
|
+
version control and check this file's size and links after changes.
|
|
32
33
|
- Keep secrets out of memory. Link to source documents rather than copying them.
|
|
33
34
|
Data the app needs belongs in collections or app configuration.
|
|
34
35
|
|
|
@@ -4,7 +4,7 @@ version = "0.1.0"
|
|
|
4
4
|
description = "{{projectTitle}} - Lumera custom app"
|
|
5
5
|
requires-python = ">=3.11"
|
|
6
6
|
dependencies = [
|
|
7
|
-
"lumera[functions]>=0.
|
|
7
|
+
"lumera[functions]>=0.45.0,<0.46.0",
|
|
8
8
|
]
|
|
9
9
|
|
|
10
10
|
[project.optional-dependencies]
|
|
@@ -17,3 +17,7 @@ dev = [
|
|
|
17
17
|
source-root = "platform"
|
|
18
18
|
modules = []
|
|
19
19
|
test-paths = ["tests/functions"]
|
|
20
|
+
|
|
21
|
+
[tool.lumera.release]
|
|
22
|
+
source-root = "platform"
|
|
23
|
+
runtime-abi = "1.0"
|