@korajs/cli 1.0.0-beta.1 → 1.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/bin.cjs +593 -290
  2. package/dist/bin.cjs.map +1 -1
  3. package/dist/bin.js +122 -35
  4. package/dist/bin.js.map +1 -1
  5. package/dist/{chunk-EOWLAAIV.js → chunk-4IKCHRJ6.js} +273 -57
  6. package/dist/chunk-4IKCHRJ6.js.map +1 -0
  7. package/dist/{chunk-B5YS4STN.js → chunk-G2PBYMMA.js} +2 -2
  8. package/dist/{chunk-B5YS4STN.js.map → chunk-G2PBYMMA.js.map} +1 -1
  9. package/dist/{chunk-BWTKRKNJ.js → chunk-Z7GCXMGW.js} +9 -5
  10. package/dist/chunk-Z7GCXMGW.js.map +1 -0
  11. package/dist/create.cjs +8 -4
  12. package/dist/create.cjs.map +1 -1
  13. package/dist/create.js +2 -2
  14. package/dist/index.cjs +389 -166
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +58 -1
  17. package/dist/index.d.ts +58 -1
  18. package/dist/index.js +12 -2
  19. package/package.json +8 -8
  20. package/templates/react-basic/README.md.hbs +1 -1
  21. package/templates/react-basic/src/main.tsx +1 -1
  22. package/templates/react-basic/src/vite-env.d.ts +1 -0
  23. package/templates/react-basic/vite.config.ts +7 -4
  24. package/templates/react-sync/README.md.hbs +6 -5
  25. package/templates/react-sync/server.ts +46 -3
  26. package/templates/react-sync/src/main.tsx +1 -1
  27. package/templates/react-sync/src/vite-env.d.ts +1 -0
  28. package/templates/react-sync/vite.config.ts +14 -4
  29. package/templates/react-tailwind/README.md.hbs +1 -1
  30. package/templates/react-tailwind/src/main.tsx +1 -1
  31. package/templates/react-tailwind/src/vite-env.d.ts +1 -0
  32. package/templates/react-tailwind/vite.config.ts +7 -4
  33. package/templates/react-tailwind-sync/README.md.hbs +6 -5
  34. package/templates/react-tailwind-sync/server.ts +46 -3
  35. package/templates/react-tailwind-sync/src/main.tsx +1 -1
  36. package/templates/react-tailwind-sync/src/vite-env.d.ts +1 -0
  37. package/templates/react-tailwind-sync/vite.config.ts +14 -4
  38. package/templates/svelte-basic/README.md.hbs +1 -1
  39. package/templates/svelte-basic/src/main.ts +1 -1
  40. package/templates/svelte-basic/vite.config.ts +4 -2
  41. package/templates/svelte-sync/README.md.hbs +6 -5
  42. package/templates/svelte-sync/server.ts +46 -3
  43. package/templates/svelte-sync/src/main.ts +1 -1
  44. package/templates/svelte-sync/src/vite-env.d.ts +1 -0
  45. package/templates/svelte-sync/vite.config.ts +11 -2
  46. package/templates/svelte-tailwind/README.md.hbs +1 -1
  47. package/templates/svelte-tailwind/src/main.ts +1 -1
  48. package/templates/svelte-tailwind/vite.config.ts +4 -2
  49. package/templates/svelte-tailwind-sync/README.md.hbs +6 -5
  50. package/templates/svelte-tailwind-sync/server.ts +46 -3
  51. package/templates/svelte-tailwind-sync/src/main.ts +1 -1
  52. package/templates/svelte-tailwind-sync/src/vite-env.d.ts +1 -0
  53. package/templates/svelte-tailwind-sync/vite.config.ts +11 -2
  54. package/templates/tauri-react/server.ts +44 -1
  55. package/templates/tauri-react/src/AppShell.tsx +1 -1
  56. package/templates/tauri-react/src/vite-env.d.ts +1 -0
  57. package/templates/vue-basic/README.md.hbs +1 -1
  58. package/templates/vue-basic/src/main.ts +1 -1
  59. package/templates/vue-basic/vite.config.ts +4 -2
  60. package/templates/vue-sync/README.md.hbs +6 -5
  61. package/templates/vue-sync/server.ts +46 -3
  62. package/templates/vue-sync/src/main.ts +1 -1
  63. package/templates/vue-sync/src/vite-env.d.ts +1 -0
  64. package/templates/vue-sync/vite.config.ts +11 -2
  65. package/templates/vue-tailwind/README.md.hbs +1 -1
  66. package/templates/vue-tailwind/src/main.ts +1 -1
  67. package/templates/vue-tailwind/vite.config.ts +4 -2
  68. package/templates/vue-tailwind-sync/README.md.hbs +6 -5
  69. package/templates/vue-tailwind-sync/server.ts +46 -3
  70. package/templates/vue-tailwind-sync/src/main.ts +1 -1
  71. package/templates/vue-tailwind-sync/src/vite-env.d.ts +1 -0
  72. package/templates/vue-tailwind-sync/vite.config.ts +11 -2
  73. package/dist/chunk-BWTKRKNJ.js.map +0 -1
  74. package/dist/chunk-EOWLAAIV.js.map +0 -1
package/dist/bin.cjs CHANGED
@@ -32,25 +32,25 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
32
  // src/utils/fs-helpers.ts
33
33
  async function directoryExists(path) {
34
34
  try {
35
- await (0, import_promises2.access)(path);
35
+ await (0, import_promises.access)(path);
36
36
  return true;
37
37
  } catch {
38
38
  return false;
39
39
  }
40
40
  }
