makersclaw 0.8.0 → 0.8.1
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 +9 -3
- package/package.json +1 -1
- package/r/activity-log.json +52 -0
- package/r/agent-changes.json +51 -0
- package/r/agent-chat.json +53 -0
- package/r/agent-column.json +85 -0
- package/r/agent-dock.json +57 -0
- package/r/agent-kit.json +49 -0
- package/r/agent-marks.json +49 -0
- package/r/agent-pane.json +93 -0
- package/r/ai-action.json +56 -0
- package/r/annotate.json +3 -3
- package/r/approval-request.json +2 -2
- package/r/approval.json +54 -0
- package/r/ask-bar.json +50 -0
- package/r/audio-player.json +2 -2
- package/r/auth-form.json +2 -2
- package/r/automation-editor.json +66 -0
- package/r/automation-list.json +57 -0
- package/r/automation-model.json +118 -0
- package/r/automations-screen.json +71 -0
- 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-pane.json +84 -0
- package/r/chat.json +2 -2
- package/r/code-editor.json +2 -2
- package/r/comment-box.json +3 -3
- package/r/connect-card.json +51 -0
- package/r/contact-section.json +2 -2
- package/r/core.json +13 -7
- package/r/cost.json +51 -0
- package/r/csv-import.json +3 -3
- package/r/data-picker.json +60 -0
- 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/first-run.json +63 -0
- package/r/fix-note.json +57 -0
- package/r/flow-canvas.json +2 -2
- package/r/flow-editor.json +79 -0
- 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/library-shelf.json +56 -0
- package/r/map.json +2 -2
- package/r/margin-notes.json +67 -0
- package/r/menubar.json +2 -2
- package/r/mind-map.json +3 -3
- package/r/navigation-menu.json +2 -2
- package/r/needs-you.json +55 -0
- package/r/order-detail.json +2 -2
- package/r/org-chart.json +3 -3
- package/r/pace-bar.json +69 -0
- 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-grid.json +52 -0
- package/r/record-notes.json +4 -4
- package/r/registry.json +4086 -1512
- package/r/run-history.json +52 -0
- package/r/run-view.json +80 -0
- package/r/schedule-card.json +54 -0
- package/r/schedule-engine.json +79 -0
- package/r/schedule-gantt.json +83 -0
- package/r/schedule-ruler.json +64 -0
- 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/source-receipt.json +52 -0
- package/r/spreadsheet.json +3 -3
- package/r/stat-cards.json +3 -3
- package/r/step-picker.json +53 -0
- package/r/step-settings.json +72 -0
- package/r/suggestion.json +58 -0
- package/r/sum-bar.json +64 -0
- package/r/task-list.json +3 -3
- package/r/task-model.json +2 -2
- package/r/testimonials.json +2 -2
- package/r/tier-map.json +67 -0
- package/r/time-grid.json +73 -0
- package/r/time-strip.json +64 -0
- package/r/top-bar.json +66 -0
- package/r/transaction-list.json +2 -2
- package/r/trigger-picker.json +61 -0
- package/r/whiteboard.json +3 -3
- package/r/workflow-view.json +55 -0
- package/registry/blocks/activity-log/README.md +112 -0
- package/registry/blocks/activity-log/activity-log.jsx +351 -0
- package/registry/blocks/activity-log/block.json +33 -0
- package/registry/blocks/activity-log/demo.jsx +48 -0
- package/registry/blocks/activity-log/index.js +4 -0
- package/registry/blocks/agent-changes/README.md +94 -0
- package/registry/blocks/agent-changes/agent-changes.jsx +118 -0
- package/registry/blocks/agent-changes/block.json +28 -0
- package/registry/blocks/agent-changes/demo.jsx +39 -0
- package/registry/blocks/agent-changes/index.js +3 -0
- package/registry/blocks/agent-chat/README.md +145 -0
- package/registry/blocks/agent-chat/agent-chat.jsx +415 -0
- package/registry/blocks/agent-chat/block.json +30 -0
- package/registry/blocks/agent-chat/demo.jsx +165 -0
- package/registry/blocks/agent-chat/index.js +3 -0
- package/registry/blocks/agent-column/README.md +197 -0
- package/registry/blocks/agent-column/agent-column.jsx +492 -0
- package/registry/blocks/agent-column/block.json +67 -0
- package/registry/blocks/agent-column/column-picker.jsx +163 -0
- package/registry/blocks/agent-column/demo.jsx +50 -0
- package/registry/blocks/agent-column/index.js +7 -0
- package/registry/blocks/agent-column/model.js +164 -0
- package/registry/blocks/agent-column/receipt.jsx +483 -0
- package/registry/blocks/agent-column/spreadsheet-type.jsx +24 -0
- package/registry/blocks/agent-dock/README.md +210 -0
- package/registry/blocks/agent-dock/agent-dock.jsx +356 -0
- package/registry/blocks/agent-dock/block.json +47 -0
- package/registry/blocks/agent-dock/demo.jsx +153 -0
- package/registry/blocks/agent-dock/dock-model.js +118 -0
- package/registry/blocks/agent-dock/index.js +5 -0
- package/registry/blocks/agent-kit/README.md +73 -0
- package/registry/blocks/agent-kit/agent-kit.jsx +86 -0
- package/registry/blocks/agent-kit/block.json +10 -0
- package/registry/blocks/agent-kit/demo.jsx +35 -0
- package/registry/blocks/agent-kit/index.js +3 -0
- package/registry/blocks/agent-marks/README.md +80 -0
- package/registry/blocks/agent-marks/agent-marks.jsx +133 -0
- package/registry/blocks/agent-marks/block.json +27 -0
- package/registry/blocks/agent-marks/demo.jsx +49 -0
- package/registry/blocks/agent-marks/index.js +3 -0
- package/registry/blocks/agent-pane/README.md +225 -0
- package/registry/blocks/agent-pane/agent-pane.jsx +244 -0
- package/registry/blocks/agent-pane/block.json +41 -0
- package/registry/blocks/agent-pane/composer.jsx +6 -0
- package/registry/blocks/agent-pane/demo.jsx +233 -0
- package/registry/blocks/agent-pane/dock-context.js +10 -0
- package/registry/blocks/agent-pane/index.js +4 -0
- package/registry/blocks/agent-pane/prose.jsx +84 -0
- package/registry/blocks/agent-pane/questions.jsx +134 -0
- package/registry/blocks/agent-pane/transcript.jsx +268 -0
- package/registry/blocks/agent-pane/work.jsx +368 -0
- package/registry/blocks/ai-action/README.md +94 -0
- package/registry/blocks/ai-action/ai-action.jsx +188 -0
- package/registry/blocks/ai-action/block.json +34 -0
- package/registry/blocks/ai-action/demo.jsx +93 -0
- package/registry/blocks/ai-action/index.js +3 -0
- package/registry/blocks/approval/README.md +145 -0
- package/registry/blocks/approval/approval.jsx +163 -0
- package/registry/blocks/approval/block.json +31 -0
- package/registry/blocks/approval/demo.jsx +121 -0
- package/registry/blocks/approval/index.js +3 -0
- package/registry/blocks/ask-bar/README.md +105 -0
- package/registry/blocks/ask-bar/ask-bar.jsx +166 -0
- package/registry/blocks/ask-bar/block.json +26 -0
- package/registry/blocks/ask-bar/demo.jsx +78 -0
- package/registry/blocks/ask-bar/index.js +3 -0
- package/registry/blocks/automation-editor/README.md +291 -0
- package/registry/blocks/automation-editor/automation-editor.jsx +656 -0
- package/registry/blocks/automation-editor/block.json +39 -0
- package/registry/blocks/automation-editor/demo.jsx +284 -0
- package/registry/blocks/automation-editor/index.js +4 -0
- package/registry/blocks/automation-editor/run-inputs.jsx +82 -0
- package/registry/blocks/automation-list/README.md +129 -0
- package/registry/blocks/automation-list/automation-list.jsx +476 -0
- package/registry/blocks/automation-list/block.json +35 -0
- package/registry/blocks/automation-list/demo.jsx +67 -0
- package/registry/blocks/automation-list/index.js +3 -0
- package/registry/blocks/automation-model/README.md +109 -0
- package/registry/blocks/automation-model/block.json +135 -0
- package/registry/blocks/automation-model/catalog.js +256 -0
- package/registry/blocks/automation-model/check.js +161 -0
- package/registry/blocks/automation-model/demo.jsx +42 -0
- package/registry/blocks/automation-model/edit.js +262 -0
- package/registry/blocks/automation-model/fixes.js +287 -0
- package/registry/blocks/automation-model/glyph.jsx +13 -0
- package/registry/blocks/automation-model/graph.js +410 -0
- package/registry/blocks/automation-model/index.js +33 -0
- package/registry/blocks/automation-model/overlay.js +175 -0
- package/registry/blocks/automation-model/parts.jsx +94 -0
- package/registry/blocks/automation-model/schedule.js +53 -0
- package/registry/blocks/automation-model/templates.js +128 -0
- package/registry/blocks/automation-model/values.js +29 -0
- package/registry/blocks/automation-model/words.js +439 -0
- package/registry/blocks/automations-screen/README.md +207 -0
- package/registry/blocks/automations-screen/automations-screen.jsx +452 -0
- package/registry/blocks/automations-screen/block.json +47 -0
- package/registry/blocks/automations-screen/demo.jsx +364 -0
- package/registry/blocks/automations-screen/index.js +4 -0
- package/registry/blocks/automations-screen/screen-model.js +129 -0
- package/registry/blocks/chat-pane/README.md +143 -0
- package/registry/blocks/chat-pane/block.json +48 -0
- package/registry/blocks/chat-pane/chat-attach.js +166 -0
- package/registry/blocks/chat-pane/chat-composer.jsx +195 -0
- package/registry/blocks/chat-pane/chat-context.js +17 -0
- package/registry/blocks/chat-pane/chat-model.js +43 -0
- package/registry/blocks/chat-pane/chat-pane.jsx +398 -0
- package/registry/blocks/chat-pane/chats-list.jsx +52 -0
- package/registry/blocks/chat-pane/demo.jsx +103 -0
- package/registry/blocks/chat-pane/index.js +9 -0
- package/registry/blocks/connect-card/README.md +99 -0
- package/registry/blocks/connect-card/block.json +10 -0
- package/registry/blocks/connect-card/connect-card.jsx +103 -0
- package/registry/blocks/connect-card/demo.jsx +49 -0
- package/registry/blocks/connect-card/index.js +3 -0
- package/registry/blocks/cost/README.md +115 -0
- package/registry/blocks/cost/block.json +10 -0
- package/registry/blocks/cost/cost.jsx +176 -0
- package/registry/blocks/cost/demo.jsx +66 -0
- package/registry/blocks/cost/index.js +3 -0
- package/registry/blocks/data-picker/README.md +81 -0
- package/registry/blocks/data-picker/block.json +38 -0
- package/registry/blocks/data-picker/data-picker.jsx +210 -0
- package/registry/blocks/data-picker/demo.jsx +34 -0
- package/registry/blocks/data-picker/fields.js +89 -0
- package/registry/blocks/data-picker/index.js +4 -0
- package/registry/blocks/data-table/demo.jsx +1 -1
- package/registry/blocks/first-run/README.md +118 -0
- package/registry/blocks/first-run/block.json +11 -0
- package/registry/blocks/first-run/demo.jsx +88 -0
- package/registry/blocks/first-run/first-run-model.js +51 -0
- package/registry/blocks/first-run/first-run.jsx +156 -0
- package/registry/blocks/first-run/index.js +5 -0
- package/registry/blocks/first-run/probe-rules.js +26 -0
- package/registry/blocks/fix-note/README.md +79 -0
- package/registry/blocks/fix-note/block.json +35 -0
- package/registry/blocks/fix-note/demo.jsx +30 -0
- package/registry/blocks/fix-note/fix-note.jsx +235 -0
- package/registry/blocks/fix-note/index.js +3 -0
- package/registry/blocks/flow-editor/README.md +108 -0
- package/registry/blocks/flow-editor/block.json +44 -0
- package/registry/blocks/flow-editor/demo.jsx +115 -0
- package/registry/blocks/flow-editor/flow-canvas.jsx +568 -0
- package/registry/blocks/flow-editor/flow-editor.jsx +154 -0
- package/registry/blocks/flow-editor/index.js +6 -0
- package/registry/blocks/flow-editor/minimap.jsx +78 -0
- package/registry/blocks/flow-editor/outline.jsx +134 -0
- package/registry/blocks/library-shelf/README.md +117 -0
- package/registry/blocks/library-shelf/block.json +28 -0
- package/registry/blocks/library-shelf/demo.jsx +68 -0
- package/registry/blocks/library-shelf/index.js +3 -0
- package/registry/blocks/library-shelf/library-shelf.jsx +211 -0
- package/registry/blocks/library-shelf/probe-rules.js +15 -0
- package/registry/blocks/margin-notes/README.md +222 -0
- package/registry/blocks/margin-notes/block.json +10 -0
- package/registry/blocks/margin-notes/demo.jsx +144 -0
- package/registry/blocks/margin-notes/index.js +20 -0
- package/registry/blocks/margin-notes/margin-model.js +224 -0
- package/registry/blocks/margin-notes/margin-notes.jsx +465 -0
- package/registry/blocks/needs-you/README.md +177 -0
- package/registry/blocks/needs-you/block.json +34 -0
- package/registry/blocks/needs-you/demo.jsx +143 -0
- package/registry/blocks/needs-you/index.js +3 -0
- package/registry/blocks/needs-you/needs-you.jsx +441 -0
- package/registry/blocks/pace-bar/README.md +230 -0
- package/registry/blocks/pace-bar/block.json +10 -0
- package/registry/blocks/pace-bar/demo.jsx +255 -0
- package/registry/blocks/pace-bar/index.js +22 -0
- package/registry/blocks/pace-bar/pace-bar.jsx +461 -0
- package/registry/blocks/pace-bar/pace-model.js +288 -0
- package/registry/blocks/record-grid/README.md +100 -0
- package/registry/blocks/record-grid/block.json +28 -0
- package/registry/blocks/record-grid/demo.jsx +43 -0
- package/registry/blocks/record-grid/index.js +3 -0
- package/registry/blocks/record-grid/record-grid.jsx +251 -0
- package/registry/blocks/run-history/README.md +138 -0
- package/registry/blocks/run-history/block.json +10 -0
- package/registry/blocks/run-history/demo.jsx +74 -0
- package/registry/blocks/run-history/index.js +3 -0
- package/registry/blocks/run-history/run-history.jsx +218 -0
- package/registry/blocks/run-view/README.md +174 -0
- package/registry/blocks/run-view/block.json +50 -0
- package/registry/blocks/run-view/demo.jsx +286 -0
- package/registry/blocks/run-view/index.js +5 -0
- package/registry/blocks/run-view/run-controls.jsx +266 -0
- package/registry/blocks/run-view/run-view.jsx +236 -0
- package/registry/blocks/run-view/runs-list.jsx +99 -0
- package/registry/blocks/schedule-card/README.md +121 -0
- package/registry/blocks/schedule-card/block.json +10 -0
- package/registry/blocks/schedule-card/demo.jsx +82 -0
- package/registry/blocks/schedule-card/index.js +3 -0
- package/registry/blocks/schedule-card/schedule-card.jsx +136 -0
- package/registry/blocks/schedule-engine/README.md +137 -0
- package/registry/blocks/schedule-engine/block.json +10 -0
- package/registry/blocks/schedule-engine/demo.jsx +82 -0
- package/registry/blocks/schedule-engine/engine.js +769 -0
- package/registry/blocks/schedule-engine/index.js +9 -0
- package/registry/blocks/schedule-engine/ops.js +71 -0
- package/registry/blocks/schedule-engine/place.js +294 -0
- package/registry/blocks/schedule-engine/tree.js +79 -0
- package/registry/blocks/schedule-engine/waits.js +80 -0
- package/registry/blocks/schedule-gantt/README.md +159 -0
- package/registry/blocks/schedule-gantt/block.json +10 -0
- package/registry/blocks/schedule-gantt/demo.jsx +223 -0
- package/registry/blocks/schedule-gantt/gantt-model.js +219 -0
- package/registry/blocks/schedule-gantt/geometry.js +176 -0
- package/registry/blocks/schedule-gantt/index.js +26 -0
- package/registry/blocks/schedule-gantt/schedule-gantt.jsx +882 -0
- package/registry/blocks/schedule-gantt/sheet.jsx +372 -0
- package/registry/blocks/schedule-gantt/track.jsx +190 -0
- package/registry/blocks/schedule-ruler/README.md +148 -0
- package/registry/blocks/schedule-ruler/block.json +10 -0
- package/registry/blocks/schedule-ruler/demo.jsx +181 -0
- package/registry/blocks/schedule-ruler/index.js +21 -0
- package/registry/blocks/schedule-ruler/ruler-model.js +239 -0
- package/registry/blocks/schedule-ruler/schedule-ruler.jsx +548 -0
- package/registry/blocks/source-receipt/README.md +97 -0
- package/registry/blocks/source-receipt/block.json +30 -0
- package/registry/blocks/source-receipt/demo.jsx +71 -0
- package/registry/blocks/source-receipt/index.js +3 -0
- package/registry/blocks/source-receipt/source-receipt.jsx +107 -0
- package/registry/blocks/spreadsheet/spreadsheet.jsx +15 -1
- package/registry/blocks/step-picker/README.md +78 -0
- package/registry/blocks/step-picker/block.json +31 -0
- package/registry/blocks/step-picker/demo.jsx +23 -0
- package/registry/blocks/step-picker/index.js +3 -0
- package/registry/blocks/step-picker/step-picker.jsx +144 -0
- package/registry/blocks/step-settings/README.md +100 -0
- package/registry/blocks/step-settings/block.json +44 -0
- package/registry/blocks/step-settings/demo.jsx +93 -0
- package/registry/blocks/step-settings/fields.jsx +58 -0
- package/registry/blocks/step-settings/flow-settings.jsx +115 -0
- package/registry/blocks/step-settings/index.js +5 -0
- package/registry/blocks/step-settings/step-settings.jsx +290 -0
- package/registry/blocks/suggestion/README.md +171 -0
- package/registry/blocks/suggestion/block.json +40 -0
- package/registry/blocks/suggestion/demo.jsx +91 -0
- package/registry/blocks/suggestion/index.js +3 -0
- package/registry/blocks/suggestion/suggestion.jsx +436 -0
- package/registry/blocks/sum-bar/README.md +122 -0
- package/registry/blocks/sum-bar/block.json +10 -0
- package/registry/blocks/sum-bar/demo.jsx +110 -0
- package/registry/blocks/sum-bar/index.js +5 -0
- package/registry/blocks/sum-bar/sum-bar.jsx +209 -0
- package/registry/blocks/sum-bar/sum-model.js +126 -0
- package/registry/blocks/tier-map/README.md +217 -0
- package/registry/blocks/tier-map/block.json +10 -0
- package/registry/blocks/tier-map/demo.jsx +222 -0
- package/registry/blocks/tier-map/index.js +24 -0
- package/registry/blocks/tier-map/tier-map.jsx +574 -0
- package/registry/blocks/tier-map/tier-model.js +318 -0
- package/registry/blocks/time-grid/README.md +305 -0
- package/registry/blocks/time-grid/block.json +10 -0
- package/registry/blocks/time-grid/demo.jsx +279 -0
- package/registry/blocks/time-grid/grid-model.js +322 -0
- package/registry/blocks/time-grid/index.js +25 -0
- package/registry/blocks/time-grid/time-grid.jsx +1325 -0
- package/registry/blocks/time-strip/README.md +141 -0
- package/registry/blocks/time-strip/block.json +10 -0
- package/registry/blocks/time-strip/demo.jsx +129 -0
- package/registry/blocks/time-strip/index.js +19 -0
- package/registry/blocks/time-strip/strip-model.js +178 -0
- package/registry/blocks/time-strip/time-strip.jsx +260 -0
- package/registry/blocks/top-bar/README.md +149 -0
- package/registry/blocks/top-bar/block.json +35 -0
- package/registry/blocks/top-bar/demo.jsx +78 -0
- package/registry/blocks/top-bar/index.js +5 -0
- package/registry/blocks/top-bar/probe-rules.js +74 -0
- package/registry/blocks/top-bar/top-bar-model.js +152 -0
- package/registry/blocks/top-bar/top-bar.jsx +244 -0
- package/registry/blocks/trigger-picker/README.md +98 -0
- package/registry/blocks/trigger-picker/block.json +38 -0
- package/registry/blocks/trigger-picker/demo.jsx +59 -0
- package/registry/blocks/trigger-picker/index.js +3 -0
- package/registry/blocks/trigger-picker/trigger-picker.jsx +374 -0
- package/registry/blocks/workflow-view/README.md +123 -0
- package/registry/blocks/workflow-view/block.json +10 -0
- package/registry/blocks/workflow-view/demo.jsx +90 -0
- package/registry/blocks/workflow-view/index.js +3 -0
- package/registry/blocks/workflow-view/workflow-view.jsx +203 -0
- package/src/install.mjs +77 -16
- package/src/registry.mjs +3 -0
- package/templates/next/browser/lib/data.js +6 -1
- package/templates/next/files/README.md +627 -24
- package/templates/next/files/check/automation-format.ts +2103 -0
- package/templates/next/files/check/automation-package.ts +142 -0
- package/templates/next/files/check/run.mjs +968 -9
- package/templates/next/files/components/ui/field.jsx +17 -4
- package/templates/next/files/components/ui/icon.jsx +13 -0
- package/templates/next/files/components/ui/index.js +2 -1
- package/templates/next/files/components/ui/layout.jsx +77 -2
- package/templates/next/files/components/ui/notice.jsx +70 -0
- package/templates/next/files/components/ui/page.jsx +124 -0
- package/templates/next/files/components/ui/stat.jsx +22 -7
- package/templates/next/files/components/ui/toast.jsx +6 -3
- package/templates/next/files/lib/automations.js +660 -0
- package/templates/next/files/lib/claw.js +241 -5
- package/templates/next/files/lib/door.js +92 -0
- package/templates/next/files/lib/hooks.js +1627 -8
- package/templates/next/files/lib/platform.js +529 -21
- package/templates/next/template.json +13 -3
|
@@ -21,9 +21,22 @@
|
|
|
21
21
|
// cancelJob): kept for a claw that has no `ask` yet. `llm` (0.8.0) is one
|
|
22
22
|
// shot of model work answered in the page, not asking an agent: lib/
|
|
23
23
|
// platform.js wraps it as llm and lib/hooks.js as useLlm, and the check
|
|
24
|
-
// refuses a screen that names its path.
|
|
25
|
-
//
|
|
26
|
-
//
|
|
24
|
+
// refuses a screen that names its path. `library` (0.8.1) is the
|
|
25
|
+
// Library's door, read only: collections of files and rows that Makersclaw
|
|
26
|
+
// keeps; lib/platform.js wraps it as library, lib/hooks.js as the
|
|
27
|
+
// useLibrary… hooks, and the check refuses a screen that names its path
|
|
28
|
+
// too. `threads` (0.8.1) reads the member's own threads in this app, the
|
|
29
|
+
// same conversation the desk's column shows: lib/platform.js wraps it as
|
|
30
|
+
// threads / thread, lib/hooks.js as useAgentThread, and the `agent-chat`
|
|
31
|
+
// block draws it — the app's own chat. Since the kit (0.8.1, D15) the
|
|
32
|
+
// app also reads its own jobs, runs, activity, accounts and agent kit
|
|
33
|
+
// (`jobs`, `runs`, `data/activity`, `connect`, `agent`) and may press Run
|
|
34
|
+
// now, the on/off switch and Live (`run`, `jobs/:id`, `pause`, `resume`):
|
|
35
|
+
// lib/platform.js wraps them, lib/hooks.js follows them, and the kit's
|
|
36
|
+
// blocks draw them in the app's look. The OS kept them as tabs so every
|
|
37
|
+
// app looked the same; the blocks now give that sameness inside the app,
|
|
38
|
+
// and the tabs stay as the full history. The yes, the account sign-in
|
|
39
|
+
// and money stay on the desk. The rest of the gateway's routes (§5) stay
|
|
27
40
|
// reachable through claw() / clawStream() for a surface that has a real
|
|
28
41
|
// reason.
|
|
29
42
|
|
|
@@ -130,13 +143,24 @@ function framed(win) {
|
|
|
130
143
|
* Ask the desk to open a request's conversation in its agent column.
|
|
131
144
|
* Posts only when the app is framed and the desk's origin is known, and
|
|
132
145
|
* only to that origin. → true when the message went.
|
|
146
|
+
*
|
|
147
|
+
* `show` (0.8.1): the member pressed something to see it on the desk
|
|
148
|
+
* ("Open on the desk", a yes's link). An app that draws its own chat (the
|
|
149
|
+
* `agent-chat` block, `"agent_in_app": true` in the package's blueprint)
|
|
150
|
+
* has its column opened only then; without it the desk only points its
|
|
151
|
+
* column at the conversation, quietly.
|
|
133
152
|
*/
|
|
134
|
-
export function openInDesk({ requestId, sessionId } = {}, win = currentWindow()) {
|
|
153
|
+
export function openInDesk({ requestId, sessionId, show = false } = {}, win = currentWindow()) {
|
|
135
154
|
const origin = deskOrigin();
|
|
136
155
|
if (!requestId || !origin || !framed(win)) return false;
|
|
137
156
|
try {
|
|
138
157
|
win.parent.postMessage(
|
|
139
|
-
{
|
|
158
|
+
{
|
|
159
|
+
type: OPEN_REQUEST_MESSAGE,
|
|
160
|
+
request_id: String(requestId),
|
|
161
|
+
session_id: sessionId ? String(sessionId) : null,
|
|
162
|
+
...(show ? { show: true } : {}),
|
|
163
|
+
},
|
|
140
164
|
origin,
|
|
141
165
|
);
|
|
142
166
|
return true;
|
|
@@ -145,12 +169,121 @@ export function openInDesk({ requestId, sessionId } = {}, win = currentWindow())
|
|
|
145
169
|
}
|
|
146
170
|
}
|
|
147
171
|
|
|
172
|
+
/** The message the app posts to the desk: open the connections panel
|
|
173
|
+
* for one of the app's declared accounts (0.8.1, the kit's
|
|
174
|
+
* `connect-card`). The desk checks the key against the app's declared
|
|
175
|
+
* needs and opens its drawer for that need's category, so every
|
|
176
|
+
* provider of the kind shows; signing in stays the member's, at the
|
|
177
|
+
* provider. */
|
|
178
|
+
export const OPEN_CONNECTIONS_MESSAGE = "claw:open-connections";
|
|
179
|
+
|
|
180
|
+
/** A declared account's key, as the desk takes it. */
|
|
181
|
+
const CONNECTION_KEY = /^[a-z0-9_-]{1,64}$/i;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Ask the desk to open its connections panel for the declared account
|
|
185
|
+
* `key`. Posts only when the app is framed, the desk's origin is known
|
|
186
|
+
* and the key has the desk's shape, and only to that origin, like
|
|
187
|
+
* openInDesk. → true when the message went; false means there is no desk
|
|
188
|
+
* to ask (the app on its own host): hand out the link instead
|
|
189
|
+
* (lib/platform.js connectLink).
|
|
190
|
+
*/
|
|
191
|
+
export function openConnections(key, win = currentWindow()) {
|
|
192
|
+
const origin = deskOrigin();
|
|
193
|
+
if (typeof key !== "string" || !CONNECTION_KEY.test(key) || !origin || !framed(win)) return false;
|
|
194
|
+
try {
|
|
195
|
+
win.parent.postMessage({ type: OPEN_CONNECTIONS_MESSAGE, key }, origin);
|
|
196
|
+
return true;
|
|
197
|
+
} catch {
|
|
198
|
+
return false; // a parent that will not take messages
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** The messages the app posts to the desk: open an app the agent made, or
|
|
203
|
+
* a file it wrote (0.8.1, D27 phase 4: the `agent-pane` block's "Open").
|
|
204
|
+
* The desk checks the sender is this frame and the ids have their shape
|
|
205
|
+
* (claw's web/src/components/play/frame-grant.ts), then navigates; the app
|
|
206
|
+
* never navigates the desk itself. */
|
|
207
|
+
export const OPEN_APP_MESSAGE = "claw:open-app";
|
|
208
|
+
export const OPEN_FILE_MESSAGE = "claw:open-file";
|
|
209
|
+
|
|
210
|
+
/** An app's id as the desk takes it: a uuid. */
|
|
211
|
+
const APP_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Ask the desk to open an app the agent made. Posts only when the app is
|
|
215
|
+
* framed, the desk's origin is known and the id is a uuid, and only to that
|
|
216
|
+
* origin, like openInDesk. → true when the message went; false means there
|
|
217
|
+
* is no desk to ask (the app on its own host).
|
|
218
|
+
*/
|
|
219
|
+
export function openApp(id, win = currentWindow()) {
|
|
220
|
+
const origin = deskOrigin();
|
|
221
|
+
if (typeof id !== "string" || !APP_ID.test(id) || !origin || !framed(win)) return false;
|
|
222
|
+
try {
|
|
223
|
+
win.parent.postMessage({ type: OPEN_APP_MESSAGE, id }, origin);
|
|
224
|
+
return true;
|
|
225
|
+
} catch {
|
|
226
|
+
return false; // a parent that will not take messages
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Ask the desk to open a file the agent wrote: `where` is "workspace" (the
|
|
232
|
+
* workspace's Files, at `path`) or "app" (the app `appRef`). Same rules as
|
|
233
|
+
* openApp. → true when the message went.
|
|
234
|
+
*/
|
|
235
|
+
export function openFile({ path, where, appRef } = {}, win = currentWindow()) {
|
|
236
|
+
const origin = deskOrigin();
|
|
237
|
+
if (!origin || !framed(win)) return false;
|
|
238
|
+
if (where === "workspace") {
|
|
239
|
+
if (typeof path !== "string" || !path || path.length > 500) return false;
|
|
240
|
+
} else if (where === "app") {
|
|
241
|
+
if (typeof appRef !== "string" || !APP_ID.test(appRef)) return false;
|
|
242
|
+
} else {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
win.parent.postMessage(
|
|
247
|
+
{ type: OPEN_FILE_MESSAGE, where, ...(where === "workspace" ? { path } : { app_ref: appRef }) },
|
|
248
|
+
origin,
|
|
249
|
+
);
|
|
250
|
+
return true;
|
|
251
|
+
} catch {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
148
256
|
/** Is this message from the desk, of this type? Only the window around
|
|
149
257
|
* the frame may send one — app/frame.js isDeskEscape, for any type. */
|
|
150
258
|
export function isDeskMessage(event, type, win = currentWindow()) {
|
|
151
259
|
return Boolean(framed(win) && event?.source === win.parent && event?.data?.type === type);
|
|
152
260
|
}
|
|
153
261
|
|
|
262
|
+
/** The message the press frame posts to the page that embeds it (0.8.1,
|
|
263
|
+
* D18; the `approval` block, useApproval): `ready`, `size`, `approved`,
|
|
264
|
+
* `declined`, `stale`, `signin`, `error`. The frame is a page of
|
|
265
|
+
* Makersclaw's in another origin, so the only thing this page can do with
|
|
266
|
+
* it is listen. */
|
|
267
|
+
export const PRESS_MESSAGE = "claw:press";
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Read a message as the press frame's, or null. Only what came from the
|
|
271
|
+
* frame's own window AND its own origin counts, and only for the request
|
|
272
|
+
* it was drawn for: app code in another frame, or a script posting to
|
|
273
|
+
* itself, cannot make the page believe a yes was given. (It could not
|
|
274
|
+
* give one anyway: the press is the frame's and the server's. This only
|
|
275
|
+
* keeps the card's words true.)
|
|
276
|
+
* → { type, request_id, state, … } | null
|
|
277
|
+
*/
|
|
278
|
+
export function pressMessage(event, { origin, source, request } = {}) {
|
|
279
|
+
if (!event || typeof origin !== "string" || !origin || event.origin !== origin) return null;
|
|
280
|
+
if (!source || event.source !== source) return null;
|
|
281
|
+
const data = event.data;
|
|
282
|
+
if (!data || typeof data !== "object" || data.type !== PRESS_MESSAGE) return null;
|
|
283
|
+
if (request && data.request_id !== request) return null;
|
|
284
|
+
return data;
|
|
285
|
+
}
|
|
286
|
+
|
|
154
287
|
/** A refusal's words, and its `code` when the gateway names one
|
|
155
288
|
* (`not_your_thread`, `needs_answer`, …): the code is what a caller
|
|
156
289
|
* branches on, the words are what it shows. */
|
|
@@ -302,19 +435,122 @@ export async function clawStream(path, body, onEvent, { signal } = {}) {
|
|
|
302
435
|
return { ok: true, status: res.status, data: null };
|
|
303
436
|
}
|
|
304
437
|
|
|
438
|
+
/**
|
|
439
|
+
* GET a newline-delimited JSON stream (0.8.1, D27 phase 4: the thread
|
|
440
|
+
* pushed as the agent writes). `onLine(object)` is called for every line as
|
|
441
|
+
* it arrives. Resolves when the stream ends, with claw()'s shape: a 404
|
|
442
|
+
* (`unavailable`, or with a `code` a route refusing) or another refusal
|
|
443
|
+
* comes back as itself; a clean end is { ok: true }; a broken body is
|
|
444
|
+
* { ok: false, error } so the caller falls back to polling.
|
|
445
|
+
*/
|
|
446
|
+
export async function clawNdjson(path, onLine, { signal } = {}) {
|
|
447
|
+
let res;
|
|
448
|
+
try {
|
|
449
|
+
res = await fetch(clawUrl(path), {
|
|
450
|
+
method: "GET",
|
|
451
|
+
credentials: "same-origin",
|
|
452
|
+
cache: "no-store",
|
|
453
|
+
headers: { accept: "application/x-ndjson" },
|
|
454
|
+
signal,
|
|
455
|
+
});
|
|
456
|
+
} catch (error) {
|
|
457
|
+
if (error?.name === "AbortError") return { ok: false, status: 0, error: "aborted", aborted: true };
|
|
458
|
+
return { ok: false, status: 0, error: "not reachable", unavailable: true };
|
|
459
|
+
}
|
|
460
|
+
if (res.status === 404) return notFound(res);
|
|
461
|
+
if (!res.ok) return { ok: false, status: res.status, ...(await readFailure(res)), unavailable: false };
|
|
462
|
+
if (!res.body) return { ok: false, status: res.status, error: "empty stream" };
|
|
463
|
+
const reader = res.body.getReader();
|
|
464
|
+
const decoder = new TextDecoder();
|
|
465
|
+
let buffer = "";
|
|
466
|
+
const dispatch = (line) => {
|
|
467
|
+
const text = line.trim();
|
|
468
|
+
if (!text) return;
|
|
469
|
+
let parsed = null;
|
|
470
|
+
try {
|
|
471
|
+
parsed = JSON.parse(text);
|
|
472
|
+
} catch {
|
|
473
|
+
return; // a torn line is skipped
|
|
474
|
+
}
|
|
475
|
+
if (parsed && typeof parsed === "object") onLine(parsed);
|
|
476
|
+
};
|
|
477
|
+
try {
|
|
478
|
+
for (;;) {
|
|
479
|
+
const { value, done } = await reader.read();
|
|
480
|
+
if (done) break;
|
|
481
|
+
buffer += decoder.decode(value, { stream: true });
|
|
482
|
+
let idx;
|
|
483
|
+
while ((idx = buffer.indexOf("\n")) >= 0) {
|
|
484
|
+
dispatch(buffer.slice(0, idx));
|
|
485
|
+
buffer = buffer.slice(idx + 1);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
dispatch(buffer);
|
|
489
|
+
} catch (error) {
|
|
490
|
+
if (error?.name === "AbortError") return { ok: false, status: 0, error: "aborted", aborted: true };
|
|
491
|
+
return { ok: false, status: res.status, error: `stream broke: ${String(error)}` };
|
|
492
|
+
}
|
|
493
|
+
return { ok: true, status: res.status, data: null };
|
|
494
|
+
}
|
|
495
|
+
|
|
305
496
|
let posted = 0;
|
|
306
497
|
const seen = new Set();
|
|
307
498
|
|
|
499
|
+
/**
|
|
500
|
+
* Browser notices that are not errors (0.8.1, D28). A browser tells a page
|
|
501
|
+
* some things through window.onerror that nothing in the app caused and
|
|
502
|
+
* nobody can act on. The worst is "ResizeObserver loop completed with
|
|
503
|
+
* undelivered notifications": a resize callback ran out of frames and the
|
|
504
|
+
* rest waits for the next one. Reported as an error it used to start a
|
|
505
|
+
* repair of the app, which found nothing to change. They are never sent.
|
|
506
|
+
*
|
|
507
|
+
* Kept in step with claw's agent-app/src/lib/app-error-notices.ts, which
|
|
508
|
+
* drops the same ones again at the _claw/events door (an app on an older
|
|
509
|
+
* template still reports them). A notice joins the list only with a reason
|
|
510
|
+
* and a test (test/error-report.test.mjs). When unsure, report.
|
|
511
|
+
*/
|
|
512
|
+
export const HARMLESS_NOTICES = [
|
|
513
|
+
{
|
|
514
|
+
name: "resize-observer",
|
|
515
|
+
message: /^ResizeObserver loop (completed with undelivered notifications|limit exceeded)\.?$/i,
|
|
516
|
+
},
|
|
517
|
+
{ name: "script-error", message: /^Script error\.?$/i },
|
|
518
|
+
{
|
|
519
|
+
name: "aborted-request",
|
|
520
|
+
message:
|
|
521
|
+
/^(AbortError: )?(The (user|operation) aborted( a request| was aborted)?|signal is aborted without reason|The operation was aborted|Fetch is aborted|The user aborted a request)\.?$/i,
|
|
522
|
+
},
|
|
523
|
+
{ name: "browser-extension", stack: /(chrome|moz|safari|ms-browser)-extension:\/\//i },
|
|
524
|
+
];
|
|
525
|
+
|
|
526
|
+
/** The name of the harmless notice this is, or null for a real error. */
|
|
527
|
+
export function harmlessNotice(message, stack) {
|
|
528
|
+
const text = typeof message === "string" ? message.trim() : "";
|
|
529
|
+
const trace = typeof stack === "string" ? stack : "";
|
|
530
|
+
for (const notice of HARMLESS_NOTICES) {
|
|
531
|
+
if (notice.message?.test(text)) return notice.name;
|
|
532
|
+
if (notice.stack && (notice.stack.test(trace) || notice.stack.test(text))) return notice.name;
|
|
533
|
+
}
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
|
|
308
537
|
/**
|
|
309
538
|
* Report a browser-side error to Makersclaw (POST _claw/events). Deduped
|
|
310
539
|
* by message+stack and capped per page load, so an error that fires on
|
|
311
540
|
* every render cannot flood the gateway. Best-effort: never throws.
|
|
541
|
+
* A harmless browser notice (harmlessNotice, above) is not reported.
|
|
542
|
+
* Nothing is repaired because of a report: it lands on the app's error
|
|
543
|
+
* list in the Activity tab and the member presses Fix it (D28).
|
|
312
544
|
*
|
|
313
545
|
* `source` defaults to errorSource() — "preview" while the artifact is a
|
|
314
546
|
* draft, "runtime" once launched — so the bench and the platform agent can
|
|
315
547
|
* tell the two apart. Pass it only when the caller knows better.
|
|
316
548
|
*/
|
|
317
549
|
export async function reportError({ message, stack, url, source }) {
|
|
550
|
+
// A browser notice is not an error: not sent, and not counted against
|
|
551
|
+
// the page's 20.
|
|
552
|
+
const notice = harmlessNotice(message, stack);
|
|
553
|
+
if (notice) return { ok: false, status: 0, error: "ignored", ignored: notice };
|
|
318
554
|
const key = `${message}\n${stack ?? ""}`;
|
|
319
555
|
if (seen.has(key) || posted >= 20) return { ok: false, status: 0, error: "skipped" };
|
|
320
556
|
seen.add(key);
|
|
@@ -35,6 +35,10 @@ import { surfaceOfPath } from "./platform";
|
|
|
35
35
|
// - Every write that answers ok calls dataChanged(). Every mounted hook
|
|
36
36
|
// reads again, and whenLanded() resolves once they have all handed
|
|
37
37
|
// out their new rows, in one pass.
|
|
38
|
+
// - A page that opens a row it just made does it with afterWrite(): the
|
|
39
|
+
// write, then the hooks' new rows, then the open. A record page says
|
|
40
|
+
// "not found" only through useNotFound(): never while a write or a
|
|
41
|
+
// re-read is out, which is when the new row is not in the page yet.
|
|
38
42
|
// - Nothing here logs activity: the door writes the line. `data` on
|
|
39
43
|
// updateRow is taken and never sent (a value never goes in a line).
|
|
40
44
|
|
|
@@ -253,15 +257,25 @@ export function loadActivity(args) {
|
|
|
253
257
|
// Actions so; plain fetches overlap, and a whole-document save that
|
|
254
258
|
// answered slowly would land over the newer one after it.
|
|
255
259
|
let turn = Promise.resolve();
|
|
260
|
+
let writesOut = 0;
|
|
256
261
|
|
|
257
262
|
/** Run `work` once every write called before it has answered. The
|
|
258
263
|
* brain's writes (lib/brain.js) take their turn here too. */
|
|
259
264
|
export function inTurn(work) {
|
|
265
|
+
writesOut += 1;
|
|
266
|
+
announce();
|
|
260
267
|
const run = turn.then(work, work);
|
|
261
268
|
turn = run.then(
|
|
262
269
|
() => undefined,
|
|
263
270
|
() => undefined,
|
|
264
271
|
);
|
|
272
|
+
// `work` has called dataChanged() by the time it answers, so the page is
|
|
273
|
+
// never "settled" between a write answering and its re-read starting.
|
|
274
|
+
const done = () => {
|
|
275
|
+
writesOut -= 1;
|
|
276
|
+
announce();
|
|
277
|
+
};
|
|
278
|
+
run.then(done, done);
|
|
265
279
|
return run;
|
|
266
280
|
}
|
|
267
281
|
|
|
@@ -438,6 +452,7 @@ export function dataChanged() {
|
|
|
438
452
|
return;
|
|
439
453
|
}
|
|
440
454
|
startLanding();
|
|
455
|
+
announce();
|
|
441
456
|
}
|
|
442
457
|
|
|
443
458
|
/** Resolves when every read the last dataChanged() started has answered
|
|
@@ -447,6 +462,81 @@ export function whenLanded() {
|
|
|
447
462
|
return new Promise((resolve) => waiting.push(resolve));
|
|
448
463
|
}
|
|
449
464
|
|
|
465
|
+
/** A write, and then the page holding what it wrote: resolves with the
|
|
466
|
+
* write's own answer once the hooks have handed out their new rows. A
|
|
467
|
+
* failed write (`ok: false`) answers at once, with nothing to wait for.
|
|
468
|
+
* This is the way to do "make a row, then open it":
|
|
469
|
+
*
|
|
470
|
+
* const out = await afterWrite(runAction({ name: "add_project", args }));
|
|
471
|
+
* if (out.ok) router.push(`/s/today?row=${out.result.id}`);
|
|
472
|
+
*
|
|
473
|
+
* Without it the page opens a row the hooks do not hold yet. Takes a
|
|
474
|
+
* promise or an answer already in hand. Never throws. */
|
|
475
|
+
export async function afterWrite(write) {
|
|
476
|
+
let out;
|
|
477
|
+
try {
|
|
478
|
+
out = await write;
|
|
479
|
+
} catch (error) {
|
|
480
|
+
return { ok: false, error: String(error?.message ?? error), code: "failed" };
|
|
481
|
+
}
|
|
482
|
+
if (out && out.ok === false) return out;
|
|
483
|
+
await whenLanded();
|
|
484
|
+
return out;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Whether the page holds what was written. Settled: no write is out, no
|
|
488
|
+
// re-read is out, none is waiting to start. A record page asks this before
|
|
489
|
+
// it says "not found" (useNotFound), so it never says it against a world
|
|
490
|
+
// that was read before the last write.
|
|
491
|
+
const watchers = new Set();
|
|
492
|
+
const isSettled = () => writesOut === 0 && !landing && !again;
|
|
493
|
+
|
|
494
|
+
function announce() {
|
|
495
|
+
const now = isSettled();
|
|
496
|
+
for (const watch of [...watchers]) {
|
|
497
|
+
try {
|
|
498
|
+
watch(now);
|
|
499
|
+
} catch {
|
|
500
|
+
/* one watcher's failure is not the others' */
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/** True while the page holds everything written so far: no write is out,
|
|
506
|
+
* and the re-read after the last one has landed. False the moment a write
|
|
507
|
+
* is called until its rows are in the hooks. */
|
|
508
|
+
export function useSettled() {
|
|
509
|
+
const [settled, set] = useState(isSettled);
|
|
510
|
+
useEffect(() => {
|
|
511
|
+
watchers.add(set);
|
|
512
|
+
set(isSettled());
|
|
513
|
+
return () => {
|
|
514
|
+
watchers.delete(set);
|
|
515
|
+
};
|
|
516
|
+
}, []);
|
|
517
|
+
return settled;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Whether a record page may say "not found" now. A record page looks its
|
|
522
|
+
* row up in what the hooks hold; right after a create that is the world
|
|
523
|
+
* read BEFORE the write, and the row is not in it yet. So "not found" is
|
|
524
|
+
* only ever said about a read that started after the last write:
|
|
525
|
+
*
|
|
526
|
+
* const gone = useNotFound(Boolean(project), { loading: world.loading });
|
|
527
|
+
* if (!project) return gone ? <NotFound /> : <Loading />;
|
|
528
|
+
*
|
|
529
|
+
* found whether the record is in what the page holds
|
|
530
|
+
* loading whether the page's first read is still out (default false)
|
|
531
|
+
* → true only when it is not found, nothing is loading, and no write or
|
|
532
|
+
* re-read is out. While it is false and `found` is false, show the
|
|
533
|
+
* loading state.
|
|
534
|
+
*/
|
|
535
|
+
export function useNotFound(found, { loading = false } = {}) {
|
|
536
|
+
const settled = useSettled();
|
|
537
|
+
return !found && !loading && settled;
|
|
538
|
+
}
|
|
539
|
+
|
|
450
540
|
function startLanding() {
|
|
451
541
|
again = false;
|
|
452
542
|
const run = { open: true, pending: new Set(), handOut: [], timer: null };
|
|
@@ -493,9 +583,11 @@ function closeLanding(run) {
|
|
|
493
583
|
if (landing === run) landing = null;
|
|
494
584
|
if (again) {
|
|
495
585
|
startLanding();
|
|
586
|
+
announce();
|
|
496
587
|
return;
|
|
497
588
|
}
|
|
498
589
|
for (const resolve of waiting.splice(0)) resolve();
|
|
590
|
+
announce();
|
|
499
591
|
}
|
|
500
592
|
|
|
501
593
|
// A hook's options are compared by value on every render: a new object
|