makersclaw 0.6.0 → 0.8.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 +56 -9
- package/package.json +1 -1
- 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 +6 -6
- 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 +10 -4
- 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 +126 -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 +3 -3
- 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 +24 -12
- 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/chart/cartesian.jsx +1 -1
- package/registry/blocks/chart/core.jsx +33 -23
- package/registry/blocks/chart/pie.jsx +1 -1
- package/registry/blocks/chat/README.md +47 -14
- package/registry/blocks/chat/demo.jsx +2 -2
- 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 +30 -12
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1 -1
- package/registry/blocks/footer/README.md +7 -4
- 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 +20 -7
- package/registry/blocks/org-chart/README.md +14 -9
- package/registry/blocks/page-builder/README.md +14 -7
- package/registry/blocks/page-builder/demo.jsx +3 -3
- 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 +26 -21
- 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/sidebar/README.md +23 -13
- package/registry/blocks/signature-pad/README.md +15 -4
- package/registry/blocks/sketch-canvas/README.md +25 -10
- 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 +34 -22
- package/src/cli.mjs +33 -6
- package/src/install.mjs +285 -26
- package/src/registry.mjs +109 -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 +1100 -89
- package/templates/next/files/app/frame.js +128 -4
- package/templates/next/files/app/shell.jsx +54 -37
- package/templates/next/files/check/run.mjs +1514 -45
- package/templates/next/files/components/ui/index.js +1 -0
- package/templates/next/files/components/ui/item.jsx +2 -2
- package/templates/next/files/components/ui/layout.jsx +307 -0
- 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 +170 -51
- 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 +15 -1
- package/templates/next/files/lib/data.js +119 -29
- package/templates/next/files/lib/db.js +97 -17
- package/templates/next/files/lib/door.js +680 -0
- package/templates/next/files/lib/hooks.js +71 -2
- package/templates/next/files/lib/platform.js +93 -4
- package/templates/next/files/next.config.mjs +36 -2
- package/templates/next/files/surfaces.js +3 -2
- package/templates/next/template.json +18 -3
- package/templates/next/files/schema.sql +0 -22
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { claw, publishDesk, publishStatus } from "./claw";
|
|
5
|
-
import { ask, cancelJob, openRequest, requests as readRequests, startJob, stopRequest } from "./platform";
|
|
5
|
+
import { ask, cancelJob, llm, openRequest, requests as readRequests, startJob, stopRequest } from "./platform";
|
|
6
6
|
|
|
7
7
|
// The React side of the _claw API, without any look: fetching, polling,
|
|
8
8
|
// streaming and cleanup. A surface renders what comes back and owns every
|
|
@@ -17,7 +17,9 @@ import { ask, cancelJob, openRequest, requests as readRequests, startJob, stopRe
|
|
|
17
17
|
// a request: the conversation lives in the desk's agent column, and the
|
|
18
18
|
// app follows only its status. `useRequests` is the same requests seen
|
|
19
19
|
// from a surface: the asks in flight on this app, so an empty table can
|
|
20
|
-
// show the work coming instead of a blank.
|
|
20
|
+
// show the work coming instead of a blank. `useLlm` (0.8.0) is neither:
|
|
21
|
+
// one call to a model, answered in the page, for text work on what the
|
|
22
|
+
// screen holds — nothing to follow, nothing on the desk.
|
|
21
23
|
//
|
|
22
24
|
// While the gateway has no _claw routes yet (`unavailable`), polls back
|
|
23
25
|
// off to once a minute so a preview that is still being wired does not
|
|
@@ -672,3 +674,70 @@ export function useJob() {
|
|
|
672
674
|
|
|
673
675
|
return { ...state, start, cancel, reset, open };
|
|
674
676
|
}
|
|
677
|
+
|
|
678
|
+
/** What useLlm shows with no call in flight and nothing to show. */
|
|
679
|
+
const QUIET = { loading: false, result: null, error: null, unavailable: false };
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* One model call from a component (lib/platform.js, llm). `run(input,
|
|
683
|
+
* opts)` takes llm()'s arguments and resolves llm()'s answer, so a caller
|
|
684
|
+
* that needs the refusal's `code` reads it there; the state is for the
|
|
685
|
+
* screen:
|
|
686
|
+
*
|
|
687
|
+
* loading a call is out
|
|
688
|
+
* result the answer when it was ok: { ok: true, text } or { ok: true,
|
|
689
|
+
* data } (null while loading and after a failure)
|
|
690
|
+
* error the failure's words (null while loading, after an answer,
|
|
691
|
+
* and on a claw with no door)
|
|
692
|
+
* unavailable the platform has no model door yet (a claw from before
|
|
693
|
+
* it) or there is no network: show the quiet "not connected
|
|
694
|
+
* yet", as for useClaw's `unavailable`. Then `error` stays
|
|
695
|
+
* null, so a refusal and a missing door are never both set
|
|
696
|
+
*
|
|
697
|
+
* A run supersedes the one before it: that one is aborted, resolves
|
|
698
|
+
* { ok: false, aborted: true } and changes nothing, so a slow answer never
|
|
699
|
+
* lands over a newer one. The hook owns the signal (one in opts is
|
|
700
|
+
* replaced). Unmounting aborts the call in flight. Nothing is called until
|
|
701
|
+
* `run` is.
|
|
702
|
+
*
|
|
703
|
+
* const { run, loading, result, error, unavailable } = useLlm();
|
|
704
|
+
* run(`Translate to French: ${text}`, { task: "translate" });
|
|
705
|
+
* …{loading ? <Spinner /> : result?.text}
|
|
706
|
+
*/
|
|
707
|
+
export function useLlm() {
|
|
708
|
+
const [state, setState] = useState(QUIET);
|
|
709
|
+
const abortRef = useRef(null);
|
|
710
|
+
const runRef = useRef(0); // the run that owns the state
|
|
711
|
+
const aliveRef = useRef(true);
|
|
712
|
+
|
|
713
|
+
// React runs this cleanup and mounts the hook again in development (its
|
|
714
|
+
// double mount; a fast refresh does the same): a call cut off by that
|
|
715
|
+
// cleanup is closed quietly in run(), below, once the answer comes back.
|
|
716
|
+
useEffect(() => {
|
|
717
|
+
aliveRef.current = true;
|
|
718
|
+
return () => {
|
|
719
|
+
aliveRef.current = false;
|
|
720
|
+
abortRef.current?.abort();
|
|
721
|
+
};
|
|
722
|
+
}, []);
|
|
723
|
+
|
|
724
|
+
const run = useCallback(async (input, opts) => {
|
|
725
|
+
abortRef.current?.abort();
|
|
726
|
+
const controller = new AbortController();
|
|
727
|
+
abortRef.current = controller;
|
|
728
|
+
const mine = ++runRef.current;
|
|
729
|
+
setState({ loading: true, result: null, error: null, unavailable: false });
|
|
730
|
+
const answer = await llm(input, { ...opts, signal: controller.signal });
|
|
731
|
+
if (runRef.current !== mine || !aliveRef.current) return answer; // a newer run owns the state, or the page is gone
|
|
732
|
+
if (controller.signal.aborted) {
|
|
733
|
+
setState(QUIET); // cut off by an unmount the hook came back from, with nothing started since
|
|
734
|
+
return answer;
|
|
735
|
+
}
|
|
736
|
+
if (answer.ok) setState({ loading: false, result: answer, error: null, unavailable: false });
|
|
737
|
+
else if (answer.unavailable) setState({ loading: false, result: null, error: null, unavailable: true });
|
|
738
|
+
else setState({ loading: false, result: null, error: answer.error || "the model did not answer", unavailable: false });
|
|
739
|
+
return answer;
|
|
740
|
+
}, []);
|
|
741
|
+
|
|
742
|
+
return { ...state, run };
|
|
743
|
+
}
|
|
@@ -8,7 +8,9 @@ import { claw, clawBasePath, clawStream, openInDesk, publishDesk, reportError }
|
|
|
8
8
|
// unavailable, code? }; nothing throws. `unavailable: true` (404 or no
|
|
9
9
|
// network) means the gateway has no such route yet — render a quiet "not
|
|
10
10
|
// connected yet" state, not an error. `code` names a refusal a caller
|
|
11
|
-
// can act on (`not_your_thread`, `needs_answer`, `queue_full`).
|
|
11
|
+
// can act on (`not_your_thread`, `needs_answer`, `queue_full`). `llm` is
|
|
12
|
+
// the one that resolves the platform's answer as it is — { ok: true, text }
|
|
13
|
+
// or { ok: true, data } — with no { status, data } around it.
|
|
12
14
|
//
|
|
13
15
|
// What lives here: who the app is (`me`), the error relay
|
|
14
16
|
// (`reportError`), and ASKING — a screen asks its agent for work with a
|
|
@@ -20,8 +22,12 @@ import { claw, clawBasePath, clawStream, openInDesk, publishDesk, reportError }
|
|
|
20
22
|
// Activity as tabs on the window, and nothing here lists chats, runs or
|
|
21
23
|
// activity. `startJob` / `cancelJob` are the 0.3.x door to the same work,
|
|
22
24
|
// streamed into the app; they stay for a claw that has no _claw/ask yet.
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
+
// And CALLING A MODEL (0.8.0): `llm` is one shot of text work on what is
|
|
26
|
+
// on screen — sort these, draft that, translate this — answered in the
|
|
27
|
+
// page, with no thread, no tools and no request on the desk. It is the
|
|
28
|
+
// opposite of `ask`, which hands work to the app's agent. `claw(path,
|
|
29
|
+
// opts)` and `clawStream` in lib/claw.js are the generic doors for the
|
|
30
|
+
// rest of §5.
|
|
25
31
|
|
|
26
32
|
/** GET _claw/me → { artifact: { id, name, vehicle, status, home },
|
|
27
33
|
* user: { id, email }, blueprint, desk_origin } */
|
|
@@ -150,8 +156,91 @@ export function cancelJob(sessionId) {
|
|
|
150
156
|
return claw("cancel", { method: "POST", body: { session_id: sessionId } });
|
|
151
157
|
}
|
|
152
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Call a model: POST _claw/llm. One shot of text work on what the screen
|
|
161
|
+
* holds — sort, draft, translate, summarise, pull a field out — answered
|
|
162
|
+
* here and now. Work that needs tools, the workspace or more than one
|
|
163
|
+
* step is `ask()`'s: that is the app's agent. The app never names a model
|
|
164
|
+
* (`tier` picks the size) and never holds a key; the platform meters the
|
|
165
|
+
* call to the member who made it.
|
|
166
|
+
*
|
|
167
|
+
* input what to work on: a string, or a conversation, [{ role:
|
|
168
|
+
* "user" | "assistant", content }] — at most 100 messages,
|
|
169
|
+
* none empty, the last one the user's (required)
|
|
170
|
+
* system how to go about it (at most 8,000 characters)
|
|
171
|
+
* schema a JSON Schema for the answer (an object, at most 16 KB
|
|
172
|
+
* serialised): the answer comes back as `data`, checked
|
|
173
|
+
* against it, not as `text`. A miss is sent back to the
|
|
174
|
+
* model once; a second is `schema_mismatch`. No `pattern`,
|
|
175
|
+
* `patternProperties`, `$ref`, `$defs` or `definitions`
|
|
176
|
+
* (bad_input); nesting at most 20 levels (bad_input); at
|
|
177
|
+
* most 1,000 parts, each object, `enum` value and listed
|
|
178
|
+
* type (too_large). A reply too large to check against the
|
|
179
|
+
* schema is a miss. `data` keeps keys the schema does not
|
|
180
|
+
* name
|
|
181
|
+
* maxTokens the answer's ceiling, a whole number (default 1,024; over
|
|
182
|
+
* 4,096 is cut to 4,096). Sent as `max_tokens`
|
|
183
|
+
* tier "fast" (the default) or "smart", for the harder job
|
|
184
|
+
* task a short label for the usage line, /^[a-z0-9-]{1,40}$/
|
|
185
|
+
* signal an AbortSignal (an abort resolves { ok: false, aborted:
|
|
186
|
+
* true })
|
|
187
|
+
*
|
|
188
|
+
* → { ok: true, text } no schema
|
|
189
|
+
* { ok: true, data } with a schema
|
|
190
|
+
* { ok: false, error, code } a refusal, passed through as the platform
|
|
191
|
+
* sent it (`status` and `unavailable: false` come with it). `code` is
|
|
192
|
+
* one of, with its status:
|
|
193
|
+
* for the member (show `error` as it is) —
|
|
194
|
+
* no_credits 402 (the workspace wallet, a suspension, or the
|
|
195
|
+
* Free plan's daily limit), member_cap 402 (the member's monthly
|
|
196
|
+
* cap), app_cap 402 (the app's weekly cap), rate_limited 429
|
|
197
|
+
* (30 calls a minute per member), model_failed 502, timeout 504
|
|
198
|
+
* (60 s, a schema retry included; a call the clock cuts is still
|
|
199
|
+
* charged), try_again 503, failed 500, no_member_identity 401,
|
|
200
|
+
* not_a_member 403;
|
|
201
|
+
* for the developer (`error` is not for the member) —
|
|
202
|
+
* bad_input 400, too_large 413 (the body over 128 KB, or a field
|
|
203
|
+
* over its cap), schema_mismatch 422, cross_origin 403,
|
|
204
|
+
* not_configured 503
|
|
205
|
+
* { ok: false, unavailable: true } a claw from before this door (a 404
|
|
206
|
+
* that names no refusal) or no network: render a quiet "not
|
|
207
|
+
* connected yet", as for every door
|
|
208
|
+
*
|
|
209
|
+
* Nothing throws. An empty input asks nothing of the platform.
|
|
210
|
+
*/
|
|
211
|
+
export async function llm(input, opts) {
|
|
212
|
+
const { system, schema, maxTokens, tier, task, signal } = opts ?? {};
|
|
213
|
+
const said = typeof input === "string" ? input.trim() !== "" : Array.isArray(input) && input.length > 0;
|
|
214
|
+
if (!said) return refused("nothing to send");
|
|
215
|
+
const body = {
|
|
216
|
+
input,
|
|
217
|
+
system: typeof system === "string" && system ? system : undefined,
|
|
218
|
+
schema: schema && typeof schema === "object" ? schema : undefined,
|
|
219
|
+
max_tokens: typeof maxTokens === "number" ? maxTokens : undefined,
|
|
220
|
+
tier: tier || undefined,
|
|
221
|
+
task: task || undefined,
|
|
222
|
+
};
|
|
223
|
+
// claw() would read a body it cannot serialise as "not reachable".
|
|
224
|
+
try {
|
|
225
|
+
JSON.stringify(body);
|
|
226
|
+
} catch {
|
|
227
|
+
return refused("that cannot be sent as JSON");
|
|
228
|
+
}
|
|
229
|
+
const r = await claw("llm", { method: "POST", body, signal });
|
|
230
|
+
if (!r.ok) return r;
|
|
231
|
+
const answer = r.data;
|
|
232
|
+
if (answer && typeof answer === "object" && !Array.isArray(answer) && typeof answer.ok === "boolean") return answer;
|
|
233
|
+
return { ok: false, status: r.status, error: "the platform answered something unexpected", unavailable: false };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** What llm() resolves for an input it will not send: the platform's own
|
|
237
|
+
* word for it, with no request made. */
|
|
238
|
+
function refused(error) {
|
|
239
|
+
return { ok: false, status: 0, error, code: "bad_input", unavailable: false };
|
|
240
|
+
}
|
|
241
|
+
|
|
153
242
|
export { reportError };
|
|
154
243
|
|
|
155
|
-
export const platform = { me, ask, requests, stopRequest, openRequest, surfaceOfPath, startJob, cancelJob, reportError };
|
|
244
|
+
export const platform = { me, ask, llm, requests, stopRequest, openRequest, surfaceOfPath, startJob, cancelJob, reportError };
|
|
156
245
|
|
|
157
246
|
export default platform;
|
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
// The app's mode, from its manifest (makersclaw.json, beside this file).
|
|
4
|
+
// A browser app builds to files (output: "export"): the platform serves
|
|
5
|
+
// them, and its data door answers their reads and writes. A server app
|
|
6
|
+
// runs `next start`. Absent or unreadable is a server app, as every app
|
|
7
|
+
// before 0.7.0 is (none has a `mode`); only the exact word "browser"
|
|
8
|
+
// makes an export. `makersclaw mode` is what changes the key, never an
|
|
9
|
+
// edit here.
|
|
10
|
+
function mode() {
|
|
11
|
+
try {
|
|
12
|
+
const m = JSON.parse(readFileSync(new URL("./makersclaw.json", import.meta.url), "utf8"));
|
|
13
|
+
return m && m.mode === "browser" ? "browser" : "server";
|
|
14
|
+
} catch {
|
|
15
|
+
return "server";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const BROWSER = mode() === "browser";
|
|
19
|
+
|
|
1
20
|
// The dashboard reaches this app at /p/<label>/ through the workspace proxy,
|
|
2
21
|
// so every link and asset must carry that prefix. product_run sets
|
|
3
22
|
// CLAW_BASE_PATH at build AND start time; leave it unset to run at /.
|
|
@@ -17,7 +36,8 @@
|
|
|
17
36
|
// (src/lib/products.ts productAllowedOrigins): the product's own FQDN in
|
|
18
37
|
// production, the dashboard's dev origin under a path prefix. Hardcoding a
|
|
19
38
|
// localhost origin here ships an app that works in dev and refuses every
|
|
20
|
-
// write in production.
|
|
39
|
+
// write in production. A browser app has no Server Actions, so it takes
|
|
40
|
+
// none: its writes go to the platform's data door (lib/door.js).
|
|
21
41
|
const allowedOrigins = (process.env.CLAW_ALLOWED_ORIGINS || "")
|
|
22
42
|
.split(",")
|
|
23
43
|
.map((o) => o.trim())
|
|
@@ -28,6 +48,8 @@ const allowedOrigins = (process.env.CLAW_ALLOWED_ORIGINS || "")
|
|
|
28
48
|
// lookups) whose Origin host is not localhost or listed here; Next 15 only
|
|
29
49
|
// warned. The preview's browser is on the product host, so without this
|
|
30
50
|
// every such request answers 403. Hostnames only: Next compares no port.
|
|
51
|
+
// Both modes: a browser app still previews on `next dev` while it is
|
|
52
|
+
// built, so CLAW_ALLOWED_ORIGINS stays its preview's rule.
|
|
31
53
|
const allowedDevOrigins = [
|
|
32
54
|
...new Set(
|
|
33
55
|
allowedOrigins
|
|
@@ -42,6 +64,12 @@ const allowedDevOrigins = [
|
|
|
42
64
|
// the production build the platform made, serves and reads as its proof
|
|
43
65
|
// (.next/BUILD_ID). check/run.mjs says more.
|
|
44
66
|
//
|
|
67
|
+
// Under output: "export" a custom distDir is where the export goes, and
|
|
68
|
+
// the build then works in .next anyway (Next 16, build/index.js). So a
|
|
69
|
+
// browser app is built with the default: the build in .next, the files
|
|
70
|
+
// in out/, which is what the platform publishes. Its check builds in a
|
|
71
|
+
// copy of the app, never in the tree.
|
|
72
|
+
//
|
|
45
73
|
// CLAW_TURBOPACK_ROOT is set by `npm run check` alone, when it builds a
|
|
46
74
|
// copy of an app folder it cannot write (check/run.mjs buildSite). The
|
|
47
75
|
// copy's node_modules is a symlink back to the app's, and Turbopack (Next
|
|
@@ -65,6 +93,11 @@ const turbopackRoot = process.env.CLAW_TURBOPACK_ROOT || "";
|
|
|
65
93
|
// turns off, the dev overlay's /__nextjs_attach-nodejs-inspector (it
|
|
66
94
|
// opens a Node debugger on loopback); only the platform can wall that
|
|
67
95
|
// (CHANGELOG, 0.6.0).
|
|
96
|
+
//
|
|
97
|
+
// Browser mode adds three: output "export" (every page a file); images
|
|
98
|
+
// unoptimized, a guard, since the export has no image server (nothing in
|
|
99
|
+
// the template uses next/image); and trailingSlash false, so a page is
|
|
100
|
+
// s/<key>.html, the file the platform's router looks for.
|
|
68
101
|
const nextConfig = {
|
|
69
102
|
basePath: process.env.CLAW_BASE_PATH || "",
|
|
70
103
|
distDir: process.env.CLAW_DIST_DIR || ".next",
|
|
@@ -72,11 +105,12 @@ const nextConfig = {
|
|
|
72
105
|
CLAW_BASE_PATH: process.env.CLAW_BASE_PATH || "",
|
|
73
106
|
},
|
|
74
107
|
agentRules: false,
|
|
108
|
+
...(BROWSER ? { output: "export", images: { unoptimized: true }, trailingSlash: false } : {}),
|
|
75
109
|
...(allowedDevOrigins.length > 0 ? { allowedDevOrigins } : {}),
|
|
76
110
|
...(turbopackRoot ? { turbopack: { root: turbopackRoot }, outputFileTracingRoot: turbopackRoot } : {}),
|
|
77
111
|
experimental: {
|
|
78
112
|
mcpServer: false,
|
|
79
|
-
...(allowedOrigins.length > 0 ? { serverActions: { allowedOrigins } } : {}),
|
|
113
|
+
...(!BROWSER && allowedOrigins.length > 0 ? { serverActions: { allowedOrigins } } : {}),
|
|
80
114
|
},
|
|
81
115
|
};
|
|
82
116
|
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* label what the nav shows
|
|
8
8
|
* kind optional, free text, one or two words for the checklist
|
|
9
9
|
* ("board", "inbox", "report") — not an enum, nothing keys on it
|
|
10
|
-
* source the table the surface reads, when it reads one
|
|
10
|
+
* source the table the surface reads, when it reads one: its bare name
|
|
11
|
+
* ("investors"), which the app's own schema answers
|
|
11
12
|
* home true on the one surface / opens; otherwise the first entry
|
|
12
13
|
* component the surface's component. LEAVE IT OUT while the surface is
|
|
13
14
|
* still planned: the nav shows it as planned and its page says
|
|
@@ -27,7 +28,7 @@
|
|
|
27
28
|
// A domain surface, once built, looks like this:
|
|
28
29
|
//
|
|
29
30
|
// import Investors from "./surfaces/investors";
|
|
30
|
-
// { key: "investors", label: "Investors", kind: "board", source: "
|
|
31
|
+
// { key: "investors", label: "Investors", kind: "board", source: "investors", home: true, component: Investors },
|
|
31
32
|
|
|
32
33
|
const surfaces = [];
|
|
33
34
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next",
|
|
3
3
|
"title": "Makersclaw app (Next.js 16)",
|
|
4
|
-
"description": "The behaviour every app shares, the parts every app is assembled from, and none of the app's own look — the colours are the workspace's. It carries the data layer (lib/data.js, lib/db.js), the write actions that log activity (lib/actions.js), the _claw platform client with its identity wrapper, the ask bridge (a screen's ask becomes a request, answered in the desk's agent column) and the hooks that follow requests (lib/claw.js, lib/platform.js, lib/hooks.js), routing (/s/<key>), the request proxy (proxy.js), error boundaries, Tailwind v4 mapped to the workspace theme (app/globals.css + _claw/theme.css), the kit (components/ui), the parts bound to the data layer and to the live requests (components/parts) and `npm run check`. The app designs the inside of the App tab on top: app/shell.jsx and every domain surface, assembled from the kit and the blocks with tokens only.",
|
|
4
|
+
"description": "The behaviour every app shares, the parts every app is assembled from, and none of the app's own look — the colours are the workspace's. It carries the data layer (lib/data.js, lib/db.js), the write actions that log activity (lib/actions.js), the company brain through the platform's data door (lib/brain.js from the browser, lib/brain-server.js for server reads), the app's own tables through the same door from the browser (lib/door.js and its hooks; a browser app's lib/data.js and lib/actions.js re-export it), the _claw platform client with its identity wrapper, the ask bridge (a screen's ask becomes a request, answered in the desk's agent column) and the hooks that follow requests (lib/claw.js, lib/platform.js, lib/hooks.js), routing (/s/<key>), the request proxy (proxy.js), error boundaries, Tailwind v4 mapped to the workspace theme (app/globals.css + _claw/theme.css), the kit (components/ui), the parts bound to the data layer and to the live requests (components/parts) and `npm run check`. The app designs the inside of the App tab on top: app/shell.jsx and every domain surface, assembled from the kit and the blocks with tokens only.",
|
|
5
5
|
"files": {
|
|
6
6
|
"fixed": [
|
|
7
7
|
"app/globals.css",
|
|
@@ -24,11 +24,18 @@
|
|
|
24
24
|
"next.config.mjs",
|
|
25
25
|
"postcss.config.mjs"
|
|
26
26
|
],
|
|
27
|
-
"docs": ["README.md", "surfaces/README.md"
|
|
27
|
+
"docs": ["README.md", "surfaces/README.md"],
|
|
28
28
|
"starter": ["app/shell.jsx", "surfaces.js"],
|
|
29
29
|
"merged": ["package.json"],
|
|
30
30
|
"retired": ["middleware.js"]
|
|
31
31
|
},
|
|
32
|
+
"modes": {
|
|
33
|
+
"browser": {
|
|
34
|
+
"overlay": "browser",
|
|
35
|
+
"drop": ["proxy.js", "app/claw-alive/route.js", "lib/db.js", "lib/brain-server.js"],
|
|
36
|
+
"dropScripts": ["start"]
|
|
37
|
+
}
|
|
38
|
+
},
|
|
32
39
|
"components": [
|
|
33
40
|
{
|
|
34
41
|
"name": "button",
|
|
@@ -194,7 +201,7 @@
|
|
|
194
201
|
"name": "item",
|
|
195
202
|
"type": "component",
|
|
196
203
|
"title": "Item, ItemGroup",
|
|
197
|
-
"description": "The list row: media (an avatar, an image) or an icon, title, description, meta on the right, actions; href makes the whole row a link, onClick a button, neither
|
|
204
|
+
"description": "The list row: media (an avatar, an image) or an icon, title, description, meta on the right, actions; href makes the whole row a link, onClick a button, neither a plain row — actions still click on their own. aria-current, onClick, target and rel go on the row's link or button (aria-current fills the row); other props on the row. size default (56px) · sm (44px) · lg (64px); variant plain · outline · muted; layout row · stacked (a card for a grid: icon or media on top, title, description, meta at the foot, actions top-right, full cell height). ItemGroup stacks them with a rule between each (variant plain · outline).",
|
|
198
205
|
"tags": ["item", "list", "row", "list item", "contact", "file", "settings row"],
|
|
199
206
|
"files": ["components/ui/item.jsx"]
|
|
200
207
|
},
|
|
@@ -326,6 +333,14 @@
|
|
|
326
333
|
"tags": ["scroll", "scroll area", "overflow", "list", "carousel", "rail"],
|
|
327
334
|
"files": ["components/ui/scroll-area.jsx"]
|
|
328
335
|
},
|
|
336
|
+
{
|
|
337
|
+
"name": "layout",
|
|
338
|
+
"type": "component",
|
|
339
|
+
"title": "AppLayout, DocumentLayout",
|
|
340
|
+
"description": "Who owns the window's height, and who scrolls. AppLayout is the app frame, the one viewport owner (the outermost; one inside another fills its slot instead): header (the top bar, in view), navigation (a rail from md, navigationWidth px, 176; below md a Sheet behind the menu button, navigationLabel), the content (contentMode scroll: its region scrolls · fill: a bounded column for a canvas or a grid that scrolls itself; contentLabel, contentClassName for spacing, scrollKey = the route to scroll back to the top), inspector (beside the content from inspectorAt md · lg · xl, inspectorWidth px, 360, 240 to 560; below it the content and the inspector share one scroll in scroll mode, and in fill mode the inspector is a bounded pane under the content), footer (under the content, in view), height viewport · parent. In print it lets go. DocumentLayout is a page that flows, for print and export: toolbar (held at the top, never printed), width prose · page (A4) · letter · full, paper, align start · center. Nothing in an app sizes itself by the window: npm run check refuses min-h-dvh, h-screen, 100vh and h-[80vh] outside the kit.",
|
|
341
|
+
"tags": ["layout", "app frame", "shell", "viewport", "scroll", "inspector", "sidebar", "navigation", "footer", "fill", "canvas", "document", "print", "export", "page"],
|
|
342
|
+
"files": ["components/ui/layout.jsx"]
|
|
343
|
+
},
|
|
329
344
|
{
|
|
330
345
|
"name": "toast",
|
|
331
346
|
"type": "component",
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
-- Reference only. artifact_scaffold creates this table in the workspace
|
|
2
|
-
-- database when it copies the template; nothing in the app runs this file.
|
|
3
|
-
-- (docs/ARTIFACT-CONTRACTS.md §4)
|
|
4
|
-
--
|
|
5
|
-
-- Every write the app makes (lib/actions.js → lib/db.js logActivity) and
|
|
6
|
-
-- every action the artifact's agent takes (its brief tells it to insert
|
|
7
|
-
-- here with the sql verb) lands in this table, keyed by the artifact id
|
|
8
|
-
-- product_run passes as CLAW_ARTIFACT_ID. The Activity tab the OS draws on
|
|
9
|
-
-- the app window reads it (§9b), and so can any surface via loadActivity.
|
|
10
|
-
|
|
11
|
-
create table if not exists public.artifact_activity (
|
|
12
|
-
id bigserial primary key,
|
|
13
|
-
artifact_id uuid not null,
|
|
14
|
-
at timestamptz not null default now(),
|
|
15
|
-
action text not null, -- found, drafted, sent, replied, skipped, edited…
|
|
16
|
-
surface text, -- surface key
|
|
17
|
-
row_ref text, -- id in the surface's source table
|
|
18
|
-
detail text, -- one sentence
|
|
19
|
-
data jsonb not null default '{}'::jsonb,
|
|
20
|
-
by text not null default 'agent' -- 'agent' | 'user:<email>' | 'run:<id>'
|
|
21
|
-
);
|
|
22
|
-
create index if not exists artifact_activity_artifact_at on public.artifact_activity (artifact_id, at desc);
|