@lunora/cli 1.0.0-alpha.42 → 1.0.0-alpha.420

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.
Files changed (138) hide show
  1. package/LICENSE.md +33 -0
  2. package/README.md +3 -1
  3. package/dist/bin.mjs +2 -10
  4. package/dist/index.d.mts +1069 -374
  5. package/dist/index.d.ts +1069 -374
  6. package/dist/index.mjs +1 -19
  7. package/dist/packem_chunks/dispatch.mjs +1 -0
  8. package/dist/packem_chunks/handler.mjs +23 -158
  9. package/dist/packem_chunks/handler10.mjs +1 -16
  10. package/dist/packem_chunks/handler11.mjs +1 -22
  11. package/dist/packem_chunks/handler12.mjs +1 -192
  12. package/dist/packem_chunks/handler13.mjs +1 -131
  13. package/dist/packem_chunks/handler14.mjs +3 -65
  14. package/dist/packem_chunks/handler15.mjs +1 -58
  15. package/dist/packem_chunks/handler16.mjs +1 -80
  16. package/dist/packem_chunks/handler17.mjs +1 -43
  17. package/dist/packem_chunks/handler18.mjs +7 -105
  18. package/dist/packem_chunks/handler19.mjs +2 -170
  19. package/dist/packem_chunks/handler2.mjs +1 -114
  20. package/dist/packem_chunks/handler20.mjs +1 -94
  21. package/dist/packem_chunks/handler21.mjs +3 -94
  22. package/dist/packem_chunks/handler22.mjs +3 -0
  23. package/dist/packem_chunks/handler23.mjs +1 -0
  24. package/dist/packem_chunks/handler24.mjs +2 -0
  25. package/dist/packem_chunks/handler25.mjs +99 -0
  26. package/dist/packem_chunks/handler26.mjs +2 -0
  27. package/dist/packem_chunks/handler27.mjs +9 -0
  28. package/dist/packem_chunks/handler28.mjs +1 -0
  29. package/dist/packem_chunks/handler3.mjs +1 -204
  30. package/dist/packem_chunks/handler4.mjs +1 -33
  31. package/dist/packem_chunks/handler5.mjs +3 -49
  32. package/dist/packem_chunks/handler6.mjs +1 -91
  33. package/dist/packem_chunks/handler7.mjs +1 -42
  34. package/dist/packem_chunks/handler8.mjs +1 -174
  35. package/dist/packem_chunks/handler9.mjs +2 -315
  36. package/dist/packem_chunks/runCodegenCommand.mjs +4 -52
  37. package/dist/packem_chunks/runDevCommand.mjs +2 -0
  38. package/dist/packem_chunks/runInitCommand.mjs +165 -1432
  39. package/dist/packem_chunks/runResetCommand.mjs +1 -41
  40. package/dist/packem_chunks/runRpcCommand.mjs +1 -68
  41. package/dist/packem_shared/COMMANDS-BCSDC-pv.mjs +1 -0
  42. package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-CyIsI3S1.mjs +1 -0
  43. package/dist/packem_shared/EXIT_CODE-D_XCixv8.mjs +1 -0
  44. package/dist/packem_shared/admin-token-VdUnvnKW.mjs +1 -0
  45. package/dist/packem_shared/admin-url-DJB8P6Jh.mjs +1 -0
  46. package/dist/packem_shared/api-spec-lYyq4vL6.mjs +1 -0
  47. package/dist/packem_shared/binding-manifest-file-CQ1eQYy1.mjs +2 -0
  48. package/dist/packem_shared/buildRegistryIndex-Dc8D8AR6.mjs +1 -0
  49. package/dist/packem_shared/cap-error-body-YBKO32BF.mjs +1 -0
  50. package/dist/packem_shared/catalog-CahzmDLV.mjs +1 -0
  51. package/dist/packem_shared/cli-BbgDNGew.mjs +2 -0
  52. package/dist/packem_shared/cli-manifest-DoQ_3bzs.mjs +1 -0
  53. package/dist/packem_shared/cloudflare-credentials-BVmZnDZk.mjs +1 -0
  54. package/dist/packem_shared/codegen-error-AmH54ofi.mjs +3 -0
  55. package/dist/packem_shared/command-CB4JM-Jl.mjs +1 -0
  56. package/dist/packem_shared/commands-DvSfLvyt.mjs +13 -0
  57. package/dist/packem_shared/createLogger-4TujevyB.mjs +2 -0
  58. package/dist/packem_shared/createRecordingSpawner-Ch7zuQQE.mjs +1 -0
  59. package/dist/packem_shared/deploy-target-resolve-BTCW1Iv4.mjs +1 -0
  60. package/dist/packem_shared/diffSnapshots-htqNZT8Q.mjs +7 -0
  61. package/dist/packem_shared/docker-DpVxvYpL.mjs +1 -0
  62. package/dist/packem_shared/free-port-DjbFhaaT.mjs +1 -0
  63. package/dist/packem_shared/health-probe-Bw9JFfIy.mjs +1 -0
  64. package/dist/packem_shared/import-BRM1hs7j.mjs +12 -0
  65. package/dist/packem_shared/index-oHZBGBwB.mjs +1 -0
  66. package/dist/packem_shared/insertSchemaExtension-DuiV6cba.mjs +8 -0
  67. package/dist/packem_shared/lint-ignore-report-DKZagpqk.mjs +2 -0
  68. package/dist/packem_shared/mcp-config-file-CcDTeXIq.mjs +2 -0
  69. package/dist/packem_shared/open-url-EnKy--w-.mjs +1 -0
  70. package/dist/packem_shared/output-format-DWe_tkTR.mjs +2 -0
  71. package/dist/packem_shared/parseManifest-CwPTKdtS.mjs +1 -0
  72. package/dist/packem_shared/path-containment-CgxYZggb.mjs +1 -0
  73. package/dist/packem_shared/plan-DFY3CqHD.mjs +5 -0
  74. package/dist/packem_shared/planDevCommand-BDoJUgQ4.mjs +1 -0
  75. package/dist/packem_shared/platform-diagnostics-Cn2g6Jh-.mjs +4 -0
  76. package/dist/packem_shared/prompt-cancelled-BvsNxg_Q.mjs +1 -0
  77. package/dist/packem_shared/render-lunora-error-B6893vbU.mjs +2 -0
  78. package/dist/packem_shared/resolve-Bdc9KEUv.mjs +5 -0
  79. package/dist/packem_shared/resolve-target-C_ZloTvd.mjs +1 -0
  80. package/dist/packem_shared/runAddCommand-BChdJQ5L.mjs +1 -0
  81. package/dist/packem_shared/runDeployCommand-D40F3PLQ.mjs +1 -0
  82. package/dist/packem_shared/runExportCommand-slAq5BCF.mjs +5 -0
  83. package/dist/packem_shared/runMigrateGenerateCommand-BwemPIOz.mjs +11 -0
  84. package/dist/packem_shared/schemaIrToSnapshot-BHuNOfgs.mjs +1 -0
  85. package/dist/packem_shared/secret-key-8DPOH98z.mjs +1 -0
  86. package/dist/packem_shared/shared-D-zCOmgY.mjs +1 -0
  87. package/dist/packem_shared/storage-DNzYhXR-.mjs +1 -0
  88. package/dist/packem_shared/tui-prompts-B3YwUhGw.mjs +4 -0
  89. package/dist/packem_shared/variables-CPYyJtsL.mjs +1 -0
  90. package/dist/packem_shared/wrangler-name-Dsk5K1f-.mjs +1 -0
  91. package/dist/packem_shared/wrangler-secrets-CTQPpalP.mjs +1 -0
  92. package/package.json +39 -19
  93. package/skills/README.md +36 -17
  94. package/skills/lunora/SKILL.md +158 -65
  95. package/skills/lunora-cloudflare-audit/SKILL.md +163 -0
  96. package/skills/lunora-create-package/SKILL.md +97 -84
  97. package/skills/lunora-deploy/SKILL.md +175 -105
  98. package/skills/lunora-functions/SKILL.md +363 -56
  99. package/skills/lunora-migration-helper/SKILL.md +162 -137
  100. package/skills/lunora-performance-audit/SKILL.md +137 -95
  101. package/skills/lunora-quickstart/SKILL.md +136 -136
  102. package/skills/lunora-realtime/SKILL.md +217 -97
  103. package/skills/lunora-setup-auth/SKILL.md +162 -102
  104. package/skills/lunora-setup-hyperdrive/SKILL.md +130 -109
  105. package/skills/lunora-setup-hyperdrive-global/SKILL.md +93 -90
  106. package/skills/lunora-setup-mail/SKILL.md +85 -113
  107. package/skills/lunora-setup-scheduler/SKILL.md +132 -96
  108. package/skills/lunora-setup-storage/SKILL.md +189 -95
  109. package/dist/packem_chunks/planDevCommand.mjs +0 -541
  110. package/dist/packem_chunks/runDeployCommand.mjs +0 -594
  111. package/dist/packem_chunks/runMigrateGenerateCommand.mjs +0 -397
  112. package/dist/packem_shared/COMMANDS-B0ftFD_3.mjs +0 -948
  113. package/dist/packem_shared/DEFAULT_IMPORT_BATCH_SIZE-Ck-2bU08.mjs +0 -244
  114. package/dist/packem_shared/admin-url-4UzT-CI4.mjs +0 -19
  115. package/dist/packem_shared/api-spec-CtA6ilu4.mjs +0 -13
  116. package/dist/packem_shared/buildRegistryIndex-BcYe607_.mjs +0 -38
  117. package/dist/packem_shared/codegen-error-DJG-ghs_.mjs +0 -31
  118. package/dist/packem_shared/command-D3lB_4Az.mjs +0 -19
  119. package/dist/packem_shared/commands-B-gR09Z_.mjs +0 -845
  120. package/dist/packem_shared/createLogger-B40gPzQo.mjs +0 -78
  121. package/dist/packem_shared/createRecordingSpawner-DxI3mebw.mjs +0 -43
  122. package/dist/packem_shared/detect-package-manager-DYp7n3mJ.mjs +0 -61
  123. package/dist/packem_shared/diffSnapshots-BeDvvNiF.mjs +0 -161
  124. package/dist/packem_shared/docker-hMQ97KSQ.mjs +0 -21
  125. package/dist/packem_shared/insertSchemaExtension-DAqbfr9Z.mjs +0 -64
  126. package/dist/packem_shared/open-url-Dfq6fAyT.mjs +0 -41
  127. package/dist/packem_shared/output-format-wUvAN6AL.mjs +0 -17
  128. package/dist/packem_shared/parseArgs-YXFuKdEk.mjs +0 -56
  129. package/dist/packem_shared/parseManifest--vZf2FY1.mjs +0 -94
  130. package/dist/packem_shared/prompt-cancelled-APzX1Im-.mjs +0 -9
  131. package/dist/packem_shared/resolve-target-qbsJ_5sF.mjs +0 -16
  132. package/dist/packem_shared/runAddCommand-bnY6-HKb.mjs +0 -4
  133. package/dist/packem_shared/schema-drift-gate-BtBt0as0.mjs +0 -79
  134. package/dist/packem_shared/schemaIrToSnapshot-DdsljJT-.mjs +0 -43
  135. package/dist/packem_shared/storage-BIsph-Vk.mjs +0 -84
  136. package/dist/packem_shared/tui-prompts-BjEN8XgP.mjs +0 -658
  137. package/dist/packem_shared/wrangler-name-cy4yhm9j.mjs +0 -12
  138. package/dist/packem_shared/wrangler-secrets-P2_ZUR-k.mjs +0 -47