41
41
  async function findProjectRoot(startDir) {
42
- let current = (0, import_node_path2.resolve)(startDir ?? process.cwd());
42
+ let current = (0, import_node_path.resolve)(startDir ?? process.cwd());
43
43
  for (; ; ) {
44
- const pkgPath = (0, import_node_path2.join)(current, "package.json");
44
+ const pkgPath = (0, import_node_path.join)(current, "package.json");
45
45
  try {
46
- const content = await (0, import_promises2.readFile)(pkgPath, "utf-8");
46
+ const content = await (0, import_promises.readFile)(pkgPath, "utf-8");
47
47
  const pkg = JSON.parse(content);
48
48
  if (isKoraProject(pkg)) {
49
49
  return current;
50
50
  }
51
51
  } catch {
52
52
  }
53
- const parent = (0, import_node_path2.dirname)(current);
53
+ const parent = (0, import_node_path.dirname)(current);
54
54
  if (parent === current) break;
55
55
  current = parent;
56
56
  }
@@ -58,14 +58,14 @@ async function findProjectRoot(startDir) {
58
58
  }
59
59
  async function findSchemaFile(projectRoot) {
60
60
  const candidates = [
61
- (0, import_node_path2.join)(projectRoot, "src", "schema.ts"),
62
- (0, import_node_path2.join)(projectRoot, "schema.ts"),
63
- (0, import_node_path2.join)(projectRoot, "src", "schema.js"),
64
- (0, import_node_path2.join)(projectRoot, "schema.js")
61
+ (0, import_node_path.join)(projectRoot, "src", "schema.ts"),
62
+ (0, import_node_path.join)(projectRoot, "schema.ts"),
63
+ (0, import_node_path.join)(projectRoot, "src", "schema.js"),
64
+ (0, import_node_path.join)(projectRoot, "schema.js")
65
65
  ];
66
66
  for (const candidate of candidates) {
67
67
  try {
68
- await (0, import_promises2.access)(candidate);
68
+ await (0, import_promises.access)(candidate);
69
69
  return candidate;
70
70
  } catch {
71
71
  }
@@ -74,16 +74,16 @@ async function findSchemaFile(projectRoot) {
74
74
  }
75
75
  async function hasTsxInstalled(projectRoot) {
76
76
  try {
77
- await (0, import_promises2.access)((0, import_node_path2.join)(projectRoot, "node_modules", "tsx", "package.json"));
77
+ await (0, import_promises.access)((0, import_node_path.join)(projectRoot, "node_modules", "tsx", "package.json"));
78
78
  return true;
79
79
  } catch {
80
80
  return false;
81
81
  }
82
82
  }
83
83
  async function resolveProjectBinaryEntryPoint(projectRoot, packageName, binaryName) {
84
- const pkgJsonPath = (0, import_node_path2.join)(projectRoot, "node_modules", packageName, "package.json");
84
+ const pkgJsonPath = (0, import_node_path.join)(projectRoot, "node_modules", packageName, "package.json");
85
85
  try {
86
- const content = await (0, import_promises2.readFile)(pkgJsonPath, "utf-8");
86
+ const content = await (0, import_promises.readFile)(pkgJsonPath, "utf-8");
87
87
  const pkg = JSON.parse(content);
88
88
  let binPath;
89
89
  if (typeof pkg.bin === "string") {
@@ -92,8 +92,8 @@ async function resolveProjectBinaryEntryPoint(projectRoot, packageName, binaryNa
92
92
  binPath = pkg.bin[binaryName];
93
93
  }
94
94
  if (!binPath) return null;
95
- const fullPath = (0, import_node_path2.join)(projectRoot, "node_modules", packageName, binPath);
96
- await (0, import_promises2.access)(fullPath);
95
+ const fullPath = (0, import_node_path.join)(projectRoot, "node_modules", packageName, binPath);
96
+ await (0, import_promises.access)(fullPath);
97
97
  return fullPath;
98
98
  } catch {
99
99
  return null;
@@ -108,12 +108,12 @@ function hasKoraDep(deps) {
108
108
  if (typeof deps !== "object" || deps === null) return false;
109
109
  return Object.keys(deps).some((key) => key === "kora" || key.startsWith("@korajs/"));
110
110
  }
111
- var import_promises2, import_node_path2;
111
+ var import_promises, import_node_path;
112
112
  var init_fs_helpers = __esm({
113
113
  "src/utils/fs-helpers.ts"() {
114
114
  "use strict";
115
- import_promises2 = require("fs/promises");
116
- import_node_path2 = require("path");
115
+ import_promises = require("fs/promises");
116
+ import_node_path = require("path");
117
117
  }
118
118
  });
119
119
 
@@ -123,7 +123,7 @@ __export(schema_loader_exports, {
123
123
  loadSchemaDefinition: () => loadSchemaDefinition
124
124
  });
125
125
  async function loadSchemaDefinition(schemaPath, projectRoot) {
126
- const ext = (0, import_node_path4.extname)(schemaPath);
126
+ const ext = (0, import_node_path5.extname)(schemaPath);
127
127
  const moduleValue = ext === ".ts" || ext === ".mts" || ext === ".cts" ? await loadTypeScriptModule(schemaPath, projectRoot) : await import(`${(0, import_node_url2.pathToFileURL)(schemaPath).href}?t=${Date.now()}-${Math.random()}`);
128
128
  return extractSchema(moduleValue);
129
129
  }
@@ -190,12 +190,12 @@ async function runCommand2(command, args, cwd) {
190
190
  });
191
191
  });
192
192
  }
193
- var import_node_child_process2, import_node_path4, import_node_url2;
193
+ var import_node_child_process2, import_node_path5, import_node_url2;
194
194
  var init_schema_loader = __esm({
195
195
  "src/commands/migrate/schema-loader.ts"() {
196
196
  "use strict";
197
197
  import_node_child_process2 = require("child_process");
198
- import_node_path4 = require("path");
198
+ import_node_path5 = require("path");
199
199
  import_node_url2 = require("url");
200
200
  init_fs_helpers();
201
201
  }
@@ -1981,13 +1981,13 @@ var spectator_manager_exports = {};
1981
1981
  __export(spectator_manager_exports, {
1982
1982
  SpectatorManager: () => SpectatorManager
1983
1983
  });
1984
- var import_node_fs6, import_node_os, import_node_path27, FORWARDED_EVENTS, MAX_EVENT_BUFFER, SpectatorManager;
1984
+ var import_node_fs7, import_node_os, import_node_path28, FORWARDED_EVENTS, MAX_EVENT_BUFFER, SpectatorManager;
1985
1985
  var init_spectator_manager = __esm({
1986
1986
  "src/commands/studio/spectator-manager.ts"() {
1987
1987
  "use strict";
1988
- import_node_fs6 = require("fs");
1988
+ import_node_fs7 = require("fs");
1989
1989
  import_node_os = require("os");
1990
- import_node_path27 = require("path");
1990
+ import_node_path28 = require("path");
1991
1991
  FORWARDED_EVENTS = [
1992
1992
  "merge:started",
1993
1993
  "merge:conflict",
@@ -2001,8 +2001,8 @@ var init_spectator_manager = __esm({
2001
2001
  SpectatorManager = class {
2002
2002
  constructor(options) {
2003
2003
  this.options = options;
2004
- this.tmpDir = (0, import_node_fs6.mkdtempSync)((0, import_node_path27.join)((0, import_node_os.tmpdir)(), "kora-studio-spectator-"));
2005
- this.dbPath = (0, import_node_path27.join)(this.tmpDir, "spectator-replica.db");
2004
+ this.tmpDir = (0, import_node_fs7.mkdtempSync)((0, import_node_path28.join)((0, import_node_os.tmpdir)(), "kora-studio-spectator-"));
2005
+ this.dbPath = (0, import_node_path28.join)(this.tmpDir, "spectator-replica.db");
2006
2006
  }
2007
2007
  options;
2008
2008
  runtime = null;
@@ -2099,7 +2099,7 @@ var init_spectator_manager = __esm({
2099
2099
  this.runtime = null;
2100
2100
  }
2101
2101
  if (this.tmpDir) {
2102
- (0, import_node_fs6.rmSync)(this.tmpDir, { recursive: true, force: true });
2102
+ (0, import_node_fs7.rmSync)(this.tmpDir, { recursive: true, force: true });
2103
2103
  this.tmpDir = null;
2104
2104
  }
2105
2105
  }
@@ -2182,13 +2182,13 @@ function summarizeEvent(type, payload) {
2182
2182
  return type.replace("lab:", "");
2183
2183
  }
2184
2184
  }
2185
- var import_node_fs7, import_node_os2, import_node_path28, import_core3, DEFAULT_CHAOS, FORWARDED_EVENTS2, MAX_EVENT_BUFFER2, LabManager;
2185
+ var import_node_fs8, import_node_os2, import_node_path29, import_core3, DEFAULT_CHAOS, FORWARDED_EVENTS2, MAX_EVENT_BUFFER2, LabManager;
2186
2186
  var init_lab_manager = __esm({
2187
2187
  "src/commands/studio/lab-manager.ts"() {
2188
2188
  "use strict";
2189
- import_node_fs7 = require("fs");
2189
+ import_node_fs8 = require("fs");
2190
2190
  import_node_os2 = require("os");
2191
- import_node_path28 = require("path");
2191
+ import_node_path29 = require("path");
2192
2192
  import_core3 = require("@korajs/core");
2193
2193
  DEFAULT_CHAOS = {
2194
2194
  dropRate: 0,
@@ -2246,7 +2246,7 @@ var init_lab_manager = __esm({
2246
2246
  }
2247
2247
  async start(initialDevices = 2) {
2248
2248
  const harness = await this.loadHarness();
2249
- this.tmpDir = (0, import_node_fs7.mkdtempSync)((0, import_node_path28.join)((0, import_node_os2.tmpdir)(), "kora-studio-lab-"));
2249
+ this.tmpDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path29.join)((0, import_node_os2.tmpdir)(), "kora-studio-lab-"));
2250
2250
  this.server = new harness.TestServer(this.schema);
2251
2251
  for (let i = 0; i < initialDevices; i++) {
2252
2252
  await this.addDevice();
@@ -2298,7 +2298,7 @@ var init_lab_manager = __esm({
2298
2298
  nodeId: entry.device.getNodeId(),
2299
2299
  connected: entry.device.isConnected(),
2300
2300
  chaos: { ...entry.chaos },
2301
- dbPath: (0, import_node_path28.join)(this.tmpDir ?? "", `test-device-${name}.db`),
2301
+ dbPath: (0, import_node_path29.join)(this.tmpDir ?? "", `test-device-${name}.db`),
2302
2302
  pendingOperations: entry.device.getSyncEngine()?.getStatus().pendingOperations ?? 0
2303
2303
  };
2304
2304
  }
@@ -2377,7 +2377,7 @@ var init_lab_manager = __esm({
2377
2377
  });
2378
2378
  this.server = null;
2379
2379
  if (this.tmpDir) {
2380
- (0, import_node_fs7.rmSync)(this.tmpDir, { recursive: true, force: true });
2380
+ (0, import_node_fs8.rmSync)(this.tmpDir, { recursive: true, force: true });
2381
2381
  this.tmpDir = null;
2382
2382
  }
2383
2383
  }
@@ -2409,12 +2409,13 @@ var init_lab_manager = __esm({
2409
2409
  });
2410
2410
 
2411
2411
  // src/bin.ts
2412
- var import_citty12 = require("citty");
2412
+ var import_citty13 = require("citty");
2413
2413
 
2414
- // src/commands/backup/backup-command.ts
2415
- var import_promises = require("fs/promises");
2416
- var import_node_path = require("path");
2414
+ // src/commands/agents/agents-command.ts
2415
+ var import_promises2 = require("fs/promises");
2416
+ var import_node_path2 = require("path");
2417
2417
  var import_citty = require("citty");
2418
+ init_fs_helpers();
2418
2419
 
2419
2420
  // src/utils/logger.ts
2420
2421
  var RESET = "\x1B[0m";
@@ -2451,22 +2452,233 @@ function createLogger(options) {
2451
2452
  banner() {
2452
2453
  console.log();
2453
2454
  console.log(
2454
- color(BOLD + CYAN, " Kora.js") + color(DIM, " \u2014 Offline-first application framework")
2455
+ color(BOLD + CYAN, " Kora.js") + color(DIM, ", the offline-first application framework")
2455
2456
  );
2456
2457
  console.log();
2457
2458
  }
2458
2459
  };
2459
2460
  }
2460
2461
 
2462
+ // src/commands/agents/agents-md-content.ts
2463
+ var AGENTS_FRAMEWORKS = ["react", "vue", "svelte"];
2464
+ function isAgentsFramework(value) {
2465
+ return AGENTS_FRAMEWORKS.includes(value);
2466
+ }
2467
+ function detectFrameworkFromManifest(manifest) {
2468
+ if (typeof manifest !== "object" || manifest === null) return null;
2469
+ const record = manifest;
2470
+ const deps = collectDependencyNames(record.dependencies, record.devDependencies);
2471
+ if (deps.has("@korajs/react")) return "react";
2472
+ if (deps.has("@korajs/vue")) return "vue";
2473
+ if (deps.has("@korajs/svelte")) return "svelte";
2474
+ return null;
2475
+ }
2476
+ function collectDependencyNames(...groups) {
2477
+ const names = /* @__PURE__ */ new Set();
2478
+ for (const group of groups) {
2479
+ if (typeof group !== "object" || group === null) continue;
2480
+ for (const name of Object.keys(group)) {
2481
+ names.add(name);
2482
+ }
2483
+ }
2484
+ return names;
2485
+ }
2486
+ var FRAMEWORK_BINDINGS = {
2487
+ react: `## React bindings
2488
+
2489
+ \`\`\`tsx
2490
+ import { KoraProvider, useCollection, useMutation, useQuery, useSyncStatus } from '@korajs/react'
2491
+
2492
+ // Wrap the tree once near your app entry: <KoraProvider app={app}><App /></KoraProvider>
2493
+
2494
+ const todos = useCollection('todos')
2495
+ const rows = useQuery(todos.where({ completed: false }).orderBy('createdAt'))
2496
+ const addTodo = useMutation((data) => todos.insert(data))
2497
+ addTodo.mutate({ title: 'x' }) // fire-and-forget; errors land in addTodo.error
2498
+ await addTodo.mutateAsync({ title: 'x' }) // resolves with the result; throws on failure
2499
+ const status = useSyncStatus() // status.status, status.pendingOperations
2500
+ \`\`\`
2501
+
2502
+ Rules: always render \`mutation.error\` somewhere. Keep \`<StrictMode>\` in place; the hooks are StrictMode-safe. \`useQuery\` returns data synchronously from the local store, so do not add loading spinners for local reads.`,
2503
+ vue: `## Vue bindings
2504
+
2505
+ \`\`\`ts
2506
+ import { useCollection, useMutation, useQuery, useSyncStatus } from '@korajs/vue'
2507
+
2508
+ const todos = useCollection('todos')
2509
+ const rows = useQuery(todos.where({ completed: false }).orderBy('createdAt')) // readonly reactive ref
2510
+ const addTodo = useMutation((data) => todos.insert(data))
2511
+ addTodo.mutate({ title: 'x' }) // fire-and-forget; errors land in addTodo.error
2512
+ const status = useSyncStatus() // status.status, status.pendingOperations
2513
+ \`\`\`
2514
+
2515
+ Rules: surface the mutation's error state in the UI. \`useQuery\` reads synchronously from the local store, so avoid loading spinners for local data. The Kora context comes from \`KoraProvider\`, wired in your app entry (for example \`src/main.ts\`).`,
2516
+ svelte: `## Svelte bindings
2517
+
2518
+ Kora's Svelte bindings from \`@korajs/svelte\` expose \`useCollection\`, \`useQuery\`, \`useMutation\`, and \`useSyncStatus\`, wired through the provider set up in your app entry.
2519
+
2520
+ \`\`\`ts
2521
+ import { useCollection, useMutation, useQuery, useSyncStatus } from '@korajs/svelte'
2522
+
2523
+ const todos = useCollection('todos')
2524
+ const rows = useQuery(todos.where({ completed: false }).orderBy('createdAt')) // reactive store
2525
+ const addTodo = useMutation((data) => todos.insert(data))
2526
+ addTodo.mutate({ title: 'x' }) // fire-and-forget; errors land in addTodo.error
2527
+ const status = useSyncStatus() // readable store; read $status.status in markup
2528
+ \`\`\`
2529
+
2530
+ Rules: queries are reactive stores that read synchronously from the local database, so avoid loading spinners for local reads. Mutations expose an \`error\` state that must be surfaced in the UI.`
2531
+ };
2532
+ function generateAgentsMd(framework) {
2533
+ return `# AGENTS.md
2534
+
2535
+ Guidance for AI coding agents working in this project. Humans: this is useful for you too.
2536
+
2537
+ ## What this project is
2538
+
2539
+ This project uses **Kora.js**, an offline-first application framework. All application data lives in a local SQLite database (WASM + OPFS in the browser, native SQLite on desktop and server) and optionally syncs across devices through a Kora sync server. Offline is the normal state, not an error state. Full docs live at https://korajs.dev, with a machine-readable index at https://korajs.dev/llms.txt and the complete docs in one file at https://korajs.dev/llms-full.txt. Any documentation page is available as raw markdown by appending \`.md\` to its URL.
2540
+
2541
+ ## Golden rules
2542
+
2543
+ 1. **The schema is the source of truth.** Collections are defined with \`defineSchema\` and the \`t.*\` field builders (by convention in \`src/schema.ts\`). To add or change data shapes, edit the schema first; types flow from it automatically. Never hand-write types for records.
2544
+ 2. **Never fetch application data over HTTP.** Do not add REST or GraphQL calls for app data, and do not talk to the sync server directly. Read and write through Kora collections only; sync happens automatically in the background.
2545
+ 3. **Await readiness before direct collection access.** Outside the UI bindings, \`await app.ready\` before calling \`app.<collection>\` methods. The framework bindings handle this for you inside components.
2546
+ 4. **Offline must keep working.** Any feature you add must function with the network off. Never gate a read or write on connectivity. If you are checking \`navigator.onLine\` before a data operation, you are doing it wrong.
2547
+ 5. **Surface mutation errors.** Fire-and-forget \`mutate\` calls fold errors into the mutation state. Always render the mutation's \`error\`, or handle the promise from the \`mutateAsync\` variant. Silent failure is the worst failure.
2548
+ 6. **Do not add a state library for server or app data.** Kora's reactive queries are the store. Do not reach for react-query, SWR, Redux, Zustand, or similar for data that lives in a collection. Local UI state (form inputs, toggles) can use your framework's normal state tools.
2549
+ 7. **Do not add loading spinners for local reads.** \`useQuery\` returns data synchronously from the local store, so there is no loading state to wait on for local data.
2550
+
2551
+ ## Data API cheat sheet
2552
+
2553
+ \`\`\`ts
2554
+ await app.ready
2555
+ const rec = await app.todos.insert({ title: 'x' }) // defaults and .auto() fields applied
2556
+ await app.todos.update(rec.id, { completed: true }) // partial update, changed fields only
2557
+ await app.todos.delete(rec.id)
2558
+ const one = await app.todos.findById(rec.id)
2559
+ const unsubscribe = app.todos
2560
+ .where({ completed: false })
2561
+ .orderBy('createdAt', 'desc')
2562
+ .subscribe((rows) => {/* fires immediately, then on every change */})
2563
+ \`\`\`
2564
+
2565
+ Schema example (\`src/schema.ts\`):
2566
+
2567
+ \`\`\`ts
2568
+ import { defineSchema, t } from 'korajs'
2569
+
2570
+ export default defineSchema({
2571
+ version: 1,
2572
+ collections: {
2573
+ todos: {
2574
+ fields: {
2575
+ title: t.string(),
2576
+ completed: t.boolean().default(false),
2577
+ tags: t.array(t.string()).default([]),
2578
+ priority: t.enum(['low', 'medium', 'high']).default('medium'),
2579
+ createdAt: t.timestamp().auto(), // set automatically; never pass it on insert
2580
+ },
2581
+ indexes: ['completed', 'createdAt'],
2582
+ },
2583
+ },
2584
+ })
2585
+ \`\`\`
2586
+
2587
+ If you change collection shapes, increment \`version\` and run \`npx kora migrate\`.
2588
+
2589
+ ## Conflict handling
2590
+
2591
+ Concurrent edits merge automatically: last-write-wins per field, add-wins for arrays, and character-level CRDT for \`t.richtext()\` fields. When a field needs domain-specific merging (counters, quantities), add a \`resolve\` function in the schema rather than writing sync logic by hand. Never write your own conflict or merge code.
2592
+
2593
+ ## Sync and auth
2594
+
2595
+ Enable sync by adding one line to \`createApp\`: \`createApp({ schema, sync: { url } })\`. When the app is offline, writes queue locally and sync when connectivity returns. If the project uses \`@korajs/auth\`, pass its client as \`createApp({ schema, sync: { url, authClient } })\`. Local writes work without sign-in; sync requires the server to accept the connection.
2596
+
2597
+ ${FRAMEWORK_BINDINGS[framework]}
2598
+
2599
+ ## Commands
2600
+
2601
+ - \`npx kora dev\` runs the dev environment (app server, local sync server when configured, schema watcher).
2602
+ - \`npx kora doctor\` diagnoses a broken setup.
2603
+ - \`npx kora migrate\` applies a schema change to the local store.
2604
+ - In a running app, the DevTools overlay (Ctrl+Shift+K, Cmd+Shift+K on macOS) inspects operations, merges, and sync status.
2605
+ `;
2606
+ }
2607
+
2608
+ // src/commands/agents/agents-command.ts
2609
+ async function fileExists(path) {
2610
+ try {
2611
+ await (0, import_promises2.access)(path);
2612
+ return true;
2613
+ } catch {
2614
+ return false;
2615
+ }
2616
+ }
2617
+ async function readManifest(root) {
2618
+ try {
2619
+ return JSON.parse(await (0, import_promises2.readFile)((0, import_node_path2.join)(root, "package.json"), "utf-8"));
2620
+ } catch {
2621
+ return null;
2622
+ }
2623
+ }
2624
+ function resolveFramework(override, manifest) {
2625
+ if (override !== void 0 && isAgentsFramework(override)) return override;
2626
+ return detectFrameworkFromManifest(manifest) ?? "react";
2627
+ }
2628
+ var agentsCommand = (0, import_citty.defineCommand)({
2629
+ meta: {
2630
+ name: "agents-md",
2631
+ description: "Write an AGENTS.md with Kora rules for AI coding agents into this project"
2632
+ },
2633
+ args: {
2634
+ force: {
2635
+ type: "boolean",
2636
+ description: "Overwrite an existing AGENTS.md",
2637
+ default: false
2638
+ },
2639
+ framework: {
2640
+ type: "string",
2641
+ description: "Override framework detection (react, vue, or svelte)"
2642
+ }
2643
+ },
2644
+ async run({ args }) {
2645
+ const logger = createLogger();
2646
+ const projectRoot = await findProjectRoot() ?? process.cwd();
2647
+ const manifest = await readManifest(projectRoot);
2648
+ const override = typeof args.framework === "string" ? args.framework : void 0;
2649
+ if (override !== void 0 && !isAgentsFramework(override)) {
2650
+ logger.error(`Unknown framework "${override}". Use one of: react, vue, svelte.`);
2651
+ process.exitCode = 1;
2652
+ return;
2653
+ }
2654
+ const framework = resolveFramework(override, manifest);
2655
+ const target = (0, import_node_path2.join)(projectRoot, "AGENTS.md");
2656
+ const force = args.force === true;
2657
+ if (await fileExists(target) && !force) {
2658
+ logger.warn("AGENTS.md already exists. Re-run with --force to overwrite it.");
2659
+ process.exitCode = 1;
2660
+ return;
2661
+ }
2662
+ await (0, import_promises2.writeFile)(target, generateAgentsMd(framework), "utf-8");
2663
+ logger.banner();
2664
+ logger.success(`Wrote AGENTS.md (${framework} bindings) to ${target}`);
2665
+ logger.step("Commit it so coding agents pick up Kora conventions automatically.");
2666
+ logger.blank();
2667
+ }
2668
+ });
2669
+
2461
2670
  // src/commands/backup/backup-command.ts
2671
+ var import_promises3 = require("fs/promises");
2672
+ var import_node_path3 = require("path");
2673
+ var import_citty2 = require("citty");
2462
2674
  var DEFAULT_SYNC_PORT = 3001;
2463
- var backupCommand = (0, import_citty.defineCommand)({
2675
+ var backupCommand = (0, import_citty2.defineCommand)({
2464
2676
  meta: {
2465
2677
  name: "backup",
2466
2678
  description: "Backup and restore Kora sync server data"
2467
2679
  },
2468
2680
  subCommands: {
2469
- create: (0, import_citty.defineCommand)({
2681
+ create: (0, import_citty2.defineCommand)({
2470
2682
  meta: {
2471
2683
  name: "create",
2472
2684
  description: "Create a backup of the sync server"
@@ -2506,7 +2718,7 @@ var backupCommand = (0, import_citty.defineCommand)({
2506
2718
  );
2507
2719
  }
2508
2720
  const buffer = await response.arrayBuffer();
2509
- await (0, import_promises.writeFile)(outFile, new Uint8Array(buffer));
2721
+ await (0, import_promises3.writeFile)(outFile, new Uint8Array(buffer));
2510
2722
  const size = (buffer.byteLength / 1024).toFixed(1);
2511
2723
  logger.success(`Backup saved to ${outFile} (${size} KB)`);
2512
2724
  } catch (error) {
@@ -2518,7 +2730,7 @@ var backupCommand = (0, import_citty.defineCommand)({
2518
2730
  }
2519
2731
  }
2520
2732
  }),
2521
- restore: (0, import_citty.defineCommand)({
2733
+ restore: (0, import_citty2.defineCommand)({
2522
2734
  meta: {
2523
2735
  name: "restore",
2524
2736
  description: "Restore a backup to the sync server"
@@ -2553,7 +2765,7 @@ var backupCommand = (0, import_citty.defineCommand)({
2553
2765
  logger.banner();
2554
2766
  logger.info(`Restoring backup from ${filePath} to ${url}...`);
2555
2767
  try {
2556
- const data = await (0, import_promises.readFile)(filePath);
2768
+ const data = await (0, import_promises3.readFile)(filePath);
2557
2769
  const restoreUrl = `${url.replace(/\/$/, "")}/__kora/backup/import?merge=${merge}`;
2558
2770
  const response = await fetch(restoreUrl, {
2559
2771
  method: "POST",
@@ -2581,7 +2793,7 @@ var backupCommand = (0, import_citty.defineCommand)({
2581
2793
  }
2582
2794
  }
2583
2795
  }),
2584
- info: (0, import_citty.defineCommand)({
2796
+ info: (0, import_citty2.defineCommand)({
2585
2797
  meta: {
2586
2798
  name: "info",
2587
2799
  description: "Show backup file information"
@@ -2597,7 +2809,7 @@ var backupCommand = (0, import_citty.defineCommand)({
2597
2809
  const logger = createLogger();
2598
2810
  const filePath = typeof args.file === "string" ? args.file : "";
2599
2811
  try {
2600
- const data = await (0, import_promises.readFile)(filePath);
2812
+ const data = await (0, import_promises3.readFile)(filePath);
2601
2813
  const { readBackupManifest } = await import("@korajs/store");
2602
2814
  const manifest = readBackupManifest(
2603
2815
  new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
@@ -2624,8 +2836,8 @@ var backupCommand = (0, import_citty.defineCommand)({
2624
2836
  });
2625
2837
 
2626
2838
  // src/commands/compact/compact-command.ts
2627
- var import_node_path5 = require("path");
2628
- var import_citty2 = require("citty");
2839
+ var import_node_path6 = require("path");
2840
+ var import_citty3 = require("citty");
2629
2841
 
2630
2842
  // src/errors.ts
2631
2843
  var import_core = require("@korajs/core");
@@ -2685,8 +2897,8 @@ init_fs_helpers();
2685
2897
 
2686
2898
  // src/commands/dev/kora-config.ts
2687
2899
  var import_node_child_process = require("child_process");
2688
- var import_promises3 = require("fs/promises");
2689
- var import_node_path3 = require("path");
2900
+ var import_promises4 = require("fs/promises");
2901
+ var import_node_path4 = require("path");
2690
2902
  var import_node_url = require("url");
2691
2903
  init_fs_helpers();
2692
2904
  var CONFIG_CANDIDATES = [
@@ -2700,7 +2912,7 @@ var CONFIG_CANDIDATES = [
2700
2912
  async function loadKoraConfig(projectRoot) {
2701
2913
  const configPath = await findKoraConfigFile(projectRoot);
2702
2914
  if (!configPath) return null;
2703
- const ext = (0, import_node_path3.extname)(configPath);
2915
+ const ext = (0, import_node_path4.extname)(configPath);
2704
2916
  if (ext === ".ts" || ext === ".mts" || ext === ".cts") {
2705
2917
  const loaded2 = await loadTypeScriptConfig(configPath, projectRoot);
2706
2918
  return toConfigObject(loaded2);
@@ -2710,9 +2922,9 @@ async function loadKoraConfig(projectRoot) {
2710
2922
  }
2711
2923
  async function findKoraConfigFile(projectRoot) {
2712
2924
  for (const file of CONFIG_CANDIDATES) {
2713
- const candidate = (0, import_node_path3.join)(projectRoot, file);
2925
+ const candidate = (0, import_node_path4.join)(projectRoot, file);
2714
2926
  try {
2715
- await (0, import_promises3.access)(candidate);
2927
+ await (0, import_promises4.access)(candidate);
2716
2928
  return candidate;
2717
2929
  } catch {
2718
2930
  }
@@ -2777,7 +2989,7 @@ function toConfigObject(mod) {
2777
2989
 
2778
2990
  // src/commands/compact/compact-command.ts
2779
2991
  init_schema_loader();
2780
- var compactCommand = (0, import_citty2.defineCommand)({
2992
+ var compactCommand = (0, import_citty3.defineCommand)({
2781
2993
  meta: {
2782
2994
  name: "compact",
2783
2995
  description: "Compact the local Kora operation log after server ack"
@@ -2808,12 +3020,12 @@ var compactCommand = (0, import_citty2.defineCommand)({
2808
3020
  if (!projectRoot) {
2809
3021
  throw new InvalidProjectError(process.cwd());
2810
3022
  }
2811
- const dbPath = typeof args.db === "string" ? (0, import_node_path5.resolve)(projectRoot, args.db) : void 0;
3023
+ const dbPath = typeof args.db === "string" ? (0, import_node_path6.resolve)(projectRoot, args.db) : void 0;
2812
3024
  if (!dbPath) {
2813
3025
  throw new Error("Missing --db <path> to the local SQLite database file.");
2814
3026
  }
2815
3027
  const config = await loadKoraConfig(projectRoot);
2816
- const schemaPath = typeof args.schema === "string" ? (0, import_node_path5.resolve)(projectRoot, args.schema) : typeof config?.schema === "string" ? (0, import_node_path5.resolve)(projectRoot, config.schema) : void 0;
3028
+ const schemaPath = typeof args.schema === "string" ? (0, import_node_path6.resolve)(projectRoot, args.schema) : typeof config?.schema === "string" ? (0, import_node_path6.resolve)(projectRoot, config.schema) : void 0;
2817
3029
  if (!schemaPath) {
2818
3030
  throw new Error("Could not resolve schema path. Pass --schema <path>.");
2819
3031
  }
@@ -2850,9 +3062,9 @@ var compactCommand = (0, import_citty2.defineCommand)({
2850
3062
  // src/commands/create/create-command.ts
2851
3063
  var import_node_child_process4 = require("child_process");
2852
3064
  var import_node_fs2 = require("fs");
2853
- var import_node_path9 = require("path");
3065
+ var import_node_path10 = require("path");
2854
3066
  var import_node_url4 = require("url");
2855
- var import_citty3 = require("citty");
3067
+ var import_citty4 = require("citty");
2856
3068
 
2857
3069
  // src/prompts/preferences.ts
2858
3070
  var import_conf = __toESM(require("conf"), 1);
@@ -3099,8 +3311,8 @@ function getRunDevCommand(pm) {
3099
3311
  }
3100
3312
 
3101
3313
  // src/commands/create/environment-detection.ts
3102
- var import_promises4 = require("fs/promises");
3103
- var import_node_path6 = require("path");
3314
+ var import_promises5 = require("fs/promises");
3315
+ var import_node_path7 = require("path");
3104
3316
  function detectEditorFromEnvironment(env = process.env) {
3105
3317
  const termProgram = String(env.TERM_PROGRAM ?? "").toLowerCase();
3106
3318
  const editorValue = `${String(env.EDITOR ?? "")} ${String(env.VISUAL ?? "")}`.toLowerCase();
@@ -3126,18 +3338,18 @@ async function detectGitContext(startDir) {
3126
3338
  };
3127
3339
  }
3128
3340
  async function detectMonorepoContext(startDir) {
3129
- let current = (0, import_node_path6.resolve)(startDir);
3341
+ let current = (0, import_node_path7.resolve)(startDir);
3130
3342
  for (; ; ) {
3131
- if (await fileExists((0, import_node_path6.join)(current, "pnpm-workspace.yaml"))) {
3343
+ if (await fileExists2((0, import_node_path7.join)(current, "pnpm-workspace.yaml"))) {
3132
3344
  return { isMonorepo: true, root: current, kind: "pnpm-workspace" };
3133
3345
  }
3134
- if (await fileExists((0, import_node_path6.join)(current, "turbo.json"))) {
3346
+ if (await fileExists2((0, import_node_path7.join)(current, "turbo.json"))) {
3135
3347
  return { isMonorepo: true, root: current, kind: "turborepo" };
3136
3348
  }
3137
- const packageJsonPath = (0, import_node_path6.join)(current, "package.json");
3138
- if (await fileExists(packageJsonPath)) {
3349
+ const packageJsonPath = (0, import_node_path7.join)(current, "package.json");
3350
+ if (await fileExists2(packageJsonPath)) {
3139
3351
  try {
3140
- const packageJsonRaw = await (0, import_promises4.readFile)(packageJsonPath, "utf-8");
3352
+ const packageJsonRaw = await (0, import_promises5.readFile)(packageJsonPath, "utf-8");
3141
3353
  const parsed = JSON.parse(packageJsonRaw);
3142
3354
  if (Array.isArray(parsed.workspaces) || isNpmWorkspaceObject(parsed.workspaces)) {
3143
3355
  return { isMonorepo: true, root: current, kind: "npm-workspaces" };
@@ -3145,7 +3357,7 @@ async function detectMonorepoContext(startDir) {
3145
3357
  } catch {
3146
3358
  }
3147
3359
  }
3148
- const parent = (0, import_node_path6.dirname)(current);
3360
+ const parent = (0, import_node_path7.dirname)(current);
3149
3361
  if (parent === current) {
3150
3362
  return { isMonorepo: false, root: null, kind: "none" };
3151
3363
  }
@@ -3157,9 +3369,9 @@ async function applyEditorWorkspacePreset(params) {
3157
3369
  if (editor !== "vscode" && editor !== "cursor" && editor !== "windsurf") {
3158
3370
  return { applied: false, filePath: null };
3159
3371
  }
3160
- const vscodeDir = (0, import_node_path6.join)(targetDir, ".vscode");
3161
- const extensionsPath = (0, import_node_path6.join)(vscodeDir, "extensions.json");
3162
- await (0, import_promises4.mkdir)(vscodeDir, { recursive: true });
3372
+ const vscodeDir = (0, import_node_path7.join)(targetDir, ".vscode");
3373
+ const extensionsPath = (0, import_node_path7.join)(vscodeDir, "extensions.json");
3374
+ await (0, import_promises5.mkdir)(vscodeDir, { recursive: true });
3163
3375
  const recommendations = ["korajs.kora-devtools"];
3164
3376
  const existing = await readJsonObject(extensionsPath);
3165
3377
  const existingRecommendations = Array.isArray(existing?.recommendations) ? existing.recommendations.filter((item) => typeof item === "string") : [];
@@ -3167,19 +3379,19 @@ async function applyEditorWorkspacePreset(params) {
3167
3379
  const next = {
3168
3380
  recommendations: mergedRecommendations
3169
3381
  };
3170
- await (0, import_promises4.writeFile)(extensionsPath, `${JSON.stringify(next, null, 2)}
3382
+ await (0, import_promises5.writeFile)(extensionsPath, `${JSON.stringify(next, null, 2)}
3171
3383
  `, "utf-8");
3172
3384
  return { applied: true, filePath: extensionsPath };
3173
3385
  }
3174
3386
  function resolveMonorepoTargetDirectory(monorepoRoot, projectName) {
3175
- return (0, import_node_path6.join)(monorepoRoot, "packages", projectName);
3387
+ return (0, import_node_path7.join)(monorepoRoot, "packages", projectName);
3176
3388
  }
3177
3389
  function dedupeStrings(values) {
3178
3390
  return Array.from(new Set(values));
3179
3391
  }
3180
3392
  async function readJsonObject(path) {
3181
3393
  try {
3182
- const content = await (0, import_promises4.readFile)(path, "utf-8");
3394
+ const content = await (0, import_promises5.readFile)(path, "utf-8");
3183
3395
  const parsed = JSON.parse(content);
3184
3396
  if (typeof parsed === "object" && parsed !== null) {
3185
3397
  return parsed;
@@ -3194,24 +3406,24 @@ function isNpmWorkspaceObject(value) {
3194
3406
  const record = value;
3195
3407
  return Array.isArray(record.packages);
3196
3408
  }
3197
- async function fileExists(path) {
3409
+ async function fileExists2(path) {
3198
3410
  try {
3199
- await (0, import_promises4.access)(path);
3411
+ await (0, import_promises5.access)(path);
3200
3412
  return true;
3201
3413
  } catch {
3202
3414
  return false;
3203
3415
  }
3204
3416
  }
3205
3417
  async function findNearestAncestorWithEntry(startDir, entryName) {
3206
- let current = (0, import_node_path6.resolve)(startDir);
3418
+ let current = (0, import_node_path7.resolve)(startDir);
3207
3419
  for (; ; ) {
3208
- const candidate = (0, import_node_path6.join)(current, entryName);
3420
+ const candidate = (0, import_node_path7.join)(current, entryName);
3209
3421
  try {
3210
- await (0, import_promises4.stat)(candidate);
3422
+ await (0, import_promises5.stat)(candidate);
3211
3423
  return current;
3212
3424
  } catch {
3213
3425
  }
3214
- const parent = (0, import_node_path6.dirname)(current);
3426
+ const parent = (0, import_node_path7.dirname)(current);
3215
3427
  if (parent === current) {
3216
3428
  return null;
3217
3429
  }
@@ -3490,8 +3702,8 @@ function validateProjectName(name) {
3490
3702
  }
3491
3703
 
3492
3704
  // src/commands/create/sync-provider-preset.ts
3493
- var import_promises5 = require("fs/promises");
3494
- var import_node_path7 = require("path");
3705
+ var import_promises6 = require("fs/promises");
3706
+ var import_node_path8 = require("path");
3495
3707
  async function applySyncProviderPreset(options) {
3496
3708
  if (!isSyncTemplate(options.template)) {
3497
3709
  return;
@@ -3501,10 +3713,10 @@ async function applySyncProviderPreset(options) {
3501
3713
  }
3502
3714
  const providerName = getProviderDisplayName(options.dbProvider);
3503
3715
  const providerConnectionString = getProviderConnectionStringExample(options.dbProvider);
3504
- const envPath = (0, import_node_path7.join)(options.targetDir, ".env.example");
3505
- const readmePath = (0, import_node_path7.join)(options.targetDir, "README.md");
3506
- const existingReadme = await (0, import_promises5.readFile)(readmePath, "utf-8");
3507
- const existingEnv = await (0, import_promises5.readFile)(envPath, "utf-8");
3716
+ const envPath = (0, import_node_path8.join)(options.targetDir, ".env.example");
3717
+ const readmePath = (0, import_node_path8.join)(options.targetDir, "README.md");
3718
+ const existingReadme = await (0, import_promises6.readFile)(readmePath, "utf-8");
3719
+ const existingEnv = await (0, import_promises6.readFile)(envPath, "utf-8");
3508
3720
  const trimmedReadme = existingReadme.trimEnd();
3509
3721
  const trimmedEnv = existingEnv.trimEnd();
3510
3722
  const envSuffix = [
@@ -3524,9 +3736,9 @@ async function applySyncProviderPreset(options) {
3524
3736
  ""
3525
3737
  ].join("\n");
3526
3738
  const readmeTemplate = `${trimmedReadme}${readmeSuffix}`;
3527
- await (0, import_promises5.writeFile)(envPath, `${trimmedEnv}${envSuffix}
3739
+ await (0, import_promises6.writeFile)(envPath, `${trimmedEnv}${envSuffix}
3528
3740
  `, "utf-8");
3529
- await (0, import_promises5.writeFile)(readmePath, readmeTemplate, "utf-8");
3741
+ await (0, import_promises6.writeFile)(readmePath, readmeTemplate, "utf-8");
3530
3742
  }
3531
3743
  function isSyncTemplate(template) {
3532
3744
  return template === "react-sync" || template === "react-tailwind-sync" || template === "vue-sync" || template === "vue-tailwind-sync" || template === "svelte-sync" || template === "svelte-tailwind-sync" || template === "tauri-react";
@@ -3570,8 +3782,8 @@ function getProviderConnectionStringExample(provider) {
3570
3782
 
3571
3783
  // src/templates/composer.ts
3572
3784
  var import_node_fs = require("fs");
3573
- var import_promises6 = require("fs/promises");
3574
- var import_node_path8 = require("path");
3785
+ var import_promises7 = require("fs/promises");
3786
+ var import_node_path9 = require("path");
3575
3787
  var import_node_url3 = require("url");
3576
3788
  var import_meta = {};
3577
3789
  function substituteVariables(template, context) {
@@ -3581,16 +3793,16 @@ function substituteVariables(template, context) {
3581
3793
  });
3582
3794
  }
3583
3795
  function getTemplatePath(templateName) {
3584
- let dir = (0, import_node_path8.dirname)((0, import_node_url3.fileURLToPath)(import_meta.url));
3796
+ let dir = (0, import_node_path9.dirname)((0, import_node_url3.fileURLToPath)(import_meta.url));
3585
3797
  for (let i = 0; i < 7; i++) {
3586
- const candidate = (0, import_node_path8.resolve)(dir, "templates", templateName);
3798
+ const candidate = (0, import_node_path9.resolve)(dir, "templates", templateName);
3587
3799
  if ((0, import_node_fs.existsSync)(candidate)) {
3588
3800
  return candidate;
3589
3801
  }
3590
- dir = (0, import_node_path8.dirname)(dir);
3802
+ dir = (0, import_node_path9.dirname)(dir);
3591
3803
  }
3592
- const currentDir = (0, import_node_path8.dirname)((0, import_node_url3.fileURLToPath)(import_meta.url));
3593
- return (0, import_node_path8.resolve)(currentDir, "..", "..", "..", "templates", templateName);
3804
+ const currentDir = (0, import_node_path9.dirname)((0, import_node_url3.fileURLToPath)(import_meta.url));
3805
+ return (0, import_node_path9.resolve)(currentDir, "..", "..", "..", "templates", templateName);
3594
3806
  }
3595
3807
  function createCompatibilityLayerPlan(templateName) {
3596
3808
  const baseLayer = { category: "base", name: "base", sourceTemplate: "react-basic" };
@@ -3723,22 +3935,22 @@ async function composeTemplateLayers(plan, targetDir, context) {
3723
3935
  }
3724
3936
  }
3725
3937
  async function copyDirectory(src, dest, vars) {
3726
- await (0, import_promises6.mkdir)(dest, { recursive: true });
3727
- const entries = await (0, import_promises6.readdir)(src);
3938
+ await (0, import_promises7.mkdir)(dest, { recursive: true });
3939
+ const entries = await (0, import_promises7.readdir)(src);
3728
3940
  for (const entry of entries) {
3729
- const srcPath = (0, import_node_path8.join)(src, entry);
3730
- const srcStat = await (0, import_promises6.stat)(srcPath);
3941
+ const srcPath = (0, import_node_path9.join)(src, entry);
3942
+ const srcStat = await (0, import_promises7.stat)(srcPath);
3731
3943
  if (srcStat.isDirectory()) {
3732
- await copyDirectory(srcPath, (0, import_node_path8.join)(dest, entry), vars);
3944
+ await copyDirectory(srcPath, (0, import_node_path9.join)(dest, entry), vars);
3733
3945
  continue;
3734
3946
  }
3735
3947
  if (entry.endsWith(".hbs")) {
3736
- const content = await (0, import_promises6.readFile)(srcPath, "utf-8");
3948
+ const content = await (0, import_promises7.readFile)(srcPath, "utf-8");
3737
3949
  const outputName = entry.slice(0, -4);
3738
- await (0, import_promises6.writeFile)((0, import_node_path8.join)(dest, outputName), substituteVariables(content, vars), "utf-8");
3950
+ await (0, import_promises7.writeFile)((0, import_node_path9.join)(dest, outputName), substituteVariables(content, vars), "utf-8");
3739
3951
  continue;
3740
3952
  }
3741
- await (0, import_promises6.copyFile)(srcPath, (0, import_node_path8.join)(dest, entry));
3953
+ await (0, import_promises7.copyFile)(srcPath, (0, import_node_path9.join)(dest, entry));
3742
3954
  }
3743
3955
  }
3744
3956
 
@@ -3750,7 +3962,7 @@ async function scaffoldTemplate(templateName, targetDir, context) {
3750
3962
 
3751
3963
  // src/commands/create/create-command.ts
3752
3964
  var import_meta2 = {};
3753
- var createCommand = (0, import_citty3.defineCommand)({
3965
+ var createCommand = (0, import_citty4.defineCommand)({
3754
3966
  meta: {
3755
3967
  name: "create",
3756
3968
  description: "Create a new Kora application"
@@ -3891,7 +4103,7 @@ var createCommand = (0, import_citty3.defineCommand)({
3891
4103
  const editorDetection = detectEditorFromEnvironment();
3892
4104
  const gitContext = await detectGitContext(process.cwd());
3893
4105
  const monorepoContext = await detectMonorepoContext(process.cwd());
3894
- let targetDir = (0, import_node_path9.resolve)(process.cwd(), projectName);
4106
+ let targetDir = (0, import_node_path10.resolve)(process.cwd(), projectName);
3895
4107
  if (!useDefaults && monorepoContext.isMonorepo && monorepoContext.root !== null) {
3896
4108
  const useWorkspaceTarget = await prompts.confirm(
3897
4109
  `Detected ${formatMonorepoKind(monorepoContext.kind)} at ${monorepoContext.root}. Create app under packages/${projectName}?`,
@@ -4061,29 +4273,33 @@ function relativeToTarget(targetDir, filePath) {
4061
4273
  }
4062
4274
  function resolveKoraVersion() {
4063
4275
  try {
4064
- let dir = (0, import_node_path9.dirname)((0, import_node_url4.fileURLToPath)(import_meta2.url));
4276
+ let dir = (0, import_node_path10.dirname)((0, import_node_url4.fileURLToPath)(import_meta2.url));
4065
4277
  for (let i = 0; i < 5; i++) {
4066
- const pkgPath = (0, import_node_path9.resolve)(dir, "package.json");
4278
+ const pkgPath = (0, import_node_path10.resolve)(dir, "package.json");
4067
4279
  if ((0, import_node_fs2.existsSync)(pkgPath)) {
4068
4280
  const pkg = JSON.parse((0, import_node_fs2.readFileSync)(pkgPath, "utf-8"));
4069
4281
  if (pkg.name === "@korajs/cli") {
4070
- if (pkg.version === "0.0.0") return "latest";
4071
- const parts = pkg.version.split(".");
4072
- return `^${parts[0]}.${parts[1]}.0`;
4282
+ return deriveKoraTemplateVersion(pkg.version);
4073
4283
  }
4074
4284
  }
4075
- dir = (0, import_node_path9.dirname)(dir);
4285
+ dir = (0, import_node_path10.dirname)(dir);
4076
4286
  }
4077
4287
  return "latest";
4078
4288
  } catch {
4079
4289
  return "latest";
4080
4290
  }
4081
4291
  }
4292
+ function deriveKoraTemplateVersion(version) {
4293
+ if (version === "0.0.0") return "latest";
4294
+ if (version.includes("-")) return version;
4295
+ const parts = version.split(".");
4296
+ return `^${parts[0]}.${parts[1]}.0`;
4297
+ }
4082
4298
 
4083
4299
  // src/commands/deploy/deploy-command.ts
4084
4300
  var import_node_fs4 = require("fs");
4085
- var import_node_path20 = require("path");
4086
- var import_citty4 = require("citty");
4301
+ var import_node_path21 = require("path");
4302
+ var import_citty5 = require("citty");
4087
4303
  init_fs_helpers();
4088
4304
 
4089
4305
  // src/commands/deploy/adapters/adapter.ts
@@ -4102,13 +4318,13 @@ function isDeployPlatform(value) {
4102
4318
 
4103
4319
  // src/commands/deploy/adapters/aws-ecs-adapter.ts
4104
4320
  var import_node_child_process6 = require("child_process");
4105
- var import_node_path12 = require("path");
4321
+ var import_node_path13 = require("path");
4106
4322
 
4107
4323
  // src/commands/deploy/builder/client-builder.ts
4108
4324
  var import_node_child_process5 = require("child_process");
4109
4325
  var import_node_fs3 = require("fs");
4110
- var import_promises7 = require("fs/promises");
4111
- var import_node_path10 = require("path");
4326
+ var import_promises8 = require("fs/promises");
4327
+ var import_node_path11 = require("path");
4112
4328
  init_fs_helpers();
4113
4329
  async function buildClient(options) {
4114
4330
  const viteEntryPoint = await resolveProjectBinaryEntryPoint(options.projectRoot, "vite", "vite");
@@ -4130,15 +4346,15 @@ async function buildClient(options) {
4130
4346
  return { outDir: options.outDir };
4131
4347
  }
4132
4348
  async function patchSqliteWasmAssets(projectRoot, outDir) {
4133
- const assetsDir = (0, import_node_path10.join)(outDir, "assets");
4349
+ const assetsDir = (0, import_node_path11.join)(outDir, "assets");
4134
4350
  if (!(0, import_node_fs3.existsSync)(assetsDir)) return;
4135
- const files = await (0, import_promises7.readdir)(assetsDir);
4351
+ const files = await (0, import_promises8.readdir)(assetsDir);
4136
4352
  const hashedWasm = files.find((f) => /^sqlite3-.+\.wasm$/.test(f));
4137
4353
  if (hashedWasm && !files.includes("sqlite3.wasm")) {
4138
- await (0, import_promises7.copyFile)((0, import_node_path10.join)(assetsDir, hashedWasm), (0, import_node_path10.join)(assetsDir, "sqlite3.wasm"));
4354
+ await (0, import_promises8.copyFile)((0, import_node_path11.join)(assetsDir, hashedWasm), (0, import_node_path11.join)(assetsDir, "sqlite3.wasm"));
4139
4355
  }
4140
4356
  if (!files.includes("sqlite3-opfs-async-proxy.js")) {
4141
- const proxyFile = (0, import_node_path10.resolve)(
4357
+ const proxyFile = (0, import_node_path11.resolve)(
4142
4358
  projectRoot,
4143
4359
  "node_modules",
4144
4360
  "@sqlite.org",
@@ -4148,7 +4364,7 @@ async function patchSqliteWasmAssets(projectRoot, outDir) {
4148
4364
  "sqlite3-opfs-async-proxy.js"
4149
4365
  );
4150
4366
  if ((0, import_node_fs3.existsSync)(proxyFile)) {
4151
- await (0, import_promises7.copyFile)(proxyFile, (0, import_node_path10.join)(assetsDir, "sqlite3-opfs-async-proxy.js"));
4367
+ await (0, import_promises8.copyFile)(proxyFile, (0, import_node_path11.join)(assetsDir, "sqlite3-opfs-async-proxy.js"));
4152
4368
  }
4153
4369
  }
4154
4370
  }
@@ -4173,9 +4389,9 @@ async function runProcess(command, args, cwd) {
4173
4389
  }
4174
4390
 
4175
4391
  // src/commands/deploy/builder/server-bundler.ts
4176
- var import_promises8 = require("fs/promises");
4177
4392
  var import_promises9 = require("fs/promises");
4178
- var import_node_path11 = require("path");
4393
+ var import_promises10 = require("fs/promises");
4394
+ var import_node_path12 = require("path");
4179
4395
  var import_esbuild = require("esbuild");
4180
4396
  var DEFAULT_ENTRY_CANDIDATES = [
4181
4397
  "server.ts",
@@ -4191,8 +4407,8 @@ async function bundleServer(options) {
4191
4407
  `Could not find a server entry file in ${options.projectRoot}. Looked for: ${candidates.join(", ")}`
4192
4408
  );
4193
4409
  }
4194
- await (0, import_promises8.mkdir)(options.deployDirectory, { recursive: true });
4195
- const outputFilePath = (0, import_node_path11.join)(options.deployDirectory, "server-bundled.js");
4410
+ await (0, import_promises9.mkdir)(options.deployDirectory, { recursive: true });
4411
+ const outputFilePath = (0, import_node_path12.join)(options.deployDirectory, "server-bundled.js");
4196
4412
  await (0, import_esbuild.build)({
4197
4413
  entryPoints: [entryFilePath],
4198
4414
  outfile: outputFilePath,
@@ -4214,9 +4430,9 @@ async function bundleServer(options) {
4214
4430
  }
4215
4431
  async function resolveServerEntry(projectRoot, candidates) {
4216
4432
  for (const candidate of candidates) {
4217
- const fullPath = (0, import_node_path11.join)(projectRoot, candidate);
4433
+ const fullPath = (0, import_node_path12.join)(projectRoot, candidate);
4218
4434
  try {
4219
- await (0, import_promises9.access)(fullPath);
4435
+ await (0, import_promises10.access)(fullPath);
4220
4436
  return fullPath;
4221
4437
  } catch {
4222
4438
  }
@@ -4318,19 +4534,19 @@ var AwsEcsAdapter = class {
4318
4534
  appName: config.appName,
4319
4535
  region: config.region
4320
4536
  };
4321
- const deployDirectory = (0, import_node_path12.join)(config.projectRoot, ".kora", "deploy");
4537
+ const deployDirectory = (0, import_node_path13.join)(config.projectRoot, ".kora", "deploy");
4322
4538
  await bundleServer({
4323
4539
  projectRoot: config.projectRoot,
4324
4540
  deployDirectory
4325
4541
  });
4326
4542
  const client = config.deployTarget === "sync-server" ? null : await buildClient({
4327
4543
  projectRoot: config.projectRoot,
4328
- outDir: (0, import_node_path12.join)(deployDirectory, "dist"),
4544
+ outDir: (0, import_node_path13.join)(deployDirectory, "dist"),
4329
4545
  mode: "production"
4330
4546
  });
4331
4547
  return {
4332
4548
  clientDirectory: client?.outDir ?? null,
4333
- serverBundlePath: (0, import_node_path12.join)(deployDirectory, "server-bundled.js"),
4549
+ serverBundlePath: (0, import_node_path13.join)(deployDirectory, "server-bundled.js"),
4334
4550
  deployDirectory
4335
4551
  };
4336
4552
  }
@@ -4596,7 +4812,7 @@ function inferLogLevel(line) {
4596
4812
 
4597
4813
  // src/commands/deploy/adapters/aws-lightsail-adapter.ts
4598
4814
  var import_node_child_process7 = require("child_process");
4599
- var import_node_path13 = require("path");
4815
+ var import_node_path14 = require("path");
4600
4816
  var AwsLightsailAdapter = class {
4601
4817
  name = "aws-lightsail";
4602
4818
  logger = createLogger();
@@ -4669,19 +4885,19 @@ var AwsLightsailAdapter = class {
4669
4885
  appName: config.appName,
4670
4886
  region: config.region
4671
4887
  };
4672
- const deployDirectory = (0, import_node_path13.join)(config.projectRoot, ".kora", "deploy");
4888
+ const deployDirectory = (0, import_node_path14.join)(config.projectRoot, ".kora", "deploy");
4673
4889
  await bundleServer({
4674
4890
  projectRoot: config.projectRoot,
4675
4891
  deployDirectory
4676
4892
  });
4677
4893
  const client = config.deployTarget === "sync-server" ? null : await buildClient({
4678
4894
  projectRoot: config.projectRoot,
4679
- outDir: (0, import_node_path13.join)(deployDirectory, "dist"),
4895
+ outDir: (0, import_node_path14.join)(deployDirectory, "dist"),
4680
4896
  mode: "production"
4681
4897
  });
4682
4898
  return {
4683
4899
  clientDirectory: client?.outDir ?? null,
4684
- serverBundlePath: (0, import_node_path13.join)(deployDirectory, "server-bundled.js"),
4900
+ serverBundlePath: (0, import_node_path14.join)(deployDirectory, "server-bundled.js"),
4685
4901
  deployDirectory
4686
4902
  };
4687
4903
  }
@@ -4981,11 +5197,11 @@ function inferLogLevel2(line) {
4981
5197
 
4982
5198
  // src/commands/deploy/adapters/fly-adapter.ts
4983
5199
  var import_node_child_process8 = require("child_process");
4984
- var import_node_path15 = require("path");
5200
+ var import_node_path16 = require("path");
4985
5201
 
4986
5202
  // src/commands/deploy/artifacts/fly-toml-generator.ts
4987
- var import_promises10 = require("fs/promises");
4988
- var import_node_path14 = require("path");
5203
+ var import_promises11 = require("fs/promises");
5204
+ var import_node_path15 = require("path");
4989
5205
  var GENERATED_HEADER = "# Generated by kora deploy \u2014 do not edit manually";
4990
5206
  function generateFlyToml(options) {
4991
5207
  const internalPort = options.internalPort ?? 3e3;
@@ -5015,9 +5231,9 @@ function generateFlyToml(options) {
5015
5231
  ].join("\n");
5016
5232
  }
5017
5233
  async function writeFlyTomlArtifact(deployDirectory, options) {
5018
- await (0, import_promises10.mkdir)(deployDirectory, { recursive: true });
5019
- const filePath = (0, import_node_path14.join)(deployDirectory, "fly.toml");
5020
- await (0, import_promises10.writeFile)(filePath, generateFlyToml(options), "utf-8");
5234
+ await (0, import_promises11.mkdir)(deployDirectory, { recursive: true });
5235
+ const filePath = (0, import_node_path15.join)(deployDirectory, "fly.toml");
5236
+ await (0, import_promises11.writeFile)(filePath, generateFlyToml(options), "utf-8");
5021
5237
  return filePath;
5022
5238
  }
5023
5239
 
@@ -5111,7 +5327,7 @@ var FlyAdapter = class {
5111
5327
  appName: config.appName,
5112
5328
  region: config.region
5113
5329
  };
5114
- const deployDirectory = (0, import_node_path15.join)(config.projectRoot, ".kora", "deploy");
5330
+ const deployDirectory = (0, import_node_path16.join)(config.projectRoot, ".kora", "deploy");
5115
5331
  await writeFlyTomlArtifact(deployDirectory, {
5116
5332
  appName: config.appName,
5117
5333
  region: config.region ?? "iad"
@@ -5122,12 +5338,12 @@ var FlyAdapter = class {
5122
5338
  });
5123
5339
  const client = config.deployTarget === "sync-server" ? null : await buildClient({
5124
5340
  projectRoot: config.projectRoot,
5125
- outDir: (0, import_node_path15.join)(deployDirectory, "dist"),
5341
+ outDir: (0, import_node_path16.join)(deployDirectory, "dist"),
5126
5342
  mode: "production"
5127
5343
  });
5128
5344
  return {
5129
5345
  clientDirectory: client?.outDir ?? null,
5130
- serverBundlePath: (0, import_node_path15.join)(deployDirectory, "server-bundled.js"),
5346
+ serverBundlePath: (0, import_node_path16.join)(deployDirectory, "server-bundled.js"),
5131
5347
  deployDirectory
5132
5348
  };
5133
5349
  }
@@ -5349,11 +5565,11 @@ ${stdout}`.toLowerCase();
5349
5565
 
5350
5566
  // src/commands/deploy/adapters/railway-adapter.ts
5351
5567
  var import_node_child_process9 = require("child_process");
5352
- var import_node_path17 = require("path");
5568
+ var import_node_path18 = require("path");
5353
5569
 
5354
5570
  // src/commands/deploy/artifacts/railway-json-generator.ts
5355
- var import_promises11 = require("fs/promises");
5356
- var import_node_path16 = require("path");
5571
+ var import_promises12 = require("fs/promises");
5572
+ var import_node_path17 = require("path");
5357
5573
  var GENERATED_HEADER2 = "Generated by kora deploy - do not edit manually.";
5358
5574
  function generateRailwayJson(options) {
5359
5575
  const file = {
@@ -5378,9 +5594,9 @@ function generateRailwayJson(options) {
5378
5594
  `;
5379
5595
  }
5380
5596
  async function writeRailwayJsonArtifact(deployDirectory, options) {
5381
- await (0, import_promises11.mkdir)(deployDirectory, { recursive: true });
5382
- const filePath = (0, import_node_path16.join)(deployDirectory, "railway.json");
5383
- await (0, import_promises11.writeFile)(filePath, generateRailwayJson(options), "utf-8");
5597
+ await (0, import_promises12.mkdir)(deployDirectory, { recursive: true });
5598
+ const filePath = (0, import_node_path17.join)(deployDirectory, "railway.json");
5599
+ await (0, import_promises12.writeFile)(filePath, generateRailwayJson(options), "utf-8");
5384
5600
  return filePath;
5385
5601
  }
5386
5602
 
@@ -5469,7 +5685,7 @@ var RailwayAdapter = class {
5469
5685
  appName: config.appName,
5470
5686
  region: config.region
5471
5687
  };
5472
- const deployDirectory = (0, import_node_path17.join)(config.projectRoot, ".kora", "deploy");
5688
+ const deployDirectory = (0, import_node_path18.join)(config.projectRoot, ".kora", "deploy");
5473
5689
  await writeRailwayJsonArtifact(deployDirectory, {
5474
5690
  appName: config.appName,
5475
5691
  environment: config.environment
@@ -5480,12 +5696,12 @@ var RailwayAdapter = class {
5480
5696
  });
5481
5697
  const client = config.deployTarget === "sync-server" ? null : await buildClient({
5482
5698
  projectRoot: config.projectRoot,
5483
- outDir: (0, import_node_path17.join)(deployDirectory, "dist"),
5699
+ outDir: (0, import_node_path18.join)(deployDirectory, "dist"),
5484
5700
  mode: "production"
5485
5701
  });
5486
5702
  return {
5487
5703
  clientDirectory: client?.outDir ?? null,
5488
- serverBundlePath: (0, import_node_path17.join)(deployDirectory, "server-bundled.js"),
5704
+ serverBundlePath: (0, import_node_path18.join)(deployDirectory, "server-bundled.js"),
5489
5705
  deployDirectory
5490
5706
  };
5491
5707
  }
@@ -5770,8 +5986,8 @@ function createDeployAdapter(platform) {
5770
5986
  }
5771
5987
 
5772
5988
  // src/commands/deploy/artifacts/dockerfile-generator.ts
5773
- var import_promises12 = require("fs/promises");
5774
- var import_node_path18 = require("path");
5989
+ var import_promises13 = require("fs/promises");
5990
+ var import_node_path19 = require("path");
5775
5991
  var GENERATED_HEADER3 = "# Generated by kora deploy \u2014 do not edit manually";
5776
5992
  function generateDockerfile(options = {}) {
5777
5993
  const nodeVersion = options.nodeVersion ?? "20-alpine";
@@ -5837,37 +6053,37 @@ function generateDockerIgnore() {
5837
6053
  ].join("\n");
5838
6054
  }
5839
6055
  async function writeDockerfileArtifact(deployDirectory, options = {}) {
5840
- await (0, import_promises12.mkdir)(deployDirectory, { recursive: true });
5841
- const dockerfilePath = (0, import_node_path18.join)(deployDirectory, "Dockerfile");
5842
- await (0, import_promises12.writeFile)(dockerfilePath, generateDockerfile(options), "utf-8");
6056
+ await (0, import_promises13.mkdir)(deployDirectory, { recursive: true });
6057
+ const dockerfilePath = (0, import_node_path19.join)(deployDirectory, "Dockerfile");
6058
+ await (0, import_promises13.writeFile)(dockerfilePath, generateDockerfile(options), "utf-8");
5843
6059
  if (options.nativeDependencies && Object.keys(options.nativeDependencies).length > 0) {
5844
- const pkgJsonPath = (0, import_node_path18.join)(deployDirectory, "package.json");
5845
- await (0, import_promises12.writeFile)(pkgJsonPath, generateDeployPackageJson(options.nativeDependencies), "utf-8");
6060
+ const pkgJsonPath = (0, import_node_path19.join)(deployDirectory, "package.json");
6061
+ await (0, import_promises13.writeFile)(pkgJsonPath, generateDeployPackageJson(options.nativeDependencies), "utf-8");
5846
6062
  }
5847
6063
  return dockerfilePath;
5848
6064
  }
5849
6065
  async function writeDockerIgnoreArtifact(deployDirectory) {
5850
- await (0, import_promises12.mkdir)(deployDirectory, { recursive: true });
5851
- const dockerIgnorePath = (0, import_node_path18.join)(deployDirectory, ".dockerignore");
5852
- await (0, import_promises12.writeFile)(dockerIgnorePath, generateDockerIgnore(), "utf-8");
6066
+ await (0, import_promises13.mkdir)(deployDirectory, { recursive: true });
6067
+ const dockerIgnorePath = (0, import_node_path19.join)(deployDirectory, ".dockerignore");
6068
+ await (0, import_promises13.writeFile)(dockerIgnorePath, generateDockerIgnore(), "utf-8");
5853
6069
  return dockerIgnorePath;
5854
6070
  }
5855
6071
 
5856
6072
  // src/commands/deploy/state/deploy-state.ts
5857
- var import_promises13 = require("fs/promises");
5858
- var import_node_path19 = require("path");
5859
- var KORA_DEPLOY_DIRECTORY = (0, import_node_path19.join)(".kora", "deploy");
6073
+ var import_promises14 = require("fs/promises");
6074
+ var import_node_path20 = require("path");
6075
+ var KORA_DEPLOY_DIRECTORY = (0, import_node_path20.join)(".kora", "deploy");
5860
6076
  var DEPLOY_STATE_FILENAME = "deploy.json";
5861
6077
  function resolveDeployDirectory(projectRoot) {
5862
- return (0, import_node_path19.join)(projectRoot, KORA_DEPLOY_DIRECTORY);
6078
+ return (0, import_node_path20.join)(projectRoot, KORA_DEPLOY_DIRECTORY);
5863
6079
  }
5864
6080
  function resolveDeployStatePath(projectRoot) {
5865
- return (0, import_node_path19.join)(resolveDeployDirectory(projectRoot), DEPLOY_STATE_FILENAME);
6081
+ return (0, import_node_path20.join)(resolveDeployDirectory(projectRoot), DEPLOY_STATE_FILENAME);
5866
6082
  }
5867
6083
  async function readDeployState(projectRoot) {
5868
6084
  const statePath = resolveDeployStatePath(projectRoot);
5869
6085
  try {
5870
- const source = await (0, import_promises13.readFile)(statePath, "utf-8");
6086
+ const source = await (0, import_promises14.readFile)(statePath, "utf-8");
5871
6087
  const parsed = JSON.parse(source);
5872
6088
  return parseDeployState(parsed);
5873
6089
  } catch (error) {
@@ -5914,13 +6130,13 @@ async function updateDeployState(projectRoot, patch, now = /* @__PURE__ */ new D
5914
6130
  return nextState;
5915
6131
  }
5916
6132
  async function resetDeployState(projectRoot) {
5917
- await (0, import_promises13.rm)(resolveDeployDirectory(projectRoot), { recursive: true, force: true });
6133
+ await (0, import_promises14.rm)(resolveDeployDirectory(projectRoot), { recursive: true, force: true });
5918
6134
  }
5919
6135
  async function persistDeployState(projectRoot, state) {
5920
6136
  const deployDir = resolveDeployDirectory(projectRoot);
5921
6137
  const statePath = resolveDeployStatePath(projectRoot);
5922
- await (0, import_promises13.mkdir)(deployDir, { recursive: true });
5923
- await (0, import_promises13.writeFile)(statePath, `${JSON.stringify(state, null, 2)}
6138
+ await (0, import_promises14.mkdir)(deployDir, { recursive: true });
6139
+ await (0, import_promises14.writeFile)(statePath, `${JSON.stringify(state, null, 2)}
5924
6140
  `, "utf-8");
5925
6141
  }
5926
6142
  function parseDeployState(value) {
@@ -5970,7 +6186,7 @@ function readOptionalString(value, field) {
5970
6186
  }
5971
6187
 
5972
6188
  // src/commands/deploy/deploy-command.ts
5973
- var deployCommand = (0, import_citty4.defineCommand)({
6189
+ var deployCommand = (0, import_citty5.defineCommand)({
5974
6190
  meta: {
5975
6191
  name: "deploy",
5976
6192
  description: "Deploy a Kora project to your selected platform"
@@ -6005,7 +6221,7 @@ var deployCommand = (0, import_citty4.defineCommand)({
6005
6221
  }
6006
6222
  },
6007
6223
  subCommands: {
6008
- status: (0, import_citty4.defineCommand)({
6224
+ status: (0, import_citty5.defineCommand)({
6009
6225
  meta: {
6010
6226
  name: "status",
6011
6227
  description: "Show current deployment status"
@@ -6036,7 +6252,7 @@ var deployCommand = (0, import_citty4.defineCommand)({
6036
6252
  logger.step(`Sync URL: ${state.syncUrl ?? "n/a"}`);
6037
6253
  }
6038
6254
  }),
6039
- rollback: (0, import_citty4.defineCommand)({
6255
+ rollback: (0, import_citty5.defineCommand)({
6040
6256
  meta: {
6041
6257
  name: "rollback",
6042
6258
  description: "Rollback the current deployment"
@@ -6067,7 +6283,7 @@ var deployCommand = (0, import_citty4.defineCommand)({
6067
6283
  logger.success(`Rolled back ${state.platform} deployment to ${deploymentId}.`);
6068
6284
  }
6069
6285
  }),
6070
- logs: (0, import_citty4.defineCommand)({
6286
+ logs: (0, import_citty5.defineCommand)({
6071
6287
  meta: {
6072
6288
  name: "logs",
6073
6289
  description: "Read deployment logs"
@@ -6254,7 +6470,7 @@ function resolveAppName(argValue, storedValue, projectRoot, confirm) {
6254
6470
  "Missing app name in --confirm mode. Provide --app or run an interactive deploy first."
6255
6471
  );
6256
6472
  }
6257
- return sanitizeAppName((0, import_node_path20.basename)(projectRoot));
6473
+ return sanitizeAppName((0, import_node_path21.basename)(projectRoot));
6258
6474
  }
6259
6475
  function resolveRegion(argValue, storedValue, confirm) {
6260
6476
  if (typeof argValue === "string" && argValue.length > 0) return argValue;
@@ -6289,17 +6505,18 @@ function configureAdapterContext(adapter, context) {
6289
6505
  }
6290
6506
  }
6291
6507
  function detectDeployTarget(projectRoot) {
6292
- return (0, import_node_fs4.existsSync)((0, import_node_path20.join)(projectRoot, "src-tauri")) ? "sync-server" : "full-stack";
6508
+ return (0, import_node_fs4.existsSync)((0, import_node_path21.join)(projectRoot, "src-tauri")) ? "sync-server" : "full-stack";
6293
6509
  }
6294
6510
  function hasContextSetter(adapter) {
6295
6511
  return typeof adapter.setContext === "function";
6296
6512
  }
6297
6513
 
6298
6514
  // src/commands/dev/dev-command.ts
6299
- var import_promises14 = require("fs/promises");
6300
- var import_node_path22 = require("path");
6515
+ var import_node_fs6 = require("fs");
6516
+ var import_promises15 = require("fs/promises");
6301
6517
  var import_node_path23 = require("path");
6302
- var import_citty5 = require("citty");
6518
+ var import_node_path24 = require("path");
6519
+ var import_citty6 = require("citty");
6303
6520
  init_fs_helpers();
6304
6521
 
6305
6522
  // src/commands/dev/process-manager.ts
@@ -6307,6 +6524,7 @@ var import_node_child_process10 = require("child_process");
6307
6524
  var ProcessManager = class {
6308
6525
  processes = /* @__PURE__ */ new Map();
6309
6526
  spawn(config) {
6527
+ this.processes.get(config.label)?.child.kill("SIGTERM");
6310
6528
  const options = {
6311
6529
  cwd: config.cwd,
6312
6530
  env: { ...process.env, ...config.env },
@@ -6350,6 +6568,20 @@ var ProcessManager = class {
6350
6568
  hasRunning() {
6351
6569
  return this.processes.size > 0;
6352
6570
  }
6571
+ async restart(config) {
6572
+ await this.stop(config.label);
6573
+ this.spawn(config);
6574
+ }
6575
+ async stop(label) {
6576
+ const running = this.processes.get(label);
6577
+ if (!running) return;
6578
+ running.child.kill("SIGTERM");
6579
+ await Promise.race([running.exitPromise, delay(5e3)]);
6580
+ const remaining = this.processes.get(label);
6581
+ if (!remaining) return;
6582
+ remaining.child.kill("SIGKILL");
6583
+ await remaining.exitPromise;
6584
+ }
6353
6585
  async shutdownAll() {
6354
6586
  const running = Array.from(this.processes.values());
6355
6587
  if (running.length === 0) return;
@@ -6392,8 +6624,9 @@ function delay(ms) {
6392
6624
  // src/commands/dev/schema-watcher.ts
6393
6625
  var import_node_child_process11 = require("child_process");
6394
6626
  var import_node_fs5 = require("fs");
6395
- var import_node_path21 = require("path");
6627
+ var import_node_path22 = require("path");
6396
6628
  init_fs_helpers();
6629
+ init_schema_loader();
6397
6630
  var SchemaWatcher = class {
6398
6631
  constructor(config) {
6399
6632
  this.config = config;
@@ -6403,6 +6636,7 @@ var SchemaWatcher = class {
6403
6636
  debounceMs;
6404
6637
  watcher = null;
6405
6638
  debounceTimer = null;
6639
+ schemaVersion = null;
6406
6640
  start() {
6407
6641
  if (this.watcher) return;
6408
6642
  this.watcher = (0, import_node_fs5.watch)(this.config.schemaPath, () => {
@@ -6411,6 +6645,9 @@ var SchemaWatcher = class {
6411
6645
  this.watcher.on("error", (error) => {
6412
6646
  this.config.onError?.(toError(error));
6413
6647
  });
6648
+ void this.refreshSchemaVersion().catch((error) => {
6649
+ this.config.onError?.(toError(error));
6650
+ });
6414
6651
  }
6415
6652
  stop() {
6416
6653
  if (this.debounceTimer) {
@@ -6421,7 +6658,7 @@ var SchemaWatcher = class {
6421
6658
  this.watcher = null;
6422
6659
  }
6423
6660
  async regenerate() {
6424
- const koraBinJs = (0, import_node_path21.join)(
6661
+ const koraBinJs = (0, import_node_path22.join)(
6425
6662
  this.config.projectRoot,
6426
6663
  "node_modules",
6427
6664
  "@korajs",
@@ -6434,6 +6671,15 @@ var SchemaWatcher = class {
6434
6671
  const args = hasTsx ? ["--import", "tsx", koraBinJs, "generate", "types", "--schema", this.config.schemaPath] : [koraBinJs, "generate", "types", "--schema", this.config.schemaPath];
6435
6672
  await spawnCommand(command, args, this.config.projectRoot);
6436
6673
  this.config.onRegenerate?.();
6674
+ await this.refreshSchemaVersion();
6675
+ }
6676
+ async refreshSchemaVersion() {
6677
+ const schema = await loadSchemaDefinition(this.config.schemaPath, this.config.projectRoot);
6678
+ const previous = this.schemaVersion;
6679
+ this.schemaVersion = schema.version;
6680
+ if (previous !== null && previous !== schema.version) {
6681
+ this.config.onSchemaVersionChange?.({ previous, next: schema.version });
6682
+ }
6437
6683
  }
6438
6684
  scheduleRegeneration() {
6439
6685
  if (this.debounceTimer) {
@@ -6487,7 +6733,7 @@ function toError(error) {
6487
6733
  }
6488
6734
 
6489
6735
  // src/commands/dev/dev-command.ts
6490
- var devCommand = (0, import_citty5.defineCommand)({
6736
+ var devCommand = (0, import_citty6.defineCommand)({
6491
6737
  meta: {
6492
6738
  name: "dev",
6493
6739
  description: "Start the Kora development environment"
@@ -6518,6 +6764,7 @@ var devCommand = (0, import_citty5.defineCommand)({
6518
6764
  if (!projectRoot) {
6519
6765
  throw new InvalidProjectError(process.cwd());
6520
6766
  }
6767
+ loadProjectEnv(projectRoot);
6521
6768
  const config = await loadKoraConfig(projectRoot);
6522
6769
  const vitePort = typeof args.port === "string" ? args.port : String(config?.dev?.port ?? 5173);
6523
6770
  const syncPortFromConfig = typeof config?.dev?.sync === "object" && typeof config.dev.sync.port === "number" ? config.dev.sync.port : 3001;
@@ -6527,7 +6774,7 @@ var devCommand = (0, import_citty5.defineCommand)({
6527
6774
  const watchDebounceMs = typeof config?.dev?.watch === "object" && typeof config.dev.watch.debounceMs === "number" ? config.dev.watch.debounceMs : 300;
6528
6775
  const viteEntryPoint = await resolveProjectBinaryEntryPoint(projectRoot, "vite", "vite");
6529
6776
  if (!viteEntryPoint) {
6530
- throw new DevServerError("vite", (0, import_node_path22.join)(projectRoot, "node_modules", ".bin", "vite"));
6777
+ throw new DevServerError("vite", (0, import_node_path23.join)(projectRoot, "node_modules", ".bin", "vite"));
6531
6778
  }
6532
6779
  const syncServerFile = await findSyncServerFile(projectRoot);
6533
6780
  let managedSyncStore = normalizeManagedSyncStore(config, projectRoot);
@@ -6542,8 +6789,8 @@ var devCommand = (0, import_citty5.defineCommand)({
6542
6789
  }
6543
6790
  }
6544
6791
  if (shouldStartSync && syncServerFile === null && managedSyncStore) {
6545
- const hasServerPackage = await fileExists2(
6546
- (0, import_node_path22.join)(projectRoot, "node_modules", "@korajs", "server", "package.json")
6792
+ const hasServerPackage = await fileExists3(
6793
+ (0, import_node_path23.join)(projectRoot, "node_modules", "@korajs", "server", "package.json")
6547
6794
  );
6548
6795
  if (!hasServerPackage) {
6549
6796
  logger.warn(
@@ -6560,8 +6807,8 @@ var devCommand = (0, import_citty5.defineCommand)({
6560
6807
  }
6561
6808
  let configuredSchemaPath = null;
6562
6809
  if (typeof config?.schema === "string") {
6563
- const candidate = (0, import_node_path23.resolve)(projectRoot, config.schema);
6564
- if (await fileExists2(candidate)) {
6810
+ const candidate = (0, import_node_path24.resolve)(projectRoot, config.schema);
6811
+ if (await fileExists3(candidate)) {
6565
6812
  configuredSchemaPath = candidate;
6566
6813
  } else {
6567
6814
  logger.warn(
@@ -6619,7 +6866,9 @@ var devCommand = (0, import_citty5.defineCommand)({
6619
6866
  logger.step(" Schema watcher disabled (schema.ts not found)");
6620
6867
  }
6621
6868
  logger.blank();
6622
- logger.step(" Kora DevTools overlay: Ctrl+Shift+K (Cmd+Shift+K on macOS) when devtools: true");
6869
+ logger.step(
6870
+ " Kora DevTools overlay: Ctrl+Shift+K (Cmd+Shift+K on macOS) when devtools is enabled"
6871
+ );
6623
6872
  processManager.spawn({
6624
6873
  label: "vite",
6625
6874
  command: process.execPath,
@@ -6630,33 +6879,31 @@ var devCommand = (0, import_citty5.defineCommand)({
6630
6879
  },
6631
6880
  onExit: onManagedProcessExit
6632
6881
  });
6633
- if (shouldStartSync && hasTsx && syncServerFile) {
6634
- processManager.spawn({
6635
- label: "sync",
6636
- command: process.execPath,
6637
- args: ["--import", "tsx", syncServerFile],
6638
- cwd: projectRoot,
6639
- env: {
6640
- PORT: String(syncPort),
6641
- KORA_SYNC_PORT: String(syncPort)
6642
- },
6643
- onExit: onManagedProcessExit
6644
- });
6645
- }
6646
- if (shouldStartSync && syncServerFile === null && managedSyncStore !== null) {
6647
- processManager.spawn({
6648
- label: "sync",
6649
- command: process.execPath,
6650
- args: ["--input-type=module", "--eval", MANAGED_SYNC_BOOTSTRAP_SCRIPT],
6651
- cwd: projectRoot,
6652
- env: {
6653
- KORA_DEV_SYNC_CONFIG: JSON.stringify({
6654
- port: Number(syncPort),
6655
- store: managedSyncStore
6656
- })
6657
- },
6658
- onExit: onManagedProcessExit
6659
- });
6882
+ const syncProcessConfig = shouldStartSync && hasTsx && syncServerFile ? {
6883
+ label: "sync",
6884
+ command: process.execPath,
6885
+ args: ["--import", "tsx", syncServerFile],
6886
+ cwd: projectRoot,
6887
+ env: {
6888
+ PORT: String(syncPort),
6889
+ KORA_SYNC_PORT: String(syncPort)
6890
+ },
6891
+ onExit: onManagedProcessExit
6892
+ } : shouldStartSync && syncServerFile === null && managedSyncStore !== null ? {
6893
+ label: "sync",
6894
+ command: process.execPath,
6895
+ args: ["--input-type=module", "--eval", MANAGED_SYNC_BOOTSTRAP_SCRIPT],
6896
+ cwd: projectRoot,
6897
+ env: {
6898
+ KORA_DEV_SYNC_CONFIG: JSON.stringify({
6899
+ port: Number(syncPort),
6900
+ store: managedSyncStore
6901
+ })
6902
+ },
6903
+ onExit: onManagedProcessExit
6904
+ } : null;
6905
+ if (syncProcessConfig) {
6906
+ processManager.spawn(syncProcessConfig);
6660
6907
  }
6661
6908
  if (watchEnabled && schemaPath) {
6662
6909
  schemaWatcher = new SchemaWatcher({
@@ -6666,6 +6913,16 @@ var devCommand = (0, import_citty5.defineCommand)({
6666
6913
  onRegenerate: () => {
6667
6914
  logger.success("Regenerated types from schema changes");
6668
6915
  },
6916
+ onSchemaVersionChange: ({ previous, next }) => {
6917
+ if (!syncProcessConfig) {
6918
+ logger.warn(
6919
+ `Schema version changed from ${previous} to ${next}; restart your sync server before clients can sync.`
6920
+ );
6921
+ return;
6922
+ }
6923
+ logger.warn(`Schema version changed from ${previous} to ${next}; restarting sync server.`);
6924
+ void processManager.restart(syncProcessConfig);
6925
+ },
6669
6926
  onError: (error) => {
6670
6927
  logger.error(`Schema watcher error: ${error.message}`);
6671
6928
  }
@@ -6678,31 +6935,68 @@ var devCommand = (0, import_citty5.defineCommand)({
6678
6935
  }
6679
6936
  });
6680
6937
  async function findSyncServerFile(projectRoot) {
6681
- const candidates = [(0, import_node_path22.join)(projectRoot, "server.ts"), (0, import_node_path22.join)(projectRoot, "server.js")];
6938
+ const candidates = [(0, import_node_path23.join)(projectRoot, "server.ts"), (0, import_node_path23.join)(projectRoot, "server.js")];
6682
6939
  for (const candidate of candidates) {
6683
6940
  try {
6684
- await (0, import_promises14.access)(candidate);
6941
+ await (0, import_promises15.access)(candidate);
6685
6942
  return candidate;
6686
6943
  } catch {
6687
6944
  }
6688
6945
  }
6689
6946
  return null;
6690
6947
  }
6691
- async function fileExists2(path) {
6948
+ async function fileExists3(path) {
6692
6949
  try {
6693
- await (0, import_promises14.access)(path);
6950
+ await (0, import_promises15.access)(path);
6694
6951
  return true;
6695
6952
  } catch {
6696
6953
  return false;
6697
6954
  }
6698
6955
  }
6956
+ function loadProjectEnv(projectRoot, mode = "development") {
6957
+ const files = [".env", ".env.local", `.env.${mode}`, `.env.${mode}.local`];
6958
+ const existingKeys = new Set(Object.keys(process.env));
6959
+ for (const file of files) {
6960
+ const path = (0, import_node_path23.join)(projectRoot, file);
6961
+ if (!(0, import_node_fs6.existsSync)(path)) continue;
6962
+ const parsed = parseEnvFile((0, import_node_fs6.readFileSync)(path, "utf8"));
6963
+ for (const [key, value] of Object.entries(parsed)) {
6964
+ if (!existingKeys.has(key)) {
6965
+ process.env[key] = value;
6966
+ }
6967
+ }
6968
+ }
6969
+ }
6970
+ function parseEnvFile(contents) {
6971
+ const env = {};
6972
+ for (const rawLine of contents.split(/\r?\n/)) {
6973
+ const line = rawLine.trim();
6974
+ if (!line || line.startsWith("#")) continue;
6975
+ const normalized = line.startsWith("export ") ? line.slice("export ".length).trim() : line;
6976
+ const equalsIndex = normalized.indexOf("=");
6977
+ if (equalsIndex <= 0) continue;
6978
+ const key = normalized.slice(0, equalsIndex).trim();
6979
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue;
6980
+ env[key] = parseEnvValue(normalized.slice(equalsIndex + 1).trim());
6981
+ }
6982
+ return env;
6983
+ }
6984
+ function parseEnvValue(value) {
6985
+ const quote = value[0];
6986
+ if ((quote === '"' || quote === "'") && value[value.length - 1] === quote) {
6987
+ const inner = value.slice(1, -1);
6988
+ return quote === '"' ? inner.replace(/\\n/g, "\n").replace(/\\r/g, "\r") : inner;
6989
+ }
6990
+ const commentIndex = value.search(/\s#/);
6991
+ return (commentIndex >= 0 ? value.slice(0, commentIndex) : value).trim();
6992
+ }
6699
6993
  function normalizeManagedSyncStore(config, projectRoot) {
6700
6994
  const sync = config?.dev?.sync;
6701
6995
  if (typeof sync !== "object" || sync === null) return null;
6702
6996
  const store = sync.store;
6703
6997
  if (store === void 0) return { type: "memory" };
6704
6998
  if (store === "memory") return { type: "memory" };
6705
- if (store === "sqlite") return { type: "sqlite", filename: (0, import_node_path22.join)(projectRoot, "kora-sync.db") };
6999
+ if (store === "sqlite") return { type: "sqlite", filename: (0, import_node_path23.join)(projectRoot, "kora-sync.db") };
6706
7000
  if (store === "postgres") {
6707
7001
  const connectionString = process.env.DATABASE_URL;
6708
7002
  if (!connectionString) return null;
@@ -6711,7 +7005,7 @@ function normalizeManagedSyncStore(config, projectRoot) {
6711
7005
  if (typeof store === "object" && store !== null) {
6712
7006
  if (store.type === "memory") return { type: "memory" };
6713
7007
  if (store.type === "sqlite") {
6714
- const filename = typeof store.filename === "string" && store.filename.length > 0 ? (0, import_node_path23.resolve)(projectRoot, store.filename) : (0, import_node_path22.join)(projectRoot, "kora-sync.db");
7008
+ const filename = typeof store.filename === "string" && store.filename.length > 0 ? (0, import_node_path24.resolve)(projectRoot, store.filename) : (0, import_node_path23.join)(projectRoot, "kora-sync.db");
6715
7009
  return { type: "sqlite", filename };
6716
7010
  }
6717
7011
  if (store.type === "postgres" && typeof store.connectionString === "string") {
@@ -6775,12 +7069,12 @@ await new Promise(() => {});
6775
7069
  `;
6776
7070
 
6777
7071
  // src/commands/doctor/doctor-command.ts
6778
- var import_citty6 = require("citty");
7072
+ var import_citty7 = require("citty");
6779
7073
  init_fs_helpers();
6780
7074
 
6781
7075
  // src/commands/doctor/doctor-checks.ts
6782
- var import_promises15 = require("fs/promises");
6783
- var import_node_path24 = require("path");
7076
+ var import_promises16 = require("fs/promises");
7077
+ var import_node_path25 = require("path");
6784
7078
  init_fs_helpers();
6785
7079
  init_schema_loader();
6786
7080
  var STATUS_ENDPOINT = "/__kora/status";
@@ -6860,9 +7154,9 @@ async function runDoctorChecks(options) {
6860
7154
  }
6861
7155
  async function resolveSchemaPath(projectRoot, configSchema) {
6862
7156
  if (typeof configSchema === "string") {
6863
- const resolved = (0, import_node_path24.resolve)(projectRoot, configSchema);
7157
+ const resolved = (0, import_node_path25.resolve)(projectRoot, configSchema);
6864
7158
  try {
6865
- await (0, import_promises15.access)(resolved);
7159
+ await (0, import_promises16.access)(resolved);
6866
7160
  return resolved;
6867
7161
  } catch {
6868
7162
  }
@@ -6871,12 +7165,12 @@ async function resolveSchemaPath(projectRoot, configSchema) {
6871
7165
  }
6872
7166
  async function checkWorkerFile(projectRoot) {
6873
7167
  const candidates = [
6874
- (0, import_node_path24.join)(projectRoot, "src", "kora-worker.ts"),
6875
- (0, import_node_path24.join)(projectRoot, "src", "kora-worker.js")
7168
+ (0, import_node_path25.join)(projectRoot, "src", "kora-worker.ts"),
7169
+ (0, import_node_path25.join)(projectRoot, "src", "kora-worker.js")
6876
7170
  ];
6877
7171
  for (const path of candidates) {
6878
7172
  try {
6879
- await (0, import_promises15.access)(path);
7173
+ await (0, import_promises16.access)(path);
6880
7174
  return {
6881
7175
  id: "worker",
6882
7176
  title: "SQLite WASM worker",
@@ -6896,7 +7190,7 @@ async function checkWorkerFile(projectRoot) {
6896
7190
  }
6897
7191
  async function checkDependencies(projectRoot) {
6898
7192
  try {
6899
- const raw = await (0, import_promises15.readFile)((0, import_node_path24.join)(projectRoot, "package.json"), "utf-8");
7193
+ const raw = await (0, import_promises16.readFile)((0, import_node_path25.join)(projectRoot, "package.json"), "utf-8");
6900
7194
  const pkg = JSON.parse(raw);
6901
7195
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
6902
7196
  const hasKora = Boolean(deps.korajs || deps.kora);
@@ -6945,9 +7239,9 @@ async function resolveSyncHttpUrl(projectRoot, config) {
6945
7239
  }
6946
7240
  async function readEnvSyncUrl(projectRoot) {
6947
7241
  for (const file of [".env", ".env.local"]) {
6948
- const path = (0, import_node_path24.join)(projectRoot, file);
7242
+ const path = (0, import_node_path25.join)(projectRoot, file);
6949
7243
  try {
6950
- const content = await (0, import_promises15.readFile)(path, "utf-8");
7244
+ const content = await (0, import_promises16.readFile)(path, "utf-8");
6951
7245
  for (const line of content.split("\n")) {
6952
7246
  const trimmed = line.trim();
6953
7247
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -7038,7 +7332,7 @@ function doctorHasFailures(results) {
7038
7332
  }
7039
7333
 
7040
7334
  // src/commands/doctor/doctor-command.ts
7041
- var doctorCommand = (0, import_citty6.defineCommand)({
7335
+ var doctorCommand = (0, import_citty7.defineCommand)({
7042
7336
  meta: {
7043
7337
  name: "doctor",
7044
7338
  description: "Check Kora project setup (schema, worker, sync server, versions)"
@@ -7093,9 +7387,9 @@ var doctorCommand = (0, import_citty6.defineCommand)({
7093
7387
  });
7094
7388
 
7095
7389
  // src/commands/generate/generate-command.ts
7096
- var import_promises16 = require("fs/promises");
7097
- var import_node_path25 = require("path");
7098
- var import_citty7 = require("citty");
7390
+ var import_promises17 = require("fs/promises");
7391
+ var import_node_path26 = require("path");
7392
+ var import_citty8 = require("citty");
7099
7393
  init_fs_helpers();
7100
7394
  init_schema_loader();
7101
7395
 
@@ -7250,13 +7544,13 @@ function toPascalCase2(name) {
7250
7544
  }
7251
7545
 
7252
7546
  // src/commands/generate/generate-command.ts
7253
- var generateCommand = (0, import_citty7.defineCommand)({
7547
+ var generateCommand = (0, import_citty8.defineCommand)({
7254
7548
  meta: {
7255
7549
  name: "generate",
7256
7550
  description: "Generate code from your Kora schema"
7257
7551
  },
7258
7552
  subCommands: {
7259
- types: (0, import_citty7.defineCommand)({
7553
+ types: (0, import_citty8.defineCommand)({
7260
7554
  meta: {
7261
7555
  name: "types",
7262
7556
  description: "Generate TypeScript types from your schema"
@@ -7280,7 +7574,7 @@ var generateCommand = (0, import_citty7.defineCommand)({
7280
7574
  }
7281
7575
  let schemaPath;
7282
7576
  if (args.schema && typeof args.schema === "string") {
7283
- schemaPath = (0, import_node_path25.resolve)(args.schema);
7577
+ schemaPath = (0, import_node_path26.resolve)(args.schema);
7284
7578
  } else {
7285
7579
  const found = await findSchemaFile(projectRoot);
7286
7580
  if (!found) {
@@ -7303,13 +7597,13 @@ var generateCommand = (0, import_citty7.defineCommand)({
7303
7597
  }
7304
7598
  const output = generateTypes(schema);
7305
7599
  const outputFile = typeof args.output === "string" ? args.output : "kora/generated/types.ts";
7306
- const outputPath = (0, import_node_path25.resolve)(projectRoot, outputFile);
7307
- await (0, import_promises16.mkdir)((0, import_node_path25.dirname)(outputPath), { recursive: true });
7308
- await (0, import_promises16.writeFile)(outputPath, output, "utf-8");
7600
+ const outputPath = (0, import_node_path26.resolve)(projectRoot, outputFile);
7601
+ await (0, import_promises17.mkdir)((0, import_node_path26.dirname)(outputPath), { recursive: true });
7602
+ await (0, import_promises17.writeFile)(outputPath, output, "utf-8");
7309
7603
  logger.success(`Generated types at ${outputPath}`);
7310
7604
  }
7311
7605
  }),
7312
- hooks: (0, import_citty7.defineCommand)({
7606
+ hooks: (0, import_citty8.defineCommand)({
7313
7607
  meta: {
7314
7608
  name: "hooks",
7315
7609
  description: "Generate per-collection React hook stubs"
@@ -7338,7 +7632,7 @@ var generateCommand = (0, import_citty7.defineCommand)({
7338
7632
  }
7339
7633
  let schemaPath;
7340
7634
  if (args.schema && typeof args.schema === "string") {
7341
- schemaPath = (0, import_node_path25.resolve)(projectRoot, args.schema);
7635
+ schemaPath = (0, import_node_path26.resolve)(projectRoot, args.schema);
7342
7636
  } else {
7343
7637
  const found = await findSchemaFile(projectRoot);
7344
7638
  if (!found) {
@@ -7352,13 +7646,13 @@ var generateCommand = (0, import_citty7.defineCommand)({
7352
7646
  schemaPath = found;
7353
7647
  }
7354
7648
  const schema = await loadSchemaDefinition(schemaPath, projectRoot);
7355
- const outputDir = typeof args.output === "string" ? (0, import_node_path25.resolve)(projectRoot, args.output) : (0, import_node_path25.resolve)(projectRoot, "kora/generated/hooks");
7649
+ const outputDir = typeof args.output === "string" ? (0, import_node_path26.resolve)(projectRoot, args.output) : (0, import_node_path26.resolve)(projectRoot, "kora/generated/hooks");
7356
7650
  const files = generateCollectionHooks(schema);
7357
7651
  for (const [name, content] of files) {
7358
7652
  const adjusted = typeof args.types === "string" && args.types !== "../types" ? content.replace("from '../types'", `from '${args.types}'`) : content;
7359
- const filePath = (0, import_node_path25.resolve)(outputDir, name);
7360
- await (0, import_promises16.mkdir)((0, import_node_path25.dirname)(filePath), { recursive: true });
7361
- await (0, import_promises16.writeFile)(filePath, adjusted, "utf-8");
7653
+ const filePath = (0, import_node_path26.resolve)(outputDir, name);
7654
+ await (0, import_promises17.mkdir)((0, import_node_path26.dirname)(filePath), { recursive: true });
7655
+ await (0, import_promises17.writeFile)(filePath, adjusted, "utf-8");
7362
7656
  }
7363
7657
  logger.success(`Generated ${String(files.size)} hook file(s) at ${outputDir}`);
7364
7658
  logger.step("Run `kora generate types` first if ../types is missing.");
@@ -7380,10 +7674,10 @@ function isSchemaDefinition2(value) {
7380
7674
  }
7381
7675
 
7382
7676
  // src/commands/logs/logs-command.ts
7383
- var import_citty8 = require("citty");
7677
+ var import_citty9 = require("citty");
7384
7678
  var DEFAULT_SYNC_PORT2 = 3001;
7385
7679
  var EVENTS_ENDPOINT = "/__kora/events";
7386
- var logsCommand = (0, import_citty8.defineCommand)({
7680
+ var logsCommand = (0, import_citty9.defineCommand)({
7387
7681
  meta: {
7388
7682
  name: "logs",
7389
7683
  description: "Stream real-time events from a Kora sync server"
@@ -7487,9 +7781,9 @@ var logsCommand = (0, import_citty8.defineCommand)({
7487
7781
  });
7488
7782
 
7489
7783
  // src/commands/migrate/migrate-command.ts
7490
- var import_promises17 = require("fs/promises");
7491
- var import_node_path26 = require("path");
7492
- var import_citty9 = require("citty");
7784
+ var import_promises18 = require("fs/promises");
7785
+ var import_node_path27 = require("path");
7786
+ var import_citty10 = require("citty");
7493
7787
  init_fs_helpers();
7494
7788
 
7495
7789
  // src/commands/migrate/migration-generator.ts
@@ -7833,6 +8127,14 @@ function mapFieldType(descriptor) {
7833
8127
  return "INTEGER";
7834
8128
  case "array":
7835
8129
  return "TEXT";
8130
+ case "object":
8131
+ return "TEXT";
8132
+ case "json":
8133
+ return "TEXT";
8134
+ case "blob":
8135
+ return "TEXT";
8136
+ case "secret":
8137
+ return "TEXT";
7836
8138
  case "richtext":
7837
8139
  return "BLOB";
7838
8140
  }
@@ -7848,7 +8150,7 @@ function quoteIdentifier(identifier) {
7848
8150
  if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(identifier)) {
7849
8151
  throw new Error(`Invalid SQL identifier: ${identifier}`);
7850
8152
  }
7851
- return identifier;
8153
+ return `"${identifier}"`;
7852
8154
  }
7853
8155
  function formatChange(change) {
7854
8156
  switch (change.type) {
@@ -8084,7 +8386,7 @@ function generateOperationTransformModule(fromVersion, toVersion) {
8084
8386
  init_schema_loader();
8085
8387
  var SNAPSHOT_PATH = "kora/schema.snapshot.json";
8086
8388
  var MIGRATIONS_DIR = "kora/migrations";
8087
- var migrateCommand = (0, import_citty9.defineCommand)({
8389
+ var migrateCommand = (0, import_citty10.defineCommand)({
8088
8390
  meta: {
8089
8391
  name: "migrate",
8090
8392
  description: "Detect schema changes and generate/apply migrations"
@@ -8126,12 +8428,12 @@ var migrateCommand = (0, import_citty9.defineCommand)({
8126
8428
  throw new InvalidProjectError(process.cwd());
8127
8429
  }
8128
8430
  const config = await loadKoraConfig(projectRoot);
8129
- const resolvedSchemaPath = typeof args.schema === "string" ? (0, import_node_path26.resolve)(projectRoot, args.schema) : typeof config?.schema === "string" ? (0, import_node_path26.resolve)(projectRoot, config.schema) : await findSchemaFile(projectRoot);
8431
+ const resolvedSchemaPath = typeof args.schema === "string" ? (0, import_node_path27.resolve)(projectRoot, args.schema) : typeof config?.schema === "string" ? (0, import_node_path27.resolve)(projectRoot, config.schema) : await findSchemaFile(projectRoot);
8130
8432
  if (!resolvedSchemaPath) {
8131
8433
  throw new SchemaNotFoundError(["src/schema.ts", "schema.ts", "src/schema.js", "schema.js"]);
8132
8434
  }
8133
8435
  const currentSchema = await loadSchemaDefinition(resolvedSchemaPath, projectRoot);
8134
- const snapshotFile = (0, import_node_path26.join)(projectRoot, SNAPSHOT_PATH);
8436
+ const snapshotFile = (0, import_node_path27.join)(projectRoot, SNAPSHOT_PATH);
8135
8437
  const previousSchema = await readSchemaSnapshot(snapshotFile);
8136
8438
  if (!previousSchema) {
8137
8439
  if (args["dry-run"] === true) {
@@ -8144,7 +8446,7 @@ var migrateCommand = (0, import_citty9.defineCommand)({
8144
8446
  return;
8145
8447
  }
8146
8448
  const diff = diffSchemas(previousSchema, currentSchema);
8147
- const outputDir = typeof args["output-dir"] === "string" ? (0, import_node_path26.resolve)(projectRoot, args["output-dir"]) : (0, import_node_path26.resolve)(projectRoot, MIGRATIONS_DIR);
8449
+ const outputDir = typeof args["output-dir"] === "string" ? (0, import_node_path27.resolve)(projectRoot, args["output-dir"]) : (0, import_node_path27.resolve)(projectRoot, MIGRATIONS_DIR);
8148
8450
  if (!diff.hasChanges) {
8149
8451
  logger.success("No schema changes detected.");
8150
8452
  if (args.apply === true) {
@@ -8196,7 +8498,7 @@ var migrateCommand = (0, import_citty9.defineCommand)({
8196
8498
  logger.warn("Dry run enabled: no files written, no migrations applied.");
8197
8499
  return;
8198
8500
  }
8199
- await (0, import_promises17.mkdir)(outputDir, { recursive: true });
8501
+ await (0, import_promises18.mkdir)(outputDir, { recursive: true });
8200
8502
  const migrationPath = await writeMigrationFile(
8201
8503
  outputDir,
8202
8504
  diff.fromVersion,
@@ -8232,7 +8534,7 @@ var migrateCommand = (0, import_citty9.defineCommand)({
8232
8534
  });
8233
8535
  async function readSchemaSnapshot(path) {
8234
8536
  try {
8235
- const content = await (0, import_promises17.readFile)(path, "utf-8");
8537
+ const content = await (0, import_promises18.readFile)(path, "utf-8");
8236
8538
  return JSON.parse(content);
8237
8539
  } catch {
8238
8540
  return null;
@@ -8253,15 +8555,15 @@ function isInteractiveTerminal2() {
8253
8555
  return process.stdin.isTTY === true && process.stdout.isTTY === true;
8254
8556
  }
8255
8557
  async function writeSchemaSnapshot(path, schema) {
8256
- await (0, import_promises17.mkdir)((0, import_node_path26.dirname)(path), { recursive: true });
8257
- await (0, import_promises17.writeFile)(path, `${JSON.stringify(schema, null, 2)}
8558
+ await (0, import_promises18.mkdir)((0, import_node_path27.dirname)(path), { recursive: true });
8559
+ await (0, import_promises18.writeFile)(path, `${JSON.stringify(schema, null, 2)}
8258
8560
  `, "utf-8");
8259
8561
  }
8260
8562
  async function writeMigrationFile(outputDir, fromVersion, toVersion, generated) {
8261
- const existing = await (0, import_promises17.readdir)(outputDir).catch(() => []);
8563
+ const existing = await (0, import_promises18.readdir)(outputDir).catch(() => []);
8262
8564
  const sequence = existing.filter((file) => /^\d{3}-/.test(file)).length + 1;
8263
8565
  const filename = `${String(sequence).padStart(3, "0")}-v${fromVersion}-to-v${toVersion}.ts`;
8264
- const path = (0, import_node_path26.join)(outputDir, filename);
8566
+ const path = (0, import_node_path27.join)(outputDir, filename);
8265
8567
  const migrationId = filename.replace(/\.ts$/, "");
8266
8568
  const fileContent = [
8267
8569
  `export const up = ${JSON.stringify(generated.up, null, 2)} as const`,
@@ -8273,10 +8575,10 @@ async function writeMigrationFile(outputDir, fromVersion, toVersion, generated)
8273
8575
  `export const containsBreakingChanges = ${generated.containsBreakingChanges}`,
8274
8576
  ""
8275
8577
  ].join("\n");
8276
- await (0, import_promises17.writeFile)(path, fileContent, "utf-8");
8277
- const transformsPath = (0, import_node_path26.join)(outputDir, `${migrationId}.transforms.ts`);
8278
- await (0, import_promises17.writeFile)(transformsPath, generateOperationTransformModule(fromVersion, toVersion), "utf-8");
8279
- await writeMigrationManifest((0, import_node_path26.join)(outputDir, `${migrationId}.json`), {
8578
+ await (0, import_promises18.writeFile)(path, fileContent, "utf-8");
8579
+ const transformsPath = (0, import_node_path27.join)(outputDir, `${migrationId}.transforms.ts`);
8580
+ await (0, import_promises18.writeFile)(transformsPath, generateOperationTransformModule(fromVersion, toVersion), "utf-8");
8581
+ await writeMigrationManifest((0, import_node_path27.join)(outputDir, `${migrationId}.json`), {
8280
8582
  id: migrationId,
8281
8583
  fromVersion,
8282
8584
  toVersion,
@@ -8288,22 +8590,22 @@ async function writeMigrationFile(outputDir, fromVersion, toVersion, generated)
8288
8590
  return path;
8289
8591
  }
8290
8592
  async function writeMigrationManifest(path, manifest) {
8291
- await (0, import_promises17.writeFile)(path, `${JSON.stringify(manifest, null, 2)}
8593
+ await (0, import_promises18.writeFile)(path, `${JSON.stringify(manifest, null, 2)}
8292
8594
  `, "utf-8");
8293
8595
  }
8294
8596
  async function listMigrationManifests(outputDir) {
8295
- const files = await (0, import_promises17.readdir)(outputDir).catch(() => []);
8597
+ const files = await (0, import_promises18.readdir)(outputDir).catch(() => []);
8296
8598
  const migrationFiles = files.filter((file) => /^\d{3}-.*\.ts$/.test(file)).sort((left, right) => left.localeCompare(right));
8297
8599
  const manifests = [];
8298
8600
  for (const file of migrationFiles) {
8299
8601
  const id = file.replace(/\.ts$/, "");
8300
- const manifestPath = (0, import_node_path26.join)(outputDir, `${id}.json`);
8602
+ const manifestPath = (0, import_node_path27.join)(outputDir, `${id}.json`);
8301
8603
  const jsonManifest = await readMigrationManifest(manifestPath);
8302
8604
  if (jsonManifest) {
8303
8605
  manifests.push({ ...jsonManifest, id });
8304
8606
  continue;
8305
8607
  }
8306
- const migrationPath = (0, import_node_path26.join)(outputDir, file);
8608
+ const migrationPath = (0, import_node_path27.join)(outputDir, file);
8307
8609
  const sourceManifest = await readMigrationManifestFromSource(migrationPath, id);
8308
8610
  manifests.push(sourceManifest);
8309
8611
  }
@@ -8311,7 +8613,7 @@ async function listMigrationManifests(outputDir) {
8311
8613
  }
8312
8614
  async function readMigrationManifest(path) {
8313
8615
  try {
8314
- const content = await (0, import_promises17.readFile)(path, "utf-8");
8616
+ const content = await (0, import_promises18.readFile)(path, "utf-8");
8315
8617
  return JSON.parse(content);
8316
8618
  } catch (error) {
8317
8619
  const code = error.code;
@@ -8322,7 +8624,7 @@ async function readMigrationManifest(path) {
8322
8624
  }
8323
8625
  }
8324
8626
  async function readMigrationManifestFromSource(path, id) {
8325
- const content = await (0, import_promises17.readFile)(path, "utf-8");
8627
+ const content = await (0, import_promises18.readFile)(path, "utf-8");
8326
8628
  const versions = parseVersionsFromMigrationId(id);
8327
8629
  return {
8328
8630
  id,
@@ -8384,18 +8686,18 @@ function parseLiteralExport(source, exportName) {
8384
8686
  }
8385
8687
  function resolveSqliteApplyPath(dbArg, projectRoot, config) {
8386
8688
  if (typeof dbArg === "string") {
8387
- return (0, import_node_path26.resolve)(projectRoot, dbArg);
8689
+ return (0, import_node_path27.resolve)(projectRoot, dbArg);
8388
8690
  }
8389
8691
  const sync = config?.dev?.sync;
8390
8692
  if (typeof sync === "object" && sync !== null) {
8391
8693
  if (sync.store === "sqlite") {
8392
- return (0, import_node_path26.join)(projectRoot, "kora-sync.db");
8694
+ return (0, import_node_path27.join)(projectRoot, "kora-sync.db");
8393
8695
  }
8394
8696
  if (typeof sync.store === "object" && sync.store !== null && sync.store.type === "sqlite") {
8395
8697
  if (typeof sync.store.filename === "string" && sync.store.filename.length > 0) {
8396
- return (0, import_node_path26.resolve)(projectRoot, sync.store.filename);
8698
+ return (0, import_node_path27.resolve)(projectRoot, sync.store.filename);
8397
8699
  }
8398
- return (0, import_node_path26.join)(projectRoot, "kora-sync.db");
8700
+ return (0, import_node_path27.join)(projectRoot, "kora-sync.db");
8399
8701
  }
8400
8702
  }
8401
8703
  return void 0;
@@ -8413,7 +8715,7 @@ function resolvePostgresConnectionString(config) {
8413
8715
  }
8414
8716
 
8415
8717
  // src/commands/status/status-command.ts
8416
- var import_citty10 = require("citty");
8718
+ var import_citty11 = require("citty");
8417
8719
  var DEFAULT_SYNC_PORT3 = 3001;
8418
8720
  var STATUS_ENDPOINT2 = "/__kora/status";
8419
8721
  async function fetchServerStatus(url, token) {
@@ -8440,7 +8742,7 @@ function formatUptime(ms) {
8440
8742
  parts.push(`${seconds % 60}s`);
8441
8743
  return parts.join(" ");
8442
8744
  }
8443
- var statusCommand = (0, import_citty10.defineCommand)({
8745
+ var statusCommand = (0, import_citty11.defineCommand)({
8444
8746
  meta: {
8445
8747
  name: "status",
8446
8748
  description: "Show Kora sync server status"
@@ -8545,10 +8847,10 @@ function printStatus(status, url, logger) {
8545
8847
  }
8546
8848
 
8547
8849
  // src/commands/studio/studio-command.ts
8548
- var import_node_fs8 = require("fs");
8549
- var import_node_path29 = require("path");
8550
- var import_citty11 = require("citty");
8551
- var studioCommand = (0, import_citty11.defineCommand)({
8850
+ var import_node_fs9 = require("fs");
8851
+ var import_node_path30 = require("path");
8852
+ var import_citty12 = require("citty");
8853
+ var studioCommand = (0, import_citty12.defineCommand)({
8552
8854
  meta: {
8553
8855
  name: "studio",
8554
8856
  description: "Kora Studio: visualize records, operations, and sync \u2014 or run the sync lab"
@@ -8597,7 +8899,7 @@ var studioCommand = (0, import_citty11.defineCommand)({
8597
8899
  );
8598
8900
  }
8599
8901
  const { loadSchemaDefinition: loadSchemaDefinition2 } = await Promise.resolve().then(() => (init_schema_loader(), schema_loader_exports));
8600
- const schema = await loadSchemaDefinition2((0, import_node_path29.resolve)(process.cwd(), args.schema), process.cwd());
8902
+ const schema = await loadSchemaDefinition2((0, import_node_path30.resolve)(process.cwd(), args.schema), process.cwd());
8601
8903
  const { SpectatorManager: SpectatorManager2 } = await Promise.resolve().then(() => (init_spectator_manager(), spectator_manager_exports));
8602
8904
  const spectator = new SpectatorManager2({
8603
8905
  url: args.connect,
@@ -8624,7 +8926,7 @@ var studioCommand = (0, import_citty11.defineCommand)({
8624
8926
  let schema = defaultLabSchema2();
8625
8927
  if (typeof args.schema === "string") {
8626
8928
  const { loadSchemaDefinition: loadSchemaDefinition2 } = await Promise.resolve().then(() => (init_schema_loader(), schema_loader_exports));
8627
- schema = await loadSchemaDefinition2((0, import_node_path29.resolve)(process.cwd(), args.schema), process.cwd());
8929
+ schema = await loadSchemaDefinition2((0, import_node_path30.resolve)(process.cwd(), args.schema), process.cwd());
8628
8930
  }
8629
8931
  const initialDevices = args.devices !== void 0 ? Math.max(1, Number.parseInt(args.devices, 10) || 2) : 2;
8630
8932
  const lab = new LabManager2(schema);
@@ -8649,8 +8951,8 @@ var studioCommand = (0, import_citty11.defineCommand)({
8649
8951
  "Pass --db <path> to inspect a database, --lab for the sync laboratory, or --connect <wss url> for live spectator mode."
8650
8952
  );
8651
8953
  }
8652
- const dbPath = (0, import_node_path29.resolve)(process.cwd(), args.db);
8653
- if (!(0, import_node_fs8.existsSync)(dbPath)) {
8954
+ const dbPath = (0, import_node_path30.resolve)(process.cwd(), args.db);
8955
+ if (!(0, import_node_fs9.existsSync)(dbPath)) {
8654
8956
  throw new Error(`Database file not found: ${dbPath}`);
8655
8957
  }
8656
8958
  const server = await startStudioServer2({ port, dbPath });
@@ -8668,12 +8970,13 @@ var studioCommand = (0, import_citty11.defineCommand)({
8668
8970
  });
8669
8971
 
8670
8972
  // src/bin.ts
8671
- var main = (0, import_citty12.defineCommand)({
8973
+ var main = (0, import_citty13.defineCommand)({
8672
8974
  meta: {
8673
8975
  name: "kora",
8674
- description: "Kora.js \u2014 Offline-first application framework"
8976
+ description: "Kora.js, the offline-first application framework"
8675
8977
  },
8676
8978
  subCommands: {
8979
+ "agents-md": agentsCommand,
8677
8980
  backup: backupCommand,
8678
8981
  compact: compactCommand,
8679
8982
  create: createCommand,
@@ -8687,5 +8990,5 @@ var main = (0, import_citty12.defineCommand)({
8687
8990
  studio: studioCommand
8688
8991
  }
8689
8992
  });
8690
- (0, import_citty12.runMain)(main);
8993
+ (0, import_citty13.runMain)(main);
8691
8994
  //# sourceMappingURL=bin.cjs.map