test(reference): pin Grok provenance and compatibility inventory - #213
Open
Blackman99 wants to merge 202 commits into
Open
Blackman99 wants to merge 202 commits into
Blackman99 wants to merge 202 commits into
Conversation
Implement #133 with isolated installed-reference probes, itemized story/ticket/acceptance mappings, raw pilot baselines, and scoped rewrite ADR supersession. Preserve legacy behavior and record unverified source/version and downstream parity work explicitly.
Resolve #133 review findings with complete compatibility syntax and source environment discovery, semantic acceptance mappings, independently resolved provenance, and strict headless format validation. Add real isolated FPS and hidden-option observations while preserving legacy behavior and the original pilot samples.
Address #133 review findings with source-seeded help traversal, independent portable source expectations, and real tutorial navigation and mode-refusal evidence. Assign remote workspace and tutorial contracts to their behavior owners while preserving existing runtime behavior and pilot samples.
Address #133 review findings with effect-based permission ownership and dedicated help/docs/debug/dock terminal scenarios. Record isolated palette, guide-reader and diagnostic probes while retaining explicit unverified dock availability and unchanged legacy behavior.
🦋 Changeset detectedLatest commit: b78e28d The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Implement ticket 02 (#134) with pinned licensed Rust UI reuse, separate Home/Profile, native candidate packaging, privacy observation and installed PTY verification. Preserve the legacy default and explicitly refuse execution until the dsh adapter is connected.
Resolve both Rust and legacy Home paths natively before writes, including existing ancestors of missing paths. Preserve symlink refusal and add installed-product PTY regressions for differently cased DSH_HOME and GROK_HOME roots, descendants, and reverse spelling. Addresses the independent ticket 02 isolation findings.
Track unresolved Home components and conservatively reject case-only potential overlap before any writes. Cover initially absent roots for both legacy Home variables through the installed native product, with distinct missing-sibling launch controls. Addresses the second independent ticket 02 isolation finding.
Distinguish dangling symlink components from missing directories before reconstructing Home paths. Refuse unresolved links before writes, retain native cycle errors, and verify explicit/default aliases, ancestors, chains and valid separate legacy links through the installed product.
Submit prompts from the isolated Rust client through released dsh ACP. Show answers, provider thoughts, empty replies, and failures without fabricating success. Keep legacy isolation when dsh cannot start.
Ask once before dsh write/edit tools run from the isolated Rust client. The UI correlates ACP permission requests with tool-call ids, shows the pending operation and dsh-supplied diff, allows that call once, and rejects or ends input without writing. Missing files, tool errors, and stale or duplicate replies are reported as failures.
Empty-draft Ctrl+C sends ACP session/cancel to released dsh; a non-empty draft is cleared without cancelling. Esc never cancels a turn or pending approval. Cancelled file tools cannot run from a late allow or reconnect, and a new prompt still works after cancel.
Rename the in-tool cancel unit test to process teardown so it is not read as resume coverage. Match --help to README: empty Ctrl+C quits only before any turn exists.
Restore persisted dsh conversation after exit with --continue/--resume. Interrupted tools show unknown and are not replayed. A second client is refused while this process holds write ownership.
Convert leftover pending tools to unknown on crash recovery. Lock Windows session owners with exclusive LockFileEx instead of succeeding open. Reap the dsh child before releasing the owner lease, and pump the live owner PTY while a rival is refused.
…tings Add an official-compatible config.toml entry for the isolated Rust client, map covered model/provider fields into generated dsh settings.yaml without overwriting a competing user file, and expose CLI/env/overlay/file/default origins through `codsh --rust inspect`. Invalid TOML is preserved. Missing credentials stay local: no grok.com login, no default telemetry, and no import of legacy ~/.dsh or ~/.grok credentials.
Write isolated dsh credentials at mode 0600 so dsh-credentials-local will load config/overlay api_key. Inspect reports the telemetry values actually forced off for dsh, stamps trace_upload origins, and keeps first-run base_url/env_key visible. Document that env_key values are passed through and that ~/.dsh and ~/.grok files are not imported.
Disconnected empty Enter reloads config.toml and connects without submitting. Credential writes patch a single refs entry and keep existing records.
…et 54 / #186) Capture over the legacy memory store (MEMORY.md, sessions/, index.sqlite), ported from grok-build a28ee2b with the reference prompts verbatim: - session end saves a metadata summary to sessions/ (3 typed prompts of 50 bytes, up to 5 topics, UTC, no model call; [memory.session] save_on_end); - /flush and the idle flush ([compaction.memory_flush] idle_timeout_secs) send the last 20 messages (whole tool exchanges) to the session model or flush_model and append the answer to the daily session log, with the delta prompt after a first flush; - /dream and the gated automatic Dream ([memory.dream] min_hours, min_sessions, check_interval_secs) merge the other session logs into the workspace MEMORY.md under the cross-process .dream-mutex lease; a failed or cancelled Dream leaves the gate open; - --memory-flush flushes after a -p turn and fails unless a log is written. The model call goes through dsh: the control plugin answers a memory_model request without appending to the session and reports the route, the messages and characters sent and the token usage; the cost is not reported. /new, a session switch and quit cancel a running request. Local deviations: an existing log is appended to, a MEMORY.md edited while Dream ran is kept (nothing written), the previous MEMORY.md and consolidated logs move to sessions/.archive/, and nothing-to-store is not reported as flushed. /memory then s shows content-free diagnostics (cursor, queue, pending age, gate, lease, last outcomes, archive) and y copies them. GROK_MEMORY_LOG writes content-free event lines. [memory_v2] enabled = true is refused: that store is not implemented. The pre-compaction flush is not wired (dsh owns compaction) and semantic dedup needs embeddings. Tests use the keyless mock model (DSH_CODE_CLI_MOCK_MEMORY and _DELAY_MS): unit tests, the control spec, and the Linux/macOS PTY test scripts/rust-memory-capture-pty-test.py (flush, delta, diagnostics, session end, busy, conflict, merge, cancel, automatic Dream, idle flush, cross-session injection, -p flush outcomes, memory_v2, GROK_MEMORY_LOG).
…with the terminal (#196) The bundled Ship plugin now starts a per-session loopback server from its hooks and prints one 'Ship graph · <summary> · <url>' line whose counts match the graph the page renders. The graph is joined from the spec, answers.json, and local tickets; the .ship.graph.json cache is only rebuilt, never read. SessionStart/SessionEnd hooks restart and stop the server; it also exits when the codsh host dies, the record changes, or the plugin data disappears. Hook host: a command hook's systemMessage is shown as a note, and hooks get CODSH_HOOK_HOST_PID. The e2e vt emulator now segments only a short head of the unread stream (long sessions cost GBs before). New headless agent-browser PTY check: scripts/rust-ship-web-pty-test.py.
4 tasks
Active, trusted plugins' .mcp.json / manifest mcpServers join mcp::discover as Source::Plugin at the lowest priority, anchored in the plugin root with GROK_PLUGIN_ROOT/DATA (and CLAUDE_PLUGIN_*). The plugin view, mcp list, /mcps, and plugin list --json report the same states. Installing or enabling grants nothing; disable/update/uninstall (or losing a name) forget the servers' remembered allows, and live TUI/editor sessions are resumed in a fresh dsh before the next prompt so withdrawn tools are gone.
… 65 / #197) One ledger folded from the dsh session log (packages/cli/bin/rust-usage.mjs) feeds every surface: - /usage (alias /cost) and the /session-info usage line in the TUI; - the status line command payload (context_window.session_input_tokens, session_output_tokens, session_usage, cost.total_api_duration_ms); - headless json / streaming-json / streaming-messages-json (usage, modelUsage, num_turns, cost_status, usage_is_incomplete), sliced to the turns the prompt started; - `codsh --rust usage <session-id> [turn]` (JSON, reference envelope). A model call is one dsh attempt (step/start or a retry to its settle) with the provider's reported usage: input with cache reads and writes, output with reasoning, per model route. Subagent children fold into the parent turn that spawned them. The whole log is folded, so a resume never double-counts; a fork keeps inherited history as in the reference. A call with no reported usage, an interrupted or failed turn, or a running or missing subagent log marks the ledger incomplete instead of adding zeros. Auxiliary calls (title, compaction summary, /btw, memory) are excluded. dsh reports no cost and no price table exists in the pinned dsh or reference sources, so cost is shown as not available (cost_status "unknown"); nothing is estimated, never $0. The TUI notice area grows from 6 to 8 rows so /session-info keeps its session id with the usage line.
…ce and rollback (ticket 62 / #194)
…208) The optional Ship extension now drives grill, to-spec and tickets (gates auto-Confirmed, Mission Contract sealed at gate 1), a parallel landing wave in worktree-isolated subagents with serial merge --no-ff and the legacy conflict validation, the separate final verification turn, and Merge-back, all from hook boundaries while dsh executes every agent. A failed or cancelled child is never merged or ticked; /ship resumes any phase; a lost run state is rebuilt from the files and a missing sealed contract stops the run. Also: the Rust client keeps a Stop-continued model call's text in the running turn, and the hook runner no longer crashes dsh on EPIPE from a hook that exits early or is killed by a cancel.
4 tasks
…ons (ticket 23 / #155)
…st client (ticket 66 / #198)
…ulti-type content Remote http/sse MCP servers run through codsh's own proxy (streamable HTTP and legacy SSE, session and protocol headers, 401 refresh, 404 re-init, refused redirects, no resend after a broken request). OAuth sign-in via mcp login / /mcps auth / editor x.ai/mcp/auth_trigger: RFC 9728/8414 discovery, RFC 7591 registration, PKCE S256 with RFC 8707 resource, loopback callback, owner-only token store, refresh, RFC 7009 revocation on logout. Tool results keep image blocks for dsh. MCP elicitation (form and URL) is answered on a TUI card or forwarded to editors as x.ai/mcp/elicit, with schema re-checks; editors also get auth_status and read_resource. Refs #168
4 tasks
Add configurable image services to `codsh --rust`. `[models] image_gen` (and optionally `image_edit`) names a `[model.<id>]` marked supports_image_generation / supports_image_edit, speaking the reference `xai` JSON body or the `openai` Images shape (for example a local stable-diffusion.cpp sd-server). With none configured neither tool exists; official hosts are a configuration error and a chat model is never used as an image service or picked as the default chat model from an image entry. dsh runs the model's `image_gen` / `image_edit` tools (rust-acp-image.mjs, registered only when the client enables them) and every call asks through the dsh approval path: the card names the prompt, the host, the number of reference images sent and that codsh does not know the service's price. `[Image #N]` chips, absolute paths, file:// and data: URLs are references; Read deny rules refuse a path. `/imagine <description>` sends the reference instruction verbatim. The native `image run --json` job checks replies (refusal, URL-only, malformed bytes, HTTP errors, timeout, cancel save nothing) and saves atomically to `<session>/images/<n>.<ext>`. The row shows elapsed time, Ctrl+C kills the request, `/images [open [N]]` lists and opens results, and resume keeps titles, `/imagine` text and the saved files. `codsh --rust image generate|edit|list` and `inspect` use the same config. Tests use the keyless mock model and a loopback fake image service (unit, spec, and the Linux/macOS PTY test scripts/rust-image-gen-pty-test.py); the openai shape was also run against a real local sd-server (SD-Turbo).
Add a configurable video service to `codsh --rust`. `[models] video_gen`
names a `[model.<id>]` marked supports_video_generation, speaking the
reference `xai` async API (POST /videos/generations, poll /videos/{id},
download video.url) or the native job API of a local stable-diffusion.cpp
sd-server (`protocol = "sdcpp"`). With none configured no video tool exists;
official hosts are a configuration error and a chat model is never used as a
video service.
The service's capabilities are explicit (video_durations, video_resolutions,
video_tools; sdcpp video_fps / video_output_format / video_strength), carried
into the tool schemas, and checked before any request: an unsupported
duration, resolution or input fails with the reason instead of being dropped.
dsh runs the model's `image_to_video` / `reference_to_video` tools
(rust-acp-video.mjs, registered only when the client enables them) and every
call asks through the dsh approval path with a card naming length,
resolution, prompt, host, image count and the unknown price. `/imagine-video`
sends the reference instruction verbatim with the attached images. The
native `video run --json` job records each job in `<session>/video-jobs/`
before the start request and maps remote states to the live row (queued with
position, generating, downloading, elapsed time). Failed, expired, refused,
malformed or foreign-host results, timeouts and Ctrl+C are distinct and save
nothing; Ctrl+C asks an sdcpp service to cancel and records its answer.
Finished videos are checked and saved atomically as
`<session>/videos/<n>.<ext>`. `/videos [open|status|cancel]` lists, opens,
queries a job nobody follows (after a timeout, a crash or `--resume`, which
names unfinished jobs) and cancels; `codsh --rust video ...` does the same
outside a session.
Tests: 15 Rust unit tests against loopback fakes of both protocols,
scripts/rust-video-gen.spec.mjs (18) and scripts/rust-video-gen-pty-test.py
(added to test:rust:pty). The sdcpp protocol was also run against a real
local sd-server (SD 1.5 + AnimateDiff mm_sd15_v3).
…#217 #218) Found by running #186 against a local Qwen3-4B (llama.cpp) with the real launcher; each fix has a unit test and a PTY check in scripts/rust-memory-capture-pty-test.py that fails on 95070ba. - #215: the first /flush after a restart or --resume was a full flush and re-captured everything. The previous flush lived only in memory (as in the reference memory_state.rs); it is now read back from the session's newest flush log (sessions/ or sessions/.archive/, the segment after the last `<!-- flush … -->`), so the delta prompt is used. Recorded as a local change in rust/upstream/MODIFICATIONS. - #216: first-turn recall joined every prompt word with AND, so a conversational question found no session log before Dream. It now follows the reference index.rs: extract_keywords (copied verbatim with its stop words and tests into memory_keywords.rs) joined with OR, ranked by BM25. search_notes keeps AND. - #217: [memory_v2] is a known top-level key, so inspect shows only the "not implemented" refusal, not an unknown security/policy field warning. - #218: a /flush or /dream busy refusal is cleared by the next memory notice, so "Dream is already running" no longer stays under "Dream completed". Other errors are kept. The memory-capture PTY test now also runs in test:rust:pty.
) A session whose first turn carried local memory was titled `<local-memory> Local memory notes the`: codsh folds memory, rules, agent definitions, and an expanded skill/command body into the same text block as the user's words, and dsh's fallback title, the picker prompts, and the resume projection all read that whole block. On resume such a first turn was dropped (isDirectUser saw the leading `<`). Follow the reference title order (rename, generated, first typed prompt): - assets::typed_prompt / helper typedPrompt strip the leading <local-memory>, <human_rules>, <agent-definitions> blocks and unwrap a skill/command invocation to the typed `/name args`. - Catalog prompts, sessions list, /resume, dashboard, /rename --auto, remote replay, resumed turns, rewind points, and export use it. - dsh's stored fallback title is never shown; provider and user titles are. - Picker prompts list only direct user messages (no plugin `<system-reminder>` or runtime snapshot). Tests: Rust unit (typed_prompt, catalog titles/projection, memory block round trip), scripts/rust-session-title.spec.mjs, and a PTY step in rust-memory-capture-pty-test.py (sessions list, /resume, resumed turn); all fail on 9b6eb6c.
…ess /deep-research (ticket 74 / #206) Real runs with a local Qwen3-4B and a local SearXNG showed three gaps in the integrated deep-research workflow (5b300a8): Web tools follow the effective settings. The launcher decided the dsh `tool-web` row from CODSH_WEB_SEARCH / CODSH_WEB_FETCH before the Rust client had read config.toml, so a setup configured only in config.toml registered neither tool: researchers (and #171's in-session search) had no web_search/web_fetch. rust.mjs now writes a fail-closed placeholder and `config::apply_to_dsh` (and the test-seam patch) appends `web_tools_yaml`, the effective `web.search/fetch.enabled` (config.toml, env overrides such as GROK_WEB_FETCH / GROK_DISABLE_WEB_SEARCH, requirements, --disable-web-search), after the overlay; dsh applies the later row. A stray CODSH_WEB_* value is no longer a setting. A partial result is not shown as a plain success. The completion notice reads `workflow deep-research [complete (result: partial)]`, and the plugin's `workflow` event carries `result`, so the tasks row and the workflow block title say `complete (result: partial)` as /workflow runs already did. Headless `-p "/deep-research <query>"` runs the built-in command instead of sending the text to the model, as the reference's slash_exec does: the client sends `workflow_launch`, the plugin waits in the foreground (CODSH_WORKFLOW_FOREGROUND), and the result block is the answer (exit 0 when the run completes, partial or verified; 1 when it is stopped, blocked, budget-limited or fails; a signal stops the run). No query prints the usage. The streaming-messages-json init line is emitted when the launch is sent and lists the session's visible tools (new control `tools` request) and `deep-research` in slash_commands. Docs: README/README.zh say that workflow children cannot answer an approval, so in `ask` mode their web_fetch needs an allow rule, a domain grant or always-approve, and record the local Qwen3-4B + SearXNG run. Tests: config unit test without CODSH_WEB_* (config-only, env override, --disable-web-search, stray env); control/headless/subagents/plain unit tests; statusWords and the partial `workflow` event in rust-workflow.spec.mjs; new scripts/rust-web-config-pty-test.py (packed install, no CODSH_ACP_PATCH, no CODSH_WEB_*; added to test:rust:pty); rust-workflow-pty-test.py now generates its overlay with web off so only config.toml turns the tools on, and checks the partial notice and tasks row and headless /deep-research; rust-plain-pipe-test.py no longer expects web_search from a stray CODSH_WEB_SEARCH.
A workflow child or subagent asked through the same approval/request
waterfall as the main session, but dsh-acp only answers for the ACP
sessions it owns, so a child's ask fell through to "unavailable" and was
refused ("permission mode ask"). In the default ask mode deep-research
researchers could never web_fetch without an allow rule.
rust-acp-child-approval.mjs (wired in rust-acp-control.mjs) now takes a
child's request when the terminal UI owns its root session and the control
channel is up. It sends child_approval with the child's label, type,
workflow and phase (from a new subagent lineage lookup), the tool and its
input, and waits for child_approval_answer. The child's aborted call, its
disposal or the root's settle the request as cancelled and close the card;
a closed channel settles it as unavailable; headless and agent stdio keep
the old refusal. file-approval passes the call's input and abort signal.
The Rust client queues the requests (child_approval.rs) behind the main
session's own prompt. The status line names who asks, the tool and the
target; with an empty prompt y allows once, a records the grant exactly as
the main prompt's a does (same grants and policy files), n returns the
refusal to the child. Enter does not answer a child's request. A pending
child approval outranks the question card like a main approval.
Reference (grok-build a28ee2b acp_handler/permissions.rs) also routes a
subagent's request into the owning session's permission queue; it cancels
the child's turn on a reject, while codsh refuses only that call.
Tests: unit tests for routing, attribution, queueing, deny, abort, stale
answers, dispose/close, headless, allow rules and always-approve (JS), the
queue, parsing, event handling and grant recording (Rust); a new installed
PTY test (rust-child-approval-pty-test.py) with a workflow child's web_fetch
in ask mode: y fetches, n refuses, a remembers the domain, /workflow stop
closes a waiting request, -p keeps the refusal.
The Rust client now installs, updates and rolls back on macOS from the
packed release product alone (no Rust toolchain), with evidence from
GitHub-hosted macOS runners.
- Version: the native reports the launcher's package version (0.24.0),
not the internal Cargo 0.1.0; build:rust passes CODSH_PACKAGE_VERSION.
- Update: packages/cli/bin/installer.mjs picks the installer that owns
the running package (npm/pnpm/yarn/bun global prefix, then an
inherited npm_config_user_agent) and is shared by `codsh update` and
the new `codsh --rust update [--check] [--to <v>] [--json]`
(schema codsh.rust-update.v1). A broken native prints a recovery line.
- dsh: codsh.testedDsh pins the dsh this release was tested with
(0.1.5-rc.3). Missing/old-dsh messages, install-check (dsh.tested,
dsh.note) and the README name `@deepseek-ai/dsh@<tested>`; the registry
latest 0.1.7-rc.2 fails the first turn ("format v4 message requires a
producer-owned source kind").
- Startup: session/new is retried for up to 15s while dsh is still
registering the provider adapter ("no adapter registered for
provider" / "ACP session persistence flush failed"), a race seen on
slow macOS and Linux runners; ACP error details are shown.
- macOS build fixes: openpty pointer mutability; install test resolves
/tmp -> /private/tmp; py3.10-compatible screen harness.
- CI: reusable rust-native.yml builds darwin-arm64/x64 and linux-x64
natives; rust-platforms.yml packs all natives and runs the clean
install/update/rollback, PTY, isolation/network audit and first-phase
flows on macOS arm64, Intel and x64 Node under Rosetta; release.yml
builds the natives and runs check:rust-package before publishing.
Linux users install the prebuilt Rust client from the packed product and complete a dsh turn, tool approval, cancel and resume, with evidence from clean GitHub-hosted systems. - Natives: linux-x64 and new linux-arm64, OpenSSL compiled in (no libssl at run time); floor recorded as glibc 2.35. - Runtime check before anything starts (and before a Rust Home is created): an ELF reader finds the native's libc and needed libraries; musl (Alpine), an older glibc or a missing shared library is refused with what to install and that plain `codsh` keeps working (codes libc / glibc / library). install-check has a `runtime` section and check:rust-package verifies it. - The turn/permission/cancel/resume PTY tests run on Linux too. - scripts/rust-platform-test.py: a reusable installed-product platform run (install-check, install/update/rollback, turn, approval, cancel, resume) that writes platform-report.json with the environment and an untested-capability list. - CI: Linux jobs on Ubuntu 22.04/24.04 x64 and 22.04 arm64 hosts, and clean containers (Debian 12/13, Fedora 41 run; Debian 11 and Alpine must refuse), all with the registry dsh at the tested version.
Build, package and run the Rust client natively on Windows x64. - rust-native.yml builds x86_64-pc-windows-msvc on windows-2022 with +crt-static; release.yml requires win32-x64 in check:rust-package. - Paths: dunce canonical paths (no \\?\ verbatim prefixes reach dsh or the Homes); drive-aware approval paths. - The ACP control channel listens on a loopback TCP port with the same one-time token on Windows (Unix socket elsewhere); process trees are ended with taskkill /T /F. - The session-owner lock on Windows locks one byte far past the record, so the mandatory byte-range lock no longer makes the owner file unreadable (resume and the scheduler failed with "no longer owned"). - Windows reports a key release for every key: releases now reach the composer only for the voice chord (every character was typed twice), and a release with no press before it (an Alt code, or a ConPTY character not on the keyboard layout such as a check mark) is typed as the character. - No kitty keyboard push/pop on Windows. - dsh's Windows shell tool is `pwsh`: it renders and is policed as a shell command; the keyless mock issues pwsh commands on win32. - scripts/rust-windows-pty-test.py drives the installed product through a real ConPTY (pywinpty): install-check, headless and interactive turns (CJK, Alt-code characters), file approval, pwsh, cancel of the process tree, resume, the refused sandbox profile, and install/update/refusal/ rollback with the Rust Home kept and legacy Homes untouched. The windows job of rust-platforms.yml runs it on windows-2022 and windows-2025 without a Rust toolchain.
…#202) Measure the installed client against pinned Grok 1.0.34 on macos-15 with thresholds frozen before any candidate process starts (scripts/rust-perf-bench.py, docs/rewrite/perf/). Client fixes that moved the numbers: - ACP unread counter and short wait_for_input slices - remembered artifact verification in the launcher - hangup watchdog so a closed terminal ends the client, dsh and the launcher - first connect() on a worker thread; Ctrl+Q during connect exits at once and kills the dsh group; keys typed during connect are kept - large paste stops resolving each line as a workspace drop; typing frames coalesce - auto-compaction session read runs off the event loop - synchronous ACP requests return when answered (session/close at quit included) Documented remaining regressions needing an explicit decision: dsh turn-start latency / no ACP token streaming (first-visible), process-tree RSS of the Node launcher + dsh, and warm-start first-output p95.
Add scripts/rust-capability-matrix.py and the capability-matrix job (ubuntu-22.04, macos-15, windows-2022) that install the packed product and record OS / terminal versions and the real effect of keys, mouse, shell, cancel, screen modes, terminal restore / hangup / early quit, the real clipboard, voice doctor without fixtures, sandbox, loopback SSH, a real tmux server and the Windows ConPTY harness. Every cell is ok, refused or unavailable; nothing passes silently. Product fixes found by the matrix: - Linux: xclip / wl-paste that cannot reach the display is reported as such, not as an empty clipboard. - Windows: /copy feeds clip.exe UTF-16LE with a BOM so CJK survives. - macOS: /copy forces a UTF-8 locale for pbcopy (CJK became MacRoman when LANG was unset). - macOS: a closed terminal is detected without POLLHUP (stdin readable with FIONREAD 0 for three checks) so the client exits 129 and dsh ends. New harnesses: rust-clipboard-pty-test.py, rust-tmux-pty-test.py; the Unix PTY harnesses now also run on Linux; the Windows harness adds keys/history, clipboard and voice doctor steps. Docs in docs/rewrite/platform-capabilities.md, README, CONTRIBUTING; changeset.
Document the three remaining macOS interaction regressions Kara accepted on 2026-09-28 so #202 can close, with measured after-f numbers and causes: first-visible (dsh ACP turn start / no token streaming), process-tree RSS (Node launcher + dsh), and warm start:first-output. Thresholds were not loosened. Point the README perf paragraph at the same decision.
…n reference (#209) Stress bench and CI evidence for ticket 209 (part of #132): - scripts/rust-stress-bench.py: concurrent sessions, busy-turn quit, long sessions, workflow pause/resume, and RSS/fd/process growth, measured against the frozen reference; per-metric validity, a metric that cannot be judged fails the run; --fetch-reference DIR. - CI: `stress` job in rust-platforms.yml (ubuntu-22.04, macos-15, windows-2022) on ci/** branches containing "stress"; evidence under evidence/stress. Thresholds and reports from run 36465419485 in docs/rewrite/perf/stress/{linux-x64,macos-arm64,windows-x64}. - acp: create an empty 0600 $DSH_HOME/.credentials.yaml when absent so dsh quit no longer waits ~1.1 s on the chokidar throttle timer; logout counts only a non-empty file as a stored credential. - A JS dsh runs with --max-semi-space-size=16 (Node 24 young-generation RSS growth of ~40-55 MiB over long sessions). Hard requirements (no leaks, no orphaned processes, no crashes) pass on all three platforms. Remaining gaps are tracked in #221: quit under load (Linux, macOS, Windows), Linux workflow resume, the Windows /workflow pause control-channel failure, and Windows late-session turn time. Thresholds were fixed before the runs and were not loosened.
This branch has not been deployed
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.
Implement #133 with isolated installed-reference probes, itemized story/ticket/acceptance mappings, raw pilot baselines, and scoped rewrite ADR supersession. Preserve legacy behavior and record unverified source/version and downstream parity work explicitly.## What
Why
Verification
pnpm changeset) if this changes user-visible behavior