makersclaw 0.3.2 → 0.4.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 (81) hide show
  1. package/README.md +3 -1
  2. package/package.json +1 -1
  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/core.json +12 -6
  16. package/r/csv-import.json +3 -3
  17. package/r/data-table.json +2 -2
  18. package/r/diagram.json +2 -2
  19. package/r/doc-editor.json +2 -2
  20. package/r/doc-page.json +3 -3
  21. package/r/email-render.json +2 -2
  22. package/r/faq.json +2 -2
  23. package/r/file-upload.json +2 -2
  24. package/r/flow-canvas.json +2 -2
  25. package/r/footer.json +2 -2
  26. package/r/gantt.json +3 -3
  27. package/r/job-panel.json +8 -5
  28. package/r/json-editor.json +3 -3
  29. package/r/map.json +2 -2
  30. package/r/menubar.json +2 -2
  31. package/r/mind-map.json +3 -3
  32. package/r/navigation-menu.json +2 -2
  33. package/r/order-detail.json +2 -2
  34. package/r/org-chart.json +3 -3
  35. package/r/page-builder.json +2 -2
  36. package/r/payment-methods.json +2 -2
  37. package/r/pdf-document.json +2 -2
  38. package/r/pdf-viewer.json +2 -2
  39. package/r/product-detail.json +2 -2
  40. package/r/product-grid.json +3 -3
  41. package/r/record-form.json +2 -2
  42. package/r/record-notes.json +4 -4
  43. package/r/registry.json +131 -123
  44. package/r/search-dialog.json +2 -2
  45. package/r/settings-list.json +2 -2
  46. package/r/setup-checklist.json +2 -2
  47. package/r/share-dialog.json +2 -2
  48. package/r/sidebar.json +2 -2
  49. package/r/signature-pad.json +2 -2
  50. package/r/sketch-canvas.json +2 -2
  51. package/r/spreadsheet.json +2 -2
  52. package/r/stat-cards.json +3 -3
  53. package/r/task-list.json +3 -3
  54. package/r/task-model.json +2 -2
  55. package/r/testimonials.json +2 -2
  56. package/r/transaction-list.json +2 -2
  57. package/r/whiteboard.json +3 -3
  58. package/registry/blocks/job-panel/README.md +40 -3
  59. package/registry/blocks/job-panel/block.json +2 -2
  60. package/registry/blocks/job-panel/demo.jsx +75 -6
  61. package/registry/blocks/job-panel/job-panel.jsx +60 -11
  62. package/src/shadcn.mjs +1 -1
  63. package/templates/next/files/README.md +339 -73
  64. package/templates/next/files/app/auto-refresh.jsx +72 -10
  65. package/templates/next/files/app/claw-alive/route.js +17 -0
  66. package/templates/next/files/app/error-relay.jsx +9 -4
  67. package/templates/next/files/app/escape-relay.jsx +27 -0
  68. package/templates/next/files/app/frame.js +218 -0
  69. package/templates/next/files/app/layout.jsx +18 -3
  70. package/templates/next/files/check/run.mjs +25 -8
  71. package/templates/next/files/components/parts/fixture.jsx +29 -4
  72. package/templates/next/files/components/parts/index.js +2 -1
  73. package/templates/next/files/components/parts/live-work.jsx +235 -0
  74. package/templates/next/files/components/ui/button.jsx +6 -1
  75. package/templates/next/files/components/ui/date-picker.jsx +15 -2
  76. package/templates/next/files/components/ui/icon.jsx +37 -2
  77. package/templates/next/files/lib/claw.js +127 -28
  78. package/templates/next/files/lib/hooks.js +454 -33
  79. package/templates/next/files/lib/platform.js +113 -15
  80. package/templates/next/files/surfaces/README.md +3 -0
  81. package/templates/next/template.json +17 -6
@@ -1,29 +1,126 @@
1
- import { claw, clawStream, reportError } from "./claw";
1
+ import { claw, clawBasePath, clawStream, openInDesk, publishDesk, reportError } from "./claw";
2
2
 
3
3
  // Typed wrappers over the _claw API (lib/claw.js), one per route an app
4
4
  // has a reason to call. BROWSER only — the grant cookie is the identity —
5
5
  // so call these from "use client" files; lib/hooks.js wraps them.
6
6
  //
7
7
  // Every call resolves { ok, status, data } or { ok: false, status, error,
8
- // unavailable }; nothing throws. `unavailable: true` (404 or no network)
9
- // means the gateway has no such route yet — render a quiet "not connected
10
- // yet" state, not an error.
8
+ // unavailable, code? }; nothing throws. `unavailable: true` (404 or no
9
+ // network) means the gateway has no such route yet — render a quiet "not
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
12
  //
