Commit Graph
302 Commits
Author SHA1 Message Date
stroblmeandClaude Opus 5.5 0d382edcbf Superuser route to flush the metrics collector now
POST /observability/flush handles what the collector has queued and writes
it, so the soak harness no longer sleeps FLUSH_INTERVAL_S before clearing
its own rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 09:53:19 +02:00
stroblmeandClaude Opus 5.5 2dc9295c26 Audit shared-library source writes
A shared source goes live in every flow using it the moment it is saved, so
the write is recorded in the audit trail like a publish. Private source saves
stay drafts and are not audited.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 09:50:04 +02:00
stroblmeandClaude Opus 5.5 be85c6c92a Retire a shared node in use with ?detach=true
DELETE /flows/library/{name} still answers 409 while nodes use the source.
With detach=true each of them keeps a copy of the code, in the published
flow and the draft, the source is deleted and the running users rebuild.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 09:48:47 +02:00
stroblmeandClaude Opus 5.5 0746c94e0a Warn when a node that runs no code names a device
A device on a node without source was accepted and silently ignored. The
build now reports it as ignored_device, an advisory issue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 09:45:24 +02:00
stroblmeandClaude Opus 5.5 13567f8990 Give a rate-limit flush its own run, linked to the run that held the value
A flush ran its cascade under no id, so its executions and failures belonged
to no run. It now records a run with source "flush", and the holding run's id
travels on the queue item into a new `flow_run.parent` column, also on the
`/observability/runs` rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 09:37:30 +02:00
stroblmeandClaude Opus 5.5 c7e38a8a44 Rename the trigger node type to debounce, migrating stored flows
The store rewrites `"type": "trigger"` to `debounce` in every published and
draft flow when it opens, bumps the version and commits once. No alias stays
behind, so `trigger` is now an unknown type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 09:34:40 +02:00
stroblmeandClaude Opus 5.5 235a9201a8 Merge remote-tracking branch 'origin/main'
Docs / docs (push) Successful in 22s
Playwright Tests / test-playwright (1, 2) (push) Failing after 4m39s
Playwright Tests / test-playwright (2, 2) (push) Successful in 2m17s
pre-commit / pre-commit (push) Failing after 2m37s
Test Backend / test-backend (push) Failing after 3m37s
Compose Smoke Test / test-compose (push) Successful in 33s
Playwright Tests / merge-reports (push) Successful in 1m38s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 08:20:11 +02:00
Melvin Strobl 36fafae065 Merge remote-tracking branch 'origin/main'
Docs / docs (push) Successful in 49s
Playwright Tests / test-playwright (1, 2) (push) Failing after 4m41s
Playwright Tests / test-playwright (2, 2) (push) Successful in 2m16s
pre-commit / pre-commit (push) Failing after 4m23s
Test Backend / test-backend (push) Failing after 4m54s
Compose Smoke Test / test-compose (push) Successful in 38s
Playwright Tests / merge-reports (push) Successful in 1m41s
2026-10-15 07:47:21 +02:00
stroblmeandClaude Opus 5.5 278a480a5c Endpoint labels sweep instead of pulse: left to right on a label publishing into the flow, right to left on one reading out of it, one pulse long, off under reduced motion; snapshot values are marked prior so catching up sweeps nothing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 00:23:01 +02:00
stroblmeandClaude Opus 5.5 98416dc516 Dashboard editor undo: ⌘Z / ⇧⌘Z over a 50-entry history of commits, folding keystrokes and the grid's own correction as the flow editor does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 00:07:58 +02:00
stroblmeandClaude Opus 5.5 0a9ea24b93 Stored state lists its keys, each with a two-press delete beside Clear
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 00:04:03 +02:00
stroblmeandClaude Opus 5.5 f2305ef619 Phone header: assistant button in the corner, gated on an available provider as the sidebar entry is; header triggers on the right at 44px
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-14 23:41:30 +02:00
stroblmeandClaude Opus 5.5 b0c07a35e9 Locked slider dims its rail: :has() on the slider, since the rail comes before the input and no sibling selector reaches it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-14 23:41:29 +02:00
stroblmeandClaude Opus 5.5 43fb446297 Stat unit sized against the hero numerals: dui-hero on the readout's outer span, so the unit's 0.4em is of the hero rather than the 14px body text
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-14 23:41:28 +02:00
stroblmeandClaude Opus 5.5 9145b7d1c0 ValueSource kind includes panel; Panels dialog no longer suggests the screen port openpanel does not serve
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-14 23:32:32 +02:00
stroblmeandClaude Opus 5.5 f2b7a23b4f Socket snapshot carries the nodes waiting for a machine, so a reconnecting browser restores their queued dots
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-14 23:31:54 +02:00
Melvin StroblandClaude Opus 5.5 78498cbbf8 Dashboard name pill opaque: the look's card colour with a hairline border, no blur
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ezWcLmBCtTVKFPxfdK2MK
2026-10-14 22:19:34 +02:00
Melvin StroblandClaude Opus 5.5 2a9b39ddb1 Dashboard name pill on a round panel: 56 high, icon and title at 24, at most 280 wide
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ezWcLmBCtTVKFPxfdK2MK
2026-10-14 22:16:00 +02:00
stroblmeandClaude Opus 5.5 b18cb30492 Add websocket node: client or served socket, listener or sender
Docs / docs (push) Successful in 26s
Playwright Tests / test-playwright (1, 2) (push) Failing after 3m56s
Playwright Tests / test-playwright (2, 2) (push) Successful in 2m1s
pre-commit / pre-commit (push) Failing after 2m38s
Test Backend / test-backend (push) Failing after 3m18s
Compose Smoke Test / test-compose (push) Successful in 46s
Playwright Tests / merge-reports (push) Successful in 1m35s
ws:// and wss:// URLs dial out and hold a supervised connection; a path is
served under /hooks/<flow>/ with an optional secret. Outputs only listen,
inputs send. Frames are JSON keyed by port, with json_key and on_connect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011CT3mowxKeZywDCH4fS1gt
2026-10-14 18:42:19 +02:00
Melvin StroblandClaude Opus 5.5 0bf2b12268 Round panel: the dashboards either side drawn in advance and live, on the face they open on, and dragged in up and down as faces are sideways; the name pill only on landing
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:20:22 +02:00
Melvin StroblandClaude Opus 5.5 603635f947 Round paging follows the finger: faces and dashboards on a track, swiped one to one with the next beside it, turned or sent back on release, rubber-banded at the ends; keys and dots slide the same track; the reading dot a smaller companion of the handle
Docs / docs (push) Successful in 24s
Playwright Tests / test-playwright (1, 2) (push) Failing after 4m14s
Playwright Tests / test-playwright (2, 2) (push) Successful in 2m11s
pre-commit / pre-commit (push) Failing after 2m2s
Test Backend / test-backend (push) Failing after 3m23s
Compose Smoke Test / test-compose (push) Successful in 34s
Playwright Tests / merge-reports (push) Successful in 1m33s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:08:51 +02:00
Melvin StroblandClaude Opus 5.5 541dbce584 Round faces: a bar as concentric arcs with a legend in the middle; larger title, gap line and face text; Read-only in the ring's gap; a round dashboard unpadded on a phone; reduced-motion ring assertion
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:52:46 +02:00
Melvin StroblandClaude Opus 5.5 f5412d2f7d Marks as dots inside the track: ticks, a selector's options and a slider's reading on the track's midline and the ring's centre line, coloured by the fill or the handle over them; the selector ring fills to its option
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:42:56 +02:00
Melvin StroblandClaude Opus 5.5 b500af84ec Dashboard motion: round dashboards page up and down, the ring eases to a notch or a reading, the slider tile to a value set elsewhere; reduced motion honoured by every tween; motion spec in the docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:34:10 +02:00
Melvin StroblandClaude Opus 5.5 5b2769c141 Slider: the set value to its step's decimals; the reading marked on the track and on the ring; mark geometry in the docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 16:00:53 +02:00
Melvin StroblandClaude Opus 5.5 a6a1f2a2c3 Slider reading in a tile: a line under the value in every look, row and fader; Beside it on every dashboard; tile geometry in the docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:51:04 +02:00
Melvin StroblandClaude Opus 5.5 84071ee106 Round dashboards: one face at a time, a face per widget type, paged by swipe, dots and keys; slider reading; face row in the editor
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 15:24:25 +02:00
Melvin StroblandClaude Opus 5.5 8b8cb5cda9 Round dashboards: shape and ring, the ring drawn and turned in every look, Knob preset and face guide in the editor
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:23:55 +02:00
Melvin StroblandClaude Opus 5.5 f067fb60d4 Gauge: no value arc at the minimum
Docs / docs (push) Successful in 22s
Playwright Tests / test-playwright (1, 2) (push) Failing after 3m53s
Playwright Tests / test-playwright (2, 2) (push) Successful in 1m57s
pre-commit / pre-commit (push) Failing after 2m37s
Test Backend / test-backend (push) Failing after 3m6s
Compose Smoke Test / test-compose (push) Successful in 30s
Playwright Tests / merge-reports (push) Successful in 1m55s
At 0 the value arc is a zero-length dash (pathLength 0), and its round
caps still painted a primary dot on the dial in every look. The arc is
now transparent while its fraction is not above 0. The widget spec puts
a gauge at 0 on its panel and checks it in each look; its tile count,
stale since the buttons widget, is 11.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:29:07 +02:00
Melvin StroblandClaude Opus 5.5 28a44853e3 Colour widget: commit the value being released
The brightness column changes and commits in one handler, so the commit
read the render's draft (still null) and sent nothing; the queued draft then
stuck and rode along with the next release. The pending colour lives in a ref
now. color-drag.spec gains a column drag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:44:38 +02:00
Melvin StroblandClaude Opus 5.5 c462f9acab Panel I/O: PanelDef.io ports, scoped publish and upload, I/O section in the Panels dialog
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 21:10:54 +02:00
stroblmeandClaude Opus 5.5 8d97b8ffaa Open in dashboard: searchable Command list
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:07:17 +02:00
stroblmeandClaude Opus 5.5 cfd2556053 Dashboard message picker: searchable combobox instead of a plain select
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:06:31 +02:00
stroblmeandClaude Opus 5.5 0ef7d027b8 Dashboard palette: switch dashboard, publish, settings; ⌘S publishes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:05:39 +02:00
stroblmeandClaude Opus 5.5 72b4cf3556 Shared Dock, PublishButton, DiscardButton, DiscardDraftDialog for the flow and dashboard editors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:04:34 +02:00
stroblmeandClaude Opus 5.5 8d158169e5 Button icon-touch/sm-touch sizes replace the repeated touch-target classes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 22:02:35 +02:00
stroblmeandClaude Opus 5.5 9c75d7ae13 Dashboard add widget: searchable command palette with ⌘P, as on flows
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:59:16 +02:00
stroblmeandClaude Opus 5.5 9a84d27347 Embed widget: Image option scales a camera stream to the tile
Docs / docs (push) Successful in 19s
Playwright Tests / test-playwright (1, 2) (push) Failing after 3m41s
Playwright Tests / test-playwright (2, 2) (push) Failing after 2m21s
pre-commit / pre-commit (push) Failing after 2m36s
Test Backend / test-backend (push) Failing after 2m58s
Compose Smoke Test / test-compose (push) Successful in 31s
Playwright Tests / merge-reports (push) Successful in 1m36s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:23:37 +02:00
stroblmeandClaude Opus 5.5 022079728c Dashboard icons: add cctv
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:20:54 +02:00
stroblmeandClaude Opus 5.5 cb2a6315c9 Make alert dialog footer buttons 44px below md
The same treatment `ui/dialog.tsx` got: every footer button is a 44px
target on a phone; desktop keeps its sizes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-07 09:32:07 +02:00
stroblmeandClaude Opus 5.5 0869e5b156 Serve index.html no-cache on every route; check the theme script's CSP hash
`try_files` served the SPA fallback inside `location /`, so `/` and every
client route went out without `Cache-Control: no-cache`. The fallback is now
the last argument, an internal redirect to the exact no-cache location.

