makersclaw 0.5.2 → 0.6.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 (73) hide show
  1. package/README.md +29 -3
  2. package/package.json +3 -2
  3. package/r/annotate.json +3 -3
  4. package/r/approval-request.json +2 -2
  5. package/r/audio-player.json +2 -2
  6. package/r/auth-form.json +2 -2
  7. package/r/board.json +2 -2
  8. package/r/calendar-view.json +3 -3
  9. package/r/cart.json +2 -2
  10. package/r/chart.json +2 -2
  11. package/r/chat.json +2 -2
  12. package/r/code-editor.json +2 -2
  13. package/r/comment-box.json +3 -3
  14. package/r/contact-section.json +2 -2
  15. package/r/csv-import.json +3 -3
  16. package/r/data-table.json +2 -2
  17. package/r/diagram.json +2 -2
  18. package/r/doc-editor.json +2 -2
  19. package/r/doc-page.json +3 -3
  20. package/r/email-render.json +2 -2
  21. package/r/faq.json +2 -2
  22. package/r/file-upload.json +2 -2
  23. package/r/flow-canvas.json +2 -2
  24. package/r/footer.json +2 -2
  25. package/r/gantt.json +3 -3
  26. package/r/job-panel.json +2 -2
  27. package/r/json-editor.json +3 -3
  28. package/r/map.json +2 -2
  29. package/r/menubar.json +2 -2
  30. package/r/mind-map.json +3 -3
  31. package/r/navigation-menu.json +2 -2
  32. package/r/order-detail.json +2 -2
  33. package/r/org-chart.json +3 -3
  34. package/r/page-builder.json +2 -2
  35. package/r/payment-methods.json +2 -2
  36. package/r/pdf-document.json +2 -2
  37. package/r/pdf-viewer.json +2 -2
  38. package/r/product-detail.json +2 -2
  39. package/r/product-grid.json +3 -3
  40. package/r/record-form.json +2 -2
  41. package/r/record-notes.json +4 -4
  42. package/r/registry.json +121 -121
  43. package/r/search-dialog.json +2 -2
  44. package/r/settings-list.json +2 -2
  45. package/r/setup-checklist.json +2 -2
  46. package/r/share-dialog.json +2 -2
  47. package/r/sidebar.json +2 -2
  48. package/r/signature-pad.json +2 -2
  49. package/r/sketch-canvas.json +2 -2
  50. package/r/spreadsheet.json +2 -2
  51. package/r/stat-cards.json +3 -3
  52. package/r/task-list.json +3 -3
  53. package/r/task-model.json +2 -2
  54. package/r/testimonials.json +2 -2
  55. package/r/transaction-list.json +2 -2
  56. package/r/whiteboard.json +3 -3
  57. package/src/cli.mjs +35 -6
  58. package/src/install.mjs +101 -4
  59. package/src/lockfile.mjs +468 -0
  60. package/src/pm.mjs +473 -0
  61. package/src/registry.mjs +48 -1
  62. package/templates/next/files/README.md +20 -15
  63. package/templates/next/files/app/claw-alive/route.js +2 -2
  64. package/templates/next/files/app/frame.js +6 -5
  65. package/templates/next/files/app/layout.jsx +2 -2
  66. package/templates/next/files/check/run.mjs +55 -14
  67. package/templates/next/files/lib/actions.js +1 -1
  68. package/templates/next/files/lib/data.js +1 -1
  69. package/templates/next/files/next.config.mjs +50 -8
  70. package/templates/next/files/package.json +3 -3
  71. package/templates/next/files/{middleware.js → proxy.js} +13 -6
  72. package/templates/next/pnpm-lock.yaml +5870 -0
  73. package/templates/next/template.json +5 -4
@@ -5,7 +5,7 @@
5
5
  "title": "SearchDialog",
6
6
  "description": "One ⌘K search over every kind of record — chats, documents, images, projects, people. Before typing it shows your sections (Last opened, Recent); while typing, ranked matches with the typed text marked, a date, image thumbnails, and kind chips (All, Chats, Images…) to narrow them. Searches your list in the browser, or your server through an async onSearch. Built on the kit's Command; SearchPanel is the same box inline.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [],