12
- // Three things live here: who the app is (`me`), the error relay
13
- // (`reportError`), and COMMISSIONING — `startJob` / `cancelJob`, the work
14
- // a founder asks for from inside the app (SOP §2.3). Monitoring is still
15
- // not an app's business: the OS draws Agent, Runs and Activity as tabs on
16
- // the window and the title bar holds the run controls, so nothing here
17
- // lists chats, runs or activity. `claw(path, opts)` and `clawStream` in
18
- // lib/claw.js are the generic doors for the rest of §5.
13
+ // What lives here: who the app is (`me`), the error relay
14
+ // (`reportError`), and ASKING — a screen asks its agent for work with a
15
+ // row as context (`ask`), and the conversation lives in the desk's agent
16
+ // column, which the ask opens. `requests` reads this app's asks in
17
+ // flight, so an empty surface can show the work coming instead of a
18
+ // blank; `stopRequest` stops one; `openRequest` opens one in the column
19
+ // again. That is not monitoring: the OS still draws Agent, Runs and
20
+ // Activity as tabs on the window, and nothing here lists chats, runs or
21
+ // activity. `startJob` / `cancelJob` are the 0.3.x door to the same work,
22
+ // streamed into the app; they stay for a claw that has no _claw/ask yet.
23
+ // `claw(path, opts)` and `clawStream` in lib/claw.js are the generic
24
+ // doors for the rest of §5.
19
25
 
20
26
  /** GET _claw/me → { artifact: { id, name, vehicle, status, home },
21
- * user: { id, email }, blueprint } */
27
+ * user: { id, email }, blueprint, desk_origin } */
22
28
  export function me() {
23
29
  return claw("me");
24
30
  }
25
31
 
