makersclaw 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +48 -8
  2. package/package.json +1 -1
  3. package/r/annotate.json +4 -4
  4. package/r/approval-request.json +3 -3
  5. package/r/audio-player.json +3 -3
  6. package/r/auth-form.json +2 -2
  7. package/r/board.json +4 -4
  8. package/r/calendar-view.json +4 -4
  9. package/r/cart.json +3 -3
  10. package/r/chart.json +3 -3
  11. package/r/chat.json +3 -3
  12. package/r/code-editor.json +4 -4
  13. package/r/comment-box.json +4 -4
  14. package/r/contact-section.json +3 -3
  15. package/r/core.json +3 -3
  16. package/r/csv-import.json +4 -4
  17. package/r/data-table.json +3 -3
  18. package/r/diagram.json +3 -3
  19. package/r/doc-editor.json +4 -4
  20. package/r/doc-page.json +4 -4
  21. package/r/email-render.json +2 -2
  22. package/r/faq.json +2 -2
  23. package/r/file-upload.json +3 -3
  24. package/r/flow-canvas.json +4 -4
  25. package/r/footer.json +3 -3
  26. package/r/gantt.json +4 -4
  27. package/r/job-panel.json +3 -3
  28. package/r/json-editor.json +4 -4
  29. package/r/map.json +5 -5
  30. package/r/menubar.json +2 -2
  31. package/r/mind-map.json +4 -4
  32. package/r/navigation-menu.json +2 -2
  33. package/r/order-detail.json +2 -2
  34. package/r/org-chart.json +4 -4
  35. package/r/page-builder.json +6 -6
  36. package/r/payment-methods.json +2 -2
  37. package/r/pdf-document.json +2 -2
  38. package/r/pdf-viewer.json +6 -6
  39. package/r/product-detail.json +3 -3
  40. package/r/product-grid.json +4 -4
  41. package/r/record-form.json +3 -3
  42. package/r/record-notes.json +5 -5
  43. package/r/registry.json +121 -121
  44. package/r/search-dialog.json +3 -3
  45. package/r/settings-list.json +3 -3
  46. package/r/setup-checklist.json +3 -3
  47. package/r/share-dialog.json +3 -3
  48. package/r/sidebar.json +2 -2
  49. package/r/signature-pad.json +3 -3
  50. package/r/sketch-canvas.json +5 -5
  51. package/r/spreadsheet.json +3 -3
  52. package/r/stat-cards.json +4 -4
  53. package/r/task-list.json +4 -4
  54. package/r/task-model.json +3 -3
  55. package/r/testimonials.json +2 -2
  56. package/r/transaction-list.json +3 -3
  57. package/r/whiteboard.json +4 -4
  58. package/registry/blocks/annotate/README.md +14 -5
  59. package/registry/blocks/approval-request/README.md +15 -8
  60. package/registry/blocks/audio-player/README.md +17 -10
  61. package/registry/blocks/board/README.md +13 -9
  62. package/registry/blocks/board/board.jsx +1 -1
  63. package/registry/blocks/calendar-view/README.md +28 -4
  64. package/registry/blocks/cart/README.md +14 -10
  65. package/registry/blocks/chart/README.md +14 -7
  66. package/registry/blocks/chat/README.md +43 -13
  67. package/registry/blocks/code-editor/README.md +4 -0
  68. package/registry/blocks/code-editor/code-editor.jsx +1 -1
  69. package/registry/blocks/comment-box/README.md +20 -13
  70. package/registry/blocks/contact-section/README.md +7 -6
  71. package/registry/blocks/csv-import/README.md +34 -12
  72. package/registry/blocks/data-table/README.md +41 -8
  73. package/registry/blocks/diagram/diagram.jsx +1 -1
  74. package/registry/blocks/doc-editor/README.md +18 -6
  75. package/registry/blocks/doc-editor/doc-editor.jsx +1 -1
  76. package/registry/blocks/doc-page/README.md +16 -6
  77. package/registry/blocks/file-upload/README.md +7 -1
  78. package/registry/blocks/flow-canvas/README.md +16 -5
  79. package/registry/blocks/flow-canvas/flow-canvas.jsx +1 -1
  80. package/registry/blocks/footer/README.md +4 -2
  81. package/registry/blocks/gantt/README.md +18 -12
  82. package/registry/blocks/job-panel/README.md +1 -1
  83. package/registry/blocks/json-editor/README.md +16 -4
  84. package/registry/blocks/map/README.md +19 -3
  85. package/registry/blocks/map/map-view.jsx +1 -1
  86. package/registry/blocks/map/maplibre.js +1 -1
  87. package/registry/blocks/mind-map/README.md +16 -5
  88. package/registry/blocks/org-chart/README.md +10 -7
  89. package/registry/blocks/page-builder/README.md +13 -6
  90. package/registry/blocks/page-builder/page-builder.jsx +1 -1
  91. package/registry/blocks/page-builder/page-view.jsx +1 -1
  92. package/registry/blocks/page-builder/page.js +1 -1
  93. package/registry/blocks/pdf-viewer/README.md +22 -20
  94. package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1 -1
  95. package/registry/blocks/pdf-viewer/pdfjs.js +1 -1
  96. package/registry/blocks/pdf-viewer/ssr-shim.js +1 -1
  97. package/registry/blocks/product-detail/README.md +13 -7
  98. package/registry/blocks/product-detail/demo.jsx +1 -1
  99. package/registry/blocks/product-grid/README.md +12 -10
  100. package/registry/blocks/record-form/README.md +26 -9
  101. package/registry/blocks/record-notes/README.md +42 -30
  102. package/registry/blocks/search-dialog/README.md +38 -7
  103. package/registry/blocks/settings-list/README.md +29 -17
  104. package/registry/blocks/setup-checklist/README.md +12 -14
  105. package/registry/blocks/share-dialog/README.md +1 -1
  106. package/registry/blocks/signature-pad/README.md +15 -4
  107. package/registry/blocks/sketch-canvas/README.md +13 -4
  108. package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1 -1
  109. package/registry/blocks/sketch-canvas/ssr-shim.js +3 -3
  110. package/registry/blocks/spreadsheet/README.md +17 -8
  111. package/registry/blocks/stat-cards/README.md +17 -8
  112. package/registry/blocks/task-list/README.md +14 -11
  113. package/registry/blocks/task-model/README.md +3 -3
  114. package/registry/blocks/transaction-list/README.md +15 -7
  115. package/registry/blocks/whiteboard/README.md +19 -13
  116. package/src/cli.mjs +31 -4
  117. package/src/install.mjs +263 -21
  118. package/src/registry.mjs +78 -1
  119. package/templates/next/browser/app/auto-refresh.jsx +67 -0
  120. package/templates/next/browser/app/layout.jsx +94 -0
  121. package/templates/next/browser/app/page.jsx +60 -0
  122. package/templates/next/browser/app/s/[key]/page.jsx +95 -0
  123. package/templates/next/browser/lib/actions.js +16 -0
  124. package/templates/next/browser/lib/data.js +43 -0
  125. package/templates/next/files/README.md +810 -79
  126. package/templates/next/files/app/frame.js +128 -4
  127. package/templates/next/files/check/run.mjs +1438 -41
  128. package/templates/next/files/components/ui/item.jsx +2 -2
  129. package/templates/next/files/components/ui/notice.jsx +1 -1
  130. package/templates/next/files/components/ui/separator.jsx +1 -1
  131. package/templates/next/files/lib/actions.js +170 -51
  132. package/templates/next/files/lib/brain-server.js +96 -0
  133. package/templates/next/files/lib/brain.js +413 -0
  134. package/templates/next/files/lib/claw.js +11 -0
  135. package/templates/next/files/lib/data.js +119 -29
  136. package/templates/next/files/lib/db.js +97 -17
  137. package/templates/next/files/lib/door.js +680 -0
  138. package/templates/next/files/next.config.mjs +36 -2
  139. package/templates/next/files/surfaces.js +3 -2
  140. package/templates/next/template.json +9 -3
  141. package/templates/next/files/schema.sql +0 -22