@@ -1,119 +1,118 @@
1
1
  ---
2
2
  name: lunora-quickstart
3
- description: Creates or adds Lunora to an app. Use for new Lunora projects, `lunora init`,
4
- framework/provider wiring, the first `lunora dev` run, env vars, or writing
5
- the first schema + query/mutation round-trip.
3
+ description: Creates a new Lunora project or adds Lunora to an existing app, then gets
4
+ the first schema + query/mutation round-trip running. Use when the user asks
5
+ to "start a Lunora app", "add Lunora to my Vite/Next/Nuxt/SvelteKit/Astro
6
+ app", runs `lunora init` (`--vite`, `-t`, `--here`, `--add`), needs the
7
+ client provider wired (`LunoraClient` + `LunoraProvider`), or is running
8
+ `lunora dev` for the first time (background mode, `lunora dev status`/`logs`/
9
+ `stop`, `VITE_LUNORA_URL`).
6
10
  ---
7
11
 
8
12
  # Lunora Quickstart
9
13
 
10
- Set up a working Lunora project as fast as possible.
14
+ Get a working Lunora project with one live query/mutation round-trip.
11
15
 
12
- ## When to Use
13
-
14
- - Starting a brand new project with Lunora.
15
- - Adding Lunora to an existing Vite, Next.js, Astro, Nuxt, SvelteKit, or
16
- TanStack Start app.
17
- - Scaffolding a Lunora app for prototyping.
18
-
19
- ## When Not to Use
20
-
21
- - The project already has Lunora installed and `lunora/` exists — just build,
22
- and run `lunora codegen` after schema/function edits.
23
- - You only need to add auth to an existing Lunora app — use the
24
- `lunora-setup-auth` skill.
16
+ Skip this skill when `lunora/` already exists (just build, and run
17
+ `lunora codegen` after edits) or when the task is only auth
18
+ (`lunora-setup-auth`).
25
19
 
