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.
- package/README.md +3 -1
- package/package.json +1 -1
- 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/core.json +12 -6
- 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 +8 -5
- 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 +131 -123
- 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/registry/blocks/job-panel/README.md +40 -3
- package/registry/blocks/job-panel/block.json +2 -2
- package/registry/blocks/job-panel/demo.jsx +75 -6
- package/registry/blocks/job-panel/job-panel.jsx +60 -11
- package/src/shadcn.mjs +1 -1
- package/templates/next/files/README.md +339 -73
- package/templates/next/files/app/auto-refresh.jsx +72 -10
- package/templates/next/files/app/claw-alive/route.js +17 -0
- package/templates/next/files/app/error-relay.jsx +9 -4
- package/templates/next/files/app/escape-relay.jsx +27 -0
- package/templates/next/files/app/frame.js +218 -0
- package/templates/next/files/app/layout.jsx +18 -3
- package/templates/next/files/check/run.mjs +25 -8
- package/templates/next/files/components/parts/fixture.jsx +29 -4
- package/templates/next/files/components/parts/index.js +2 -1
- package/templates/next/files/components/parts/live-work.jsx +235 -0
- package/templates/next/files/components/ui/button.jsx +6 -1
- package/templates/next/files/components/ui/date-picker.jsx +15 -2
- package/templates/next/files/components/ui/icon.jsx +37 -2
- package/templates/next/files/lib/claw.js +127 -28
- package/templates/next/files/lib/hooks.js +454 -33
- package/templates/next/files/lib/platform.js +113 -15
- package/templates/next/files/surfaces/README.md +3 -0
- package/templates/next/template.json +17 -6
|
@@ -8,7 +8,8 @@ import { Button, Card, Empty, Field, Icon, Skeleton, Textarea, cx } from "../../
|
|
|
8
8
|
// keeps the four rules a hand-drawn panel breaks: it is not there when
|
|
9
9
|
// nothing runs, it shows each step's label (the founder's phrase, never
|
|
10
10
|
// the tool's name), the agent's text is its account and not the
|
|
11
|
-
// deliverable (the rows are), and Stop / Close are always one press away
|
|
11
|
+
// deliverable (the rows are), and Stop / Close are always one press away
|
|
12
|
+
// (Answer in Stop's place while the agent waits on the founder).
|
|
12
13
|
//
|
|
13
14
|
// const job = useJob();
|
|
14
15
|
// <Button onClick={() => job.start("Draft a launch plan for Rowhouse")}>Generate a launch plan</Button>
|
|
@@ -24,10 +25,21 @@ import { Button, Card, Empty, Field, Icon, Skeleton, Textarea, cx } from "../../
|
|
|
24
25
|
// options={<Field …><Select …/></Field>}
|
|
25
26
|
// onGenerate={(prompt) => job.start(`Make a product photo: ${prompt}. Size ${size}.`)}
|
|
26
27
|
// results={photos.map((p) => <PhotoCard key={p.id} photo={p} />)} />
|
|
28
|
+
//
|
|
29
|
+
// Since 0.4.0 a job is a request, and its conversation lives in the
|
|
30
|
+
// desk's agent column: the agent's questions and the founder's yes are
|
|
31
|
+
// there, not here. So the panel reads two more states off the job, when
|
|
32
|
+
// the job has them: needsYou (the agent waits on the founder — the
|
|
33
|
+
// heading says so and Answer, in Stop's place, opens the question in the
|
|
34
|
+
// column) and queued (one job per list runs at a time — the heading names
|
|
35
|
+
// the job it waits behind). A 0.3.x job object has neither and draws
|
|
36
|
+
// exactly as it always did.
|
|
27
37
|
|
|
28
38
|
function StepMark({ status }) {
|
|
29
39
|
if (status === "done") return <Icon name="check" size={14} className="shrink-0 text-success" />;
|
|
30
40
|
if (status === "failed") return <Icon name="warning" size={14} className="shrink-0 text-destructive" />;
|
|
41
|
+
if (status === "needs") return <Icon name="circle-help" size={14} className="shrink-0 text-warning" />;
|
|
42
|
+
if (status === "queued") return <Icon name="clock" size={14} className="shrink-0 text-muted-foreground" />;
|
|
31
43
|
return <span aria-hidden="true" className="mx-[3px] size-2 shrink-0 animate-pulse rounded-full bg-primary" />;
|
|
32
44
|
}
|
|
33
45
|
|
|
@@ -36,11 +48,17 @@ export function JobPanel({ variant = "panel", ...props }) {
|
|
|
36
48
|
return <Panel {...props} />;
|
|
37
49
|
}
|
|
38
50
|
|
|
51
|
+
// Waiting on the founder or on another job is still a live job: not over,
|
|
52
|
+
// only paused. useJob counts both as running; an object of its own shape
|
|
53
|
+
// that sets only the flag gets the same panel.
|
|
54
|
+
const isLive = (job) => Boolean(job?.running || job?.needsYou || job?.queued);
|
|
55
|
+
|
|
39
56
|
function Panel({
|
|
40
57
|
job,
|
|
41
58
|
title = "Working on it",
|
|
42
59
|
doneTitle = "Done",
|
|
43
60
|
failedTitle = "It stopped",
|
|
61
|
+
needsTitle = "Needs your answer",
|
|
44
62
|
onRetry,
|
|
45
63
|
autoClose = 6000,
|
|
46
64
|
maxSteps = 6,
|
|
@@ -48,7 +66,9 @@ function Panel({
|
|
|
48
66
|
className,
|
|
49
67
|
}) {
|
|
50
68
|
const textRef = useRef(null);
|
|
51
|
-
const
|
|
69
|
+
const needsYou = Boolean(job?.needsYou);
|
|
70
|
+
const queued = !needsYou && Boolean(job?.queued);
|
|
71
|
+
const running = isLive(job);
|
|
52
72
|
const failed = !running && Boolean(job?.error);
|
|
53
73
|
const done = !running && !failed && Boolean(job?.finishedAt);
|
|
54
74
|
|
|
@@ -67,23 +87,43 @@ function Panel({
|
|
|
67
87
|
|
|
68
88
|
if (!job || !(running || failed || done)) return null;
|
|
69
89
|
|
|
70
|
-
|
|
90
|
+
// What the job waits on, if anything: its mark replaces the pulse.
|
|
91
|
+
const waiting = needsYou ? "needs" : queued ? "queued" : null;
|
|
92
|
+
const heading = needsYou
|
|
93
|
+
? needsTitle
|
|
94
|
+
: queued
|
|
95
|
+
? `Queued · after ${job.queuedAfter?.after_title ?? "the job before it"}`
|
|
96
|
+
: running
|
|
97
|
+
? title
|
|
98
|
+
: failed
|
|
99
|
+
? failedTitle
|
|
100
|
+
: doneTitle;
|
|
101
|
+
// A queued request's one step is its line, and its line is this
|
|
102
|
+
// heading again: say it once.
|
|
103
|
+
const steps = (job.steps ?? []).filter((step) => !(queued && step.label === heading));
|
|
71
104
|
const hidden = Math.max(0, steps.length - maxSteps);
|
|
72
105
|
const visible = steps.slice(hidden);
|
|
73
|
-
|
|
106
|
+
// The question is in the desk's agent column; open() takes the founder
|
|
107
|
+
// there. Without it there is nowhere to point, and Stop stays.
|
|
108
|
+
const answer = needsYou && typeof job.open === "function";
|
|
74
109
|
|
|
75
110
|
return (
|
|
76
111
|
<section
|
|
77
112
|
aria-label={heading}
|
|
78
|
-
className={cx(
|
|
113
|
+
className={cx(
|
|
114
|
+
"rounded-lg border bg-card p-4 text-card-foreground",
|
|
115
|
+
failed ? "border-destructive/50" : needsYou ? "border-warning/50" : "border-border",
|
|
116
|
+
className,
|
|
117
|
+
)}
|
|
79
118
|
>
|
|
80
119
|
<div className="flex items-start justify-between gap-3">
|
|
81
120
|
<div className="min-w-0">
|
|
82
121
|
<p aria-live="polite" className="flex items-center gap-2 text-sm font-semibold">
|
|
83
|
-
{running ?
|
|
122
|
+
<StepMark status={waiting ?? (running ? "running" : failed ? "failed" : "done")} />
|
|
84
123
|
<span className="min-w-0">{heading}</span>
|
|
85
124
|
</p>
|
|
86
125
|
{failed ? <p className="mt-1 text-sm text-muted-foreground">{job.error}</p> : null}
|
|
126
|
+
{needsYou ? <p className="mt-1 text-sm text-muted-foreground">The question is in the agent column.</p> : null}
|
|
87
127
|
</div>
|
|
88
128
|
<div className="flex shrink-0 gap-2">
|
|
89
129
|
{failed && onRetry ? (
|
|
@@ -91,7 +131,11 @@ function Panel({
|
|
|
91
131
|
Try again
|
|
92
132
|
</Button>
|
|
93
133
|
) : null}
|
|
94
|
-
{
|
|
134
|
+
{answer ? (
|
|
135
|
+
<Button size="sm" variant="secondary" onClick={() => job.open()}>
|
|
136
|
+
Answer
|
|
137
|
+
</Button>
|
|
138
|
+
) : running ? (
|
|
95
139
|
<Button size="sm" variant="quiet" onClick={() => job.cancel?.()}>
|
|
96
140
|
Stop
|
|
97
141
|
</Button>
|
|
@@ -107,12 +151,14 @@ function Panel({
|
|
|
107
151
|
{hidden > 0 ? <li className="text-xs text-muted-foreground">{hidden} earlier {hidden === 1 ? "step" : "steps"}</li> : null}
|
|
108
152
|
{visible.map((step, i) => (
|
|
109
153
|
<li key={`${hidden + i}-${step.name}`} className="flex items-center gap-2">
|
|
110
|
-
<StepMark status={step.status} />
|
|
154
|
+
<StepMark status={waiting && step.status === "running" ? waiting : step.status} />
|
|
111
155
|
<span className={step.status === "running" ? "text-foreground" : "text-muted-foreground"}>{step.label ?? "Working"}</span>
|
|
112
156
|
</li>
|
|
113
157
|
))}
|
|
114
158
|
</ol>
|
|
115
159
|
) : null}
|
|
160
|
+
{/* The agent's account, on the 0.3.x path. A request's text is empty
|
|
161
|
+
(its account is in the column), so the area is not drawn. */}
|
|
116
162
|
{showText && job.text ? (
|
|
117
163
|
<div
|
|
118
164
|
ref={textRef}
|
|
@@ -159,6 +205,7 @@ function Generator({
|
|
|
159
205
|
title = "Working on it",
|
|
160
206
|
doneTitle = "Done",
|
|
161
207
|
failedTitle = "It stopped",
|
|
208
|
+
needsTitle = "Needs your answer",
|
|
162
209
|
onRetry,
|
|
163
210
|
autoClose = 6000,
|
|
164
211
|
maxSteps = 6,
|
|
@@ -175,7 +222,7 @@ function Generator({
|
|
|
175
222
|
if (controlled === undefined) setOwn(v);
|
|
176
223
|
onPromptChange?.(v);
|
|
177
224
|
};
|
|
178
|
-
const running =
|
|
225
|
+
const running = isLive(job);
|
|
179
226
|
const canGenerate = !disabled && !running && !starting && (canGenerateEmpty || value.trim().length > 0);
|
|
180
227
|
|
|
181
228
|
async function generate(text = value) {
|
|
@@ -192,8 +239,9 @@ function Generator({
|
|
|
192
239
|
setStarting(false);
|
|
193
240
|
if (r && r.ok === false && !r.aborted) setError(r.error ?? "It did not start");
|
|
194
241
|
}
|
|
195
|
-
// useJob's start resolves when the
|
|
196
|
-
//
|
|
242
|
+
// useJob's start resolves when the ask is taken (on a 0.3.x claw, when
|
|
243
|
+
// the job ends); a failure it reports is already the panel's error, so
|
|
244
|
+
// the field says only what the panel does not.
|
|
197
245
|
const fieldError = error && !job?.error ? error : null;
|
|
198
246
|
|
|
199
247
|
const cols = { 1: "grid-cols-1", 2: "grid-cols-1 sm:grid-cols-2", 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3", 4: "grid-cols-2 lg:grid-cols-4" };
|
|
@@ -236,6 +284,7 @@ function Generator({
|
|
|
236
284
|
title={title}
|
|
237
285
|
doneTitle={doneTitle}
|
|
238
286
|
failedTitle={failedTitle}
|
|
287
|
+
needsTitle={needsTitle}
|
|
239
288
|
onRetry={onRetry ?? (lastPrompt.current || canGenerateEmpty ? () => generate(lastPrompt.current) : undefined)}
|
|
240
289
|
autoClose={autoClose}
|
|
241
290
|
maxSteps={maxSteps}
|
package/src/shadcn.mjs
CHANGED
|
@@ -104,7 +104,7 @@ function coreItem() {
|
|
|
104
104
|
title: "Makersclaw kit",
|
|
105
105
|
description:
|
|
106
106
|
"The kit every Makersclaw block is built from — Button, Field, Select, Sheet, Tabs, Menu, Notice, Icon, Depiction — " +
|
|
107
|
-
"and the parts bound to data (RecordSwitcher, useFixture). Native elements under the project's own theme tokens.",
|
|
107
|
+
"and the parts bound to data (RecordSwitcher, useFixture, LiveEmpty). Native elements under the project's own theme tokens.",
|
|
108
108
|
files,
|
|
109
109
|
cssVars: CSS_VARS,
|
|
110
110
|
css: CSS,
|