@lunora/config 1.0.0-alpha.70 → 1.0.0-alpha.71

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/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@ import { AgentIR, ContainerIR, WorkflowIR, QueueIR, WranglerVariableIR } from '@
2
2
  export type { AgentIR, ContainerIR, WorkflowIR } from '@lunora/codegen';
3
3
  import { Writable } from 'node:stream';
4
4
  import 'ts-morph';
5
- export { type A as AdditivePolicyEdit, type D as DestructivePolicyEdit, type P as PolicyEdit, type a as PolicyScaffoldFailureReason, type b as ScaffoldFileResult, type S as ScaffoldPolicyEdit, type c as WireResult, type W as WireRlsEdit, d as classifyPolicyEdit, s as scaffoldPolicyFile, w as wireRlsIntoProcedure } from "./packem_shared/policy-scaffold.d-DCmwn7zQ.mjs";
5
+ export { type A as AdditivePolicyEdit, type D as DestructivePolicyEdit, type P as PolicyEdit, type a as PolicyScaffoldFailureReason, type b as ScaffoldFileResult, type S as ScaffoldPolicyEdit, type c as WireResult, type W as WireRlsEdit, d as classifyPolicyEdit, s as scaffoldPolicyFile, w as wireRlsIntoProcedure } from "./packem_shared/policy-scaffold.d-CFd2FlqG.mjs";
6
6
  /** Minimal env shape — `process.env` structurally, injectable for tests. */
7
7
  type EnvLike = Readonly<Record<string, string | undefined>>;
8
8
  /** One detected agent: which tool, and which env var gave it away. */