26
20
  ## Workflow
27
21
 
28
- 1. Determine the starting point: new project or existing app.
29
- 2. New project: scaffold with `lunora init` and pick a template.
30
- 3. Existing app: run `lunora init --here` to patch the Vite config and wire
31
- Lunora into the current project.
32
- 4. Run `lunora codegen` to generate `lunora/_generated/` and typecheck the
33
- schema + functions. This is the agent's feedback loop.
34
- 5. Start the dev loop with `lunora dev` (ask the user to run it locally, or
35
- start it in the background for cloud/headless agents — it is long-running and
36
- does not exit).
37
- 6. Verify a query/mutation round-trip works end to end.
22
+ 1. New project: `lunora init <name> --vite <framework>` or `-t <template>`.
23
+ Existing app: `lunora init --here`.
24
+ 2. `lunora codegen` to generate `lunora/_generated/`.
25
+ 3. Start the dev server in the background (`lunora dev --background`).
26
+ 4. Write or adapt a query + mutation and use them from a component.
27
+ 5. `lunora verify` (wrangler config + codegen dry-run + `tsc --noEmit`) passes,
28
+ and the client re-renders live after a mutation.
38
29
 
39
- ## Path 1: New Project (Recommended)
40
-
41
- `lunora init` fetches a whole-project template (frontend + worker entry + Vite
42
- plugin + `lunora/` already wired together).
30
+ ## Path 1: new project
43
31
 
