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.
- package/README.md +29 -3
- package/package.json +3 -2
- package/r/annotate.json +3 -3
- package/r/approval-request.json +2 -2
- package/r/audio-player.json +2 -2
- package/r/auth-form.json +2 -2
- package/r/board.json +2 -2
- package/r/calendar-view.json +3 -3
- package/r/cart.json +2 -2
- package/r/chart.json +2 -2
- package/r/chat.json +2 -2
- package/r/code-editor.json +2 -2
- package/r/comment-box.json +3 -3
- package/r/contact-section.json +2 -2
- package/r/csv-import.json +3 -3
- package/r/data-table.json +2 -2
- package/r/diagram.json +2 -2
- package/r/doc-editor.json +2 -2
- package/r/doc-page.json +3 -3
- package/r/email-render.json +2 -2
- package/r/faq.json +2 -2
- package/r/file-upload.json +2 -2
- package/r/flow-canvas.json +2 -2
- package/r/footer.json +2 -2
- package/r/gantt.json +3 -3
- package/r/job-panel.json +2 -2
- package/r/json-editor.json +3 -3
- package/r/map.json +2 -2
- package/r/menubar.json +2 -2
- package/r/mind-map.json +3 -3
- package/r/navigation-menu.json +2 -2
- package/r/order-detail.json +2 -2
- package/r/org-chart.json +3 -3
- package/r/page-builder.json +2 -2
- package/r/payment-methods.json +2 -2
- package/r/pdf-document.json +2 -2
- package/r/pdf-viewer.json +2 -2
- package/r/product-detail.json +2 -2
- package/r/product-grid.json +3 -3
- package/r/record-form.json +2 -2
- package/r/record-notes.json +4 -4
- package/r/registry.json +121 -121
- package/r/search-dialog.json +2 -2
- package/r/settings-list.json +2 -2
- package/r/setup-checklist.json +2 -2
- package/r/share-dialog.json +2 -2
- package/r/sidebar.json +2 -2
- package/r/signature-pad.json +2 -2
- package/r/sketch-canvas.json +2 -2
- package/r/spreadsheet.json +2 -2
- package/r/stat-cards.json +3 -3
- package/r/task-list.json +3 -3
- package/r/task-model.json +2 -2
- package/r/testimonials.json +2 -2
- package/r/transaction-list.json +2 -2
- package/r/whiteboard.json +3 -3
- package/src/cli.mjs +35 -6
- package/src/install.mjs +101 -4
- package/src/lockfile.mjs +468 -0
- package/src/pm.mjs +473 -0
- package/src/registry.mjs +48 -1
- package/templates/next/files/README.md +20 -15
- package/templates/next/files/app/claw-alive/route.js +2 -2
- package/templates/next/files/app/frame.js +6 -5
- package/templates/next/files/app/layout.jsx +2 -2
- package/templates/next/files/check/run.mjs +55 -14
- package/templates/next/files/lib/actions.js +1 -1
- package/templates/next/files/lib/data.js +1 -1
- package/templates/next/files/next.config.mjs +50 -8
- package/templates/next/files/package.json +3 -3
- package/templates/next/files/{middleware.js → proxy.js} +13 -6
- package/templates/next/pnpm-lock.yaml +5870 -0
- package/templates/next/template.json +5 -4
|
@@ -17,23 +17,37 @@
|
|
|
17
17
|
// npm run check -- --static static rules only
|
|
18
18
|
//
|
|
19
19
|
// The smoke test builds for itself, and only when a source file is newer
|
|
20
|
-
// than its last build. Where: in
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
// (
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
// preview
|
|
20
|
+
// than its last build. Where: in place when the app folder is writable,
|
|
21
|
+
// into `.next-check` (CLAW_DIST_DIR, next.config.mjs). Where it is not (a
|
|
22
|
+
// sandbox tree made `2755` before claw opened app trees to its `claw`
|
|
23
|
+
// group, tree-access.ts), the sources are copied to a folder of its own
|
|
24
|
+
// (`~/.claw-check/<app>`, node_modules symlinked back) and built there.
|
|
25
|
+
//
|
|
26
|
+
// Never into `.next`: it is not the check's. In a working copy it is the
|
|
27
|
+
// preview dev server's; in a live app it holds the production build the
|
|
28
|
+
// platform made and serves, and whose .next/BUILD_ID it reads as proof of
|
|
29
|
+
// a build. The founder's live preview keeps running, untouched, while the
|
|
30
|
+
// check runs beside it. What Next 16 changed (16.3.7, 2026-09-29): `next
|
|
31
|
+
// dev` keeps its own files in `.next/dev`, and a build by the same user
|
|
32
|
+
// beside a running dev server works and leaves `dev/` alone. Under claw's
|
|
33
|
+
// umask 002 a `.next` the dev server makes is 775, so the EACCES on
|
|
34
|
+
// .next/trace that Next 15 hit across users should not happen in today's
|
|
35
|
+
// sandbox (not tried with two Linux users). It comes back wherever the
|
|
36
|
+
// builder cannot write `.next` (`chmod 555` on it: EACCES on .next/trace),
|
|
37
|
+
// which is where one Linux user per app, claw's planned walls, leads.
|
|
38
|
+
//
|
|
39
|
+
// A copy's node_modules is a symlink back to the app's, and Turbopack
|
|
40
|
+
// reads nothing outside its root, so the copy's build is told a root
|
|
41
|
+
// that holds both (CLAW_TURBOPACK_ROOT, commonRoot below).
|
|
28
42
|
//
|
|
29
43
|
// Output is meant to be read by the platform agent in one glance: keep
|
|
30
44
|
// it under twenty lines, name file:line, say what to do instead.
|
|
31
45
|
|
|
32
|
-
import { accessSync, constants, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, symlinkSync } from "node:fs";
|
|
46
|
+
import { accessSync, constants, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, symlinkSync } from "node:fs";
|
|
33
47
|
import { createHash } from "node:crypto";
|
|
34
48
|
import { spawn, spawnSync } from "node:child_process";
|
|
35
49
|
import { createServer } from "node:net";
|
|
36
|
-
import { basename, dirname, join, relative } from "node:path";
|
|
50
|
+
import { basename, dirname, join, relative, sep } from "node:path";
|
|
37
51
|
import { homedir, tmpdir } from "node:os";
|
|
38
52
|
import { fileURLToPath } from "node:url";
|
|
39
53
|
|
|
@@ -47,8 +61,11 @@ const STATIC_ONLY = process.argv.includes("--static");
|
|
|
47
61
|
// `kit` rule refuses it (a shared piece goes in components/, a picture in
|
|
48
62
|
// components/depictions/). The list is the template's; `makersclaw
|
|
49
63
|
// update` lays both folders again.
|
|
50
|
-
// Exact names AND extensions:
|
|
51
|
-
//
|
|
64
|
+
// Exact names AND extensions: a file of the same name with an extension
|
|
65
|
+
// the bundler tries first wins unseen. Next 15's webpack tried .js before
|
|
66
|
+
// .jsx (a components/ui/depiction.js beside depiction.jsx won); Next 16's
|
|
67
|
+
// Turbopack tries .jsx before .js (seen on 16.3.7), so the kit's own file
|
|
68
|
+
// wins there, but the rule holds for every bundler.
|
|
52
69
|
const KIT = /^components\/(?:ui\/(?:cx|index)\.js|ui\/(?:radio|toggle|button-group|avatar|breadcrumb|pagination|button|collapsible|item|table|depiction|feedback|stat|distribution|swatch|steps|separator|scroll-area|field|icon|menu|context-menu|popover|calendar|date-picker|tooltip|notice|sheet|tabs|slider|input-group|image|file-input|input-otp|command|combobox|rating|toast|carousel|resizable)\.jsx|parts\/(?:index|sample)\.js|parts\/(?:fixture|record-switcher|live-work)\.jsx)$/;
|
|
53
70
|
|
|
54
71
|
// The pins: sha256 of every fixed file, written by `makersclaw init` and
|
|
@@ -104,7 +121,7 @@ const SKIP = [
|
|
|
104
121
|
/^app\/frame\.js$/,
|
|
105
122
|
/^app\/claw-alive\/route\.js$/,
|
|
106
123
|
/^app\/s\/\[key\]\/page\.jsx$/,
|
|
107
|
-
/^
|
|
124
|
+
/^proxy\.js$/,
|
|
108
125
|
/^next\.config\.mjs$/,
|
|
109
126
|
/^postcss\.config\.mjs$/,
|
|
110
127
|
/^public\//,
|
|
@@ -344,6 +361,13 @@ const surfaceKeys = [];
|
|
|
344
361
|
if (e.isFile() && /^(?:ui|parts|depictions|blocks)\.[^.]+$/.test(e.name)) L.hit(`components/${e.name}`, "shadow", `a file beside the components/${e.name.replace(/\..*$/, "")}/ folder wins module resolution over it; delete it`);
|
|
345
362
|
}
|
|
346
363
|
}
|
|
364
|
+
// Next 16 runs proxy.js (fixed) before every request. A middleware file
|
|
365
|
+
// beside it, the name Next 15 used, fails the build; alone it would run
|
|
366
|
+
// in the token check's place. `makersclaw update` removes the template's
|
|
367
|
+
// own from 0.5.x.
|
|
368
|
+
for (const e of existsSync(ROOT) ? readdirSync(ROOT) : []) {
|
|
369
|
+
if (/^(?:middleware|proxy)\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/.test(e) && e !== "proxy.js") L.hit(e, "proxy", `Next 16 runs proxy.js, the template's fixed token check; delete ${e}`);
|
|
370
|
+
}
|
|
347
371
|
// check/ is this script and its pins; a module hidden there is bundled
|
|
348
372
|
// by Next and read by no rule.
|
|
349
373
|
if (existsSync(join(ROOT, "check"))) {
|
|
@@ -656,6 +680,18 @@ function buildSite() {
|
|
|
656
680
|
return { dir: join(home, ".claw-check", name), dist: ".next", copied: true };
|
|
657
681
|
}
|
|
658
682
|
|
|
683
|
+
/** The nearest folder holding both paths, by their real paths ("/" at
|
|
684
|
+
* worst). A copy's build reads node_modules through a symlink back to the
|
|
685
|
+
* app, and Turbopack reads nothing outside its root: the check hands it
|
|
686
|
+
* this folder as the root (CLAW_TURBOPACK_ROOT, next.config.mjs). */
|
|
687
|
+
function commonRoot(a, b) {
|
|
688
|
+
const x = realpathSync(a).split(sep);
|
|
689
|
+
const y = realpathSync(b).split(sep);
|
|
690
|
+
let i = 0;
|
|
691
|
+
while (i < x.length && i < y.length && x[i] === y[i]) i++;
|
|
692
|
+
return x.slice(0, i).join(sep) || sep;
|
|
693
|
+
}
|
|
694
|
+
|
|
659
695
|
/** Copy the app's sources (never node_modules or a build) to `dir`, and
|
|
660
696
|
* point its node_modules back at the app's. */
|
|
661
697
|
function copySources(dir) {
|
|
@@ -693,7 +729,12 @@ function buildForCheck(site, env) {
|
|
|
693
729
|
async function smoke() {
|
|
694
730
|
const site = buildSite();
|
|
695
731
|
const base = { ...process.env, ...dotenv(join(ROOT, ".env")), NODE_ENV: "production", HOSTNAME: "127.0.0.1", CLAW_DIST_DIR: site.dist };
|
|
696
|
-
delete base.
|
|
732
|
+
delete base.CLAW_TURBOPACK_ROOT;
|
|
733
|
+
if (site.copied) {
|
|
734
|
+
mkdirSync(site.dir, { recursive: true });
|
|
735
|
+
base.CLAW_TURBOPACK_ROOT = commonRoot(site.dir, ROOT);
|
|
736
|
+
}
|
|
737
|
+
delete base.CLAW_PRODUCT_TOKEN; // the check is not the product proxy; proxy.js would 401 it
|
|
697
738
|
const built = buildForCheck(site, base);
|
|
698
739
|
if (!built.ok) {
|
|
699
740
|
fail("smoke", "build", `next build failed:\n${built.tail}`);
|
|
@@ -10,7 +10,7 @@ import { ident, logActivity, query } from "./db";
|
|
|
10
10
|
// are quoted through ident(), which refuses anything that is not a plain
|
|
11
11
|
// identifier. Returns { ok } or { ok: false, error }; never throws.
|
|
12
12
|
//
|
|
13
|
-
// `surface` is optional:
|
|
13
|
+
// `surface` is optional: proxy.js stamps the current surface key on
|
|
14
14
|
// the request, so a surface rarely needs to pass it.
|
|
15
15
|
//
|
|
16
16
|
// `detail` is the founder's sentence for the row. The OS Activity tab
|
|
@@ -160,7 +160,7 @@ export async function loadActivity({ limit = 100, surface, since } = {}) {
|
|
|
160
160
|
* code keeps one import. */
|
|
161
161
|
export { markSample };
|
|
162
162
|
|
|
163
|
-
/** The surface key of the current request (
|
|
163
|
+
/** The surface key of the current request (proxy.js sets it from
|
|
164
164
|
* /s/<key>), unless the caller names one — a string, or the page's
|
|
165
165
|
* `surface` object. */
|
|
166
166
|
export async function currentSurface(explicit) {
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
// attribute app/layout.jsx renders is the runtime copy and is read first, so
|
|
8
8
|
// a start under a different prefix than the build still resolves.
|
|
9
9
|
//
|
|
10
|
-
// allowedOrigins is NOT optional here, and it is not yours to edit. Next
|
|
11
|
-
// refuses a Server Action whose `Origin` header disagrees with
|
|
10
|
+
// allowedOrigins is NOT optional here, and it is not yours to edit. Next
|
|
11
|
+
// (15 and 16) refuses a Server Action whose `Origin` header disagrees with
|
|
12
12
|
// `x-forwarded-host` — and in this stack they always disagree, because the
|
|
13
13
|
// sandbox ingress rewrites `x-forwarded-host` to its own vercel.run name
|
|
14
14
|
// while the browser is on the product host. Without this the app loads
|
|
@@ -23,19 +23,61 @@ const allowedOrigins = (process.env.CLAW_ALLOWED_ORIGINS || "")
|
|
|
23
23
|
.map((o) => o.trim())
|
|
24
24
|
.filter(Boolean);
|
|
25
25
|
|
|
26
|
+
// The same hosts, for `next dev` alone. Next 16 refuses a request for a
|
|
27
|
+
// dev resource (/_next/*, /__nextjs*: the HMR socket, the error overlay's
|
|
28
|
+
// lookups) whose Origin host is not localhost or listed here; Next 15 only
|
|
29
|
+
// warned. The preview's browser is on the product host, so without this
|
|
30
|
+
// every such request answers 403. Hostnames only: Next compares no port.
|
|
31
|
+
const allowedDevOrigins = [
|
|
32
|
+
...new Set(
|
|
33
|
+
allowedOrigins
|
|
34
|
+
.map((o) => o.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "").replace(/\/.*$/, "").replace(/:\d+$/, "").toLowerCase())
|
|
35
|
+
.filter(Boolean),
|
|
36
|
+
),
|
|
37
|
+
];
|
|
38
|
+
|
|
26
39
|
// `npm run check` builds into its own folder (CLAW_DIST_DIR=.next-check,
|
|
27
|
-
// check/run.mjs) so it never touches `.next
|
|
28
|
-
//
|
|
29
|
-
//
|
|
40
|
+
// check/run.mjs) so it never touches `.next`, which is not the check's:
|
|
41
|
+
// in a working copy it is the dev server's, and in a live app it holds
|
|
42
|
+
// the production build the platform made, serves and reads as its proof
|
|
43
|
+
// (.next/BUILD_ID). check/run.mjs says more.
|
|
44
|
+
//
|
|
45
|
+
// CLAW_TURBOPACK_ROOT is set by `npm run check` alone, when it builds a
|
|
46
|
+
// copy of an app folder it cannot write (check/run.mjs buildSite). The
|
|
47
|
+
// copy's node_modules is a symlink back to the app's, and Turbopack (Next
|
|
48
|
+
// 16's bundler for build as well as dev) refuses a symlink that leaves its
|
|
49
|
+
// root: "Symlink [project]/node_modules is invalid, it points out of the
|
|
50
|
+
// filesystem root". The check names the nearest folder holding both.
|
|
51
|
+
// Unset, Turbopack finds the root itself.
|
|
52
|
+
const turbopackRoot = process.env.CLAW_TURBOPACK_ROOT || "";
|
|
53
|
+
|
|
54
|
+
// agentRules: false. Next 16's `next dev` writes AGENTS.md and CLAUDE.md
|
|
55
|
+
// into the app folder when it sees an AI agent in its environment
|
|
56
|
+
// (AI_AGENT, CLAUDECODE…), telling the agent to read Next's own docs.
|
|
57
|
+
// This app's agent brief is the platform's, beside the app, and the app
|
|
58
|
+
// folder holds only what the template and the app's own screens put there.
|
|
59
|
+
//
|
|
60
|
+
// mcpServer: false. Next 16's `next dev` also serves an MCP endpoint at
|
|
61
|
+
// /_next/mcp (the app's routes, logs and errors, the errors of every
|
|
62
|
+
// browser on the page, a route compile) and answers it before proxy.js
|
|
63
|
+
// runs, so no product token guards it. Off: the token check is meant to
|
|
64
|
+
// be the preview's only door. One more answers there that no setting
|
|
65
|
+
// turns off, the dev overlay's /__nextjs_attach-nodejs-inspector (it
|
|
66
|
+
// opens a Node debugger on loopback); only the platform can wall that
|
|
67
|
+
// (CHANGELOG, 0.6.0).
|
|
30
68
|
const nextConfig = {
|
|
31
69
|
basePath: process.env.CLAW_BASE_PATH || "",
|
|
32
70
|
distDir: process.env.CLAW_DIST_DIR || ".next",
|
|
33
71
|
env: {
|
|
34
72
|
CLAW_BASE_PATH: process.env.CLAW_BASE_PATH || "",
|
|
35
73
|
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
74
|
+
agentRules: false,
|
|
75
|
+
...(allowedDevOrigins.length > 0 ? { allowedDevOrigins } : {}),
|
|
76
|
+
...(turbopackRoot ? { turbopack: { root: turbopackRoot }, outputFileTracingRoot: turbopackRoot } : {}),
|
|
77
|
+
experimental: {
|
|
78
|
+
mcpServer: false,
|
|
79
|
+
...(allowedOrigins.length > 0 ? { serverActions: { allowedOrigins } } : {}),
|
|
80
|
+
},
|
|
39
81
|
};
|
|
40
82
|
|
|
41
83
|
export default nextConfig;
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@tailwindcss/postcss": "^4",
|
|
13
|
-
"next": "^
|
|
13
|
+
"next": "^16.3.7",
|
|
14
14
|
"pg": "^8.16.0",
|
|
15
|
-
"react": "^19.
|
|
16
|
-
"react-dom": "^19.
|
|
15
|
+
"react": "^19.3.0",
|
|
16
|
+
"react-dom": "^19.3.0",
|
|
17
17
|
"tailwindcss": "^4"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
3
|
+
// Next runs this before every request. Until 0.6.0 it was middleware.js
|
|
4
|
+
// (Next 15's name for it); Next 16 renamed the file and its export to
|
|
5
|
+
// `proxy`, and runs it on Node, never the edge runtime. A middleware.js
|
|
6
|
+
// beside this file fails the build, so `makersclaw update` removes the old
|
|
7
|
+
// one. Not to be confused with the product proxy, the Makersclaw dashboard
|
|
8
|
+
// door that sits in front of the whole app.
|
|
9
|
+
//
|
|
10
|
+
// The only door is that product proxy, which stamps this token on every
|
|
11
|
+
// request. The sandbox port itself is public, so without this check
|
|
12
|
+
// anyone with the URL could read the founder's data.
|
|
6
13
|
//
|
|
7
14
|
// It also tells the server which surface a request is for: /s/<key> becomes
|
|
8
15
|
// the x-claw-surface request header, so lib/data.js and lib/actions.js can
|
|
@@ -13,12 +20,12 @@ import { NextResponse } from "next/server";
|
|
|
13
20
|
// the desk, and the product proxy carries it as the x-claw-theme header
|
|
14
21
|
// on every later request (the browser's cookies never reach the app).
|
|
15
22
|
// ?theme= on any URL wins for that request and sets the claw_theme cookie
|
|
16
|
-
// too, so the app keeps its theme when run without the proxy
|
|
17
|
-
// `next dev`). app/layout.jsx reads header, then cookie, onto
|
|
23
|
+
// too, so the app keeps its theme when run without the product proxy
|
|
24
|
+
// (local `next dev`). app/layout.jsx reads header, then cookie, onto
|
|
18
25
|
// <html data-theme>.
|
|
19
26
|
const THEMES = new Set(["light", "dark"]);
|
|
20
27
|
|
|
21
|
-
export function
|
|
28
|
+
export function proxy(request) {
|
|
22
29
|
const expected = process.env.CLAW_PRODUCT_TOKEN;
|
|
23
30
|
if (expected && request.headers.get("x-claw-product-token") !== expected) {
|
|
24
31
|
return new NextResponse("Open this app from your Makersclaw dashboard.", {
|