@lumerahq/cli 0.19.25 → 0.20.0-dev.0
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 +3 -0
- package/dist/flags-AVQEXEDT.js +89 -0
- package/dist/index.js +11 -0
- package/package.json +2 -1
- package/templates/default/AGENTS.md +18 -12
- package/templates/default/platform/agents/.gitkeep +0 -0
package/README.md
CHANGED
|
@@ -32,6 +32,9 @@ lumera show <resource> # Show resource details
|
|
|
32
32
|
lumera destroy # Delete remote resources
|
|
33
33
|
|
|
34
34
|
lumera run <target> # Run script, automation, or invoke agent
|
|
35
|
+
|
|
36
|
+
lumera flags list # List this sandbox's feature flags
|
|
37
|
+
lumera flags get <key> # Print one flag's value (--default <v> if unset)
|
|
35
38
|
```
|
|
36
39
|
|
|
37
40
|
## Scaffolding Projects
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import "./chunk-PNKVD2UK.js";
|
|
2
|
+
|
|
3
|
+
// src/commands/flags.ts
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
|
|
6
|
+
// src/lib/flags.ts
|
|
7
|
+
import { readFileSync, statSync } from "fs";
|
|
8
|
+
var ENV_PATH = "LUMERA_FEATURE_FLAGS_PATH";
|
|
9
|
+
var DEFAULT_PATH = "/opt/lumera/feature-flags/flags.json";
|
|
10
|
+
function flagsPath() {
|
|
11
|
+
return process.env[ENV_PATH] || DEFAULT_PATH;
|
|
12
|
+
}
|
|
13
|
+
var cache = null;
|
|
14
|
+
function featureFlags() {
|
|
15
|
+
const path = flagsPath();
|
|
16
|
+
let key;
|
|
17
|
+
try {
|
|
18
|
+
key = `${path}:${statSync(path).mtimeMs}`;
|
|
19
|
+
} catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
if (cache && cache.key === key) return cache.flags;
|
|
23
|
+
let flags2 = {};
|
|
24
|
+
try {
|
|
25
|
+
const data = JSON.parse(readFileSync(path, "utf-8"));
|
|
26
|
+
if (data && typeof data === "object" && data.flags && typeof data.flags === "object") {
|
|
27
|
+
flags2 = data.flags;
|
|
28
|
+
}
|
|
29
|
+
} catch {
|
|
30
|
+
flags2 = {};
|
|
31
|
+
}
|
|
32
|
+
cache = { key, flags: flags2 };
|
|
33
|
+
return flags2;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/commands/flags.ts
|
|
37
|
+
async function flags(subcommand, args) {
|
|
38
|
+
switch (subcommand) {
|
|
39
|
+
case "get": {
|
|
40
|
+
const key = args[0];
|
|
41
|
+
if (!key) {
|
|
42
|
+
console.error(pc.red("Usage: lumera flags get <key> [--default <value>]"));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const defIdx = args.indexOf("--default");
|
|
46
|
+
const fallback = defIdx !== -1 ? args[defIdx + 1] : void 0;
|
|
47
|
+
const all = featureFlags();
|
|
48
|
+
if (!(key in all)) {
|
|
49
|
+
if (fallback !== void 0) {
|
|
50
|
+
console.log(fallback);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
printValue(all[key]);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
case void 0:
|
|
59
|
+
case "list": {
|
|
60
|
+
const all = featureFlags();
|
|
61
|
+
if (process.env.LUMERA_JSON === "1") {
|
|
62
|
+
console.log(JSON.stringify(all, null, 2));
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
const keys = Object.keys(all).sort();
|
|
66
|
+
if (keys.length === 0) {
|
|
67
|
+
console.log(pc.dim("No feature flags available."));
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
for (const k of keys) {
|
|
71
|
+
console.log(`${pc.cyan(k)} = ${formatValue(all[k])}`);
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
console.error(pc.red(`Unknown flags subcommand: ${subcommand}`));
|
|
77
|
+
console.error("Usage: lumera flags [list | get <key> [--default <value>]]");
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function formatValue(v) {
|
|
82
|
+
return typeof v === "string" ? v : JSON.stringify(v);
|
|
83
|
+
}
|
|
84
|
+
function printValue(v) {
|
|
85
|
+
console.log(formatValue(v));
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
flags
|
|
89
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -95,6 +95,7 @@ var COMMANDS = [
|
|
|
95
95
|
"migrate",
|
|
96
96
|
"skills",
|
|
97
97
|
"deps",
|
|
98
|
+
"flags",
|
|
98
99
|
"login",
|
|
99
100
|
"logout",
|
|
100
101
|
"whoami"
|
|
@@ -162,6 +163,10 @@ ${pc.dim("Skills:")}
|
|
|
162
163
|
${pc.cyan("skills install")} Install skills
|
|
163
164
|
${pc.cyan("skills update")} Update skills
|
|
164
165
|
|
|
166
|
+
${pc.dim("Feature Flags:")}
|
|
167
|
+
${pc.cyan("flags list")} List feature flags in this sandbox
|
|
168
|
+
${pc.cyan("flags get")} <key> Print one flag's value (--default <v> if unset)
|
|
169
|
+
|
|
165
170
|
${pc.dim("Auth:")}
|
|
166
171
|
${pc.cyan("login")} Login to Lumera
|
|
167
172
|
${pc.cyan("logout")} Clear credentials
|
|
@@ -189,6 +194,8 @@ ${pc.dim("Examples:")}
|
|
|
189
194
|
lumera run automations/sync # Trigger automation
|
|
190
195
|
lumera run agents/support "Hello" # Invoke an agent
|
|
191
196
|
lumera dev # Start dev server
|
|
197
|
+
lumera flags list # List this sandbox's feature flags
|
|
198
|
+
lumera flags get studio_browser --default false # one flag (fallback if unset)
|
|
192
199
|
|
|
193
200
|
${pc.dim("Documentation:")}
|
|
194
201
|
https://docs.lumerahq.com/cli
|
|
@@ -270,6 +277,10 @@ async function main() {
|
|
|
270
277
|
case "deps":
|
|
271
278
|
await import("./deps-HWO6X5WM.js").then((m) => m.deps(args.slice(1)));
|
|
272
279
|
break;
|
|
280
|
+
// Feature flags (read the in-sandbox snapshot)
|
|
281
|
+
case "flags":
|
|
282
|
+
await import("./flags-AVQEXEDT.js").then((m) => m.flags(subcommand, args.slice(2)));
|
|
283
|
+
break;
|
|
273
284
|
// Auth
|
|
274
285
|
case "login":
|
|
275
286
|
await import("./auth-NI7JTMJM.js").then((m) => m.login(args.slice(1)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumerahq/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0-dev.0",
|
|
4
4
|
"description": "CLI for building and deploying Lumera apps",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsup src/index.ts --format esm --clean",
|
|
18
18
|
"dev": "tsup src/index.ts --format esm --watch",
|
|
19
|
+
"test": "rm -rf dist-test && tsc -p tsconfig.test.json && node --test 'dist-test/**/*.test.js'",
|
|
19
20
|
"prepublishOnly": "pnpm build"
|
|
20
21
|
},
|
|
21
22
|
"dependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# {{projectTitle}}
|
|
2
2
|
|
|
3
|
-
A Lumera app built with collections, automations, hooks, and a React frontend.
|
|
3
|
+
A Lumera app built with collections, automations, hooks, custom agents, and a React frontend.
|
|
4
4
|
|
|
5
5
|
## Project Structure
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@ A Lumera app built with collections, automations, hooks, and a React frontend.
|
|
|
8
8
|
platform/
|
|
9
9
|
├── collections/ # Collection schemas (JSON) — deployed via lumera apply
|
|
10
10
|
├── automations/ # Python automations (config.json + run.py per automation)
|
|
11
|
+
├── agents/ # Custom AI agents (config.json + system_prompt.md + optional policy.js)
|
|
11
12
|
├── hooks/ # JavaScript hooks on collection lifecycle events
|
|
12
13
|
src/
|
|
13
14
|
├── routes/index.tsx # Home page
|
|
@@ -29,6 +30,7 @@ A Lumera app is built from these primitives — all defined as code in `platform
|
|
|
29
30
|
|
|
30
31
|
- **Collections** (`platform/collections/*.json`) — Data tables with typed fields. Deployed via `lumera apply`.
|
|
31
32
|
- **Automations** (`platform/automations/*/`) — Python scripts that run on Lumera's servers. Each has a `config.json` and `run.py`.
|
|
33
|
+
- **Custom agents** (`platform/agents/*/`) — AI-powered agents with prompts, skills, optional policies, and reusable sessions. Use them for classification, extraction, enrichment, drafting, guided review, and tool-heavy workflows. When creating or changing agents, read the Building Agents skill first.
|
|
32
34
|
- **Hooks** (`platform/hooks/*.js`) — JavaScript on collection lifecycle events (`before_create`, `after_update`, etc.).
|
|
33
35
|
- **Webhooks** — Receive events from external services (Stripe, GitHub, etc.). Events land in `lm_event_log`; process them with hooks or automations.
|
|
34
36
|
- **Mailbox** — Each tenant gets an email address. Inbound emails are persisted to `lm_mailbox_messages` — use hooks to trigger automations on new mail.
|
|
@@ -151,22 +153,26 @@ changes, tell them to open the **Preview tab**.
|
|
|
151
153
|
|
|
152
154
|
## Workflow
|
|
153
155
|
|
|
154
|
-
Follow the user's lead. If they tell you exactly what to build, build it. The workflow below is the default when they describe a goal and leave the approach to you.
|
|
156
|
+
Follow the user's lead. If they tell you exactly what to build and no critical unknowns block correctness, build it. If critical unknowns exist, ask before encoding assumptions. The workflow below is the default when they describe a goal and leave the approach to you.
|
|
155
157
|
|
|
156
|
-
### Step 1: Plan
|
|
158
|
+
### Step 1: Understand and Plan
|
|
157
159
|
1. **Read skills first** — Read the matching skill files for API details and patterns.
|
|
158
|
-
2. **
|
|
159
|
-
3. **
|
|
160
|
+
2. **Decide one-off vs repeatable** — Determine whether the user needs a one-off answer/artifact or a repeatable workflow. For one-off tasks, answer the question, analyze the data, or produce the requested artifact directly; do not build an app unless the user asks. Propose an app, automation, agent, or durable workflow only when the process will be reused.
|
|
161
|
+
3. **Inspect uploaded files** — If the user uploaded files, inspect them before planning. Identify what each file represents: one-time input data, recurring source data, configuration data, mapping/lookup tables, business rules or domain knowledge, templates, expected input/output examples, exports from another system, or debugging evidence. Decide whether each file should be used only for this turn, stored as durable configuration/reference data, imported into collections, converted into an automation input, or preserved as documentation/examples.
|
|
162
|
+
4. **Identify critical unknowns** — Before proposing or building, list unknowns that affect correctness in real use. Pay special attention to source-of-truth data, ownership/assignment/approval rules, escalation or routing rules, permissions/roles/access control, integrations and required scopes, identifiers and mappings between systems, and what should happen when required data is missing.
|
|
163
|
+
5. **Ask blockers, state assumptions** — Ask concise clarifying questions for blockers. Do not silently create manual lookup tables, fallback rules, durable apps, or business assumptions unless the user explicitly accepts them. For non-blocking details, state your assumption and proceed.
|
|
164
|
+
6. **Discuss the plan** — Propose the **smallest validated useful slice**: a complete horizontal slice that proves the workflow with real data and realistic edge cases. Propose incremental steps that layer on complexity; if decisions are obvious, you can execute multiple steps in one go.
|
|
165
|
+
7. **Stop and ask the user to approve.** Iterate until they're happy with the plan. They may reorder steps, drop features, or add ones you didn't think of.
|
|
160
166
|
|
|
161
167
|
### Step 2: Build (one slice at a time)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
168
|
+
1. **Build horizontally** — Pick the first step. Build the full slice: collection schema and/or agent definition → `lumera apply` → seed data → UI route/components → commit. Each slice should be deployable and usable on its own.
|
|
169
|
+
2. **Stop and ask for feedback** — Tell the user to open the **Preview tab** to see the app. Do not mention local dev-server commands or localhost URLs. Iterate on the slice until they're happy.
|
|
170
|
+
3. **Repeat** — Move to the next step. Build, deploy, get feedback.
|
|
165
171
|
|
|
166
172
|
### Rules
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
173
|
+
1. **Code is source of truth** — Edit files in `platform/`, then deploy with `lumera apply`. Don't edit in the Lumera UI.
|
|
174
|
+
2. **Keep docs current** — After each slice, update `architecture.md` with what was built (data models, relationships, hook logic, design decisions). Also update the project description at the top of this file (`AGENTS.md`) so it reflects what the project actually does now — not the original template description.
|
|
175
|
+
3. **Commit and push** — After each slice or significant change, stage your changes, create a meaningful commit with both a title and description, then push. The sandbox is ephemeral — uncommitted work is lost if recycled.
|
|
170
176
|
- Use a conventional subject (`feat:`, `fix:`, `chore:`, `docs:`, `test:`) that explains the user-visible change, not just the filenames.
|
|
171
177
|
- Include a body that describes why the change was needed, what you changed, and the main areas covered.
|
|
172
178
|
- Avoid generic messages like `update files`, `changes`, `WIP`, or filename-only summaries.
|
|
@@ -187,7 +193,7 @@ Follow the user's lead. If they tell you exactly what to build, build it. The wo
|
|
|
187
193
|
)"
|
|
188
194
|
git push
|
|
189
195
|
```
|
|
190
|
-
|
|
196
|
+
4. **Deploy marker** — When your changes need `lumera apply`, include at the end of your response: `<!-- DEPLOY: short commit message -->`. Skip for frontend-only changes.
|
|
191
197
|
|
|
192
198
|
## File Artifacts
|
|
193
199
|
|
|
File without changes
|