makersclaw 0.5.2 → 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.
- package/README.md +73 -7
- package/package.json +3 -2
- package/r/annotate.json +4 -4
- package/r/approval-request.json +3 -3
- package/r/audio-player.json +3 -3
- package/r/auth-form.json +2 -2
- package/r/board.json +4 -4
- package/r/calendar-view.json +4 -4
- package/r/cart.json +3 -3
- package/r/chart.json +3 -3
- package/r/chat.json +3 -3
- package/r/code-editor.json +4 -4
- package/r/comment-box.json +4 -4
- package/r/contact-section.json +3 -3
- package/r/core.json +3 -3
- package/r/csv-import.json +4 -4
- package/r/data-table.json +3 -3
- package/r/diagram.json +3 -3
- package/r/doc-editor.json +4 -4
- package/r/doc-page.json +4 -4
- package/r/email-render.json +2 -2
- package/r/faq.json +2 -2
- package/r/file-upload.json +3 -3
- package/r/flow-canvas.json +4 -4
- package/r/footer.json +3 -3
- package/r/gantt.json +4 -4
- package/r/job-panel.json +3 -3
- package/r/json-editor.json +4 -4
- package/r/map.json +5 -5
- package/r/menubar.json +2 -2
- package/r/mind-map.json +4 -4
- package/r/navigation-menu.json +2 -2
- package/r/order-detail.json +2 -2
- package/r/org-chart.json +4 -4
- package/r/page-builder.json +6 -6
- package/r/payment-methods.json +2 -2
- package/r/pdf-document.json +2 -2
- package/r/pdf-viewer.json +6 -6
- package/r/product-detail.json +3 -3
- package/r/product-grid.json +4 -4
- package/r/record-form.json +3 -3
- package/r/record-notes.json +5 -5
- package/r/registry.json +121 -121
- package/r/search-dialog.json +3 -3
- package/r/settings-list.json +3 -3
- package/r/setup-checklist.json +3 -3
- package/r/share-dialog.json +3 -3
- package/r/sidebar.json +2 -2
- package/r/signature-pad.json +3 -3
- package/r/sketch-canvas.json +5 -5
- package/r/spreadsheet.json +3 -3
- package/r/stat-cards.json +4 -4
- package/r/task-list.json +4 -4
- package/r/task-model.json +3 -3
- package/r/testimonials.json +2 -2
- package/r/transaction-list.json +3 -3
- package/r/whiteboard.json +4 -4
- package/registry/blocks/annotate/README.md +14 -5
- package/registry/blocks/approval-request/README.md +15 -8
- package/registry/blocks/audio-player/README.md +17 -10
- package/registry/blocks/board/README.md +13 -9
- package/registry/blocks/board/board.jsx +1 -1
- package/registry/blocks/calendar-view/README.md +28 -4
- package/registry/blocks/cart/README.md +14 -10
- package/registry/blocks/chart/README.md +14 -7
- package/registry/blocks/chat/README.md +43 -13
- package/registry/blocks/code-editor/README.md +4 -0
- package/registry/blocks/code-editor/code-editor.jsx +1 -1
- package/registry/blocks/comment-box/README.md +20 -13
- package/registry/blocks/contact-section/README.md +7 -6
- package/registry/blocks/csv-import/README.md +34 -12
- package/registry/blocks/data-table/README.md +41 -8
- package/registry/blocks/diagram/diagram.jsx +1 -1
- package/registry/blocks/doc-editor/README.md +18 -6
- package/registry/blocks/doc-editor/doc-editor.jsx +1 -1
- package/registry/blocks/doc-page/README.md +16 -6
- package/registry/blocks/file-upload/README.md +7 -1
- package/registry/blocks/flow-canvas/README.md +16 -5
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1 -1
- package/registry/blocks/footer/README.md +4 -2
- package/registry/blocks/gantt/README.md +18 -12
- package/registry/blocks/job-panel/README.md +1 -1
- package/registry/blocks/json-editor/README.md +16 -4
- package/registry/blocks/map/README.md +19 -3
- package/registry/blocks/map/map-view.jsx +1 -1
- package/registry/blocks/map/maplibre.js +1 -1
- package/registry/blocks/mind-map/README.md +16 -5
- package/registry/blocks/org-chart/README.md +10 -7
- package/registry/blocks/page-builder/README.md +13 -6
- package/registry/blocks/page-builder/page-builder.jsx +1 -1
- package/registry/blocks/page-builder/page-view.jsx +1 -1
- package/registry/blocks/page-builder/page.js +1 -1
- package/registry/blocks/pdf-viewer/README.md +22 -20
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1 -1
- package/registry/blocks/pdf-viewer/pdfjs.js +1 -1
- package/registry/blocks/pdf-viewer/ssr-shim.js +1 -1
- package/registry/blocks/product-detail/README.md +13 -7
- package/registry/blocks/product-detail/demo.jsx +1 -1
- package/registry/blocks/product-grid/README.md +12 -10
- package/registry/blocks/record-form/README.md +26 -9
- package/registry/blocks/record-notes/README.md +42 -30
- package/registry/blocks/search-dialog/README.md +38 -7
- package/registry/blocks/settings-list/README.md +29 -17
- package/registry/blocks/setup-checklist/README.md +12 -14
- package/registry/blocks/share-dialog/README.md +1 -1
- package/registry/blocks/signature-pad/README.md +15 -4
- package/registry/blocks/sketch-canvas/README.md +13 -4
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1 -1
- package/registry/blocks/sketch-canvas/ssr-shim.js +3 -3
- package/registry/blocks/spreadsheet/README.md +17 -8
- package/registry/blocks/stat-cards/README.md +17 -8
- package/registry/blocks/task-list/README.md +14 -11
- package/registry/blocks/task-model/README.md +3 -3
- package/registry/blocks/transaction-list/README.md +15 -7
- package/registry/blocks/whiteboard/README.md +19 -13
- package/src/cli.mjs +65 -9
- package/src/install.mjs +360 -21
- package/src/lockfile.mjs +468 -0
- package/src/pm.mjs +473 -0
- package/src/registry.mjs +125 -1
- package/templates/next/browser/app/auto-refresh.jsx +67 -0
- package/templates/next/browser/app/layout.jsx +94 -0
- package/templates/next/browser/app/page.jsx +60 -0
- package/templates/next/browser/app/s/[key]/page.jsx +95 -0
- package/templates/next/browser/lib/actions.js +16 -0
- package/templates/next/browser/lib/data.js +43 -0
- package/templates/next/files/README.md +818 -82
- package/templates/next/files/app/claw-alive/route.js +2 -2
- package/templates/next/files/app/frame.js +134 -9
- package/templates/next/files/app/layout.jsx +2 -2
- package/templates/next/files/check/run.mjs +1491 -53
- package/templates/next/files/components/ui/item.jsx +2 -2
- package/templates/next/files/components/ui/notice.jsx +1 -1
- package/templates/next/files/components/ui/separator.jsx +1 -1
- package/templates/next/files/lib/actions.js +171 -52
- package/templates/next/files/lib/brain-server.js +96 -0
- package/templates/next/files/lib/brain.js +413 -0
- package/templates/next/files/lib/claw.js +11 -0
- package/templates/next/files/lib/data.js +120 -30
- package/templates/next/files/lib/db.js +97 -17
- package/templates/next/files/lib/door.js +680 -0
- package/templates/next/files/next.config.mjs +85 -9
- package/templates/next/files/package.json +3 -3
- package/templates/next/files/{middleware.js → proxy.js} +13 -6
- package/templates/next/files/surfaces.js +3 -2
- package/templates/next/pnpm-lock.yaml +5870 -0
- package/templates/next/template.json +13 -6
- package/templates/next/files/schema.sql +0 -22
|
@@ -125,27 +125,34 @@ States
|
|
|
125
125
|
## Example
|
|
126
126
|
|
|
127
127
|
```jsx
|
|
128
|
-
//
|
|
128
|
+
// surfaces/overview.jsx — client: the numbers, read in the browser
|
|
129
129
|
"use client";
|
|
130
|
-
import {
|
|
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(
|
|
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.
|
|
139
|
-
{ id: "churn", label: "Logo churn", value: kpis.churn, delta: kpis.
|
|
140
|
-
{ id: "trials", label: "Active trials", value: kpis.trials, previous: kpis.
|
|
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
|
-
|
|
148
|
-
|
|
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 —
|
|
102
|
-
|
|
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
|
|
106
|
-
const
|
|
107
|
-
const 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: "
|
|
136
|
-
: w.op === "update" ? await updateRow({ source: "
|
|
137
|
-
: await deleteRow({ source: "
|
|
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: "
|
|
117
|
-
: w.op === "update" ? await updateRow({ source: "
|
|
118
|
-
: await deleteRow({ source: "
|
|
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
|
-
//
|
|
82
|
+
// surfaces/billing.jsx — client: invoices and payments
|
|
83
83
|
"use client";
|
|
84
|
-
import {
|
|
84
|
+
import { useRows } from "../lib/data";
|
|
85
|
+
import { TransactionList } from "../components/blocks/transaction-list";
|
|
85
86
|
|
|
86
|
-
export default function Billing(
|
|
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
|
-
|
|
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.
|
|
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 {
|
|
118
|
-
import {
|
|
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(
|
|
123
|
-
const
|
|
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
|
-
|
|
130
|
+
key={board.id}
|
|
131
|
+
title={board.title}
|
|
127
132
|
onRename={async (next) => {
|
|
128
|
-
const res = await updateRow({ source: "
|
|
129
|
-
if (res.ok)
|
|
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: "
|
|
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: "
|
|
148
|
-
onOpenTask={(task) => router.push(`/tasks
|
|
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, 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 = {
|
|
@@ -21,6 +21,9 @@ const COMMANDS = {
|
|
|
21
21
|
diff: "diff",
|
|
22
22
|
update: "update",
|
|
23
23
|
upgrade: "update",
|
|
24
|
+
install: "install",
|
|
25
|
+
i: "install",
|
|
26
|
+
mode: "mode",
|
|
24
27
|
help: "help",
|
|
25
28
|
};
|
|
26
29
|
|
|
@@ -30,6 +33,8 @@ const VALUE_FLAGS = new Map([
|
|
|
30
33
|
["--template", "template"],
|
|
31
34
|
["--type", "type"],
|
|
32
35
|
["--limit", "limit"],
|
|
36
|
+
["--tables", "tables"],
|
|
37
|
+
["--mode", "mode"],
|
|
33
38
|
]);
|
|
34
39
|
const BOOL_FLAGS = new Map([
|
|
35
40
|
["--json", "json"],
|
|
@@ -74,6 +79,8 @@ function helpText() {
|
|
|
74
79
|
return `makersclaw ${version} — the Makersclaw app template, its kit and its blocks
|
|
75
80
|
|
|
76
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)
|
|
77
84
|
npx makersclaw add <name...> install blocks, or restore a kit component
|
|
78
85
|
npx makersclaw search <words...> find blocks and components by what they do
|
|
79
86
|
npx makersclaw view <name> one item: props, data, an example
|
|
@@ -82,9 +89,12 @@ function helpText() {
|
|
|
82
89
|
npx makersclaw diff what update would change in this app
|
|
83
90
|
npx makersclaw update [--major] lay this version's fixed files and blocks
|
|
84
91
|
[--adopt] …or take on an app laid before makersclaw (kit era)
|
|
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
|
|
85
94
|
|
|
86
95
|
--cwd <dir> the app (default: this folder) --json one JSON object
|
|
87
96
|
--force init over an app that exists (your own files stay)
|
|
97
|
+
install: MAKERSCLAW_PNPM names a pnpm, MAKERSCLAW_PNPM_STORE its store
|
|
88
98
|
templates: ${templateNames().join(", ")}`;
|
|
89
99
|
}
|
|
90
100
|
|
|
@@ -100,6 +110,13 @@ function packageLines(changes) {
|
|
|
100
110
|
return [` package.json: ${changes.map((c) => `${c.name} ${c.from ?? "(new)"} → ${c.to}`).join(" · ")}`];
|
|
101
111
|
}
|
|
102
112
|
|
|
113
|
+
/** The lock's line, when it was written. What it left out is a note. */
|
|
114
|
+
function lockLine(lock, written) {
|
|
115
|
+
if (!lock || !written) return [];
|
|
116
|
+
const kept = lock.carried.length ? ` · kept from yours: ${lock.carried.join(", ")}` : "";
|
|
117
|
+
return [` pnpm-lock.yaml: cut from this release's lock, ${plural(lock.covered, "dependency", "dependencies")}${kept}`];
|
|
118
|
+
}
|
|
119
|
+
|
|
103
120
|
function layText(r, verb) {
|
|
104
121
|
const head =
|
|
105
122
|
verb === "update"
|
|
@@ -115,10 +132,11 @@ function layText(r, verb) {
|
|
|
115
132
|
if (r.removed.length) lines.push(` removed (no longer shipped): ${listLine(r.removed)}`);
|
|
116
133
|
if (r.blocks.length) lines.push(` blocks: ${r.blocks.join(", ")}`);
|
|
117
134
|
lines.push(...packageLines(r.package));
|
|
118
|
-
lines.push(
|
|
135
|
+
lines.push(...lockLine(r.lock, r.written.includes("pnpm-lock.yaml")));
|
|
136
|
+
lines.push(` ${plural(r.pinned, "fixed file")} pinned in check/pins.json · makersclaw.json records ${r.version}, tables ${r.tables}, mode ${r.mode}`);
|
|
119
137
|
for (const n of r.notes) lines.push(` note: ${n}`);
|
|
120
138
|
const next = [];
|
|
121
|
-
if (r.install) next.push("
|
|
139
|
+
if (r.install) next.push("npx makersclaw install");
|
|
122
140
|
if (verb === "init" && !r.from) next.push("design app/shell.jsx and the surfaces", "find blocks: npx makersclaw search <what the surface needs>");
|
|
123
141
|
else next.push("npm run check");
|
|
124
142
|
lines.push(`next: ${next.join(" · ")}`);
|
|
@@ -134,7 +152,9 @@ function addText(r) {
|
|
|
134
152
|
lines.push(` ${a.import}`);
|
|
135
153
|
}
|
|
136
154
|
lines.push(...packageLines(r.package));
|
|
137
|
-
|
|
155
|
+
lines.push(...lockLine(r.lock, r.lock?.written));
|
|
156
|
+
for (const n of r.notes) lines.push(` note: ${n}`);
|
|
157
|
+
if (r.install) lines.push("next: npx makersclaw install");
|
|
138
158
|
for (const u of r.usage) if (u.readme) lines.push("", u.readme.trimEnd());
|
|
139
159
|
return lines.join("\n");
|
|
140
160
|
}
|
|
@@ -186,8 +206,25 @@ function listText(items) {
|
|
|
186
206
|
return lines.join("\n");
|
|
187
207
|
}
|
|
188
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
|
+
|
|
189
226
|
function diffText(r) {
|
|
190
|
-
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}`];
|
|
191
228
|
if (!r.entries.length && !r.package.length) {
|
|
192
229
|
lines.push(` nothing to update — the app matches makersclaw ${r.to}`);
|
|
193
230
|
return lines.join("\n");
|
|
@@ -198,6 +235,16 @@ function diffText(r) {
|
|
|
198
235
|
return lines.join("\n");
|
|
199
236
|
}
|
|
200
237
|
|
|
238
|
+
function installText(r) {
|
|
239
|
+
const how = r.manager === "pnpm" ? `pnpm ${r.version} (${r.via})` : `npm ${r.version ?? ""}`.trim();
|
|
240
|
+
const lock = r.manager !== "pnpm" ? "pnpm-lock.yaml not read" : r.frozen ? "frozen: pnpm-lock.yaml as laid" : `pnpm-lock.yaml updated — ${r.why}`;
|
|
241
|
+
const lines = [`installed with ${how} · ${lock}`];
|
|
242
|
+
if (r.manager === "pnpm") lines.push(` node_modules hoisted, hard-linked from ${r.store ?? "pnpm's default store"}`);
|
|
243
|
+
for (const n of r.notes) lines.push(` note: ${n}`);
|
|
244
|
+
lines.push("next: npm run check");
|
|
245
|
+
return lines.join("\n");
|
|
246
|
+
}
|
|
247
|
+
|
|
201
248
|
function templateFor(opts, fallback = "next") {
|
|
202
249
|
const name = opts.template ?? fallback;
|
|
203
250
|
const tpl = loadTemplate(name);
|
|
@@ -205,8 +252,9 @@ function templateFor(opts, fallback = "next") {
|
|
|
205
252
|
return tpl;
|
|
206
253
|
}
|
|
207
254
|
|
|
208
|
-
/** Run one command. Returns { result, text } or throws a CliError.
|
|
209
|
-
|
|
255
|
+
/** Run one command. Returns { result, text } or throws a CliError.
|
|
256
|
+
* `stderr` hears what must not wait for the end (install's fallback). */
|
|
257
|
+
export function run(opts, { stderr = process.stderr, env = process.env } = {}) {
|
|
210
258
|
const cwd = resolve(opts.cwd ?? process.cwd());
|
|
211
259
|
switch (opts.command) {
|
|
212
260
|
case "help":
|
|
@@ -215,7 +263,7 @@ export function run(opts) {
|
|
|
215
263
|
return { result: packageInfo(), text: packageInfo().version };
|
|
216
264
|
case "init": {
|
|
217
265
|
const dir = opts.args[0] ? resolve(cwd, opts.args[0]) : cwd;
|
|
218
|
-
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 });
|
|
219
267
|
return { result: { dir, ...result }, text: layText(result, "init") };
|
|
220
268
|
}
|
|
221
269
|
case "update": {
|
|
@@ -233,6 +281,14 @@ export function run(opts) {
|
|
|
233
281
|
text: `removed ${opts.args.join(", ")} — ${plural(result.removed.length, "file")}; installed now: ${result.blocks.join(", ") || "no blocks"}`,
|
|
234
282
|
};
|
|
235
283
|
}
|
|
284
|
+
case "install": {
|
|
285
|
+
const result = install(cwd, { env, onNote: (line) => stderr.write(`makersclaw: ${line}\n`) });
|
|
286
|
+
return { result: { dir: cwd, ...result }, text: installText(result) };
|
|
287
|
+
}
|
|
288
|
+
case "mode": {
|
|
289
|
+
const result = mode(cwd, opts.args[0] ?? opts.mode);
|
|
290
|
+
return { result: { dir: cwd, ...result }, text: modeText(result) };
|
|
291
|
+
}
|
|
236
292
|
case "diff": {
|
|
237
293
|
const result = diff(cwd);
|
|
238
294
|
return { result: { dir: cwd, ...result }, text: diffText(result) };
|
|
@@ -299,7 +355,7 @@ export function main(argv, { stdout = process.stdout, stderr = process.stderr, e
|
|
|
299
355
|
try {
|
|
300
356
|
opts = parseArgs(argv);
|
|
301
357
|
if (opts.help && opts.command !== "help") opts = { ...opts, command: "help" };
|
|
302
|
-
const { result, text } = run(opts);
|
|
358
|
+
const { result, text } = run(opts, { stderr, env });
|
|
303
359
|
stdout.write(opts.json ? `${JSON.stringify({ ok: true, command: opts.command, ...result }, null, 2)}\n` : `${text}\n`);
|
|
304
360
|
return 0;
|
|
305
361
|
} catch (error) {
|