@@ -15,10 +15,10 @@ interface AgentDetection {
15
15
  /** Env var that forces agent mode on (`1`/`true`) or off (`0`/`false`), overriding detection. */
16
16
  declare const AGENT_MODE_ENV = "LUNORA_AGENT_MODE";
17
17
  /**
18
- * Detect the AI agent driving this process, or `undefined` when none is.
19
- * `LUNORA_AGENT_MODE` wins over `@visulima/find-ai-runner`'s marker table in
20
- * both directions. Pure — pass a custom `env` in tests.
21
- */
18
+ * Detect the AI agent driving this process, or `undefined` when none is.
19
+ * `LUNORA_AGENT_MODE` wins over `@visulima/find-ai-runner`'s marker table in
20
+ * both directions. Pure — pass a custom `env` in tests.
21
+ */
22
22
  declare const detectAiAgent: (env?: EnvLike) => AgentDetection | undefined;
23
23
  interface DiscoverAgentInfoResult {
24
24
  /** Discovered agent definitions; `[]` when none are declared or parsing failed. */
@@ -27,47 +27,47 @@ interface DiscoverAgentInfoResult {
27
27
  error?: string;
28
28
  }
29
29
  /**
30
- * Discover the project's `defineAgent` declarations. Returns `{ agents: [] }`
31
- * when the project has no `lunora/agents.ts` (not an error), or
32
- * `{ agents: [], error }` when the file exists but could not be parsed — callers
33
- * decide whether that is a warning (validator) or ignorable (inference).
34
- */
30
+ * Discover the project's `defineAgent` declarations. Returns `{ agents: [] }`
31
+ * when the project has no `lunora/agents.ts` (not an error), or
32
+ * `{ agents: [], error }` when the file exists but could not be parsed — callers
33
+ * decide whether that is a warning (validator) or ignorable (inference).
34
+ */
35
35
  declare const discoverAgentInfo: (projectRoot: string, schemaDirectory: string) => DiscoverAgentInfoResult;
36
36
  /**
37
- * Project-relative directory the Lunora agent skills ("rules") install into.
38
- * This is the portable [Agent Skills](https://tanstack.com/intent/latest/docs/registry)
39
- * location — Cursor, Claude Code, and GitHub Copilot all discover skills here.
40
- */
37
+ * Project-relative directory the Lunora agent skills ("rules") install into.
38
+ * This is the portable [Agent Skills](https://tanstack.com/intent/latest/docs/registry)
39
+ * location — Cursor, Claude Code, and GitHub Copilot all discover skills here.
40
+ */
41
41
  declare const AGENT_RULES_DIR = ".agents/skills";
42
42
  /** Env var the once-per-process-tree hint guard ({@link claimAgentRulesHint}) sets. */
43
43
  declare const AGENT_RULES_HINT_ENV = "LUNORA_RULES_HINT_SHOWN";
44
44
  /**
45
- * The Lunora agent skills shipped by `@lunora/cli`. The first entry (`lunora`)
46
- * is the router skill — its presence is what {@link detectAgentRules} treats as
47
- * "rules installed", since every other skill is reachable through it.
48
- */
45
+ * The Lunora agent skills shipped by `@lunora/cli`. The first entry (`lunora`)
46
+ * is the router skill — its presence is what {@link detectAgentRules} treats as
47
+ * "rules installed", since every other skill is reachable through it.
48
+ */
49
49
  declare const LUNORA_SKILL_NAMES: ReadonlyArray<string>;
50
50
  /** The router skill whose presence marks the rule set as installed. */
51
51
  declare const ROOT_SKILL_NAME = "lunora";
52
52
  /**
53
- * The single "rules not installed" message shared by every surface (the CLI
54
- * `lunora dev` summary and the Vite dev plugin), so the wording and the
55
- * pointer at `lunora rules install` stay identical wherever it appears.
56
- */
53
+ * The single "rules not installed" message shared by every surface (the CLI
54
+ * `lunora dev` summary and the Vite dev plugin), so the wording and the
55
+ * pointer at `lunora rules install` stay identical wherever it appears.
56
+ */
57
57
  declare const AGENT_RULES_HINT = "Lunora AI rules not installed — run `lunora rules install` so your coding agent knows how to use Lunora.";
58
58
  /**
59
- * Process-tree guard so the hint is emitted at most once. The first surface to
60
- * print it sets {@link AGENT_RULES_HINT_ENV} on `process.env`; later surfaces (a
61
- * Vite dev-server restart, or a child process that inherited the env) read it
62
- * and stay quiet. Returns `true` the first time, `false` afterwards.
63
- */
59
+ * Process-tree guard so the hint is emitted at most once. The first surface to
60
+ * print it sets {@link AGENT_RULES_HINT_ENV} on `process.env`; later surfaces (a
61
+ * Vite dev-server restart, or a child process that inherited the env) read it
62
+ * and stay quiet. Returns `true` the first time, `false` afterwards.
63
+ */
64
64
  declare const claimAgentRulesHint: () => boolean;
65
65
  interface AgentRulesStatus {
66
66
  /**
67
- * True when the `lunora` router skill is installed. We key on the router
68
- * (not "all nine present") so a project that intentionally trims the set
69
- * still counts as installed and isn't nagged.
70
- */
67
+ * True when the `lunora` router skill is installed. We key on the router
68
+ * (not "all nine present") so a project that intentionally trims the set
69
+ * still counts as installed and isn't nagged.
70
+ */
71
71
  readonly installed: boolean;
72
72
  /** Skill names with no `SKILL.md` under `&lt;root>/.agents/skills/&lt;name>/`. */
73
73
  readonly missing: ReadonlyArray<string>;
@@ -75,12 +75,12 @@ interface AgentRulesStatus {
75
75
  readonly present: ReadonlyArray<string>;
76
76
  }
77
77
  /**
78
- * Detect whether the Lunora agent skills are installed in `projectRoot` by
79
- * checking the skills folder for each `SKILL.md`. Pure filesystem reads, safe to
80
- * call on every dev-server / CLI startup — the CLI, the Vite plugin, and the
81
- * studio host all use it to decide whether to surface the "rules not installed"
82
- * hint.
83
- */
78
+ * Detect whether the Lunora agent skills are installed in `projectRoot` by
79
+ * checking the skills folder for each `SKILL.md`. Pure filesystem reads, safe to
80
+ * call on every dev-server / CLI startup — the CLI, the Vite plugin, and the
81
+ * studio host all use it to decide whether to surface the "rules not installed"
82
+ * hint.
83
+ */
84
84
  declare const detectAgentRules: (projectRoot: string) => AgentRulesStatus;
85
85
  interface DiscoverContainerInfoResult {
86
86
  /** Discovered container definitions; `[]` when none are declared or parsing failed. */
@@ -89,12 +89,12 @@ interface DiscoverContainerInfoResult {
89
89
  error?: string;
90
90
  }
91
91
  /**
92
- * Discover the project's `defineContainer` declarations. Returns
93
- * `{ containers: [] }` when the project has no `lunora/containers.ts` (not an
94
- * error), or `{ containers: [], error }` when the file exists but could not be
95
- * parsed — callers decide whether that is a warning (validator) or ignorable
96
- * (inference).
97
- */
92
+ * Discover the project's `defineContainer` declarations. Returns
93
+ * `{ containers: [] }` when the project has no `lunora/containers.ts` (not an
94
+ * error), or `{ containers: [], error }` when the file exists but could not be
95
+ * parsed — callers decide whether that is a warning (validator) or ignorable
96
+ * (inference).
97
+ */
98
98
  declare const discoverContainerInfo: (projectRoot: string, schemaDirectory: string) => DiscoverContainerInfoResult;
99
99
  /** Severity a container output line is surfaced at: `stderr` → `error`, `stdout` → `info`. */
100
100
  type ContainerLogLevel = "error" | "info";
@@ -160,25 +160,25 @@ interface DockerLike {
160
160
  };
161
161
  }
162
162
  /**
163
- * Follow the local Docker logs of every declared container, emitting each output
164
- * line through `onLine` tagged with its export name. Polls for containers (they
165
- * start lazily on first request and may be replaced on restart), attaches once
166
- * per container id, and drops streams whose container has gone. Returns
167
- * immediately with a `close()` handle; all work happens asynchronously.
168
- */
163
+ * Follow the local Docker logs of every declared container, emitting each output
164
+ * line through `onLine` tagged with its export name. Polls for containers (they
165
+ * start lazily on first request and may be replaced on restart), attaches once
166
+ * per container id, and drops streams whose container has gone. Returns
167
+ * immediately with a `close()` handle; all work happens asynchronously.
168
+ */
169
169
  declare const streamContainerLogs: (options: ContainerLogStreamOptions) => ContainerLogStreamHandle;
170
170
  /**
171
- * The meta-frameworks Lunora can compose with, plus `"none"` for a standalone
172
- * SPA / SSR-less project (the current default). Mirrors PLAN4 §2.4.
173
- */
171
+ * The meta-frameworks Lunora can compose with, plus `"none"` for a standalone
172
+ * SPA / SSR-less project (the current default). Mirrors PLAN4 §2.4.
173
+ */
174
174
  type DetectedFramework = "astro" | "none" | "nuxt" | "react-router" | "solid-start" | "sveltekit" | "tanstack-start" | "tanstack-start-solid";
175
175
  /**
176
- * void's class model (PLAN4 §3). Class A is Vite-native and Lunora owns the
177
- * worker entry (`createWorker({ httpRouter })`). Class B frameworks own their own
178
- * Cloudflare adapter, so Lunora injects its worker composition into the
179
- * framework's server entry via hooks (PLAN4 M4). Class C is non-CF / SSR-less —
180
- * ship the client adapter + a standalone Lunora worker (today's default).
181
- */
176
+ * void's class model (PLAN4 §3). Class A is Vite-native and Lunora owns the
177
+ * worker entry (`createWorker({ httpRouter })`). Class B frameworks own their own
178
+ * Cloudflare adapter, so Lunora injects its worker composition into the
179
+ * framework's server entry via hooks (PLAN4 M4). Class C is non-CF / SSR-less —
180
+ * ship the client adapter + a standalone Lunora worker (today's default).
181
+ */
182
182
  type FrameworkClass = "A" | "B" | "C";
183
183
  interface FrameworkDetection {
184
184
  /** void's composition class for the detected framework. */
@@ -187,20 +187,20 @@ interface FrameworkDetection {
187
187
  framework: DetectedFramework;
188
188
  }
189
189
  /**
190
- * Read and parse the project `package.json`, returning its merged
191
- * `dependencies` + `devDependencies` name set (empty on any failure). Public
192
- * so sibling consumers (e.g. the CLI's Vite-project detection) share one
193
- * best-effort reader instead of re-parsing `package.json` themselves.
194
- */
190
+ * Read and parse the project `package.json`, returning its merged
191
+ * `dependencies` + `devDependencies` name set (empty on any failure). Public
192
+ * so sibling consumers (e.g. the CLI's Vite-project detection) share one
193
+ * best-effort reader instead of re-parsing `package.json` themselves.
194
+ */
195
195
  declare const readProjectDependencyNames: (root: string) => ReadonlySet<string>;
196
196
  /**
197
- * Detect which meta-framework a project uses by inspecting its `package.json`
198
- * dependencies, and classify it under void's class-A/B/C model (PLAN4 §3).
199
- *
200
- * Pure and best-effort: never throws. An unknown / missing / malformed
201
- * `package.json` yields `{ framework: "none", class: "C" }` so the standalone
202
- * SPA flow is preserved.
203
- */
197
+ * Detect which meta-framework a project uses by inspecting its `package.json`
198
+ * dependencies, and classify it under void's class-A/B/C model (PLAN4 §3).
199
+ *
200
+ * Pure and best-effort: never throws. An unknown / missing / malformed
201
+ * `package.json` yields `{ framework: "none", class: "C" }` so the standalone
202
+ * SPA flow is preserved.
203
+ */
204
204
  declare const detectFramework: (root: string) => FrameworkDetection;
205
205
  /** Directory holding per-checkout Lunora state (gitignored by convention). */
206
206
  declare const DEV_STATE_DIR = ".lunora";
@@ -209,23 +209,23 @@ declare const DEV_STATE_FILE: string;
209
209
  /** Log file a backgrounded dev server's output is captured to, relative to the project root. */
210
210
  declare const DEV_LOG_FILE: string;
211
211
  /**
212
- * Marker env `lunora dev --background` sets on the detached server process
213
- * (the daemon `lunora dev` or `vite dev`), so it records itself as
214
- * `background: true` — and, for the CLI daemon, never re-detects an agent and
215
- * recurses into background mode again.
216
- */
212
+ * Marker env `lunora dev --background` sets on the detached server process
213
+ * (the daemon `lunora dev` or `vite dev`), so it records itself as
214
+ * `background: true` — and, for the CLI daemon, never re-detects an agent and
215
+ * recurses into background mode again.
216
+ */
217
217
  declare const DEV_DAEMON_ENV = "LUNORA_DEV_DAEMON";
218
218
  /** Env carrying the capture-log path into the detached server, recorded in the state file. */
219
219
  declare const DEV_LOG_FILE_ENV = "LUNORA_DEV_LOG_FILE";
220
220
  /**
221
- * Env carrying the PID of a parent that holds a *provisional* state record it
222
- * expects the child dev server to supersede. The CLI claims `.lunora/dev.json`
223
- * with its own PID before spawning the real server (closing the duplicate-start
224
- * race for the vite flavor and the wrangler daemon), then hands its PID down
225
- * via this variable; the child's claim (see {@link claimDevServerState}'s
226
- * `supersedePid`) may replace exactly that record with the authoritative
227
- * URL + PID.
228
- */
221
+ * Env carrying the PID of a parent that holds a *provisional* state record it
222
+ * expects the child dev server to supersede. The CLI claims `.lunora/dev.json`
223
+ * with its own PID before spawning the real server (closing the duplicate-start
224
+ * race for the vite flavor and the wrangler daemon), then hands its PID down
225
+ * via this variable; the child's claim (see {@link claimDevServerState}'s
226
+ * `supersedePid`) may replace exactly that record with the authoritative
227
+ * URL + PID.
228
+ */
229
229
  declare const DEV_HANDOFF_ENV = "LUNORA_DEV_HANDOFF_PID";
230
230
  /** How the recorded dev server runs. */
231
231
  type DevServerMode = "cli" | "vite";
@@ -247,56 +247,56 @@ interface DevServerState {
247
247
  url: string;
248
248
  }
249
249
  /**
250
- * True when a process with `pid` is currently alive AND signalable by this
251
- * user. Signal `0` performs the existence check without delivering anything.
252
- *
253
- * `EPERM` ("alive but another user's process") deliberately counts as NOT
254
- * alive here: every dev server this module tracks was spawned by the current
255
- * user, so a PID we cannot signal is by definition a recycled PID — treating
256
- * it as running would wedge the lockfile permanently and aim `dev stop`'s
257
- * kill escalation at an innocent process.
258
- */
250
+ * True when a process with `pid` is currently alive AND signalable by this
251
+ * user. Signal `0` performs the existence check without delivering anything.
252
+ *
253
+ * `EPERM` ("alive but another user's process") deliberately counts as NOT
254
+ * alive here: every dev server this module tracks was spawned by the current
255
+ * user, so a PID we cannot signal is by definition a recycled PID — treating
256
+ * it as running would wedge the lockfile permanently and aim `dev stop`'s
257
+ * kill escalation at an innocent process.
258
+ */
259
259
  declare const isProcessAlive: (pid: number) => boolean;
260
260
  /**
261
- * True when the record's PID verifiably still refers to the dev server that
262
- * wrote the record — not merely "some process exists with that number".
263
- * Guards against PID reuse: a server process necessarily starts BEFORE its
264
- * record is written, so a process that started after `startedAt` (+ skew) is
265
- * a recycled PID wearing the corpse's number. The start-time check runs only
266
- * where the platform exposes it (Linux); elsewhere liveness alone decides.
267
- */
261
+ * True when the record's PID verifiably still refers to the dev server that
262
+ * wrote the record — not merely "some process exists with that number".
263
+ * Guards against PID reuse: a server process necessarily starts BEFORE its
264
+ * record is written, so a process that started after `startedAt` (+ skew) is
265
+ * a recycled PID wearing the corpse's number. The start-time check runs only
266
+ * where the platform exposes it (Linux); elsewhere liveness alone decides.
267
+ */
268
268
  declare const isRecordedProcessCurrent: (state: DevServerState) => boolean;
269
269
  /**
270
- * Read the state record from `.lunora/dev.json`, or `undefined` when there is
271
- * no usable record. Best-effort; performs NO liveness check — use
272
- * {@link readLiveDevServerState} for "is a dev server actually running".
273
- */
270
+ * Read the state record from `.lunora/dev.json`, or `undefined` when there is
271
+ * no usable record. Best-effort; performs NO liveness check — use
272
+ * {@link readLiveDevServerState} for "is a dev server actually running".
273
+ */
274
274
  declare const readDevServerState: (projectRoot: string) => DevServerState | undefined;
275
275
  /**
276
- * Write the state record to `.lunora/dev.json`, creating the `.lunora/`
277
- * directory when absent. Returns the absolute path written, or `undefined`
278
- * when the write failed (state is convenience metadata — a read-only checkout
279
- * must never crash dev startup).
280
- */
276
+ * Write the state record to `.lunora/dev.json`, creating the `.lunora/`
277
+ * directory when absent. Returns the absolute path written, or `undefined`
278
+ * when the write failed (state is convenience metadata — a read-only checkout
279
+ * must never crash dev startup).
280
+ */
281
281
  declare const writeDevServerState: (projectRoot: string, state: DevServerState) => string | undefined;
282
282
  /**
283
- * Merge `patch` into the existing state record, when one exists. Used by the
284
- * CLI to stamp `background`/`logFile` onto the record the Vite plugin wrote.
285
- * Returns the merged record, or `undefined` when there was nothing to update.
286
- */
283
+ * Merge `patch` into the existing state record, when one exists. Used by the
284
+ * CLI to stamp `background`/`logFile` onto the record the Vite plugin wrote.
285
+ * Returns the merged record, or `undefined` when there was nothing to update.
286
+ */
287
287
  declare const updateDevServerState: (projectRoot: string, patch: Partial<DevServerState>) => DevServerState | undefined;
288
288
  /**
289
- * Remove `.lunora/dev.json`. Idempotent and never throws. When `expectedPid`
290
- * is given, the file is only removed while it still records that PID — so a
291
- * shutting-down server can't clobber the record a newer server just wrote.
292
- */
289
+ * Remove `.lunora/dev.json`. Idempotent and never throws. When `expectedPid`
290
+ * is given, the file is only removed while it still records that PID — so a
291
+ * shutting-down server can't clobber the record a newer server just wrote.
292
+ */
293
293
  declare const clearDevServerState: (projectRoot: string, expectedPid?: number) => void;
294
294
  /**
295
- * The state record of a dev server that is verifiably running right now, or
296
- * `undefined`. A record whose PID is dead — or recycled onto a different
297
- * process (see {@link isRecordedProcessCurrent}) — is stale: it is cleared on
298
- * the spot so subsequent starts don't keep re-reading a corpse.
299
- */
295
+ * The state record of a dev server that is verifiably running right now, or
296
+ * `undefined`. A record whose PID is dead — or recycled onto a different
297
+ * process (see {@link isRecordedProcessCurrent}) — is stale: it is cleared on
298
+ * the spot so subsequent starts don't keep re-reading a corpse.
299
+ */
300
300
  declare const readLiveDevServerState: (projectRoot: string) => DevServerState | undefined;
301
301
  /** Result of {@link claimDevServerState}: claimed, or lost to the live server already recorded. */
302
302
  interface ClaimDevServerStateResult {
@@ -309,27 +309,25 @@ declare const claimDevServerState: (projectRoot: string, state: DevServerState,
309
309
  supersedePid?: number;
310
310
  }) => ClaimDevServerStateResult;
311
311
  /**
312
- * The `.dev.vars` line grammar — one owner, shared by every reader/writer of the
313
- * file so the format can't drift between packages. `@lunora/cli`'s `env`
314
- * command (parse/serialize) and `@lunora/config`'s scaffolder (comment-
315
- * preserving rewrite) do different *transforms*, but they agree on these
316
- * primitives: the filename, what a `KEY` looks like, how lines split, and how
317
- * quotes strip.
318
- */
312
+ * The `.dev.vars` line grammar — one owner, shared by every reader/writer of the
313
+ * file so the format can't drift between packages. `@lunora/cli`'s `env`
314
+ * command (parse/serialize) and `@lunora/config`'s scaffolder (comment-
315
+ * preserving rewrite) do different *transforms*, but they agree on these
316
+ * primitives: the filename, what a `KEY` looks like, how lines split, and how
317
+ * quotes strip.
318
+ */
319
319
  /** The conventional filename for local Cloudflare dev secrets (gitignored). */
320
320
  declare const DEV_VARS_FILE: string;
321
321
  /** Its committed, secret-free counterpart that scaffolding reads from. */
322
322
  declare const DEV_VARS_EXAMPLE_FILE: string;
323
323
  /** A bare `KEY` identifier — the part left of `=` in a `.dev.vars` line. */
324
324
  declare const DEV_VARS_KEY_PATTERN: RegExp;
325
- /** Splits file content into lines on either newline style. */
326
-
327
- /**
328
- * Parse `.dev.vars` content into its `{ key, value }` entries, in file order,
329
- * with values unquoted and comments/blank/invalid lines dropped. The canonical
330
- * read of the whole file — callers that just want the variables (rather than a
331
- * comment-preserving rewrite) use this instead of hand-rolling the split loop.
332
- */
325
+ /**
326
+ * Parse `.dev.vars` content into its `{ key, value }` entries, in file order,
327
+ * with values unquoted and comments/blank/invalid lines dropped. The canonical
328
+ * read of the whole file callers that just want the variables (rather than a
329
+ * comment-preserving rewrite) use this instead of hand-rolling the split loop.
330
+ */
333
331
  declare const parseDevVariableEntries: (content: string) => {
334
332
  key: string;
335
333
  value: string;
@@ -341,53 +339,53 @@ interface DiscoverWorkflowInfoResult {
341
339
  workflows: ReadonlyArray<WorkflowIR>;
342
340
  }
343
341
  /**
344
- * Discover the project's `defineWorkflow` declarations. Returns
345
- * `{ workflows: [] }` when the project has no `lunora/workflows.ts` (not an
346
- * error), or `{ workflows: [], error }` when the file exists but could not be
347
- * parsed — callers decide whether that is a warning (validator) or ignorable
348
- * (inference).
349
- */
342
+ * Discover the project's `defineWorkflow` declarations. Returns
343
+ * `{ workflows: [] }` when the project has no `lunora/workflows.ts` (not an
344
+ * error), or `{ workflows: [], error }` when the file exists but could not be
345
+ * parsed — callers decide whether that is a warning (validator) or ignorable
346
+ * (inference).
347
+ */
350
348
  declare const discoverWorkflowInfo: (projectRoot: string, schemaDirectory: string) => DiscoverWorkflowInfoResult;
351
349
  interface DurableObjectSpec {
352
350
  binding: string;
353
351
  className: string;
354
352
  }
355
353
  /**
356
- * A `defineContainer` declaration plus whether its generated DO class is
357
- * exported by the worker entry. Only exported containers are safe to
358
- * provision — wrangler rejects a `containers[].class_name` (and its Durable
359
- * Object binding) that the worker doesn't export.
360
- */
354
+ * A `defineContainer` declaration plus whether its generated DO class is
355
+ * exported by the worker entry. Only exported containers are safe to
356
+ * provision — wrangler rejects a `containers[].class_name` (and its Durable
357
+ * Object binding) that the worker doesn't export.
358
+ */
361
359
  interface InferredContainer extends ContainerIR {
362
360
  exported: boolean;
363
361
  }
364
362
  /**
365
- * A `defineWorkflow` declaration plus whether its generated
366
- * `WorkflowEntrypoint` class is exported by the worker entry. Only exported
367
- * workflows are safe to provision — wrangler rejects a `workflows[].class_name`
368
- * the worker doesn't export. Workflows are NOT Durable Objects, so this never
369
- * implies a `durable_objects` binding or migration.
370
- */
363
+ * A `defineWorkflow` declaration plus whether its generated
364
+ * `WorkflowEntrypoint` class is exported by the worker entry. Only exported
365
+ * workflows are safe to provision — wrangler rejects a `workflows[].class_name`
366
+ * the worker doesn't export. Workflows are NOT Durable Objects, so this never
367
+ * implies a `durable_objects` binding or migration.
368
+ */
371
369
  interface InferredWorkflow extends WorkflowIR {
372
370
  exported: boolean;
373
371
  }
374
372
  /**
375
- * A `defineAgent` declaration plus whether its generated agent
376
- * `WorkflowEntrypoint` class (e.g. `SupportAgentWorkflow`) is exported by the
377
- * worker entry. An agent compiles onto a Cloudflare Workflow, so — exactly like
378
- * {@link InferredWorkflow} — only exported agents are safe to provision
379
- * (wrangler rejects a `workflows[].class_name` the worker doesn't export), and
380
- * an agent is NOT a Durable Object (no `durable_objects` binding or migration).
381
- */
373
+ * A `defineAgent` declaration plus whether its generated agent
374
+ * `WorkflowEntrypoint` class (e.g. `SupportAgentWorkflow`) is exported by the
375
+ * worker entry. An agent compiles onto a Cloudflare Workflow, so — exactly like
376
+ * {@link InferredWorkflow} — only exported agents are safe to provision
377
+ * (wrangler rejects a `workflows[].class_name` the worker doesn't export), and
378
+ * an agent is NOT a Durable Object (no `durable_objects` binding or migration).
379
+ */
382
380
  interface InferredAgent extends AgentIR {
383
381
  exported: boolean;
384
382
  }
385
383
  /**
386
- * A queue declared in `lunora/queues.ts`. Unlike workflows, a queue needs no
387
- * worker-entry class export (its `queue()` handler rides `createWorker`), so
388
- * there is no `exported` flag — every declared queue is reconcilable into the
389
- * wrangler `queues.producers[]` / `queues.consumers[]`.
390
- */
384
+ * A queue declared in `lunora/queues.ts`. Unlike workflows, a queue needs no
385
+ * worker-entry class export (its `queue()` handler rides `createWorker`), so
386
+ * there is no `exported` flag — every declared queue is reconcilable into the
387
+ * wrangler `queues.producers[]` / `queues.consumers[]`.
388
+ */
391
389
  type InferredQueue = QueueIR;
392
390
  interface InferredBindings {
393
391
  /** Agents declared in `lunora/agents.ts` (exported or not — see {@link InferredAgent.exported}); reconciled into `workflows[]`. */
@@ -397,11 +395,11 @@ interface InferredBindings {
397
395
  /** Durable Objects the worker entry exports → safe to bind. */
398
396
  durableObjects: DurableObjectSpec[];
399
397
  /**
400
- * The wrangler `flagship[].binding` name implied by `lunora/flags.ts` when it
401
- * uses the Flagship provider in binding mode — `undefined` for HTTP-mode
402
- * Flagship, a custom OpenFeature provider, or no flags. The binding needs an
403
- * un-mintable `app_id`, so it is reconciled as a hint, not auto-written.
404
- */
398
+ * The wrangler `flagship[].binding` name implied by `lunora/flags.ts` when it
399
+ * uses the Flagship provider in binding mode — `undefined` for HTTP-mode
400
+ * Flagship, a custom OpenFeature provider, or no flags. The binding needs an
401
+ * un-mintable `app_id`, so it is reconciled as a hint, not auto-written.
402
+ */
405
403
  flagshipBinding?: string;
406
404
  /** Schema declares a `.global()` table → needs the `DB` D1 binding. */
407
405
  needsD1: boolean;
@@ -450,33 +448,33 @@ interface InferOptions {
450
448
  schemaDir?: string;
451
449
  }
452
450
  /**
453
- * Scan a Lunora project and report which Cloudflare bindings its code implies.
454
- * Read-only: performs no writes. Binding provisioning is driven by the worker
455
- * entry's Durable Object exports plus the schema's D1 need; capability imports
456
- * surface as hints.
457
- */
451
+ * Scan a Lunora project and report which Cloudflare bindings its code implies.
452
+ * Read-only: performs no writes. Binding provisioning is driven by the worker
453
+ * entry's Durable Object exports plus the schema's D1 need; capability imports
454
+ * surface as hints.
455
+ */
458
456
  declare const inferLunoraBindings: (options: InferOptions) => Promise<InferredBindings>;
459
457
  /**
460
- * Derive the list of `@lunora/*` package names that are actively used by a
461
- * project, based on its already-resolved {@link InferredBindings}.
462
- *
463
- * This is the canonical bridge between binding inference and the package-aware
464
- * `.dev.vars.example` scaffolding in `scaffold-dev-variables.ts`. The result is
465
- * a stable, predictable slice of {@link CAPABILITY_SOURCES} source values,
466
- * filtered to the flags that are `true` in `bindings` — in CAPABILITY_SOURCES
467
- * declaration order.
468
- */
458
+ * Derive the list of `@lunora/*` package names that are actively used by a
459
+ * project, based on its already-resolved {@link InferredBindings}.
460
+ *
461
+ * This is the canonical bridge between binding inference and the package-aware
462
+ * `.dev.vars.example` scaffolding in `scaffold-dev-variables.ts`. The result is
463
+ * a stable, predictable slice of {@link CAPABILITY_SOURCES} source values,
464
+ * filtered to the flags that are `true` in `bindings` — in CAPABILITY_SOURCES
465
+ * declaration order.
466
+ */
469
467
  declare const packageNamesFromBindings: (bindings: InferredBindings) => string[];
470
468
  /** Directory holding per-checkout Lunora state (gitignored by convention). */
471
469
  declare const LINKED_PROJECT_DIR = ".lunora";
472
470
  /** The canonical link filename, relative to the project root. */
473
471
  declare const LINKED_PROJECT_FILE: string;
474
472
  /**
475
- * The link record persisted to `.lunora/project.json`. Every field is optional
476
- * so a partially-populated link (e.g. a worker name with no URL yet) still
477
- * round-trips. `linkedAt` is an ISO-8601 stamp written at link time, purely
478
- * informational.
479
- */
473
+ * The link record persisted to `.lunora/project.json`. Every field is optional
474
+ * so a partially-populated link (e.g. a worker name with no URL yet) still
475
+ * round-trips. `linkedAt` is an ISO-8601 stamp written at link time, purely
476
+ * informational.
477
+ */
480
478
  interface LinkedProject {
481
479
  /** Cloudflare account id the worker lives under, when known. */
482
480
  account?: string;
@@ -490,34 +488,17 @@ interface LinkedProject {
490
488
  workerUrl?: string;
491
489
  }
492
490
  /**
493
- * Read the link record from `.lunora/project.json`, or `undefined` when there
494
- * is no usable link. Best-effort: a missing file, parse error, or unexpected
495
- * shape all collapse to `undefined`.
496
- */
491
+ * Read the link record from `.lunora/project.json`, or `undefined` when there
492
+ * is no usable link. Best-effort: a missing file, parse error, or unexpected
493
+ * shape all collapse to `undefined`.
494
+ */
497
495
  declare const readLinkedProject: (projectRoot: string) => LinkedProject | undefined;
498
496
  /**
499
- * Write the link record to `.lunora/project.json`, creating the `.lunora/`
500
- * directory when absent. Only defined fields are persisted (so an empty value
501
- * never clobbers a known one). Returns the absolute path written.
502
- */
497
+ * Write the link record to `.lunora/project.json`, creating the `.lunora/`
498
+ * directory when absent. Only defined fields are persisted (so an empty value
499
+ * never clobbers a known one). Returns the absolute path written.
500
+ */
503
501
  declare const writeLinkedProject: (projectRoot: string, link: LinkedProject) => string;
504
- /**
505
- * Shared formatter for the structured log events the Lunora runtime emits to the
506
- * worker's `console` during development. Both the CLI `dev` command and the Vite
507
- * plugin pipe worker output through `formatLunoraEvent` so a developer sees
508
- * attributed, readable lines instead of raw JSON.
509
- *
510
- * The runtime emits two event shapes, each a single `console` line tagged
511
- * `source: "lunora"` (see `@lunora/do`'s `request-log.ts`): a `type: "log"`
512
- * event per `ctx.log.*` call, and a `type: "request"` event per RPC dispatch
513
- * (opt-in for successful calls, always for errors).
514
- *
515
- * This module is intentionally dependency-free and colour-free: it returns the
516
- * severity plus a plain display string, leaving ANSI/level colouring to each
517
- * caller (the CLI routes through its `pail` logger; the Vite plugin dims inline).
518
- * Any line that is not a lunora event returns `undefined`, signalling the caller
519
- * to pass it through unchanged.
520
- */
521
502
  /** Severity a formatted line should be surfaced at, mapped onto the three logger channels. */
522
503
  type LunoraLineLevel = "error" | "info" | "warn";
523
504
  /** A formatted lunora event: the channel to surface it on, the display text, and which event produced it. */
@@ -532,11 +513,11 @@ interface LunoraFormattedLine {
532
513
  /** Stable `source` tag every lunora console event carries. Mirrors `REQUEST_LOG_EVENT_SOURCE` in `@lunora/do`. */
533
514
  declare const LUNORA_EVENT_SOURCE = "lunora";
534
515
  /**
535
- * Parse a single worker-output line and, when it is a lunora structured event,
536
- * return its severity plus display text. Returns `undefined` for anything else —
537
- * non-JSON lines, JSON that isn't a lunora event, or an unrecognised event type
538
- * — so the caller passes the original line through untouched. Pure and total.
539
- */
516
+ * Parse a single worker-output line and, when it is a lunora structured event,
517
+ * return its severity plus display text. Returns `undefined` for anything else —
518
+ * non-JSON lines, JSON that isn't a lunora event, or an unrecognised event type
519
+ * — so the caller passes the original line through untouched. Pure and total.
520
+ */
540
521
  declare const formatLunoraEvent: (line: string) => LunoraFormattedLine | undefined;
541
522
  declare class LunoraReporter {
542
523
  #private;
@@ -545,32 +526,32 @@ declare class LunoraReporter {
545
526
  log(meta: unknown): void;
546
527
  }
547
528
  /**
548
- * Per-package secret-requirements registry for `.dev.vars` scaffolding.
549
- *
550
- * Each entry maps a `@lunora/*` package name → the secrets it requires at
551
- * runtime, expressed as `{ key, description, docsUrl }` records. The scaffolder
552
- * in {@link ./scaffold-dev-variables} reads this registry to emit package-aware
553
- * `.dev.vars.example` entries (placeholders + inline doc-pointer comments).
554
- *
555
- * ## Adding a new add-on
556
- *
557
- * When a new `@lunora/*` package requires runtime secrets, add one entry to
558
- * {@link PACKAGE_SECRETS_REGISTRY} keyed by its exact npm package name. Each
559
- * `SecretEntry` in the array needs:
560
- *
561
- * - `key` — the env-var name the package reads from `env` (e.g. `RESEND_API_KEY`).
562
- * - `description` — one line describing the secret and how to obtain it.
563
- * - `docsUrl` — a stable URL to the package/provider docs.
564
- *
565
- * The registry lives in `@lunora/config` so that add-ons themselves never need
566
- * to depend on it (no circular coupling). Add-ons document their secrets in
567
- * their own READMEs; the registry duplicates that knowledge in a machine-readable
568
- * form that the scaffolder can consume.
569
- *
570
- * **Never write a real secret value** in this file — `placeholderValue` entries
571
- * are the only allowed values (they must pass `isPlaceholderValue` from
572
- * scaffold-dev-variables).
573
- */
529
+ * Per-package secret-requirements registry for `.dev.vars` scaffolding.
530
+ *
531
+ * Each entry maps a `@lunora/*` package name → the secrets it requires at
532
+ * runtime, expressed as `{ key, description, docsUrl }` records. The scaffolder
533
+ * in {@link ./scaffold-dev-variables} reads this registry to emit package-aware
534
+ * `.dev.vars.example` entries (placeholders + inline doc-pointer comments).
535
+ *
536
+ * ## Adding a new add-on
537
+ *
538
+ * When a new `@lunora/*` package requires runtime secrets, add one entry to
539
+ * {@link PACKAGE_SECRETS_REGISTRY} keyed by its exact npm package name. Each
540
+ * `SecretEntry` in the array needs:
541
+ *
542
+ * - `key` — the env-var name the package reads from `env` (e.g. `RESEND_API_KEY`).
543
+ * - `description` — one line describing the secret and how to obtain it.
544
+ * - `docsUrl` — a stable URL to the package/provider docs.
545
+ *
546
+ * The registry lives in `@lunora/config` so that add-ons themselves never need
547
+ * to depend on it (no circular coupling). Add-ons document their secrets in
548
+ * their own READMEs; the registry duplicates that knowledge in a machine-readable
549
+ * form that the scaffolder can consume.
550
+ *
551
+ * **Never write a real secret value** in this file — `placeholderValue` entries
552
+ * are the only allowed values (they must pass `isPlaceholderValue` from
553
+ * scaffold-dev-variables).
554
+ */
574
555
  /** A single secret variable required by a package. */
575
556
  interface SecretEntry {
576
557
  /** One sentence describing what this secret is and how to obtain it. */
@@ -580,96 +561,87 @@ interface SecretEntry {
580
561
  /** The env-var key as it appears in `.dev.vars`, e.g. `AUTH_SECRET`. */
581
562
  key: string;
582
563
  /**
583
- * The placeholder value written into `.dev.vars.example`.
584
- * Must pass `isPlaceholderValue` from scaffold-dev-variables so the
585
- * scaffolder regenerates it when generating `.dev.vars`. Use angle-bracket
586
- * conventions or a recognised marker like `replace-with-openssl-rand-hex-32`.
587
- * Non-secret env-vars (e.g. `AUTH_URL`) may carry a real default value.
588
- */
564
+ * The placeholder value written into `.dev.vars.example`.
565
+ * Must pass `isPlaceholderValue` from scaffold-dev-variables so the
566
+ * scaffolder regenerates it when generating `.dev.vars`. Use angle-bracket
567
+ * conventions or a recognised marker like `replace-with-openssl-rand-hex-32`.
568
+ * Non-secret env-vars (e.g. `AUTH_URL`) may carry a real default value.
569
+ */
589
570
  placeholderValue: string;
590
571
  }
591
572
  /**
592
- * Secrets every Lunora project needs regardless of which capability packages are
593
- * installed — scaffolded into `.dev.vars` always. `LUNORA_ADMIN_TOKEN` is the
594
- * bearer the local Studio uses to call the worker's admin endpoints (the data
595
- * browser, schema edits) in dev; the worker reads the SAME `.dev.vars` value via
596
- * its admin gate, so both agree and the Studio authenticates without a prompt.
597
- * Without it, every `/_lunora/admin/*` call is `ADMIN_FORBIDDEN` (403).
598
- */
599
-
600
- /**
601
- * The canonical registry of per-package secret requirements.
602
- *
603
- * Keys are exact npm package names (e.g. `"@lunora/auth"`). Values are
604
- * non-empty arrays of {@link SecretEntry} — one entry per required secret key.
605
- *
606
- * The scaffolder in `scaffold-dev-variables.ts` calls
607
- * {@link secretsForPackages} to resolve the applicable entries from this map
608
- * given the set of detected capability package names.
609
- */
573
+ * The canonical registry of per-package secret requirements.
574
+ *
575
+ * Keys are exact npm package names (e.g. `"@lunora/auth"`). Values are
576
+ * non-empty arrays of {@link SecretEntry} one entry per required secret key.
577
+ *
578
+ * The scaffolder in `scaffold-dev-variables.ts` calls
579
+ * {@link secretsForPackages} to resolve the applicable entries from this map
580
+ * given the set of detected capability package names.
581
+ */
610
582
  declare const PACKAGE_SECRETS_REGISTRY: Readonly<Record<string, ReadonlyArray<SecretEntry>>>;
611
583
  /**
612
- * Collect all secret entries required by the given set of package names. The
613
- * order follows the order of `packageNames` (stable, predictable output), and
614
- * within each package the entries are returned in registry declaration order.
615
- *
616
- * Only packages present in {@link PACKAGE_SECRETS_REGISTRY} contribute entries;
617
- * unknown package names are silently ignored — this makes the call site resilient
618
- * to future capability flags whose packages have no secrets.
619
- */
584
+ * Collect all secret entries required by the given set of package names. The
585
+ * order follows the order of `packageNames` (stable, predictable output), and
586
+ * within each package the entries are returned in registry declaration order.
587
+ *
588
+ * Only packages present in {@link PACKAGE_SECRETS_REGISTRY} contribute entries;
589
+ * unknown package names are silently ignored — this makes the call site resilient
590
+ * to future capability flags whose packages have no secrets.
591
+ */
620
592
  declare const secretsForPackages: (packageNames: ReadonlyArray<string>) => SecretEntry[];
621
593
  /** The canonical project-config filename probed at the project root. */
622
594
  declare const LUNORA_CONFIG_FILE = "lunora.json";
623
595
  /**
624
- * The parsed `remote` preference from `lunora.json`:
625
- *
626
- * - `true` / `false` — the boolean form: enable or explicitly disable remote dev.
627
- * - `undefined` — no usable preference (file absent, key absent, or malformed).
628
- *
629
- * The object form (scoping which binding kinds go remote) is reserved for a
630
- * future increment; for now an object value is treated as "enabled" (truthy
631
- * presence) so forward-written configs still turn remote on.
632
- */
596
+ * The parsed `remote` preference from `lunora.json`:
597
+ *
598
+ * - `true` / `false` — the boolean form: enable or explicitly disable remote dev.
599
+ * - `undefined` — no usable preference (file absent, key absent, or malformed).
600
+ *
601
+ * The object form (scoping which binding kinds go remote) is reserved for a
602
+ * future increment; for now an object value is treated as "enabled" (truthy
603
+ * presence) so forward-written configs still turn remote on.
604
+ */
633
605
  type RemotePreference = boolean | undefined;
634
606
  /** The structural slice of `lunora.json` Lunora reads. */
635
607
  interface LunoraProjectConfig {
636
608
  remote?: unknown;
637
609
  }
638
610
  /**
639
- * Interpret a raw `remote` value into a tri-state preference. A boolean passes
640
- * through; an object is treated as enabled (the documented-but-not-yet-honored
641
- * scoping form is still an opt-in); anything else (string, number, null) is no
642
- * preference.
643
- */
611
+ * Interpret a raw `remote` value into a tri-state preference. A boolean passes
612
+ * through; an object is treated as enabled (the documented-but-not-yet-honored
613
+ * scoping form is still an opt-in); anything else (string, number, null) is no
614
+ * preference.
615
+ */
644
616
  declare const interpretRemote: (value: unknown) => RemotePreference;
645
617
  /**
646
- * Read the project's `remote` preference from `lunora.json`, or `undefined` when
647
- * there's no usable preference. Best-effort: never throws — a missing file,
648
- * parse error, or unexpected shape all collapse to `undefined` so the caller
649
- * falls through to the env/flag layers.
650
- */
618
+ * Read the project's `remote` preference from `lunora.json`, or `undefined` when
619
+ * there's no usable preference. Best-effort: never throws — a missing file,
620
+ * parse error, or unexpected shape all collapse to `undefined` so the caller
621
+ * falls through to the env/flag layers.
622
+ */
651
623
  declare const readProjectRemotePreference: (projectRoot: string) => RemotePreference;
652
624
  /**
653
- * Whether we can interactively prompt — stdin must be a TTY. In CI / piped
654
- * contexts this is false, and callers should fall back to a non-interactive
655
- * default (skip, or require an explicit `--yes`) rather than hang on a read.
656
- */
625
+ * Whether we can interactively prompt — stdin must be a TTY. In CI / piped
626
+ * contexts this is false, and callers should fall back to a non-interactive
627
+ * default (skip, or require an explicit `--yes`) rather than hang on a read.
628
+ */
657
629
  declare const isInteractive: () => boolean;
658
630
  /**
659
- * Ask a yes/no question on stdin. With `defaultYes`, an empty answer (just
660
- * Enter) counts as yes and the prompt should read `[Y/n]`; otherwise empty is
661
- * no (`[y/N]`). Shared by the CLI (`reset`, `dev`) and the Vite dev server.
662
- */
631
+ * Ask a yes/no question on stdin. With `defaultYes`, an empty answer (just
632
+ * Enter) counts as yes and the prompt should read `[Y/n]`; otherwise empty is
633
+ * no (`[y/N]`). Shared by the CLI (`reset`, `dev`) and the Vite dev server.
634
+ */
663
635
  declare const promptYesNo: (prompt: string, options?: {
664
636
  defaultYes?: boolean;
665
637
  }) => Promise<boolean>;
666
638
  /**
667
- * Build a default-yes `confirm(message)` for the scaffolders' `ensureDevVariables`:
668
- * an interactive `[Y/n]` prompt (optionally prefixed, e.g. `"[lunora] "`) when
669
- * stdin is a TTY, or an immediate `false` otherwise — so CI declines silently
670
- * instead of blocking. Keeps the "non-interactive ⇒ decline" policy in one place
671
- * rather than re-stated at every call site.
672
- */
639
+ * Build a default-yes `confirm(message)` for the scaffolders' `ensureDevVariables`:
640
+ * an interactive `[Y/n]` prompt (optionally prefixed, e.g. `"[lunora] "`) when
641
+ * stdin is a TTY, or an immediate `false` otherwise — so CI declines silently
642
+ * instead of blocking. Keeps the "non-interactive ⇒ decline" policy in one place
643
+ * rather than re-stated at every call site.
644
+ */
673
645
  declare const createConfirm: (prefix?: string) => ((message: string) => Promise<boolean>);
674
646
  /** One choice in a {@link promptSelect} list. `value` is returned; `label` (and optional `description`) are shown. */
675
647
  interface SelectOption<T extends string> {
@@ -678,50 +650,50 @@ interface SelectOption<T extends string> {
678
650
  value: T;
679
651
  }
680
652
  /**
681
- * Ask the user to pick one option from a numbered list on stdin. Accepts the
682
- * 1-based number or the option's `value`/`label` typed verbatim; an empty answer
683
- * (just Enter) takes `settings.default`. In a non-interactive context (CI /
684
- * piped — no TTY) it never reads and returns `settings.default` (or `undefined`),
685
- * mirroring {@link createConfirm}'s "non-interactive ⇒ fall back" policy so
686
- * automation never blocks.
687
- */
653
+ * Ask the user to pick one option from a numbered list on stdin. Accepts the
654
+ * 1-based number or the option's `value`/`label` typed verbatim; an empty answer
655
+ * (just Enter) takes `settings.default`. In a non-interactive context (CI /
656
+ * piped — no TTY) it never reads and returns `settings.default` (or `undefined`),
657
+ * mirroring {@link createConfirm}'s "non-interactive ⇒ fall back" policy so
658
+ * automation never blocks.
659
+ */
688
660
  declare const promptSelect: <T extends string>(message: string, options: ReadonlyArray<SelectOption<T>>, settings?: {
689
661
  default?: T;
690
662
  }) => Promise<T | undefined>;
691
663
  /**
692
- * Ask a free-text question on stdin, returning the trimmed answer. An empty
693
- * answer (just Enter) takes `settings.default`. In a non-interactive context
694
- * (CI / piped — no TTY) it never reads and returns `settings.default` (or
695
- * `undefined`), mirroring {@link promptSelect}'s "non-interactive ⇒ fall back"
696
- * policy so automation never blocks.
697
- */
664
+ * Ask a free-text question on stdin, returning the trimmed answer. An empty
665
+ * answer (just Enter) takes `settings.default`. In a non-interactive context
666
+ * (CI / piped — no TTY) it never reads and returns `settings.default` (or
667
+ * `undefined`), mirroring {@link promptSelect}'s "non-interactive ⇒ fall back"
668
+ * policy so automation never blocks.
669
+ */
698
670
  declare const promptText: (message: string, settings?: {
699
671
  default?: string;
700
672
  }) => Promise<string | undefined>;
701
673
  /** One choice in a {@link promptMultiSelect} list. Identical shape to {@link SelectOption}; `value` is returned when picked. */
702
674
  type MultiSelectOption<T extends string> = SelectOption<T>;
703
675
  /**
704
- * Ask the user to pick zero or more options from a numbered list on stdin.
705
- * Accepts a comma- or space-separated list of 1-based numbers and/or option
706
- * `value`/`label`s typed verbatim; an empty answer (just Enter) takes
707
- * `settings.defaults`. In a non-interactive context (CI / piped — no TTY) it
708
- * never reads and returns `settings.defaults ?? []`, mirroring {@link promptSelect}'s
709
- * "non-interactive ⇒ fall back" policy so automation never blocks. Unknown
710
- * tokens are ignored; the returned list is de-duplicated and preserves option
711
- * order.
712
- */
676
+ * Ask the user to pick zero or more options from a numbered list on stdin.
677
+ * Accepts a comma- or space-separated list of 1-based numbers and/or option
678
+ * `value`/`label`s typed verbatim; an empty answer (just Enter) takes
679
+ * `settings.defaults`. In a non-interactive context (CI / piped — no TTY) it
680
+ * never reads and returns `settings.defaults ?? []`, mirroring {@link promptSelect}'s
681
+ * "non-interactive ⇒ fall back" policy so automation never blocks. Unknown
682
+ * tokens are ignored; the returned list is de-duplicated and preserves option
683
+ * order.
684
+ */
713
685
  declare const promptMultiSelect: <T extends string>(message: string, options: ReadonlyArray<MultiSelectOption<T>>, settings?: {
714
686
  defaults?: ReadonlyArray<T>;
715
687
  }) => Promise<T[]>;
716
688
  /**
717
- * A container/workflow that is declared (so codegen emits its class) but the
718
- * worker entry never re-exports — the one wiring step the generators can't always
719
- * do for the developer. wrangler rejects a `class_name` the deployed worker
720
- * doesn't export, so a deploy fails late on this; surfacing it as structured data
721
- * lets the Vite plugin raise it in the dev error overlay (not just the console)
722
- * the moment the gap appears. The human-readable form is also folded into
723
- * {@link ReconcileBindingsResult.warnings}.
724
- */
689
+ * A container/workflow that is declared (so codegen emits its class) but the
690
+ * worker entry never re-exports — the one wiring step the generators can't always
691
+ * do for the developer. wrangler rejects a `class_name` the deployed worker
692
+ * doesn't export, so a deploy fails late on this; surfacing it as structured data
693
+ * lets the Vite plugin raise it in the dev error overlay (not just the console)
694
+ * the moment the gap appears. The human-readable form is also folded into
695
+ * {@link ReconcileBindingsResult.warnings}.
696
+ */
725
697
  interface ExportGap {
726
698
  /** Generated class wrangler needs exported, e.g. `OrderPipelineWorkflow`. */
727
699
  className: string;
@@ -738,10 +710,10 @@ interface ReconcileBindingsResult {
738
710
  /** `true` when `wrangler.jsonc` was rewritten. */
739
711
  changed: boolean;
740
712
  /**
741
- * Declared containers/workflows the worker entry doesn't re-export — the
742
- * structured form of the corresponding `warnings` entries, for the dev error
743
- * overlay. Empty when every declaration is wired.
744
- */
713
+ * Declared containers/workflows the worker entry doesn't re-export — the
714
+ * structured form of the corresponding `warnings` entries, for the dev error
715
+ * overlay. Empty when every declaration is wired.
716
+ */
745
717
  exportGaps: ExportGap[];
746
718
  /** Reason reconciliation was skipped, for logging. */
747
719
  reason?: string;
@@ -751,11 +723,11 @@ interface ReconcileBindingsResult {
751
723
  wranglerPath?: string;
752
724
  }
753
725
  /**
754
- * Reconcile inferred Durable Object / D1 bindings into `wrangler.jsonc`.
755
- *
756
- * Writes only when something is missing; returns `changed: false` when the
757
- * config already satisfies the inferred needs.
758
- */
726
+ * Reconcile inferred Durable Object / D1 bindings into `wrangler.jsonc`.
727
+ *
728
+ * Writes only when something is missing; returns `changed: false` when the
729
+ * config already satisfies the inferred needs.
730
+ */
759
731
  declare const reconcileWranglerBindings: (projectRoot: string, inferred: InferredBindings) => ReconcileBindingsResult;
760
732
  interface ReconcileCompatibilityDateResult {
761
733
  /** `true` when `wrangler.jsonc` was rewritten. */
@@ -768,9 +740,9 @@ interface ReconcileCompatibilityDateResult {
768
740
  wranglerPath?: string;
769
741
  }
770
742
  /**
771
- * Reconcile the `compatibility_date` in `wrangler.jsonc` when Workers Cache
772
- * is enabled but the date is below the minimum required.
773
- */
743
+ * Reconcile the `compatibility_date` in `wrangler.jsonc` when Workers Cache
744
+ * is enabled but the date is below the minimum required.
745
+ */
774
746
  declare const reconcileWranglerCompatibilityDate: (projectRoot: string) => ReconcileCompatibilityDateResult;
775
747
  interface ReconcileResult {
776
748
  /** `true` when `wrangler.jsonc` was rewritten. */
@@ -781,38 +753,38 @@ interface ReconcileResult {
781
753
  wranglerPath?: string;
782
754
  }
783
755
  /**
784
- * Reconcile the codegen-derived cron schedules into the project's
785
- * `wrangler.jsonc` `triggers.crons` array, preserving comments and formatting
786
- * via `jsonc-parser`'s structural edits.
787
- *
788
- * When `triggers.crons` already matches `cronTriggers`, nothing is written (so
789
- * we don't churn the file or trip the dev server's file watcher). When the
790
- * project declares no crons, a stale non-empty array is cleared so removed
791
- * crons stop firing.
792
- *
793
- * This intentionally writes the SAME `triggers.crons` shape the
794
- * `@lunora/config` validator accepts, so the wrangler validator never fights
795
- * the generated value.
796
- */
756
+ * Reconcile the codegen-derived cron schedules into the project's
757
+ * `wrangler.jsonc` `triggers.crons` array, preserving comments and formatting
758
+ * via `jsonc-parser`'s structural edits.
759
+ *
760
+ * When `triggers.crons` already matches `cronTriggers`, nothing is written (so
761
+ * we don't churn the file or trip the dev server's file watcher). When the
762
+ * project declares no crons, a stale non-empty array is cleared so removed
763
+ * crons stop firing.
764
+ *
765
+ * This intentionally writes the SAME `triggers.crons` shape the
766
+ * `@lunora/config` validator accepts, so the wrangler validator never fights
767
+ * the generated value.
768
+ */
797
769
  declare const reconcileWranglerCrons: (projectRoot: string, cronTriggers: ReadonlyArray<string>) => ReconcileResult;
798
770
  /**
799
- * The wrangler config sections Lunora can safely flip to remote mode in dev,
800
- * each with the human label used in logs and the structural `shape` the entry
801
- * lives in.
802
- *
803
- * `"array"` is a top-level array of binding objects (`d1_databases`,
804
- * `kv_namespaces`, `r2_buckets`, `vectorize`, `services`). `"producers"` is
805
- * `queues.producers[]` — consumers are NOT remoted (their schema has no `remote`
806
- * field) and the edit path is two levels deep. `"object"` is a single binding
807
- * object, not an array (`ai`), whose edit path targets the section key directly.
808
- *
809
- * Every kind here was confirmed against `wrangler/config-schema.json`: the
810
- * entry's schema declares a `remote` property. Deliberately omits
811
- * `durable_objects` (no CF remote-DO mode; shards stay local) and sections whose
812
- * schema has no `remote` field (`hyperdrive`, `analytics_engine_datasets`,
813
- * `secrets_store_secrets`, queue consumers, …). Widening further is a one-line
814
- * table edit.
815
- */
771
+ * The wrangler config sections Lunora can safely flip to remote mode in dev,
772
+ * each with the human label used in logs and the structural `shape` the entry
773
+ * lives in.
774
+ *
775
+ * `"array"` is a top-level array of binding objects (`d1_databases`,
776
+ * `kv_namespaces`, `r2_buckets`, `vectorize`, `services`). `"producers"` is
777
+ * `queues.producers[]` — consumers are NOT remoted (their schema has no `remote`
778
+ * field) and the edit path is two levels deep. `"object"` is a single binding
779
+ * object, not an array (`ai`), whose edit path targets the section key directly.
780
+ *
781
+ * Every kind here was confirmed against `wrangler/config-schema.json`: the
782
+ * entry's schema declares a `remote` property. Deliberately omits
783
+ * `durable_objects` (no CF remote-DO mode; shards stay local) and sections whose
784
+ * schema has no `remote` field (`hyperdrive`, `analytics_engine_datasets`,
785
+ * `secrets_store_secrets`, queue consumers, …). Widening further is a one-line
786
+ * table edit.
787
+ */
816
788
  declare const REMOTE_ELIGIBLE_KEYS: {
817
789
  readonly ai: {
818
790
  readonly label: "AI";
@@ -856,11 +828,11 @@ interface RemoteBindingPlan {
856
828
  /** Short kind label for logging (`"D1"`, `"KV"`, `"R2"`, `"Vectorize"`, …). */
857
829
  kind: string;
858
830
  /**
859
- * The jsonc edit path within {@link RemoteBindingPlan.section}, relative to
860
- * the section key: `[index]` for an `"array"` section, `["producers", index]`
861
- * for a queue producer, or `[]` for the single-object `ai` section. The
862
- * materializer prepends the section key and appends `"remote"`.
863
- */
831
+ * The jsonc edit path within {@link RemoteBindingPlan.section}, relative to
832
+ * the section key: `[index]` for an `"array"` section, `["producers", index]`
833
+ * for a queue producer, or `[]` for the single-object `ai` section. The
834
+ * materializer prepends the section key and appends `"remote"`.
835
+ */
864
836
  path: ReadonlyArray<number | string>;
865
837
  /** The wrangler config key the entry lives under. */
866
838
  section: RemoteEligibleKey;
@@ -878,19 +850,19 @@ interface RemoteWranglerShape {
878
850
  vectorize?: ReadonlyArray<BindingEntry | null | undefined>;
879
851
  }
880
852
  /**
881
- * Inspect a parsed wrangler config and list every eligible binding that should
882
- * be flipped to remote mode. Pure — no file-system access, no mutation. An
883
- * entry already carrying `"remote": true` is still reported (so logging is
884
- * complete) but the materializer's edit is a harmless no-op for it.
885
- */
853
+ * Inspect a parsed wrangler config and list every eligible binding that should
854
+ * be flipped to remote mode. Pure — no file-system access, no mutation. An
855
+ * entry already carrying `"remote": true` is still reported (so logging is
856
+ * complete) but the materializer's edit is a harmless no-op for it.
857
+ */
886
858
  declare const planRemoteBindings: (parsed: RemoteWranglerShape) => RemoteBindingPlan[];
887
859
  /**
888
- * Inject `"remote": true` onto each planned binding in the config `text`,
889
- * comment-preservingly via jsonc edits. Pure string→string; the edits target
890
- * disjoint entries so applying them sequentially is safe. The edit path is
891
- * `[section, ...plan.path, "remote"]`, which resolves to the array element, the
892
- * `queues.producers[i]` entry, or the single `ai` object as the plan demands.
893
- */
860
+ * Inject `"remote": true` onto each planned binding in the config `text`,
861
+ * comment-preservingly via jsonc edits. Pure string→string; the edits target
862
+ * disjoint entries so applying them sequentially is safe. The edit path is
863
+ * `[section, ...plan.path, "remote"]`, which resolves to the array element, the
864
+ * `queues.producers[i]` entry, or the single `ai` object as the plan demands.
865
+ */
894
866
  declare const injectRemoteFlags: (text: string, plans: ReadonlyArray<RemoteBindingPlan>) => string;
895
867
  interface MaterializeOptions {
896
868
  /** When `false`, the call is a no-op (returns `enabled: false`). */
@@ -899,18 +871,18 @@ interface MaterializeOptions {
899
871
  }
900
872
  interface MaterializeResult {
901
873
  /**
902
- * Removes the generated temp config file. Always present and always safe to
903
- * call: it is idempotent, a no-op when nothing was written (disabled /
904
- * fall-through cases), and never throws if the path is already gone. The dev
905
- * command calls this on every exit path (normal, signal, error).
906
- */
874
+ * Removes the generated temp config file. Always present and always safe to
875
+ * call: it is idempotent, a no-op when nothing was written (disabled /
876
+ * fall-through cases), and never throws if the path is already gone. The dev
877
+ * command calls this on every exit path (normal, signal, error).
878
+ */
907
879
  cleanup: () => void;
908
880
  /**
909
- * Absolute path to the generated temp config to pass to
910
- * `wrangler dev --config`. `undefined` when remote mode is disabled, no
911
- * wrangler config was found, it failed to parse, or it declared no eligible
912
- * binding (nothing to remote — run plain local dev).
913
- */
881
+ * Absolute path to the generated temp config to pass to
882
+ * `wrangler dev --config`. `undefined` when remote mode is disabled, no
883
+ * wrangler config was found, it failed to parse, or it declared no eligible
884
+ * binding (nothing to remote — run plain local dev).
885
+ */
914
886
  configPath?: string;
915
887
  /** Whether remote mode was requested at all. */
916
888
  enabled: boolean;
@@ -920,33 +892,33 @@ interface MaterializeResult {
920
892
  remoteBindings: RemoteBindingPlan[];
921
893
  }
922
894
  /**
923
- * Produce a temporary wrangler config with `"remote": true` on every eligible
924
- * binding, so `lunora dev` can run `wrangler dev --config &lt;temp>` against the
925
- * deployed D1/KV/R2 without touching the user's file.
926
- *
927
- * The temp file is written as a sibling of the source `wrangler.jsonc` (in the
928
- * project root), NOT an OS temp dir: wrangler resolves a config's relative paths
929
- * (`main`, `assets`, `migrations_dir`, …) against the **config file's own
930
- * directory**, so a temp config in `/tmp` would make wrangler look for
931
- * `/tmp/src/server.ts` and fail to start the worker. Keeping it beside the real
932
- * config preserves those relative paths. Returns `configPath: undefined` (with a
933
- * `reason`) for every fall-through case so the caller degrades to plain local
934
- * dev instead of failing.
935
- */
895
+ * Produce a temporary wrangler config with `"remote": true` on every eligible
896
+ * binding, so `lunora dev` can run `wrangler dev --config &lt;temp>` against the
897
+ * deployed D1/KV/R2 without touching the user's file.
898
+ *
899
+ * The temp file is written as a sibling of the source `wrangler.jsonc` (in the
900
+ * project root), NOT an OS temp dir: wrangler resolves a config's relative paths
901
+ * (`main`, `assets`, `migrations_dir`, …) against the **config file's own
902
+ * directory**, so a temp config in `/tmp` would make wrangler look for
903
+ * `/tmp/src/server.ts` and fail to start the worker. Keeping it beside the real
904
+ * config preserves those relative paths. Returns `configPath: undefined` (with a
905
+ * `reason`) for every fall-through case so the caller degrades to plain local
906
+ * dev instead of failing.
907
+ */
936
908
  declare const materializeRemoteWranglerConfig: (options: MaterializeOptions) => MaterializeResult;
937
909
  /**
938
- * Parse a `LUNORA_REMOTE` env value into the on/off decision. Truthy when set to
939
- * `"1"` or `"true"` (case-insensitive); anything else — unset, `"0"`, `"false"`,
940
- * empty — is off. Mirrors the `"1" | "true"` convention used across the runtime.
941
- */
910
+ * Parse a `LUNORA_REMOTE` env value into the on/off decision. Truthy when set to
911
+ * `"1"` or `"true"` (case-insensitive); anything else — unset, `"0"`, `"false"`,
912
+ * empty — is off. Mirrors the `"1" | "true"` convention used across the runtime.
913
+ */
942
914
  declare const isRemoteEnvEnabled: (value: string | undefined) => boolean;
943
915
  /** The three inputs that can switch remote-binding dev on, in precedence order. */
944
916
  interface RemoteEnableInputs {
945
917
  /**
946
- * The `remote` preference from `lunora.json` (the lowest-priority signal).
947
- * `undefined` means "no project preference"; an explicit `false` here loses
948
- * to neither the flag nor the env when those are absent — it just stays off.
949
- */
918
+ * The `remote` preference from `lunora.json` (the lowest-priority signal).
919
+ * `undefined` means "no project preference"; an explicit `false` here loses
920
+ * to neither the flag nor the env when those are absent — it just stays off.
921
+ */
950
922
  configPreference?: boolean;
951
923
  /** The raw `LUNORA_REMOTE` env value (parsed with {@link isRemoteEnvEnabled}). */
952
924
  envValue?: string;
@@ -954,44 +926,44 @@ interface RemoteEnableInputs {
954
926
  flag?: boolean;
955
927
  }
956
928
  /**
957
- * Resolve whether remote-binding dev is on, with a clear precedence:
958
- *
959
- * 1. an explicit `--remote` flag (highest — a deliberate per-invocation choice),
960
- * 2. then `LUNORA_REMOTE` in the environment,
961
- * 3. then the `remote` key in `lunora.json` (lowest — a project default).
962
- *
963
- * The flag and env are one-directional (they can only turn remote *on*); only
964
- * the config preference carries a meaningful `false`, and it applies solely when
965
- * neither stronger signal is present. So a project that sets `"remote": false`
966
- * is still overridable per-run by `--remote` or `LUNORA_REMOTE=1`.
967
- */
929
+ * Resolve whether remote-binding dev is on, with a clear precedence:
930
+ *
931
+ * 1. an explicit `--remote` flag (highest — a deliberate per-invocation choice),
932
+ * 2. then `LUNORA_REMOTE` in the environment,
933
+ * 3. then the `remote` key in `lunora.json` (lowest — a project default).
934
+ *
935
+ * The flag and env are one-directional (they can only turn remote *on*); only
936
+ * the config preference carries a meaningful `false`, and it applies solely when
937
+ * neither stronger signal is present. So a project that sets `"remote": false`
938
+ * is still overridable per-run by `--remote` or `LUNORA_REMOTE=1`.
939
+ */
968
940
  declare const resolveRemoteEnabled: (inputs: RemoteEnableInputs) => boolean;
969
941
  /** Core (always-scaffolded) secrets followed by the package-specific ones for the detected capabilities. */
970
942
  declare const requiredSecrets: (packageNames: ReadonlyArray<string>) => SecretEntry[];
971
943
  /**
972
- * Whether an (already-unquoted) value looks like a fill-me-in placeholder —
973
- * empty, angle-bracketed, or containing a known marker — rather than a real
974
- * value. Used both when scaffolding (which values to regenerate) and by
975
- * `lunora env doctor` (which set values are still unfilled).
976
- */
944
+ * Whether an (already-unquoted) value looks like a fill-me-in placeholder —
945
+ * empty, angle-bracketed, or containing a known marker — rather than a real
946
+ * value. Used both when scaffolding (which values to regenerate) and by
947
+ * `lunora env doctor` (which set values are still unfilled).
948
+ */
977
949
  declare const isPlaceholderValue: (value: string) => boolean;
978
950
  /**
979
- * True for a secret-looking key whose value Lunora can mint locally (a random
980
- * 32-byte hex, like `openssl rand -hex 32`) — e.g. `AUTH_SECRET`,
981
- * `LUNORA_ADMIN_TOKEN`, `STORAGE_SIGNING_SECRET`. False for provider-issued keys
982
- * ({@link PROVIDER_SECRET_KEYS}) and any non-secret key.
983
- */
951
+ * True for a secret-looking key whose value Lunora can mint locally (a random
952
+ * 32-byte hex, like `openssl rand -hex 32`) — e.g. `AUTH_SECRET`,
953
+ * `LUNORA_ADMIN_TOKEN`, `STORAGE_SIGNING_SECRET`. False for provider-issued keys
954
+ * ({@link PROVIDER_SECRET_KEYS}) and any non-secret key.
955
+ */
984
956
  declare const isMintableSecretKey: (key: string) => boolean;
985
957
  /** Mint a fresh strong secret value — 64 hex chars (32 bytes), like `openssl rand -hex 32`. */
986
958
  declare const generateSecretValue: (randomHex?: (bytes: number) => string) => string;
987
959
  /**
988
- * The outcome of planning a scaffold — a discriminated union so the orchestrator
989
- * never has to re-derive whether `content` is present.
990
- *
991
- * `exists`: `.dev.vars` is already there; nothing to do.
992
- * `no-example`: nothing to scaffold from (stay silent — the project may not use secrets).
993
- * `generate`: write `content`, a copy of the example with secret-looking placeholders replaced by fresh random hex (`generatedKeys` lists which).
994
- */
960
+ * The outcome of planning a scaffold — a discriminated union so the orchestrator
961
+ * never has to re-derive whether `content` is present.
962
+ *
963
+ * `exists`: `.dev.vars` is already there; nothing to do.
964
+ * `no-example`: nothing to scaffold from (stay silent — the project may not use secrets).
965
+ * `generate`: write `content`, a copy of the example with secret-looking placeholders replaced by fresh random hex (`generatedKeys` lists which).
966
+ */
995
967
  type ScaffoldPlan = {
996
968
  content: string;
997
969
  generatedKeys: string[];
@@ -1004,7 +976,8 @@ type ScaffoldPlan = {
1004
976
  /** Decide whether (and what) to scaffold. Pure — given the current state of the two files. */
1005
977
  declare const planDevVariablesScaffold: (input: {
1006
978
  devVarsExists: boolean;
1007
- exampleContent: string | undefined; /** Injectable for deterministic tests; defaults to `crypto.randomBytes`. */
979
+ exampleContent: string | undefined;
980
+ /** Injectable for deterministic tests; defaults to `crypto.randomBytes`. */
1008
981
  randomHex?: (bytes: number) => string;
1009
982
  }) => ScaffoldPlan;
1010
983
  interface AugmentPlan {
@@ -1016,22 +989,23 @@ interface AugmentPlan {
1016
989
  missingKeys: string[];
1017
990
  }
1018
991
  /**
1019
- * Plan how to top up an existing `.dev.vars` from the example: every example key
1020
- * not already present becomes an appended line (secret placeholders filled with
1021
- * fresh random hex, other values copied). Pure — no I/O. Empty `missingKeys`
1022
- * means the file is already complete.
1023
- */
992
+ * Plan how to top up an existing `.dev.vars` from the example: every example key
993
+ * not already present becomes an appended line (secret placeholders filled with
994
+ * fresh random hex, other values copied). Pure — no I/O. Empty `missingKeys`
995
+ * means the file is already complete.
996
+ */
1024
997
  declare const planDevVariablesAugment: (input: {
1025
998
  exampleContent: string;
1026
- existingContent: string; /** Injectable for deterministic tests; defaults to `crypto.randomBytes`. */
999
+ existingContent: string;
1000
+ /** Injectable for deterministic tests; defaults to `crypto.randomBytes`. */
1027
1001
  randomHex?: (bytes: number) => string;
1028
1002
  }) => AugmentPlan;
1029
1003
  interface EnsureDevVariablesDeps {
1030
1004
  /**
1031
- * Ask the user to confirm generating the file. Return `true` to generate.
1032
- * Consumers pass a TTY-aware prompt; in non-interactive contexts they should
1033
- * resolve `false` (we then report `"declined"` and the caller can hint).
1034
- */
1005
+ * Ask the user to confirm generating the file. Return `true` to generate.
1006
+ * Consumers pass a TTY-aware prompt; in non-interactive contexts they should
1007
+ * resolve `false` (we then report `"declined"` and the caller can hint).
1008
+ */
1035
1009
  confirm: (message: string) => Promise<boolean>;
1036
1010
  cwd: string;
1037
1011
  /** Emit a human-facing line (success / hint). */
@@ -1050,41 +1024,41 @@ interface EnsureDevVariablesResult {
1050
1024
  status: EnsureDevVariablesStatus;
1051
1025
  }
1052
1026
  /**
1053
- * Reconcile the project's `.dev.vars` with its `.dev.vars.example`:
1054
- *
1055
- * - file missing → offer to generate it (secret placeholders auto-filled);
1056
- * - file present but missing keys the example lists → offer to append them;
1057
- * - file present and complete → nothing to do.
1058
- *
1059
- * Prompts via `confirm` (skipped when `yes`); never overwrites existing values.
1060
- * Returns what happened so the caller can tailor any follow-up. Shared by
1061
- * `lunora dev` and the `@lunora/vite` dev server. All side effects funnel
1062
- * through `confirm`/`info`/`randomHex`.
1063
- */
1027
+ * Reconcile the project's `.dev.vars` with its `.dev.vars.example`:
1028
+ *
1029
+ * - file missing → offer to generate it (secret placeholders auto-filled);
1030
+ * - file present but missing keys the example lists → offer to append them;
1031
+ * - file present and complete → nothing to do.
1032
+ *
1033
+ * Prompts via `confirm` (skipped when `yes`); never overwrites existing values.
1034
+ * Returns what happened so the caller can tailor any follow-up. Shared by
1035
+ * `lunora dev` and the `@lunora/vite` dev server. All side effects funnel
1036
+ * through `confirm`/`info`/`randomHex`.
1037
+ */
1064
1038
  declare const ensureDevVariables: (deps: EnsureDevVariablesDeps) => Promise<EnsureDevVariablesResult>;
1065
1039
  /**
1066
- * Build the text that should be merged into `.dev.vars.example` for the given
1067
- * set of package names. Only entries whose key is not already present in
1068
- * `existingKeys` are included (additive / idempotent). Returns an empty string
1069
- * when there is nothing to add.
1070
- *
1071
- * The output is grouped by package with a blank-line separator so the file
1072
- * reads cleanly when multiple packages each contribute several keys.
1073
- *
1074
- * **Safety invariant:** this function never writes a real secret — every value
1075
- * in the output is the entry's `placeholderValue`.
1076
- */
1040
+ * Build the text that should be merged into `.dev.vars.example` for the given
1041
+ * set of package names. Only entries whose key is not already present in
1042
+ * `existingKeys` are included (additive / idempotent). Returns an empty string
1043
+ * when there is nothing to add.
1044
+ *
1045
+ * The output is grouped by package with a blank-line separator so the file
1046
+ * reads cleanly when multiple packages each contribute several keys.
1047
+ *
1048
+ * **Safety invariant:** this function never writes a real secret — every value
1049
+ * in the output is the entry's `placeholderValue`.
1050
+ */
1077
1051
  declare const buildPackageSecretsBlock: (packageNames: ReadonlyArray<string>, existingKeys: ReadonlySet<string>) => string;
1078
1052
  /**
1079
- * Write (or update) `.dev.vars.example` so that it contains the secrets
1080
- * required by `packageNames`. Existing lines are never removed or rewritten;
1081
- * new entries are appended (with a blank-line separator after existing content).
1082
- *
1083
- * Idempotent: re-running with the same `packageNames` does not duplicate keys
1084
- * already in the file. Returns the list of keys that were actually appended.
1085
- *
1086
- * **Safety invariant:** only placeholder values are written — no real secrets.
1087
- */
1053
+ * Write (or update) `.dev.vars.example` so that it contains the secrets
1054
+ * required by `packageNames`. Existing lines are never removed or rewritten;
1055
+ * new entries are appended (with a blank-line separator after existing content).
1056
+ *
1057
+ * Idempotent: re-running with the same `packageNames` does not duplicate keys
1058
+ * already in the file. Returns the list of keys that were actually appended.
1059
+ *
1060
+ * **Safety invariant:** only placeholder values are written — no real secrets.
1061
+ */
1088
1062
  declare const ensureDevVariablesExample: (cwd: string, packageNames: ReadonlyArray<string>) => string[];
1089
1063
  interface DevSecretsFillPlan {
1090
1064
  /** {@link CORE_SECRETS} keys appended because they were absent (each generated). */
@@ -1095,19 +1069,19 @@ interface DevSecretsFillPlan {
1095
1069
  filledKeys: string[];
1096
1070
  }
1097
1071
  /**
1098
- * Plan the in-place generation of dev secrets for a `.dev.vars`. First, every
1099
- * line whose KEY looks like a secret (`*_SECRET`, `*_TOKEN`, `*_KEY`,
1100
- * `*_PASSWORD`) and whose value is empty or a placeholder gets a freshly
1101
- * generated value — so a `lunora add`-scaffolded `.dev.vars` (which writes each
1102
- * secret blank) becomes usable on `lunora dev` / `vite dev` without the user
1103
- * running `openssl` by hand. Second, any {@link CORE_SECRETS} key absent from
1104
- * the file is appended (generated) — notably `LUNORA_ADMIN_TOKEN`, which the
1105
- * local Studio needs to call the worker's admin gate in dev (without it the
1106
- * Studio shows its login gate).
1107
- *
1108
- * Pure (given `randomHex`): real (non-placeholder) values are never touched, and
1109
- * comments + non-secret entries are preserved verbatim.
1110
- */
1072
+ * Plan the in-place generation of dev secrets for a `.dev.vars`. First, every
1073
+ * line whose KEY looks like a secret (`*_SECRET`, `*_TOKEN`, `*_KEY`,
1074
+ * `*_PASSWORD`) and whose value is empty or a placeholder gets a freshly
1075
+ * generated value — so a `lunora add`-scaffolded `.dev.vars` (which writes each
1076
+ * secret blank) becomes usable on `lunora dev` / `vite dev` without the user
1077
+ * running `openssl` by hand. Second, any {@link CORE_SECRETS} key absent from
1078
+ * the file is appended (generated) — notably `LUNORA_ADMIN_TOKEN`, which the
1079
+ * local Studio needs to call the worker's admin gate in dev (without it the
1080
+ * Studio shows its login gate).
1081
+ *
1082
+ * Pure (given `randomHex`): real (non-placeholder) values are never touched, and
1083
+ * comments + non-secret entries are preserved verbatim.
1084
+ */
1111
1085
  declare const planDevSecretsFill: (input: {
1112
1086
  existingContent: string;
1113
1087
  randomHex?: (bytes: number) => string;
@@ -1121,18 +1095,18 @@ interface FillDevSecretsResult {
1121
1095
  status: "created" | "filled" | "unchanged";
1122
1096
  }
1123
1097
  /**
1124
- * Generate any missing/empty dev secrets in the project's `.dev.vars`, in place.
1125
- *
1126
- * Complements {@link ensureDevVariables} (which scaffolds `.dev.vars` from
1127
- * `.dev.vars.example`). A `lunora add`-scaffolded project writes secrets blank
1128
- * straight into `.dev.vars` (no example) and never includes `LUNORA_ADMIN_TOKEN`
1129
- * — so the worker boots with empty secrets and the Studio shows its login gate.
1130
- * This fills those gaps at dev startup, so both `lunora dev` and the
1131
- * `@lunora/vite` dev server give a working project with zero manual `openssl`.
1132
- *
1133
- * Never overwrites a real (non-placeholder) value. The write is atomic + owner-
1134
- * only (temp + rename, `mode: 0o600`), matching the other `.dev.vars` writers.
1135
- */
1098
+ * Generate any missing/empty dev secrets in the project's `.dev.vars`, in place.
1099
+ *
1100
+ * Complements {@link ensureDevVariables} (which scaffolds `.dev.vars` from
1101
+ * `.dev.vars.example`). A `lunora add`-scaffolded project writes secrets blank
1102
+ * straight into `.dev.vars` (no example) and never includes `LUNORA_ADMIN_TOKEN`
1103
+ * — so the worker boots with empty secrets and the Studio shows its login gate.
1104
+ * This fills those gaps at dev startup, so both `lunora dev` and the
1105
+ * `@lunora/vite` dev server give a working project with zero manual `openssl`.
1106
+ *
1107
+ * Never overwrites a real (non-placeholder) value. The write is atomic + owner-
1108
+ * only (temp + rename, `mode: 0o600`), matching the other `.dev.vars` writers.
1109
+ */
1136
1110
  declare const fillDevSecrets: (deps: {
1137
1111
  cwd: string;
1138
1112
  info?: (message: string) => void;
@@ -1149,11 +1123,11 @@ interface AddOptionalColumnEdit {
1149
1123
  readonly kind: "addOptionalColumn";
1150
1124
  readonly table: string;
1151
1125
  /**
1152
- * Inner validator expression text WITHOUT the `v.optional(...)` wrapper, e.g.
1153
- * `v.string()`. Always wrapped in `v.optional(...)` on apply, because only
1154
- * optional columns are additive-safe (a required column needs a backfill
1155
- * migration).
1156
- */
1126
+ * Inner validator expression text WITHOUT the `v.optional(...)` wrapper, e.g.
1127
+ * `v.string()`. Always wrapped in `v.optional(...)` on apply, because only
1128
+ * optional columns are additive-safe (a required column needs a backfill
1129
+ * migration).
1130
+ */
1157
1131
  readonly validator: string;
1158
1132
  }
1159
1133
  /** Add a secondary index to an existing table. */
@@ -1167,9 +1141,9 @@ interface AddIndexEdit {
1167
1141
  /** Additive edits — the only requests {@link applyAdditiveEdit} applies. */
1168
1142
  type AdditiveEdit = AddIndexEdit | AddOptionalColumnEdit | AddTableEdit;
1169
1143
  /**
1170
- * Destructive edits — never applied directly; routed to the migration handoff
1171
- * (plan 024 Item 5). Carried as data so the editor can describe the request.
1172
- */
1144
+ * Destructive edits — never applied directly; routed to the migration handoff
1145
+ * (plan 024 Item 5). Carried as data so the editor can describe the request.
1146
+ */
1173
1147
  interface DestructiveEdit {
1174
1148
  readonly column?: string;
1175
1149
  readonly kind: "changeColumnType" | "dropColumn" | "dropTable" | "makeRequired" | "renameColumn";
@@ -1180,9 +1154,9 @@ interface DestructiveEdit {
1180
1154
  /** Any edit the editor can request. */
1181
1155
  type SchemaEdit = AdditiveEdit | DestructiveEdit;
1182
1156
  /**
1183
- * Classify an edit request. Additive edits ({@link AdditiveEdit}) apply
1184
- * directly; everything else changes stored data and is destructive.
1185
- */
1157
+ * Classify an edit request. Additive edits ({@link AdditiveEdit}) apply
1158
+ * directly; everything else changes stored data and is destructive.
1159
+ */
1186
1160
  declare const classifyEdit: (edit: SchemaEdit) => "additive" | "destructive";
1187
1161
  /** Failure reasons an additive edit can report. */
1188
1162
  type ApplyFailureReason = "aliased-define-schema" | "destructive" | "duplicate-column" | "duplicate-index" | "duplicate-table" | "invalid-identifier" | "invalid-validator" | "no-define-schema" | "non-object-argument" | "unknown-table";
@@ -1195,10 +1169,10 @@ type ApplyEditResult = {
1195
1169
  text: string;
1196
1170
  };
1197
1171
  /**
1198
- * Apply an **additive** edit to a schema source string, preserving formatting.
1199
- * Destructive edits are refused with `{ ok: false, reason: "destructive" }`;
1200
- * route them through the migration handoff (plan 024 Item 5).
1201
- */
1172
+ * Apply an **additive** edit to a schema source string, preserving formatting.
1173
+ * Destructive edits are refused with `{ ok: false, reason: "destructive" }`;
1174
+ * route them through the migration handoff (plan 024 Item 5).
1175
+ */
1202
1176
  declare const applyAdditiveEdit: (source: string, edit: SchemaEdit) => ApplyEditResult;
1203
1177
  /** A single declared column: its name and the raw validator expression text. */
1204
1178
  interface SchemaColumn {
@@ -1237,16 +1211,10 @@ type ParseSchemaResult = {
1237
1211
  tables: ReadonlyArray<SchemaTable>;
1238
1212
  };
1239
1213
  /**
1240
- * Every `CallExpression` at or below a node. `getDescendantsOfKind` excludes the
1241
- * node itself, but a table initializer often is the outermost call in the
1242
- * `defineTable(...).global().index(...)` chain, so include it explicitly.
1243
- */
1244
-
1245
- /**
1246
- * Parse the tables (with typed columns + indexes) out of a `lunora/schema.ts`
1247
- * source string. Returns a tagged result so callers can render a helpful
1248
- * message per failure mode without throwing.
1249
- */
1214
+ * Parse the tables (with typed columns + indexes) out of a `lunora/schema.ts`
1215
+ * source string. Returns a tagged result so callers can render a helpful
1216
+ * message per failure mode without throwing.
1217
+ */
1250
1218
  declare const parseSchema: (source: string) => ParseSchemaResult;
1251
1219
  interface SchemaInfo {
1252
1220
  /** Whether the lunora schema declares any `.global()` table. */
@@ -1261,16 +1229,16 @@ interface DiscoverSchemaInfoResult {
1261
1229
  info: SchemaInfo | undefined;
1262
1230
  }
1263
1231
  /**
1264
- * Discover {@link SchemaInfo} for a project. Returns `{ info: undefined }` when
1265
- * the project declares no `schema.ts` (not an error), or `{ info: undefined,
1266
- * error }` when a present schema could not be parsed — callers decide whether a
1267
- * parse failure is a warning (validator) or simply ignorable (inference).
1268
- */
1232
+ * Discover {@link SchemaInfo} for a project. Returns `{ info: undefined }` when
1233
+ * the project declares no `schema.ts` (not an error), or `{ info: undefined,
1234
+ * error }` when a present schema could not be parsed — callers decide whether a
1235
+ * parse failure is a warning (validator) or simply ignorable (inference).
1236
+ */
1269
1237
  declare const discoverSchemaInfo: (projectRoot: string, schemaDirectory: string) => DiscoverSchemaInfoResult;
1270
1238
  /**
1271
- * A badge: the short colored label that prefixes a line. `bg`/`fg` are hex so the
1272
- * same value drives both colorize's `bgHex().hex()` and the tui `&lt;Text>` props.
1273
- */
1239
+ * A badge: the short colored label that prefixes a line. `bg`/`fg` are hex so the
1240
+ * same value drives both colorize's `bgHex().hex()` and the tui `&lt;Text>` props.
1241
+ */
1274
1242
  interface BadgeSpec {
1275
1243
  bg: `#${string}`;
1276
1244
  fg: `#${string}`;
@@ -1286,24 +1254,24 @@ type BadgeName = LevelBadgeName | StepBadgeName;
1286
1254
  /** The ordered step-phase names, used to register custom pail log types. */
1287
1255
  declare const STEP_BADGE_NAMES: ReadonlyArray<StepBadgeName>;
1288
1256
  /**
1289
- * Every badge, keyed by name. Levels get their conventional colors (red/amber/
1290
- * green/blue/grey); step phases follow create-astro's green→purple→cyan rhythm.
1291
- */
1257
+ * Every badge, keyed by name. Levels get their conventional colors (red/amber/
1258
+ * green/blue/grey); step phases follow create-astro's green→purple→cyan rhythm.
1259
+ */
1292
1260
  declare const BADGES: Record<BadgeName, BadgeSpec>;
1293
1261
  /**
1294
- * Luna, the mascot: the folklore rabbit-in-the-moon — a bunny tucked inside the
1295
- * moon disc. Pure ASCII so it renders the same everywhere (including piped logs).
1296
- * The CLI signs off the `init` flow with it, the way create-astro closes with
1297
- * Houston.
1298
- */
1262
+ * Luna, the mascot: the folklore rabbit-in-the-moon — a bunny tucked inside the
1263
+ * moon disc. Pure ASCII so it renders the same everywhere (including piped logs).
1264
+ * The CLI signs off the `init` flow with it, the way create-astro closes with
1265
+ * Houston.
1266
+ */
1299
1267
  declare const LUNA_NAME = "Luna";
1300
1268
  declare const LUNA_SIGNOFF = "Safe travels, voyager.";
1301
1269
  declare const LUNA_BUNNY: string;
1302
1270
  /**
1303
- * {@link LUNA_BUNNY} with its leading newline stripped, ready to render inline
1304
- * (beside the name + sign-off). Both render paths — the tui mascot frame and the
1305
- * pail off-TTY fallback — use this so neither re-implements the strip.
1306
- */
1271
+ * {@link LUNA_BUNNY} with its leading newline stripped, ready to render inline
1272
+ * (beside the name + sign-off). Both render paths — the tui mascot frame and the
1273
+ * pail off-TTY fallback — use this so neither re-implements the strip.
1274
+ */
1307
1275
  declare const LUNA_ART: string;
1308
1276
  /** The colored part of a badge — the word with one space of padding each side. */
1309
1277
  declare const padBadge: (text: string) => string;
@@ -1318,16 +1286,16 @@ declare const paintBadge: (spec: BadgeSpec) => string;
1318
1286
  /** Dim continuation text (a step's chosen answer, shown under the question). */
1319
1287
  declare const paintAnswer: (text: string) => string;
1320
1288
  /**
1321
- * Single source of truth for "does this wrangler config enable Workers
1322
- * Cache?" and "what compatibility_date does that require?".
1323
- *
1324
- * Before this module, `reconcile-compatibility-date.ts` (auto-bump) and
1325
- * `wrangler-validator.ts` (validation) each carried their own
1326
- * `WORKERS_CACHE_MIN_DATE` literal and their own top-level/`exports[]`
1327
- * cache-enabled walk — two copies of the same fact that could silently drift
1328
- * apart (a date bumped in one file without the other would either validate a
1329
- * config the reconciler wouldn't produce, or vice versa).
1330
- */
1289
+ * Single source of truth for "does this wrangler config enable Workers
1290
+ * Cache?" and "what compatibility_date does that require?".
1291
+ *
1292
+ * Before this module, `reconcile-compatibility-date.ts` (auto-bump) and
1293
+ * `wrangler-validator.ts` (validation) each carried their own
1294
+ * `WORKERS_CACHE_MIN_DATE` literal and their own top-level/`exports[]`
1295
+ * cache-enabled walk — two copies of the same fact that could silently drift
1296
+ * apart (a date bumped in one file without the other would either validate a
1297
+ * config the reconciler wouldn't produce, or vice versa).
1298
+ */
1331
1299
  /** The `compatibility_date` Workers Cache (`cache.enabled: true`) requires. */
1332
1300
  declare const WORKERS_CACHE_MIN_DATE = "2026-05-01";
1333
1301
  /** The subset of a parsed `wrangler.jsonc` the cache-enabled check reads. */
@@ -1342,11 +1310,11 @@ interface WranglerCacheShape {
1342
1310
  } | null> | null;
1343
1311
  }
1344
1312
  /**
1345
- * Whether Workers Cache is enabled anywhere in a parsed wrangler config — the
1346
- * top-level `cache.enabled` toggle, or a per-export override in
1347
- * `exports[name].cache.enabled` (Workers can scope cache per named export).
1348
- * `undefined`/`null` (an unparsed or absent config) is treated as disabled.
1349
- */
1313
+ * Whether Workers Cache is enabled anywhere in a parsed wrangler config — the
1314
+ * top-level `cache.enabled` toggle, or a per-export override in
1315
+ * `exports[name].cache.enabled` (Workers can scope cache per named export).
1316
+ * `undefined`/`null` (an unparsed or absent config) is treated as disabled.
1317
+ */
1350
1318
  declare const isCacheEnabled: (parsed: WranglerCacheShape | null | undefined) => boolean;
1351
1319
  /** Candidate wrangler config filenames, in the order every consumer probes them. */
1352
1320
  declare const WRANGLER_FILES: readonly ["wrangler.jsonc", "wrangler.json"];
@@ -1359,28 +1327,28 @@ interface ReadWranglerResult<T> {
1359
1327
  text: string;
1360
1328
  }
1361
1329
  /**
1362
- * Read and JSONC-parse a wrangler config file. Returns the raw `text` (for
1363
- * structural edits) alongside `parsed`, which is `undefined` when the file is
1364
- * not valid JSONC or does not parse to an object. Allows trailing commas, as
1365
- * wrangler does.
1366
- */
1330
+ * Read and JSONC-parse a wrangler config file. Returns the raw `text` (for
1331
+ * structural edits) alongside `parsed`, which is `undefined` when the file is
1332
+ * not valid JSONC or does not parse to an object. Allows trailing commas, as
1333
+ * wrangler does.
1334
+ */
1367
1335
  declare const readWranglerJsonc: <T = unknown>(wranglerPath: string) => ReadWranglerResult<T>;
1368
1336
  /**
1369
- * Pure scan of a `vars` map for plaintext secrets — the FS-free core, exported for
1370
- * unit tests. A variable is flagged when, for a **string** value that is neither a
1371
- * placeholder nor a public/publishable key, EITHER the value matches a known
1372
- * secret shape (`secretKindOf`) OR the key name strongly implies a secret and the
1373
- * value is long enough to plausibly be one. `kind` is the matched shape, or
1374
- * `secret_named_var` for the key-name path.
1375
- */
1337
+ * Pure scan of a `vars` map for plaintext secrets — the FS-free core, exported for
1338
+ * unit tests. A variable is flagged when, for a **string** value that is neither a
1339
+ * placeholder nor a public/publishable key, EITHER the value matches a known
1340
+ * secret shape (`secretKindOf`) OR the key name strongly implies a secret and the
1341
+ * value is long enough to plausibly be one. `kind` is the matched shape, or
1342
+ * `secret_named_var` for the key-name path.
1343
+ */
1376
1344
  declare const scanWranglerVariablesForSecrets: (variables: Record<string, unknown> | undefined, file: string) => WranglerVariableIR[];
1377
1345
  /**
1378
- * Read the project's `wrangler.jsonc` and return its plaintext-secret `vars` as IR
1379
- * for the `plaintext_secret_in_wrangler_vars` lint. Returns `[]` when there is no
1380
- * wrangler config, it doesn't parse, or nothing looks like a secret. Scans the
1381
- * top-level `vars` block (mirroring the existing `validateCorsVariables` scope);
1382
- * per-environment `env.&lt;name>.vars` overrides are out of scope for now.
1383
- */
1346
+ * Read the project's `wrangler.jsonc` and return its plaintext-secret `vars` as IR
1347
+ * for the `plaintext_secret_in_wrangler_vars` lint. Returns `[]` when there is no
1348
+ * wrangler config, it doesn't parse, or nothing looks like a secret. Scans the
1349
+ * top-level `vars` block (mirroring the existing `validateCorsVariables` scope);
1350
+ * per-environment `env.&lt;name>.vars` overrides are out of scope for now.
1351
+ */
1384
1352
  declare const collectWranglerSecretVariables: (projectRoot: string) => WranglerVariableIR[];
1385
1353
  declare const REQUIRED_COMPATIBILITY_DATE: string;
1386
1354
  declare const REQUIRED_FLAG: string;
@@ -1389,10 +1357,10 @@ interface WranglerDurableObjectBinding {
1389
1357
  name?: string;
1390
1358
  }
1391
1359
  /**
1392
- * A `tail_consumers` entry: a Worker that receives this Worker's tail events
1393
- * (logs, exceptions, fetch metadata) for forwarding to an external sink. See
1394
- * `withTailConsumer` for the wiring helper.
1395
- */
1360
+ * A `tail_consumers` entry: a Worker that receives this Worker's tail events
1361
+ * (logs, exceptions, fetch metadata) for forwarding to an external sink. See
1362
+ * `withTailConsumer` for the wiring helper.
1363
+ */
1396
1364
  interface TailConsumer {
1397
1365
  /** Optional Cloudflare environment of the consumer Worker. */
1398
1366
  environment?: string;
@@ -1411,10 +1379,10 @@ interface WranglerContainerEntry {
1411
1379
  max_instances?: number;
1412
1380
  }
1413
1381
  /**
1414
- * A wrangler `workflows[]` entry (parsed from untrusted JSONC). Unlike
1415
- * containers, workflows are NOT Durable Objects — the entry stands alone (no
1416
- * `durable_objects` binding, no migration class).
1417
- */
1382
+ * A wrangler `workflows[]` entry (parsed from untrusted JSONC). Unlike
1383
+ * containers, workflows are NOT Durable Objects — the entry stands alone (no
1384
+ * `durable_objects` binding, no migration class).
1385
+ */
1418
1386
  interface WranglerWorkflowEntry {
1419
1387
  binding?: string;
1420
1388
  class_name?: string;
@@ -1550,23 +1518,23 @@ interface WranglerValidationReport {
1550
1518
  warnings: string[];
1551
1519
  }
1552
1520
  /**
1553
- * Return a new `WranglerConfig` with `consumer` present in `tail_consumers`,
1554
- * wiring this Worker to forward its tail events (logs/exceptions) to another
1555
- * Worker that fans them out to an external sink. Pure and idempotent: an
1556
- * existing entry with the same `service` + `environment` is left untouched
1557
- * rather than duplicated, so it is safe to call on every codegen/deploy.
1558
- */
1521
+ * Return a new `WranglerConfig` with `consumer` present in `tail_consumers`,
1522
+ * wiring this Worker to forward its tail events (logs/exceptions) to another
1523
+ * Worker that fans them out to an external sink. Pure and idempotent: an
1524
+ * existing entry with the same `service` + `environment` is left untouched
1525
+ * rather than duplicated, so it is safe to call on every codegen/deploy.
1526
+ */
1559
1527
  declare const withTailConsumer: (wrangler: WranglerConfig, consumer: TailConsumer) => WranglerConfig;
1560
1528
  /**
1561
- * Pure validator: given a parsed `WranglerConfig` object and an optional
1562
- * `SchemaInfo`, produce a structured report. Performs no I/O.
1563
- */
1529
+ * Pure validator: given a parsed `WranglerConfig` object and an optional
1530
+ * `SchemaInfo`, produce a structured report. Performs no I/O.
1531
+ */
1564
1532
  declare const validateWranglerConfig: (wrangler: WranglerConfig | undefined, schema?: SchemaInfo) => WranglerValidationReport;
1565
1533
  /**
1566
- * Convenience alias matching the original task-spec signature
1567
- * `validateWrangler(wranglerJson, schema)` returning
1568
- * `{ valid, errors, warnings }`.
1569
- */
1534
+ * Convenience alias matching the original task-spec signature
1535
+ * `validateWrangler(wranglerJson, schema)` returning
1536
+ * `{ valid, errors, warnings }`.
1537
+ */
1570
1538
  declare const validateWrangler: typeof validateWranglerConfig;
1571
1539
  interface WranglerProjectValidationOptions {
1572
1540
  projectRoot: string;
@@ -1578,10 +1546,10 @@ interface WranglerProjectValidationResult {
1578
1546
  wranglerPath: string | undefined;
1579
1547
  }
1580
1548
  /**
1581
- * File-system aware variant: reads `wrangler.jsonc`/`wrangler.json` from
1582
- * the given project root, discovers the schema (if any), and delegates to
1583
- * `validateWranglerConfig`. Returns the legacy
1584
- * `{ problems, wranglerPath }` shape plus the structured `report`.
1585
- */
1549
+ * File-system aware variant: reads `wrangler.jsonc`/`wrangler.json` from
1550
+ * the given project root, discovers the schema (if any), and delegates to
1551
+ * `validateWranglerConfig`. Returns the legacy
1552
+ * `{ problems, wranglerPath }` shape plus the structured `report`.
1553
+ */
1586
1554
  declare const validateWranglerProject: (options: WranglerProjectValidationOptions) => WranglerProjectValidationResult;
1587
1555
  export { ACCENT, AGENT_MODE_ENV, AGENT_RULES_DIR, AGENT_RULES_HINT, AGENT_RULES_HINT_ENV, type AddIndexEdit, type AddOptionalColumnEdit, type AddTableEdit, type AdditiveEdit, type AgentDetection, type AgentRulesStatus, type ApplyEditResult, type ApplyFailureReason, type AugmentPlan, BADGES, BADGE_COLUMN_WIDTH, type BadgeName, type BadgeSpec, type ClaimDevServerStateResult, type ContainerLogLevel, type ContainerLogLine, type ContainerLogSource, type ContainerLogStreamHandle, type ContainerLogStreamOptions, DEV_DAEMON_ENV, DEV_HANDOFF_ENV, DEV_LOG_FILE, DEV_LOG_FILE_ENV, DEV_STATE_DIR, DEV_STATE_FILE, DEV_VARS_EXAMPLE_FILE, DEV_VARS_FILE, DEV_VARS_KEY_PATTERN, type DestructiveEdit, type DetectedFramework, type DevSecretsFillPlan, type DevServerMode, type DevServerState, type DiscoverAgentInfoResult, type DiscoverContainerInfoResult, type DiscoverSchemaInfoResult, type DiscoverWorkflowInfoResult, type DockerLike, type EnsureDevVariablesDeps, type EnsureDevVariablesResult, type EnsureDevVariablesStatus, type ExportGap, type FillDevSecretsResult, type FrameworkClass, type FrameworkDetection, type InferOptions, type InferredAgent, type InferredBindings, type InferredContainer, type InferredWorkflow, LINKED_PROJECT_DIR, LINKED_PROJECT_FILE, LUNA_ART, LUNA_BUNNY, LUNA_NAME, LUNA_SIGNOFF, LUNORA_CONFIG_FILE, LUNORA_EVENT_SOURCE, LUNORA_SKILL_NAMES, type LevelBadgeName, type LinkedProject, type LunoraFormattedLine, type LunoraLineLevel, type LunoraProjectConfig, LunoraReporter, type MaterializeOptions, type MaterializeResult, type MultiSelectOption, PACKAGE_SECRETS_REGISTRY, type ParseSchemaResult, REMOTE_ELIGIBLE_KEYS, REQUIRED_COMPATIBILITY_DATE, REQUIRED_FLAG, ROOT_SKILL_NAME, type ReadWranglerResult, type ReconcileBindingsResult, type ReconcileCompatibilityDateResult, type ReconcileResult as ReconcileCronsResult, type RemoteBindingPlan, type RemoteEnableInputs, type RemotePreference, type RemoteWranglerShape, STEP_BADGE_NAMES, type ScaffoldPlan, type SchemaColumn, type SchemaEdit, type SchemaIndex, type SchemaInfo, type SchemaTable, type SecretEntry, type SelectOption, type StepBadgeName, type TailConsumer, WORKERS_CACHE_MIN_DATE, WRANGLER_FILES, type WranglerCacheShape, type WranglerConfig, type WranglerContainerEntry, type WranglerProjectValidationOptions, type WranglerProjectValidationResult, type WranglerValidationReport, type WranglerWorkflowEntry, applyAdditiveEdit, badgeLead, badgeWidth, buildPackageSecretsBlock, claimAgentRulesHint, claimDevServerState, classifyEdit, clearDevServerState, collectWranglerSecretVariables, createConfirm, detectAgentRules, detectAiAgent, detectFramework, discoverAgentInfo, discoverContainerInfo, discoverSchemaInfo, discoverWorkflowInfo, ensureDevVariables, ensureDevVariablesExample as ensureDevVarsExample, fillDevSecrets, findWranglerFile, formatLunoraEvent, generateSecretValue, inferLunoraBindings, injectRemoteFlags, interpretRemote, isCacheEnabled, isInteractive, isMintableSecretKey, isPlaceholderValue, isProcessAlive, isRecordedProcessCurrent, isRemoteEnvEnabled, materializeRemoteWranglerConfig, packageNamesFromBindings, padBadge, paintAnswer, paintBadge, parseDevVariableEntries, parseSchema, planDevSecretsFill, planDevVariablesAugment, planDevVariablesScaffold, planRemoteBindings, promptMultiSelect, promptSelect, promptText, promptYesNo, readDevServerState, readLinkedProject, readLiveDevServerState, readProjectDependencyNames, readProjectRemotePreference, readWranglerJsonc, reconcileWranglerBindings, reconcileWranglerCompatibilityDate, reconcileWranglerCrons, requiredSecrets, resolveRemoteEnabled, scanWranglerVariablesForSecrets, secretsForPackages, streamContainerLogs, updateDevServerState, validateWrangler, validateWranglerConfig, validateWranglerProject, withTailConsumer, writeDevServerState, writeLinkedProject };