@@ -125,27 +125,34 @@ States
125
125
  ## Example
126
126
 
127
127
  ```jsx
128
- // components/Overview.jsx — client: the numbers the server read
128
+ // surfaces/overview.jsx — client: the numbers, read in the browser
129
129
  "use client";
130
- import { StatCards } from "./blocks/stat-cards";
130
+ import { useRows } from "../lib/data";
131
131
  import { updateRow } from "../lib/actions";
132
+ import { StatCards } from "../components/blocks/stat-cards";
132
133
 
133
- export default function Overview({ kpis, usage }) {
134
+ export default function Overview() {
135
+ const summary = useRows({ source: "kpi_summary", limit: 1 }); // a view of the app's: this week's numbers, one row
136
+ const usage = useRows({ source: "quotas", orderBy: "name asc" });
137
+ const kpis = summary.rows[0] ?? {};
134
138
  return (
135
139
  <div className="grid gap-6">
136
140
  <StatCards
141
+ loading={summary.loading}
142
+ error={summary.error}
137
143
  items={[
138
- { id: "mrr", label: "MRR", value: kpis.mrr, delta: kpis.mrrChange, trend: kpis.mrrWeeks, href: "/revenue" },
139
- { id: "churn", label: "Logo churn", value: kpis.churn, delta: kpis.churnChange, invert: true },
140
- { id: "trials", label: "Active trials", value: kpis.trials, previous: kpis.trialsLastWeek, delta: kpis.trialsChange },
144
+ { id: "mrr", label: "MRR", value: kpis.mrr, delta: kpis.mrr_change, trend: kpis.mrr_weeks, href: "/s/revenue" },
145
+ { id: "churn", label: "Logo churn", value: kpis.churn, delta: kpis.churn_change, invert: true },
146
+ { id: "trials", label: "Active trials", value: kpis.trials, previous: kpis.trials_last_week, delta: kpis.trials_change },
141
147
  ]}
142
148
  variant="cards"
143
149
  />
144
150
  <StatCards
145
151
  variant="usage"
146
152
  title="Plan usage"
147
- items={usage.map((u) => ({ id: u.id, label: u.name, used: u.used, limit: u.limit, unit: u.unit }))}
148
- onLimitChange={(item, limit) => updateRow({ source: "public.quotas", id: item.id, patch: { limit } })}
153
+ loading={usage.loading}
154
+ items={usage.rows.map((u) => ({ id: u.id, label: u.name, used: u.used, limit: u.limit, unit: u.unit }))}
155
+ onLimitChange={(item, limit) => updateRow({ source: "quotas", id: item.id, patch: { limit } })}
149
156
  limitLabel="Change budget"
150
157
  />
151
158
  </div>
@@ -153,6 +160,8 @@ export default function Overview({ kpis, usage }) {
153
160
  }
154
161
  ```