44
32
  ```bash
45
- lunora init my-app --template vite
33
+ lunora init my-app --vite react
46
34
  cd my-app
47
35
  pnpm install
48
36
  ```
49
37
 
50
- ### Pick a template
51
-
52
- | Template | Stack |
53
- | ---------------------- | ---------------------------------------------- |
54
- | `vite` | React + Vite (the simplest full-stack starter) |
55
- | `standalone` | Worker-only Lunora backend, no frontend |
56
- | `astro` | Astro integration |
57
- | `nuxt` | Nuxt (Vue) |
58
- | `sveltekit` | SvelteKit |
59
- | `tanstack-start-react` | TanStack Start (React) |
60
- | `tanstack-start-solid` | TanStack Start (Solid) |
61
-
62
- If the user has not specified a preference, default to `vite`. Pass `--template`
63
- explicitly to avoid the interactive prompt. Templates are fetched remotely (via
64
- `giget`) from `gh:anolilab/lunora/templates/<type>`; pass `--from <dir>` to use a
65
- local template directory offline.
66
-
67
- ### Generate types and push the first run
68
-
69
- Run this yourself — it is one-shot and exits cleanly:
38
+ Two scaffold paths take different flags.
39
+
40
+ `--vite <framework>` applies the Lunora layer over the official create-vite
41
+ base. Use it for a plain SPA: `react` (the default), `vue`, `solid`, `svelte`,
42
+ or `vanilla` (overlay-only, not in the picker). `-t react|vue|solid|svelte` is
43
+ accepted as an alias for the same overlay.
44
+
45
+ `-t` / `--template <type>` fetches a whole-project template from
46
+ `gh:anolilab/lunora/templates/<type>`:
47
+
48
+ | `-t` value | Stack |
49
+ | ----------------------------- | ---------------------------------------------------------------- |
50
+ | `next` | Next.js App Router (OpenNext) + a standalone Lunora worker |
51
+ | `vinext` | Next.js App Router on Vite (vinext), one worker (experimental) |
52
+ | `vinext-pages` | Next.js Pages Router on Vite (vinext), one worker (experimental) |
53
+ | `tanstack-start-react` | TanStack Start (React), SSR with live-loader routes |
54
+ | `tanstack-start-solid` | TanStack Start (Solid) |
55
+ | `tanstack-start-react-rspack` | TanStack Start (React) on Rsbuild, one worker |
56
+ | `rspack-react` | React SPA on Rsbuild (`@lunora/rspack`) |
57
+ | `solid-v2` | Solid 2.0 SPA (`@solidjs/web`, `vite-plugin-solid` 3) |
58
+ | `astro` | Astro, Lunora composed into the adapter worker |
59
+ | `sveltekit` | SvelteKit, Lunora composed into the adapter worker |
60
+ | `nuxt` | Nuxt (Vue), Lunora mounted in Nitro |
61
+ | `analog` | AnalogJS (Angular), Lunora mounted in Nitro |
62
+ | `expo` | React Native (Expo) app + a Lunora worker |
63
+ | `standalone` | Worker-only backend, no frontend |
64
+
65
+ There is no `vite` template value; `-t vite` errors. Solid 2.0 is a template
66
+ rather than an overlay because create-vite's Solid base is still 1.x, so
67
+ `--vite solid` stays on Solid 1.x.
68
+
69
+ In a non-interactive shell, `init` errors unless it gets a name and a framework
70
+ (or `--yes`, which takes the React overlay). As an agent, pass `--vite` or `-t`
71
+ explicitly; if the user stated no preference, use `--vite react`.
72
+
73
+ Other flags:
70
74
 
