@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 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.19.25",
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. **Discuss the plan** — Start from the **simplest thing that works** one collection, one screen, one feature. Propose incremental steps that layer on complexity but if the decisions are obvious, you can execute multiple steps in one go. Each step should be a complete horizontal slice (collection + backend logic + UI).
159
- 3. **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
+ 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
- 4. **Build horizontally** — Pick the first step. Build the full slice: collection schema → `lumera apply` → seed data → UI route/components → commit. Each slice should be deployable and usable on its own.
163
- 5. **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.
164
- 6. **Repeat** — Move to the next step. Build, deploy, get feedback.
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
- 7. **Code is source of truth** — Edit files in `platform/`, then deploy with `lumera apply`. Don't edit in the Lumera UI.
168
- 8. **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.
169
- 9. **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.
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
- 10. **Deploy marker** — When your changes need `lumera apply`, include at the end of your response: `<!-- DEPLOY: short commit message -->`. Skip for frontend-only changes.
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