155
162
 
163
+ In a server-mode app the same calls are `loadRows` in a server surface and the Server Actions of `lib/actions`.
164
+
156
165
  ## What it will not do
157
166
 
158
167
  - Fetch or compute: numbers come in formatted, changes already worked out.
@@ -98,14 +98,15 @@ drag-to-reorder saves; tasks without one keep the order given.
98
98
  ## Example
99
99
 
100
100
  ```jsx
101
- // surfaces/tasks.jsx — server: load, hand over
102
- import { loadRows } from "../lib/data";
101
+ // surfaces/tasks.jsx — client: read, hand over
102
+ "use client";
103
+ import { useRows } from "../lib/data";
103
104
  import Tasks from "../components/Tasks";
104
105
 
105
- export default async function TasksSurface() {
106
- const { rows, error } = await loadRows({ source: "public.tasks", orderBy: "created_at asc" });
107
- const people = await loadRows({ source: "public.people" });
108
- return <Tasks tasks={rows} people={people.rows} error={error} />;
106
+ export default function TasksSurface() {
107
+ const tasks = useRows({ source: "tasks", orderBy: "created_at asc" });
108
+ const people = useRows({ source: "people" });
109
+ return <Tasks tasks={tasks.rows} people={people.rows} loading={tasks.loading || people.loading} error={tasks.error} />;
109
110
  }
110
111
  ```
111
112
 
