Skip to content

Releases: matthewratcliffe/devstudio

devStudio 1.0.191

Choose a tag to compare

@github-actions github-actions released this 16 Sep 23:27
123b3bd
Agent plugin selection, and the editor ticks that go with it (#57)

* Show an agent's saved skills and MCP servers when the editor opens

The two tick lists are built from the config of the machine the agent runs
on, and that config was fetched after the editor was already on screen. The
first render therefore drew both sections against an empty list, and the
ticks an agent had saved never appeared — so every visit looked like the
selection had been lost, and re-ticking wrote back what was already there.

The config is now fetched before the editor is shown, so those sections are
built once, from the real list. The checkboxes bind through @bind:get/set
with a key per skill and server, which keeps a row's state tied to the row
it belongs to rather than to its position.

Two neighbouring losses, found while confirming that one: the working copy
the editor edits was dropping the agent's category, the machine it runs on,
and its quick-chat and team-file markers, so opening an agent to change one
field quietly moved it back to this machine and out of its category. And
re-picking the machine an agent was already on cleared its repository,
login, skills and servers, which is only right when the machine changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVM6yGQKPGp6QEQ2rUf5ia

* Let an agent choose which of a CLI's plugins its sessions run

Plugins are installed by the CLI that runs them, so devStudio reads what
claude, codex and opencode each recorded for themselves rather than keeping
a second list that would only ever be one install behind. What it owns is
which of them an agent uses: everything installed and not ticked is written
out as off, or a plugin somebody enabled globally rides along with every
agent and what an agent can do depends on the machine rather than on its
own definition.

Each CLI is then told in its own language, for that run only, so no login's
configuration is rewritten: claude gets a settings file through --settings,
codex a -c plugins."name@marketplace".enabled override, opencode the plugin
array of the workspace config its server reads for that directory.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Matt Ratcliffe <m.ratcliffe@htrak.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

devStudio 1.0.188

Choose a tag to compare

@github-actions github-actions released this 05 Sep 04:52
58146a2
Show an agent's saved skills and MCP servers when the editor opens (#56)

The two tick lists are built from the config of the machine the agent runs
on, and that config was fetched after the editor was already on screen. The
first render therefore drew both sections against an empty list, and the
ticks an agent had saved never appeared — so every visit looked like the
selection had been lost, and re-ticking wrote back what was already there.

The config is now fetched before the editor is shown, so those sections are
built once, from the real list. The checkboxes bind through @bind:get/set
with a key per skill and server, which keeps a row's state tied to the row
it belongs to rather than to its position.

Two neighbouring losses, found while confirming that one: the working copy
the editor edits was dropping the agent's category, the machine it runs on,
and its quick-chat and team-file markers, so opening an agent to change one
field quietly moved it back to this machine and out of its category. And
re-picking the machine an agent was already on cleared its repository,
login, skills and servers, which is only right when the machine changes.


Claude-Session: https://claude.ai/code/session_01BVM6yGQKPGp6QEQ2rUf5ia

Co-authored-by: Matt Ratcliffe <m.ratcliffe@htrak.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

devStudio 1.0.185

Choose a tag to compare

@github-actions github-actions released this 04 Sep 04:52
Set a credential once, and let every CLI the app launches see it

A token pasted against one MCP server reaches that one process and nothing
else — not the skills the CLI runs, not its hooks, not its other servers. The
only way to share one was to copy it onto every agent that might reach for it.

Global settings now carry a list of environment variables handed to every AI
CLI this install launches, and so to everything those CLIs spawn as children.
Each variable can be switched off without losing its value, and each decides
for itself whether it may travel to a remote instance — off by default, because
sending a secret to another machine is a decision somebody makes rather than a
side effect of setting one. A remote applies its own shared environment
underneath anything that arrives, so the usual answer is to set it over there.

Shared variables are the weakest layer: they go down first, under each
adapter's own HOME and account selection, then the CLI definition, the agent,
and the turn. A stray HOME row in Settings therefore cannot point a turn at
somebody else's login.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

devStudio 1.0.184

Choose a tag to compare

@github-actions github-actions released this 04 Sep 04:09
Take "This machine" literally, and show what is running on the others

The Runs on picker on the new-session page read This machine while a session
started there went to whatever the agent was pinned to: the null it sends meant
"unset", and the agent's own instance filled the gap. A dropdown that names a
machine has to be the machine it names, so the request now says whether its null
was picked or merely left out, and a picked one wins over the agent. Callers with
no picker behind them pass nothing and still follow the agent, as queues,
schedules and workflows do.

The other half is being able to see the work once it has gone. A remote session's
CLI is over there but its transcript is here, so each instance card now lists what
is running on it and every row opens the conversation, with the same list on the
dashboard as a Remote tasks in progress card - shown only where a remote exists,
since an empty panel on a single-machine install is worse than none.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

devStudio 1.0.183

Choose a tag to compare

@github-actions github-actions released this 04 Sep 01:33
Launch npm CLIs on Windows via their .cmd shim, not the POSIX one

ResolveExecutable searched PATH with the bare name before any PATHEXT
extension, so it matched npm's extensionless shell shim (e.g.
%APPDATA%\npm\claude) and CreateProcess refused it: "not a valid
application for this OS platform". Try PATHEXT candidates first and the
bare name last, matching WindowsCommandLine.Resolve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBDPfVz4e5Qt7nicWfUxJj

devStudio 1.0.182

Choose a tag to compare

