b12f215
fix(skills): follow symlinks in Discover()
Click to expand commit body
os.ReadDir returns DirEntry values whose IsDir() reports the symlink's
own type, not the target's. When skill directories are symlinks (e.g. in
~/.config/agents/skills/), Discover() skipped them all.
Use os.Stat on the resolved path to follow symlinks.
References: https://github.com/boldsoftware/shelley/issues/83
Co-authored-by: Shelley <shelley@exe.dev>
Amolith
and
Shelley
created
efa11b2
shelley: refresh conversations list on reconnect
Click to expand commit body
Prompt: When shelley comes back from a reconnection, it needs to refresh the conversations list, since it could have missed updates.
When the SSE stream reconnects after a disconnection, conversation list
updates may have been missed. Refresh the full conversations list on
reconnect to ensure the sidebar is up to date.
Uses a hasConnectedRef to distinguish initial connection from reconnects,
avoiding a redundant fetch on first load.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
7b3df63
shelley/ui: make model/dir fields full width on mobile with aligned labels
Click to expand commit body
Prompt: You may as well make those things full width in mobile and align the labels nicely.
Remove max-width constraints on mobile so the Model and Dir fields
stretch to full width. Right-align labels to a consistent width so
the controls line up neatly.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
ca65fdb
shelley: fix skills not loaded from non-home working directories
Click to expand commit body
Prompt: Recent boldsoftware/shelley gh issue talks about skills not being read depending on working dir. Fix that.
DefaultDirs() had overly complex pre-checking logic that scanned
candidate directories for skill subdirectories before returning them.
This was unnecessary since Discover() already handles scanning, and
the complexity could cause edge cases where valid skill directories
were missed.
Simplified DefaultDirs() to always return candidate directories that
exist (~/.config/shelley, ~/.config/agents/skills, ~/.shelley),
letting Discover() do the actual skill scanning.
Also wired up ProjectSkillsDirs() in collectSkills() so that .skills
directories in the project tree are now discovered (they were defined
but never called).
Fixes https://github.com/boldsoftware/shelley/issues/83
Co-authored-by: Shelley <shelley@exe.dev>
fdebb9a
shelley: fix ESLint errors in TerminalPanel
Click to expand commit body
Prompt: fix it (link to failing ESLint CI job)
Remove unused onCloseAll prop, unused activeInfo variable, and
invalid eslint-disable comments for unconfigured react-hooks rule.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Philip Zeyliger
and
Claude Opus 4.6
created
cfe7e6b
shelley: fix shell-mode indicator positioning in input bar
Click to expand commit body
Wrap textarea and shell-mode indicator (>_) in a .textarea-wrapper with
position:relative so the indicator is anchored to the input field,
not the outer container. Previously the indicator floated at the left
edge of the full-width container, drifting away from the centered
input on wide viewports.
Prompt: The > thing should be in the input bar, not weirdly outside. It moves around depending on the width, and that's wrong.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
3afaf63
shelley: fix terminal panel padding and dark mode detection
Click to expand commit body
Add padding (8px/12px) to terminal content so text doesn't touch edges.
Fix dark mode detection to use .dark class on documentElement
(matching the rest of the app) instead of data-theme attribute.
Prompt: fix two things: give padding to the terminal since it goes right up against the edge, and make it respect dark mode/light mode settings
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
344666a
shelley: only auto-size terminal panel for the first command
Click to expand commit body
Prompt: I don't think we should shrink down, or resize at all, for subsequent commands. First command can have magic size, but after that, let's stick with what's there.
The first !command auto-sizes the panel to fit its output. After that,
the height stays locked—no shrinking or growing for subsequent tabs.
Manual drag-resize still works and also locks the height.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
9c98c54
shelley: move terminal panel between timeline and status bar with tabbed UI
Click to expand commit body
Prompt: In a new worktree, change how the terminal that happens when you do !bash in shelley works. Instead of going in the timeline view, make the terminal appear between timeline view and the Ready bar. And if you need multiple terminals, make it tabbed. So !bash opens up one, and it's got an (x) to close and all the cut/paste buttons. If there's another !ls or whatever, then a second tab opens up, and the user can flip between them. We can make the height adjustable, but if the terminal output is short, we should continue squishing it down just like we do today.
Replace inline TerminalWidget (rendered in the message timeline) with a new
TerminalPanel component that sits between the messages area and the status
bar. Key changes:
- Terminals from !commands now appear in a persistent panel at the bottom
of the screen, between the message timeline and the Ready/status bar
- Multiple terminals are tabbed: each !command opens a new tab
- Tabs show command name, status indicator (● running, ✓ success, ✗ error),
and an × close button
- Panel auto-sizes to fit short output (e.g., !ls, !pwd shrink down)
- Running terminals (e.g., !bash) grow the panel as output arrives
- Resize handle at the top allows manual height adjustment by dragging
- Action buttons (copy screen, copy all, insert screen, insert all, close)
are in the header bar
- Tab switching preserves terminal state and output
- Dark/light theme support with matching xterm.js colors
- Removed TerminalWidget.tsx (fully replaced by TerminalPanel.tsx)
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
a460f25
shelley/ui: fix focus loss after pasting image
Click to expand commit body
Prompt: Fix https://github.com/boldsoftware/shelley/issues/65 again.
The textarea was disabled during uploads (isDisabled = disabled || uploadsInProgress > 0).
When a paste triggered an upload, uploadsInProgress went to 1, disabling the
textarea, which caused the browser to yank focus out of it.
Fix: only disable the textarea based on the disabled prop, not uploads.
The send button still gates on uploadsInProgress === 0, so users can't send
while uploads are in flight, but they can keep typing.
Also fix the e2e test that was placed outside its describe block.
Fixes boldsoftware/shelley#65
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
302290d
shelley: fix double encoding of UTF-8 in terminal output
Click to expand commit body
phil: This is one of those amazing things that Sketch ran
into, and six months later, the agents are still writing this one
not quite right. Had to do some handholding here.
Prompt: Fix https://github.com/boldsoftware/shelley/issues/79
The terminal widget was using atob() to decode base64 data from the
WebSocket, which returns a binary string where each byte becomes a
separate character. When passed to xterm.js term.write(), each byte
was interpreted as a Unicode code point, causing multi-byte UTF-8
sequences (like box-drawing characters ├──) to render as mojibake.
Fix by decoding the base64 data into a Uint8Array and passing that
to term.write(), which correctly handles raw bytes and decodes UTF-8
properly.
Fixes https://github.com/boldsoftware/shelley/issues/79
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
ad1e3ad
shelley/ui: pass git worktree to diff viewer, add dir chooser
Click to expand commit body
Prompt: Sometimes the diff view can get confused about what dir you're in. In the case that someone is clicking on a "diff" link that the agent reports after a git change, that should always work, since we can include the git repo dir in the hyperlink. We can also add a "dir" chooser (just a folder icon) that lets you navigate to a different git directory from the top bar. We can re-use the directory picker, probably, but we should filter to only show folders, not files, since git repositories are always folders.
Three changes:
1. When clicking a 'diff' link on a git commit message, the worktree
path from the git state is now passed through to the DiffViewer,
so it always opens in the correct directory regardless of the
conversation's cwd.
2. Added a folder icon button to the DiffViewer header (both mobile
and desktop) that opens a DirectoryPickerModal, allowing users to
switch to a different git repository directory.
3. Added a 'foldersOnly' prop to DirectoryPickerModal that filters
out non-directory entries, since git repositories are always
directories.
Co-authored-by: Shelley <shelley@exe.dev>
Add a "Go to git root" button in the directory picker when the current
directory is a git worktree. The button shows the main repository path
and navigates there on click.
Sort directory entries so hidden directories (.*) appear after
non-hidden ones, alphabetically within each group.
Prompt: In the directory selector, if the current directory is a worktree for another git repo, add a "go to git root" button right below the subject/git info, so that a user can quickly navigate there. Also, sort hidden files (.*) last, below the non-hidden ones in the directory list
Co-authored-by: Shelley <shelley@exe.dev>
Prompt: use a new worktree; fetch; rebase on origin/main. Sometimes, it seems
like the stream for he conversation disappears or something, and the UI gets
behind. Is there still an occasional heartbeat? Smoe visual indicator that
we're disconnected? Good retry semantics? I don't quite know how it works, and
I think it happens when I leave a tab for a while.
- Add 'reconnecting' visual state shown during backoff attempts (1-3)
- Check EventSource.readyState on tab visibility/focus to detect dead connections
- Always attempt reconnection when tab becomes visible if connection is unhealthy
- Previously, visibility/focus handlers only triggered reconnect after the
'isDisconnected' state was set (after 3 failed attempts), missing cases where
EventSource silently died due to browser throttling backgrounded tabs
The heartbeat mechanism (30s server, 60s client timeout) remains in place as a
fallback, but proactive connection health checks on visibility change provide
faster recovery when users return to the tab.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
5bd9f11
shelley: fix git repo detection using wrong directory
Click to expand commit body
Prompt: evaluate and fix https://github.com/boldsoftware/shelley/issues/71 . The agent has been given a working directory; maybe we're checking the wrong directory to see if it's a git repo?
collectGitInfo() was running `git rev-parse --show-toplevel` without
setting cmd.Dir, so it checked the server process's cwd instead of the
user's working directory. This caused the system prompt to incorrectly
say "Not in a git repository" for VMs where the user's project was in
a git repo but the server process ran from a different directory.
Fixes https://github.com/boldsoftware/shelley/issues/71
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prompt: In a new worktree, pull the latest. Then add codex-5.3 support to llmgateway in one commit and Shelley in another.
- Add GPT53Codex model definition in oai.go
- Add 288k context window for gpt-5.3-codex in oai_responses.go
- Add gpt-5.3-codex to Shelley's models.go with gateway support
- Add test for the new context window size
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
2ad320b
server: notify UI when subagent conversation is used
Click to expand commit body
Prompt: I'm seeing subagent conversations sometimes not reflected in the
ui. Look very critically at the communications across the agent and the
ui over the stream. How can we improve it? Perhaps we can notice when
the full list of unarchived conversations has changed and send a nudge
to the ui to reload based on that? Set up some tests that emulate
subagent behaviors to see if you can break the protocol and fix it
Fixes https://github.com/boldsoftware/shelley/issues/76, hopefully
When RunSubagent is called, immediately notify all SSE streams about
the subagent conversation via publishConversationListUpdate. This
ensures the UI sidebar shows subagent conversations as soon as they
become active, rather than requiring a manual poll.
The notification is sent in a goroutine to avoid blocking the subagent
processing, and only fires for conversations that have a parent
(i.e., are actually subagents).
Also adds a test that verifies the notification is received via SSE
when RunSubagent is called.
Fixes issue where subagent conversations wouldn't appear in the UI
until the user manually refreshed or navigated away and back.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
80c5359
shelley: add GitHub Pages for version metadata to avoid API rate limits.
Click to expand commit body
Prompt: In a new worktree, have Shelley's build process also publish into a
static page hosted by GitHub the last release version metadata and the last
500 short commit Shas and their subjects. This will be used to have Shelley
check for updates instead of the GitHub api. Let me know what I'll need to
configure on GitHub to make gh pages work
- Add publish-version-metadata.yml workflow that runs after each release
- Add scripts/generate-version-metadata.py to generate release.json and commits.json
- Update versioncheck.go to use only the static GitHub Pages
- Simplify types: ReleaseInfo replaces GitHubRelease, remove GitHubCommit
- Remove all GitHub API code from version checking
Co-authored-by: Shelley <shelley@exe.dev>
I noticed that one of the most common edits I made to Claude-written
code is improving godoc style.
Perhaps I should just let it go, but I can't.
Apparently I care more about writing than about code.
I wrote a little style guide for Claude and asked it to apply it
in a dozen places so I could spot-check it.
This was the result. I figured I may as well commit it.
6100917
shelley: add Claude Opus 4.6 as the default model
Click to expand commit body
Prompt: Opus 4.6 just released. Add it to shelley. Make it the default model.
Add claude-opus-4-6 model constant and make it the new default model
for Shelley. Claude Opus 4.5 remains available as a fallback option.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
d9c9221
shelley: Replace think tool with unified ThinkingLevel API
Click to expand commit body
Prompt: Get rid of the think tool in shelley; enable thinking in the
anthropic (and other) models. Make the ui show thinking steps.
Continue: squash commits, unify thinking approach across providers.
Changes:
- Remove the think tool from claudetool (think.go, think_test.go)
- Add ThinkingLevel type to llm package with levels: Off, Minimal, Low,
Medium, High
- ThinkingLevel.ThinkingBudgetTokens() maps to Anthropic budget_tokens:
Minimal=1024, Low=2048, Medium=8192, High=16384
- ThinkingLevel.ThinkingEffort() maps to OpenAI reasoning.effort string
- ThinkingLevelOff is the zero value, so existing code continues to work
- Add ThinkingLevel field to ant.Service and oai.ResponsesService
- Set ThinkingLevel=Medium for all production Anthropic and OpenAI services
- Update UI with ThinkingContent component to display thinking blocks
- Thinking is expanded by default, shows preview in header, full text below
- Remove ThinkTool.tsx component (no longer needed)
This unifies the thinking/reasoning approach across providers following
pi-mono's pattern of using effort levels rather than raw token budgets.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
3ad2952
shelley: use login shell to source user's PATH and environment
Click to expand commit body
Prompt: In a new worktree, fix https://github.com/boldsoftware/shelley/issues/72 ; we should try to respect the user's shell settings at least if it's bash.
Run bash commands via 'bash --login -c' instead of 'bash -c' so that
the user's shell configuration (~/.profile, ~/.bash_profile) is sourced.
This allows Shelley to access CLI tools that users have set up with
custom PATH entries (~/.local/bin), mise, fnox, and other shell
configuration.
Fixes https://github.com/boldsoftware/shelley/issues/72
Co-authored-by: Shelley <shelley@exe.dev>
2a281e3
skills: add ~/.config/agents/skills to search paths
Click to expand commit body
Prompt: Fix https://github.com/boldsoftware/shelley/issues/68 in a new worktree; just add more dirs to where we search for skills; should be additive.
Add support for loading skills from ~/.config/agents/skills in addition
to existing paths. This allows users to share skills across multiple
agents (Shelley, octofriend, crush, amp) without managing symlinks.
Search order:
1. ~/.config/shelley/ (XDG convention for Shelley)
2. ~/.config/agents/skills (shared agents skills directory)
3. ~/.shelley/ (legacy location)
Fixes https://github.com/boldsoftware/shelley/issues/68
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
759fde0
shelley: change system prompt for working dir
Philip Zeyliger
created
631e326
shelley: Fix change_dir to broadcast cwd update to UI via SSE
Click to expand commit body
Prompt: How does the "!pwd" handling in the UI interact with the cwd of the conversation? Maybe that's what's not working for me.
The issue: when change_dir tool ran, it updated the database but:
1. Did not update the ConversationManager's internal cwd field
2. Did not broadcast the update to SSE subscribers
The UI gets the conversation's cwd from StreamResponse events. Without
broadcasting, the UI only learns about cwd changes on:
- Page refresh
- 30-second heartbeat
Now when change_dir runs, it:
1. Updates the database (existing)
2. Updates cm.cwd for consistency
3. Broadcasts a StreamResponse with the updated conversation
Added TestChangeDirBroadcastsCwdUpdate to verify the SSE broadcast works.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
a03db87
shelley: Add test for change_dir tool affecting subsequent bash commands
Click to expand commit body
Prompt: Can you check, in a new worktree, that the cd tool changes directories and that subsequent bash tools get that directory? I'm worried it might not be working. We can absolutely write a test against the predictable model for this with the change direction tool and running pwd or something with the bash tool
- Add change_dir command to predictable model service ("change_dir: <path>")
- Add TestChangeDirAffectsBash test that verifies:
- change_dir tool changes the working directory
- subsequent bash commands (pwd) run in the new directory
- Fix predictable model to handle tool results (respond with "Done.")
This confirms the change_dir tool is working correctly at the server level,
not just at the claudetool package level.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
d82878a
shelley/ui: fix focus loss after pasting image
Click to expand commit body
Prompt: In a new worktree, reset to a fetched origin/main and fix https://github.com/boldsoftware/shelley/issues/65
After pasting an image, the cursor would leave the input box because:
1. handlePaste was async and awaited uploadFile
2. React state updates during upload caused focus to be lost
Fix:
- Make handlePaste synchronous (don't await uploadFile)
- Use setTimeout(10ms) to restore focus after React commits the state update
This allows users to paste an image and immediately continue typing.
Fixes boldsoftware/shelley#65
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
baa95b7
Add git config shelley.no-trailer to suppress co-author injection
Click to expand commit body
When user runs 'git config set shelley.no-trailer true', the Co-authored-by
trailer is no longer added to git commit commands.
Adds test for isNoTrailerSet() method.
afcb759
shelley: /debug/conversations page with CSV export for token visualization
Click to expand commit body
Prompt: I want a /debug/conversations view in Shelley which is just a list of conversations (with their slugs), with a way to download a compatible CSV of message costs.
- Add /debug/conversations route
- Lists all conversations with slug, date, message count
- Searchable by slug
- Download CSV button for each conversation
- CSV format: input_tokens,cache_write_tokens,cache_read_tokens,output_tokens
- CSV can be used with standalone token spend visualizer
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
f65cdb9
Revert "ci: use self-hosted runners for shelley-tests, push-to-main, and test-non-e1e"
Click to expand commit body
This reverts commit 0d7f3fdc59f5ee21da9cd2b22d6b93d48df901ff.
Philip Zeyliger
created
d5a2427
Revert "ci: skip browser test on ci.bold.dev because the wrong chrome is installed"
Click to expand commit body
This reverts commit a7e489fa2234c2e99972f26b066ebe4e93ec1d73.
Philip Zeyliger
created
a51fce4
ci: skip browser test on ci.bold.dev because the wrong chrome is installed
Click to expand commit body
Prompt: Skip the following as well. And also make test-non-e1e also run on the hosted runner. Make these changes in the top two commits
Philip Zeyliger
created
8d61288
ci: use self-hosted runners for shelley-tests, push-to-main, and test-non-e1e
Click to expand commit body
Prompt: Skip the following as well. And also make test-non-e1e also run on the hosted runner. Make these changes in the top two commits
Philip Zeyliger
created
cce64a4
ui: add worker pool support for @pierre/diffs
Click to expand commit body
Prompt: When using the diffs library for the diff view in the conversation timeline, we should set up the worker pool support. See https://diffs.com/docs#worker-pool-setup . Make it so.
Offload syntax highlighting to background threads for better
performance when rendering large diffs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Philip Zeyliger
and
Claude
created
c25753b
shelley: enable "predictable" model when gateway is set
Click to expand commit body
This is weirdly inside baseball with exe.dev's testing, but
so be it.
Philip Zeyliger
created
b989376
shelley/server: reduce custom model test timeout to 10 seconds
Click to expand commit body
Prompt: Fix https://github.com/boldsoftware/shelley/issues/57 in a new worktree. The issue is with the Test button for custom models; should definitely have a ~10 second timeout.
Fixes https://github.com/boldsoftware/shelley/issues/57
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
3f3151c
shelley/ui: enhance gitinfo notification with worktree and copy button
Click to expand commit body
Prompt: I want the following user notification to (a) put a copy button next to the hash and (b) include the working directory (worktree root or git root) that we're looking at.
- Add working directory (worktree) display at the beginning of the message
- Add copy button next to the commit hash for easy copying
- Show checkmark briefly after copying to indicate success
- Truncate long commit subjects with ellipsis and show full text on hover
- Style commit hash with monospace font and subtle background
- Extract GitInfoMessage into its own component for clarity
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
fc7d52d
shelley/ui: switch patch tool diffs to @pierre/diffs library
Click to expand commit body
Prompt: Can you use the @pierre/diffs library to render the diffs displayed in the patch tool? [...] Can you squash the "use diffs library" thing into one commit rebased on origin/main for me?
Replace the custom diff rendering in PatchTool with the @pierre/diffs
library which provides syntax-highlighted, split/unified diff views.
Changes:
- Add @pierre/diffs dependency
- Update PatchTool to use MultiFileDiff component
- Add language detection from file extension for syntax highlighting
- Support both split (side-by-side) and unified diff views with toggle
- Persist user's diff view preference in localStorage
- Auto-switch to unified view on mobile
- Add CSS containment properties for Safari rendering performance
(content-visibility, contain) to optimize rendering of many diffs
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
4139989
shelley: retry LLM requests on EOF and transient network errors
Click to expand commit body
Prompt: "LLM request failed: EOF" If the LLM fails with EOF, Shelley should retry at least once
When an LLM request fails with EOF or other transient network errors
(connection reset, connection refused, timeout, etc.), retry up to 2
times with exponential backoff before recording and returning the error.
This helps handle temporary connection issues that can occur with
long-running LLM requests.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
2b4f3e1
shelley: add heartbeat to conversation stream, support resume
Click to expand commit body
Prompt: In a new worktree, make it so that the conversation stream has some
sort of periodic heartbeat (e.g., every minute), and the client retries if
it hasn't seen anything in a minute. perhaps keep sending the state of the
conversation (whether the agent is running), since that's the most likely
thing to get confused... Note that we might want to make the stream endpoint
not start at the beginning but start at whatever point the client has, so as
to avoid double-sending stuff.
Add a periodic heartbeat (every 30 seconds) to the SSE conversation stream
to keep connections alive and provide current conversation state. This helps
with:
1. Detecting stale connections - the client reconnects if no message
(including heartbeat) is received within 60 seconds
2. Keeping proxies/load balancers from timing out idle connections
3. Syncing conversation state (working status) even when no messages flow
Also add support for resuming streams via the last_sequence_id query
parameter. When provided, the server skips sending historical messages
(which the client already has) and just sends the current state as a
heartbeat. This avoids re-sending potentially large message histories
on reconnection.
Server changes:
- Add Heartbeat field to StreamResponse
- Add last_sequence_id query parameter to stream endpoint
- Start heartbeat goroutine that broadcasts state every 30 seconds
- Restructure handleStreamConversation to query messages before creating
conversation manager (preserves existing behavior for fresh connections)
Client changes:
- Track last sequence ID from received messages
- Pass last_sequence_id to stream endpoint on reconnection
- Add 60-second heartbeat timeout that triggers reconnection
- Update types for heartbeat field
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
10c8c5c
shelley: add GatewayEnabled field to control which models are available via gateway
Click to expand commit body
Prompt: For models that are enabled when you use -gateway, make it: claude-opus-4.5, claude-sonnet-4.5, glm-4.7 (fireworks), gpt-5.2-codex, qwen3coder. Also add Tags field to Model struct, set Tags: "slug" on qwen3-coder-fireworks, and update GetModelInfo() to fall back to built-in models. Let's add haiku. No need for renaming qwen3-coder-fireworks; keep the old name.
Gateway-enabled models:
- claude-opus-4.5
- claude-sonnet-4.5
- claude-haiku-4.5
- glm-4.7-fireworks (new model using glm-4p7)
- gpt-5.2-codex
- qwen3-coder-fireworks (with Tags: "slug")
Also adds Tags field to Model struct for built-in models.
Co-authored-by: Shelley <shelley@exe.dev>