@@ -132,19 +133,19 @@ const COLUMNS = ["id", "title", "status", "assignees", "due", "priority", "tags"
132
133
  async function save(change) {
133
134
  for (const w of changeWrites(change, { columns: COLUMNS, keepNewIds: false })) {
134
135
  const r =
135
- w.op === "insert" ? await insertRow({ source: "public.tasks", values: w.values, detail: w.values.title })
136
- : w.op === "update" ? await updateRow({ source: "public.tasks", id: w.id, patch: w.patch })
137
- : await deleteRow({ source: "public.tasks", id: w.id });
136
+ w.op === "insert" ? await insertRow({ source: "tasks", values: w.values, detail: w.values.title })
137
+ : w.op === "update" ? await updateRow({ source: "tasks", id: w.id, patch: w.patch })
138
+ : await deleteRow({ source: "tasks", id: w.id });
138
139
  if (r?.ok === false) return r;
139
140
  }
140
141
  return { ok: true };
141
142
  }
142
143
 
143
- export default function Tasks({ tasks, people, error }) {
144
+ export default function Tasks({ tasks, people, loading, error }) {
144
145
  const [open, setOpen] = useState(null);
145
146
  return (
146
147
  <>
147
- <TaskList tasks={tasks} statuses={STATUSES} people={people} onChange={save} onOpen={setOpen} error={error}
148
+ <TaskList tasks={tasks} statuses={STATUSES} people={people} onChange={save} onOpen={setOpen} loading={loading} error={error}
148
149
  starters={[{ label: "Weekly planning", tasks: [{ title: "Review last week" }, { title: "Pick three priorities" }] }]} />
149
150
  <Sheet open={Boolean(open)} onClose={() => setOpen(null)} title={open?.title}>{/* the task's fields */}</Sheet>
150
151
  </>
@@ -152,6 +153,8 @@ export default function Tasks({ tasks, people, error }) {
152
153
  }
153
154
  ```
154
155
 
156
+ In a server-mode app the same calls are `loadRows` in a server surface and the Server Actions of `lib/actions`.
157
+
155
158
  Grouped by person, only open work, showing the project:
156
159
 
157
160
  ```jsx
@@ -113,9 +113,9 @@ const COLUMNS = ["id", "title", "status", "assignees", "due", "priority", "paren
113
113
 
114
114
  async function onChange(change) {
115
115
  for (const w of changeWrites(change, { columns: COLUMNS, keepNewIds: false })) {
116
- const r = w.op === "insert" ? await insertRow({ source: "public.tasks", values: w.values })
117
- : w.op === "update" ? await updateRow({ source: "public.tasks", id: w.id, patch: w.patch })
118
- : await deleteRow({ source: "public.tasks", id: w.id });
116
+ const r = w.op === "insert" ? await insertRow({ source: "tasks", values: w.values })
117
+ : w.op === "update" ? await updateRow({ source: "tasks", id: w.id, patch: w.patch })
118
+ : await deleteRow({ source: "tasks", id: w.id });
119
119
  if (r.ok === false) return r;
120
120
  }
121
121
  return { ok: true };
@@ -79,22 +79,28 @@ An invoice row:
79
79
  ## Example
80
80
 
81
81
  ```jsx
82
- // components/Billing.jsx — client
82
+ // surfaces/billing.jsx — client: invoices and payments
83
83
  "use client";
84
- import { TransactionList } from "./blocks/transaction-list";
84
+ import { useRows } from "../lib/data";
85
+ import { TransactionList } from "../components/blocks/transaction-list";
85
86
 
86
- export default function Billing({ invoices, payments, error }) {
87
+ export default function Billing() {
88
+ const invoices = useRows({ source: "invoices", orderBy: "date desc" });
89
+ const payments = useRows({ source: "payments", orderBy: "date desc" });
87
90
  return (
88
91
  <div className="grid gap-6 lg:grid-cols-2">
89
92
  <TransactionList
90
93
  variant="invoices"
91
- rows={invoices}
92
- error={error}
94
+ rows={invoices.rows}
95
+ loading={invoices.loading}
96
+ error={invoices.error}
93
97
  description="Every invoice we have sent you."
94
- downloadHref={(inv) => inv.pdfUrl}
98
+ downloadHref={(inv) => inv.pdf_url}
95
99
  />
96
100
  <TransactionList
97
- rows={payments}
101
+ rows={payments.rows}
102
+ loading={payments.loading}
103
+ error={payments.error}
98
104
  dateFilter
99
105
  description="Money in and out of the account."
100
106
  onExport={async (rows) => {
@@ -109,6 +115,8 @@ export default function Billing({ invoices, payments, error }) {
109
115
  }
110
116
  ```
111
117
 
118
+ In a server-mode app the same calls are `loadRows` in a server surface and the Server Actions of `lib/actions`.
119
+
112
120
  ## What it will not do
113
121
 
114
122
  - Sort, page, or filter by column: rows come in ordered, and a record set
@@ -113,39 +113,45 @@ reuse them:
113
113
  A board page that saves itself:
114
114
 
115
115
  ```jsx
116
+ // surfaces/board.jsx — client: one board, saved as it changes
116
117
  "use client";
117
- import { useState } from "react";
118
- import { Whiteboard } from "./blocks/whiteboard";
119
- import { sketchToText } from "./blocks/sketch-canvas";
118
+ import { useSearchParams } from "next/navigation";
119
+ import { useRow, whenLanded } from "../lib/data";
120
120
  import { updateRow } from "../lib/actions";
121
+ import { Whiteboard } from "../components/blocks/whiteboard";
122
+ import { sketchToText } from "../components/blocks/sketch-canvas";
121
123
 
122
- export default function BoardPage({ board, onShare }) {
123
- const [title, setTitle] = useState(board.title);
124
+ export default function BoardPage() {
125
+ const id = useSearchParams().get("row");
126
+ const { row: board, loading } = useRow({ source: "boards", id });
127
+ if (loading || !board) return null;
124
128
  return (
125
129
  <Whiteboard
126
- title={title}
130
+ key={board.id}
131
+ title={board.title}
127
132
  onRename={async (next) => {
128
- const res = await updateRow({ source: "public.boards", id: board.id, patch: { title: next } });
129
- if (res.ok) setTitle(next);
133
+ const res = await updateRow({ source: "boards", id: board.id, patch: { title: next } });
134
+ if (res.ok) await whenLanded(); // the board is read again: the title is the new one
130
135
  return res;
131
136
  }}
132
- defaultValue={board.sketch} // jsonb, may be null
133
- onSave={(sketch) => updateRow({ source: "public.boards", id: board.id, patch: { sketch, sketch_text: sketchToText(sketch) } })}
134
- onShare={onShare}
137
+ defaultValue={board.sketch} // jsonb, may be null; read once per board
138
+ onSave={(sketch) => updateRow({ source: "boards", id: board.id, patch: { sketch, sketch_text: sketchToText(sketch) } })}
135
139
  className="h-dvh rounded-none border-0"
136
140
  />
137
141
  );
138
142
  }
139
143
  ```
140
144
 
145
+ In a server-mode app the same calls are `loadRows` in a server surface and the Server Actions of `lib/actions`.
146
+
141
147
  Notes that become tasks (a `tasks` table of your own):
142
148
 
143
149
  ```jsx
144
150
  <Whiteboard
145
151
  defaultValue={board.sketch}
146
152
  onSave={save}
147
- onCreateTask={({ title, sourceIds }) => insertRow({ source: "public.tasks", values: { title, board_id: board.id, source_ids: sourceIds } })}
148
- onOpenTask={(task) => router.push(`/tasks/${task.id}`)}
153
+ onCreateTask={({ title, sourceIds }) => insertRow({ source: "tasks", values: { title, board_id: board.id, source_ids: sourceIds } })}
154
+ onOpenTask={(task) => router.push(`/s/tasks?row=${task.id}`)}
149
155
  />
150
156
  ```
151
157
 
package/src/cli.mjs CHANGED
@@ -4,7 +4,7 @@
4
4
  // --json is the same result as one object, for the platform.
5
5
 
6
6
  import { delimiter, resolve } from "node:path";
7
- import { CliError, add, diff, init, install, remove, update } from "./install.mjs";
7
+ import { CliError, add, diff, init, install, mode, remove, update } from "./install.mjs";
8
8
  import { loadItems, loadTemplate, packageInfo, readmeOf, searchItems, suggest, templateNames, useExtraBlockRoots } from "./registry.mjs";
9
9
 
10
10
  const COMMANDS = {
@@ -23,6 +23,7 @@ const COMMANDS = {
23
23
  upgrade: "update",
24
24
  install: "install",
25
25
  i: "install",
26
+ mode: "mode",
26
27
  help: "help",
27
28
  };
28
29
 
@@ -32,6 +33,8 @@ const VALUE_FLAGS = new Map([
32
33
  ["--template", "template"],
33
34
  ["--type", "type"],
34
35
  ["--limit", "limit"],
36
+ ["--tables", "tables"],
37
+ ["--mode", "mode"],
35
38
  ]);
36
39
  const BOOL_FLAGS = new Map([
37
40
  ["--json", "json"],
@@ -76,6 +79,8 @@ function helpText() {
76
79
  return `makersclaw ${version} — the Makersclaw app template, its kit and its blocks
77
80
 
78
81
  npx makersclaw init [dir] [-t next] lay the template: base files, the kit, the check
82
+ [--tables own|public] where its tables live (new apps: own; never changes an app's)
83
+ [--mode browser|server] its mode (new apps: server; browser writes tables own too)
79
84
  npx makersclaw add <name...> install blocks, or restore a kit component
80
85
  npx makersclaw search <words...> find blocks and components by what they do
81
86
  npx makersclaw view <name> one item: props, data, an example
@@ -85,6 +90,7 @@ function helpText() {
85
90
  npx makersclaw update [--major] lay this version's fixed files and blocks
86
91
  [--adopt] …or take on an app laid before makersclaw (kit era)
87
92
  npx makersclaw install the app's packages: pnpm, from pnpm-lock.yaml
93
+ npx makersclaw mode <browser|server> switch the app's mode: its fixed files, and what its code must change
88
94
 
89
95
  --cwd <dir> the app (default: this folder) --json one JSON object
90
96
  --force init over an app that exists (your own files stay)
@@ -127,7 +133,7 @@ function layText(r, verb) {
127
133
  if (r.blocks.length) lines.push(` blocks: ${r.blocks.join(", ")}`);
128
134
  lines.push(...packageLines(r.package));
129
135
  lines.push(...lockLine(r.lock, r.written.includes("pnpm-lock.yaml")));
130
- lines.push(` ${plural(r.pinned, "fixed file")} pinned in check/pins.json · makersclaw.json records ${r.version}`);
136
+ lines.push(` ${plural(r.pinned, "fixed file")} pinned in check/pins.json · makersclaw.json records ${r.version}, tables ${r.tables}, mode ${r.mode}`);
131
137
  for (const n of r.notes) lines.push(` note: ${n}`);
132
138
  const next = [];
133
139
  if (r.install) next.push("npx makersclaw install");
@@ -200,8 +206,25 @@ function listText(items) {
200
206
  return lines.join("\n");
201
207
  }
202
208
 
209
+ function modeText(r) {
210
+ const lines = [
211
+ r.changed
212
+ ? `makersclaw ${r.version} · template ${r.template} · mode ${r.was} → ${r.mode}`
213
+ : `makersclaw ${r.version} · template ${r.template} · already ${r.mode}: its fixed files laid again`,
214
+ ];
215
+ if (r.written.length) lines.push(` wrote ${plural(r.written.length, "file")}: ${listLine(r.written)}`);
216
+ if (r.removed.length) lines.push(` removed (${r.mode} mode lays none): ${listLine(r.removed)}`);
217
+ lines.push(...packageLines(r.package));
218
+ lines.push(` ${plural(r.pinned, "fixed file")} pinned in check/pins.json · makersclaw.json records mode ${r.mode}`);
219
+ for (const n of r.notes) lines.push(` note: ${n}`);
220
+ lines.push(`the app's own code${r.changed ? " must change" : ", in this mode"}:`);
221
+ for (const c of r.change) lines.push(` - ${c}`);
222
+ lines.push(`next: ${[...(r.install ? ["npx makersclaw install"] : []), "npm run check"].join(" · ")}`);
223
+ return lines.join("\n");
224
+ }
225
+
203
226
  function diffText(r) {
204
- const lines = [`makersclaw ${r.from} → ${r.to} · ${r.compatible ? "compatible" : "changes the contract — update --major"}`];
227
+ const lines = [`makersclaw ${r.from} → ${r.to} · ${r.compatible ? "compatible" : "changes the contract — update --major"} · mode ${r.mode}`];
205
228
  if (!r.entries.length && !r.package.length) {
206
229
  lines.push(` nothing to update — the app matches makersclaw ${r.to}`);
207
230
  return lines.join("\n");
@@ -240,7 +263,7 @@ export function run(opts, { stderr = process.stderr, env = process.env } = {}) {
240
263
  return { result: packageInfo(), text: packageInfo().version };
241
264
  case "init": {
242
265
  const dir = opts.args[0] ? resolve(cwd, opts.args[0]) : cwd;
243
- const result = init(dir, { template: opts.template ?? "next", force: Boolean(opts.force) });
266
+ const result = init(dir, { template: opts.template ?? "next", force: Boolean(opts.force), tables: opts.tables, mode: opts.mode });
244
267
  return { result: { dir, ...result }, text: layText(result, "init") };
245
268
  }
246
269
  case "update": {
@@ -262,6 +285,10 @@ export function run(opts, { stderr = process.stderr, env = process.env } = {}) {
262
285
  const result = install(cwd, { env, onNote: (line) => stderr.write(`makersclaw: ${line}\n`) });
263
286
  return { result: { dir: cwd, ...result }, text: installText(result) };
264
287
  }
288
+ case "mode": {
289
+ const result = mode(cwd, opts.args[0] ?? opts.mode);
290
+ return { result: { dir: cwd, ...result }, text: modeText(result) };
291
+ }
265
292
  case "diff": {
266
293
  const result = diff(cwd);
267
294
  return { result: { dir: cwd, ...result }, text: diffText(result) };