@lunora/cli 1.0.0-alpha.58 → 1.0.0-alpha.59

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 (39) hide show
  1. package/dist/bin.mjs +1 -1
  2. package/dist/index.d.mts +36 -10
  3. package/dist/index.d.ts +36 -10
  4. package/dist/index.mjs +3 -3
  5. package/dist/packem_chunks/handler.mjs +2 -2
  6. package/dist/packem_chunks/handler10.mjs +1 -1
  7. package/dist/packem_chunks/handler11.mjs +1 -1
  8. package/dist/packem_chunks/handler12.mjs +1 -1
  9. package/dist/packem_chunks/handler13.mjs +1 -1
  10. package/dist/packem_chunks/handler14.mjs +1 -1
  11. package/dist/packem_chunks/handler15.mjs +2 -2
  12. package/dist/packem_chunks/handler16.mjs +1 -1
  13. package/dist/packem_chunks/handler17.mjs +1 -1
  14. package/dist/packem_chunks/handler18.mjs +1 -1
  15. package/dist/packem_chunks/handler19.mjs +1 -1
  16. package/dist/packem_chunks/handler2.mjs +2 -2
  17. package/dist/packem_chunks/handler20.mjs +3 -3
  18. package/dist/packem_chunks/handler21.mjs +1 -1
  19. package/dist/packem_chunks/handler3.mjs +1 -1
  20. package/dist/packem_chunks/handler4.mjs +1 -1
  21. package/dist/packem_chunks/handler5.mjs +2 -2
  22. package/dist/packem_chunks/handler6.mjs +2 -2
  23. package/dist/packem_chunks/handler7.mjs +1 -1
  24. package/dist/packem_chunks/handler8.mjs +1 -1
  25. package/dist/packem_chunks/handler9.mjs +2 -2
  26. package/dist/packem_chunks/planDevCommand.mjs +497 -28
  27. package/dist/packem_chunks/runCodegenCommand.mjs +2 -2
  28. package/dist/packem_chunks/runDeployCommand.mjs +3 -3
  29. package/dist/packem_chunks/runInitCommand.mjs +3 -3
  30. package/dist/packem_chunks/runMigrateGenerateCommand.mjs +1 -1
  31. package/dist/packem_chunks/runResetCommand.mjs +1 -1
  32. package/dist/packem_chunks/runRpcCommand.mjs +1 -1
  33. package/dist/packem_shared/{COMMANDS-DsWLzOXZ.mjs → COMMANDS-0BD3K1pb.mjs} +20 -1
  34. package/dist/packem_shared/{command-D3lB_4Az.mjs → command-lYnl4QyF.mjs} +1 -1
  35. package/dist/packem_shared/{createLogger-B40gPzQo.mjs → createLogger-CIWSHrTL.mjs} +33 -6
  36. package/dist/packem_shared/{createRecordingSpawner-DxI3mebw.mjs → createRecordingSpawner-Cw5Iu73G.mjs} +12 -2
  37. package/dist/packem_shared/{output-format-wUvAN6AL.mjs → output-format-B4642rjE.mjs} +1 -1
  38. package/package.json +2 -2
  39. package/skills/lunora-quickstart/SKILL.md +25 -5
@@ -4,7 +4,7 @@ import { createCerebro } from '@visulima/cerebro';
4
4
  import completionCommand from '@visulima/cerebro/command/completion';
5
5
  import versionCommand from '@visulima/cerebro/command/version';
6
6
  import { A as API_SPEC_HELP } from './api-spec-Bx0iKbxA.mjs';
7
- import { createLogger } from './createLogger-B40gPzQo.mjs';
7
+ import { createLogger } from './createLogger-CIWSHrTL.mjs';
8
8
  import { VisulimaError, renderError } from '@visulima/error';
9
9
  import { tmpdir } from 'node:os';
10
10
  import { join } from 'node:path';
@@ -215,9 +215,19 @@ const deploymentsCommand = {
215
215
  };
216
216
 
