Commit Graph
15 Commits
Author SHA1 Message Date
Mohamed Boudra fcde2072ab feat(diff): stream Changes revisions without blocking the socket (#8907)
* feat(protocol): define streamed diff revisions and resolve tag bases

* feat(server): stream shared diff revisions with paced file bodies

* feat(client): observe streamed diffs with atomic revision updates

* feat(app): show the Changes tree while diff bodies stream

* fix(server): retain the legacy structured diff payload budget

* fix(diff): preserve revision ordering and readable files

* fix(diff): select renamed patches and read dangling symlinks

* fix(diff): preserve nested checkouts and ambiguous patch paths

Only regular files and symlinks are readable untracked entries. Prefer patch metadata to ambiguous unquoted headers so paths containing a prefix delimiter keep their hunks.

* fix(diff): preserve BOM text and complete file replacements

Decode each string without consuming its leading BOM. File-type replacements emit multiple patch sections for one listed path, so retain all matching hunks. Assert the optional rename metadata in the existing commit-file journey.

* fix(diff): highlight symlinks from their stored target text

Working tree source context must match the symlink blob emitted by Git rather than the contents reached by following the link. Otherwise highlight runs do not cover the patch line and encoding fails the revision.

* fix(diff): tolerate disappearing highlight sources

Source context is optional after Git has produced the patch. Missing worktree link metadata must preserve the existing hunk-based highlighting fallback instead of failing the revision.

* fix(diff): batch cold reads and refresh logical comparison inputs

Acquire bounded pages of tracked patches lazily after Begin while retaining per-file highlighting and awaited frame delivery. Keep legacy preferred-base selection live across revisions and include submodule Git state in worktree cache identity.

* fix(diff): distinguish gitlink directories from replacements

A raw old gitlink mode also occurs when a submodule becomes a regular file. Query nested Git state only for a current directory, preserving normal file identity for replacements.

* fix(diff): invalidate timestamp-preserving file replacements

Size and modification time do not identify live file contents after a preserving copy. Include filesystem change time and file identity for tracked and untracked reuse, and verify live revisions agree with fresh reads.

* fix(diff): align highlight tokens with normalized patch lines

Git can normalize CRLF worktrees while highlighting reads their original line endings. Match tokens to the emitted patch text and trim only a normalization CR before encoding runs; mismatched source tokens are not attached.

* fix(diff): refresh equivalent worktree paths across platforms

Explicit refreshes must match filesystem-equivalent roots, including Windows path aliases. Use the existing realpath-aware matcher, budget real Git completion waits consistently, and assert optional status metadata in the filesystem commit-file journey.

* fix(diff): validate Git inputs and resolve refresh roots

Reuse now accounts for effective attributes, configuration, and canonical worktree blobs as well as filesystem state. Explicit refresh resolves repository identity like subscription creation, and callers await that resolution before acknowledging the command.

* fix(diff): keep non-Git workspace refresh successful

Diff invalidation has no target repository for an ordinary folder. Treat that expected absence as a no-op while preserving other root-resolution errors.

* fix(diff): observe scoped Git interpretation settings

Classify each metadata root with its worktree and common scopes, retaining both when the directories coincide. Shared attributes affect all checkouts, while config.worktree belongs to the owning checkout. Real subscriptions verify automatic binary and hunk-context refreshes in main and linked worktrees.

* fix(diff): observe interpretation inputs for pinned comparisons

Immutable commit objects still depend on mutable Git configuration and attributes. Declare those metadata inputs independently of ref, index, and worktree mutability, while keeping unrelated endpoint events out of pinned comparisons.

* fix(diff): observe interpretation independently of comparison endpoints

Commit comparisons still read worktree attributes. Watch those inputs independently, checking effective Git interpretation before invalidating fixed contents. Retain paths hidden by whitespace filtering so attribute changes can expose them. Forward binary frames through the branch-loading test interceptor.
2026-11-08 11:00:21 +07:00
Mohamed Boudra 9bc998fa38 fix(server): keep Git observation and worktree IO off the event loop (#7943)
* fix(server): keep Git observation and worktree IO off the event loop

Resolve subscription path identities before callbacks and serialize async worktree metadata mutations by canonical ownership. Git command tracing must not probe the working directory before spawning.

* test(server): verify Git trace records without filesystem probes

* fix(server): establish Git identities at observation setup

Read-only checkout refreshes should not resolve watcher namespaces. Observation tests await setup and compare cross-workspace fan-out without depending on completion order.

* fix(server): retain literal symlink targets in Git event identity

Canonical realpaths can erase a symlink target spelling when its parent is also a symlink, such as /var on macOS. Resolve these aliases once during setup so deleted and ignored event paths still match without per-event IO.

* fix(server): preserve Windows worktree path spelling

* fix(server): retain native aliases in worktree ownership

* test(server): write Git IO trace markers asynchronously
2026-10-27 09:57:35 +07:00
Mohamed Boudra 33a52d0ae7 Speed up cold diffs and wrapped text measurement (#4676)
* perf(app): optimize wrapped measurements and checkpoint native layout experiment

Compute full grapheme geometry only for final wrap fragments. Preserve shaped-text search behavior while bounding additive wrap probes. Keep the Android background layout experiment isolated from the normal diff renderer; native renderer integration and iOS bindings remain unfinished.

* perf(server): reduce cold diff generation work

Keep active diff reads owned across invalidation and wait for the initial watcher inventory before cold generation. Batch patch and blob reads while preserving per-file size isolation, bounded output, and daemon responsiveness. Avoid constructing fallback tokens when full-file highlighting already covers both sides.

* test(server): exercise oversized highlighted diff rejection

The single-line fixture now bypasses highlighting under the long-line guard, so it no longer reaches the structured payload limit. Use short dense lines to keep testing oversized rejection and continued socket usability.

* fix(server): queue fresh diffs for forced reads

A forced request following a repository mutation must not reuse an older active build. Invalidate that result and coalesce waiting callers onto one subsequent build. Give the cache a named object input and completed-value type.

* test(server): share deferred diff loader setup

* test(server): name completed diff cache setup

* refactor(server): use aliases for new diff imports

* fix(server): keep shipped diff imports resolvable by Node

The TypeScript build preserves path aliases without a runtime resolver. Restore relative imports for shipped code and declarations, and correct the server import guideline that prompted the regression.
2026-09-11 08:07:01 +02:00
Mohamed Boudra 708f9260b1 fix(server): disable repository fsmonitor commands (#4208)
A repository-controlled core.fsmonitor command can execute when the daemon refreshes Git state. Opening or reconciling a malicious checkout therefore allows code execution as the daemon user. Force core.fsmonitor=false on daemon-owned Git invocations before repository config is considered.
2026-09-02 13:15:51 +02:00
Mohamed Boudra fb67d2cdc8 Keep the daemon responsive during Git queue pressure (#3945)
* fix(server): keep Git pressure from stalling daemon

Git process starts were refilled synchronously, so slow process spawning could monopolize the main loop long enough to trip connection liveness checks. Admit one process per event-loop turn and expose refresh/fetch provenance in runtime queue metrics.

* perf(server): avoid delaying isolated Git commands

Start the first command immediately when the scheduler is idle. Backlog admission and completion-driven refills still yield between spawns, preserving daemon liveness without adding a turn to normal sequential Git traffic.

* fix(server): keep Git admission outside fake clocks

Subprocess admission is event-loop ordering rather than simulated wall-clock behavior. Use the native Node immediate so service tests can fake debounce timers without deadlocking queued real Git processes.

* refactor(server): bind Git command provenance explicitly

* test(server): expect bound Git fetch runner
2026-08-28 10:25:20 +02:00
Mohamed Boudra a06e4d60e9 Keep workspace Git refreshes responsive at scale (#2979)
* fix(server): prevent Git watcher fanout stalls

Repository metadata events were refreshing every observed worktree, multiplying Git process submissions and starving workspace create and archive requests behind observation work. Route metadata to the workspaces that depend on it, preserve conservative shared-ref refreshes, and admit interactive lifecycle operations ahead of queued background reads.

* fix(server): preserve Git metadata dependencies
2026-08-07 18:50:43 +08:00
Mohamed Boudra 2e188787ff Limit daemon-wide Git process pressure (#2797)
* perf(server): bound Git process starts

Git refresh bursts could keep creating short-lived processes at the concurrency ceiling, causing sustained process churn on constrained hosts. Apply one daemon-global start-rate and concurrency policy to every Git command while preserving the legacy concurrency environment variable.

* build(nix): update npm dependency hash

* fix(server): hold Git slots until process exit

* fix(server): enforce Git limits across process lifetime

* fix(server): align Git metrics with process exit

* Fix Git limiter test deadlocks

* Tune default Git process rate
2026-08-02 19:59:43 +02:00
Mohamed Boudra 0a106dd35f Keep Git status and diffs current across platforms (#2775)
* fix(server): make Git observation cross-platform

Platform-specific watchers and forced full refreshes amplified Git processes and could miss nested changes. Share checkout and repository observation internally, scope final-state refreshes, and bound degraded polling so streamed summaries and diffs stay correct under bursts.

* fix(server): refresh Git worktree state on metadata changes

* fix(server): keep Git watcher runtime inputs current

* fix(server): normalize watcher runtime boundaries

* fix(server): reconcile Git observer topology

* test(server): report Git watcher event batches

* fix(server): close Git observation gaps

* chore(ci): remove temporary Git observation jobs
2026-08-02 12:20:20 +02:00
Mohamed Boudra 12612f6646 Make Git slowdowns visible in daemon metrics (#2366)
* feat(server): expose daemon Git pressure metrics

Separate limiter queue wait from Git execution time and report subscription ownership so accumulating work is visible in the existing runtime log.

* fix(server): collect subscriptions in agent metrics

Reuse the existing agent snapshot during runtime flushes so WebSocket shutdown does not require an additional AgentManager method call.

* test(server): retry transient hub cleanup
2026-07-23 21:57:08 +02:00
Mohamed Boudra 5d8dc800fc Reduce startup git work for workspace snapshots 2026-05-27 20:18:49 +07:00
Samatar 5a1c7f266c fix(server): render non-ASCII filenames in git output
Fixes #436
2026-05-19 01:16:33 +00:00
Mohamed Boudra 2d3c9101f3 Trace git command spawn and close metadata
Thread an optional logger through runGitCommand and the CheckoutContext
helpers so workspace-git-service can emit trace-level traces around each
git invocation. Behavior is unchanged when no logger is supplied.
2026-05-15 09:50:05 +07:00
Mohamed Boudra 3b7971a463 Fix Windows git command console flashing (#897) 2026-05-10 19:46:25 +08:00
Mohamed Boudra 15df680a64 [codex] Centralize subprocess env boundaries (#585)
* Centralize subprocess env boundaries

* Remove env boundary static audit test

* Tighten env boundary process launches

* Fix Windows native process launches

* Inline provider env pass-throughs
2026-04-27 13:24:16 +08:00
Mohamed Boudraandgithub-actions[bot] 964bf3e13f fix(server): centralize git subprocesses with p-limit throttling (#310)
* Fix uncaught timeout rejection when archiving agents

* fix(server): centralize git subprocesses under runGitCommand with p-limit throttling

Supersedes #299. Same problem (unbounded git subprocess concurrency causing
zombie accumulation), different approach: a single `runGitCommand(args, opts)`
function backed by `p-limit` instead of a custom semaphore pool.

- Always uses `spawn` (one code path, no exec/execFile split)
- Concurrency configurable via PASEO_GIT_CONCURRENCY env var (default 8)
- 30s default timeout for read-only ops, 120s for mutations
- Centralized error formatting, stdout truncation, process reaping
- Runtime tests verifying throttling, timeout kills, deadlock prevention

* fix: update lockfile signatures and Nix hash

* fix(server): add Windows compatibility to runGitCommand

- shell: true on Windows (resolves .cmd/.bat git shims)
- windowsHide: true always (prevents console window flashes)
- quoteForCmd for args with spaces when routing through cmd.exe
- Tests verify shell/windowsHide behavior per platform

* refactor: use spawnProcess instead of duplicating Windows handling

spawnProcess from spawn.ts already handles shell: true on Windows,
arg quoting for cmd.exe, and windowsHide: true. No need to reimplement.

* fix: non-null assertions for stdio streams in strict build

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-04-13 13:03:01 +08:00