chore: version packages#1012
Merged
Merged
Conversation
github-actions
Bot
force-pushed
the
changeset-release/main
branch
30 times, most recently
from
July 22, 2026 22:09
3b1f5ab to
a6657f4
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
16 times, most recently
from
July 23, 2026 19:09
7142518 to
405a0c0
Compare
github-actions
Bot
force-pushed
the
changeset-release/main
branch
12 times, most recently
from
July 23, 2026 20:33
da7f179 to
bcf2a89
Compare
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 free
to 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.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@gemstack/the-framework@2.0.0
Major Changes
b2d23ed: Rename the package from
@gemstack/frameworkto@gemstack/the-framework, and the CLI command fromframeworktothe-framework(Rename packagethe-framework#1071), for consistency with the product name The Framework.This is a breaking change: update installs to
@gemstack/the-frameworkand invocations tothe-framework. The old@gemstack/frameworkpackage will be deprecated on npm with a pointer to the new name.Minor Changes
61451a1: Dashboard: the session page says its branch once. The handoff card that repeated the branch name under the action bar is gone; its verdict ("2 commits · 0 files", "no changes", "branch gone") and its Push branch / Open PR buttons now ride in the branch row itself, and clicking that row expands the commits and changed files. A live session's Changes panel folds into the same row: the file count sits beside the branch, the rows open underneath.
ecf2ce4: feat(framework): context fragment lists the recorded conversations (Update Context prompt fragment #683)
Adds
.the-framework/conversations/**.mdtoCONTEXT_DOCS, so a run is told to read the human conversations (Discord/chat turns) that earlier runs committed there. A read-only pointer, liketickets/andTODO_AGENTS.md, so it stays out of the merge-update set. The path is pinned by a test to the canonicalTHE_FRAMEWORK_DIR/CONVERSATIONS_DIRconstants so it cannot drift from where runs actually commit.053db85: feat(framework): context fragment points the knowledge base at a
knowledge-base/folder (Update Context prompt fragment #683)Splits the flat
KNOWLEDGE-BASE.mdintoknowledge-base/FACTS.mdandknowledge-base/INSIGHTS.md, and movesDECISIONS.mdandMARKET_RESEARCH.mdunderknowledge-base/, with aknowledge-base/**.mdcatch-all. The on-before-mergeable prompt and the Market research preset name the same paths.7c70533: Dashboard: the session log reads like a conversation. Your prompt is its own
YOUrow and the agent's turn isAGENT, so a message is no longer echoed twice — the redundantYou: …log line is gone and the first prompt and every follow-up now read the same way.Both your prompts and the agent's replies render as Markdown (headings, bold, lists, code, links), at the log's own density. A short message renders inline; a long one collapses to its first line with a chevron and expands in place on click, so the log stays scannable without hiding the text.
Also: the sessions rail's home row is now "New session" (a launcher) instead of "Live", and a session's id is always offered for copy in the toolbar (the exact string
--resumetakes), beside the existing copy-branch action.a1552ac: feat(framework): remote-daemon lane, non-loopback bind guarded by a shared token (Remote-daemon lane: non-loopback bind + shared token (atomic) #1051)
framework --daemon --host <addr>binds the dashboard daemon to a non-loopback address so a device you own can reach it. Because a daemon that spawns processes is code execution for anyone who finds the port, a non-loopback bind generates and persists a shared token (crypto.randomBytes(32), a top-levelRegistry.daemonToken, never a preference and never shipped to the browser bundle), and one guard fronts every route (static bundle,/_telefunc,/browser): a request needs a validfw_daemoncookie or a matching?token=, else 401, compared withcrypto.timingSafeEqual. A valid?token=sets anHttpOnly; SameSite=Strictcookie and 302s to the clean path, so one cookie rides the RPC, the live-events Channel, and the MJPEG screencast alike. A loopback bind generates nothing and the guard is a no-op, so the local zero-config path is byte-identical. The CLI prints a loud warning and the token URL on any non-loopback bind. Composes with (does not replace) the existing CSRF origin check.3166507: Devices: online/offline status and remove-device in the "Run on" gear (Devices: persist the pairing, show online/offline status, and allow removing a device #1072).
Each saved-device row in the gear gains a remove (X) control that drops the device; if the removed device was the selected run target, the selection clears back to a driver target. The gear device rows and the connection indicator now show a green (online) / grey (offline) reachability dot, and an offline row is muted and labelled. The device tokens stay browser-side (per Client connection profiles + "a device I have" in the gear #1052), so the browser hands the local daemon each device's {url, token} and the daemon does a cookie'd
GET /_relay/pingto report reachable or not; a short client poll drives the dots. The new ping endpoint is cookie-guarded (401 without) and starts nothing.969b9bb: Dashboard launcher and rail UX pass:
f20add1: Dashboard: the session view holds still. A run ending used to swap the whole page for a different one — the action bar blanked, the output was replaced by "Loading session…", the run overview disappeared and the composer was rebuilt. Live and finished are now the same view, so only what the bar, feed and composer say changes. The action bar is one row at any width (the branch truncates, the least important facts drop out, the buttons never wrap under it), and the composer no longer vanishes on a session that ended without a resumable id: it stays and starts a new session instead.
85c5f73: Onboarding checklist and a settings page (Onboarding #958).
The Overview gains an Onboarding section: add a project (one click for the directory the server runs in), fill the AI task queue, fill
tickets/(with an "Import tickets from GitHub" button), add the Discord bot, turn on browser notifications, and add Discord notifications. Every step's done-state is derived from a real fact (a registered project, a non-empty queue, a ticket on disk, a granted browser permission, credentials the daemon holds), so a step cannot be ticked by clicking it, and one done outside the dashboard shows up done. It can be dismissed, which hides it only on the Overview.Settings now have a page of their own at
/settings, reachable from the header, collecting what was spread across the header menus: appearance and editor, agent / model / run-on, run options, eco, notifications, and automation. The Onboarding checklist lives there too and is not dismissible, which is what dismissing it on the Overview points you to.Supporting changes:
onDashboard's per-project rollup carrieshasTickets, a newonOnboardingread offers the server's working directory as a first project (gated on the same wiring as adding projects, so a public host discloses nothing), andonboardingDismissedjoins the preferences.d3cd883: Custom presets can now be saved to a project, not just to you. When you create a preset with a project open, a "Save to" choice lets you keep it private (as before) or commit it into the repo's
.the-framework/custom-presets.json, so everyone who clones the project gets it. Shared presets show up in their own "Project presets" group in the Presets menu and under/in the editor, and delete from there. Personal presets still live in your home config and follow you across every project.30e94f9: feat(framework): run a session on a connected device via a server-side relay (Run on: run a session on a connected device without leaving the dashboard (remote-run relay) #1067, slice 1)
Picking a saved device in the "Run on" gear now makes it a true run target: you stay on this dashboard, submit, and the session runs on the remote device and streams its events back into the current run view. A device row no longer navigates the browser; it selects the device in place (the token stays a per-browser secret, memory-only, never persisted).
Under the hood the local daemon relays the run: it POSTs the run to the remote daemon's new
/_relay/start(authenticating with the device token as thefw_daemoncookie, no Origin) and fetch-streams the remote's/_relay/eventsback into the local run view over the normal same-origin channel. The browser never talks cross-origin and the token never leaves the two daemons. Both/_relay/*endpoints are fronted by the same Remote-daemon lane: non-loopback bind + shared token (atomic) #1051 token guard.Slice 1 is submit + live events. The remote run executes in the device's own home checkout, and the diff, PR, push/handoff, and browser screencast panels show a "not available for remote runs yet" placeholder; those (and per-project remote targeting) land in later slices.
38ef437: A run started on a connected device is now a true peer: its file reads, diffs, git status, worktree, run-handoff, live steering, and push/open-PR all work by relaying each run-scoped RPC to the device over the Remote-daemon lane: non-loopback bind + shared token (atomic) #1051 token cookie, keyed by a durable per-run marker on the local daemon; push and PR run on the device's own checkout. The run view's diff and handoff panels are no longer suppressed for remote runs (Run on: run a session on a connected device without leaving the dashboard (remote-run relay) #1067, slice 2). The browser preview stays local-only for now (slice 3).
1c8d520: A run relayed to a connected device (Run on: run a session on a connected device without leaving the dashboard (remote-run relay) #1067) now appears in the local project's session list and re-opens after a dashboard reload, instead of showing "This session is gone". The local daemon keeps a lightweight in-memory RunMeta for each relayed run (target 'remote', the device label, a status that flips when the relay stream ends) and merges it into the run list; the event backlog already survives via the daemon-side stream (Run on: a remote run should survive a dashboard reload (show in the local session list) #1077).
3bc2a2e: Make a remote run's session-list row accurate and legible (Run on: run a session on a connected device without leaving the dashboard (remote-run relay) #1067). The local in-memory stub for a relayed run now folds every streamed event through the store's own reducer, so it mirrors the device: it shows WAITING while the run is parked on you (not a permanent RUNNING), settles to the right terminal status, and picks up the agent logo and any pending-choice state. The row also gets a small device glyph (with the device name on hover) so a session running on a connected device is distinguishable at a glance from a local one.
df6ac36: Run target: wire GitHub Actions into the "Run on" gear (Run target: wire GitHub Actions into the "Run on" gear selector (driver axis) #1050). The options gear gains a single-select "Run on" submenu (Current device, the default; GitHub Actions; Claude web as a disabled placeholder), and picking GitHub Actions runs the turn on a fresh Actions runner via the already-merged ActionsDriver instead of on this device. The choice sticks per project like the agent and model. A new
--run-on <local|actions>flag drives it from the CLI;actionsreads the repo owner/repo from the origin remote and a user token fromGH_TOKEN(repo + workflow scopes).localis unchanged.9202800: Run-view polish for a GitHub Actions target (Run-view polish for non-local run targets (Actions burst-mode + remote) #1053). A run started with
--run-on actionsnow records its target on the run's meta, and the run view reads it: instead of an apparently-stalled live feed (the ActionsDriver replays its transcript in a burst at the end, on a fresh runner per turn), it shows a "running on GitHub Actions, updates arrive when the run finishes" affordance with a clickable link through to the live Actions run (from theaction/noticeevents the driver emits, which carry the run'shtml_url). The right rail's Browser pane is gated off for an Actions run, since there is no browser on the runner to screencast. A local or remote-device run is unchanged.c55dcca: Dashboard: a stopped session can be deleted. The sessions rail only ever grew — remove-worktree reclaimed a checkout on disk but kept the row, and nothing removed the record. Delete (a trash button beside Remove, which is now a folder-x icon so the two read apart) takes the session out of the dashboard: its run record and event log, and its worktree if one remains. It confirms first, because unlike remove-worktree the replayable history can't be recovered. It deliberately leaves the git branch and its commits, the committed
LOGS.mdline and the conversation record — deleting a branch that may carry merged work or an open PR is not something a trash icon should do silently. It refuses while a run is still going.3dd90eb: Dashboard: the session's branch row fills in about three times faster. It was waiting on a
gh pr view(≈574ms, against ~10ms for every git read beside it) that ran twice per session, on every navigation and every poll. That lookup is now read through a single-flight, stale-while-revalidate cache, and it no longer blocks the branch, dirty flag, size, commits or files — they render at git speed while the PR arrives behind them. Opening a PR invalidates the cached answer, and a lookup still in flight is reported as pending rather than as "no PR", so the Open PR button holds off instead of offering to open a second one.c2c5798: Dashboard: semantic status colours, a real Checkbox, a stable Sessions rail, and no emoji glyphs.
The status colours are now four tokens (
--success,--warning,--danger,--info) tuned pertheme, replacing every raw palette value. Before this, "good" was six different greens,
amber-500meant both "stopped" and "building, fine", and the flat
-500tones sat near 2:1 contrast on thelight canvas.
Checkboxes are a shadcn-style primitive on Base UI instead of bare
<input type="checkbox">, sothey follow the theme and carry the same focus ring as everything else.
The Sessions rail no longer collapses to a strip when the right rail opens the Browser or Views
tab; its width is now constant.
The ✅/❌/⚠️ glyphs in the Enhanced System Prompt disclosure are replaced by a status dot and plain
text, matching how every other state in the app is drawn.
Sessions rail rows now show which agent ran them, and lead with something that identifies the
session: the agent's own session name or its branch when there is no typed prompt, and the start
time when there is neither. They used to print a bold "(no prompt)" while the timestamp that
actually told them apart sat beside it in small muted text.
A clean git tree's dot is neutral rather than green. Green means "added / new / done" everywhere
else, so a green dot for "nothing changed" sat one pane from the file tree's green dot for "this
folder has changes".
Claude's logo is its own starburst rather than the Anthropic wordmark.
6e4eb69: Dashboard: the session toolbar leads with the session's name — the same label the rail shows (your prompt) — instead of the branch. The agent renames its branch near the end of a run, and with the branch as the headline that mutation read as the whole view changing; as muted git context beside a stable name, it no longer does. The shared
the-framework/prefix is dropped from the branch for legibility (the full name stays in the tooltip and copy). The branch summary also stops blanking for a beat when a run stops: it holds the last file counts until the handoff has loaded, so it swaps once instead of flashing empty. One line still, with the label truncating last and the branch, size and summary dropping out as the pane narrows.Patch Changes
9fd8951: Let the GitHub Actions run target (Run target: wire GitHub Actions into the "Run on" gear selector (driver axis) #1050) read back a run's work and continue on it (Actions run target: driver can't discover the branch the agent pushed (readCode + multi-turn continuity) #1085).
claude-code-action@v1leaves itsbranch_nameoutput empty for aworkflow_dispatchagent run, so the driver never learned the branch the agent pushed:readCodefailed and a follow-up turn started over onmain. The driver now names the branch itself (claude/framework-<session>) and passes it to the workflow, which pushes the run's work there and records it, so the diff view works and each turn builds on the last.c6548ca: Give each GitHub Actions run (
--run-on actions, Run target: wire GitHub Actions into the "Run on" gear selector (driver axis) #1050) a correlation id that is unique across driver processes. The id seeded a per-process counter, so a freshframework runprocess restarted it at 1 and every run's first turn wasactions-1-turn-1; a new run could then match an earlier, identically named run still in the recent-runs window and report its stale result. The session id now mixes in a random tag, so a run only ever finds its own workflow run.6740853: Never silently downgrade a run into your own checkout when its worktree could not be created (fix(framework): one 10s timeout covers every git op, and a timed-out 'worktree add' silently drops the run into the user's main checkout #997).
Every run gets its own git worktree (Per-worktree concurrency: allow multiple live runs per project #736) so the agent never edits the working tree you are sitting
in. When
git worktree addfailed, the daemon logged a line and ran the agent in the project's maincheckout instead, mixing its edits into your uncommitted work. That is reachable in normal use: on a
large repo
worktree addwrites a whole checkout and can outrun its budget and be killed.A project that is not a git repo still falls back to the main checkout, which is the supported
pre-Per-worktree concurrency: allow multiple live runs per project #736 behavior. A project that is a repo and whose
worktree addfailed now fails the Startinstead, and the dashboard shows why. A failed Start is recoverable by starting it again; a checkout
with agent edits mixed into it is not.
A
worktree addkilled mid-write leaves the partial checkout it had already written behind (gitdrops its own administrative entry on the way out, so
git worktree prunefinds nothing to do), sothat directory is now removed on the timeout path.
The fallback's log line also says which case it is: "is not a git repository, so it gets no
worktree" rather than a generic "no worktree" that read the same either way.
38bb24a:
gitTimeoutMs()no longer mistakes the value of a global git option for the subcommand, and aconversation commit that keeps failing now says why.
gitTimeoutMs()picked the subcommand by dropping every word that starts with-, which dropsthe flags but keeps the values of the global options that take one.
git -C /repo pushthereforeread as the subcommand
/repo, and the push silently got the 30s local-mutation budget instead ofits intended 120s network budget. The same held for
-c key=val,--git-dir,--work-tree,--namespaceand--exec-path. The leading global options are now skipped properly, value andall, so the real subcommand is what picks the budget. No call site in the package passes
-Ctoday, so no timeout that was already correct changes; this closes the trap before a future call
site falls into it.
gitTimeoutMs()'s signature is unchanged.The conversation committer logged only its successes.
commitConversations()returns a reasonwhen it declines or fails, and the poller dropped it, so a project whose commit failed every tick
re-queued itself forever while printing nothing at all. The reason is now logged, but on change
only: the first failure prints one line, and repeats of the same reason stay quiet until the
reason changes or the commit lands, so a stuck project cannot flood the daemon log one line per
poll window. The ordinary "no conversation changes" outcome is never reported as a failure.
fd8e13f: Stop a throwing onEvent listener from escaping a prompt run (runPrompt).
runFramework wraps each
opts.onEvent(event)call in a try/catch and logs-and-ignores a listenerthat throws, but runPrompt's emit did not. Because emit is called both inside and outside the run's
try block (the session-start and system-prompt events fire before it), an onEvent listener that threw
could escape runPrompt uncaught, or skip the run's
endevent. runPrompt now guards the listener thesame way, so a bad listener can no longer take the run down.
96f7b6d: Dashboard launcher polish. The run Context picker is now a dropdown that sits in the composer control row next to the presets button, instead of an inline section that pushed the form down. The options gear moved next to the model selector, before Send, and shows a small presence dot rather than a count. "Enhanced System Prompt" is now a dropdown too, sharing the "In play" row. Every menu trigger stays highlighted while its menu is open, and menus open toward the side with room. The prompt editor and all dropdowns now scroll through the shared thin overlay scrollbar, which also removes the doubled border/track the native bar left inside popups.
c9864a6: Dashboard: fix the Usage card's dividers rendering at full text brightness, and stop the
Overview cards stretching into empty space.
Tailwind v4 defaults an uncoloured
border-ttocurrentColor, so the three dividers in theUsage card painted at
oklch(0.95 0 0), the body text colour, against hairlines that areoklch(0.3 0.01 264)everywhere else in the app. They now use the border token.The two Overview card rows also stretched each card to its neighbour's height, so on a quiet
board half of "Session outcomes" and most of "Working now" were empty card. They are now two
column stacks that size to their content, which pairs the tall chart against the tall list and
brings the Projects table a full screen higher.
deb130e: Dashboard: the "New preset" form is now a centered modal dialog instead of a panel that pushed the composer controls down. Same fields (name, prompt, and the "Save to" scope choice); a backdrop click, Esc, or the close button dismisses it. Adds a reusable shadcn-style
Dialogon Base UI for future forms.8a8cd75: Dashboard: make the
dark:utilities follow the theme toggle instead of the OS.Tailwind v4 compiles
dark:to@media (prefers-color-scheme: dark)unless a custom variantsays otherwise, but the dashboard's tokens live on the
.darkclass that LayoutDefault toggles.The two disagreed: picking Dark on a light OS applied the dark tokens while leaving every
dark:text-*rule unapplied, so diff counts, the stream-lost banner and the daemon-health bannerkept their light-mode colours on a dark canvas (and the reverse on a dark OS set to Light).
Declaring
@custom-variant darkbinds both to the same signal.decace4: Breaking (
@gemstack/ai-autopilot): the framework-detection exports are renamed so they nolonger collide with the user-facing domain presets.
Two unrelated subsystems were distinguished only by a directory's singular-vs-plural:
src/preset/(the Open Loop domain bundles,
{loops, prompts}) andsrc/presets/(framework detection). Bothwere re-exported side by side from the one entry point, so
definePresetandselectPresetreadlike a pair while being from different subsystems. "Preset" now means the user-facing domain bundle
only, which is what the shipped root
presets/markdown and the dashboard already meant by it.src/presets/moves tosrc/framework-detection/(internal), and the exports rename:definePresetdefineFrameworkPresetPresetFrameworkPresetPresetSpecFrameworkPresetSpecPresetSignalsFrameworkPresetSignalsPresetScoreFrameworkPresetScorePresetRegistryFrameworkPresetRegistryPresetErrorFrameworkPresetErrorbuiltinPresetsbuiltinFrameworkPresetsbuiltinPresetRegistrybuiltinFrameworkPresetRegistrydetectFramework,vikePreset,nextPreset,FrameworkSignalsandFrameworkDetectionareunchanged: they were already unambiguous. The domain-preset exports (
defineDomainPreset,selectPreset,composeDomainPresets,loadDomainPreset,builtinDomainPresets,builtinPresetsDir, ...) are unchanged.No behavior change. As a side effect
@gemstack/ai-autopilotno longer exports adefinePresetthat clashes with the unrelated
definePresetin@gemstack/the-framework.ca48f85: Fix a remote run vanishing from the session list on a dashboard reload ("This session is gone").
onRunsread the relayed-run stubs throughcontextRemote()after two awaits, but telefunc only exposesgetContext()synchronously at the top of a telefunction, so the call threw and every remote run was silently dropped from the list. The context is now read before the first await, so a relayed run stays in the list and re-opens after a reload as Run on: a remote run should survive a dashboard reload (show in the local session list) #1077 intended.6601c44: fix(framework): set the daemon token cookie SameSite=Lax so the "a device I have" connection hop works
The non-loopback bind guard (Remote-daemon lane: non-loopback bind + shared token (atomic) #1051) set the fw_daemon cookie SameSite=Strict. Connecting to a saved device (Client connection profiles + "a device I have" in the gear #1052) is a cross-origin top-level navigation, and a Strict cookie set during that navigation is withheld by the browser on the immediate redirect to the clean path, so the device connect landed on a 401. Lax still rides top-level GET navigations, and CSRF protection is unchanged (the same-origin check still fronts /_telefunc).
ef4f007: Dashboard: the session log labels each row with a plain word instead of its internal event name (Make the session-log labels self-explanatory (e.g. DRIVER) #1035). The badge used to show the raw event kind, so a turn of the AI read
DRIVER, the paused state readSETTLED, and the spend row readUSAGE. These now readAGENT,WAITING, andCOST, and the resume-link row readsRESUME. Kinds that were already clear are unchanged.8154e20: Dashboard: widen the session-log badge column so "SYSTEM PROMPT" fits on one line. The badge column was narrow enough that the one two-word label wrapped to two lines; the column now fits it (measured at 106px, column is 112px).
Updated dependencies [decace4]
@gemstack/ai-autopilot@0.12.0
Minor Changes
decace4: Breaking (
@gemstack/ai-autopilot): the framework-detection exports are renamed so they nolonger collide with the user-facing domain presets.
Two unrelated subsystems were distinguished only by a directory's singular-vs-plural:
src/preset/(the Open Loop domain bundles,
{loops, prompts}) andsrc/presets/(framework detection). Bothwere re-exported side by side from the one entry point, so
definePresetandselectPresetreadlike a pair while being from different subsystems. "Preset" now means the user-facing domain bundle
only, which is what the shipped root
presets/markdown and the dashboard already meant by it.src/presets/moves tosrc/framework-detection/(internal), and the exports rename:definePresetdefineFrameworkPresetPresetFrameworkPresetPresetSpecFrameworkPresetSpecPresetSignalsFrameworkPresetSignalsPresetScoreFrameworkPresetScorePresetRegistryFrameworkPresetRegistryPresetErrorFrameworkPresetErrorbuiltinPresetsbuiltinFrameworkPresetsbuiltinPresetRegistrybuiltinFrameworkPresetRegistrydetectFramework,vikePreset,nextPreset,FrameworkSignalsandFrameworkDetectionareunchanged: they were already unambiguous. The domain-preset exports (
defineDomainPreset,selectPreset,composeDomainPresets,loadDomainPreset,builtinDomainPresets,builtinPresetsDir, ...) are unchanged.No behavior change. As a side effect
@gemstack/ai-autopilotno longer exports adefinePresetthat clashes with the unrelated
definePresetin@gemstack/the-framework.Patch Changes
@gemstack/mcp@0.5.0
Minor Changes
9258b84: Remove the dead
Mcpserver registry and correct the docs to the real mounting API.@gemstack/mcpexportedMcp.web()/Mcp.local()/Mcp.getWebServers()/Mcp.getLocalServers(), backed by a store on the__gemstack_mcp_servers__global. Nothing in the repo ever read that store: no package, no example, no runtime path. Six README and docs pages nevertheless presentedMcp.web(path, ServerClass)as the way to mount a server, so anyone following them registered into a map nobody read, got no error, and got no working endpoint.Removed:
Mcp,McpWebEntry,McpWebBuilder, and the global store. The real, already-working mounts are unchanged:createMcpHttpHandler(server)for rawnode:http/ Express / Connect (main entry),createWebRequestHandler(server)for Fetch-style hosts andstartStdio(server)for stdio (both from@gemstack/mcp/runtime). Note the shape difference the old docs hid: these take a server instance, not a class.@gemstack/mcptakes a minor rather than a major: it is pre-1.0, where a breaking removal is conventionally a minor, and no working code can be relying on the removed surface since nothing ever consumed it. The connector packages take a patch: their published READMEs (and, for@gemstack/mcp-connectors, themountConnectorsJSDoc that ships in its.d.ts) carried the false mount snippet, so the corrected text is worth a release.@gemstack/ai-sdk@0.6.1
Patch Changes
cd121f4: fix(ai-sdk): a store whose unscoped
list()hides other users' threads no longer fails open on resume-by-idThe ai-sdk: a conversation id is loaded and appended to without any owner check #984 owner check settles ownership from
ConversationStoreListEntry.userId, falling back to an unscopedstore.list()when the caller's scoped listing does not hold the thread. A thread missing from that unscoped listing was read as "no owner recorded" and allowed, which is right for a pre-ai-sdk: a conversation id is loaded and appended to without any owner check #984 ownerless row but wrong for a store whoselist()with no user id returns nothing. Such a store implementslist(userId)correctly and is fully owner-aware, and a cross-user resume was still allowed.The unscoped listing reporting nothing at all, while the store demonstrably holds rows (the caller has threads of their own, or the target thread has messages), now proves the listing is not enumerating the backend, and the resume is refused with
ConversationOwnershipError.Deliberately unchanged: a listing that reports rows but not this one stays permissive, since an absent thread and a partial listing are indistinguishable there. Ownerless legacy threads on a store that enumerates normally stay resumable, with or without a user on the run, and a store that omits
userIdfrom its entries keeps its old permissive behavior.ConversationStoregains no members. The listing contract the check depends on is now documented on the interface itself, where an implementer sees it, rather than only on the entry type'suserIdfield.780ef3e: Internal: the provider layer no longer carries four copies of the same code. Every adapter builds its SDK client through one shared
lazyClient()helper, the five pure OpenAI-compatible providers (xai,groq,deepseek,ollama,azure) come from one factory, and the Anthropic stream-event mapping is shared with Bedrock instead of being inlined twice.Two side effects worth naming. A first client build is now memoised as a promise, so two concurrent calls share one client rather than racing to construct two, and a failed dynamic import no longer caches. And
XaiProvider.nameand friends are typedstringrather than the literal'xai', matching theProviderFactorycontract they are consumed through.All public exports keep their names, constructor signatures, and default base URLs.
23c1fb7:
CachedSubAgentRunStore.load()now returnsnull(notundefined) when aCacheAdapterresolvesundefinedon a miss, matchingCachedAgentRunStore.load(). TheCacheAdaptercontract already declaresPromise<T | null>, so adapters that honour it are unaffected; adapters that resolveundefinednow get the documentednull.Internal: both run-store families now share one storage implementation. All public exports (
InMemoryAgentRunStore,CachedAgentRunStore,newAgentRunId,InMemorySubAgentRunStore,CachedSubAgentRunStoreand their types) keep the same shape.@gemstack/mcp-connector-github@0.2.2
Patch Changes
9258b84: Remove the dead
Mcpserver registry and correct the docs to the real mounting API.@gemstack/mcpexportedMcp.web()/Mcp.local()/Mcp.getWebServers()/Mcp.getLocalServers(), backed by a store on the__gemstack_mcp_servers__global. Nothing in the repo ever read that store: no package, no example, no runtime path. Six README and docs pages nevertheless presentedMcp.web(path, ServerClass)as the way to mount a server, so anyone following them registered into a map nobody read, got no error, and got no working endpoint.Removed:
Mcp,McpWebEntry,McpWebBuilder, and the global store. The real, already-working mounts are unchanged:createMcpHttpHandler(server)for rawnode:http/ Express / Connect (main entry),createWebRequestHandler(server)for Fetch-style hosts andstartStdio(server)for stdio (both from@gemstack/mcp/runtime). Note the shape difference the old docs hid: these take a server instance, not a class.@gemstack/mcptakes a minor rather than a major: it is pre-1.0, where a breaking removal is conventionally a minor, and no working code can be relying on the removed surface since nothing ever consumed it. The connector packages take a patch: their published READMEs (and, for@gemstack/mcp-connectors, themountConnectorsJSDoc that ships in its.d.ts) carried the false mount snippet, so the corrected text is worth a release.Updated dependencies [9258b84]
@gemstack/mcp-connector-google-drive@0.2.2
Patch Changes
9258b84: Remove the dead
Mcpserver registry and correct the docs to the real mounting API.@gemstack/mcpexportedMcp.web()/Mcp.local()/Mcp.getWebServers()/Mcp.getLocalServers(), backed by a store on the__gemstack_mcp_servers__global. Nothing in the repo ever read that store: no package, no example, no runtime path. Six README and docs pages nevertheless presentedMcp.web(path, ServerClass)as the way to mount a server, so anyone following them registered into a map nobody read, got no error, and got no working endpoint.Removed:
Mcp,McpWebEntry,McpWebBuilder, and the global store. The real, already-working mounts are unchanged:createMcpHttpHandler(server)for rawnode:http/ Express / Connect (main entry),createWebRequestHandler(server)for Fetch-style hosts andstartStdio(server)for stdio (both from@gemstack/mcp/runtime). Note the shape difference the old docs hid: these take a server instance, not a class.@gemstack/mcptakes a minor rather than a major: it is pre-1.0, where a breaking removal is conventionally a minor, and no working code can be relying on the removed surface since nothing ever consumed it. The connector packages take a patch: their published READMEs (and, for@gemstack/mcp-connectors, themountConnectorsJSDoc that ships in its.d.ts) carried the false mount snippet, so the corrected text is worth a release.Updated dependencies [9258b84]
@gemstack/mcp-connectors@0.2.2
Patch Changes
9258b84: Remove the dead
Mcpserver registry and correct the docs to the real mounting API.@gemstack/mcpexportedMcp.web()/Mcp.local()/Mcp.getWebServers()/Mcp.getLocalServers(), backed by a store on the__gemstack_mcp_servers__global. Nothing in the repo ever read that store: no package, no example, no runtime path. Six README and docs pages nevertheless presentedMcp.web(path, ServerClass)as the way to mount a server, so anyone following them registered into a map nobody read, got no error, and got no working endpoint.Removed:
Mcp,McpWebEntry,McpWebBuilder, and the global store. The real, already-working mounts are unchanged:createMcpHttpHandler(server)for rawnode:http/ Express / Connect (main entry),createWebRequestHandler(server)for Fetch-style hosts andstartStdio(server)for stdio (both from@gemstack/mcp/runtime). Note the shape difference the old docs hid: these take a server instance, not a class.@gemstack/mcptakes a minor rather than a major: it is pre-1.0, where a breaking removal is conventionally a minor, and no working code can be relying on the removed surface since nothing ever consumed it. The connector packages take a patch: their published READMEs (and, for@gemstack/mcp-connectors, themountConnectorsJSDoc that ships in its.d.ts) carried the false mount snippet, so the corrected text is worth a release.Updated dependencies [9258b84]
@gemstack/framework-dashboard@0.3.0
Minor Changes
3e02886: Client connection profiles + "a device I have" in the gear (Client connection profiles + "a device I have" in the gear #1052). The "Run on" submenu gains an "A device I have" section: Local (this machine's own daemon), your saved daemons, and "Add a device". These rows diverge from the driver rows above them: a driver row writes a preference, a device row NAVIGATES the browser to that daemon's origin carrying its token, where the same-origin bootstrap re-authenticates from the cookie it sets. "Add a device" takes the full
http://host:port/?token=…URL a box prints on its network bind (any reachable host: LAN IP, tailnet name, tunnel URL), parsing the origin and token out of one paste. Profiles live in per-browser localStorage, so the token never reaches the daemon's registry file. A "connected to " indicator in the header shows which daemon the dashboard is talking to.3166507: Devices: online/offline status and remove-device in the "Run on" gear (Devices: persist the pairing, show online/offline status, and allow removing a device #1072).
Each saved-device row in the gear gains a remove (X) control that drops the device; if the removed device was the selected run target, the selection clears back to a driver target. The gear device rows and the connection indicator now show a green (online) / grey (offline) reachability dot, and an offline row is muted and labelled. The device tokens stay browser-side (per Client connection profiles + "a device I have" in the gear #1052), so the browser hands the local daemon each device's {url, token} and the daemon does a cookie'd
GET /_relay/pingto report reachable or not; a short client poll drives the dots. The new ping endpoint is cookie-guarded (401 without) and starts nothing.51fca19: Block Start when the selected "Run on" device is offline. When the run target is a saved device whose live status (from Devices: persist the pairing, show online/offline status, and allow removing a device #1072) is offline, the submit button is disabled and a note asks you to pick another target in the "Run on" gear. Pressing Start no longer silently attempts the slow relay, and the target is never switched automatically (Run on: block starting on an offline device and make the user pick another target (no auto-fallback) #1073). An unknown or still-checking status does not block.
30e94f9: feat(framework): run a session on a connected device via a server-side relay (Run on: run a session on a connected device without leaving the dashboard (remote-run relay) #1067, slice 1)
Picking a saved device in the "Run on" gear now makes it a true run target: you stay on this dashboard, submit, and the session runs on the remote device and streams its events back into the current run view. A device row no longer navigates the browser; it selects the device in place (the token stays a per-browser secret, memory-only, never persisted).
Under the hood the local daemon relays the run: it POSTs the run to the remote daemon's new
/_relay/start(authenticating with the device token as thefw_daemoncookie, no Origin) and fetch-streams the remote's/_relay/eventsback into the local run view over the normal same-origin channel. The browser never talks cross-origin and the token never leaves the two daemons. Both/_relay/*endpoints are fronted by the same Remote-daemon lane: non-loopback bind + shared token (atomic) #1051 token guard.Slice 1 is submit + live events. The remote run executes in the device's own home checkout, and the diff, PR, push/handoff, and browser screencast panels show a "not available for remote runs yet" placeholder; those (and per-project remote targeting) land in later slices.
38ef437: A run started on a connected device is now a true peer: its file reads, diffs, git status, worktree, run-handoff, live steering, and push/open-PR all work by relaying each run-scoped RPC to the device over the Remote-daemon lane: non-loopback bind + shared token (atomic) #1051 token cookie, keyed by a durable per-run marker on the local daemon; push and PR run on the device's own checkout. The run view's diff and handoff panels are no longer suppressed for remote runs (Run on: run a session on a connected device without leaving the dashboard (remote-run relay) #1067, slice 2). The browser preview stays local-only for now (slice 3).
1c8d520: A run relayed to a connected device (Run on: run a session on a connected device without leaving the dashboard (remote-run relay) #1067) now appears in the local project's session list and re-opens after a dashboard reload, instead of showing "This session is gone". The local daemon keeps a lightweight in-memory RunMeta for each relayed run (target 'remote', the device label, a status that flips when the relay stream ends) and merges it into the run list; the event backlog already survives via the daemon-side stream (Run on: a remote run should survive a dashboard reload (show in the local session list) #1077).
3bc2a2e: Make a remote run's session-list row accurate and legible (Run on: run a session on a connected device without leaving the dashboard (remote-run relay) #1067). The local in-memory stub for a relayed run now folds every streamed event through the store's own reducer, so it mirrors the device: it shows WAITING while the run is parked on you (not a permanent RUNNING), settles to the right terminal status, and picks up the agent logo and any pending-choice state. The row also gets a small device glyph (with the device name on hover) so a session running on a connected device is distinguishable at a glance from a local one.
53cd77d: Flatten the "Run on" picker into one list and preserve the composer draft across a device hop (Run on: unify the execution-target picker into one flat list (drop redundant Local, don't lose the prompt) #1066). The gear's "Run on" submenu was two axes stacked as one confusing list: driver rows (where a run executes) plus a separate "A device I have" section (which daemon the dashboard talks to), which also duplicated "Local" with "Current device". It is now a single flat list: This machine / GitHub Actions / Claude web (coming soon) / your saved devices / Add a device, with exactly one checkmark. On the local daemon the checkmark tracks the driver target; connected to a device it sits on that device, and clicking "This machine" goes home instead of writing a driver preference. Switching devices no longer nukes the typed prompt: the connect hop carries the draft alongside the token, the remote SPA moves it out of the URL into sessionStorage at boot (so it never sits in the address bar, history, or a Referer), and the launcher rehydrates it. Oversize drafts fall back to a plain connect so a huge paste can't blow the URL length.
9202800: Run-view polish for a GitHub Actions target (Run-view polish for non-local run targets (Actions burst-mode + remote) #1053). A run started with
--run-on actionsnow records its target on the run's meta, and the run view reads it: instead of an apparently-stalled live feed (the ActionsDriver replays its transcript in a burst at the end, on a fresh runner per turn), it shows a "running on GitHub Actions, updates arrive when the run finishes" affordance with a clickable link through to the live Actions run (from theaction/noticeevents the driver emits, which carry the run'shtml_url). The right rail's Browser pane is gated off for an Actions run, since there is no browser on the runner to screencast. A local or remote-device run is unchanged.Patch Changes
@gemstack/example-autopilot-quickstart@0.0.12
Patch Changes
@gemstack/example-bootstrap-quickstart@0.0.12
Patch Changes
@gemstack/example-connectors-quickstart@0.0.4
Patch Changes
@gemstack/example-framework-demo@0.0.9
Patch Changes
@gemstack/example-mcp-quickstart@0.0.3
Patch Changes