* fix(github): count gh pr and issue commands against the GraphQL rate limit
gh serves pr/issue/repo view-style subcommands over GraphQL, but the breaker
filed every non-api command under core and only matched REST's
"API rate limit exceeded" wording, so GraphQL exhaustion never tripped it.
Map those subcommands to the graphql bucket, match GraphQL's
"API rate limit already exceeded", and guard project-view issue close/reopen
against the GraphQL quota.
Fixes#28767
* test(github): drop redundant Date.now() args in graphql breaker test
Keeps the flaky-test-pattern ratchet at its baseline.
---------
Co-authored-by: Neil <neil@stably.ai>
The Goose (block.github.io/goose/docs/quickstart/) and Continue
(docs.continue.dev/guides/cli) links 404. Point them at
goose-docs.ai/docs/quickstart/ and docs.continue.dev/cli/quickstart in
the READMEs, the supported-agents docs page, and the in-app agent catalog.
Co-authored-by: Neil <neil@stably.ai>
* perf(native-chat): memoize file-link context per chat on its resolver inputs
Every mounted chat (hidden ones included) re-resolved its directory and
runtime owner on every store write. Reuse the context until an input the
resolvers read changes.
* docs(native-chat): scope the file-link input completeness comment
* feat(i18n): add Traditional Chinese (zh-Hant) UI locale
Adds 繁體中文 as a selectable UI language and derives its catalog from
zh.json rather than translating English afresh, so the reviewed Simplified
terminology and Orca glossary decisions carry over.
The conversion needed three corrections beyond OpenCC's `cn -> twp`:
- One pass only. `twp`'s phrase dictionary is not idempotent (it maps
進程->程序 and 程序->程式), and iterating to a fixed point makes output
worse: it rewrites the correct Taiwan 游標 to 遊標, and 程序 to 程式 where
the source meant an OS process.
- 16 terms where `twp` emits a form Taiwan does not use, each confirmed
against Microsoft's VS Code zh-Hant language pack (許可權 0 vs 權限 84,
賬戶 0 vs 帳戶 111, and so on).
- 進程 vs 程序 collapse in `twp` output. Taiwan calls an OS process 行程, so
the generator consults the Simplified source to disambiguate; daemon copy
reads 守護行程, not 守護程式.
Also pins `load: 'currentOnly'` on both i18next instances. i18next's default
expands `zh-Hant` into ['zh-Hant', 'zh', 'en'], so a key missing from the
Traditional catalog would silently render Simplified.
zh-Hant.json is generated and compared byte-for-byte, so the new check is
wired into verify:localization-catalogs to fail when a Simplified edit skips
regeneration.
Refs #10592
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(i18n): fail the zh-Hant check on an unreadable zh.json
The generator caught every error from reading and parsing zh.json, so a
malformed or unreadable Simplified catalog logged "absent here" and exited
0 without ever comparing the generated Traditional catalog. Only ENOENT
means there is nothing to derive, so every other failure now propagates.
Tests cover the three paths the catch was conflating: an absent zh.json
still passes for the combined verifier's synthetic fixtures, malformed
JSON throws, and a directory where the catalog belongs throws EISDIR
rather than reporting the file as missing.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* feat(i18n): ship Traditional Chinese (Taiwan) as a maintained built-in catalog
Keeps the zh-Hant locale from this PR and makes it a hand-maintained
catalog like the other built-ins, without the OpenCC generator:
- Catalog reconciled with current en.json. Per key it prefers the
Taiwan-reviewed copy from #22402 (which carries #14223), falls back to
the zh-derived copy here, and drops entries whose English changed.
A review pass then applied Taiwan terms (代理程式, 工作階段, 存放庫,
分頁, 列/欄) and 「」 quotes. Glossary: config/i18n-traditional-chinese.md.
- Label 繁體中文(台灣)in every catalog, the picker, onboarding and search.
- Detection maps zh-TW/zh-HK/zh-MO/zh-Hant* to zh-Hant; zh-CN/zh-SG/zh-Hans
stay on zh. Both i18next instances use load: 'currentOnly' so missing
keys fall back to English, not Simplified.
- Drops opencc-js, the generator scripts and their verify hook.
Co-authored-by: hungchihsueh <84211143+hungchihsueh@users.noreply.github.com>
Co-authored-by: chilung-cgu <b0423031@gmail.com>
* feat(i18n): translate remaining Traditional Chinese (Taiwan) catalog keys
Fill the 2,043 keys added to en since the source PRs branched, following
the Taiwan glossary, and extend the glossary with skill, automation,
usage, review, token and related terms.
* fix(i18n): review Traditional Chinese (Taiwan) catalog wording
Apply 629 reviewed corrections across the full catalog: 30 meaning or
untranslated-text fixes and 599 glossary and phrasing fixes (終端機, 用量,
API 金鑰, clearer counts and actions). Each edit was cross-checked by an
independent review pass.
* fix(i18n): polish sampled zh-Hant strings and drop redundant locale test
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: hungchihsueh <84211143+hungchihsueh@users.noreply.github.com>
Co-authored-by: chilung-cgu <b0423031@gmail.com>
The layout oracle merge gate keeps Blacksmith via fast_runners: true; the
advisory e2e call, nightly schedule and layout-owner dispatch run on
ubuntu-24.04.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Naming a Dispatch's own Run with --run is equivalent to omitting it, so
mail to a Dispatch whose assignee now coordinates a child Run redirects
to that Run's mailbox instead of failing recipient_run_mismatch.
Fixes#24699
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* ci: run terminal perf on demand only, on a hosted runner
The nightly failed every run: the presented-frame guard accepts only
GitHub-hosted Xvfb displays, but the workflow ran on Blacksmith. Drop the
schedule, move dispatch runs to ubuntu-24.04 and document local use.
* docs: record the first hosted terminal perf result
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
isTrustedBrowserRenderer and isTrustedClipboardRenderer fell back to
trusting any sender whose URL started with file:// in packaged builds
when no main renderer id was pinned (e.g. after the last window closes
on macOS), unlocking clipboard read/write and all browser:* handlers for
arbitrary local documents. Fail closed like isTrustedUIRenderer already
does, and share one isTrustedMainRendererSender check across the browser,
clipboard, and UI trust gates so they cannot drift again.
Fixes#25521
Co-authored-by: Matheus Breguêz <matbrgz@gmail.com>
* feat(tab-bar): "(CLI)" rows in the + menu offer a chat button
An agent set to open as a CLI shows as "Claude (CLI)" in the + menu with no
way to start it as a chat, while chat rows already carry a trailing terminal
button for the CLI. A CLI row whose agent can open as a chat on this host now
carries the mirror button: the row starts the CLI, the button (or ArrowRight,
then Enter) starts the chat.
* Test agent menu activation and alternate route work
* Use activated agent menu action and skip unused route work
* Fix agent menu lint and formatting
* Cover CLI row annotations in picker and search
* Share prepared agent menu answer context and verify route work
* Align agent menu fixture imports with static checks
NativeChatResolvedView rendered NativeChatMessageList without an image
runtime context, so image-ref attachments in terminal-backed chats (e.g.
Claude pasted images) fell into the label-only compatibility mode with
no thumbnail or click-to-open. Resolve the owner with the existing
useNativeChatImageRuntimeContext(terminalTabId), as the structured lane
does, so reads route through the tab's local/folder/runtime/SSH owner
and fail closed while ownership is unresolved.
Fixes#22327
Running a command group with no subcommand (e.g. `orca skills`,
`orca browser identity`) printed "Unknown command" with unrelated
suggestions. Print the group's help instead, and when flags are passed
to a bare group, report a missing subcommand that points at its help.
Co-authored-by: Neil <neil@stably.ai>
New-agent tab shortcuts pressed while the floating workspace panel owns
focus now launch the agent in the floating workspace instead of the main
worktree. Both the main workspace capture listener and the floating
panel's own shortcut handler route through one shared launcher, so the
agent launches exactly once regardless of listener order, including when
no main worktree is open.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* fix(i18n): resolve count strings with each language's plural rules
translate() now resolves a literal _one/_other key passed a numeric count
through its plural family, so i18next picks the CLDR form for the active
language or plugin pack. Built-in catalogs fill missing plural categories
(e.g. many in es/fr/pt) from _other so large counts stay in-language.
_one strings that hardcoded 1 now interpolate the count.
Closes#12106
* fix(i18n): pass value0 to fullCoverage_one so one-form languages interpolate the count
Languages with a single plural category (ja/ko/zh) now resolve count 1 to fullCoverage_other, which interpolates {{value0}}.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
`orca worktree ps --agent-wait --json` now reports, on each terminal-backed
agent row of the returned page, the same agentWait verdict
`orca terminal show --json` gives for that terminal. The lookup is opt-in
(RPC `includeAgentWait: true`) because it reads screens and may probe PTYs,
which is too costly for default pollers. Hook rows use their terminal handle
only when a connected PTY confirms it, and pane-only hook rows resolve the
live terminal by pane key. Structured-worker rows and older hosts omit the
field (absent = not evaluated; null = looked, no wait).
Fixes#23921
Co-authored-by: Neil <neil@stably.ai>
Bundled ConPTY 1.23 sends a DA1 query as soon as its input reader starts
and stalls ~3s waiting for the reply. The daemon held that query in the
startup buffer until a client attached, so every new Windows pane paid
the stall. The startup watcher now answers the DA1 itself, strips the
query from the replayed startup output, and leaves CPR and other output
for the client. The ConPTY DA1 reply moves to a shared constant used by
the daemon and renderer.
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* Revert "Keep same-machine folders with matching Git remotes in separate projects (#32272)"
This reverts commit 29a5f89b8a.
On a machine with several clones of one repo, #32272 moved the oldest clone
into the shared cross-host project. Shared Windows QA machines have several
orca clones, so everyone's sidebar "orca" project suddenly gained that
machine's main checkout and its worktrees. Revert until the intended
grouping is decided.
Conflicts resolved against later main: Settings files moved into
settings/repository (imports adjusted), and two test files later deleted on
main stay deleted.
* Use checked types in restored test fixtures
* Combine restored fixture type imports
resolveEditorOwnerRoute spread the full app state on every owner lookup;
project only route inputs, cached per state. Compare worktreesByRepo by its
owner fields so sort-order/unread/activity patches skip editor ownership
invalidation.
Linear-provided titles, states, assignees, projects, labels, workspace
names and error messages were printed verbatim, so remote text could
emit OSC/CSI/C1 sequences or forge extra output lines. Move terminalSafe
into src/shared/terminal-safe-text.ts, add terminalSafeLine (collapses
CR/LF), and apply it to every Linear text field in the human-readable
formatters. --json output is unchanged.
Fixes#20478
Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
* chore(i18n): add a detector for catalog keys no source references
A key can leave the code without leaving the catalog: a feature is reverted, a
setting is rewritten in place, a component is deleted. Nothing fails, so the
entries stay. Every locale carries them, translators spend effort on strings no
screen renders, and coverage numbers understate how much is actually translated.
`verify:localization-extraction` already reports an unreferenced set, but it
cannot be deleted as-is: i18next-cli does not see a key held in a data structure
(`{ key: '…' }`) or passed as a variable, and 18 files do exactly that. So this
requires two independent conditions — extraction misses the key AND the exact
string appears in no source literal under src/ or mobile/.
Two properties matter and both were found the hard way:
- Plural variants are judged by their base key. i18next appends the CLDR
category at runtime, so `…_one` never appears in a source file even though the
base does. Without this the scan eats every plural in the catalog.
- The scan is iterative. Removing a base key can strand the variants that
survived on its account, so it must be re-run until it reports none.
Registered as `verify:localization-orphans` but deliberately left out of the
lint chain: it reports 1,401 keys on current main, so gating now would fail CI.
The prune and the gate come together in a follow-up.
* test(i18n): cover the orphan detector's two non-obvious rules
Both rules decide whether a key is live, and both are easy to break without
noticing: the plural rule keeps `…count_one` when only `…count` appears in
source, and the literal scan is the sole evidence for keys extraction cannot
see — held in a data structure or passed as a variable.
Extracting them as pure functions changes no behaviour: the detector still
reports 14,459 keys, 12,887 referenced, 1,401 orphans, and --check still
exits 1.
* chore(i18n): rename the detector's key pattern constant
main gained the anti-slop rule no-shape-in-symbol-names after this branch
was cut, and KEY_SHAPED trips it once the branch is merged with main.
Renamed to CATALOG_KEY_PATTERN; no behaviour change.
* chore(i18n): name the orphan detector like the other localization verifiers
CODEOWNERS routes /config/scripts/*localization*.mjs to the localization owner, and find-orphaned-catalog-keys.mjs matched neither that pattern nor *locale*, so a change to it asked nobody for review. The file now carries the name of the npm script that runs it, verify:localization-orphans.
* fix(i18n): report stranded plural variants in the same pass as their base key
isKeyReferenced kept a plural variant alive whenever en.json still carried its base key, even when no source reached that base key. The base key was reported and the variants were not, so a prune needed a second run to find them. Only a base key that extraction or a source literal references keeps its variants now; the --check message drops the re-run advice and names the override tables, which sit outside the scan roots.
* fix(i18n): let the literal scan accept every key-shaped literal
The scan captured only literals of seven characters or more and then applied CATALOG_KEY_PATTERN, which has no such floor. A live key shorter than that, held in a data structure, would have been reported as an orphan. en.json has no key that short today, so the result is unchanged; the capture now leaves the shape decision to the one pattern.
* fix(i18n): stop the orphan scan when a source root cannot be read
collectSourceFiles swallowed every readdir error, so a directory it could not read contributed no literals and a key named only there would have been reported as safe to delete. Only a missing mobile/ root is skipped now, since a checkout without the mobile app is still a complete desktop scan; any other error stops the scan.
* style(i18n): wrap one line of the orphan detector to the formatter's width
* chore(i18n): fold the orphan-key detector into the extraction check and retire 1,644 unreferenced keys
verify-localization-extraction.mjs now filters its own unreferenced set by
source literals (src/ and mobile/), plural base keys and dynamic prefixes
composed inside translate calls, and fails when any key is named nowhere.
That replaces the standalone verify-localization-orphans.mjs script and its
second extraction pass.
The prune is recomputed on current main: 1,644 keys leave all seven locale
catalogs, 285 stale entries leave the key-override tables, and
en-runtime-required.json is regenerated.
Supersedes #19801.
Co-authored-by: Evgenii <413011+smwbev@users.noreply.github.com>
* chore(i18n): scope the unused-key scan to src/ and require a dotted dynamic prefix
mobile/ edits do not trigger the extraction check, so literals there must not
decide its verdict; a dotless runtime-built prefix would keep unrelated keys alive.
Co-authored-by: Evgenii <413011+smwbev@users.noreply.github.com>
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Evgenii <413011+smwbev@users.noreply.github.com>
Packaged macOS builds now append /opt/local/bin and /opt/local/sbin to the
seeded PATH when the default-prefix `port` binary exists, and the agent CLI
install-dir fallback also checks /opt/local/bin. Both are appended last so
existing Homebrew/system resolutions never change.
Co-authored-by: Neil <neil@stably.ai>
Each openFiles change (e.g. a dirty toggle) re-resolved every tab's owner
route twice. Cache owner keys per tab until an owner input changes, so a
single-tab update resolves only that tab.
dsh-tui 0.14+ boots the backend last picked in its launchpad
(~/.dsh-tui/kernel.json), so a plain `dsh-tui --resume <id>` could hand
a DSH session id to the Claude or Codex backend. Pin --backend=dsh in the
resume argv; dsh-tui <0.14 skips the joined form, but would read a
separate `dsh` token as the initial prompt.
Fixes#27944
* ci: restore main's Vitest transform cache in PR unit shards
Main produces per-shard transform caches on a schedule; PR shards restore
the newest one for the same config/lockfile/runtime policy. A Vitest cache
key generator folds each literal specifier's resolution candidates into the
per-module key so newly added files that shadow a resolution invalidate the
importer, and bails on glob-expanded dynamic imports.
* ci: list the resolution key plugin in the node tsconfig project
* ci: accept Vitest's CACHEDIR.TAG when sealing the unit module cache
Vitest 5.0.5 tags its cache root, which made every seal fail with
'invalid cache entry name' so no producer cache was ever saved.
* ci: reseed the unit module cache when any cache-key input lands on main
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
The contracts count operations and retained objects; wall-clock budgets
stay in pnpm test:perf:benchmarks, which no CI job runs. They do not
need Blacksmith's consistent hardware, and the PR path filter runs them
~40 times a day ($7.90/day, $5.50 of it on the 6-vCPU Mac).
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Each 12-vCPU arch job spends ~3 of its ~7 minutes waiting on Apple's
notary service; packaging itself runs at the same speed as the hourly
build's 6-vCPU runner. Halve the per-minute rate.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
electron-builder's temp-file cleanup registers async-exit-hook, whose
beforeExit handler calls process.exit(0). The overlap script reported
failures through process.exitCode, so a thrown build exited 0: the
retry wrapper logged success and skipped its second attempt (hourly run
40608643418). Exit explicitly instead, as electron-builder's own CLI
guards against the same hook.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
- Warm electron-builder-linux-<versions> and the hosted ubuntu-24.04 Electron native modules
- PRs restore hosted Linux Electron native modules without saving
- Replace mobile verify's bundler-cache with a restore of a warmup-saved bundle
- Drop the pnpm store cache where a direct install was faster (mobile main, glibc-floor containers)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
The single-file oracle cannot be split by whole-file balancing, so pass
Playwright test-level shards to the changed-spec lane. It was the last
required check in 40 of 42 measured runs.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Scripted guest codex (app-server) and grok (ACP) fixtures, installed on the
guest login PATH beside claude. orcad streams a partial reply, asks for an
approval and takes Stop for each; the lane checks the guest wrapper ran the
fixture with the guest runtime, and that Windows-side codex/grok decoys on
WSL's appended PATH never ran.
Co-authored-by: m4air <m4air@Mac.localdomain>
Node 26.12 bundles SQLite 3.54, which rejects ALTER TABLE ADD COLUMN for
rowid aliases; rebuild the shadowing table with CREATE TABLE instead.
Node 26.10 binds explicit undefined as NULL. The deleted test only pinned
node:sqlite's own validation (a parity guard for the removed Bun adapter);
SqliteBindings already rejects undefined at compile time.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Each lifecycle step now resolves when the stub prints its marker (ready,
booting:, runtime-exit:N) or rejects with diagnostics when the launcher's
output closes first, so a slow macOS Intel runner only makes a step later.
* test(native-chat): name the stalled step in the live-history watcher test
A CI run hit the 30 s test timeout with no step named. Each wait now has its
own 8 s deadline that reports the stalled step with what the watcher had
delivered, and the file sets IS_REACT_ACT_ENVIRONMENT so act() flushes.
* test(native-chat): share one 27 s budget across the live-history waits
Per-step 8 s deadlines were stricter than the old 30 s test timeout; a shared
deadline keeps the total unchanged and only improves the failure message.
* test(native-chat): use an AbortSignal budget instead of the wall clock
Date.now trips the flaky-test wall-clock rule; AbortSignal.timeout gives the
same shared 27 s budget without reading the clock.
* fix(runtime): accept Muse's composer when the voice-input label is absent
Muse labels its composer's top rule "Voice input" only where voice is
available, so on Linux the readiness predicate never matched and
worker-start timed out at agent_readiness. Keep the voice-label match and
also accept the composer itself: a rule (two or more rule chars) directly
before the prompt glyph after the latest Muse banner, so a shell prompt like
'~/app ❯' or '╰─❯' under a printed banner is still not ready.
Fixes#25005
Co-authored-by: j33pia <242526320+j33pia@users.noreply.github.com>
Co-authored-by: Nawapat Buakoet <nawapat.b@covest.finance>
* fix(runtime): escape Muse composer regex so the orcad bundle stays ASCII
---------
Co-authored-by: Neil <neil@stably.ai>
Co-authored-by: j33pia <242526320+j33pia@users.noreply.github.com>
Co-authored-by: Nawapat Buakoet <nawapat.b@covest.finance>
* test(pty): scope the group-reap test's ps to its own PTY
The helper listed every host process with full command lines, which
overflows execFileSync's 1MB buffer on busy machines (ENOBUFS). Discover
the tagged job on the test PTY's terminal and recheck survivors by their
captured pids, so the output stays small by construction and a job that
lost the hung-up terminal is still caught.
Refs #34410
* test(pty): clean up a job that discovery never captured
Refs #34410
* fix(daemon): read the PTY process table without blocking on terminal kill and resize
The terminal daemon force-killed a session by running ps and reading
/proc/<pid>/stat synchronously, and checked the resize foreground group
with execFileSync('ps'). A slow or wedged ps froze every terminal the
daemon serves for up to the ps timeout on each call.
Both paths now use the async process-table read (runProcess with a
timeout that kills the child). SubprocessHandle.forceKill may return a
promise; the termination controller awaits it so a refused signal still
releases the claim for a retry. A force-kill or SIGWINCH whose root
exits while ps runs signals nothing, since the captured groups could
already be recycled. ConPTY force-kill stays synchronous so dispose()
still sees the node-pty kill it must not repeat. The in-process
provider's app-quit sweep keeps the blocking variant. The ps dialect
and table readers move to posix-pty-process-table.ts.
Refs #34410
Refs #33870
* fix(daemon): address review on async PTY process-table reads
Guard only the root-pid fallback on exit so proven groups are still swept
after dispose, wait out at most one ps dialect probe, move the sync-launch
baseline entry with the table reader, and keep tests cross-platform.
Refs #34410
Refs #33870
* fix(daemon): keep the PTY open until an in-flight force-kill sweep finishes
A sweep whose root exits mid-read must not signal: the freed TTY may
belong to another terminal. Dispose therefore defers destroy() until the
sweep settles, so its hangup cannot end the root first.
Refs #34410
Refs #33870
* test(daemon): build the destroy-tracking PTY mock without a type assertion
Refs #34410
Refs #33870
* fix(pty): make the local graceful-deadline force-kill async and stub ps in tests
The in-process provider's graceful-deadline timer now uses the async
group sweep; the app-quit sweep and the root-signal path stay
synchronous. Tests that drove force-kill through fixture pids now stub
the async process-table read instead of querying the host, and a new
test pins that waiters do not chain behind a failed dialect probe.
Session ids are only read for rows on the root's terminal.
Refs #34410
Refs #33870
* fix(pty): hold PTY teardown until an in-flight force-kill sweep settles
Orphan cleanup could destroy a local PTY while the graceful-deadline
sweep was still reading the process table, neutralizing its fallback
kill and hanging up the root first. Both the daemon handle and the
local provider now defer teardown through PendingPtyGroupSweep.
Concurrent force-kill callers in the daemon now await the shared
in-flight request, so a joiner's physical-exit budget starts after the
signals are sent and it sees their rejection.
Refs #34410
Refs #33870
* fix(pty): let disposal and orphan cleanup join the in-flight force-kill sweep
Session disposal now joins the controller's shared force-kill request
instead of starting a second sweep. Local orphan cleanup decides its
escalation only after a pending graceful-deadline sweep settles, so a
refused sweep is escalated before the handle is released rather than
leaving the retry with a neutralized kill.
Refs #34410
Refs #33870
* fix(daemon): SIGKILL live PTY groups before a shutdown deadline exit
The old synchronous sweep sent its signals before the shutdown deadline
timer could run; the async sweep can still be reading the process table
when it fires. The deadline now SIGKILLs each live session's process
group synchronously before exiting (node-pty roots lead their own
group), falling back to the root pid when the group kill is refused.
POSIX only.
Refs #34410
Refs #33870
* chore(ratchet): gate event-loop-blocking calls in the daemon, PTY and orcad code
The terminal daemon and orcad serve every pane from one event loop, so a
synchronous child launch or file write there freezes all of them. A new
count ratchet tracks execFileSync/spawnSync/execSync, runProcessSync,
appendFileSync and writeSync per file under src/main/daemon,
src/main/pty, src/main/runtime and src/main/orcad; counts may only go
down. It reuses the sync-spawn ratchet's import-aware call collector,
now extracted to gated-call-use-collector.mjs, so aliases, namespace
imports and re-exports count and same-named methods on other objects
do not.
Refs #34410
Refs #33870