71
75
  ```bash
72
- lunora codegen
76
+ lunora init my-app --vite react --ci github # add a deploy pipeline (or --ci gitlab)
77
+ lunora init my-app -t next --add auth,email # add capabilities without prompting
78
+ lunora init my-app --vite react --yes # skip the interactive auth/email offer
79
+ lunora init my-app --vite react --dry-run # walk every step, write nothing
73
80
  ```
74
81
 
75
- It writes `lunora/_generated/` and typechecks your schema + functions. Read its
76
- output to find out whether the code you just wrote is valid.
82
+ `--add` takes a comma-separated list of `ai | auth | auth-ui | backup | browser
83
+ | cloudflare-access | crons | email | flags | hyperdrive | payment | presence |
84
+ queue | storage | workflow`. `--ref <branch|tag|commit>` pins the template
85
+ source (e.g. `--ref alpha`); `--from <dir>` copies from a local templates root.
77
86
 
78
- ### Start the dev loop
79
-
80
- ```bash
81
- lunora dev
82
- ```
83
-
84
- `lunora dev` runs the Vite dev server with the Cloudflare Worker on the same
85
- origin, plus codegen-on-save and the Lunora Studio. It is long-running and does
86
- not exit, so:
87
-
88
- - **Local development (user at the keyboard):** ask the user to run `lunora dev`
89
- in a terminal.
90
- - **Cloud or headless agents:** start `lunora dev` in the background.
91
-
92
- Vite serves on `http://localhost:5173` by default; the Worker is served on the
93
- same origin via `@cloudflare/vite-plugin`.
94
-
95
- ## Path 2: Add Lunora to an Existing App
96
-
97
- Use this when the user already has a Vite-based frontend and wants Lunora as the
98
- backend.
87
+ ## Path 2: add Lunora to an existing app
99
88
 
100
89
  ```bash
101
90
  lunora init --here
102
91
  ```
103
92
 
104
- This finds the existing `vite.config.*` (or creates a minimal one), patches in
105
- the Lunora Vite plugin, and scaffolds a starter `lunora/`. Then run
106
- `lunora codegen` and `lunora dev` as above.
93
+ This detects the framework from `package.json`, scaffolds `lunora/schema.ts` and
94
+ `lunora/messages.ts` (skipped if a schema exists), and patches or creates the
95
+ Vite config with the `lunora()` plugin. SvelteKit, Nuxt and Astro wire Lunora
96
+ through their server entry instead, so their Vite config is left alone. It then
97
+ prints framework-specific next steps: the packages to install, the provider to
98
+ mount, and how to compose the worker. Follow those; the CLI does not edit
99
+ framework-owned files.
107
100
 
108
- ### Wire up the client provider
101
+ Templates and `--vite` overlays map `#lunora/*` to `./lunora/*` in
102
+ `package.json` `imports`, which is why their function files import
103
+ `#lunora/_generated/server.js`. A `--here` project has no such mapping; its
104
+ starter uses the relative `./_generated/server`. Match whichever the project
105
+ already uses.
109
106
 
110
- Create the `LunoraClient` once at module scope (never inside a component) and
111
- wrap the app with the framework provider. React example:
107
+ ### Client provider
108
+
109
+ Create the `LunoraClient` once at module scope (not inside a component, or every
110
+ render opens a new socket) and wrap the app in the framework provider:
112
111
 