32
+ /** The surface the page is on: the <key> of /s/<key>. Searched anywhere
33
+ * in the path, not only at its start, because in path mode the app is
34
+ * served under /p/<label>/ and the browser's path carries that prefix.
35
+ * The base path is cut first when it is there, so a label that happens
36
+ * to read "s" cannot pass for the surface. */
37
+ export function surfaceOfPath(pathname) {
38
+ let path = String(pathname ?? "");
39
+ const base = clawBasePath();
40
+ if (base && path.startsWith(`${base}/`)) path = path.slice(base.length);
41
+ const match = /\/s\/([^/?#]+)/.exec(path);
42
+ if (!match) return undefined;
43
+ try {
44
+ return decodeURIComponent(match[1]);
45
+ } catch {
46
+ return match[1];
47
+ }
48
+ }
49
+
50
+ function currentSurface() {
51
+ return typeof location === "undefined" ? undefined : surfaceOfPath(location.pathname);
52
+ }
53
+
26
54
  /**
55
+ * Ask the app's agent for work: POST _claw/ask. The platform makes it a
56
+ * request, hands it to the app's agent, and the conversation lives in the
57
+ * desk's agent column — which this opens, unless `open` is false.
58
+ *
59
+ * text what to do, in the founder's words (required)
60
+ * row the row it is about, as context for the agent
61
+ * how instructions for the agent only (the AGENTS.md section)
62
+ * job a declared job's key, or true: let the platform pick the
63
+ * job whose view is this surface, else the app's only job
64
+ * list the list it belongs to, for an app that declares lists
65
+ * surface defaults to the <key> of /s/<key> in the page's path
66
+ * sessionId continue this thread instead of starting one
67
+ *
68
+ * → { ok: true, status, data: { ok, request, desk_origin } }, or a
69
+ * refusal with its `code`: `not_your_thread` (403, a teammate's thread:
70
+ * start your own), `needs_answer` (409, the thread waits on an answer in
71
+ * the column), `queue_full` (409).
72
+ */
73
+ export async function ask({ text, row, how, job, list, surface, sessionId, open = true, signal } = {}) {
74
+ const words = String(text ?? "").trim();
75
+ if (!words) return { ok: false, status: 0, error: "nothing to ask", unavailable: false };
76
+ const r = await claw("ask", {
77
+ method: "POST",
78
+ body: {
79
+ text: words,
80
+ row: row ?? undefined,
81
+ how: how || undefined,
82
+ // true or a key; anything else is no job, and the key is left out.
83
+ job: job === true || (typeof job === "string" && job) ? job : undefined,
84
+ list: list ?? undefined,
85
+ surface: surface ?? currentSurface(),
86
+ session_id: sessionId || undefined,
87
+ },
88
+ signal,
89
+ });
90
+ if (r.ok) {
91
+ publishDesk(r.data?.desk_origin);
92
+ const request = r.data?.request;
93
+ if (open && request?.id) openInDesk({ requestId: request.id, sessionId: request.app_session_id });
94
+ }
95
+ return r;
96
+ }
97
+
98
+ /** GET _claw/requests → { requests, run, desk_origin }: this app's asks
99
+ * in flight (and those that ended in the last day), every member's, with
100
+ * session ids only on the viewer's own, plus its running scheduled run.
101
+ * With { id }: GET _claw/requests?id=<id> → { request }. */
102
+ export function requests({ id, signal } = {}) {
103
+ return claw(id ? `requests?id=${encodeURIComponent(id)}` : "requests", { signal });
104
+ }
105
+
106
+ /** POST _claw/requests/<id>/stop → { ok, request }. The asker may stop
107
+ * their own; an admin or the app's owner may stop anyone's. */
108
+ export function stopRequest(id) {
109
+ return claw(`requests/${encodeURIComponent(id)}/stop`, { method: "POST", body: {} });
110
+ }
111
+
112
+ /** Open a request's conversation in the desk's agent column again. Takes
113
+ * the request (its thread opens with it when it is yours) or its id.
114
+ * → true when the desk was asked. */
115
+ export function openRequest(requestOrId) {
116
+ const request = requestOrId && typeof requestOrId === "object" ? requestOrId : { id: requestOrId };
117
+ return openInDesk({ requestId: request.id, sessionId: request.app_session_id ?? null });
118
+ }
119
+
120
+ /**
121
+ * Legacy: the 0.3.x job door. useJob falls back to it on a claw that has
122
+ * no _claw/ask; new code calls ask().
123
+ *
27
124
  * Commission work: POST _claw/chat as a stream, and call `onEvent` for
28
125
  * every frame — `session` (once, first, carrying the thread's id),
29
126
  * `delta` ({ text } as the answer is written), `tool` ({ name, label,
@@ -46,14 +143,15 @@ export function startJob(message, { sessionId, onEvent, signal } = {}) {
46
143
  );
47
144
  }
48
145
 
49
- /** POST _claw/cancel — stop a job's turn. The rows it already wrote stay;
50
- * so does its run in the Runs tab. */
146
+ /** Legacy: the 0.3.x job door (stopRequest is the new one). POST
147
+ * _claw/cancel — stop a job's turn. The rows it already wrote stay; so
148
+ * does its run in the Runs tab. */
51
149
  export function cancelJob(sessionId) {
52
150
  return claw("cancel", { method: "POST", body: { session_id: sessionId } });
53
151
  }
54
152
 
55
153
  export { reportError };
56
154
 
57
- export const platform = { me, startJob, cancelJob, reportError };
155
+ export const platform = { me, ask, requests, stopRequest, openRequest, surfaceOfPath, startJob, cancelJob, reportError };
58
156
 
59
157
  export default platform;
@@ -25,6 +25,9 @@ that follows it — `useJob()` in `../lib/hooks.js`, §5 of `../README.md`.
25
25
  The panel is not a surface and takes no key: it opens because the founder
26
26
  pressed something and closes when the work lands.
27
27
 
28
+ An empty table shows `LiveEmpty` — the live work coming, never an
29
+ example (`../README.md` §3a).
30
+
28
31
  Register each in `../surfaces.js` (import + entry with `component`).
29
32
  Until the entry has a `component` the surface is planned: marked in the
30
33
  nav, "Makersclaw is building this" on its page.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "next",
3
3
  "title": "Makersclaw app (Next.js 15)",
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 and hooks (lib/claw.js, lib/platform.js, lib/hooks.js), routing (/s/<key>), the middleware, 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 (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 _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 middleware, 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",
@@ -12,6 +12,9 @@
12
12
  "app/not-found.jsx",
13
13
  "app/error-relay.jsx",
14
14
  "app/auto-refresh.jsx",
15
+ "app/escape-relay.jsx",
16
+ "app/frame.js",
17
+ "app/claw-alive/route.js",
15
18
  "app/s/[key]/page.jsx",
16
19
  "lib/*.js",
17
20
  "components/ui/*",
@@ -30,7 +33,7 @@
30
33
  "name": "button",
31
34
  "type": "component",
32
35
  "title": "Button, IconButton",
33
- "description": "The one button: variant primary (one per surface) · secondary · quiet · danger · link (inline text: no padding, no min-height, wraps and truncates with its sentence; size inherit takes the sentence's text; tone primary · muted for a secondary link) · nav (a full-width, start-aligned, normal-weight navigation row, filled when aria-current); size md (44px) · sm; align center · start; icon; href for a link; loading (a spinner, same width, aria-busy, disabled). IconButton for an icon alone, label required.",
36
+ "description": "The one button: variant primary (the surface's one main action, in the app's accent; ask for it — a Button with no variant is secondary) · secondary (the default) · quiet · danger · link (inline text: no padding, no min-height, wraps and truncates with its sentence; size inherit takes the sentence's text; tone primary · muted for a secondary link) · nav (a full-width, start-aligned, normal-weight navigation row, filled when aria-current); size md (44px) · sm; align center · start; icon; href for a link; loading (a spinner, same width, aria-busy, disabled). IconButton for an icon alone, label required.",
34
37
  "tags": ["button", "action", "link", "icon button"],
35
38
  "files": ["components/ui/button.jsx"]
36
39
  },
@@ -102,7 +105,7 @@
102
105
  "name": "date-picker",
103
106
  "type": "component",
104
107
  "title": "DatePicker, DateInput, DATE_PRESETS",
105
- "description": "DatePicker: a field that reads like an input and opens a Calendar in a Popover — mode single · range (formatRange in the field), presets beside the calendar (true for Today, Last 7 days, This month… or your own), clearable, disabled, min/max, a hidden input for forms; goes in <Field>. DateInput: the browser's own typed date field with the Calendar one button away.",
108
+ "description": "DatePicker: a field that reads like an input and opens a Calendar in a Popover — mode single · range (formatRange in the field), presets beside the calendar (true for Today, Last 7 days, This month… or your own), clearable, disabled, min/max, a hidden input for forms; goes in <Field>. DateInput: the browser's own typed date field with the Calendar one button away; clearable adds an × once it holds a date.",
106
109
  "tags": ["date picker", "date", "range", "due date", "presets", "date input", "report period"],
107
110
  "files": ["components/ui/date-picker.jsx"]
108
111
  },
@@ -142,7 +145,7 @@
142
145
  "name": "icon",
143
146
  "type": "component",
144
147
  "title": "Icon",
145
- "description": "One inline sprite of stroke glyphs; ICON_NAMES lists them. A missing glyph is added here, never drawn as an <svg> in a surface.",
148
+ "description": "One inline sprite of stroke glyphs; ICON_NAMES lists them. size is pixels or xs 12 · sm 14 · md 16 (the default) · lg 20 · xl 24. The sprite is fixed: a glyph it lacks is added in the template, never drawn as an <svg> in a surface.",
146
149
  "tags": ["icon", "glyph", "svg"],
147
150
  "files": ["components/ui/icon.jsx"]
148
151
  },