217
217
  const devCommand = {
218
+ argument: {
219
+ description: "Optional subcommand: stop (shut the running dev server down) | status (report it) | logs (print its captured output)",
220
+ name: "args",
221
+ type: String
222
+ },
218
223
  description: "Run the dev stack: wrangler worker + studio + codegen watch",
219
224
  examples: [
220
225
  ["lunora dev", "Run the worker + studio + codegen watch"],
226
+ ["lunora dev --background", "Run detached: blocks until ready, prints URL + PID, then returns"],
227
+ ["lunora dev stop", "Stop the background/tracked dev server (idempotent)"],
228
+ ["lunora dev status", "Report the running dev server (URL, PID, uptime)"],
229
+ ["lunora dev logs", "Print the captured dev-server log (background runs)"],
230
+ ["lunora dev --json", "Machine-readable JSON log lines (also LUNORA_LOG_JSON=1)"],
221
231
  ["lunora dev --no-studio", "Skip the embedded studio server"],
222
232
  ["lunora dev --worker-port 8080", "Use a custom wrangler dev port"],
223
233
  ["lunora dev --remote", "Proxy D1/KV/R2 to the deployed worker (also LUNORA_REMOTE=1)"]
@@ -227,10 +237,19 @@ const devCommand = {
227
237
  return { default: m.execute };
228
238
  }),
229
239
  name: "dev",
240
+ // KEEP IN SYNC with `daemonArguments` in `./lifecycle.ts`: a new flag that
241
+ // must reach a `--background` daemon has to be forwarded there explicitly.
230
242
  options: [
231
243
  { description: `Which API spec(s) codegen emits: ${API_SPEC_HELP} (default openapi)`, name: "api-spec", type: String },
232
244
  { description: "Studio server port (default 6173)", name: "port", type: Number },
233
245
  { description: "wrangler dev port (default 8787)", name: "worker-port", type: Number },
246
+ {
247
+ description: "Run the dev server as a managed background process (auto-enabled when an AI agent is detected; LUNORA_AGENT_MODE=0 disables)",
248
+ name: "background",
249
+ type: Boolean
250
+ },
251
+ { description: "Emit machine-readable JSON log lines (also LUNORA_LOG_JSON=1; auto-enabled for AI agents)", name: "json", type: Boolean },
252
+ { description: "How many trailing lines `lunora dev logs` prints (default 100, 0 = all)", name: "lines", type: Number },
234
253
  { description: "Don't start the embedded studio server", name: "no-studio", type: Boolean },
235
254
  { description: "Don't watch + regenerate codegen", name: "no-codegen", type: Boolean },
236
255
  { description: "Proxy D1/KV/R2 bindings to the deployed worker (or set LUNORA_REMOTE=1)", name: "remote", type: Boolean }
@@ -1,4 +1,4 @@
1
- import { createLogger } from './createLogger-B40gPzQo.mjs';
1
+ import { createLogger } from './createLogger-CIWSHrTL.mjs';
2
2
  import { P as PromptCancelledError, a as PROMPT_CANCEL_EXIT_CODE } from './prompt-cancelled-APzX1Im-.mjs';
3
3
 
4
4
  const defineHandler = (body) => async (toolbox) => {
@@ -2,19 +2,46 @@ import { STEP_BADGE_NAMES, LunoraReporter } from '@lunora/config';
2
2
  import { JsonReporter } from '@visulima/pail/reporter/json';
3
3
  import { createPail } from '@visulima/pail/server';
4
4
 
5
+ let sharedPail;
6
+ let jsonForced = false;
7
+ let configuredReporters;
5
8
  const wantJson = () => {
9
+ if (jsonForced) {
10
+ return true;
11
+ }
6
12
  const flag = process.env.LUNORA_LOG_JSON;
7
13
  return flag === "1" || flag === "true";
8
14
  };
9
- const buildReporter = () => {
10
- const Reporter = wantJson() ? JsonReporter : LunoraReporter;
11
- return new Reporter();
15
+ const constructReporter = (Reporter) => new Reporter();
16
+ const buildReporters = () => {
17
+ if (jsonForced) {
18
+ return [constructReporter(JsonReporter)];
19
+ }
20
+ if (configuredReporters !== void 0 && configuredReporters.length > 0) {
21
+ return configuredReporters;
22
+ }
23
+ return [constructReporter(wantJson() ? JsonReporter : LunoraReporter)];
24
+ };
25
+ const forceJsonLogging = () => {
26
+ if (jsonForced) {
27
+ return;
28
+ }
29
+ jsonForced = true;
30
+ sharedPail = void 0;
31
+ };
32
+ const logHandlers = {
33
+ compose: (...reporters) => reporters,
34
+ console: () => constructReporter(LunoraReporter),
35
+ json: () => constructReporter(JsonReporter)
36
+ };
37
+ const configureLogHandlers = (reporters) => {
38
+ configuredReporters = Array.isArray(reporters) ? reporters : [reporters];
39
+ sharedPail = void 0;
12
40
  };
13
41
  const STEP_LOG_TYPES = Object.fromEntries(STEP_BADGE_NAMES.map((name) => [name, { label: name, logLevel: "informational" }]));
14
- let sharedPail;
15
42
  const getPail = () => {
16
43
  sharedPail ??= createPail({
17
- reporters: [buildReporter()],
44
+ reporters: buildReporters(),
18
45
  scope: ["lunora"],
19
46
  stderr: process.stderr,
20
47
  stdout: process.stdout,
@@ -75,4 +102,4 @@ const logStep = (type, message) => {
75
102
  getPail()[type](message);
76
103
  };
77
104
 
78
- export { createLogger, createStderrLogger, getPail, logStep, pail };
105
+ export { configureLogHandlers, createLogger, createStderrLogger, forceJsonLogging, getPail, logHandlers, logStep, pail };
@@ -1,5 +1,13 @@
1
1
  import { spawn } from 'node:child_process';
2
2
 
3
+ const NEEDS_CMD_QUOTING = /\s/;
4
+ const spawnShellCompat = (command, args, platform = process.platform) => {
5
+ if (platform !== "win32" || command === process.execPath) {
6
+ return { args: [...args], command, shell: false };
7
+ }
8
+ const quote = (value) => NEEDS_CMD_QUOTING.test(value) ? `"${value}"` : value;
9
+ return { args: args.map((argument) => quote(argument)), command: quote(command), shell: true };
10
+ };
3
11
  const defaultSpawner = (descriptor) => new Promise((resolve, reject) => {
4
12
  const hasInput = typeof descriptor.input === "string";
5
13
  const wantCapture = descriptor.captureStdout === true;
@@ -9,9 +17,11 @@ const defaultSpawner = (descriptor) => new Promise((resolve, reject) => {
9
17
  } else if (descriptor.stdoutToStderr) {
10
18
  stdout = 2;
11
19
  }
12
- const child = spawn(descriptor.command, [...descriptor.args], {
20
+ const exec = spawnShellCompat(descriptor.command, descriptor.args);
21
+ const child = spawn(exec.command, exec.args, {
13
22
  cwd: descriptor.cwd ?? process.cwd(),
14
23
  env: descriptor.env ? { ...process.env, ...descriptor.env } : process.env,
24
+ shell: exec.shell,
15
25
  stdio: [hasInput ? "pipe" : "inherit", stdout, "inherit"]
16
26
  });
17
27
  let captured = "";
@@ -40,4 +50,4 @@ const createRecordingSpawner = (exitCode = 0) => {
40
50
  return { calls, spawner };
41
51
  };
42
52
 
43
- export { createRecordingSpawner, defaultSpawner };
53
+ export { createRecordingSpawner, defaultSpawner, spawnShellCompat };
@@ -1,4 +1,4 @@
1
- import { createStderrLogger } from './createLogger-B40gPzQo.mjs';
1
+ import { createStderrLogger } from './createLogger-CIWSHrTL.mjs';
2
2
 
3
3
  const OUTPUT_FORMATS = /* @__PURE__ */ new Set(["json", "pretty"]);
4
4
  const validateOutputFormat = (command, format) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/cli",
3
- "version": "1.0.0-alpha.58",
3
+ "version": "1.0.0-alpha.59",
4
4
  "description": "The Lunora CLI: init, dev, deploy, codegen, run, reset, and migrate commands",
5
5
  "keywords": [
6
6
  "agent-skills",
@@ -53,7 +53,7 @@
53
53
  "dependencies": {
54
54
  "@bomb.sh/tab": "0.0.17",
55
55
  "@lunora/codegen": "1.0.0-alpha.29",
56
- "@lunora/config": "1.0.0-alpha.46",
56
+ "@lunora/config": "1.0.0-alpha.47",
57
57
  "@lunora/container": "1.0.0-alpha.6",
58
58
  "@lunora/d1": "1.0.0-alpha.22",
59
59
  "@lunora/errors": "1.0.0-alpha.1",
@@ -31,9 +31,12 @@ Set up a working Lunora project as fast as possible.
31
31
  Lunora into the current project.
32
32
  4. Run `lunora codegen` to generate `lunora/_generated/` and typecheck the
33
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).
34
+ 5. Start the dev loop. As an agent, run `lunora dev --background` it starts
35
+ the server as a managed detached process, blocks until it accepts requests,
36
+ prints the URL + PID, and returns (under a detected AI agent, plain
37
+ `lunora dev` does this automatically, with JSON logs). Never leave a bare
38
+ `lunora dev` running in your own shell — it is long-running and does not
39
+ exit.
37
40
  6. Verify a query/mutation round-trip works end to end.
38
41
 
39
42
  ## Path 1: New Project (Recommended)
@@ -87,7 +90,23 @@ not exit, so:
87
90
 
88
91
  - **Local development (user at the keyboard):** ask the user to run `lunora dev`
89
92
  in a terminal.
90
- - **Cloud or headless agents:** start `lunora dev` in the background.
93
+ - **Agents:** run `lunora dev --background`. It detaches the server, waits until
94
+ it answers HTTP, prints `Dev server running at <url> (pid <n>)`, and exits —
95
+ no orphaned shell, no PID bookkeeping. When Lunora detects an AI agent
96
+ (Claude Code, Cursor, Codex, …), plain `lunora dev` flips into this mode
97
+ automatically with JSON logs; `LUNORA_AGENT_MODE=0` opts out.
98
+
99
+ Manage the running server afterwards:
100
+
101
+ ```bash
102
+ lunora dev status --json # machine-readable: url, pid, uptime, logFile
103
+ lunora dev logs --lines 50 # tail the captured output (.lunora/dev.log)
104
+ lunora dev stop # idempotent — succeeds even if nothing runs
105
+ ```
106
+
107
+ A second `lunora dev` never double-starts: it reports the existing instance
108
+ (`.lunora/dev.json` is the lockfile). Probe readiness or liveness at
109
+ `GET /_lunora/status` (`{"ok":true}`).
91
110
 
92
111
  Vite serves on `http://localhost:5173` by default; the Worker is served on the
93
112
  same origin via `@cloudflare/vite-plugin`.
@@ -236,5 +255,6 @@ ids, `.dev.vars` secrets, and container exports.
236
255
  - [ ] New project: scaffolded with `lunora init --template <t>`.
237
256
  - [ ] Existing app: ran `lunora init --here` and wired `LunoraProvider`.
238
257
  - [ ] Ran `lunora codegen`: `lunora/_generated/` exists and typecheck is clean.
239
- - [ ] `lunora dev` is running — user terminal, or background for cloud agents.
258
+ - [ ] Dev server is running — user terminal, or `lunora dev --background`
259
+ (check with `lunora dev status`).
240
260
  - [ ] Verified a query/mutation round-trip re-renders the client live.