@lumerahq/cli 0.7.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 +118 -0
- package/dist/auth-7RGL7GXU.js +311 -0
- package/dist/chunk-2CR762KB.js +18 -0
- package/dist/chunk-AVKPM7C4.js +199 -0
- package/dist/chunk-D2BLSEGR.js +59 -0
- package/dist/chunk-NDLYGKS6.js +77 -0
- package/dist/chunk-V2XXMMEI.js +147 -0
- package/dist/dev-UTZC4ZJ7.js +87 -0
- package/dist/index.js +157 -0
- package/dist/init-OQCIET53.js +363 -0
- package/dist/migrate-2DZ6RQ5K.js +190 -0
- package/dist/resources-PNK3NESI.js +1350 -0
- package/dist/run-4NDI2CN4.js +257 -0
- package/dist/skills-56EUKHGY.js +414 -0
- package/dist/status-BEVUV6RY.js +131 -0
- package/package.json +37 -0
- package/templates/default/CLAUDE.md +245 -0
- package/templates/default/README.md +59 -0
- package/templates/default/biome.json +33 -0
- package/templates/default/index.html +13 -0
- package/templates/default/package.json.hbs +46 -0
- package/templates/default/platform/automations/.gitkeep +0 -0
- package/templates/default/platform/collections/example_items.json +28 -0
- package/templates/default/platform/hooks/.gitkeep +0 -0
- package/templates/default/pyproject.toml.hbs +14 -0
- package/templates/default/scripts/seed-demo.py +35 -0
- package/templates/default/src/components/Sidebar.tsx +84 -0
- package/templates/default/src/components/StatCard.tsx +31 -0
- package/templates/default/src/components/layout.tsx +13 -0
- package/templates/default/src/lib/queries.ts +27 -0
- package/templates/default/src/main.tsx +137 -0
- package/templates/default/src/routes/__root.tsx +10 -0
- package/templates/default/src/routes/index.tsx +90 -0
- package/templates/default/src/routes/settings.tsx +25 -0
- package/templates/default/src/styles.css +40 -0
- package/templates/default/tsconfig.json +23 -0
- package/templates/default/vite.config.ts +27 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getToken,
|
|
3
|
+
getTokenSource
|
|
4
|
+
} from "./chunk-NDLYGKS6.js";
|
|
5
|
+
import {
|
|
6
|
+
detectProjectVersion,
|
|
7
|
+
findProjectRoot,
|
|
8
|
+
getAppName,
|
|
9
|
+
getAppTitle,
|
|
10
|
+
getBaseUrl,
|
|
11
|
+
readPackageJson
|
|
12
|
+
} from "./chunk-D2BLSEGR.js";
|
|
13
|
+
|
|
14
|
+
// src/commands/status.ts
|
|
15
|
+
import pc from "picocolors";
|
|
16
|
+
import { existsSync, readdirSync } from "fs";
|
|
17
|
+
import { join } from "path";
|
|
18
|
+
async function validateToken(token) {
|
|
19
|
+
const baseUrl = getBaseUrl();
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(`${baseUrl}/api/me`, {
|
|
22
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
23
|
+
});
|
|
24
|
+
if (!response.ok) {
|
|
25
|
+
return { valid: false, error: `${response.status} ${response.statusText}` };
|
|
26
|
+
}
|
|
27
|
+
const data = await response.json();
|
|
28
|
+
return {
|
|
29
|
+
valid: true,
|
|
30
|
+
user: data.user?.email,
|
|
31
|
+
company: data.user?.company?.name
|
|
32
|
+
};
|
|
33
|
+
} catch (err) {
|
|
34
|
+
return { valid: false, error: err instanceof Error ? err.message : "Unknown error" };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function countItems(dir) {
|
|
38
|
+
if (!existsSync(dir)) return 0;
|
|
39
|
+
return readdirSync(dir, { withFileTypes: true }).filter((d) => d.isFile() || d.isDirectory()).length;
|
|
40
|
+
}
|
|
41
|
+
async function status(args) {
|
|
42
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
43
|
+
console.log(`
|
|
44
|
+
${pc.dim("Usage:")}
|
|
45
|
+
lumera status
|
|
46
|
+
|
|
47
|
+
${pc.dim("Description:")}
|
|
48
|
+
Show project information and status.
|
|
49
|
+
`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
let projectRoot;
|
|
53
|
+
try {
|
|
54
|
+
projectRoot = findProjectRoot();
|
|
55
|
+
} catch {
|
|
56
|
+
console.error(pc.red("Not in a Lumera project directory."));
|
|
57
|
+
console.error(pc.dim("Run this command from a project with a package.json."));
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
const pkg = readPackageJson(projectRoot);
|
|
61
|
+
const version = detectProjectVersion(projectRoot);
|
|
62
|
+
const appName = getAppName(projectRoot);
|
|
63
|
+
const appTitle = getAppTitle(projectRoot);
|
|
64
|
+
const tokenSource = getTokenSource(projectRoot);
|
|
65
|
+
console.log();
|
|
66
|
+
console.log(pc.bold(`Project: ${appTitle}`));
|
|
67
|
+
console.log(pc.dim(` Name: ${appName}`));
|
|
68
|
+
console.log(pc.dim(` Version: ${pkg.version || "0.0.0"}`));
|
|
69
|
+
console.log(pc.dim(` Structure: v${version}${version === 0 ? " (legacy)" : ""}`));
|
|
70
|
+
console.log();
|
|
71
|
+
const platformDir = version === 0 ? "lumera_platform" : "platform";
|
|
72
|
+
const collectionsDir = join(projectRoot, platformDir, "collections");
|
|
73
|
+
const automationsDir = join(projectRoot, platformDir, "automations");
|
|
74
|
+
const hooksDir = join(projectRoot, platformDir, "hooks");
|
|
75
|
+
const scriptsDir = version === 0 ? join(projectRoot, platformDir, "scripts") : join(projectRoot, "scripts");
|
|
76
|
+
const collections = countItems(collectionsDir);
|
|
77
|
+
const automations = countItems(automationsDir);
|
|
78
|
+
const hooks = countItems(hooksDir);
|
|
79
|
+
const scripts = countItems(scriptsDir);
|
|
80
|
+
console.log(pc.bold("Platform:"));
|
|
81
|
+
console.log(` ${collections} collection${collections !== 1 ? "s" : ""}`);
|
|
82
|
+
console.log(` ${automations} automation${automations !== 1 ? "s" : ""}`);
|
|
83
|
+
console.log(` ${hooks} hook${hooks !== 1 ? "s" : ""}`);
|
|
84
|
+
console.log();
|
|
85
|
+
if (scripts > 0) {
|
|
86
|
+
console.log(pc.bold("Scripts:"));
|
|
87
|
+
console.log(` ${scripts} script${scripts !== 1 ? "s" : ""}`);
|
|
88
|
+
console.log();
|
|
89
|
+
}
|
|
90
|
+
console.log(pc.bold("Auth:"));
|
|
91
|
+
const baseUrl = getBaseUrl();
|
|
92
|
+
console.log(pc.dim(` API: ${baseUrl}`));
|
|
93
|
+
if (tokenSource) {
|
|
94
|
+
let token;
|
|
95
|
+
try {
|
|
96
|
+
token = getToken(projectRoot);
|
|
97
|
+
} catch {
|
|
98
|
+
console.log(pc.yellow(` \u26A0 Token source found but could not read token`));
|
|
99
|
+
console.log(pc.dim(` Run \`lumera login\` to re-authenticate`));
|
|
100
|
+
console.log();
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const validation = await validateToken(token);
|
|
104
|
+
if (validation.valid) {
|
|
105
|
+
console.log(pc.green(` \u2713 Authenticated (${tokenSource})`));
|
|
106
|
+
if (validation.user) console.log(pc.dim(` User: ${validation.user}`));
|
|
107
|
+
if (validation.company) console.log(pc.dim(` Company: ${validation.company}`));
|
|
108
|
+
} else {
|
|
109
|
+
console.log(pc.red(` \u2717 Token invalid (${tokenSource})`));
|
|
110
|
+
console.log(pc.dim(` Error: ${validation.error}`));
|
|
111
|
+
console.log(pc.dim(` Run \`lumera login\` to re-authenticate`));
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
console.log(pc.yellow(` \u26A0 Not logged in`));
|
|
115
|
+
console.log(pc.dim(` Run \`lumera login\` to authenticate`));
|
|
116
|
+
}
|
|
117
|
+
console.log();
|
|
118
|
+
if (version === 0) {
|
|
119
|
+
console.log(pc.yellow("\u26A0 This project uses legacy structure (v0)."));
|
|
120
|
+
console.log(pc.dim(" Run `lumera project migrate` to upgrade to v1."));
|
|
121
|
+
console.log();
|
|
122
|
+
console.log(pc.dim(" Limited functionality in v0:"));
|
|
123
|
+
console.log(pc.dim(" - lumera app deploy: \u2713 supported"));
|
|
124
|
+
console.log(pc.dim(" - lumera platform apply: \u2717 requires v1"));
|
|
125
|
+
console.log(pc.dim(" - lumera run: \u2717 requires v1"));
|
|
126
|
+
console.log();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export {
|
|
130
|
+
status
|
|
131
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lumerahq/cli",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "CLI for building and deploying Lumera apps",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18.0.0"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"lumera": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"templates"
|
|
15
|
+
],
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"archiver": "^7.0.1",
|
|
18
|
+
"dotenv": "^16.4.7",
|
|
19
|
+
"open": "^10.1.0",
|
|
20
|
+
"picocolors": "^1.1.1",
|
|
21
|
+
"prompts": "^2.4.2"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/archiver": "^6.0.3",
|
|
25
|
+
"@types/node": "^22.10.2",
|
|
26
|
+
"@types/prompts": "^2.4.9",
|
|
27
|
+
"tsup": "^8.5.0",
|
|
28
|
+
"typescript": "^5.7.2"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsup src/index.ts --format esm --clean",
|
|
35
|
+
"dev": "tsup src/index.ts --format esm --watch"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# {{projectTitle}} - Claude Code Instructions
|
|
2
|
+
|
|
3
|
+
**Full Architecture**: See `ARCHITECTURE.md`
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## AI Agent Skills
|
|
8
|
+
|
|
9
|
+
This project includes Lumera skills for AI coding agents. Skills provide detailed documentation for building on the Lumera platform.
|
|
10
|
+
|
|
11
|
+
**Installed skills** (in `.claude/skills/`):
|
|
12
|
+
- **lumera-collections** - Collections and Records API
|
|
13
|
+
- **lumera-automations** - Python automation scripts
|
|
14
|
+
- **lumera-webhooks** - Receiving external webhooks
|
|
15
|
+
- **write-hooks** - Server-side JavaScript hooks
|
|
16
|
+
- **lumera-sdk** - Python SDK reference
|
|
17
|
+
- **using-lumera** - Platform overview and patterns
|
|
18
|
+
|
|
19
|
+
### Installing/Updating Skills
|
|
20
|
+
|
|
21
|
+
Skills are auto-installed when creating the app. To manually install or update:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx skills add git@github.com:lumerahq/lumera-skills.git
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
> **Note:** Requires SSH access to the lumerahq GitHub organization.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Quick Reference
|
|
32
|
+
|
|
33
|
+
### Lumera CLI
|
|
34
|
+
|
|
35
|
+
All `lumera` commands are run via `pnpm dlx`:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Shortcuts
|
|
39
|
+
pnpm dev # Start dev server
|
|
40
|
+
pnpm deploy # Deploy frontend
|
|
41
|
+
|
|
42
|
+
# All other commands
|
|
43
|
+
pnpm dlx @lumerahq/cli platform plan
|
|
44
|
+
pnpm dlx @lumerahq/cli platform apply
|
|
45
|
+
pnpm dlx @lumerahq/cli platform destroy
|
|
46
|
+
pnpm dlx @lumerahq/cli run scripts/seed-demo.py
|
|
47
|
+
pnpm dlx @lumerahq/cli status
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Running the Frontend
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# Login first (stores credentials in .lumera/credentials.json)
|
|
54
|
+
lumera login
|
|
55
|
+
|
|
56
|
+
# Start dev server
|
|
57
|
+
pnpm dev
|
|
58
|
+
|
|
59
|
+
# With custom port
|
|
60
|
+
lumera app dev --port 3000
|
|
61
|
+
|
|
62
|
+
# With ngrok tunnel
|
|
63
|
+
lumera app dev --url https://my-tunnel.ngrok.io
|
|
64
|
+
|
|
65
|
+
# Plain vite (no Lumera registration)
|
|
66
|
+
pnpm dev:vite
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Linting & Formatting
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Type check without emitting
|
|
73
|
+
pnpm typecheck
|
|
74
|
+
|
|
75
|
+
# Lint and auto-fix
|
|
76
|
+
pnpm lint
|
|
77
|
+
|
|
78
|
+
# Format code
|
|
79
|
+
pnpm format
|
|
80
|
+
|
|
81
|
+
# Run all checks (lint + typecheck) - use in CI
|
|
82
|
+
pnpm check:ci
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Deploying
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Deploy frontend to S3
|
|
89
|
+
lumera app deploy
|
|
90
|
+
|
|
91
|
+
# Apply platform resources (collections, automations, hooks)
|
|
92
|
+
lumera platform apply
|
|
93
|
+
|
|
94
|
+
# Preview platform changes first
|
|
95
|
+
lumera platform plan
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Running Scripts
|
|
99
|
+
|
|
100
|
+
All scripts are **idempotent** - safe to run multiple times during iterative development.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Run a script locally
|
|
104
|
+
lumera run scripts/seed-demo.py
|
|
105
|
+
|
|
106
|
+
# Dependencies can be declared inline (PEP 723)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Running Automations via External ID
|
|
110
|
+
|
|
111
|
+
Always run automations using their `external_id` (not the internal Lumera ID which changes per tenant).
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
uv run python << 'EOF'
|
|
115
|
+
from lumera import automations
|
|
116
|
+
|
|
117
|
+
# Run automation by external_id (returns Run object immediately)
|
|
118
|
+
run = automations.run_by_external_id(
|
|
119
|
+
"{{projectName}}:my_automation",
|
|
120
|
+
inputs={"param": "value"}
|
|
121
|
+
)
|
|
122
|
+
print(f"Run ID: {run.id}")
|
|
123
|
+
print(f"Status: {run.status}")
|
|
124
|
+
|
|
125
|
+
# Wait for completion (blocks until done or timeout)
|
|
126
|
+
result = run.wait(timeout=600) # 10 min timeout
|
|
127
|
+
print(f"Result: {result}")
|
|
128
|
+
EOF
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Run object properties**: `id`, `status`, `result`, `error`, `inputs`, `is_terminal`
|
|
132
|
+
**Run object methods**: `wait(timeout)`, `refresh()`, `cancel()`
|
|
133
|
+
**Status values**: `queued`, `running`, `succeeded`, `failed`, `cancelled`, `timeout`
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Important Rules
|
|
138
|
+
|
|
139
|
+
1. **Authenticate first** - Before running any CLI or SDK commands, ensure the user has run `lumera login --local`. This stores credentials in `.lumera/credentials.json` which the SDK reads automatically.
|
|
140
|
+
|
|
141
|
+
2. **Source of truth is code** - `platform/` contains all schemas, automations, hooks. Update local code first, then deploy.
|
|
142
|
+
|
|
143
|
+
3. **Never edit Lumera directly** - Don't change data/schema in Lumera UI without explicit user approval.
|
|
144
|
+
|
|
145
|
+
4. **Offer to deploy** - When schemas, hooks, or automations change, offer to deploy to Lumera.
|
|
146
|
+
|
|
147
|
+
5. **Use lumera-sdk skill for Python** - When writing scripts or automations, refer to the **lumera-sdk** skill (`.claude/skills/lumera-sdk.md`) for available SDK functions and usage patterns. The SDK source code is also available in `.venv/lib/python*/site-packages/lumera/` for detailed implementation reference. Key modules:
|
|
148
|
+
- `lumera.pb` - Record and collection operations (search, get, create, update, delete)
|
|
149
|
+
- `lumera.storage` - File uploads and downloads
|
|
150
|
+
- `lumera.llm` - LLM completions
|
|
151
|
+
- `lumera.automations` - Running and managing automations
|
|
152
|
+
- `lumera.integrations` - Third-party integrations (Google, Slack, etc.)
|
|
153
|
+
|
|
154
|
+
6. **Use Python SDK for ad-hoc investigation** - When you need to quickly query data, inspect records, or debug issues, use the Python SDK with `uv run python` (uses `.venv` automatically via `pyproject.toml`):
|
|
155
|
+
```bash
|
|
156
|
+
uv run python -c "from lumera import pb; print(pb.search('collection_name'))"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Key Directories
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
platform/
|
|
165
|
+
├── automations/ # Automation scripts (Python)
|
|
166
|
+
├── collections/ # Collection schemas (JSON)
|
|
167
|
+
└── hooks/ # Server-side JavaScript hooks
|
|
168
|
+
|
|
169
|
+
scripts/ # Local scripts (seed, migrate, etc.)
|
|
170
|
+
|
|
171
|
+
src/ # React frontend
|
|
172
|
+
├── routes/ # TanStack Router pages
|
|
173
|
+
├── lib/ # queries.ts, api helpers
|
|
174
|
+
└── components/ # React components
|
|
175
|
+
|
|
176
|
+
.venv/ # Python venv with lumera SDK (for IDE autocomplete)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Python Environment
|
|
180
|
+
|
|
181
|
+
A Python virtual environment is created at `.venv/` with the `lumera` SDK pre-installed. This provides IDE autocomplete when writing automations and scripts.
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Activate venv (optional - for IDE integration)
|
|
185
|
+
source .venv/bin/activate
|
|
186
|
+
|
|
187
|
+
# SDK is available for import
|
|
188
|
+
python -c "from lumera import pb; print(pb)"
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
> **Note:** You don't need to activate the venv to run scripts - `lumera run` handles this automatically.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Frontend Patterns
|
|
196
|
+
|
|
197
|
+
### Fetching Data
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import { pbSql, pbList } from '@lumerahq/ui/lib';
|
|
201
|
+
|
|
202
|
+
const result = await pbSql<{ id: string; name: string }>({
|
|
203
|
+
sql: 'SELECT id, name FROM users WHERE active = true'
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const items = await pbList<User>('users', {
|
|
207
|
+
filter: 'active = true',
|
|
208
|
+
sort: '-created',
|
|
209
|
+
perPage: 50,
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Running Automations from Frontend
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import { createRun, pollRun } from '@lumerahq/ui/lib';
|
|
217
|
+
|
|
218
|
+
const run = await createRun({
|
|
219
|
+
automationId: '{{projectName}}:process_data',
|
|
220
|
+
inputs: { file_id: 'abc123' },
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const result = await pollRun(run.id);
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Debugging with Lumera SDK
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
uv run python << 'EOF'
|
|
232
|
+
from lumera import pb
|
|
233
|
+
|
|
234
|
+
# List collections
|
|
235
|
+
print(pb.list_collections())
|
|
236
|
+
|
|
237
|
+
# Search records
|
|
238
|
+
result = pb.search("my_collection", per_page=10)
|
|
239
|
+
print(result)
|
|
240
|
+
|
|
241
|
+
# Get single record
|
|
242
|
+
record = pb.get("my_collection", "record_id")
|
|
243
|
+
print(record)
|
|
244
|
+
EOF
|
|
245
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# {{projectTitle}}
|
|
2
|
+
|
|
3
|
+
Lumera custom embedded app.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Install dependencies:
|
|
8
|
+
```bash
|
|
9
|
+
pnpm install
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
2. Login to Lumera:
|
|
13
|
+
```bash
|
|
14
|
+
lumera login
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
3. Start development server:
|
|
18
|
+
```bash
|
|
19
|
+
pnpm dev
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## CLI Commands
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Development
|
|
26
|
+
lumera app dev # Start dev server
|
|
27
|
+
lumera app dev --port 3000 # Custom port
|
|
28
|
+
|
|
29
|
+
# Deployment
|
|
30
|
+
lumera app deploy # Build and deploy frontend
|
|
31
|
+
lumera platform apply # Apply collections, automations, hooks
|
|
32
|
+
lumera platform plan # Preview platform changes
|
|
33
|
+
|
|
34
|
+
# Scripts
|
|
35
|
+
lumera run scripts/seed-demo.py # Run seed script
|
|
36
|
+
|
|
37
|
+
# Project info
|
|
38
|
+
lumera status # Show project info
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Project Structure
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
├── src/ # Frontend (React + TanStack)
|
|
45
|
+
│ ├── routes/ # TanStack Router pages
|
|
46
|
+
│ ├── components/ # React components
|
|
47
|
+
│ └── lib/ # API utilities
|
|
48
|
+
├── platform/ # Backend resources
|
|
49
|
+
│ ├── collections/ # Collection schemas (JSON)
|
|
50
|
+
│ ├── automations/ # Automation scripts (Python)
|
|
51
|
+
│ └── hooks/ # Server-side hooks (JS)
|
|
52
|
+
├── scripts/ # Local scripts
|
|
53
|
+
└── CLAUDE.md # AI assistant instructions
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Documentation
|
|
57
|
+
|
|
58
|
+
- `CLAUDE.md` - AI coding assistant instructions
|
|
59
|
+
- `ARCHITECTURE.md` - System architecture (customize for your app)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
|
|
3
|
+
"vcs": {
|
|
4
|
+
"enabled": true,
|
|
5
|
+
"clientKind": "git",
|
|
6
|
+
"useIgnoreFile": true
|
|
7
|
+
},
|
|
8
|
+
"files": {
|
|
9
|
+
"ignoreUnknown": false,
|
|
10
|
+
"includes": ["**", "!!**/node_modules", "!!**/dist", "!!**/*routeTree.gen.ts"]
|
|
11
|
+
},
|
|
12
|
+
"formatter": {
|
|
13
|
+
"enabled": true,
|
|
14
|
+
"indentStyle": "space",
|
|
15
|
+
"indentWidth": 2,
|
|
16
|
+
"lineWidth": 100
|
|
17
|
+
},
|
|
18
|
+
"linter": {
|
|
19
|
+
"enabled": true,
|
|
20
|
+
"rules": {
|
|
21
|
+
"recommended": true,
|
|
22
|
+
"suspicious": { "noExplicitAny": "off" },
|
|
23
|
+
"style": { "noNonNullAssertion": "off" }
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"javascript": {
|
|
27
|
+
"formatter": {
|
|
28
|
+
"quoteStyle": "single",
|
|
29
|
+
"semicolons": "always",
|
|
30
|
+
"trailingCommas": "es5"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="theme-color" content="#000000" />
|
|
7
|
+
<title>{{projectTitle}}</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{projectName}}",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"pnpm": {
|
|
6
|
+
"overrides": {
|
|
7
|
+
"@tanstack/router-core": "1.155.0"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"lumera": {
|
|
11
|
+
"version": 1,
|
|
12
|
+
"name": "{{projectTitle}}"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"dev": "pnpm dlx @lumerahq/cli app dev",
|
|
16
|
+
"deploy": "pnpm dlx @lumerahq/cli app deploy",
|
|
17
|
+
"dev:vite": "vite",
|
|
18
|
+
"build": "vite build && tsc",
|
|
19
|
+
"preview": "vite preview",
|
|
20
|
+
"typecheck": "tsc --noEmit",
|
|
21
|
+
"lint": "biome lint --write .",
|
|
22
|
+
"format": "biome format --write .",
|
|
23
|
+
"check": "biome check --write .",
|
|
24
|
+
"check:ci": "biome check . && tsc --noEmit"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@lumerahq/ui": "^0.3.0",
|
|
28
|
+
"@tanstack/react-query": "^5.90.11",
|
|
29
|
+
"@tanstack/react-router": "1.155.0",
|
|
30
|
+
"@tanstack/router-plugin": "1.155.0",
|
|
31
|
+
"lucide-react": "^0.469.0",
|
|
32
|
+
"react": "^19.2.0",
|
|
33
|
+
"react-dom": "^19.2.0",
|
|
34
|
+
"sonner": "^2.0.7",
|
|
35
|
+
"tailwindcss": "^4.0.6"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@biomejs/biome": "^2.0.0",
|
|
39
|
+
"@tailwindcss/vite": "^4.0.6",
|
|
40
|
+
"@types/react": "^19.2.0",
|
|
41
|
+
"@types/react-dom": "^19.2.0",
|
|
42
|
+
"@vitejs/plugin-react": "^5.0.4",
|
|
43
|
+
"typescript": "^5.7.2",
|
|
44
|
+
"vite": "^7.1.7"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "example_items",
|
|
3
|
+
"name": "example_items",
|
|
4
|
+
"fields": [
|
|
5
|
+
{
|
|
6
|
+
"name": "name",
|
|
7
|
+
"type": "text",
|
|
8
|
+
"required": true
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "status",
|
|
12
|
+
"type": "select",
|
|
13
|
+
"values": ["pending", "processing", "completed"],
|
|
14
|
+
"default": "pending"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "description",
|
|
18
|
+
"type": "text"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "source_id",
|
|
22
|
+
"type": "text"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"indexes": [
|
|
26
|
+
{ "fields": ["source_id"], "unique": true }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# /// script
|
|
2
|
+
# dependencies = ["lumera-sdk"]
|
|
3
|
+
# ///
|
|
4
|
+
"""
|
|
5
|
+
Seed demo data into Lumera (idempotent - safe to run multiple times).
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
lumera run scripts/seed-demo.py
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from lumera import pb
|
|
12
|
+
|
|
13
|
+
# Seed demo items
|
|
14
|
+
demo_items = [
|
|
15
|
+
{
|
|
16
|
+
"external_id": "demo:item_1",
|
|
17
|
+
"name": "Example Item 1",
|
|
18
|
+
"status": "pending",
|
|
19
|
+
"description": "This is an example item",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"external_id": "demo:item_2",
|
|
23
|
+
"name": "Example Item 2",
|
|
24
|
+
"status": "pending",
|
|
25
|
+
"description": "Another example item",
|
|
26
|
+
},
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
print("Seeding demo data...")
|
|
30
|
+
|
|
31
|
+
for item in demo_items:
|
|
32
|
+
pb.upsert("example_items", item)
|
|
33
|
+
print(f" ✓ {item['name']}")
|
|
34
|
+
|
|
35
|
+
print(f"\nSeeded {len(demo_items)} items")
|