* Hide projects from the sidebar without stopping them
Adds Repo.hiddenAt, a per-host, view-only flag. A hidden project's
workspaces, empty header and project-filter entry leave the desktop
sidebar, the paired phone's list, the new-workspace picker and the
palette's project filter. Its terminals, agents and automations keep
running, and repo.list / worktree.ps still list it.
- Hide Project in the project menu (toast with Undo), a collapsed
"N hidden projects" list under the workspace list with Show buttons,
and a Hide from sidebar switch in Settings > Projects.
- repo.setHidden RPC ({repo, repoHostId?, hidden} -> {repo, hostId,
hidden}) and `orca repo hide|unhide [--host]`; `repo list` marks
hidden rows.
- Opening a hidden project's workspace (notification, CLI, deep link)
focuses it without unhiding it, lifting sidebar filters, or leaving a
pending sidebar reveal.
- repo.update echo check: a host that drops hiddenAt reports failure
instead of reading as hidden.
* Address hidden-projects review: multi-host hide, picker scope, mute, stale filters, shared predicate, restore list styling
* Hidden projects re-review: keep saved filters, Agents filter, composer seed, per-toast Undo, shared default host
* Hidden projects: address review threads (pre-feed, palette search, notices, dialog default, seed remap, row keys, a11y)
* Hidden projects: no implicit dialog default when every project is hidden
* feat(plugins): host API 1.9: agent.listSessions (history:read), resume past sessions, agents.list task titles
* test(plugins): host API 1.9 coverage; regenerate plugin artifacts
* fix(plugins): host API 1.9 review fixes
- agent.resume starts a past session where the desktop's Resume would: the same preparation
request and answer handling (now shared), and the transcript in the home it pins
- AI Vault list cache keeps four scopes, so plugin reads never evict the panel's list
- list fingerprints ignore scan id and issues, so an unchanged history revalidates
- workspace mapping resolves symlinked workspaces and prefers a project over a folder
- agents.list task only for open dispatches, read at most once a second
- running matches OpenCode versions; history reads reset when the vault list is invalidated
- truncation, consent copy and limitations documented
* fix(plugins): forced history refresh supersedes cached scopes; resume legacy Codex sessions from their recorded transcript
* fix(plugins): address host API 1.9 review threads
- a scan that began before a forced history refresh no longer caches its older result
- list fingerprints count which issues there are (not their wording)
- symlinked workspaces rank by their resolved folder
- a session-only status row is no live pane: resume prepares the session
- a failed task-title read leaves agents.list rows intact
- the symlink test uses a junction on Windows
* test(ai-vault): order the stale scan before the forced refresh
* feat(plugins): proposed tier for host methods not yet frozen
A method spec may set `proposed: true`: only development plugins may call
it (others get not_permitted), and the minor, frame/worker method lists,
typings and skill references omit it. The reference renders such methods
in a separate Proposed section; dev workers' host.has answers for them.
* feat(plugins): param capabilities, host confirmations, automation provenance
- PluginHostMethodSpec.paramCapabilities: a passed param can require a
second capability; executePluginHostCall and the mock host refuse it with
capability_denied before any audit or effect, and the reference shows it.
- confirmPluginAction generalizes the external-open prompt into a host-owned
confirmation, exposed as PluginHostServices.confirm (desktop only; absent
in headless serve). It re-checks the plugin's approval after the answer.
- Automations record createdBy { kind: 'plugin', pluginKey, name }, set by
the runtime from the in-process plugin caller (RpcContext.plugin), never
from params; the Automations detail shows "Created by <plugin>".
* feat(plugins): workspace:create, automation:read and automation:write capabilities
New closed-enum kinds (older Orcas refuse such manifests with the engines
message), worker-only, with consent copy that names what each allows;
release floor PLUGIN_HOST_API_1_8_SINCE (1.4.259) joins
PLUGIN_SCHEMA_NEWEST_SINCE. agent:launch copy now says it also resumes.
* feat(plugins): host API 1.8 methods: workspace.create, agent.resume, automation.*
- workspace.create (workspace:create; agent also needs agent:launch): a
worktree in a Git project, as orca worktree create does; with agent, the
CLI's agent.launch create-worktree path, so the agent starts after setup.
Setup is skipped or follows the project's settings; never run, an
approved hash or a startup command.
- agent.resume (agent:launch): terminal.ensureAgentSession by session id;
started is false when a terminal already ran it. agents.list rows and
agent.status.changed carry sessionId.
- automation.list/create/update/delete (automation:read/write): create
forwards only name, prompt, agent, target, schedule, time zone and
enabled; update/delete of automations another plugin or the person made
ask the person first and report cancelled or consent-unavailable.
* test(plugins): host API 1.8 coverage; regenerate plugin artifacts
Covers param capabilities (host and mock host), workspace.create payloads
and refusals, agent.resume keys and adoption, sessionId on agents.list,
automation projection, forbidden create fields, confirmation outcomes,
runtime-set provenance and capability access growth. Regenerates the
reference, schemas, typings, declarative runtime and skill references.
* fix(plugins): host API 1.8 review fixes
- Confirmations spend the frame dialog budget, allow one question per
plugin at a time and pause after a refusal (rate_limited); a worker's
question shows in the focused window, else the first visible one.
- Changing what an automation with extra agent settings runs (prompt,
schedule, resuming) asks first even for its creator, showing the prompt.
- Removing, disabling or blocking a plugin pauses its automations and ends
its ownership (createdBy.endedAt), so neither re-enabling nor a reinstall
under the key resumes or edits them silently; the remove dialog says so.
- workspace.create and agent.resume record the terminals they return as
the plugin's own; a launch that fails after its worktree exists names it.
- Setup-decision refusals are told by the runtime's error class (kept as
the in-process RPC error's cause); generated names see every worktree
of the project; resume transcripts match the workspace and host.
- Created by shows the plugin id beside its name.
* fix(plugins): end automation ownership only on uninstall, disable or block
- The ownership sweep no longer reads discovery: only an uninstall
(announced by the removal path), the disabled list, the kill list or
the plugin-system switch end it, and only once the service is ready,
so an unreadable plugins folder pauses nothing. An install under the
same key after a removal keeps what it creates.
- A new time zone on an automation with extra agent settings asks first.
- A failed launch names only a new worktree made from the requested name.
- Settings' plugins-off state and the CLI's plugin system off and plugin
disable say that plugin-created automations are paused and stay so.
* fix(plugins): address host API 1.8 review threads
- Confirmations close when the worker's call ends, freeing the plugin's
turn; they name the automation (short id, project, workspace,
schedule), show any new prompt, and are refused as `changed` when the
automation was edited while the person was asked.
- automation.create takes hostId (through the project's setup on that
host) and a creationKey scoped to the plugin; the runtime rechecks the
plugin's approval right before the write.
- agent.resume records only terminals it started; both it and
workspace.create recheck approval before recording.
- automation.list never cuts a schedule (null when too long) or fails on
an id too long to show.
- The Automations detail says when a creator plugin was removed or
disabled.
Windows hosts' Git Bash (and agents that shell through it) print drive
paths as /c/Users/..., which resolved as POSIX paths and never linked.
Map /<drive>/<segment>... to <DRIVE>:\... when the workspace lives on a
Windows drive and no WSL distro owns the pane; bare /c stays literal so
'cmd /c' is not linked to C:\. Moves the existing MSYS drive conversion
from the main-process shell args to shared so both sides reuse it.
Closes#41357
* feat(plugins): host API 1.7 — workspace ids, project/terminal list, terminal focus/close
Plugins that track workspaces and terminals across Orca had to read the private runtime
token or shell out to the CLI. Host API 1.7 gives them the same through consented methods:
- workspace.readContext (and workspace.changed) carry `workspaceId`, the id workspace.list
gives; workspace.created/removed and agent.status.changed add `workspaceListId` beside
their existing raw `workspaceId`, which keeps its meaning.
- workspace.list rows name their `projectId`; opt-in `includeStatus` joins each row's agent
state, unread flag, live terminal count and last activity from worktree.ps.
- project.list (workspace:read), terminal.list (workspace:read), terminal.focus
(workspace:write, desktop only, steers only this window) and terminal.close
(terminal:send, reports whether the process is known to have stopped).
- Runtime refusals (unknown or ambiguous workspace, stale or exited terminal) reach plugins
as fixed messages instead of runtime wording.
- Consent copy for workspace:read, workspace:write and terminal:send says what they now
allow; terminal.focus and terminal.close are audited by terminal id.
- PLUGIN_SCHEMA_NEWEST_SINCE covers the editor typography and theme video floors it missed,
and the provisional 1.7 floor, so development builds accept plugins requiring them.
* fix(plugins): narrow terminal.close and harden host API 1.7 from review
- terminal.close closes only terminals of the focused workspace (the check terminal.sendText
uses) or ones this plugin opened with terminal.create or agent.launch, recorded in a bounded
per-plugin registry that is forgotten when its worker stops or it is disabled or removed.
terminal.focus stays any-terminal; summaries and terminal:send copy say so.
- Lifecycle events carry the worktree's identity and host: from the new row on create, and read
host-qualified before the purge on every removal path. agent.status.changed looks up the
identity on the reporting host only. The global removed-identity map is gone.
- includeStatus shares one in-flight worktree.ps and a 1 s cache across plugins, and reports
statusTruncated when that listing stopped short.
- Stored remote contexts get their identity host-qualified; panels and editors never get a raw,
path-bearing workspace id from readContext or workspace.changed.
- Runtime refusals map to fixed messages (tab pinned, no window, tab gone, host disconnected);
any other runtime error or malformed answer is a fixed action_failed with the detail logged.
- hostId is `local`, `ssh:` or `runtime:` in both workspace.list and project.list; rows past the
id or path bounds are left out with truncated set instead of failing the list.
- The mock testing host answers terminal.focus and terminal.close by default.
* fix(plugins): keep shipped host API values and codes; honest terminal results
- workspace.list hostId keeps the values 1.3 shipped (recorded host, else null; folder rows
their executionHostId); project.list always names the host. Both summaries say which.
- Methods that shipped before 1.7 report every runtime refusal as action_failed, as before;
the unavailable/conflict mapping applies to 1.7 methods only.
- includeStatus shares a pending worktree.ps however long it runs; the 1 s TTL starts when it
lands.
- The opened-terminal registry records only for a call still approved and not cancelled, and is
pruned on disable or removal only, so event-driven workers keep close rights across restarts.
- terminal.close answers { closed: true }: a local close cannot tell whether the process exited.
terminal.focus answers focused: false when the request was superseded or not navigated.
- workspace.list and project.list cut labels to 512 instead of failing the list.
- Removal events from the runtime job and the IPC retry are tested to carry the identity read
before the purge; folder deletion carries its host.
* fix(plugins): name the status-listing owner type
* refactor(ai-vault): group scanner modules by defining owner
* refactor(ai-vault): consolidate owner imports and isolate path absence
* Preserve mobile CI triggers for extracted absence predicate
Select each child's workflow state in the issue detail query and render
a colored state dot plus the state name on every sub-issue row. Rows
without a state (older servers, sub-issues created locally before a
refetch) render as before.
Fixes#41348
* fix(computer): stop echoing written text and secure read-backs in action results
* fix(computer): treat a truncated set-value read-back as unverifiable
* fix(computer): accept code-point truncated read-backs as unverifiable
* fix(workspace-cleanup): warn before deleting a workspace's ignored local files
git worktree remove deletes ignored files such as .env and local config,
and git status never reports them, so cleanup showed "Clean git" and the
delete dialog said nothing. Read them with a bounded ls-files listing,
skip regenerable output, symlinks and byte-identical copies of the main
checkout, and surface the rest as an approval-only cleanup blocker and a
warning in the delete confirmation.
* fix(workspace-cleanup): show an unchecked warning when the ignored-files check fails
* style(workspace-cleanup): format merged fact status list
The cleanup scan ran only in desktop main over its own saved repos, so
workspaces on a paired server or an SSH host's orcad never showed up, and an
SSH host's retained source rows showed as "Remote unavailable" even while its
orcad served them.
Each host now runs the same scan over the repos it owns through a new
workspaceCleanup.scan RPC. The dialog merges every known host's answer,
names remote rows by this window's runtime host id so removal goes through
the existing worktree.rm route, cancels remote legs with their scan id, and
builds "Remote unavailable" rows from its catalog only when a host can't be
reached. Desktop main scans only the repos it shows.
* feat(plugins): Featured and Newly added rows in the plugin catalog
Featured shows the most installed plugin per category; Newly added lists plugins
by the catalog's new entry-level addedAt (hidden when no catalog dates entries),
with a New badge for 24h and an Added this week filter. Snapshots move to a v3
cache key so older builds never read addedAt.
* feat(plugins): derive Newly added dates from release dates, as the website does
Drops the catalog-level addedAt field (schema, docs, v3 snapshot key). Main now
estimates a listing date for each non-official plugin from its oldest dated
release, and the Newly added row, New badge and This week filter read it through
shared helpers that mirror orca-site's pluginNew.ts: 30-day window, newest first,
dates more than an hour in the future ignored, "just now / N hours ago / N days ago".
* feat(plugins): show nine Newly added plugins, drop the counts release dates inflate
Listing dates come from each community plugin's oldest kept release, and
catalogs keep only recent releases, so almost every plugin looks new: 181
of 182 fall in the 30-day window and 142 count as this week. Remove what
that inflates rather than flag it: the "N this week" count and its See all,
the This week filter, and the 24h New badge.
The Newly added row now offers the website's nine in the catalog's normal
wrapping grid, the same columns and card widths as the catalog groups.
* fix(plugins): pick Featured winners by every kind a plugin belongs to
Featured used only a plugin's first filter kind, while the category filters
count every kind, so category order could change winners or drop a kind's only
candidate. Each plugin, walked by installs with a key tie-break, now fills one
unfilled kind it belongs to (the one with the fewest candidates left, then by
name). Also note why Featured is a capped one-row teaser and pin the cap.
* fix(plugins): hide Featured when Newly added is empty
Without Newly added, Featured sat directly on the Official catalog, whose
leading cards are the same popular plugins in the same columns, so back-to-back
rows repeated and read as a render bug. Featured now shows only alongside
Newly added. Leaving featured plugins out of their catalog instead would move a
card into the catalog the moment it's installed and skew the catalog's N of M.
Adds a PluginManager test that no plugin card shows twice in the empty state,
and page-level fixtures (390, 600, 1440, empty 1440) for screenshots.
* fix(plugins): cap Newly added at two full rows of the current columns
At phone width nine stacked cards pushed the catalogs about 3.5 screens
down. The grid now shows two full rows of its container-query column
count (8 at four columns, 4 at two, 2 at one), hides a partial last row,
and the pick renders at most eight. Hidden plugins stay listed in their
catalog group, so there's no See all.
* Correct plugin catalog fixture evidence
* Make plugin highlight tests match observable behavior
* fix(sidebar): keep the session name first on a monitoring agent row
Leading with "Monitoring background tasks" made every monitoring row in a
narrow sidebar truncate to the same text. The row's dot already draws the
monitoring glyph, so the status can trail the name like every other state.
* fix(agents): keep a monitoring child row's name first too
Sub-agent rows (desktop sidebar, chat strip and mobile) share one lead/trail
rule that also put "Monitoring background tasks" before the name.
Monaco falls back to brackets for auto-closing, so a plugin bracket up to 128
characters was typed into the file as you type. The shared schema now fills in
autoClosingPairs with the brackets that pass the 8-character typed-pair rule.
* feat(workspace-cleanup): mark merged and unchanged workspaces from git evidence
Squash-merged branches whose remote was deleted were flagged as unpushed
and needed a forced delete. The scan now reads what HEAD holds beyond the
workspace's base (ancestor, Git's squash proof, or a cached merged PR) and
reports merged/unchanged reasons; landed commits no longer count as at risk.
A gone upstream no longer hides unpushed commits. Renames idle-clean to
inactive and drops the dead tier, selectedByDefault and volatile-local-context.
* fix(workspace-cleanup): read HEAD once, skip a reused branch as its own base
Merge evidence now compares the cached PR and the base against the HEAD it
reads, not the listing's possibly stale one; a workspace opened on an
existing branch no longer counts that branch as its base; the proof
wrapper settles the WSL route before building its caches; a visit keeps
merged/unchanged reasons; landed rows stop sorting as unpushed.
* fix(workspace-cleanup): qualify base refs and trust the branch proof only for HEAD
Base refs resolve through the worktree base-ref qualifier so a tag cannot
shadow them and only the branch's own family is skipped, including the
repo default; SHA-256 pinned commits are not bases; the squash proof runs
only while the branch ref is the HEAD just read; expanded details stop
counting landed commits as unpushed.
* test(workspace-cleanup): build the repo fixture without a cast
* fix(workspace-cleanup): never take a tag as a workspace's base
* fix(agent-hooks): keep the Claude session model on later hook status
SessionStart reports the model, but the Claude handler dropped it, so the
mobile composer chip stayed on "Model". Publish that model and retain it
when later lead and child events omit it.
* fix(agent-hooks): keep the Claude model across an Orca restart
Claude reports its model only on SessionStart. After a restart the listener's
lead state is empty, so the next hook dropped the saved model from the row.
* test: run the Claude model restart test in the node pool
* fix(agent-hooks): keep the Claude model when a terminal status row lands first
* refactor(agent-hooks): read the Claude lead model once to keep claude-events under the line limit
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
* feat(agent-picker): fold legacy models the same way in every model picker
Claude aliases whose versioned model is listed, and Codex models superseded
in their family or by a newer major line, fold under Legacy models in the
agent launch picker, text-generation pickers, and native chat on desktop and
mobile. The default and current model always stay listed.
* feat(agent-picker): expand legacy models in place instead of a separate list
* feat(source-control): fold legacy models in the action model menu
* fix(agent-picker): keep model rows keyed across sections; let launch search find legacy models
* fix(agent-picker): keep rows in place while picking; classify each model catalog once
Legacy membership no longer depends on the selected model; a picker opens the
legacy section when the current model is in it. Classification is one pass and
cached per catalog, so streamed chat renders don't reclassify an unchanged list.
Typing on a closed Select no longer swallows its next close.
* fix(agent-picker): reopen menus with the current legacy model shown; PTY chats classify their discovered list
* test(agent-picker): wait on the menu instead of sleeping
* fix(agent-picker): keep the Legacy models row last, expanding older models above it
* fix(agent-picker): label the folded section More models, matching mobile
* perf(orchestration): read released worker output from its original instead of a saved copy
* fix(orchestration): keep refusal codes on released chat reads and locate legacy remote transcripts
* test(orchestration): prune flaky-pattern baseline for removed archive tests; guard a cursor read
* fix(orchestration): keep locator fields when stripping copies; never let the optional receipt page block remote release
* test(orchestration): drop removed archive tests from the node-runtime test list
* refactor(orchestration): drop the background strip; old rows keep their saved copy and its reader
* fix(orchestration): give reference rows the empty copy fields older Orca reads, with a note
* test(orchestration): give the slow-exit release mock a stored archive body
* fix(orchestration): record a transcript reference only for agents the reader can open
Liquid's {% comment %} / {% endcomment %} were dropped by hosts and refused by
validate:plugin. Comment markers are only inserted by Toggle Comment, so they
share the 128-character printable one-line rule with brackets; typed pairs keep 8.
* feat(wsl): turn WSL hosts on by default; ORCA_INTERNAL_WSL_HOSTS=0, false, off or no turns them off
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(wsl): review follow-ups for WSL hosts on by default
- Off words also match when quoted (cmd.exe's set NAME="0" keeps the quotes).
- The refusal now says WSL hosts are turned off for this launch, not missing from the build.
- New preload test pins when the renderer gets the WSL hosts API.
- Unit tests no longer inherit the gate state an Orca terminal publishes.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Two merges each added lines to global-settings-types.ts and pushed it past
the 300-line cap on main. Move workspaceCleanupPolicy into a group owned by
the workspace cleanup policy module, composed through GlobalSettingsBase like
the other feature settings. No behaviour change.
The site now lives at orca.dev; the old onorca.dev and www.onorca.dev hosts
redirect there. Linking to orca.dev directly skips that redirect.
Only page links change. Service hosts, sign-in and relay endpoints stay as they are.
* chore(endpoints): call orca.dev for feedback, plugin lists and update notes
The site moved to orca.dev. Feedback, connection diagnostics, plugin install
stats, the plugin kill list, update nudges and the changelog feed now use
orca.dev, as do the diagnostics token URL baked into builds and the release
download mirror (downloads.orca.dev). The old hosts serve the same paths,
so released builds keep working.
Skill share links on share.orca.dev are accepted, and the mobile scanner
recognizes the orca.dev Android download code. The old hosts stay accepted.
* chore(ci): leave the release JavaScript benchmark workflow unchanged
Editing it triggers the benchmark, whose parity check currently fails on
arm64 because max-quality brotli output for the mobile page differs by
architecture. The benchmark only needs some diagnostics URL, and the old
host still serves it.
The Agents list titled a thread with the tab's generated title, the first
prompt that tab saw. After `claude --resume` in a new tab, that is the
message sent after the resume, so the list kept a status note as the
thread's name while the tab and the agent row showed the session's own
name. Rank a named provider title of the pane's own session above the
generated title, as resolveTabNameSource does, and share the session
ownership check with the agent row.
Adds off-by-default workspace cleanup rules (merged, unchanged, inactive,
automation runs, orchestration workers, keep-when) to global settings and
an inherit/off/custom override on each repo. resolveWorkspaceCleanupPolicy
is the single source of truth for the coming background runner, and the
rules are exposed to paired clients through settings.get/settings.update.
No UI and no behaviour change yet.
* feat(orchestration): let coordinators approve worker permission prompts when the user turns it on
One setting on the orchestration page, off by default. When on, the
escalation offers orchestration approve and deny, both with a reason, and
the user still sees Allow/Deny: the first answer wins. A prompt the
worker's agent lets only a person approve is refused and stays with the
user. The machine running the worker enforces its own setting.
* fix(native-chat): a worker approval's receipt shows the command, not its tool input as JSON
* test(orchestration): list every worker-side case in the coordinator approval table
* chore(i18n): ship the coordinator approval setting's search keywords in the runtime catalog
* fix(orchestration): a reasonless allow keeps the person's refusal, and terminal checks no hook may approve are person-only
* fix(orchestration): address review on coordinator approvals
- A person-only chat prompt answered meanwhile reports as closed.
- A terminal allow reads Claude's warning from the screen it checks, so a
late-painted person-only warning still refuses before the hook is used.
- The receipt keeps a chat worker's whole command.
- orchestration approve prints the reason it sent.
* fix(native-chat): read the receipt's command through a parsed shape, not Reflect
* docs(skills): drop worker permission prompt guidance; the escalation carries it
Pi 1.5.1+ shrinks every image it is sent, including mid-turn ones; older Pi
sends steered images as given, so it keeps a 3.75 MiB (5 MB base64) cap.
Part of #37005
* fix(orchestration): label follow-up worker cards, gate remote-owned start cards on ready
A send that continues a finished or closed worker starts a follow-up Dispatch,
and the coordinator's chat showed it as "Started worker". The agent-start item
now carries the Dispatch it followed and whether the conversation reopened, and
the card reads "Reopened worker" or "Sent follow-up to worker".
worker-start --on a server that owns its workers wrote the card for any parsed
answer, with no agent kind. It now passes the started agent and writes the
card only once the server readied the worker, as local and attached starts do.
* test(native-chat): assert follow-up heading kind, not its copy
* feat(settings): move Remove project to a confirmed row at the bottom of Project Settings
* chore(i18n): sync protected copy keys for the remove-project dialog
* fix(settings): use primitive variants in the remove-project disclosure and dialog
* fix(settings): keep remove-project row off the per-write store path
The terminal count now lives in a dialog-only component, and the VM-recipe check is
memoized on worktree/runtime identity. Checkouts are grouped by host id, SSH labels
resolve through the setup's runtime owner, and a runtime missing from the catalog
shows as Unknown host instead of its raw id.
* fix(settings): select only the removed repos' worktree lists
Selecting the whole worktreesByRepo map re-rendered the remove-project row on every
other repo's worktree write. Also drop the orphaned terminalCount catalog keys.
* fix(settings): count remove-project terminals once on open; hide raw SSH ids
The dialog's terminal warning reads the count when Remove… is clicked instead of
subscribing, so no store write walks tabs. An SSH host with no label now shows as
Unknown host like an unlisted runtime, since generated target ids mean nothing to users.
* fix(settings): re-check terminal count before removing a project
A terminal opened from another client while the confirm dialog is up would close
without warning. Confirm now re-reads the count and, if it grew, updates the warning
and waits for a second confirm.
* test(settings): build remove-project fixture setups without a type assertion
* test(settings): cover the remove-project confirm holding for new terminals
* test(settings): drop the copy assertion from the remove-project confirm test