@@ -357,8 +360,8 @@
357
360
  {
358
361
  "name": "fixture",
359
362
  "type": "part",
360
- "title": "useFixture, isSample, FixtureNotice",
361
- "description": "The worked example shown while a table is empty — rows in code, never INSERTed; clearing writes nothing; a sample row carries _sample.",
363
+ "title": "useFixture, isSample, FixtureNotice, Examples, useExamples",
364
+ "description": "The worked example shown while a table is empty — examples shown only outside a Makersclaw workspace (the Examples provider, off in a workspace: there an empty table shows its live requests, LiveEmpty); rows in code, never INSERTed; clearing writes nothing; a sample row carries _sample.",
362
365
  "tags": ["example", "sample", "fixture", "empty state", "onboarding"],
363
366
  "files": ["components/parts/fixture.jsx"]
364
367
  },
@@ -369,6 +372,14 @@
369
372
  "description": "Pick a saved record or make a new one; with nothing saved it shows only New.",
370
373
  "tags": ["switcher", "picker", "saved", "records", "select"],
371
374
  "files": ["components/parts/record-switcher.jsx"]
375
+ },
376
+ {
377
+ "name": "live-work",
378
+ "type": "part",
379
+ "title": "LiveEmpty, LiveWork, liveWords",
380
+ "description": "The empty state that shows the live job, never example rows. LiveEmpty takes useRequests() and shows the request in flight on this surface or job — its line, whose request it is, Queued · after …, Answer when it needs you, Stop for the asker — with \"Rows appear here as they land\", or the app's scheduled run while it goes; with nothing in flight, the empty block (icon, title, line, one action). LiveWork is that one row; liveWords the status word (Working, Needs you, Answered, Done, Stopped, Didn't finish).",
381
+ "tags": ["empty state", "live", "request", "working", "needs you", "queued"],
382
+ "files": ["components/parts/live-work.jsx"]
372
383
  }
373
384
  ]
374
385
  }