11
11
  "files": [
@@ -44,7 +44,7 @@
44
44
  "docs": "Installed to components/makersclaw/blocks/search-dialog. Import: import { SearchDialog, SearchPanel } from \"@/components/makersclaw/blocks/search-dialog\". Props and an example: components/makersclaw/blocks/search-dialog/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
45
45
  "meta": {
46
46
  "makersclaw": {
47
- "version": "0.5.2",
47
+ "version": "0.6.0",
48
48
  "useWhen": "An app has more than one kind of record and wants one global search box or ⌘K palette to find any of them, or a search page with type filters."
49
49
  }
50
50
  }
@@ -5,7 +5,7 @@
5
5
  "title": "SettingsList",
6
6
  "description": "A card of settings, one row each — icon, label, description, meta lines, a badge, and its control: a Switch, a Select, a Button, a remove button or a menu of actions, with optional details that open under the row. Every change saves on its own through an async callback; the row shows the new value at once, a spinner while it saves, and on failure the old value back with the reason and Try again. variant=\"matrix\" is the notification grid: events by group down the side, channels (email, push, SMS) across, a switch per cell, stacked on a phone.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [],
11
11
  "files": [
@@ -59,7 +59,7 @@
59
59
  "docs": "Installed to components/makersclaw/blocks/settings-list. Import: import { SettingsList } from \"@/components/makersclaw/blocks/settings-list\". Props and an example: components/makersclaw/blocks/settings-list/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
60
60
  "meta": {
61
61
  "makersclaw": {
62
- "version": "0.5.2",
62
+ "version": "0.6.0",
63
63
  "useWhen": "An account or workspace settings screen where each setting applies the moment it is changed: preferences, two-step sign-in methods, signed-in devices, connected integrations, billing profiles, notification preferences per channel. Not for a form of fields saved together with one button (record-form)."
64
64
  }
65
65
  }
@@ -5,7 +5,7 @@
5
5
  "title": "SetupChecklist",
6
6
  "description": "The steps to get set up: which are done, how far along the whole is (a ring, a bar, or \"Step 2 of 4\"), and the button for the next one, sent out through an async onAction that can fail on the step. Four shapes: folding rows in a card with a dismiss menu, numbered step cards, a plain step list with a help panel, and bordered accordion rows that can be locked until the step before is done.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [],
11
11
  "files": [
@@ -44,7 +44,7 @@
44
44
  "docs": "Installed to components/makersclaw/blocks/setup-checklist. Import: import { SetupChecklist } from \"@/components/makersclaw/blocks/setup-checklist\". Props and an example: components/makersclaw/blocks/setup-checklist/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
45
45
  "meta": {
46
46
  "makersclaw": {
47
- "version": "0.5.2",
47
+ "version": "0.6.0",
48
48
  "useWhen": "A new account, workspace or shop has a few things to do before it is useful (complete the profile, invite the team, connect a tool, launch) and the founder should see what is left. Not for a running job's stages (kit Steps or job-panel), and not for a multi-page form wizard."
49
49
  }
50
50
  }
@@ -5,7 +5,7 @@
5
5
  "title": "ShareDialog",
6
6
  "description": "Who can see a record and how to let more people in: invite by email (comma separated, with an access level), each person with their access in a menu (can view, can edit, remove), sharing switches, and a link with a copy button that turns to a check. A dialog, or the same body inline (SharePanel). Every change is an async callback; a failure shows and the old value comes back.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [],
11
11
  "files": [
@@ -45,7 +45,7 @@
45
45
  "docs": "Installed to components/makersclaw/blocks/share-dialog. Import: import { ShareDialog, SharePanel } from \"@/components/makersclaw/blocks/share-dialog\". Props and an example: components/makersclaw/blocks/share-dialog/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
46
46
  "meta": {
47
47
  "makersclaw": {
48
- "version": "0.5.2",
48
+ "version": "0.6.0",
49
49
  "useWhen": "A record, project, document or workspace can be shared: an \"Invite\" or \"Share\" button, a members list with roles, a public link to copy."
50
50
  }
51
51
  }
package/r/sidebar.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "title": "Sidebar",
6
6
  "description": "An app's navigation down the left edge: app name or workspace switcher, groups of items with icons, counts and nested items, the signed-in person with their menu; collapses to icons (remembered) and becomes a Sheet behind a trigger on a phone. Optional: inset or floating look, a ⌘K search over every item, folding groups with colour dots, a second column (a mail list, or a parent's children to drill into), a \"New\" button and a \"…\" menu per item (a chat history).",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [],
11
11
  "files": [
@@ -62,7 +62,7 @@
62
62
  "docs": "Installed to components/makersclaw/blocks/sidebar. Import: import { Sidebar, SidebarLayout, SidebarTrigger, useSidebar } from \"@/components/makersclaw/blocks/sidebar\". Props and an example: components/makersclaw/blocks/sidebar/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
63
63
  "meta": {
64
64
  "makersclaw": {
65
- "version": "0.5.2",
65
+ "version": "0.6.0",
66
66
  "useWhen": "An app with more than a handful of places to go (inbox, deals, contacts, reports, settings, projects) that wants a real app shell: compose it in app/shell.jsx around the surfaces. Not for in-page tabs (Tabs) or a short strip of links."
67
67
  }
68
68
  }
@@ -5,7 +5,7 @@
5
5
  "title": "SignaturePad",
6
6
  "description": "A signature field (signature_pad) in the workspace theme: a full-name field, then draw on a paper box (smooth pen strokes, undo the last stroke, clear with Undo) or type the name set as a signature. Sign returns a record: a cropped transparent PNG in dark ink, the typed name, the mode and the time; the signed view shows it with Sign again. Works as a form field too, through a handle (toPNG, getSignature).",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [
11
11
  "signature_pad@5.1.4"
@@ -65,7 +65,7 @@
65
65
  "docs": "Installed to components/makersclaw/blocks/signature-pad. Import: import { SignaturePad, useSignaturePad, signatureRecord, formatSignedAt } from \"@/components/makersclaw/blocks/signature-pad\". Props and an example: components/makersclaw/blocks/signature-pad/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
66
66
  "meta": {
67
67
  "makersclaw": {
68
- "version": "0.5.2",
68
+ "version": "0.6.0",
69
69
  "useWhen": "A screen needs someone to sign: accepting a proposal or a quote, a delivery or work-done sign-off, a waiver, a consent form, an approval on a record. The proposal-accept block is built on it. It records an acceptance with a picture of the signature — it is not a certified legal e-signature (no identity check, no audit trail beyond what you store)."
70
70
  }
71
71
  }
@@ -5,7 +5,7 @@
5
5
  "title": "SketchCanvas",
6
6
  "description": "A freeform drawing canvas (Excalidraw) in the workspace theme: a Miro-style tool rail (select, pan, draw, shapes, arrows, text, image, eraser, frames), a floating toolbar over the selection with colours from the theme's tokens, zoom and undo controls, a friendly empty state, and stamp tools that place ready-made drawings (UI wireframe pieces built in). Optional locked background image for annotating a screenshot. The sketch is plain JSON; helpers read its words for an agent, and the handle exports a PNG.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [
11
11
  "@excalidraw/excalidraw@0.18.1"
@@ -92,7 +92,7 @@
92
92
  "docs": "Installed to components/makersclaw/blocks/sketch-canvas. Import: import { SketchCanvas, useSketchCanvas, SKETCH_TOOLS, WIREFRAME_STAMPS, STROKES, FILLS, emptySketch, isSketchEmpty, sketchToText, sketchItems, toSketch } from \"@/components/makersclaw/blocks/sketch-canvas\". Props and an example: components/makersclaw/blocks/sketch-canvas/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
93
93
  "meta": {
94
94
  "makersclaw": {
95
- "version": "0.5.2",
95
+ "version": "0.6.0",
96
96
  "useWhen": "A screen needs freehand drawing: a whiteboard, marking up a screenshot, sketching a UI wireframe, a diagram drawn by hand. The whiteboard, annotate and sketch-to-app blocks are built on it. Not for structured boards of cards and connectors (flow-canvas), charts (chart) or a kanban (board)."
97
97
  }
98
98
  }
@@ -5,7 +5,7 @@
5
5
  "title": "Spreadsheet",
6
6
  "description": "A table you edit like Google Sheets or Airtable, virtualised for 10,000+ rows: typed columns (text, number, currency, date, single and multiple select, person, checkbox, link, rating) each with its own in-cell editor, a cell cursor and range selection with the mouse and arrow keys, typing to edit, copy and paste ranges as TSV (to and from Sheets and Excel), drag-to-fill and ⌘D fill down, undo/redo, column resize, drag to reorder, hide, freeze, rename, change type and add fields, row insert and delete with Undo, sort and filter panels, search, a sum/average of the selection, validation marks, and a phone layout. Edits go out as async callbacks answering { ok }, applied at once and rolled back on failure. A column-type registry and an imperative handle for blocks built on it.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [
11
11
  "@tanstack/react-virtual@3.14.13"
@@ -83,7 +83,7 @@
83
83
  "docs": "Installed to components/makersclaw/blocks/spreadsheet. Import: import { Spreadsheet, CellValue, CellPanel, OptionBadge, editorFor, TYPE_ORDER, sortWords, COLUMN_TYPES, typeOf, parseCell, convertValue, guessType, parseNumberText, parseDateText, optionValue, isBlank, emptyView, normalizeView, orderedColumns, visibleColumns, processRows, passesFilters, parseTSV, toTSV, pasteChanges, fillChanges, clearChanges, applyChanges, invertChanges } from \"@/components/makersclaw/blocks/spreadsheet\". Props and an example: components/makersclaw/blocks/spreadsheet/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
84
84
  "meta": {
85
85
  "makersclaw": {
86
- "version": "0.5.2",
86
+ "version": "0.6.0",
87
87
  "useWhen": "People need to enter or clean up many records in a grid, fast, with the keyboard: a lead list, an inventory, a budget, a content calendar, a table view over any collection, the grid under an Airtable-like base. Not for a read-mostly list to scan and act on row by row (data-table), records moving through stages (board), or a single record (record-form)."
88
88
  }
89
89
  }
package/r/stat-cards.json CHANGED
@@ -5,8 +5,8 @@
5
5
  "title": "Stat cards",
6
6
  "description": "A row of key numbers, each with its name and its change: one bordered strip, or a card each with a change in the corner or after the value, a \"from\" value, a status dot and a goal meter, a sparkline, a \"View more\" footer; or a usage tile per amount against its limit (a bar or a ring, a split by kind with what is free, a warning line near the cap, an action and a limit the founder can change); or a plain list of values with their change. Loading, empty and error states.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json",
9
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/chart.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json",
9
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/chart.json"
10
10
  ],
11
11
  "dependencies": [],
12
12
  "files": [
@@ -59,7 +59,7 @@
59
59
  "docs": "Installed to components/makersclaw/blocks/stat-cards. Import: import { StatCards } from \"@/components/makersclaw/blocks/stat-cards\". Props and an example: components/makersclaw/blocks/stat-cards/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
60
60
  "meta": {
61
61
  "makersclaw": {
62
- "version": "0.5.2",
62
+ "version": "0.6.0",
63
63
  "useWhen": "The few numbers at the top of a dashboard or a report: revenue, users, conversion, spend against budget, seats and storage against a plan. Not for a trend worth reading on its own (a chart), many rows of records (a table), or one subject scored against thresholds (a scorecard)."
64
64
  }
65
65
  }
package/r/task-list.json CHANGED
@@ -5,8 +5,8 @@
5
5
  "title": "Task list",
6
6
  "description": "The List view of work, like ClickUp's or Linear's: tasks under headings that fold (group by status, assignee, priority, project, due date or any field), a round check to complete each, the title edited in place, subtasks indented under their parent with their own fold, the fields you choose (assignees, due date, priority, tags, project, estimate) as inline pickers, a quick-add row at the end of every group, drag to reorder and to move between groups (saving the new status, assignee or due date), multi-select with a bulk bar (status, assign, due, priority, delete with undo), a toolbar with search, filter chips, group by, sort and fields, and friendly empty states with starter templates. One async onChange saves every change; failures roll back with a notice.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json",
9
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/task-model.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json",
9
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/task-model.json"
10
10
  ],
11
11
  "dependencies": [],
12
12
  "files": [
@@ -56,7 +56,7 @@
56
56
  "docs": "Installed to components/makersclaw/blocks/task-list. Import: import { TaskList } from \"@/components/makersclaw/blocks/task-list\". Props and an example: components/makersclaw/blocks/task-list/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
57
57
  "meta": {
58
58
  "makersclaw": {
59
- "version": "0.5.2",
59
+ "version": "0.6.0",
60
60
  "useWhen": "A screen that lists work to get done and moves it along: a team's tasks, a launch checklist, a sprint, a personal to-do list, onboarding steps, content to publish. Not for records that are not work (data-table), for stage columns side by side (board), or for dates on a grid (calendar)."
61
61
  }
62
62
  }
package/r/task-model.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "title": "Task model",
6
6
  "description": "The shared work-item model every task view reads: one task shape (status, assignees, start/due, estimate, progress, priority, parent, dependencies, location, tags, project, extra fields) with statuses, people and projects; pure helpers to search, filter, group by any field, sort, nest subtasks, do date math (week and month grids, working days, overlaps, time scales), sum capacity per person, follow dependencies and the critical path, and apply, undo and persist changes; the shared parts (StatusPill, AssigneeStack, DueLabel, PriorityFlag, TaskChip, CompleteToggle), the ViewToolbar (search, filter chips, group by, sort, show fields), drag primitives on @dnd-kit, a hook for optimistic saves with rollback and undo, and adapters that drive the Board and DataTable blocks from tasks.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [
11
11
  "@dnd-kit/core@6.3.1",
@@ -91,7 +91,7 @@
91
91
  "docs": "Installed to components/makersclaw/blocks/task-model. Import: import { NONE, PRIORITIES, DEFAULT_STATUSES, TASK_FIELDS, DEFAULT_VIEW, normalizeTask, normalizeTasks, createTaskContext, fieldOf, isDone, doneStatusId, openStatusId, toggleDoneChange, newTaskId, draftTask, valuesOf, optionsOf, labelOf, searchText, searchTasks, filterTasks, orderOf, sortTasks, sortOptions, groupTasks, groupOptions, movePatch, applyView, activeFilterCount, rankBetween, placeChange, childrenMap, buildTree, flattenTree, descendantIds, ancestorIds, subtaskCounts, rollup, progressOf, dependencyEdges, blockersOf, wouldCycle, dateConflicts, criticalPath, hoursPerDay, workload, sumOf, applyChange, invertChange, changeWrites, changedIds, deleteChange, toBoard, toTableRows, taskFacets, StatusPill, CompleteToggle, AssigneeStack, PersonLabel, DueLabel, PriorityFlag, TagList, SubtaskCount, ProgressLine, TaskChip, GroupLabel, taskColumns, TONE_TEXT, HUE_EDGE, HUE_BG, TaskDragProvider, SortableGroup, useSortableTask, useDraggableTask, useDropTarget, DragHandle, DropLine, LIFTED, useReducedMotion, arrayMove, isDay, dayNumber, fromDayNumber, dayOf, minutesOf, withTime, todayDay, addDays, diffDays, weekdayOf, startOfWeek, endOfWeek, weekDays, startOfMonth, endOfMonth, addMonths, daysBetween, monthGrid, WEEKEND, isWeekend, isWorkingDay, workingDaysBetween, addWorkingDays, spanOf, spansOverlap, tasksInRange, tasksOnDay, shiftDates, spanPatch, dueBucket, DUE_BUCKETS, dayForBucket, formatDay, formatTime, formatDate, timeScale, rangeOfTasks, isNewId } from \"@/components/makersclaw/blocks/task-model\". Props and an example: components/makersclaw/blocks/task-model/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
92
92
  "meta": {
93
93
  "makersclaw": {
94
- "version": "0.5.2",
94
+ "version": "0.6.0",
95
95
  "useWhen": "You are building a view of work items — a list, calendar, gantt, workload, roadmap or a switcher between them — or driving Board / DataTable from tasks. Views import it; a surface rarely renders it alone. Not for records that are not work (use data-table or board directly)."
96
96
  }
97
97
  }
@@ -5,7 +5,7 @@
5
5
  "title": "Testimonials",
6
6
  "description": "A marketing section of customer quotes: name, role, company, face or logo, the quote, an optional star rating, a verified mark and a \"view on X\" source, and optional headline numbers (stats). Layouts: a grid of cards (plain, card or raised; hover can light one and dim the rest; a \"write a review\" tile), one large quote, a switcher of faces, and a carousel, optionally over a picture.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [],
11
11
  "files": [
@@ -45,7 +45,7 @@
45
45
  "docs": "Installed to components/makersclaw/blocks/testimonials. Import: import { Testimonials } from \"@/components/makersclaw/blocks/testimonials\". Props and an example: components/makersclaw/blocks/testimonials/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
46
46
  "meta": {
47
47
  "makersclaw": {
48
- "version": "0.5.2",
48
+ "version": "0.6.0",
49
49
  "useWhen": "Social proof on a public page: a landing page, a pricing page, a product page, a case-study teaser. Not for reviews a signed-in user writes and manages (a record list or form), or an app's own activity feed."
50
50
  }
51
51
  }
@@ -5,7 +5,7 @@
5
5
  "title": "TransactionList",
6
6
  "description": "Money records as a plain list, in two variants: history (payments in and out, grouped by month, a received / paid / pending / failed mark and a signed amount) and invoices (number, date, a Paid / Due in N days / N days overdue badge, amount, download). Optional date-range filter, Export and per-row download. Empty, loading and error states built in.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json"
9
9
  ],
10
10
  "dependencies": [],
11
11
  "files": [
@@ -46,7 +46,7 @@
46
46
  "docs": "Installed to components/makersclaw/blocks/transaction-list. Import: import { TransactionList } from \"@/components/makersclaw/blocks/transaction-list\". Props and an example: components/makersclaw/blocks/transaction-list/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
47
47
  "meta": {
48
48
  "makersclaw": {
49
- "version": "0.5.2",
49
+ "version": "0.6.0",
50
50
  "useWhen": "A billing page's invoices, an account's payment history, a wallet's recent activity: records read top to bottom, newest first. Not for records the founder sorts, filters by column or totals (data-table), or for one order (order-detail)."
51
51
  }
52
52
  }
package/r/whiteboard.json CHANGED
@@ -5,8 +5,8 @@
5
5
  "title": "Whiteboard",
6
6
  "description": "A full-page freeform whiteboard on sketch-canvas: a top bar with the board's title (click to rename), the save state (Saving…, Saved, or the error with Retry), a Board / Text view switch, Export PNG and an optional Share button; under it the Miro-style canvas (tool rail, floating toolbar, zoom, undo). An empty board offers starter templates — blank, a grid of titled areas, a 2×2 matrix — and the Text view lists every word on the board for a screen reader or an agent. With onCreateTask, a selected note or text becomes a task from the top bar (\"Create task\", editable title; several notes make one task each), and a small badge marks it on the board from then on. The sketch is plain JSON; saves are async callbacks answering { ok }.",
7
7
  "registryDependencies": [
8
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/core.json",
9
- "https://cdn.jsdelivr.net/npm/makersclaw@0.5.2/r/sketch-canvas.json"
8
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/core.json",
9
+ "https://cdn.jsdelivr.net/npm/makersclaw@0.6.0/r/sketch-canvas.json"
10
10
  ],
11
11
  "dependencies": [],
12
12
  "files": [
@@ -59,7 +59,7 @@
59
59
  "docs": "Installed to components/makersclaw/blocks/whiteboard. Import: import { Whiteboard, WHITEBOARD_TEMPLATES, gridSketch, matrixSketch } from \"@/components/makersclaw/blocks/whiteboard\". Props and an example: components/makersclaw/blocks/whiteboard/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
60
60
  "meta": {
61
61
  "makersclaw": {
62
- "version": "0.5.2",
62
+ "version": "0.6.0",
63
63
  "useWhen": "A screen is one board to think on: a team whiteboard, a planning or prioritisation board, a place to sketch an idea and keep it with a record. Not for marking up a screenshot (annotate), sketching a UI to build (sketch-to-app), a structured board of cards and connectors (flow-canvas), or a kanban (board)."
64
64
  }
65
65
  }
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, 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,8 @@ const COMMANDS = {
21
21
  diff: "diff",
22
22
  update: "update",
23
23
  upgrade: "update",
24
+ install: "install",
25
+ i: "install",
24
26
  help: "help",
25
27
  };
26
28
 
@@ -82,9 +84,11 @@ function helpText() {
82
84
  npx makersclaw diff what update would change in this app
83
85
  npx makersclaw update [--major] lay this version's fixed files and blocks
84
86
  [--adopt] …or take on an app laid before makersclaw (kit era)
87
+ npx makersclaw install the app's packages: pnpm, from pnpm-lock.yaml
85
88
 
86
89
  --cwd <dir> the app (default: this folder) --json one JSON object
87
90
  --force init over an app that exists (your own files stay)
91
+ install: MAKERSCLAW_PNPM names a pnpm, MAKERSCLAW_PNPM_STORE its store
88
92
  templates: ${templateNames().join(", ")}`;
89
93
  }
90
94
 
@@ -100,6 +104,13 @@ function packageLines(changes) {
100
104
  return [` package.json: ${changes.map((c) => `${c.name} ${c.from ?? "(new)"} → ${c.to}`).join(" · ")}`];
101
105
  }
102
106
 
107
+ /** The lock's line, when it was written. What it left out is a note. */
108
+ function lockLine(lock, written) {
109
+ if (!lock || !written) return [];
110
+ const kept = lock.carried.length ? ` · kept from yours: ${lock.carried.join(", ")}` : "";
111
+ return [` pnpm-lock.yaml: cut from this release's lock, ${plural(lock.covered, "dependency", "dependencies")}${kept}`];
112
+ }
113
+
103
114
  function layText(r, verb) {
104
115
  const head =
105
116
  verb === "update"
@@ -115,10 +126,11 @@ function layText(r, verb) {
115
126
  if (r.removed.length) lines.push(` removed (no longer shipped): ${listLine(r.removed)}`);
116
127
  if (r.blocks.length) lines.push(` blocks: ${r.blocks.join(", ")}`);
117
128
  lines.push(...packageLines(r.package));
129
+ lines.push(...lockLine(r.lock, r.written.includes("pnpm-lock.yaml")));
118
130
  lines.push(` ${plural(r.pinned, "fixed file")} pinned in check/pins.json · makersclaw.json records ${r.version}`);
119
131
  for (const n of r.notes) lines.push(` note: ${n}`);
120
132
  const next = [];
121
- if (r.install) next.push("npm install");
133
+ if (r.install) next.push("npx makersclaw install");
122
134
  if (verb === "init" && !r.from) next.push("design app/shell.jsx and the surfaces", "find blocks: npx makersclaw search <what the surface needs>");
123
135
  else next.push("npm run check");
124
136
  lines.push(`next: ${next.join(" · ")}`);
@@ -134,7 +146,9 @@ function addText(r) {
134
146
  lines.push(` ${a.import}`);
135
147
  }
136
148
  lines.push(...packageLines(r.package));
137
- if (r.install) lines.push("next: npm install");
149
+ lines.push(...lockLine(r.lock, r.lock?.written));
150
+ for (const n of r.notes) lines.push(` note: ${n}`);
151
+ if (r.install) lines.push("next: npx makersclaw install");
138
152
  for (const u of r.usage) if (u.readme) lines.push("", u.readme.trimEnd());
139
153
  return lines.join("\n");
140
154
  }
@@ -198,6 +212,16 @@ function diffText(r) {
198
212
  return lines.join("\n");
199
213
  }
200
214
 
215
+ function installText(r) {
216
+ const how = r.manager === "pnpm" ? `pnpm ${r.version} (${r.via})` : `npm ${r.version ?? ""}`.trim();
217
+ const lock = r.manager !== "pnpm" ? "pnpm-lock.yaml not read" : r.frozen ? "frozen: pnpm-lock.yaml as laid" : `pnpm-lock.yaml updated — ${r.why}`;
218
+ const lines = [`installed with ${how} · ${lock}`];
219
+ if (r.manager === "pnpm") lines.push(` node_modules hoisted, hard-linked from ${r.store ?? "pnpm's default store"}`);
220
+ for (const n of r.notes) lines.push(` note: ${n}`);
221
+ lines.push("next: npm run check");
222
+ return lines.join("\n");
223
+ }
224
+
201
225
  function templateFor(opts, fallback = "next") {
202
226
  const name = opts.template ?? fallback;
203
227
  const tpl = loadTemplate(name);
@@ -205,8 +229,9 @@ function templateFor(opts, fallback = "next") {
205
229
  return tpl;
206
230
  }
207
231
 
208
- /** Run one command. Returns { result, text } or throws a CliError. */
209
- export function run(opts) {
232
+ /** Run one command. Returns { result, text } or throws a CliError.
233
+ * `stderr` hears what must not wait for the end (install's fallback). */
234
+ export function run(opts, { stderr = process.stderr, env = process.env } = {}) {
210
235
  const cwd = resolve(opts.cwd ?? process.cwd());
211
236
  switch (opts.command) {
212
237
  case "help":
@@ -233,6 +258,10 @@ export function run(opts) {
233
258
  text: `removed ${opts.args.join(", ")} — ${plural(result.removed.length, "file")}; installed now: ${result.blocks.join(", ") || "no blocks"}`,
234
259
  };
235
260
  }
261
+ case "install": {
262
+ const result = install(cwd, { env, onNote: (line) => stderr.write(`makersclaw: ${line}\n`) });
263
+ return { result: { dir: cwd, ...result }, text: installText(result) };
264
+ }
236
265
  case "diff": {
237
266
  const result = diff(cwd);
238
267
  return { result: { dir: cwd, ...result }, text: diffText(result) };
@@ -299,7 +328,7 @@ export function main(argv, { stdout = process.stdout, stderr = process.stderr, e
299
328
  try {
300
329
  opts = parseArgs(argv);
301
330
  if (opts.help && opts.command !== "help") opts = { ...opts, command: "help" };
302
- const { result, text } = run(opts);
331
+ const { result, text } = run(opts, { stderr, env });
303
332
  stdout.write(opts.json ? `${JSON.stringify({ ok: true, command: opts.command, ...result }, null, 2)}\n` : `${text}\n`);
304
333
  return 0;
305
334
  } catch (error) {
package/src/install.mjs CHANGED
@@ -6,6 +6,10 @@
6
6
  // block with the version it came from
7
7
  // check/pins.json sha256 of every fixed file, the template's and the
8
8
  // blocks' — `npm run check` refuses one that differs
9
+ // and a third says which package versions it installs:
10
+ // pnpm-lock.yaml cut from the release lock for this package.json
11
+ // (src/lockfile.mjs) by init, add and update; the
12
+ // install writes in what the release does not lock
9
13
  //
10
14
  // Everything this CLI writes is FIXED (ours: pinned, replaced by update),
11
15
  // DOCS (ours, not pinned), a STARTER (laid when missing, the app's from
@@ -15,6 +19,8 @@
15
19
  import { existsSync, readFileSync } from "node:fs";
16
20
  import { join } from "node:path";
17
21
  import { hashFile, readJson, removeFile, sha256, walk, writeFile, writeJson } from "./fsutil.mjs";
22
+ import { LOCKFILE, LockError, deriveLock, parseLock } from "./lockfile.mjs";
23
+ import { NPM_LOCKFILE, PNPM_VERSION, installDeps } from "./pm.mjs";
18
24
  import { BLOCK_DIR, loadBlocks, loadItems, loadTemplate, packageInfo, readmeOf, suggest, templateNames } from "./registry.mjs";
19
25
 
20
26
  export const MANIFEST = "makersclaw.json";
@@ -97,11 +103,60 @@ function mergePackage(app, tpl) {
97
103
  return { out, changes };
98
104
  }
99
105
 
106
+ const releaseLocks = new Map();
107
+ function releaseLock(tpl) {
108
+ if (!releaseLocks.has(tpl.lock)) releaseLocks.set(tpl.lock, parseLock(readFileSync(tpl.lock, "utf8")));
109
+ return releaseLocks.get(tpl.lock);
110
+ }
111
+
112
+ /**
113
+ * The app's pnpm-lock.yaml for `pkg`, cut from the template's release
114
+ * lock: { text, before, covered, carried, left, notes }, or null when the
115
+ * template ships no lock. The app's current lock lends what the release
116
+ * does not lock (src/lockfile.mjs says when); one this reader cannot take
117
+ * lends nothing, and the install resolves those packages again.
118
+ */
119
+ function cutLock(dir, tpl, pkg) {
120
+ if (!tpl.lock || !pkg) return null;
121
+ const path = join(dir, LOCKFILE);
122
+ const before = existsSync(path) ? readFileSync(path, "utf8") : null;
123
+ const notes = [];
124
+ let current = null;
125
+ if (before !== null) {
126
+ try {
127
+ current = parseLock(before);
128
+ } catch (error) {
129
+ if (!(error instanceof LockError)) throw error;
130
+ notes.push(`${LOCKFILE} could not be read (${error.message}) — cut again from the release lock`);
131
+ }
132
+ }
133
+ const cut = deriveLock(releaseLock(tpl), pkg, current);
134
+ // The install resolves what is left; where npm installed the app before,
135
+ // at package-lock.json's versions when they still fit (src/pm.mjs).
136
+ const one = cut.left.length === 1;
137
+ const npmPinned = existsSync(join(dir, NPM_LOCKFILE)) ? `, keeping ${NPM_LOCKFILE}'s version${one ? "" : "s"} where ${one ? "it fits" : "they fit"}` : "";
138
+ if (cut.left.length) notes.push(`${LOCKFILE}: ${cut.left.join(", ")} not in makersclaw ${version()}'s lock — the install resolves ${one ? "it" : "them"}${npmPinned}`);
139
+ return { ...cut, before, notes };
140
+ }
141
+
142
+ /** Write the cut when it differs; say so in `written`. */
143
+ function writeLock(dir, cut, written) {
144
+ if (!cut || cut.text === cut.before) return false;
145
+ writeFile(join(dir, LOCKFILE), cut.text);
146
+ written.push(LOCKFILE);
147
+ return true;
148
+ }
149
+
150
+ const lockSummary = (cut) => (cut ? { covered: cut.covered.length, carried: cut.carried, left: cut.left } : null);
151
+
100
152
  /** Paths a template may remove when a newer version stops shipping them:
101
- * its fixed files and the kit, parts and block folders. Anything else a
102
- * pins.json names is left alone — it is not ours to delete. */
153
+ * its fixed files, the ones it names as retired (middleware.js since
154
+ * 0.6.0: Next 16 fails a build that has it beside proxy.js), and the kit,
155
+ * parts and block folders. Anything else a pins.json names is left alone
156
+ * — it is not ours to delete. */
103
157
  function ownedPath(path, tpl) {
104
158
  if (/^components\/(?:ui|parts|blocks)\//.test(path) || /^lib\/[^/]+\.js$/.test(path)) return true;
159
+ if ((tpl.retired ?? []).includes(path)) return true;
105
160
  return tpl.files.some((f) => f.class === "fixed" && f.path === path);
106
161
  }
107
162
 
@@ -187,6 +242,11 @@ function lay(dir, tpl, before) {
187
242
  }
188
243
  }
189
244
 
245
+ // The lock last: package.json is final now.
246
+ const cut = cutLock(dir, tpl, readJson(join(dir, "package.json")));
247
+ const lockWritten = writeLock(dir, cut, written);
248
+ if (cut) notes.push(...cut.notes);
249
+
190
250
  for (const p of Object.keys(before.pins)) {
191
251
  if (p in pins) continue;
192
252
  if (p.startsWith(`${BLOCK_DIR}/`) && !(p.split("/")[2] in blocks)) continue;
@@ -210,7 +270,8 @@ function lay(dir, tpl, before) {
210
270
  kept,
211
271
  removed,
212
272
  package: pkg,
213
- install: fresh || pkg.some((c) => c.key !== "scripts"),
273
+ lock: lockSummary(cut),
274
+ install: fresh || lockWritten || pkg.some((c) => c.key !== "scripts"),
214
275
  pinned: Object.keys(pins).length,
215
276
  blocks: Object.keys(blocks),
216
277
  notes,
@@ -355,13 +416,19 @@ export function add(dir, names) {
355
416
  if (changes.length) writeJson(path, out);
356
417
  pkg = changes;
357
418
  }
419
+ // A block's packages come with their lock entries: the release resolved
420
+ // them with everything else, so the next install is frozen.
421
+ const cut = cutLock(dir, tpl, readJson(join(dir, "package.json")));
422
+ const lockWritten = writeLock(dir, cut, []);
358
423
  writeJson(join(dir, PINS), sortKeys(pins));
359
424
  writeJson(join(dir, MANIFEST), { ...manifest, blocks: sortKeys(manifest.blocks) });
360
425
  return {
361
426
  version: v,
362
427
  added,
363
428
  package: pkg,
364
- install: pkg.length > 0,
429
+ lock: cut ? { ...lockSummary(cut), written: lockWritten } : null,
430
+ notes: cut?.notes ?? [],
431
+ install: pkg.length > 0 || lockWritten,
365
432
  usage: order.filter((i) => i.type === "block" && names.includes(i.name)).map((i) => ({ name: i.name, readme: readmeOf(i) })),
366
433
  };
367
434
  }
@@ -464,6 +531,12 @@ export function diff(dir) {
464
531
  // …and the installed blocks' npm packages, which update lays with them.
465
532
  const blockDeps = Object.assign({}, ...Object.keys(manifest.blocks ?? {}).map((n) => known.find((b) => b.name === n)?.dependencies ?? {}));
466
533
  if (existsSync(pkgPath) && Object.keys(blockDeps).length) pkg.push(...mergePackage(readJson(pkgPath), { dependencies: blockDeps }).changes);
534
+ // …and the lock update would cut for the package.json it would leave.
535
+ if (existsSync(pkgPath) && tplPkg) {
536
+ const after = mergePackage(mergePackage(readJson(pkgPath), readJson(tplPkg.from)).out, { dependencies: blockDeps }).out;
537
+ const cut = cutLock(dir, tpl, after);
538
+ if (cut && cut.text !== cut.before) entries.push({ item: "template", path: LOCKFILE, status: cut.before === null ? "new" : "changed" });
539
+ }
467
540
  return {
468
541
  from: manifest.version,
469
542
  to: v,
@@ -473,3 +546,27 @@ export function diff(dir) {
473
546
  blocks: manifest.blocks ?? {},
474
547
  };
475
548
  }
549
+
550
+ /** `install` — the app's packages: pnpm from its lock, frozen when the
551
+ * lock names exactly package.json's dependencies (src/pm.mjs); npm when
552
+ * no pnpm runs, said in `notes` — but not when the registry did not
553
+ * answer, since npm would need it too. */
554
+ export function install(dir, { env = process.env, onNote } = {}) {
555
+ if (!existsSync(join(dir, "package.json"))) {
556
+ throw new CliError(`${dir} has no package.json — there is no app here`, "makersclaw init lays the template here");
557
+ }
558
+ const r = installDeps(dir, { env, onNote });
559
+ if (r.unreachable) {
560
+ throw new CliError(
561
+ `no pnpm on this machine, and npm could not fetch pnpm ${PNPM_VERSION}: the registry did not answer (${r.unreachable}). An npm install would need the same registry, so nothing was installed\n${r.log}`,
562
+ `name a pnpm ${PNPM_VERSION.split(".")[0]} in MAKERSCLAW_PNPM or put one on PATH, or install again once the registry answers`,
563
+ );
564
+ }
565
+ if (!r.ok) {
566
+ throw new CliError(
567
+ `${r.manager} install failed (exit ${r.code})${r.notes.length ? ` — ${r.notes.join("; ")}` : ""}${r.log ? `\n${r.log}` : ""}`,
568
+ r.manager === "pnpm" && r.frozen ? "a frozen install needs every package in the store or the registry" : null,
569
+ );
570
+ }
571
+ return r;
572
+ }