`src/csp.check.ts` recomputes the inline theme script's sha256 and fails
`bun run check` with the new value when the CSP no longer names it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-07 09:32:06 +02:00
stroblmeandClaude Opus 5.5 e85253a3dc Sandbox website tiles by default; opt into same-origin per widget
A website tile now runs in an opaque origin (allow-scripts, popups, forms).
Its new "Trusted site" setting adds allow-same-origin for sites that need
their own cookies and storage, and a trusted tile pointing at the origin the
app runs on (its own, or the hub's) shows a notice instead of the frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-07 09:31:49 +02:00
stroblmeandClaude Opus 5.5 5259b8db0a Authenticate sockets by header or one-time ticket instead of ?token=
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-07 08:58:22 +02:00
stroblmeandClaude Opus 5.5 21537e2eb6 Bind a worker's name and labels into its token; list and revoke tokens by jti
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-07 08:42:14 +02:00
stroblmeandClaude Opus 5.5 847abd67d6 Give connectors a store that survives restarts, and a way to clear it
`ConnectorNode.store` keeps short strings per connector package in the
engine's database (`connector_state`, migration f8c3e5a91d27), so the nodes of
one package share them and `fluksio serve` needs nothing new: get, set and
delete, at most 64 kB a value and 256 keys a package. A superuser lists the
keys (never the values) and clears them through `/connectors/{node_type}/state`,
or under Stored state in a connector node's panel. Documented in the connector
contract.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-06 17:19:48 +02:00
stroblmeandClaude Opus 5.5 b086d5d22b Show Secrets to superusers only, and guard its route as Admin is
The page reads GET /secrets/, which is a superuser's, so any other account
opened it onto a permission error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-06 12:33:00 +02:00
stroblmeandClaude Opus 5.5 6c0ab2049b Send a CSP and security headers from the frontend's nginx
script-src admits the bundle and the pre-paint theme script by hash, with no
unsafe-inline or unsafe-eval; style-src keeps unsafe-inline for the <style>
elements Monaco, Radix and the toasts insert. frame-ancestors 'self',
nosniff and strict-origin-when-cross-origin go with it, and the Dockerfile
adds the API origin to connect-src when the bundle calls one elsewhere. Zod
runs jitless so its eval probe is not reported on every page. The embed
widget keeps allow-same-origin: the demo's weather map does not render
without it; the comment now says so and what it costs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-06 12:30:47 +02:00
stroblmeandClaude Opus 5.5 7f06260c1a Read secret names in the node panel only as a superuser
GET /secrets/ is a superuser's, so every node a non-superuser opened
showed "You do not have permission to do that". The query now runs only
for a superuser; anyone else gets no secret suggestions, silently.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-06 12:01:53 +02:00
stroblmeandClaude Opus 5.5 48b87cc16e Upgrade dependencies flagged by pip-audit and bun audit
Backend: starlette 1.7.0, pyjwt 2.15.1, python-multipart 0.0.32,
aiohttp 3.14.4, anyio, idna, urllib3, click, lxml, mako, multidict,
pydantic-settings, pygments, python-dotenv, requests. pip-audit goes
from 121 findings in 16 packages to pytest alone (dev, needs 9.x).

Frontend: axios 1.20.0, form-data 4.0.6, dompurify 3.4.16 through an
override (monaco-editor pins 3.4.8), vite 7.3.7, the router packages
and the vite and router build-time dependencies within their ranges.
bun audit goes from 97 to 21, all through @hey-api/openapi-ts 0.73.0,
whose fix is a breaking 0.97 upgrade. The new router plugin reorders
routeTree.gen.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-06 11:50:35 +02:00
stroblmeandClaude Opus 5.5 7370105cd8 Make changing engine-run code superuser-only
Writing node source, installing modules and any flow save that adds,
retypes or repoints a code node (Function, Command), edits a Command
node's settings or changes a node's resources.env now answer 403 for
everyone but a superuser. MCP tools and the assistant reach the same
routes, so they inherit the gate. Node types report runs_code.

The editor shows code read-only with a note, disables a Command node's
settings, leaves code nodes and reusable nodes out of the palette and
paste, and the Modules page offers no install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013GAeg4Jo6xjZzjwy9QDWMQ
2026-10-06 11:36:30 +02:00