Uh oh!
There was an error while loading. Please reload this page.
feat(amicode): the harmonic wave working indicator, and two transcript cleanups - #100
Merged
Merged
Conversation
(cherry picked from commit f086433)
(cherry picked from commit 358d2ae)
…c number The three curves are physically n=2,4,6 for a fixed-end string (lambda_n = 2L/n with L=30), labelled 1/2/3 because the index counts full wavelengths across the box. The consecutive set (lambda 60/30/20) was built and compared; the current set won on looks. Written down because this codebase's readers are quantum- control physicists who will reach for lambda_n = 2L/n and find the labels off by a factor of two. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 4691a0b)
…ment Adds the SolidJS component (amico-wave.tsx) that renders the standing-wave glyph purely from amico-wave.ts's geometry/timing constants via CSS custom properties, plus the matching CSS block and an anti-drift test guarding the one unavoidable duplicated literal (the @Keyframes percentage). Removes the now-superseded amc-text-shimmer treatment (leading dot + shimmer keyframes) from the thinking line. Also flips allowImportingTsExtensions on for packages/ui: this directory now has both amico-wave.ts (pure module) and amico-wave.tsx (component) sharing a stem, and under "bundler" resolution an extensionless "./amico-wave" import resolves to the .tsx sibling instead of the .ts module (confirmed empirically with a standalone repro) — the component would have silently self-imported. Pinning the import with an explicit ".ts" extension fixes it, and this flag is TypeScript's sanctioned way to permit that syntax under noEmit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 7a7bcff)
…the .ts/.tsx stem collision amico-wave.ts and amico-wave.tsx shared a stem, and bun resolves an extensionless import of that stem to the .tsx — so the component self-imported. Fixed by renaming rather than by relaxing tsconfig: the directory convention (thinking.ts / thinking-line.tsx) already avoids this by construction. Reverts allowImportingTsExtensions and adds a test that fails if any same-stem pair reappears in this directory. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 3b7b3b4)
… drift guard The :root:not([data-theme="light"]) selector was derived from CSS that is inside a block comment in v2/styles/theme.css. data-theme carries a theme id, not a scheme, so the selector matched every reachable state and the wave rendered lemon at ~1.1:1 on light themes. oc-2.json already encodes the ink role in v2-icon-icon-accent (grey-800 light, #FFF676 dark), which is what amico-presence.css uses, so no theme selector is needed at all. Also tightens the amc-wave-mode CSS/TS drift guard: the old toContain() check passed under mutations that break the animation (ON edge dragged to 50%, OFF edge dragged to 40%) because the literal could still appear elsewhere in a loosely-bounded slice. Now asserts each breakpoint against its own selector+brace, and the previously-unguarded OFF literal is exported as MODE_OFF_PCT and checked too. Adds a MODE_HOLD_MS % WAVE_PERIOD_MS invariant test, and rewords two comments that described the component as already mounted (it isn't yet — a later task wires it in). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit fdab7d9)
… guards (cherry picked from commit 158f522)
…tatic (cherry picked from commit 2270998)
(cherry picked from commit f2090dd)
…with a count Four amicode_* calls against the same entity rendered four identical cards. Runs of consecutive receipts sharing (problem, entity, action) now render as one card with a count, opening the latest seq. Conservative by design: a differing action, entity or problem, an interrupting part, or an unparseable sentinel all prevent merging, so no state change can be hidden. (cherry picked from commit 5176a69)
An activated skill rendered as a bare name ('brainstorming'), indistinguishable
from any other tool call: ui.tool.skill ('Skill') was reachable only as a
fallback for a missing input.name, which never happens. The kind now always
renders in front of the name, in both the expandable trigger and the compact
title map.
Also removes the last TextShimmer in the skill renderer. The previous commit
retired the shimmer from tool-status-title but missed this site, leaving the two
inconsistent.
Not made an amicode receipt card, despite the temptation: those carry an
AMICODE_DIFF sentinel and open an entity view. A skill has neither, and spending
the H-mark card on generic agent mechanics would dilute what the mark means.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit b6981f6)Amicode's skills are Amico's own repertoire, so activating one is Amico acting and earns the same chip the domain receipts wear: H-mark, rule, label naming the kind, detail naming the skill. Replaces the plain text label from the previous commit. New AmicoSkillChip in card.tsx rather than a new mode on Chip -- Chip is sentinel-driven and a skill has no AMICODE_DIFF, so threading it through would have meant special-casing the parse path. Inert shell, no chevron: there is no entity to open. It nests inside BasicTool's trigger so the expandable instruction body is kept. That is only safe because BasicTool declares an `icon` prop and never renders it -- verified, nothing in basic-tool.tsx reads props.icon -- so the H-mark is the row's only glyph and no stock component needed changing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 17c6755)
Expanding a skill dumped its instructions as bare markdown into the transcript, because [data-component="tool-output"] has no surface of its own -- no border, no background, no padding, and white-space:pre. So an opened skill read as more conversation. It is a file, so it now gets a file's surface: hairline, tint, padding, and a bounded scrolling height instead of pushing the transcript around. Scoped to skills; other tools' output is unchanged. Compound selector because a bare .amc-skill-file would tie with [data-component="tool-output"] on specificity and be settled by stylesheet order. Follows a revert of the aside-lane attempt, which indented the whole activation behind an accent spine and broke the shared left edge that Model / Skill / Recommend chips read along. The chip belongs flush with its siblings; it was only ever the opened body that needed separating. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> (cherry picked from commit 8e11411)
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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.
The chat had two "working" indicators that looked identical — the thinking line and the tool-group header — because both were shimmering text with no glyph. This replaces that with one brand motif, and fixes two transcript problems found while verifying it in the dev host.
The harmonic wave
A standing wave in quadrature: two identical sine curves, the companion a quarter period out of phase, so one is at full swing whenever the other crosses zero. That is what stops the glyph reading as a blink at 12px — a single standing line passes through zero amplitude twice per cycle. Three curves cross-fade so the harmonic index climbs.
Geometry and timing live in
wave-geometry.ts, pure and DOM-free, following thethinking.ts/run-series.tsconvention. All animation is CSS — two keyframes, transform and opacity only, no rAF — since this sits on screen for minutes at a time.Two correctness traps are written down in the code because both are invisible on inspection:
animation-delaymagnitudes must descend for the visible sequence to ascend. The intuitive-1×/-2×ordering silently plays mode 1 → 3 → 2. The delays are therefore computed by a tested function and passed as inline style, so the CSS cannot reintroduce it. There is a regression test that fails if the ordering inverts.<defs>and noidattributes. Several indicators mount at once (one per in-flight tool call) and SVG ids are document-global, so ids would collide and every instance would resolve to the first definition. A story mounts 8 at once as the guard.Repeated receipt cards collapse
Four
amicode_*calls against one entity rendered four identical cards. Runs of consecutive receipts sharing(problem, entity, action)now render as one card with a count, opening the highestseq. Conservative by design — a differing action, entity or problem, an interrupting part, or an unparseable sentinel all prevent merging, so no state change can hide.INLINE_KINDSentities are excluded entirely: they can resolve to a liveInlineEntityViewvia a reactive currency check the pure module cannot see, so collapsing them risked dropping a render path.Skill activations
ui.tool.skill("Skill") was reachable only as a fallback for a missinginput.name, which never happens — so an activated skill rendered as a bare word, indistinguishable from any other tool. Skills now say what they are and wear the Amico chip, since amicode's skills are Amico's repertoire. An opened skill file gets a bounded, tinted panel instead of dumping markdown into the transcript, because[data-component="tool-output"]carries no surface of its own.Notes for review
tool-status-title.tsxis a stock opencode component. The change is logged inAMICODE-PATCHES.md. Only the shimmer went; the active→done word morph is deliberately preserved.--v2-icon-icon-accentis the ink role, resolved byoc-2.jsontogrey-800on light and#FFF676on dark. Do not add a scheme selector for it. In particular,:root:not([data-theme="light"])is dead CSS — the block containing it inv2/styles/theme.cssis inside a/* */comment, anddata-themeholds a theme id rather than a scheme. An earlier revision built on it and shipped a lemon-on-white glyph at ~1.1:1.data-color-schemeon a wrapper; its preview loads only the v1 theme bundle.amico-wave.stories.tsxresolves tokens throughresolveThemeVariantV2()instead, which is the only reason the contrast bug above was caught before a user saw it..amc-lane's head is now static, since two animated brand marks side by side compete with each other.Testing
bun test srcinpackages/ui: 432 pass / 0 fail.bun turbo typecheckclean.oxlint packages/ui/srcat 505 warnings / 0 errors — identical to the base, no new warnings. Verified in the extension dev host on both light and dark themes.Not included
A transcript rail (a vertical spine bracketing Amico's stretch of a turn) was built and reverted. The design held up, but it stalled on a dev-host webview serving a stale content-hashed document, which meant no CSS or JS change reached the screen at all and looked exactly like a broken feature. Worth knowing independently of this PR: a new vendored binary needs a full dev-host restart, not
Cmd+R— the webview can stay pinned to the old asset hash.