113
112
  ```tsx
114
113
  // src/client/main.tsx
115
- import { LunoraClient } from "@lunora/client";
116
114
  import { LunoraProvider } from "@lunora/react";
115
+ import { LunoraClient } from "lunorash/client";
117
116
  import { StrictMode } from "react";
118
117
  import { createRoot } from "react-dom/client";
119
118
 
@@ -132,18 +131,19 @@ createRoot(document.querySelector("#root")!).render(
132
131
  );
133
132
  ```
134
133
 
135
- Vue, Solid, and Svelte have matching providers in `@lunora/vue`, `@lunora/solid`,
136
- and `@lunora/svelte`. `VITE_LUNORA_URL` is optional — it defaults to
137
- `location.origin`, which is correct for the single-origin dev setup.
138
-
139
- ## Writing Your First Function
134
+ `LunoraClient` is also exported by `@lunora/client`. Other adapters:
135
+ `@lunora/vue`, `@lunora/solid`, `@lunora/svelte`, `@lunora/angular`
136
+ (`provideLunora` / `injectLunoraClient`), and `@lunora/react-native`
137
+ (`createLunoraClient`, re-exporting `@lunora/react`). `@lunora/astro` and
138
+ `@lunora/nuxt` mount Lunora server-side. `VITE_LUNORA_URL` is optional; the
139
+ same-origin default is right for local dev.
140
140
 
141
- Create a schema and a query/mutation to verify the full loop.
141
+ ## First function
142
142
 
143
143
  `lunora/schema.ts`:
144
144
 
145
145
  ```ts
146
- import { defineSchema, defineTable, v } from "@lunora/server";
146
+ import { defineSchema, defineTable, v } from "lunorash/server";
147
147
 
148
148
  export default defineSchema({
149
149
  todos: defineTable({
@@ -157,27 +157,25 @@ export default defineSchema({
157
157
  `lunora/todos.ts`:
158
158
 
159
159
  ```ts
160
- import type { Id } from "@lunora/server";
161
- import { mutation, query, v } from "@lunora/server";
160
+ import { mutation, query, v } from "#lunora/_generated/server.js";
162
161
 
163
162
  export const list = query.query(async ({ ctx }) => ctx.db.query("todos").withIndex("by_creation").collect());
164
163
 
165
164
  export const add = mutation
166
- .input({ text: v.string() })
167
- .mutation(async ({ ctx, args: { text } }): Promise<Id<"todos">> => ctx.db.insert("todos", { text, done: false, createdAt: Date.now() }));
165
+ .input({ text: v.string().max(4096) })
166
+ .mutation(async ({ ctx, args }) => ctx.db.insert("todos", { text: args.text, done: false, createdAt: Date.now() }));
168
167
  ```
169
168
 
170
- Run `lunora codegen`, then use it in a component. The `api` object and `Doc` /
171
- `Id` types come from `lunora/_generated/`:
169
+ Run `lunora codegen`, then call it from a component. Argument and return types
170
+ are inferred from the generated `api`, so no casts are needed:
172
171
 
173
172
  ```tsx
174
173
  import { useMutation, useQuery } from "@lunora/react";
175
174
 
176
175
  import { api } from "../../lunora/_generated/api";
177
- import type { Doc } from "../../lunora/_generated/dataModel";
178
176
 
179
- function Todos() {
180
- const todos = useQuery(api.todos.list, {}) as Doc<"todos">[] | undefined;
177
+ export const Todos = () => {
178
+ const todos = useQuery(api.todos.list, {});
181
179
  const { mutate: add, pending } = useMutation(api.todos.add);
182
180
 
183
181
  return (
@@ -185,56 +183,58 @@ function Todos() {
185
183
  <button disabled={pending} onClick={() => add({ text: "New todo" })}>
186
184
  Add
187
185
  </button>
188
- {todos?.map((t) => (
189
- <div key={t._id}>{t.text}</div>
186
+ {todos?.map((todo) => (
187
+ <div key={todo._id}>{todo.text}</div>
190
188
  ))}
191
189
  </div>
192
190
  );
193
- }
191
+ };
194
192
  ```
195
193
 
196
- `useQuery` opens a live subscription: the list re-renders the instant any
197
- mutation changes the queried rows.
194
+ `useQuery` returns `undefined` while loading, then re-renders whenever a
195
+ mutation changes the queried rows. A function in a folder nests in `api`:
196
+ `lunora/billing/invoices.ts` is `api.billing.invoices.*`.
197
+
198
+ ## Dev server
198
199
 
199
- ## Development vs Production
200
+ `lunora dev` runs the worker (behind Vite via `@cloudflare/vite-plugin` in Vite
201
+ projects), codegen-on-save, and the embedded Studio at `/__lunora`. It does not
202
+ exit on its own.
200
203
 
201
- Use `lunora dev` during development. When ready to ship:
204
+ - User at the keyboard: ask them to run `lunora dev` in a terminal.
205
+ - Agent: run `lunora dev --background`. It detaches, waits until the server
206
+ answers, prints `Dev server running at <url> (pid <n>)`, and exits. When an AI
207
+ agent is detected (Claude Code, Cursor, Codex, …), plain `lunora dev` does
208
+ this automatically with JSON logs; `LUNORA_AGENT_MODE=0` opts out. Avoid a
209
+ bare foreground `lunora dev` in your own shell, since it blocks until killed.
202
210
 
203
211
  ```bash
204
- lunora deploy
212
+ lunora dev status --json # url, pid, uptime, logFile
213
+ lunora dev logs --lines 50 # tail .lunora/dev.log
214
+ lunora dev stop # idempotent
205
215
  ```
206
216
 
207
- `lunora deploy` runs codegen, the schema-drift gate, and `wrangler deploy`. Do
208
- not use it during day-to-day development.
217
+ A second `lunora dev` reports the running instance instead of starting another
218
+ (`.lunora/dev.json` is the lockfile). `GET /_lunora/status` returns
219
+ `{"ok":true}` once the worker is up. Vite defaults to `http://localhost:5173`.
220
+ `lunora dev --tunnel` shares the worker on a public `*.trycloudflare.com` URL
221
+ (needs `cloudflared`).
209
222
 
210
- Before deploying, run the preflight:
223
+ ## Shipping
211
224
 
212
225
  ```bash
213
- lunora doctor
226
+ lunora doctor # preflight: SHARD DO binding, placeholder D1 ids, .dev.vars secrets, container exports
227
+ lunora deploy # codegen + schema-drift gate + wrangler deploy
214
228
  ```
215
229
 
216
- It checks `wrangler.jsonc` (the `SHARD` durable-object binding), D1 placeholder
217
- ids, `.dev.vars` secrets, and container exports.
218
-
219
- ## Next Steps
220
-
221
- - Add authentication: use the `lunora-setup-auth` skill.
222
- - Add a prebuilt capability (mail, presence, storage, rate limit, crons):
223
- `lunora registry add <item>` (see `lunora registry list`). For capabilities
224
- with a dedicated skill, use it: `lunora-setup-mail`, `lunora-setup-storage`,
225
- `lunora-setup-scheduler`. See the `lunora` router's capability entry for the
226
- full routing.
227
- - Build your own reusable capability: use the `lunora-create-package` skill.
228
- - Plan a schema change: use the `lunora-migration-helper` skill.
229
- - Scaffold more functions: `vis generate lunora-query --name=listMessages`,
230
- `lunora-mutation`, `lunora-action`, `lunora-table`, `lunora-cron` (always use
231
- the `--name=value` form).
232
-
233
- ## Checklist
234
-
235
- - [ ] Determined starting point: new project or existing app.
236
- - [ ] New project: scaffolded with `lunora init --template <t>`.
237
- - [ ] Existing app: ran `lunora init --here` and wired `LunoraProvider`.
238
- - [ ] Ran `lunora codegen`: `lunora/_generated/` exists and typecheck is clean.
239
- - [ ] `lunora dev` is running — user terminal, or background for cloud agents.
240
- - [ ] Verified a query/mutation round-trip re-renders the client live.
230
+ Use `lunora-deploy` for bindings, secrets and environments.
231
+
232
+ ## Next steps
233
+
234
+ - Auth: `lunora-setup-auth`.
235
+ - Add-ons: `lunora add <feature>` (e.g. `email`, `storage`, `crons`,
236
+ `presence`; `lunora registry list` for all). Mail, storage and scheduling have
237
+ their own skills: `lunora-setup-mail`, `lunora-setup-storage`,
238
+ `lunora-setup-scheduler`.
239
+ - Schema and function rules: `lunora-functions`. Schema changes on live data:
240
+ `lunora-migration-helper`.