@github-actions github-actions released this 04 Sep 00:38
fef93bb
Stop the file library losing files while it publishes them (#55)

Saving a library file published it in two steps: move the current file aside to
a .bak, then move the new one into place. Between those the file did not exist
at its own name. It also did that work inside the published folder — the same
folder copied wholesale into every agent workspace before a session starts.

The standards sync then rewrote all of its files on every run, and it runs on a
timer and again before each session, so that window was opening constantly.

In one operator's log this cost 342 failed stagings: 300 were half-written
working files being copied into workspaces as though they were reference
material, and 42 were real standards files that never arrived at all. Those
sessions ran without the standards they were meant to have, and the only thing
that said so was a warning nobody reads.

File.Replace looked like the answer and is not: a test reproducing the race
still found the file missing on roughly half of all reads, and checking
File.Exists alongside the directory listing showed it genuinely unlinked rather
than merely missed by enumeration — File.Replace is itself a two-step rename.
An overwriting File.Move holds the name throughout; measured over ten thousand
concurrent reads it never went missing once. It can fail outright when a reader
has the file open, which is the right trade: a visible, retryable failure beats
a file that silently is not there. It retries briefly.

So: staging moved to a sibling folder, so the published folder only ever holds
real files and no reader needs to know the convention; publishing is a single
overwriting move, with a copy-based backup so the published file is never taken
away to make one; and the sync skips files whose bytes have not changed —
compared by content rather than timestamps, because a fresh checkout rewrites
mtimes without changing anything. That last one was the amplifier.

"Nothing to import" now distinguishes an empty folder from one that simply has
not changed, which previously read as though the standards had gone missing.


Claude-Session: https://claude.ai/code/session_01JwMfdZjqLyrBMgVab8P8b6

Co-authored-by: Matt Ratcliffe <m.ratcliffe@htrak.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

devStudio 1.0.179

Choose a tag to compare

@github-actions github-actions released this 03 Sep 23:44
bac0007
Add remote instances, so one devStudio can run work on another (#54)

Introduces IExecutionHost: the machine a session's work happens on. Everything
on it is filesystem- or process-bound — the CLI registry, workspace service,
account service, workspace files and terminal — which is exactly the set of
things that stops being true when the work moves elsewhere.

LocalExecutionHost returns the services that were already registered, so the
local path is unchanged and remoting is the special case. RemoteExecutionHost
returns proxies that turn each call into a SignalR invocation, and the hub on
the far side hands them to its own ordinary services — the same ones its UI
uses, so there is no separate "remote mode" to drift.

The session, its transcript, the agent, the project and the queue that
dispatched it all stay local, so there is still one place you look for your
conversations. What travels is the CLI process, the login it runs as, the
checkout and the workspace.

Transport is SignalR at /hubs/remote. A turn is a stream — the events a CLI
produces arrive over a minute or several — so a hub method returning
IAsyncEnumerable<AgentEvent> maps straight onto IProviderCli.RunTurnAsync and a
remote transcript fills in as the work happens rather than arriving all at once.

Pairing is asked for on one side and granted on the other: a request lodges as
pending with a six-digit code and a notification, somebody approves it, and a
five-year JWT is issued. Long on purpose — this pairs two machines the same
person owns, and what ends it is revocation rather than the calendar. The grant
is checked on every call, so revoking takes effect on the far side's next
request despite the expiry.

Choosing an instance reloads every dependent dropdown, because a repository id,
a login, a skill and an MCP server all name something on one particular machine.
One GetConfig call answers for both local and remote, so the two share a path.

Also carries a WorkspacePlan seam through IWorkspaceService: the project's
contribution — repository, base branch and uploaded files, contents and all — is
resolved locally and carried across, because over there the project does not
exist. Local and remote then run the same build.

Two faults found while driving this between two live instances:
UseStatusCodePagesWithReExecute turned the empty 401s from the remote endpoints
into sign-in redirects, which the far side follows instead of noticing its
access was withdrawn; and StreamTerminal read IsRunning twice, so a process
exiting between the send and the check ended the stream after a frame claiming
it was still going, leaving the caller with no exit code.


Claude-Session: https://claude.ai/code/session_01JwMfdZjqLyrBMgVab8P8b6

Co-authored-by: Matt Ratcliffe <m.ratcliffe@htrak.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

devStudio 1.0.176

Choose a tag to compare

@github-actions github-actions released this 20 Aug 07:23
30bbbef
v1.0.176

Show real tool call descriptions, add thinking effort and context-lim…

devStudio 1.0.173

Choose a tag to compare

@github-actions github-actions released this 20 Aug 06:24
3c60e03
Answer opencode permission prompts and add slash command support (#52)

Opencode's HTTP API never answered its own permission.asked events, so
any tool call that needed approval left the turn hanging forever
regardless of the session's permission mode. Now it replies via
POST permission/{id}/reply based on PermissionMode, matching how
AcpCli handles the same decision for ACP-driven providers.

Also wires up opencode's server-side slash commands: a leading
"/name args" prompt is matched against the live command list and
routed through session/{id}/command instead of the plain message
endpoint, and the command list is fetched live for UI autocomplete
in Chat and QuickChat.


Claude-Session: https://claude.ai/code/session_01BuN546g4FftKu675fu9spD

Co-authored-by: Matt Ratcliffe <m.ratcliffe@htrak.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

devStudio 1.0.170

Choose a tag to compare

@github-actions github-actions released this 20 Aug 05:53
74bb0d8
v1.0.170

Merge pull request #51 from matthewratcliffe/fix/standards-recursive-…