Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
58fbaae
amicode(home): cards paint above the session list + grid row can shrink
Rchari1 Jul 6, 2026
3d659ea
amicode: theme bridge for the VS Code webview host
Rchari1 Jul 6, 2026
c3e4784
amicode(server): one-spine terminal semantics — run-status/run-series…
Rchari1 Jul 6, 2026
bfc3e89
amicode: in-place profile editing + brand polish
Rchari1 Jul 6, 2026
d18d666
amicode(home): hide the single-project row (brand block covers it); t…
Rchari1 Jul 6, 2026
b4c0187
amicode: straight AMICODE wordmark + animated tagline — 'Amico — Your…
Rchari1 Jul 6, 2026
e075367
amicode: session-tab brand mark (H-robot spinner while working, dot f…
Rchari1 Jul 7, 2026
f4cc8b6
amicode: forward ⌘⇧P to the host editor's Command Palette when embedd…
Rchari1 Jul 7, 2026
57fa090
amicode(home): Meet-Amico card — gold shine sweep + lift on hover; ca…
Rchari1 Jul 7, 2026
36f7fe6
amicode(home): session rows use the brand mark (H-robot spinner while…
Rchari1 Jul 7, 2026
2b9fe88
amicode(home): session rows get a quiet chevron (brand mark everywher…
Rchari1 Jul 7, 2026
11d1dc9
amicode(home): session rows always show the quiet chevron (a wedged s…
Rchari1 Jul 7, 2026
ecb91d6
amicode: code-typing boot splash (harmoniqs.co motif — Piccolo lines …
Rchari1 Jul 7, 2026
7d144c8
amicode: reopened interviews stay usable — ask-cards derive state fro…
Rchari1 Jul 7, 2026
b67f9bc
amicode: About-You institution profile + scholar link; stalled-run de…
Rchari1 Jul 7, 2026
3d342f5
amicode: paste works in profile fields + LinkedIn-style institution s…
Rchari1 Jul 7, 2026
29c5721
amicode: institution logos via Google's favicon service (clearbit log…
Rchari1 Jul 7, 2026
5a2f1dd
amicode: paste rides the extension clipboard bridge (navigator.clipbo…
Rchari1 Jul 7, 2026
e9c9e16
amicode: About-You restructure — institution banner is THE block (no …
Rchari1 Jul 7, 2026
3a0ac13
amicode: institution logos upgrade to the Wikipedia page image at pic…
Rchari1 Jul 7, 2026
72d60f8
amicode: institution logos resolve Wikidata P154 (the BRAND logo — NY…
Rchari1 Jul 7, 2026
643dbf3
amicode(home): top band hugs content (flex-none, md max-h cap) — coll…
Rchari1 Jul 7, 2026
3324cb0
amicode(home): Meet-Amico CTA — big accent 'Open chat ↗' (center-left…
Rchari1 Jul 7, 2026
8eb9e51
amicode(home): footer — Harmoniqs brand link (bridge-opened), Piccolo…
Rchari1 Jul 7, 2026
471c8d2
amicode(home): harmoniqs.ai (correct domain) in footer; fluid full-sc…
Rchari1 Jul 7, 2026
2490f6e
amicode(ui): stalled runs render honestly + hide MCP status popover
Rchari1 Jul 7, 2026
17a264d
amicode(home): fit one screen on laptop heights — @media(max-height) …
Rchari1 Jul 7, 2026
3e1f4de
test: amicode-problems tests updated to the one-spine + stalled contr…
Rchari1 Jul 7, 2026
01aeab8
fix(run-series): pulse parse honors the ;-drive seam — split(",") NaN…
Rchari1 Jul 7, 2026
7fb5669
fix(run-window): pulse plot renders one path per drive (pulse_meta sl…
Jul 7, 2026
29edf1d
fix(rail): run chip keeps 'stopped'/'aborted' — the parser whiteliste…
Rchari1 Jul 7, 2026
5d99d67
fix(run-window): 'stopped'/'aborted' get honest colors (muted/danger,…
Rchari1 Jul 7, 2026
9efb9b3
fix(run-status): isStalled's logless fallback anchors on run.toml mti…
Rchari1 Jul 7, 2026
4a5dcf9
fix(profile): Save failures show a message instead of silently revert…
Rchari1 Jul 7, 2026
6dc54ff
fix(profile): resolvingLogo is a counter — overlapping institution pi…
Rchari1 Jul 7, 2026
ce075ac
fix(profile): institution search hardened — out-of-order responses ca…
Rchari1 Jul 7, 2026
ecd48e5
fix(profile): paste interception is iframe-only — in a plain browser …
Rchari1 Jul 7, 2026
548aa47
fix(profile): dead logo URLs fall back to the monogram tile (hero) or…
Rchari1 Jul 7, 2026
63bc0c2
fix(profile): guard against a non-object profile.json — a JSON primit…
Rchari1 Jul 7, 2026
e62f625
fix(run-terminal): align the mirror with the canonical contract — raw…
Rchari1 Jul 7, 2026
4741f6b
fix(home): run-status polls at 5s while Home is mounted (2.5s while s…
Rchari1 Jul 7, 2026
5efb019
docs(home): session-row comment matches reality — the working-spinner…
Rchari1 Jul 7, 2026
d0a829b
style: prettier over the branch's touched files (repo formatter, 3.6.2)
Rchari1 Jul 7, 2026
d653148
style: prettier repo-wide (repo config; upstream already clean — rema…
Rchari1 Jul 7, 2026
553e409
fix(home): laptop tiers compact CONTENT, not just chrome — ≤880px tig…
Rchari1 Jul 7, 2026
4eefa40
fix(tools): legacyJsonSchema normalizes nullable unions — type:['arra…
Rchari1 Jul 7, 2026
e737dba
fix(home): dead Help row removed (platform.openLink is a no-op inside…
Rchari1 Jul 7, 2026
d9deac3
fix(home): brand block nudged down a touch; floating '?' HelpButton r…
Rchari1 Jul 7, 2026
46d106e
feat(run-cards): GET /amicode/run-cards — every completed solve acros…
Rchari1 Jul 7, 2026
ab787ef
feat(run-cards): shareable solve cards + run gallery — fixed 1200×630…
Rchari1 Jul 7, 2026
b3ad983
fix(entity-view): cap the dialog at 680px/68vh with internal scroll —…
Rchari1 Jul 7, 2026
00b06ae
test(app): update WSL settings assertions to rebranded Amicode strings
jack-champagne Jul 7, 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
130 changes: 71 additions & 59 deletions AMICODE-PATCHES.md

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions packages/app/public/oc-theme-preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@
localStorage.removeItem("opencode-theme-css-dark")
}

// amicode: VS Code webview bridge — the extension passes ?colorScheme=light|dark
// (from vscode.window.activeColorTheme). Seed the storage key BEFORE the read
// below so the app boots in the editor's theme (prefers-color-scheme inside a
// webview iframe reports the OS, not VS Code).
try {
var q = new URLSearchParams(location.search).get("colorScheme")
if (q === "light" || q === "dark") localStorage.setItem("opencode-color-scheme", q)
} catch (e) {
/* storage unavailable — keep defaults */
}

var scheme = localStorage.getItem("opencode-color-scheme") || "system"
var isDark = scheme === "dark" || (scheme === "system" && matchMedia("(prefers-color-scheme: dark)").matches)
var mode = isDark ? "dark" : "light"
Expand Down
35 changes: 33 additions & 2 deletions packages/app/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { MarkedProvider } from "@opencode-ai/ui/context/marked"
import { File } from "@opencode-ai/ui/file"
import { Font } from "@opencode-ai/ui/font"
import { Splash } from "@opencode-ai/ui/logo"
import { ThemeProvider } from "@opencode-ai/ui/theme/context"
import { ThemeProvider, useTheme } from "@opencode-ai/ui/theme/context"
import { MetaProvider } from "@solidjs/meta"
import { type BaseRouterProps, Navigate, Route, Router, useParams, useSearchParams } from "@solidjs/router"
import { QueryClient, QueryClientProvider } from "@tanstack/solid-query"
Expand Down Expand Up @@ -50,6 +50,7 @@ import DirectoryLayout, { DirectoryDataProvider } from "@/pages/directory-layout
import Layout from "@/pages/layout"
import { ErrorPage } from "./pages/error"
import { useCheckServerHealth } from "./utils/server-health"
import { AmicodeSplash } from "@opencode-ai/ui/amicode-splash"

const HomeRoute = lazy(() => import("@/pages/home"))
const Session = lazy(() => import("@/pages/session"))
Expand Down Expand Up @@ -227,6 +228,35 @@ function RouterRoot(props: ParentProps<{ appChildren?: JSX.Element }>) {
)
}

/** amicode: live theme bridge for the VS Code webview host. The extension
* forwards editor theme changes as window messages (outer relay → iframe);
* route them through the existing setColorScheme so everything re-themes. */
function AmicodeThemeBridge() {
const theme = useTheme()
const onMsg = (e: MessageEvent) => {
const d = e.data as { source?: string; kind?: string; colorScheme?: string } | undefined
if (d?.source !== "amicode" || d.kind !== "theme") return
if (d.colorScheme === "light" || d.colorScheme === "dark") theme.setColorScheme(d.colorScheme)
}
window.addEventListener("message", onMsg)
onCleanup(() => window.removeEventListener("message", onMsg))
// ⌘⇧P / Ctrl+Shift+P: when embedded in the amicode webview (we have a
// parent), the EDITOR's Command Palette wins over the app's own palette —
// capture-phase so the in-app binding never sees it; forwarded over the
// existing allowlisted command bridge.
const onKey = (e: KeyboardEvent) => {
if (window.parent === window) return
if ((e.metaKey || e.ctrlKey) && e.shiftKey && (e.key === "p" || e.key === "P")) {
e.preventDefault()
e.stopPropagation()
window.parent.postMessage({ source: "amicode", kind: "command", command: "workbench.action.showCommands" }, "*")
}
}
window.addEventListener("keydown", onKey, { capture: true })
onCleanup(() => window.removeEventListener("keydown", onKey, { capture: true }))
return null
}

export function AppBaseProviders(props: ParentProps<{ locale?: Locale }>) {
return (
<MetaProvider>
Expand All @@ -236,6 +266,7 @@ export function AppBaseProviders(props: ParentProps<{ locale?: Locale }>) {
void window.api?.setTitlebar?.({ mode })
}}
>
<AmicodeThemeBridge />
<LanguageProvider locale={props.locale}>
<UiI18nBridge>
<ErrorBoundary
Expand Down Expand Up @@ -296,7 +327,7 @@ function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) {
when={!checking()}
fallback={
<div class="h-dvh w-screen flex flex-col items-center justify-center bg-background-base">
<Splash class="w-16 h-20 opacity-50 animate-pulse" />
<AmicodeSplash />
</div>
}
>
Expand Down
9 changes: 7 additions & 2 deletions packages/app/src/components/session/session-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import { messageAgentColor } from "@/utils/agent"
import { decode64 } from "@/utils/base64"
import { Persist, persisted } from "@/utils/persist"
import { StatusPopover, StatusPopoverV2 } from "../status-popover"

// AMICODE: the MCP/LSP/Plugins/Vaults status popover is opencode-operator
// noise here ("No MCPs configured"). Hidden, not deleted — the trigger slot is
// where a solver-health panel (server/Julia env/runs dir) belongs later.
const AMICODE_HIDE_STATUS_POPOVER = true
import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2"
import { Icon as IconV2 } from "@opencode-ai/ui/v2/icon"

Expand Down Expand Up @@ -439,7 +444,7 @@ export function SessionHeader() {
</div>
</Show>
<div class="flex items-center gap-1">
<Show when={status()}>
<Show when={!AMICODE_HIDE_STATUS_POPOVER && status()}>
<Tooltip placement="bottom" value={language.t("status.popover.trigger")}>
<StatusPopover />
</Tooltip>
Expand Down Expand Up @@ -531,7 +536,7 @@ type SessionHeaderV2ActionsState = {
function SessionHeaderV2Actions(props: { state: SessionHeaderV2ActionsState }) {
return (
<div class="flex items-center gap-2">
<Show when={props.state.statusVisible}>
<Show when={!AMICODE_HIDE_STATUS_POPOVER && props.state.statusVisible}>
<Tooltip placement="bottom" value={props.state.statusLabel}>
<StatusPopoverV2 />
</Tooltip>
Expand Down
16 changes: 13 additions & 3 deletions packages/app/src/components/session/session-new-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { amicodeGet } from "@/utils/amicode-fetch"
import { parseProblemsResponse } from "@opencode-ai/ui/amicode-problem-switcher"
import { Icon } from "@opencode-ai/ui/icon"
import { AmicodeGettingStarted } from "@opencode-ai/ui/amicode-getting-started"
import { Logo, Mark } from "@opencode-ai/ui/logo"
import { Mark } from "@opencode-ai/ui/logo"
import { getDirectory, getFilename } from "@opencode-ai/core/util/path"

const MAIN_WORKTREE = "main"
Expand Down Expand Up @@ -79,8 +79,18 @@ export function NewSessionView(props: NewSessionViewProps) {
<div class="w-full max-w-200 flex flex-col items-center text-center gap-4">
<div class="flex flex-col items-center gap-6">
<Mark class="w-28" />
{/* amicode: brand wordmark replaces the localized headline — brand marks don't translate */}
<Logo class="w-56 max-w-full" />
{/* amicode: straight wordmark (the Logo's Racing Sans One face reads as
italic); byline keeps the brand attribution. */}
<div
style={{
"font-size": "34px",
"font-weight": "700",
"letter-spacing": "0.1em",
color: "var(--v2-text-text-base)",
}}
>
AMICODE
</div>
</div>
{/* amicode: getting-started block (tagline + how-it-works + starter chips) */}
<AmicodeGettingStarted
Expand Down
11 changes: 10 additions & 1 deletion packages/app/src/components/status-popover-body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,16 @@ import { Switch } from "@opencode-ai/ui/switch"
import { Tabs } from "@opencode-ai/ui/tabs"
import { showToast } from "@/utils/toast"
import { useNavigate } from "@solidjs/router"
import { type Accessor, createEffect, createMemo, createResource, For, type JSXElement, onCleanup, Show } from "solid-js"
import {
type Accessor,
createEffect,
createMemo,
createResource,
For,
type JSXElement,
onCleanup,
Show,
} from "solid-js"
import { createStore } from "solid-js/store"
import { ServerHealthIndicator, ServerRow } from "@/components/server/server-row"
import { useLanguage } from "@/context/language"
Expand Down
24 changes: 17 additions & 7 deletions packages/app/src/components/titlebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import { useGlobal } from "@/context/global"
import { decode64 } from "@/utils/base64"
import { ServerConnection, useServer } from "@/context/server"
import { tabHref, useTabs, type Tab } from "@/context/tabs"
import { Mark } from "@opencode-ai/ui/logo"
import { AmicoSpinner } from "@opencode-ai/ui/amico-spinner"

type TauriDesktopWindow = {
startDragging?: () => Promise<void>
Expand Down Expand Up @@ -862,14 +864,22 @@ function ProjectTabAvatar(props: {
const directory = () => props.directory
const sessionId = () => props.sessionId
const state = useSessionTabAvatarState(directory, sessionId, () => props.activeServer)
// amicode: brand mark instead of the letter project-avatar ("blue A"). Idle =
// static Mark; while the agent works, Aaron's H-robot spinner (gentle pulse,
// honors prefers-reduced-motion) replaces the radar ring. Unread keeps a dot.
return (
<ProjectAvatar
fallback={displayName(props.project ?? { worktree: props.directory })}
src={getProjectAvatarSource(props.project?.id, props.project?.icon)}
variant={getProjectAvatarVariant(props.project?.icon?.color)}
unread={state.unread()}
loading={state.loading()}
/>
<span class="relative inline-flex size-5 shrink-0 items-center justify-center">
<Show when={state.loading()} fallback={<Mark class="size-4" />}>
<AmicoSpinner class="size-4" />
</Show>
<Show when={state.unread()}>
<span
aria-hidden="true"
class="absolute -top-0.5 -right-0.5 size-1.5 rounded-full"
style={{ background: "var(--v2-icon-icon-accent)" }}
/>
</Show>
</span>
)
}

Expand Down
9 changes: 9 additions & 0 deletions packages/app/src/context/command.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,15 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
const modified = event.ctrlKey || event.metaKey || event.altKey
const isTab = event.key === "Tab"

// Clipboard/undo chords belong to the focused editor — never to the app
// keymap — when typing in an input/textarea (paste into profile fields
// was being swallowed by a colliding keybind).
const isClipboardChord =
(event.metaKey || event.ctrlKey) &&
!event.altKey &&
["v", "c", "x", "a", "z", "y"].includes(event.key.toLowerCase())
if (isEditableTarget(event.target) && isClipboardChord && !isPalette) return

if (isEditableTarget(event.target) && !isPalette && !isAllowedEditableKeybind(option?.id) && !modified && !isTab)
return

Expand Down
Loading
Loading