Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
151 commits
Select commit Hold shift + click to select a range
5053e91
cli-ux: hstack/distributeCols in UI.Layout; WIP tracker + dev-ux-chec…
StachuDotNet Jul 18, 2026
d957c24
cli-ux: SplitPane (focus-aware bordered two-pane split, both orientat…
StachuDotNet Jul 18, 2026
7322c6e
cli-ux: workbench Frame chrome (tab bar, breadcrumb, key-hint render …
StachuDotNet Jul 18, 2026
e1cb568
cli-ux: workbench SubApp — framed navigable package tree; register 'w…
StachuDotNet Jul 18, 2026
104004c
wip: log workbench SubApp milestone; next = interactive verify + body…
StachuDotNet Jul 18, 2026
4256791
cli-ux: dev-drive PTY visual-verify helper; workbench render+nav veri…
StachuDotNet Jul 18, 2026
edc4b8f
wip: workbench visually verified; next = body split + dark default flip
StachuDotNet Jul 18, 2026
6011833
cli-ux: workbench body split Tree|Inspect (SplitPane) with live sourc…
StachuDotNet Jul 18, 2026
45a3de7
wip: Tree|Inspect split done; next = flip dark default
StachuDotNet Jul 18, 2026
4a82936
cli-ux: dark (no args) opens the workbench by default; classic prompt…
StachuDotNet Jul 18, 2026
fb2a464
wip: P1 complete (dark opens workbench); P2 plan = scroll then wire v…
StachuDotNet Jul 18, 2026
32830eb
cli-ux: Tree viewport scroll (keeps selection visible in big modules)…
StachuDotNet Jul 18, 2026
e13bec8
wip: P2.1 tree scroll done; next = Inspect scroll
StachuDotNet Jul 18, 2026
0e30081
cli-ux: Inspect-pane scroll (focus-aware ↑↓; detailScroll, reset on s…
StachuDotNet Jul 18, 2026
2e24c41
wip: P2.2 Inspect scroll done; next = wire Changes view
StachuDotNet Jul 18, 2026
aaf33ee
cli-ux: wire Changes view (view-aware items — WIP list + clean state)…
StachuDotNet Jul 18, 2026
94b5a2e
wip: P2.3 Changes wired; next = History
StachuDotNet Jul 18, 2026
7207468
cli-ux: wire History view (recent commits via getCommitsWithAncestors)
StachuDotNet Jul 18, 2026
f98e603
cli-ux: [ ] cycle through all 13 views (digits only reached 1-9)
StachuDotNet Jul 18, 2026
1f53cce
wip: History + view-cycling done; next = wire read-only Resolve/Mesh/…
StachuDotNet Jul 18, 2026
3080ec5
cli-ux: wire Resolve (Sync.Conflicts.list) + Docs (allTopics) views
StachuDotNet Jul 18, 2026
3100556
wip: Resolve + Docs wired; next = Services + Home dashboard
StachuDotNet Jul 18, 2026
2e600e9
cli-ux: Home dashboard (WIP/commits/owners summary) + Services view (…
StachuDotNet Jul 18, 2026
5782c75
wip: Home + Services done (8 views live); next = default→Home, then R…
StachuDotNet Jul 18, 2026
14f9623
cli-ux: default landing = Home; view-aware breadcrumb (path / Home / …
StachuDotNet Jul 18, 2026
c3699c4
wip: default→Home + view-aware breadcrumb done; next = Runs/Mesh then…
StachuDotNet Jul 18, 2026
e1ede1a
cli-ux: wire Runs view (Builtin.tracesList) + honest per-view key hints
StachuDotNet Jul 18, 2026
cfe6ba6
wip: Runs + keyhints done (9/13 views); next = Mesh (safe) or polish
StachuDotNet Jul 18, 2026
a5be68e
cli-ux: wire Mesh view (Tailscale.status; graceful 'tailnet unavailab…
StachuDotNet Jul 18, 2026
4d9b197
wip: Mesh done (10/13 views); next = polish (scroll indicator, Docs r…
StachuDotNet Jul 18, 2026
ad9348a
cli-ux: scrollbar thumb on overflowing lists (direct print to survive…
StachuDotNet Jul 18, 2026
7ee6b9a
wip: scrollbar done; next = Docs Enter-to-read
StachuDotNet Jul 18, 2026
a98524e
cli-ux: Docs Enter opens a scrollable full-body topic reader (reading…
StachuDotNet Jul 18, 2026
84c364f
wip: Docs reader done; next = ? help overlay (reuse reader)
StachuDotNet Jul 18, 2026
e62cb63
cli-ux: ? opens a help overlay (full keymap) reusing the reader
StachuDotNet Jul 18, 2026
a82d937
wip: ? help overlay done; next = full view sweep (QA)
StachuDotNet Jul 18, 2026
3af372f
cli-ux: QA sweep (all views clean) + pluralize Home counts (1 commit …
StachuDotNet Jul 18, 2026
dcc8efd
wip: QA sweep + plural done; next = History Enter→ops in reader
StachuDotNet Jul 18, 2026
0fddd30
cli-ux: History Enter opens commit ops in the reader (PackageOp.packa…
StachuDotNet Jul 18, 2026
f787ef9
wip: History ops reader done; next = Changes item source in reader
StachuDotNet Jul 18, 2026
9d34fa4
cli-ux: Changes Enter opens the WIP item's source in the reader (pars…
StachuDotNet Jul 18, 2026
c36d368
wip: Changes source reader done; next = richer Home / Tree-leaf sourc…
StachuDotNet Jul 18, 2026
e894ce1
cli-ux: Tree leaf Enter opens item source full-screen in the reader (…
StachuDotNet Jul 18, 2026
9f16a4f
wip: Tree-leaf Enter done; next = richer Home then final sweep + PR s…
StachuDotNet Jul 18, 2026
11cbebd
cli-ux: richer Home dashboard (recent WIP item names + last-commit line)
StachuDotNet Jul 18, 2026
0770882
wip: richer Home done; next = final sweep + PR summary
StachuDotNet Jul 18, 2026
66ae67a
wip: final interaction sweep (clean) + PR summary at top of WIP
StachuDotNet Jul 18, 2026
9e86332
wip: read-only workbench complete; next frontier = write actions (com…
StachuDotNet Jul 18, 2026
1333ea6
cli-ux: first write action — commit from Changes (single-line input m…
StachuDotNet Jul 18, 2026
22003af
wip: first write action (commit from Changes) done + verified; next =…
StachuDotNet Jul 18, 2026
703796c
cli-ux: write action — discard WIP from Changes (x → y-confirm → SCM …
StachuDotNet Jul 18, 2026
ec7edbe
wip: discard action done; next = branch ops then edit-lite
StachuDotNet Jul 18, 2026
d2ebc36
cli-ux: write action — branch create (b) + switch (s) from History (i…
StachuDotNet Jul 18, 2026
c628b94
wip: branch ops done (3 write actions); next = attempt Edit-lite or p…
StachuDotNet Jul 18, 2026
54ffb2d
cli-ux: informative Edit placeholder (points at fn/type/val); update …
StachuDotNet Jul 18, 2026
83b039e
wip: Edit placeholder + summary done; next = build Edit properly (ste…
StachuDotNet Jul 18, 2026
c3ebbda
cli-ux: Edit step 1 — pure multiline text buffer (ui/editor.dark: ins…
StachuDotNet Jul 18, 2026
6bb9757
wip: Edit step 1 (multiline buffer) done + verified; next = editing s…
StachuDotNet Jul 18, 2026
b72f08c
cli-ux: Edit step 2 — interactive multiline editor (render+cursor, ty…
StachuDotNet Jul 18, 2026
08097c1
wip: Edit step 2 (interactive editor) done; next = Ctrl+S save
StachuDotNet Jul 18, 2026
ca7e96b
cli-ux: Edit COMPLETE — Ctrl+S saves the authored fn (local parse→WT→…
StachuDotNet Jul 18, 2026
68ff3a3
cli-ux: Edit tab points at the working Tree n → editor authoring flow
StachuDotNet Jul 18, 2026
b5ac740
wip: EDIT COMPLETE — full author→save→commit loop in the workbench; n…
StachuDotNet Jul 18, 2026
ea25746
cli-ux: edit-in-place — Tree e opens the selected fn in the editor pr…
StachuDotNet Jul 18, 2026
289c996
wip: edit-in-place done (fn authoring round-trips); next = consolidat…
StachuDotNet Jul 18, 2026
0b24bc0
wip: consolidation verified (clean, no regressions, artifacts auto-cl…
StachuDotNet Jul 18, 2026
82ece43
cli-ux: type/val authoring — Tree t/v create types/values (kind-aware…
StachuDotNet Jul 18, 2026
69c1bce
wip: type/val authoring done — workbench DESIGN-COMPLETE; slowing loo…
StachuDotNet Jul 18, 2026
a67dd9e
wip: Phase 4 — real-terminal tmux testing; found rapid-key coalescing…
StachuDotNet Jul 18, 2026
8fa18b0
wip: Phase 4 horizon — work until 2pm, then print updated report + se…
StachuDotNet Jul 18, 2026
9526d85
cli-ux: batch render writes (printAt one write; drawBox one string) —…
StachuDotNet Jul 18, 2026
8104ae3
wip: branch cli-ux-redux (pushed to github); render batching done; ne…
StachuDotNet Jul 18, 2026
4b65784
cli-ux: fix paste/fast-type input — accept any non-empty keyChar (was…
StachuDotNet Jul 18, 2026
9e5d03a
cli-ux: render survives terminal resize — clamp getWidth/getHeight to…
StachuDotNet Jul 18, 2026
9994de5
wip: fixed paste-drop + resize-crash via tmux; next = write-flow/read…
StachuDotNet Jul 18, 2026
6d388ce
wip: full write-flow + reader sweep PASSES in tmux (author/commit/dis…
StachuDotNet Jul 18, 2026
68369ef
editor: multi-line paste (insertText) + fix stale '^s save — soon' hint
StachuDotNet Jul 18, 2026
54ae69a
wip: polish backlog exhausted (paste + hint done, breadcrumb non-issu…
StachuDotNet Jul 18, 2026
df9bb17
workbench: surface conflicts honestly (Home line + Resolve tab badge …
StachuDotNet Jul 18, 2026
7d3ca05
ui: reusable UI.Box component; frame every list view (no more naked p…
StachuDotNet Jul 18, 2026
adabd18
workbench: discoverable footer + ':' run prompt (eval from anywhere)
StachuDotNet Jul 18, 2026
703f2bc
cli: quick one-key experience chooser on interactive launch (replaces…
StachuDotNet Jul 18, 2026
29393e1
workbench: spacious multi-line authoring (no more cramped bottom-bar …
StachuDotNet Jul 18, 2026
99a5d27
workbench: coherent keymap — vim motion + safer Esc
StachuDotNet Jul 18, 2026
2ee3332
wip: A+B done; plan C (list+preview) next, highlighter located + ANSI…
StachuDotNet Jul 18, 2026
b3214b9
workbench: list+preview splits for Changes/History/Docs/Resolve (IDE …
StachuDotNet Jul 18, 2026
5ca79df
workbench: syntax-highlight the code previews (Inspect + Changes source)
StachuDotNet Jul 18, 2026
5d40e4f
wip: C (list+preview) + H (highlighted previews) done; D (search) next
StachuDotNet Jul 18, 2026
f0ad4f7
workbench: global search (/) across the whole package tree
StachuDotNet Jul 18, 2026
94b44ae
wip: D (search) done; E (touchpoints) + reader highlighting next
StachuDotNet Jul 18, 2026
4767f10
workbench: syntax-highlight the full-screen reader for code too
StachuDotNet Jul 18, 2026
09a507f
workbench: show login state on Home
StachuDotNet Jul 18, 2026
7e8de3e
wip: reader highlighting + login-on-Home done; G quick wins + E rest …
StachuDotNet Jul 18, 2026
cc70619
workbench: 'terminal too small' guard below a usable size
StachuDotNet Jul 18, 2026
e16ca41
wip: reader-highlight + login + too-small-guard done; toast row + dep…
StachuDotNet Jul 18, 2026
05b4ebc
workbench: transient toast row + fix shallow-depth authoring
StachuDotNet Jul 18, 2026
e4fe7cf
wip: toast row + shallow-authoring fix done; deps + branch ops + comp…
StachuDotNet Jul 18, 2026
003b4c5
workbench: 'd' shows a Tree leaf's dependencies in the reader
StachuDotNet Jul 18, 2026
d5274db
workbench: branch merge (m) + rebase (r) from History, with confirm +…
StachuDotNet Jul 18, 2026
e6c5daf
wip: deps + merge/rebase + toast styling done; item F components next
StachuDotNet Jul 18, 2026
96fae75
ui: ANSI-aware UI.Layout.truncateVisible; use it for highlighted prev…
StachuDotNet Jul 18, 2026
d130893
ui: extract UI.ListView (viewport + scrollbar) from renderTreeList
StachuDotNet Jul 18, 2026
37c1f72
wip: item F done (truncateVisible + UI.ListView); all planned items c…
StachuDotNet Jul 18, 2026
ebdd8c6
wip: QA sweep of all views passed, no regressions; idling to finalize
StachuDotNet Jul 18, 2026
135c3d0
workbench: edit-in-place for types + values, not just fns
StachuDotNet Jul 18, 2026
747eb25
workbench: hide 'tab preview' hint on split views when they're empty
StachuDotNet Jul 18, 2026
1a8894f
workbench: make / search results jumpable (Enter navigates to the hit)
StachuDotNet Jul 18, 2026
e405c68
workbench: ? opens a pretty keymap overlay (centered box) instead of …
StachuDotNet Jul 18, 2026
fdd1221
workbench: make leaving for the classic prompt an explicit confirm
StachuDotNet Jul 18, 2026
a92f99c
workbench: inline command bar — run any old-school command in-frame (:)
StachuDotNet Jul 18, 2026
1d645b7
workbench: Agents view is a real ask surface (enter prompts, see repl…
StachuDotNet Jul 18, 2026
8539eba
cli: ditch the new-vs-classic chooser — dark opens the workbench, com…
StachuDotNet Jul 19, 2026
6039226
workbench: real item rename (r on a Tree leaf) — it was never blocked
StachuDotNet Jul 19, 2026
29afe9b
workbench: Agents -> AI panel, a real thread board (list+preview)
StachuDotNet Jul 19, 2026
47f480b
workbench: build out Values view (was the confusing 'Things') + AI al…
StachuDotNet Jul 19, 2026
5d3c272
workbench: author from anywhere — target module carried in the editor
StachuDotNet Jul 19, 2026
cc10007
wip: phase 7 overnight plan (SCM/Matter view, Apps&Views, doc rewrite…
StachuDotNet Jul 19, 2026
209081d
workbench: Matter view — one SCM-centric home over Dark Matter
StachuDotNet Jul 19, 2026
1d92b7f
wip: matter v1 logged; apps&views next
StachuDotNet Jul 19, 2026
1373b00
workbench: Apps & Views — peek at registered views live in the preview
StachuDotNet Jul 19, 2026
683256e
wip: apps&views done; layout rename skipped (rationale logged); doc r…
StachuDotNet Jul 19, 2026
4f8d025
workbench: real +/- diff in the Changes + Matter preview (reuse revie…
StachuDotNet Jul 19, 2026
9da1811
wip: diff pane done; next = full test pass + matter v2 + tree-native …
StachuDotNet Jul 19, 2026
584f83e
wip: add command-coverage audit task
StachuDotNet Jul 19, 2026
259fa82
workbench: view-picker overlay (`) + tab renames (Tree->Matter, Resol…
StachuDotNet Jul 19, 2026
58dd595
workbench: real Edit flow — free-form draft, module line applies to t…
StachuDotNet Jul 19, 2026
2e12cfc
workbench: Inspect standalone tab is a real Overview (captured packag…
StachuDotNet Jul 19, 2026
726112b
workbench: Conflicts view is resolvable — o keep-ours / t keep-theirs…
StachuDotNet Jul 19, 2026
ee7631f
wip: big batch logged (picker/renames/edit-flow/inspect/conflicts); d…
StachuDotNet Jul 19, 2026
5042943
workbench: d shows dependents too, not just dependencies
StachuDotNet Jul 19, 2026
1651d3e
wip: deps-dependents done; apps-run skipped (command bar covers it)
StachuDotNet Jul 19, 2026
792d686
wip: all-views sweep clean, feature-complete; winding down to 01:55 f…
StachuDotNet Jul 19, 2026
9ec2762
workbench: tree-native view peek — a render fn previews live in Inspect
StachuDotNet Jul 19, 2026
99ddc17
workbench: Escape just leaves — commit fully to the new UX, no classi…
StachuDotNet Jul 19, 2026
4129cf3
workbench: fix stale ? help overlay — esc/q quit, real Conflicts/SCM …
StachuDotNet Jul 19, 2026
8492b6c
workbench: restructure to 10 views — consolidate SCM, rebuild Inspect…
StachuDotNet Jul 24, 2026
560b56e
docs(for-ai-internal): multi-clone container-picker trap + dark-multi…
StachuDotNet Jul 24, 2026
8ddf714
docs(for-ai-internal): full concurrent-dev-environments playbook
StachuDotNet Jul 24, 2026
01ce762
workbench: fix Values-lens preview showing (not found)
StachuDotNet Jul 24, 2026
3e75cc5
workbench: fix authoring prefill doubling the owner
StachuDotNet Jul 24, 2026
dc1e238
workbench: flesh out the thin surfaces so the app reads as complete
StachuDotNet Jul 24, 2026
7f6e838
workbench: AI gets Agents + Prompts subsections (Tab-switchable)
StachuDotNet Jul 24, 2026
f70d590
workbench: Inspect metadata strip + real Apps install toggle
StachuDotNet Jul 24, 2026
d6a528e
workbench: refresh the ? help overlay — V values, AI sections, real A…
StachuDotNet Jul 24, 2026
4680054
workbench: Apps ⏎ installs/uninstalls (the primary action), not just 'i'
StachuDotNet Jul 24, 2026
fefe121
workbench: more natural keys — ⏎ = primary action, L not V for values…
StachuDotNet Jul 24, 2026
2247172
workbench: real instance name + UUID, drop patch segment, explicit (m…
StachuDotNet Jul 24, 2026
62ebfc2
workbench: ctrl+←/→ switch tabs — a universal shortcut that scales pa…
StachuDotNet Jul 24, 2026
a68c507
workbench: SCM gets a Branches section — list + switch/new/rename/delete
StachuDotNet Jul 24, 2026
c9f44b5
workbench: compose views through a ViewDef registry + add Errors/Cron…
StachuDotNet Jul 24, 2026
596f08a
workbench: internal-tier Builtins view (real data), gated on internal…
StachuDotNet Jul 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
307 changes: 307 additions & 0 deletions WIP-ux.md

Large diffs are not rendered by default.

447 changes: 447 additions & 0 deletions WIP.md

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions backend/src/Builtins/Builtins.Cli/Libs/Output.fs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,42 @@ let fns () : List<BuiltInFn> =
deprecated = NotDeprecated }


{ name = fn "stdoutCaptureStart" 0
typeParams = []
parameters = [ Param.make "unit" TUnit "A unit" ]
returnType = TUnit
description =
"Start capturing standard output into an in-memory buffer instead of printing it. Pair with <fn stdoutCaptureStop>. Used to run a command and show its output in-frame."
fn =
(function
| _, _, _, [ DUnit ] ->
NonBlockingConsole.startCapture ()
Ply DUnit
| _ -> incorrectArgs ())
sqlSpec = NotQueryable
previewable = Impure
capabilities = LibExecution.Capabilities.Needs.stdout
deprecated = NotDeprecated }


{ name = fn "stdoutCaptureStop" 0
typeParams = []
parameters = [ Param.make "unit" TUnit "A unit" ]
returnType = TString
description =
"Stop capturing standard output and return everything written since <fn stdoutCaptureStart>."
fn =
(function
| _, _, _, [ DUnit ] ->
let captured = NonBlockingConsole.stopCapture ()
Ply(DString captured)
| _ -> incorrectArgs ())
sqlSpec = NotQueryable
previewable = Impure
capabilities = LibExecution.Capabilities.Needs.stdout
deprecated = NotDeprecated }


{ name = fn "debug" 0
typeParams = []
parameters =
Expand Down
24 changes: 23 additions & 1 deletion backend/src/Prelude/NonBlockingConsole.fs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ type private Private() =

static let mQueue : BlockingCollection = new BlockingCollection()

// When capturing (non-null), writes go to this buffer instead of the console queue. Used by the CLI to run
// a command and show its output in-frame (the workbench's inline command bar) rather than to stdout. Capture
// is driven synchronously from the interactive loop's key handler, so the single-writer assumption holds.
static let mutable captureBuffer : System.Text.StringBuilder = null

// Use a lock so that wait() doesn't return until the thread has actually printed
// (it would finish once it was removed from the queue)
static let mLock : obj = obj ()
Expand Down Expand Up @@ -54,11 +59,28 @@ type private Private() =
lock mLock (fun () -> shouldWait <- mQueue.Count > 0)

static member Write(value : string) : unit =
if isWasm then System.Console.Write value else mQueue.Add(value)
if isWasm then
System.Console.Write value
else
let cb = captureBuffer
if not (isNull cb) then cb.Append(value) |> ignore else mQueue.Add(value)

static member StartCapture() : unit = captureBuffer <- System.Text.StringBuilder()

static member StopCapture() : string =
let sb = captureBuffer
captureBuffer <- null
if isNull sb then "" else sb.ToString()


let wait () : unit = Private.wait ()

let writeInline (value : string) : unit = Private.Write value

let writeLine (value : string) : unit = Private.Write(value + "\n")

/// Route subsequent `print`/`printLine` output into an in-memory buffer instead of the console.
let startCapture () : unit = Private.StartCapture()

/// Stop capturing and return everything written since `startCapture`.
let stopCapture () : string = Private.StopCapture()
50 changes: 50 additions & 0 deletions dev-drive
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
# dev-drive — visual-verify a full-screen CLI app under a PTY (host expect isn't installed; run-in-docker is
# too slow). Spawns `./scripts/run-cli <args>`, optionally sends keystrokes, and prints the screen with ANSI
# stripped so you can eyeball the frame.
# ./dev-drive workbench # dump the initial frame
# ./dev-drive workbench --keys 'DOWN DOWN RIGHT' # send keys, then dump
# Keys: UP DOWN LEFT RIGHT ENTER ESC TAB, a literal char, or \xNN. Waits ~1.5s between key and dump.
import os, pty, subprocess, time, select, termios, struct, fcntl, sys, re

args = sys.argv[1:]
keys = []
if "--keys" in args:
i = args.index("--keys"); keys = args[i+1].split(); args = args[:i]

KEYMAP = {"UP":b"\x1b[A","DOWN":b"\x1b[B","RIGHT":b"\x1b[C","LEFT":b"\x1b[D",
"ENTER":b"\r","ESC":b"\x1b","TAB":b"\t","CTRLS":b"\x13","SP":b" "}

master, slave = pty.openpty()
ROWS = int(os.environ.get("DEV_DRIVE_ROWS", "40"))
COLS = int(os.environ.get("DEV_DRIVE_COLS", "120"))
fcntl.ioctl(slave, termios.TIOCSWINSZ, struct.pack("HHHH", ROWS, COLS, 0, 0))
p = subprocess.Popen(["./scripts/run-cli"]+args, stdin=slave, stdout=slave, stderr=slave, close_fds=True)
os.close(slave)

def drain(t):
end=time.time()+t; buf=b""
while time.time()<end:
r,_,_=select.select([master],[],[],0.2)
if r:
try: buf+=os.read(master,65536)
except OSError: break
return buf

raw = drain(6) # the initial frame
for k in keys:
os.write(master, KEYMAP.get(k, k.encode())); time.sleep(0.4)
if keys:
raw = drain(2) # the screen after the keystrokes
try:
os.write(master, b"\x03"); time.sleep(0.2); p.terminate()
except: pass

# Keep only the LAST full redraw (each frame starts with a clear-screen), so multi-key drives show the
# settled final frame instead of every intermediate repaint.
frames = raw.split(b'\x1b[2J')
raw = frames[-1] if len(frames) > 1 else raw
txt = re.sub(rb'\x1b\[[0-9;?]*[a-zA-Z]', b'', raw)
txt = re.sub(rb'\x1b[()=>][B0]?', b'', txt)
sys.stdout.buffer.write(txt)
print()
28 changes: 28 additions & 0 deletions dev-ux-check
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/bash
# dev-ux-check — the tight inner loop for CLI-UX work. Reload packages, report PASS/FAIL + first error.
# Usage: ./dev-ux-check (reload + check)
# ./dev-ux-check twice (reload twice — for .dark TYPE changes: embedded ref-hashes need 2 passes)
set -uo pipefail
cd "$(dirname "$0")"

reload() { DARK_CONFIG_TRACE_DETAIL=off ./scripts/build/reload-packages 2>&1; }

out="$(reload)"
[ "${1:-}" = "twice" ] && out="$(reload)"

# A clean reload prints only "Reloading packages …" and "Done reloading packages". Anything else that looks
# like an error (a failed parse/name-resolution/load) is the real signal.
errs="$(printf '%s\n' "$out" \
| grep -iE 'error|exception|fail|not found|unhandled|unexpected|cannot|abort|unresolved' \
| grep -vE 'reload-packages|logs/packages\.log' \
| head -6)"

if printf '%s' "$out" | grep -q "Done reloading packages" && [ -z "$errs" ]; then
echo "PASS — packages reloaded clean"
exit 0
else
echo "FAIL:"
[ -n "$errs" ] && printf '%s\n' "$errs" | sed 's/^/ /'
printf '%s' "$out" | grep -q "Done reloading packages" || echo " (reload did not finish — see rundir/logs/packages.log)"
exit 1
fi
Loading