Repository navigation
fm/cf genui fleet - #1087
Draft
i098 wants to merge 68 commits into
Draft
fm/cf genui fleet#1087i098 wants to merge 68 commits into
i098 wants to merge 68 commits into
Conversation
…tecture doc Closes #1017
…ed keeps placement
Renders a spec over the stub WebSocket contract: cards move, resize, link and pin; the header toggle picks agent wins or user wins; the input box sends text to the agent; the sketch layer stays on top. A local mock server stands in for apps/genui-server. Docs in docs/genui/canvas.md. Closes #1020
Replace the three stub contract.ts copies with @crewship/genui-spec (src/wire.ts). Server emit_view accepts the kit's STATE_SNAPSHOT event; the kit's intent socket connects with ?role=agent so forwarded user intents reach it. Closes #1017
…stages, at), link label, spec.projects
…layout, tiling, link lines, camera and zoom, spread, pull-out, phone fit
…uster answers (D44-D47)
…re-baseline sentrux for the new world module
…c, removed) and keeps tap targets
Card chrome, Geist Mono, every view kind (decision, conflict, pipeline, timeline, crew, shipped, plan, embed, incident, compare, ask, sys, tui), live stamp, resize grip, hover ring and build-in motion (D13-D28). renderCard(spec, component, widthTier) from src/views/index.ts.
…space ink, uploads, hotkeys
D38-D43 of the genui design diff. New src/overlays.ts exports initOverlays(ctx)
and returns { sync }; src/overlays.css ports the design styles.
…al pills, nav/log pills, hint, chips, ask bar, up-next queue, action log)
Co-locate the views test with the views and re-baseline sentrux for the new views module.
…nui-p0 was already 6712; shell adds -11)
Pen, ask input and log button use the S1 selectors; S1 owns #attach and the non-drawing placeholders. Esc runs in capture so it closes one thing.
…o small functions
Cards use their width and fit their text (pretext title sizes, wrap, ellipsis); short titles with the detail in body; clusters sit apart around the top one; one-line fixed-height top bar with a collapsible pill row; overview first, cluster and full-view detail on request, open cards update live; render speed: fit only changed on-screen cards, no per-frame link work without lines, static cluster tint, off-screen cards skip paint.
The hidden meter sits off screen, so content-visibility: auto skipped its content and every card measured 44 px.
Asks were ordered by their status file's mtime, so a busy mate's old asks filled an open cluster's 8 slots and hid a newer ask from another task. Each ask now carries the at= stamp of the line that raised it.
The canvas starts empty and draws asks, PRs, crew or usage only when the owner asks in chat. Each ask shows its real options parsed from the note, the recommended one tagged, and a free-text answer box. A cluster pages its asks instead of a bare count, the header counts every ask that waits, and a model-made decision card is refused. Cards in a cluster pack in rows with no gaps: each row is as tall as its tallest card and the cards stretch to fill it (plan rounds 8 and 27).
cards() and diff() grew past the complexity gate with the on-demand topics. PR cards and the per-card prop patch are now their own functions.
Each ask card shows a model-written line on what it is, one on why it matters now, and the options as short full labels with the pick marked. The raw note stays in the full view. Briefs are cached by ask and time. Asks older than two days are stale and no longer drawn (owner bug 030/031).
…in-board windows, confirm shows sending then sent Each ask card carries a ref line: the PR it links (or names by number), else the brief's ref, else the task and its project. A link opens a window card inside the board; a page that forbids frames (frame-ancestors, X-Frame-Options) shows a plain blocked note. Only a card's own link opens. On Yes, the confirm card stays in place, shows Sending, then Sent with the result, then leaves the board.
Selecting or opening a card and asking about it ("more context") now
shows the card's real facts at once inside the same card: an ask's full
note, its task's latest lines, a PR's title and checks. The model's
answer streams in under them. No new card opens. A crew card still takes
a plain instruction as a steer.
The chat model can send one plan line per question: which cards stay, their order and size, which card stacks behind another, and which pins to the edge. Every other card goes to a rail under the composer; one tap brings a card back, and Reset returns the overview. Undoing the question also undoes its plan. When cards leave, the staying cards move after them, and new cards build last.
genui-window opens, moves, raises, lowers, floats, sinks and closes a floating card through the agent API. A floating card keeps its spot over any layout, stacks by layer, comes to the top when grabbed, and a chat plan never sets it aside.
…e board around it An ask about a selected card opens its facts in a floating context window beside it and plans the board around that card: the card stays large in front, its PRs and asks join it, everything else is set aside. Answer cards list the real asks, PRs and crew rows in full and wait for the fleet to load instead of saying it is still loading. Floating windows cap their height and scroll. genui-window gains --near to open a window over a card.
…rage can move off a slow disk A plan's kept cards stay in their own project's cluster instead of moving to one shared cluster, and while a plan is on the board all its clusters show at full size. GENUI_STATE moves the board's storage (for example to /dev/shm), so the first snapshot does not wait on fsync when the disk is under heavy write load.
… a tap brings one to the front
…nt card, tall enough to tap
… a tap reaches the deepest one
…t wider
[ ] and Tab step through the front cluster's cards in order, h j k l and the arrows pick the nearest card that way,
g G (Home End) jump to the first and last, Enter opens the selected card, and { } now switch clusters. The hint lists
the keys. On a wider screen a card starts 460 px wide (was 380), a small one 320 (was 260), the edge column 320, and
a body shows six lines before it clips (was four).
… ] switch clusters again" This reverts commit 118a1a9.
While Tab is held, Tab, [ ], h j k l, the arrows and g G add the card they reach to the selection instead of replacing it; a tap already adds. Releasing Tab keeps the selection.
…cting it and typing steers that worker
| case"Metric":return`<div class="metric"><span class="text muted">${esc(p.label)}</span><br><b>${esc(p.value)}</b><small>${esc(p.unit||"")}</small></div>`; | ||
| case"Badge":return`<span class="badge ${p.tone||"info"}">${esc(p.text)}</span>`; | ||
| default:return`<div class="text muted">[${esc(e.type)}]</div>`}} | ||
| const render=()=>{root.innerHTML=doc.root?node(doc.root):""}; |
| world.append(meter); | ||
| } | ||
| meter.style.width = `${w}px`; | ||
| meter.innerHTML = html; |
| : "nothing needs you"; | ||
| const name = spec.projects?.[b.proj]?.name ?? b.proj; | ||
| const hd = `<b style="background:${col}">${esc(name)}</b>${esc(say)}`; | ||
| if (box.firstElementChild!.innerHTML !== hd) box.firstElementChild!.innerHTML = hd; |
| let spec: BoardSpec; | ||
| const memo = new Map<Element, string>(); | ||
| /** Writes markup only on change, so a tap that spans a repaint still lands and animations do not restart. */ | ||
| const put = (el: Element, html: string) => memo.get(el) !== html && (memo.set(el, html), (el.innerHTML = html)); |
| /** Patches the live DOM toward `html`, so kept parts move and change in place instead of re-appearing. */ | ||
| export function morph(el: Element, html: string) { | ||
| const t = document.createElement("div"); | ||
| t.innerHTML = html; |
| }, BUILD_MS); | ||
| return stamp(el); | ||
| } | ||
| if (t._html === undefined) el.innerHTML = html; |
|
|
||
| /** Parses `state [at=epoch]: text`. Returns undefined for any other line. */ | ||
| export function parseStatusLine(line: string): StatusLine | undefined { | ||
| const m = LINE.exec(line.trim()); |
| }; | ||
|
|
||
| export function createGenuiClient(opts: GenuiClientOptions): GenuiClient { | ||
| const base = opts.url.replace(/\/+$/, ""); |
| let doc={root:"",elements:{},style:{},links:[]},seq=0;const t0=performance.now(); | ||
| const esc=s=>String(s).replace(/[&<>"]/g,c=>({"&":"&","<":"<",">":">",'"':"""}[c])); | ||
| function apply(ops){for(const o of ops){const k=o.path.split("/").slice(1).map(s=>s.replace(/~1/g,"/").replace(/~0/g,"~")); | ||
| if(!k.length){doc=o.value;continue}let p=doc;for(const x of k.slice(0,-1))p=p[x];const l=k.at(-1);o.op==="remove"?delete p[l]:p[l]=o.value}} |
| let doc={root:"",elements:{},style:{},links:[]},seq=0;const t0=performance.now(); | ||
| const esc=s=>String(s).replace(/[&<>"]/g,c=>({"&":"&","<":"<",">":">",'"':"""}[c])); | ||
| function apply(ops){for(const o of ops){const k=o.path.split("/").slice(1).map(s=>s.replace(/~1/g,"/").replace(/~0/g,"~")); | ||
| if(!k.length){doc=o.value;continue}let p=doc;for(const x of k.slice(0,-1))p=p[x];const l=k.at(-1);o.op==="remove"?delete p[l]:p[l]=o.value}} |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1086
Base of the stacked PR #1088 (end-to-end fixes, issue #1085). Draft until the owner OKs the GenUI screenshots. Do not merge.