All UI code moves to strict TypeScript in ui/src/, compiled by tsc (no
bundler) to ui/build/, which index.html loads; the app's build.rs runs the
compile so every cargo build ships the current UI. Sources import each
other as ./x.ts so node --test runs them directly, and the data types
mirror crates/craft-core/src/model.rs.
app.ts now exports start(api) and main.ts wires it to Tauri or the browser
preview, so the UI can be tested in happy-dom against a fake host: sorting,
dragging, clicks, the window picker, status, the urgent view and shortcuts.
Sort toggling and drop placement move into model.ts with unit tests. The
inline error-reporting script becomes report.ts.
CLAUDE.md records the rule: no .js/.mjs/.cjs/.jsx files, inline scripts,
inline handlers or javascript: URLs. ui/src/repo.test.ts enforces it in
make test; make check adds a tsc type-check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rows can be dragged into any order at any time, so higher-priority repos
can sit on top. Dropping saves the order on screen and switches the table
to it, clearing the sort column; clicking a column header sorts again and
keeps the manual order for the next drag. Repos added to the config later
go at the bottom of a manual list.
Dragging uses pointer events, not HTML5 drag and drop, which the webview's
file-drop handling can swallow. A press only becomes a drag after moving a
few pixels, so clicking a row still opens its urgent issues, and the table
doesn't re-render mid-drag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Walking a week of commit authors, PRs and issues was ~80% of each poll's
GitHub time. Keep them per repo in ~/Library/Caches/craft-status/raw/,
keyed by commit oid and PR/issue number, and fetch only from just before
the previous fetch; refetch from scratch every six hours. Three busy repos
go from 111 s to 28 s with identical counts. The snapshot (the rendered
view) is now saved after each repo, not only at the end of a poll.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Polls still hit a secondary rate limit about a minute in: GitHub allows
60 s of GraphQL server time per minute, and two workers firing heavy
queries back to back exceed it. Fetch serially and, after each GraphQL
request, wait as long as it took. A full poll of 15 repos now takes ~4
minutes with no rate limiting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit dropped the return along with the value assignment,
so every render threw before drawing anything.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each poll ran 24 GraphQL searches per repo (~360 per poll), which trips
GitHub's search secondary rate limit even with plenty of hourly budget
left. Per-window PR/issue counts now come from walking recent PRs and
issues newest first and bucketing them locally; no search at all.
A rate-limited repo now halts the rest of the poll, the error reports
GitHub's retry-after time, and two repos are fetched at a time, not four.
The UI rebuilt the window dropdown on every render (every 15 s and per
repo during a poll), which could close it mid-choice. The group header
row is now built once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add storytold/craft-launcher and storytold/figcraft to the default repo list
and config template.
GitHub answers 404 / NOT_FOUND for private repos the token can't see. Treat
that as a successful poll with no data: the row renders blank (with a
"Not accessible" tooltip) instead of as an error, and doesn't count toward
the failed-repos banner or retry backoff.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>