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
@@ -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 running = Boolean(job?.running);
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
- const steps = job.steps ?? [];
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
- const heading = running ? title : failed ? failedTitle : doneTitle;
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("rounded-lg border bg-card p-4 text-card-foreground", failed ? "border-destructive/50" : "border-border", className)}
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 ? <StepMark status="running" /> : <StepMark status={failed ? "failed" : "done"} />}
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
- {running ? (
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 = Boolean(job?.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 job ends; a failure it reports is
196
- // already the panel's error, so the field says only what the panel does not.
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,