Skip to content

amicode: widget-kernel — home dashboard, in-chat widget authoring, Amico presence, clipboard/model bridges (fork half of amicode#136) - #20

Merged
Rchari1 merged 70 commits into
local/amicodefrom
wip/stage1-widget-kernel
Jul 14, 2026
Merged

amicode: widget-kernel — home dashboard, in-chat widget authoring, Amico presence, clipboard/model bridges (fork half of amicode#136)#20
Rchari1 merged 70 commits into
local/amicodefrom
wip/stage1-widget-kernel

Conversation

@Rchari1

@Rchari1 Rchari1 commented Jul 14, 2026

Copy link
Copy Markdown
Member

Aaron's widget-kernel program, opened as a PR so CI runs and it's reviewable. 70 commits, +7,953/−382 across 111 files — 0 behind local/amicode, merges clean. All commits are Aaron's; it adds alongside the already-merged amicode fork work (solver-toggle #13, chat-fixes #18) without reverting any of it.

The load-bearing bit for amicode#136

The fork half of the bidirectional bridges whose extension-side listeners are in amicode#136 — without this PR + a vendored-binary bump, those three features are dead listeners:

  • packages/app/src/components/prompt-input/clipboard-bridge.ts → sends clipboard-write (copy-back) + clipboard-image-request, consumes the clipboard-image reply (image paste). Has a test.
  • packages/app/src/components/amicode-default-model.tsx → sends set-default-model (drives amicode's amicode.defaultModel).

The rest of the program

  • Home dashboard = WidgetGrid (legacy cards as fallback): panel-first chrome strip, sessions flyout, responsive grid.
  • In-chat widget authoring (Stage 2): author tool + live in-chat preview + pin; widgets served as documents with their own CSP (srcdoc inheriting the app CSP was killing the inline runtime — fixed here).
  • Amico third-actor presence wired into the chat flow (packages/ui/src/amicode/amico-presence.*, with stories + test).
  • Durable default-model pin — pin slot in the models store + fallback chain + control rebind.
  • Server-side: dashboard.ts, widgets.ts + widgets-src/*, widget-*.ts, toml-lite.ts (all new under server/amicode/); problems.ts bumps the log tail 8→24 (a smaller window can blank the filtered mid-solve view).

Before this lights up in shipped amicode

  1. This PR reviewed + merged to the fork default.
  2. Cut a fork release + bump the vendored binary in the amicode extension.
  3. Merge amicode#136 (the extension half).

One verification I want a reviewer to confirm

The bridge senders live in packages/app; Kate's original paste bridge was in packages/ui. Worth confirming a binary built from this branch actually serves the packages/app code (a strings check on the built binary), so the senders don't just exist in-tree but ship. I can run this once we're at the release-cut step.

🤖 Generated with Claude Code

aarontrowbridge and others added 30 commits July 8, 2026 20:24
Prepend 'Aero' to the AMICODE wordmark/logo font-family chain (logo.tsx,
wordmark-v2.tsx), matching each file's current fallback stack. Additive
only. Re-applied fresh after the branch fast-forwarded 57 commits to
current origin/local/amicode — this had been uncommitted WIP on the old
base.

Aero is donationware (Nirmal Biswas / Picatype, $25+) — bundled preview-
only, must be licensed or replaced before any release. See AMICODE-
PATCHES.md #15.
The chat composer's handlePaste bailed out silently whenever
event.clipboardData was empty — which it always is inside the sandboxed
cross-origin webview iframe (navigator.clipboard is denied there too).
Cmd/Ctrl+V into the composer was a no-op.

The extension side of this bridge already ships on main (chat_panel.ts
answers clipboard-request), and home-cards.tsx already proved the pattern
for a different input. This wires the same bridge into the main composer:
platform.readClipboardText (new, mirrors readClipboardImage) -> entry.tsx
implements it via the postMessage bridge when framed -> attachments.ts
falls back to it when clipboardData yields no text.

See AMICODE-PATCHES.md #16 for the full trace + build/verify evidence.
Live test (Aaron) found the prior commit's fix was composer-only: pasting
into a generic "Connect <provider>" API-key dialog (dialog-connect-
provider.tsx - one of many such plain-input settings forms) was still a
silent no-op, since that input has no knowledge of the bridge.

Same root cause, generalized properly: one document-level paste listener
(installGlobalPasteFallback, entry.tsx) covers every form field and
contenteditable in the app, activating only when the native paste event
gave no text (the sandboxed-iframe symptom) - a no-op everywhere
clipboardData already works. The composer's own handler stopPropagation()s
on every paste it handles, so it never double-fires there.

See AMICODE-PATCHES.md #16 addendum for the full trace + build evidence.
QNode {id, prereqs, relevant?(value predicate), optionsFrom?, batchable};
frontier(graph, answers) returns answerable-now nodes (prereqs met AND
optionsFrom answered AND relevant AND not-yet-answered). Value-dependent and
relevance-pruning guardrails both covered. v1 = tested reference the SCORE
batching policy mirrors (not runtime-wired; spec §4.1). 6/6 bun test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chipText (system): composite branch -> compositeChip (N=1 matches the legacy
flat chip; N>1 = "platform · N×role · kind · arch"); entityRows: composite
branch -> compositeSystemRows (component-table + coupling-list, not a JSON
blob); new systemProjection (composite read-through; flat collapses to N=1
with isComposite flag). All parse BOTH shapes defensively in place -- the fork
repo cannot import the plugin normalizeSystem (spec §3 cross-repo). Never
throws. +5 tests; 73/73 amicode-ui bun suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bring the fork mainline up to date with the merged upstream stack
(PRs #6#12): onboarding wizard, Library upload, brand-mark
consolidation, receipt-card + entity-view redesign, Inspect Run
button, chat-jitter/reduced-motion fix, accent-rail removal.

Conflicts resolved:
- logo.tsx: auto-merged; the local 'Aero' font-family prepend survived
  origin's brand-mark rewrite (verified line 112 + wordmark-v2 intact).
- AMICODE-PATCHES.md: kept both sides. Local Aero (#15) + composer
  paste bridge (#16) preserved; origin's mark-drift entry renumbered
  15 -> 17 to sit after them. Local Aero + paste-bridge commits
  (a4fd244/c811798/b868a59) retained — still local-only WIP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New facets.ts (pure). receipt.ts short()/problem.ts shortValue() delegate
to compactValue — arrays/objects render as compact summaries, never raw
JSON blobs. Spec §4 / plan Task 1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sk 2)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ask 4)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
spec §6.1 / plan Task 5. Thin SolidJS over systemProjection + system-render
models; theme-aware --v2-* CSS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
spec §5,§6.1 / plan Task 6. entity-view routes system→SystemComposite
(generic field-row path retired for system; Hamiltonian moved to the hero).
card.tsx renders systemReceiptPieces (semantic +/−/change, or post-state
compositeChip on creation/large/elided) instead of JSON diff pieces.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ey) + shared corpus

spec §6.2,§9 / plan Task 12. Defensive legacy/structured projection (never
throws, raw passthrough on unknown enums), derives primaryKey from
type+free_phase+time_mode, synthesizes derivedFinalFidelity for min_time.
Re-implements the §10 mapping in place (no cross-repo import), locked to the
amicode corpus by a byte-identical fixture mirror. 9 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…m problem_type (spec §6.3 / Task 13)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… + constraints)

spec §6.2 / plan Task 14. Mode-badge header via modeBadges; derived primary
objective headline + OBJECTIVE_LATEX (keyed by primaryKey, distinct from
ObjectiveKind); added-terms + typed-constraint rows (incl. the synthesized
min-time final_fidelity row); solve scalars. Theme-aware --v2-* CSS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ask 15)

entity-view routes formulation→FormulationView (generic field-rows gated off
for both hero kinds). card.tsx generalizes the system receipt path to a
hero path (system|formulation): formulationReceiptPieces renders mode
transitions / flag +/− / objective+constraint setDiff, or the post-state
mode-chip on creation/large/elided. 107 fork tests green; typecheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nk grid/flex children

Grid/flex children defaulted to min-width:auto, so long history notes / table
params forced the dialog content wider than its frame and clipped the right
edge (timestamps). Add min-width:0 + overflow-wrap:anywhere on the offending
children (history summary, system table params, formulation constraints/solve)
and overflow-x:auto on the LaTeX blocks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…bulletproof dialog overflow

- systemHamiltonianLatex: derive an illustrative Hamiltonian for ANY composite
  (drift per role + interaction per coupling kind + drive) so the System hero
  shows math for cavity+qubit/etc., not just transmon/rydberg ("show the system").
- param symbols (ω/δ/χ/J) in the component table; unit-suffixed keys kept.
- formatTs: compact ISO ("07-10 15:53") for history + Updated — cleaner, no clip.
- overflow: container overflow-x:hidden + min-width:0 down the timeline/event
  chain + nowrap compact timestamp → history no longer bleeds past the frame.
110 fork tests green; typecheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…el bleed)

The fit Dialog sizes to content; the wrapper only set overflow-y, so a wide
child (long history line) bled past 680px, grew the panel, and clipped both
edges. Set overflow:auto + min-width:0 + max-width:90vw so the 680px box holds
and content wraps within it. Root cause of the "still cut off" reports.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fit-panel growth)

The fit Dialog was measuring the scroll-width of a nowrap child (the katex
Hamiltonian) through the wrapper's overflow-x:auto, growing the panel to ~1170px
and clipping both edges. Switch to a definite 620px width with overflow-x:hidden
(+ overflow-y:auto for history) so there's no scroll-width to leak — content
wraps within, the Hamiltonian scrolls inside its own box.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pull Raghav's "bunch of bug fixes just landed" (2026-07-10) into the
composite-system work. 13 commits from the local/amicode integration branch:

  #13  High-Performance Solver toggle + brand typeface (Racing Sans One) restore
  #16  entity-view + problem-switcher modal padding, remove card-family gold tint
  #17  chat paste via extension clipboard bridge (⌘V intercept)
  #18  chat prose no longer clips + AMICO signature on every assistant turn

Conflict resolutions (4 files), all preferring the landed, reviewed fixes:
  - message-timeline.tsx: took the team wrapper (width:100%); dropped my
    untested 620px definite-width workaround. The katex Hamiltonian is now
    contained by the auto-merged amicode.css hardening (entity-view
    overflow-x:hidden + .amc-ev-formula overflow-x:auto), so width:100%
    against the v1 dialog's definite max is sufficient.
  - logo.tsx: took Racing Sans One (team brand decision, straight-sans
    reverted per review). Dropped the Aero face — it is license-pending
    donationware and cannot ship.
  - prompt-input.tsx / attachments.ts: took the canonical paste-bridge impl
    (readClipboardViaBridge, resolves "" not null).

Verify: packages/ui amicode suite 112 pass / 0 fail; packages/app paste-bridge
43 pass. The 1 pre-existing submit.test.ts failure (Toast export via
Object.assign, bun ESM quirk) is untouched by this merge on both sides.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Revert the merge's Racing Sans One resolution back to Aero per Aaron —
matches wordmark-v2.tsx (already 'Aero', 'Racing Sans One' fallback). Aero
@font-face + asset survived the sync (index.css, public/assets/Aero-Regular.ttf).

NOTE: Aero is license-pending donationware (preview-only, USD 25+ to the
author). Racing Sans One (OFL) remains the CSS fallback. Must be licensed or
replaced before any release ships.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…atch #18)

anthropic.txt "Tone and style" -> "Communicating with the user": output
renders as rich GFM (headings/bold/lists/tables/inline code), match
structure to content, lead with the outcome, readable-beats-brief in
complete sentences. "interactive CLI tool" -> "interactive coding agent".
Companion patch in amicode AGENTS.md covers custom-prompt agents
(pulse-designer) that bypass this file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ha 3c26d8d9

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
#18 addendum)

Live test showed no change: the model pin is opencode/deepseek-v4-flash-free
(no anthropic creds), so sessions load default.txt — whose "fewer than 4
lines / one word answers are best" rules steamroll everything. Same
"Communicating with the user" section as anthropic.txt, terse examples
replaced with structure-matching ones; gemini.txt minimal-output bullets
replaced likewise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… model (patch #18 addendum 2)

One canonical "Communicating with the user" section (communicating.txt)
appended in provider() for all model families, with a supersede clause
that outranks per-model CLI/terseness rules. Inlined copies in
anthropic/default/gemini slimmed back to near-stock. Custom-prompt
agents still bypass by design (subagents return model-directed data);
pulse-designer is covered via amicode AGENTS.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…for user-facing custom-prompt agents

system-render.ts: role-aware driveTerm — atoms get Ω(t)/2(|r><1| + h.c.)
instead of the hardcoded bosonic ε(t)(â+â†); atom drift -Δ n̂ → -Δ|r><r|.
+3 tests (115 pass).

request.ts: custom-prompt agents append PROMPT_COMMUNICATING unless
mode === "subagent" — covers pulse-designer interview sessions at the
system-prompt level; subagent output stays style-free (model-directed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two-finger / right-click on a tab now opens a context menu:
  · Close                    (mirrors the × / middle-click)
  · Close other tabs         (disabled when only one tab)
  · Close tabs to the right  (disabled when it's the last tab)

- context/tabs.tsx: two bulk actions (closeOthers, closeToRight) living
  alongside removeTab/removeSessions. Both are navigation-safe — closeOthers
  activates the kept tab; closeToRight re-navigates to the anchor only if the
  active tab was among those removed (via a new currentTabIndex helper that
  matches session tabs by href and draft tabs by draftId). Index-shift safe:
  single splice under produce/startTransition, not a removeTab loop.
- titlebar.tsx: wrap TabNavItem's root in the existing Kobalte ContextMenu
  (Trigger as="div", modal={false}), mirroring sidebar-project.tsx. Wired from
  the <For> where the index is in scope; enablement flags from tab count/index.
- i18n/en.ts: common.closeOtherTabs + common.closeTabsToRight (other locales
  are Partial and fall back to en).

Scope: session tabs (TabNavItem). Draft "new session" tabs unchanged.
Verify: packages/app tsgo -b exit 0, 0 errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e above not below (patch #20)

Upstream styled all h1-h6 identical to body text (14px medium, same
color as the container) with the margin below the title instead of
above — section titles read as unrendered prose. strong/b 500 -> 600
(500 vs the 400 body was near-invisible).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
aarontrowbridge and others added 27 commits July 12, 2026 01:13
…+ preview

The conflict-safe core of spec-20260712-014749 (all NEW files; no edits to the
message-part.tsx / entity-rail.tsx / run-window.tsx surfaces the dashboard agent
is actively changing):
- amico-presence.ts: pure presence state machine (dormant/stepping_in/on/
  settling/idle) — classify + transition; the shared brain rail+flow read. 14 tests.
- amico-presence.css: offset accent lane + rail wake/settle motion (v2 tokens,
  reduced-motion gated); new file, not the hot amicode.css.
- amico-presence.stories.tsx: self-contained Storybook preview of all 5 states +
  an auto-playing pop-in/out sequence (mock data).

Deferred (dashboard-agent file contention): the invasive wiring — stamp scrub in
message-part/card/ask-card/run-window, thinking-line decouple, rail wake/settle
hookup. Fully specified in the approved spec; needs a coordinated pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…inherits the app CSP and kills the inline runtime
…pill

The old edit mode floated a heavy row of five bordered buttons above every
card with a truncated label, drowning the content and reading as its own UI.
Rebuild: cards stay visible under a light scrim + dashed ring ("arranging,
not using"), each gets one compact grouped control pill in its top-right
corner (↑↓ reorder / ⚙ config / fork / ×), a banner orients, the add-back
tray only appears when something is hidden. Reorder ↑/↓ disable at row ends;
move buckets by hero/tile row (matches what the user sees). Overlay is
click-safe over the iframe; scrim blocks accidental widget clicks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…the frame

Moving display:none onto the frame wrapper left the cell holding an empty
grid column. Hide the whole cell when not editing and there's nothing to
render; keep the frame mounted under display:none so its amc:empty signal
keeps flowing and the cell re-appears if the widget later has content.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Realizes the approved spec (identity rule + working lane) — the conflict-scoped
pass (rail wake via CSS only; NO edit to entity-rail.tsx, which the widget kernel
is editing):
- message-part.tsx: drop the per-turn AMICO signature (data-slot=
  amicode-turn-signature); repurpose the amicode_* check as the in-domain signal;
  mount the thinking line in an offset accent lane BELOW the streamed parts, gated
  on inDomainTurn && working (decouples it from the old card-suppression so it now
  shows on in-domain turns — the reviewer's issue 5).
- card.tsx / ask-card.tsx / run-window.tsx: drop the 'AMICO' wordmark (keep the
  H-mark glyph as a subtle leading icon); remove orphaned separators.
- amico-presence.css: rail wakes on entry via [data-component=amicode-entity-rail]
  (session-sticky mount => plays once, no entity-rail.tsx edit).
- styles/index.css: load amico-presence.css in the components layer.

Verified: 20 tests pass, 0 typecheck errors. NOT visually run (heavy fork build;
main checkout held by widget agent). Deferred: grouping amicode cards INTO the
offset lane (open-question-2) + rail livedot-while-working — visual-iteration
follow-ups. Not merged/pushed; reconciles with wip/stage1-widget-kernel at merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…el build

Disjoint from the widget kernel (UI chat flow vs dashboard widgets); brings
the presence lane + un-stamped cards into the current build for live review.
Stage 2 widget-author WIP left uncommitted in the working tree, untouched.
…n-chat preview + pin

Prompt Amico to build a home widget; it renders a live preview in the chat and
you pin it to the dashboard. Rides the existing /^amicode_/ tool-name seam — no
stock-code, no new part type, no new route.

Server (opencode):
- authorWidget() in widgets.ts: validate structured manifest fields + js, assemble
  the manifest TOML, round-trip through parseManifest, write ~/.amico/widgets/<id>/;
  re-authoring an id overwrites (new content hash = hot-reload). Never throws.
- amicode_author_widget built-in tool (Tool.define + registry) whose description IS
  the authoring contract (mount signature, --amc-* tokens, fetch allowlist,
  empty-state). Output carries an AMICODE_WIDGET {json} sentinel for the preview.
- mergeDashboard: BUILT-IN widgets still auto-surface; USER/authored/forked widgets
  are now opt-in via pin (no home clutter while iterating in chat).

UI:
- widget-preview.ts: pure parseWidgetSentinel (mirrors parseDiffSentinel).
- WidgetPreviewCard: live WidgetFrame (reuses the kernel) + Pin button + warnings;
  reads a widgetHost transport off the ui-bridge; degrades to a note with no host.
- AmicodeToolCard: new <Match> for amicode_author_widget.
- ui-bridge: AmicodeWidgetHost {frameSrc, callbacks, pin}; entity-rail passes it in.

App:
- message-timeline provides widgetHost (frame src, fetch/prompt callbacks, pin =
  GET+append+POST /amicode/dashboard).

Tests: authorWidget 5, sentinel parser 4, dashboard opt-in 1 (ui 178 / server 40 green).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…or.clipboard.read in the outer webview + copy-back

The webview half of the bidirectional clipboard bridge (extension half is in amicode#136):
image paste answered client-side in the outer webview where navigator.clipboard.read is
granted (the sandboxed iframe + text-only vscode.env.clipboard can't); copy writes back to
the OS clipboard; text-paste fallback on any failure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Rchari1
Rchari1 requested a review from aarontrowbridge July 14, 2026 22:52
@Rchari1
Rchari1 marked this pull request as ready for review July 14, 2026 22:54
@Rchari1
Rchari1 merged commit 3afee91 into local/amicode Jul 14, 2026
0 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants