Skip to content

Windows 1/5: foundation, durable runtime, and stack workflow - #1006

Merged
arul28 merged 45 commits into
mainfrom
codex/windows-foundation-runtime
Aug 3, 2026
Merged

Windows 1/5: foundation, durable runtime, and stack workflow#1006
arul28 merged 45 commits into
mainfrom
codex/windows-foundation-runtime

Conversation

@arul28

@arul28 arul28 commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Stack position

Windows 1/5 · parent: main · downstream: #1007

This is the foundation of stack #1011. No layer merges independently; PR #1010 is the cumulative full-system head.

Based on the Windows implementation by @nsxdavid in #999.

Responsibilities

  • Windows filesystem, process, executable resolution, IPC, SQLite/CRR, and platform-capability foundations.
  • Stable/Beta per-user runtime isolation and durable background-brain supervision.
  • Capability gates preserving macOS/Linux behavior.
  • Stack-aware /quality, /test, and /ship --stack-ready.
  • Native Windows Node 22 CI for affected contracts.

Exclusions

CLI/provider UX belongs to #1007; desktop auth/sync to #1008; packaging/updating to #1009; release proof to #1010. WSL, ARM64, and native Windows computer use are out of scope.

Validation

Draft checkpoint: direct-parent desktop and ADE CLI typechecks pass on native Windows with Node 22.13.1. Worker integration, focused tests, /quality, /test, and ready-stacked binding are in progress.

Evidence and provenance

Summary by CodeRabbit

  • New Features
    • Added broader Windows support for runtime services, local connections, synchronization, clipboard tools, and desktop behavior.
    • Improved isolation for local communication across users and application channels.
    • Added clearer platform-aware computer-use capabilities and file-reveal labels.
  • Bug Fixes
    • Improved runtime recovery, startup readiness, stale-process handling, and failure reporting.
    • Reduced unwanted console windows and prevented competing service repairs on Windows.
    • Updated account and machine wording from “Mac” to “computer.”
  • Developer Experience
    • Improved development startup, cleanup, documentation validation, and cross-platform automated checks.

@vercel

vercel Bot commented Aug 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Aug 3, 2026 9:55pm

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@arul28, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 56 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b73b754-9bfe-410c-a8f5-228a2c197082

📥 Commits

Reviewing files that changed from the base of the PR and between 70dbf3a and 276ed5a.

📒 Files selected for processing (2)
  • apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
  • apps/desktop/src/shared/types/sync.ts
📝 Walkthrough

Walkthrough

Changes

This PR adds Windows foundation support across service supervision, named-pipe IPC, runtime startup, process identity, desktop behavior, development tooling, CI, and review workflows. It also updates platform-neutral wording and cross-platform test infrastructure.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested labels: desktop, ios, docs, ci

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.42% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the PR's main Windows foundation, runtime supervision, and stack workflow changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/windows-foundation-runtime

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@arul28 arul28 changed the title codex/windows foundation runtime Windows 1/5: foundation, durable runtime, and stack workflow Aug 1, 2026
@arul28
arul28 marked this pull request as ready for review August 2, 2026 02:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/ade-cli/src/headlessLinearServices.ts (1)

1121-1136: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

requestRawWithCredentialFallback bypasses the injected fetchImpl.

Every other GitHub request path in this file (validateToken, probeRepoAccess, both apiRequest call sites, and the GitHub App auth service) now routes through requestGitHub, which honors options.fetchImpl. requestRawWithCredentialFallback still passes fetchImpl: fetchGitHub directly. fetchGitHub's third parameter defaults to the global fetch when omitted, so this call always uses the real network fetch, not options.fetchImpl.

This breaks the stated goal that this diff makes GitHub requests use the injectable transport. Any caller of requestRawWithCredentialFallback that relies on a custom fetchImpl (tests, or an alternate transport on a platform without direct network access) silently falls back to real network calls.

🐛 Proposed fix to route raw requests through the injected fetch
   const requestRawWithCredentialFallback = async (
     args: GithubRawRequestArgs,
   ): Promise<Response> => await requestGithubRawWithCredentialFallback({
     ...args,
     candidates: (await readCredentialInventoryAsync()).candidates,
-    fetchImpl: fetchGitHub,
+    fetchImpl: requestGitHub,
     userAgent: "ade-cli",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/headlessLinearServices.ts` around lines 1121 - 1136, Update
requestRawWithCredentialFallback to pass the injected options.fetchImpl through
the requestGithubRawWithCredentialFallback call instead of always using
fetchGitHub, while preserving the existing credential candidates, user agent,
auth-missing message, and fallback logging.
🧹 Nitpick comments (8)
scripts/dev-shared.test.mjs (1)

71-94: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case for the unresolvable npm entry point.

resolveNpmInvocation throws when no candidate exists. That error message is the only guidance a Windows developer gets for a broken Node installation. No test covers it.

Add one case with pathExists: () => false and assert the thrown error.

💚 Proposed test
+test("reports a clear failure when npm's entry point is missing on Windows", () => {
+  assert.throws(
+    () => resolveNpmInvocation(["run", "dev"], {
+      platform: "win32",
+      execPath: "C:\\Program Files\\nodejs\\node.exe",
+      env: {},
+      pathExists: () => false,
+    }),
+    /Unable to resolve npm's JavaScript entry point/,
+  );
+});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/dev-shared.test.mjs` around lines 71 - 94, Add a test for
resolveNpmInvocation using Windows options and pathExists: () => false,
asserting that it throws when no npm entry point can be resolved and validating
the resulting error message. Keep the existing successful invocation test
unchanged.
scripts/dev-shared.mjs (1)

260-270: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Reject npm_execpath values that are not JavaScript entry points.

The resolved candidate is executed as node <candidate>. npm_execpath normally points at npm-cli.js, but some shells and wrappers set it to npm.cmd or a shell script. Node then fails with a syntax error instead of the clear message this function provides.

Accept only .js, .cjs, and .mjs candidates.

♻️ Proposed guard
   const candidates = [
     env.npm_execpath?.trim(),
     path.join(path.dirname(execPath), "node_modules", "npm", "bin", "npm-cli.js"),
     path.join(path.dirname(execPath), "node_modules", "corepack", "dist", "npm.js"),
-  ].filter(Boolean);
+  ]
+    .filter(Boolean)
+    .filter((candidate) => /\.(c|m)?js$/i.test(candidate));
   const npmCliPath = candidates.find((candidate) => pathExists(candidate));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/dev-shared.mjs` around lines 260 - 270, Update the candidate
filtering in the npm entry-point resolution flow around candidates and
npmCliPath to accept only existing JavaScript entry points with .js, .cjs, or
.mjs extensions, rejecting npm_execpath values such as npm.cmd or shell scripts
before selection. Preserve the existing fallback candidates and clear error
behavior when no valid path remains.
apps/desktop/scripts/dev.cjs (1)

334-341: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Restart detection can miss builds that share a modification-time tick.

The watcher compares only curr.mtimeMs. Some filesystems report a coarse modification time. Two successful builds inside the same tick then produce equal mtimeMs, and Electron does not restart. The marker content already contains a unique value, so a content comparison is exact.

♻️ Proposed content-based restart trigger
-  let lastReadyMarkerMtimeMs = initialReadyMarkerStat.mtimeMs;
+  let lastReadyMarkerToken = fs.readFileSync(mainReadyMarker, "utf8");
   fs.watchFile(mainReadyMarker, { interval: 250 }, (curr) => {
     if (shuttingDown) return;
     if (!curr || curr.nlink === 0) return;
-    if (curr.mtimeMs <= lastReadyMarkerMtimeMs) return;
-    lastReadyMarkerMtimeMs = curr.mtimeMs;
+    let token;
+    try {
+      token = fs.readFileSync(mainReadyMarker, "utf8");
+    } catch {
+      return;
+    }
+    if (token === lastReadyMarkerToken) return;
+    lastReadyMarkerToken = token;
     requestElectronRestart("main build completed");
   });

initialReadyMarkerStat then becomes unused at line 282.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/scripts/dev.cjs` around lines 334 - 341, Update the ready-marker
watcher around lastReadyMarkerMtimeMs to detect changes by reading and comparing
the marker’s content rather than relying on mtimeMs; initialize the previous
content from the existing marker and update it before calling
requestElectronRestart. Remove the now-unused initialReadyMarkerStat value and
retain the shuttingDown and missing-link guards.
apps/ade-cli/src/serviceManager/windowsSupervisor.ts (1)

108-108: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Write the PID record as UTF-8.

lastLaunchError carries an exception message that can contain non-ASCII characters, for example a localized Windows error or a path with accented characters. [Text.Encoding]::ASCII replaces those characters with ?. The reader uses fs.readFileSync(pidPath, "utf8"), so UTF-8 without BOM keeps the diagnostic readable and stays JSON-compatible.

♻️ Proposed change
-    "  [IO.File]::WriteAllText($pidPath, ($record | ConvertTo-Json -Compress), [Text.Encoding]::ASCII)",
+    "  [IO.File]::WriteAllText($pidPath, ($record | ConvertTo-Json -Compress), (New-Object System.Text.UTF8Encoding($false)))",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/serviceManager/windowsSupervisor.ts` at line 108, Update the
PowerShell PID-record write in the Windows supervisor to use UTF-8 encoding
without a BOM instead of [Text.Encoding]::ASCII, preserving non-ASCII characters
in lastLaunchError and keeping compatibility with the reader’s utf8 decoding.
apps/ade-cli/src/services/projects/machineLayout.test.ts (1)

33-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case that pins the effect of ADE_RUNTIME_SERVICE_NAME.

windowsChannelIdentity prefers ADE_RUNTIME_SERVICE_NAME over ADE_PACKAGE_CHANNEL for the hashed identity. No test states the expected result when only one process sets that variable. Add a case that documents the intended behavior, for example that { ADE_HOME: ".ade-beta", ADE_PACKAGE_CHANNEL: "beta" } and the same environment plus ADE_RUNTIME_SERVICE_NAME: "com.ade.runtime.beta" produce the same pipe name.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/services/projects/machineLayout.test.ts` around lines 33 -
54, Add a test alongside the Windows channel layout case that compares two
resolveMachineAdeLayout calls: one using ADE_HOME and ADE_PACKAGE_CHANNEL, and
the other using the same values plus ADE_RUNTIME_SERVICE_NAME set to the beta
service name. Assert both results have the same socketPath, documenting the
expected service-name identity behavior.
apps/ade-cli/src/serviceManager/installWindows.ts (1)

169-174: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider sharing one PowerShell quoting helper.

powerShellSingleQuotedLiteral exists here and in windowsSupervisor.ts (line 63) with the same escaping rule and different error text. Export one implementation and import it, so a future escaping fix applies to both command builders.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/serviceManager/installWindows.ts` around lines 169 - 174,
Consolidate the duplicate PowerShell quoting logic by exporting the existing
powerShellSingleQuotedLiteral implementation from one module and importing it in
the other, including the Windows scheduled-task and supervisor command builders.
Remove the local duplicate and retain identical single-quote escaping and
NUL-byte validation through the shared helper.
apps/ade-cli/src/serviceManager/installWindows.test.ts (1)

495-526: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case that lets uninstall resolve identity from the command environment.

Every uninstall test passes serviceName and launcherPath explicitly. That hides the identity-resolution path used in production, where ADE_PACKAGE_CHANNEL and ADE_HOME arrive through command.env. Add a case that omits serviceName and launcherPath and asserts that the Run-key value name equals the task name produced by the install path. This case covers the install/uninstall asymmetry flagged in installWindows.ts line 602.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/serviceManager/installWindows.test.ts` around lines 495 -
526, Add an uninstall test that omits serviceName and launcherPath, supplies
ADE_PACKAGE_CHANNEL and ADE_HOME through command.env, and verifies identity
resolution uses the install-path task name as the Run-key value name. Anchor the
assertions in uninstallWindowsService and the existing
buildWindowsRunKeyQueryArgs helpers, while preserving the current cleanup and
call-sequence expectations.
apps/ade-cli/src/services/runtime/socketSpawnLock.ts (1)

93-99: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Share one isWindowsNamedPipePath implementation.

localIpcListenOptions.ts uses a function with the same name and the same normalization rule. Export one helper and import it in both modules, so the pipe-detection rule cannot drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/services/runtime/socketSpawnLock.ts` around lines 93 - 99,
Consolidate the duplicate isWindowsNamedPipePath implementations by exporting a
single helper from the existing shared location and importing it in both
socketSpawnLock.ts and localIpcListenOptions.ts. Remove the local duplicate
while preserving the current trim, slash normalization, lowercasing, and Windows
named-pipe prefix check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.agents/skills/test/SKILL.md:
- Around line 69-73: Update the test command instructions so TEST_REVIEW_BASE is
resolved before the empty-feature-hint inference that runs git diff and git
status. Move that inference after the review-base setup, preserving both tracked
and untracked file detection and the existing --base behavior.
- Around line 303-305: Update each parity-pass context step to include untracked
files by appending git ls-files --others --exclude-standard to the existing
changed-file commands. Apply this in .agents/skills/test/SKILL.md at lines
303-305, 376-379, 447-449, and 527-529, and require the docs, mobile, CLI, and
TUI agents respectively to read or inspect those untracked files.

In @.github/workflows/ci.yml:
- Line 417: Update the actions/checkout@v4 step in the CI workflow to set
persist-credentials to false, ensuring the checkout token is not retained in
.git/config before the npm ci commands run.

In `@apps/ade-cli/src/cli.ts`:
- Line 14891: Update the CLI runtime-connect boundary that invokes
repairMachineRuntimeServiceConnection() to catch
RuntimeServiceRecoveryOwnedError and classify it as an expected
connection/conflict failure with a clear CLI message. Preserve the existing null
handling for blocked installs and allow unrelated errors to propagate normally.

In `@apps/ade-cli/src/lib/trustedWindowsTools.test.ts`:
- Around line 69-96: Update the child-process setup around the test’s module URL
and `tsxCli` resolution to invoke `tsx` through the package manager, using the
npm-script-compatible `npm exec tsx --eval ...` command rather than cwd-relative
`src/lib` and `node_modules/tsx/dist/cli.mjs` paths. Preserve the existing
`childScript` contents and result handling while ensuring the same
package-manager-provided binary is used locally and in CI.

In `@apps/ade-cli/src/serviceManager/installWindows.test.ts`:
- Line 175: Update the uniqueness assertion around the Set containing
stableArul, betaArul, and betaOtherUser to assert its size equals 3 rather than
using toHaveLength, ensuring duplicate task names are detected.

In `@apps/ade-cli/src/serviceManager/installWindows.ts`:
- Around line 598-617: Update uninstallWindowsService to resolve serviceName
with serviceCommand and construct the merged runtime environment from env plus
serviceCommand.env, matching installWindowsService and getWindowsServiceStatus.
Use that merged environment when resolving the launcher path and related service
identity so uninstall targets the same task, Run-key entry, and launcher created
by installation.

In `@apps/ade-cli/src/services/projects/machineLayout.ts`:
- Around line 49-78: The Windows pipe identity in windowsChannelIdentity must be
derived from the resolved channel label, matching localRuntimeConnectionPool.ts.
Keep the existing label resolution logic, but return label as identity instead
of using ADE_RUNTIME_SERVICE_NAME or ADE_PACKAGE_CHANNEL directly, so equivalent
channel configurations always use the same endpoint.

In `@apps/ade-cli/src/services/sync/syncHostSingleton.ts`:
- Around line 103-105: Update windowsPidStopCommand and the
buildQuitCommand/detectSyncHostSingletonConflict stop flow to preserve the lock
owner’s process identity, not only its PID. Include identity metadata in the
persisted Windows stop command, and validate that metadata against the current
process identity before invoking Stop-Process; reject mismatched owners without
killing the reused PID.

In `@apps/ade-cli/src/services/sync/syncService.ts`:
- Around line 1468-1473: Update the crdtSyncAvailable-false branch in the
blockingStateText expression to avoid asserting that crsqlite.dll failed to
load. Use a capability-level message covering both unavailable and
runtime-unusable CR-SQLite states, while preserving the existing
live-chat/terminal message and platform branching.

In `@apps/ade-cli/src/test/crrModelPickerWorker.ts`:
- Around line 27-39: Update the worker success path around the JSON output and
process.exit(0) so the process exits only after stdout has finished writing; use
the write callback or drain handling for process.stdout.write. Preserve the
existing serialized payload and Windows teardown behavior, and keep the error
path unchanged.

In `@apps/desktop/src/main/services/attention/attentionNotchHelper.ts`:
- Line 206: Update getHealth() so the unsupported-platform state is returned
before the disabled ADE Notch state, preventing non-darwin users from receiving
enablement instructions for an unavailable feature. Preserve the existing
disabled-state behavior and user-facing copy for supported platforms.

In `@apps/desktop/src/main/services/localRuntime/localRuntimeConnectionPool.ts`:
- Around line 2320-2358: Update connectSpawnedRuntime to immediately rethrow
LocalRuntimeCompatibilityError from connectClient instead of storing it in
lastError and retrying. Preserve the existing retry behavior for other
connection errors and retain the compatibility error instance, including its
pid, runtimeVersion, and runtimeBuildHash fields.

In `@scripts/dev-runtime-stop.mjs`:
- Around line 22-26: Update the usage/help text for the socket option near
parseArgs to describe the default as platform-specific instead of stating only
/tmp/ade-runtime-dev.sock, while preserving the existing argument parsing and
resolveDevSocketPath behavior.
- Around line 4-8: Update the cleanup logic in dev-runtime-stop.mjs to skip
fs.unlinkSync(socketPath) when isWindowsNamedPipe is true, while preserving the
existing tcp:// skip guard. Ensure unlinkSync runs only for filesystem socket
paths.

In `@scripts/validate-docs.mjs`:
- Around line 89-105: Update targetExists to reject normalized targets equal to
"/.." or prefixed by "/../" before constructing repoPath or performing
filesystem access. Add a validation fixture covering a relative link such as
"../../outside.mdx" and assert that validation fails.

---

Outside diff comments:
In `@apps/ade-cli/src/headlessLinearServices.ts`:
- Around line 1121-1136: Update requestRawWithCredentialFallback to pass the
injected options.fetchImpl through the requestGithubRawWithCredentialFallback
call instead of always using fetchGitHub, while preserving the existing
credential candidates, user agent, auth-missing message, and fallback logging.

---

Nitpick comments:
In `@apps/ade-cli/src/serviceManager/installWindows.test.ts`:
- Around line 495-526: Add an uninstall test that omits serviceName and
launcherPath, supplies ADE_PACKAGE_CHANNEL and ADE_HOME through command.env, and
verifies identity resolution uses the install-path task name as the Run-key
value name. Anchor the assertions in uninstallWindowsService and the existing
buildWindowsRunKeyQueryArgs helpers, while preserving the current cleanup and
call-sequence expectations.

In `@apps/ade-cli/src/serviceManager/installWindows.ts`:
- Around line 169-174: Consolidate the duplicate PowerShell quoting logic by
exporting the existing powerShellSingleQuotedLiteral implementation from one
module and importing it in the other, including the Windows scheduled-task and
supervisor command builders. Remove the local duplicate and retain identical
single-quote escaping and NUL-byte validation through the shared helper.

In `@apps/ade-cli/src/serviceManager/windowsSupervisor.ts`:
- Line 108: Update the PowerShell PID-record write in the Windows supervisor to
use UTF-8 encoding without a BOM instead of [Text.Encoding]::ASCII, preserving
non-ASCII characters in lastLaunchError and keeping compatibility with the
reader’s utf8 decoding.

In `@apps/ade-cli/src/services/projects/machineLayout.test.ts`:
- Around line 33-54: Add a test alongside the Windows channel layout case that
compares two resolveMachineAdeLayout calls: one using ADE_HOME and
ADE_PACKAGE_CHANNEL, and the other using the same values plus
ADE_RUNTIME_SERVICE_NAME set to the beta service name. Assert both results have
the same socketPath, documenting the expected service-name identity behavior.

In `@apps/ade-cli/src/services/runtime/socketSpawnLock.ts`:
- Around line 93-99: Consolidate the duplicate isWindowsNamedPipePath
implementations by exporting a single helper from the existing shared location
and importing it in both socketSpawnLock.ts and localIpcListenOptions.ts. Remove
the local duplicate while preserving the current trim, slash normalization,
lowercasing, and Windows named-pipe prefix check.

In `@apps/desktop/scripts/dev.cjs`:
- Around line 334-341: Update the ready-marker watcher around
lastReadyMarkerMtimeMs to detect changes by reading and comparing the marker’s
content rather than relying on mtimeMs; initialize the previous content from the
existing marker and update it before calling requestElectronRestart. Remove the
now-unused initialReadyMarkerStat value and retain the shuttingDown and
missing-link guards.

In `@scripts/dev-shared.mjs`:
- Around line 260-270: Update the candidate filtering in the npm entry-point
resolution flow around candidates and npmCliPath to accept only existing
JavaScript entry points with .js, .cjs, or .mjs extensions, rejecting
npm_execpath values such as npm.cmd or shell scripts before selection. Preserve
the existing fallback candidates and clear error behavior when no valid path
remains.

In `@scripts/dev-shared.test.mjs`:
- Around line 71-94: Add a test for resolveNpmInvocation using Windows options
and pathExists: () => false, asserting that it throws when no npm entry point
can be resolved and validating the resulting error message. Keep the existing
successful invocation test unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a9c9e635-d5a3-4e79-8de3-e25ec3655c5b

📥 Commits

Reviewing files that changed from the base of the PR and between 95561c0 and 16c1627.

⛔ Files ignored due to path filters (3)
  • AGENTS.md is excluded by !*.md
  • docs/ARCHITECTURE.md is excluded by !docs/**
  • docs/playbooks/ship-lane.md is excluded by !docs/**
📒 Files selected for processing (92)
  • .agents/skills/quality/SKILL.md
  • .agents/skills/quality/references/ade-review-rules.md
  • .agents/skills/quality/references/correctness-security-review.md
  • .agents/skills/quality/references/thermo-nuclear-review.md
  • .agents/skills/ship/SKILL.md
  • .agents/skills/test/SKILL.md
  • .github/workflows/ci.yml
  • apps/ade-cli/src/bootstrap.test.ts
  • apps/ade-cli/src/cli.ts
  • apps/ade-cli/src/headlessLinearServices.test.ts
  • apps/ade-cli/src/headlessLinearServices.ts
  • apps/ade-cli/src/lib/trustedWindowsTools.test.ts
  • apps/ade-cli/src/lib/trustedWindowsTools.ts
  • apps/ade-cli/src/multiProjectRpcServer.ts
  • apps/ade-cli/src/serviceManager/common.test.ts
  • apps/ade-cli/src/serviceManager/common.ts
  • apps/ade-cli/src/serviceManager/index.ts
  • apps/ade-cli/src/serviceManager/installWindows.test.ts
  • apps/ade-cli/src/serviceManager/installWindows.ts
  • apps/ade-cli/src/serviceManager/windowsSupervisor.test.ts
  • apps/ade-cli/src/serviceManager/windowsSupervisor.ts
  • apps/ade-cli/src/services/agentRegistry.test.ts
  • apps/ade-cli/src/services/builtInBrowser/desktopBridgeClient.test.ts
  • apps/ade-cli/src/services/modelPickerStore.test.ts
  • apps/ade-cli/src/services/projects/machineLayout.test.ts
  • apps/ade-cli/src/services/projects/machineLayout.ts
  • apps/ade-cli/src/services/projects/projectIconResolver.test.ts
  • apps/ade-cli/src/services/projects/projectRegistry.test.ts
  • apps/ade-cli/src/services/projects/projectRegistry.ts
  • apps/ade-cli/src/services/runtime/brainLoopWatchdog.test.ts
  • apps/ade-cli/src/services/runtime/brainLoopWatchdog.ts
  • apps/ade-cli/src/services/runtime/localIpcListenOptions.test.ts
  • apps/ade-cli/src/services/runtime/localIpcListenOptions.ts
  • apps/ade-cli/src/services/runtime/socketSpawnLock.ts
  • apps/ade-cli/src/services/sync/machineIdentitySigningStore.test.ts
  • apps/ade-cli/src/services/sync/syncHostService.test.ts
  • apps/ade-cli/src/services/sync/syncHostService.ts
  • apps/ade-cli/src/services/sync/syncHostSingleton.test.ts
  • apps/ade-cli/src/services/sync/syncHostSingleton.ts
  • apps/ade-cli/src/services/sync/syncLoopbackCollision.test.ts
  • apps/ade-cli/src/services/sync/syncPairingStore.test.ts
  • apps/ade-cli/src/services/sync/syncService.test.ts
  • apps/ade-cli/src/services/sync/syncService.ts
  • apps/ade-cli/src/test/crrModelPickerWorker.ts
  • apps/ade-cli/src/test/filesystem.ts
  • apps/ade-cli/src/tuiClient/app.tsx
  • apps/ade-cli/src/tuiClient/imageTargets.ts
  • apps/desktop/scripts/dev.cjs
  • apps/desktop/src/main/main.ts
  • apps/desktop/src/main/services/attention/attentionAccountCoordinator.test.ts
  • apps/desktop/src/main/services/attention/attentionAccountCoordinator.ts
  • apps/desktop/src/main/services/attention/attentionNotchHelper.test.ts
  • apps/desktop/src/main/services/attention/attentionNotchHelper.ts
  • apps/desktop/src/main/services/computerUse/localComputerUse.test.ts
  • apps/desktop/src/main/services/computerUse/localComputerUse.ts
  • apps/desktop/src/main/services/localRuntime/localRuntimeConnectionPool.test.ts
  • apps/desktop/src/main/services/localRuntime/localRuntimeConnectionPool.ts
  • apps/desktop/src/main/services/remoteRuntime/runtimeRpcClient.ts
  • apps/desktop/src/main/services/runtime/projectRecoveryService.ts
  • apps/desktop/src/main/services/shared/utils.ts
  • apps/desktop/src/main/services/storage/diskPressure.ts
  • apps/desktop/src/main/windowAppearance.test.ts
  • apps/desktop/src/main/windowAppearance.ts
  • apps/desktop/src/renderer/components/activity/ActivitySettingsPopover.test.tsx
  • apps/desktop/src/renderer/components/activity/ActivitySettingsPopover.tsx
  • apps/desktop/src/renderer/components/activity/ActivitySettingsPopover.windows.test.tsx
  • apps/desktop/src/renderer/components/activity/HeaderActivityControl.test.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatPane.test.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
  • apps/desktop/src/renderer/components/lanes/CreateLaneDialogHostBinding.test.tsx
  • apps/desktop/src/renderer/components/lanes/laneMachines.test.ts
  • apps/desktop/src/renderer/components/lanes/laneMachines.ts
  • apps/desktop/src/renderer/components/settings/ActivitySection.test.tsx
  • apps/desktop/src/renderer/components/settings/ActivitySettingsControls.tsx
  • apps/desktop/src/renderer/lib/platform.test.ts
  • apps/desktop/src/renderer/lib/platform.ts
  • apps/desktop/src/renderer/main.tsx
  • apps/desktop/src/shared/machineIdentity.ts
  • apps/desktop/src/shared/types/attention.ts
  • apps/desktop/src/shared/types/core.ts
  • apps/desktop/src/shared/types/sessions.ts
  • apps/desktop/src/shared/types/sync.ts
  • apps/desktop/tsup.config.ts
  • apps/ios/ADE/Shared/AttentionActionIntents.swift
  • apps/ios/ADE/Views/Activity/ActivityDrawerModel.swift
  • scripts/dev-desktop.mjs
  • scripts/dev-runtime-stop.mjs
  • scripts/dev-shared.mjs
  • scripts/dev-shared.test.mjs
  • scripts/run-desktop-test-shards.mjs
  • scripts/validate-docs.mjs
  • scripts/validate-docs.test.mjs

Comment thread .agents/skills/test/SKILL.md
Comment thread .agents/skills/test/SKILL.md
Comment thread .github/workflows/ci.yml
Comment thread apps/ade-cli/src/cli.ts
Comment thread apps/ade-cli/src/lib/trustedWindowsTools.test.ts
Comment thread apps/desktop/src/main/services/attention/attentionNotchHelper.ts
Comment thread scripts/dev-runtime-stop.mjs
Comment thread scripts/dev-runtime-stop.mjs
Comment thread scripts/validate-docs.mjs
nsxdavid and others added 22 commits August 2, 2026 13:46
Move the shared runtime initialize timeout contract into the foundation layer while deferring release-repository wiring to packaging.

Co-authored-by: David Whatley <nsxdavid@gmail.com>

Based-on: nsxdavid/ADE#999
Based-on: nsxdavid/ADE#999

Co-authored-by: David Whatley <nsxdavid@gmail.com>
Based-on: nsxdavid/ADE#999

Co-authored-by: David Whatley <nsxdavid@gmail.com>
Based-on: nsxdavid/ADE#999

Co-authored-by: David Whatley <nsxdavid@gmail.com>
Prevent the CLI from launching a competing manual brain while a registered supervisor owns readiness recovery, and make stack readiness block on exact-SHA proof required at the current position.

Co-authored-by: David Whatley <nsxdavid@gmail.com>

Based-on: nsxdavid/ADE#999
Route the CLI brain listener through intended-user named-pipe options and replace an empty CI filter with a real native Windows contract test.

Co-authored-by: David Whatley <nsxdavid@gmail.com>

Based-on: nsxdavid/ADE#999
Resolve ADE-owned PowerShell, registry, task scheduler, and process termination commands through the kernel SystemRoot alias, validate their canonical System32 paths, and persist the absolute PowerShell path for startup supervision.

Add native Windows cwd, PATH, SystemRoot, and windir poisoning regressions covering service and clipboard launch paths.

Based-on: nsxdavid/ADE#999
Move platform-neutral Activity naming and native Notch gating into the foundation layer so every stacked diff is internally testable.

Co-authored-by: David Whatley <nsxdavid@gmail.com>

Based-on: nsxdavid/ADE#999
Stack-ready mode was attestation-only: it required a coordinator-created PR, refused to commit, push, open a PR, or fix red CI/review, and converted actionable feedback into a stack-coordinator-fix-required bail-out. A lane could not reach ready-stacked without a human doing its work first.

Stack mode now runs the same loop as ordinary /ship — Phase 0 through Phase 5, the same poll/decide/fix machinery, the same 5-iteration budget — and stops one step short of landing. The lane commits and pushes its own layer branch, opens its PR against the resolved direct parent, polls CI and review bots, fixes red CI and verified findings on its own layer, and rebinds commit-bound quality revalidation to the exact resulting head.

Reserved to the coordinator: rebases and restacks, gh stack sync/rebase/push/submit, base retargeting, and the merge. Force-finalize and every bypass-review path stay off in stack mode; the spent iteration budget escalates instead of forcing.

The stack-coordinator-* states remain, re-scoped to what the lane genuinely cannot do, with a Stack escalation states table naming the exact case and the coordinator action for each.

ready-stacked can no longer be recorded over a known gap. Every required proof scenario needs a link bound to the validated head, or a deferredProofScenarios entry naming a higher position and branch that exist in this stack; the top layer defers nothing, and the state-file jq check enforces it.

Based-on: nsxdavid/ADE#999
(cherry picked from commit d0f922e10d292c1fd887ac19c82a8736b676def1)
The pre-channel Windows installer registered a single global "ADE Runtime"
scheduled task. Install and uninstall both removed that name unconditionally
before touching the channel-scoped task, so a Beta install, repair, or
uninstall would end and delete a Stable channel's legacy runtime task -- a
side-by-side isolation violation that silently kills a running Stable brain.

Legacy migration is still needed, so gate it on ownership instead of dropping
it: query the legacy task's actions and migrate only when its Execute path and
CLI entry match the current channel's serve command. A legacy action never
carried the runtime environment, so ADE_HOME is not recoverable from it; the
packaged executable plus entry script is the ownership evidence that survives.
Requiring both matters because development builds of every channel share
process.execPath. When the action cannot be read the operation fails rather
than guessing, and a foreign legacy task is left running untouched.

The existing migration test asserted the broken behavior; it now pins the
owned-task path, and new regressions assert the recorded schtasks argv for a
Beta install and uninstall that find a Stable-owned legacy task.

Based-on: nsxdavid/ADE#999
(cherry picked from commit d094524ef1662382ac09a3160584c3e7a2ea4beb)
getWindowsServiceStatus claimed "A legacy ADE Scheduled Task is installed...
Run `ade brain start` to migrate it", but it only ever queried the
channel-scoped task name, never the global pre-channel "ADE Runtime" task. The
message could not fire for the situation it described.

This matters more now that legacy migration is ownership-gated: a legacy task
belonging to another install is deliberately left running, and until now no
command anywhere told the user it was there.

Status now probes the global task on the otherwise-"not installed" path, where
the answer is actionable and no extra spawn is added to a healthy channel, and
reuses isWindowsLegacyTaskOwnedByCommand to separate three real states: a task
this channel owns (migratable via `ade brain start`), one belonging to a
different ADE install (left running on purpose), and one whose owner could not
be determined. The pre-existing channel-scoped message now says so explicitly
so the two cannot be confused.

The probe is supplementary, so its failure degrades to "no legacy task
detected" instead of turning an answerable status into an error.

Based-on: nsxdavid/ADE#999
(cherry picked from commit f2349cc170b12789796f217f5fd73a1f7ba4a91e)
validate-docs.mjs fed native `path.relative()` output straight into its
route/link namespace. On Windows every doc id came out backslash-separated
(`configuration\ai-providers`), so no `.mdx` route ever matched a
forward-slash link target and the `docs/` prefix test never fired -- 248
phantom errors, exit 1, and all 77 `docs/**/*.md` files silently skipped.
Linux CI never saw it.

Route ids are a URL-ish namespace and are now forward-slash on every host.
`toRouteId()` is the single boundary where a native path becomes an id;
`targetExists()` and the doc reader convert back to native segments before
touching the filesystem. `toRouteId()` is the identity function when
`path.sep === "/"`, so POSIX behaviour is bit-for-bit unchanged.

Also sorts directory entries so error output is ordered identically on
both platforms, and extracts the pure helpers behind an `isDirectRun`
guard (matching scripts/posthog/provision.mjs) so the separator handling
is unit-testable from a POSIX runner.

Windows now reports 0 errors / exit 0, matching ubuntu CI. No validation
rule was loosened.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 3689bebce3a489ef3e5fbaa18fc18574be72cddd)
PR1 added Windows runtime startup timing and a `connectSpawnedRuntime`
retry path, but the native Windows CI job ran only three unrelated
desktop files, so none of it was gated. Adding the owning suite to that
job first required making the suite runnable on Windows: it was 50
passed / 12 failed natively under Node 22.

All 12 were test-layer portability defects, not production bugs:

- Eight daemon-backed tests hardcoded `<ADE_HOME>/sock/ade.sock`. Node
  maps a path-style endpoint onto a named pipe on Windows, so a
  filesystem path is not a connectable address and each died with
  `connect ENOENT`. They now derive the endpoint through
  `resolveMachineAdeLayout`, exactly as production does, which is
  byte-identical on macOS/Linux and yields the real per-user pipe on
  Windows.
- Those same eight also hit a second, stacked failure: the tsx loader
  was injected as `--import <absolute path>`. Node's ESM loader rejects
  a Windows absolute path (ERR_UNSUPPORTED_ESM_URL_SCHEME, "Received
  protocol 'c:'"), killing the spawned daemon before it could listen and
  surfacing only as a downstream connect error. It now passes a file://
  URL, which is equally valid on POSIX.
- The NODE_PATH test compared against forward-slash literals although
  the helper joins with the host path module; it now joins the
  expectation the same way.
- Two release-build-output tests compared raw POSIX literals against
  values the production helpers return `path.resolve`d.

No assertion was dropped or skipped; the POSIX expectations are
unchanged. The suite is now 62 passed / 0 failed on Windows, and it is
gated by a new step in the windows-foundation job.

The readiness wait is also given the same Windows budget production
already uses for runtime startup (30s vs 10s), since a cold Windows
daemon start is genuinely slower. It is a ceiling rather than a sleep,
so the suite still finishes in ~38s locally.

Based-on: nsxdavid/ADE#999
(cherry picked from commit fa2f30e2a9237b2350a9e9c7a5c0ae820e0e29c9)
A "This Mac" -> "This computer" copy sweep also matched the substring
inside the machine-name fixture "This MacBook", leaving the nonsense
name "This computerBook" in the Attention coordinator suite.

That silently weakened the copy/parity regression: the assertion that
the degraded-availability message names the host machine was checking
for a string no machine could ever be called, so it could no longer
catch the host name being dropped or replaced.

These are user machine *names* (test data), not product copy, and were
never in the sweep's scope: the same file's "Studio Mac" and "First Mac"
fixtures are untouched, and the identical "This MacBook" fixture on the
inline override at line 85 survived. Restoring the name makes the file
self-consistent again.

Swept the repo for other collateral damage from the same pass; these
were the only three occurrences. Every remaining `computer`-adjacent
token is a legitimate pre-existing identifier (`computerUse`, and the
`desktopcomputer` / `laptopcomputer` SF Symbol names on iOS).

Based-on: nsxdavid/ADE#999
(cherry picked from commit 25df8905cd784637e38db812a5f67d0c269e660c)
…nt guard

`isPrimaryMachineRuntimeSocketPath` refuses to spawn an app-owned brain
onto the machine's primary runtime endpoint. On Windows it was
defeatable, because it compared named pipes as raw strings.

Win32 accepts `/` and `\` interchangeably in a pipe path and matches
pipe names case-insensitively, so `\.\pipe\ade-runtime-stable-abc`,
`//./pipe/ade-runtime-stable-abc`, and a case variant all address one
pipe. Verified on Windows 11 / Node 22.13.1: a server listening on the
first accepts connections addressed to the other two.
`isAdeRuntimeNamedPipePath` already encodes this by accepting both
separator forms after lowercasing, but `normalizeComparableSocketPath`
returned pipe paths verbatim, so equivalent spellings compared unequal.

Because `createConnection` honours an operator-supplied
ADE_RUNTIME_SOCKET_PATH, any equivalent spelling of the layout pipe slid
past the guard and got a second brain on the machine's primary sync
endpoint -- the split-brain the guard exists to prevent.

Pipe paths are now folded to a lowercase, backslash-separated
comparison key. That key is used only to compare: it is built inside a
module-private helper whose sole consumer returns a boolean, and every
address that is connected to, listened on, probed, logged, or reported
still comes from the caller's original `socketPath`, so the lowercasing
cannot reach a real endpoint. POSIX socket paths keep `path.resolve`
and stay case-sensitive, since `/tmp/ADE.sock` and `/tmp/ade.sock` are
genuinely different files.

`defaultChannelRuntimeSocketPaths` -- the cross-channel half of the same
guard -- was separately dead on Windows. It hardcoded
`~/.ade{,-alpha,-beta}/sock/ade.sock`, addresses that never exist there,
so a Windows user running Stable and Beta together got none of the
protection macOS users get. It now derives each channel endpoint through
`resolveMachineAdeLayout`, the same production derivation used
everywhere else, which is byte-identical on POSIX. ADE_PACKAGE_CHANNEL
and ADE_RUNTIME_SERVICE_NAME are dropped while enumerating: both
outrank the home-name-inferred channel, so leaving them in would pin all
three homes onto the running channel's own pipe.

Regressions assert the guard's decision through `createConnection`, not
the normalizer's return value, with `spawnRuntime` stubbed to throw so a
guard that lets the spawn through fails loudly. All three Windows cases
fail without this change; the cross-channel one reported
`blocked: false, spawnAttempted: true` with requested
`\.\pipe\ade-runtime-beta-*` against layout
`\.\pipe\ade-runtime-stable-*`. A POSIX-only case pins that the pipe
canonicalization does not bleed onto case-sensitive filesystem sockets.

Based-on: nsxdavid/ADE#999
(cherry picked from commit c95efe27257125840f7bc4204156be86b028bed2)
`scripts/validate-docs.test.mjs` (7 tests, `node --test`) covers the
docs validator that the `validate-docs` job runs, but nothing invoked
it. Added its path to the existing `node --test` step in
`typecheck-ade-cli`, alongside the archive and packaging guards.

The file arrives with a sibling lane and does not exist on this branch,
so this step cannot pass until the stack is composed; it is wired blind
by design and needs verifying after composition.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 021e865baeaa4a50885b66c474bba035ff088a55)
…fires

`readParentPid` is the default ancestry backend for
`isCurrentProcessDescendantOfPid`, which `runtimeSelfShutdownBlock` and
`runtimeServiceSelfShutdownBlock` use to refuse `ade runtime repair` /
`ade runtime stop` when the command was issued from a shell running inside
the runtime it is about to kill. It only ever ran `ps -o ppid= -p <pid>`.

On Windows that query cannot succeed. Git Bash ships a `ps` that is found
and then rejects the POSIX flags (status 1, no error code); a box without
Git Bash reports ENOENT. Either way `status !== 0` returned null, the
ancestry walk terminated on its first iteration, and the guard never fired
— a user tore down their own live runtime and every active session on it
with no warning.

Dispatch per platform, matching how `serviceManager/index.ts` dispatches
`getRuntimeServiceMainPid`. The win32 branch reads ParentProcessId from
`Get-CimInstance Win32_Process` (not `wmic`, which is deprecated and being
removed from Windows) through `resolveTrustedWindowsTool("powershell")`,
so a poisoned PATH/SystemRoot cannot redirect a query that gates a
destructive operation.

Ancestry lookups now distinguish "no further parent" from "the query could
not be answered". The guard fails CLOSED on the latter: a false block costs
one refusal that names the ADE_ALLOW_RUNTIME_SERVICE_SELF_MUTATION=1
override, while a false allow destroys live state. Only the first is
recoverable. POSIX keeps its previous end-of-chain behaviour because `ps`
exits 1 for both cases and cannot tell them apart.

The existing tests injected a fake `parentPid` on all three cases, so
`readParentPid` was never reached and the Windows CI job stayed green over
a symbol that could not work. The added coverage drives the real default
backend, plus two zero-mock cases that check the resolved parent against
`process.ppid` on a real Windows host.

Based-on: nsxdavid/ADE#999
(cherry picked from commit c8d6e4d0f951c6583ed806a13790cbfbc3a5a285)
`inspectSyncListenerPort` shelled out to `lsof` and `ps` unconditionally.
Neither exists on Windows — and under Git Bash `ps` is found but rejects the
POSIX flags — while `execFileText` swallows the failure and returns null, so
every Windows diagnosis came back with an empty `holders`.

Two consequences follow from that empty list. `createSharedSyncListener`
diagnoses a port only after EADDRINUSE, and with no holders `findStaleHolder`
can never recognise a wedged same-channel sibling, so the reclaim path is
dead and mobile sync drifts onto a fallback port permanently — the port
paired phones have saved is never recovered. The same empty list also stops
the port being marked occupied, so the bind burns all eight preferred-port
retries before drifting. And `ade doctor` fell through to its "no holders
visible to this user" branch, which advises `tailscale serve status` and a
root-owned tailscaled holder: advice that cannot apply on Windows.

Dispatch per platform. The win32 branch pairs `Get-NetTCPConnection` with
`Get-CimInstance Win32_Process` in a single PowerShell invocation, resolved
through `resolveTrustedWindowsTool`, and returns the pid, command line, and
an ISO creation time for the PID-reuse guard. One spawn replaces the 1 + 2N
the POSIX path needs. `Get-NetTCPConnection` is the supported replacement
for scraping `netstat`; when it is unavailable the query simply yields no
holders, which is the current behaviour, so a `netstat -ano` fallback would
add a PATH-reachable executable for no coverage gain.

The 200ms budget that suits lsof/ps would kill every PowerShell query before
it answered — the real query takes ~2s on a warm host — so the timeout is
now per-call.

Added coverage drives the real dispatch rather than the injected `inspectPort`
seam the existing reclaim test uses, including a zero-mock case that binds a
port and asserts this process is named as its holder on a real Windows host.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 8144099e63817d3fd24439584b849f83f687f0ef)
A platform-gated test assertion could exist with no CI runner that ever
executed it, and nothing detected that. The gate reported as "skipped" on
every runner the repo has -- or, in the `if (process.platform === "win32")
return;` form, as a green pass -- so the file's presence in a job read as
coverage that did not exist.

scripts/validate-platform-gates.mjs parses every apps/**/*.test.ts(x) for
platform gates in each form this repo uses: it.skipIf / it.runIf, the
ternary-to-it form, alias constants such as `itUnix` and `crdtHostIt` whose
call sites read as a plain `it(...)`, and the vacuous early `return`. It
then parses .github/workflows/ci.yml for which test files each job runs and
on which runs-on, and fails when a gated assertion has no runner -- including
when no job for that platform exists at all, which is the case today for
macOS.

Adoption is incremental. scripts/platform-gate-baseline.json records the 16
known violations, keyed on (file, kind, form, requires) rather than line
number so it survives edits. It is a ratchet: a new or grown entry fails
immediately, and an entry that shrank fails too, with an instruction to
re-record, so the backlog cannot go stale. `// WINDOWS-GATE: <reason>` and
`// DARWIN-GATE: <reason>` are the documented escape hatch.

The check is dependency-free and rides in the existing validate-docs job;
its node --test suite joins the existing typecheck-ade-cli step. No new job.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 9105ca507743aac98cf3d5bc15170261d6930378)
arul28 added 5 commits August 2, 2026 13:46
windows-foundation ran 17 files. Two groups were missing.

The suites docs/development/windows-port-lane.md names as the Windows
validation -- pathUtils and processExecution, plus the window, app-control,
and auto-update services -- had an empty intersection with this job, so the
documented gate had never actually run on Windows. Measured here: 5 files,
87 tests, ~4.3s.

trustedWindowsTools is a security control whose only substantive case is
win32-gated, so before this it ran on no runner at all; the credential store
and the `ade://` deeplink command-injection guard are both filesystem- and
quoting-sensitive in ways a Linux-hosted job cannot exercise. Measured here:
3 files, 54 tests, ~3.5s.

All eight files verified green on a native Windows 11 host under Node
22.13.1. Total measured wall-clock added: 8-13s warm against a 25 minute
budget.

Deliberately not added:
  - ptyService.test.ts, 81 of 354 cases fail natively -- the reap path
    asserts POSIX process-group signalling, `kill(-pid, "SIGKILL")`;
  - cli.test.ts, 5 of 340 fail natively on POSIX-absolute path assumptions
    such as expecting "/explicit/project-root" where Windows resolves
    "C:\explicit\project-root";
  - kvDb.rebuildRecovery.test.ts and the CR-SQLite/kvDb group, where 12
    cases fail with EBUSY on `fs.rmSync` because a SQLite handle is not
    closed before teardown -- fatal on Windows, a no-op on POSIX.
Each needs a source fix before it can join a required job.

Adding trustedWindowsTools to the job retires its two baseline entries, so
the platform-gate baseline shrinks from 16 violations to 14.

Based-on: nsxdavid/ADE#999
(cherry picked from commit a4a30a980099ce9b07cc72c3b4b56ba1562858d8)
…elper

PR1 renamed the local machine's absolute display name from the macOS-only
"This Mac" to the platform-neutral "This computer" and moved it behind
`shared/machineIdentity.ts`, because ADE now runs on Windows and calling a
Windows box "This Mac" is wrong. Four renderer tests still spelled the old
literal and failed against the new implementation.

Rather than re-typing the new string, the assertions now import
THIS_MACHINE_NAME and compose from it: TopBar matches the machine menu on a
regex built from the constant (the menu appends a lane count, so the
accessible name is a substring), PersonalChatsPage and ProjectlessSidebar
interpolate it into the picker's aria-label sentence, and SessionCard's
hover-card row checks it directly. A future rename of the label now moves
these tests with it instead of breaking them a fourth time.

ProjectlessSidebar was not failing — it feeds the label in as a prop — but it
is the same fixture and is switched over for the same reason. The SessionCard
case is renamed to "on this computer": it describes local-machine behaviour,
not Apple hardware. Docs that quoted the constant's value, the machine
picker's option label, or the push-divergence warning are corrected; the
"This Mac" card in Connections is a component name whose UI copy PR1 did not
change, so those references stand.

Based-on: nsxdavid/ADE#999
(cherry picked from commit d6fc636843a904512cadfa32ebc9d6525784f333)
The docs-validator guard landed with the foundation layer, so the path it
runs resolves on this branch. The note described a transient state during
stack composition.

Based-on: nsxdavid/ADE#999
The holder lookup is win32-gated: on Windows it goes through PowerShell
rather than lsof/ps, and a broken lookup silently disables stale-port
reclaim instead of failing. Only a Windows runner executes that gate.

Caught by validate-platform-gates at stack composition -- the gate and the
checker landed in separate lanes, so neither could see the gap alone.

Based-on: nsxdavid/ADE#999
`windows-foundation` failed five projectIconResolver cases on every stacked
PR. The GitHub runner's account is `runneradmin`, so `os.tmpdir()` reports the
8.3 short form `C:\Users\RUNNER~1\AppData\Local\Temp`. The fixtures
canonicalized that with the JS `fs.realpathSync`, which resolves symlinks but
leaves 8.3 aliases alone, while the resolver canonicalizes with
`fs.realpathSync.native`, which expands them. Every `path.join(root, …)`
expectation then compared two spellings of one directory.

Point both icon fixtures at `fs.realpathSync.native` so they build roots in the
spelling the resolver answers in.

The investigation also turned up a real defect behind the fixture mismatch.
`resolveProjectIcon`, `resolveProjectIconPath`, `setProjectIconOverride`,
`removeProjectIconOverride` and `setProjectIconOverrideFromSelection` normalized
the project root with `path.resolve` alone, while every path they return is
realpath-canonical. A root that arrives as an 8.3 short name — or through a
junction or symlink — therefore makes `toProjectRelative` emit a `..`
traversal, and `setProjectIconOverride` persists that traversal into the
shared, committed `.ade/ade.yaml` as the project's `iconPath`:

    iconPath: ../../../../shortpath-repro/runneradmin/Temp/…/brand/custom-icon.png

Today's shipped callers all pre-canonicalize (the desktop IPC through
`resolveAllowedProjectRoot`, the CLI through `normalizeProjectRootPath`), so
this is latent rather than reachable — but the resolver never stated that
precondition and cannot rely on it. Canonicalize the root inside the module
with the realpath it already uses for candidates, and cover it with a desktop
test that drives a junction-spelled root; that test fails on the old code on
every platform. A matching CLI test pins the "icons come back in the
filesystem's spelling" contract the fixtures depend on.

Verified by reproducing the runner exactly: with `TEMP` pointed at a real 8.3
short path, the step's twelve suites failed 5/183 before and pass 189/189 after.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 106cb1d69f2e748c14cd93832647055a77e67ce6)
@arul28
arul28 force-pushed the codex/windows-foundation-runtime branch from 74f7ca4 to c70076e Compare August 2, 2026 17:51
arul28 and others added 16 commits August 2, 2026 14:39
`isCrsqliteAvailable()` resolves `vendor/crsqlite/<platform>-<arch>/`, and
only darwin-arm64, darwin-x64, and win32-x64 are vendored. `test-desktop`
runs on ubuntu-latest, where that gate is false, so 57 tests across kvDb,
kvDb.migrations, kvDb.sync, deviceRegistryService, syncHostService, and
syncService skip silently — including two files that skip in full. The
ubuntu shard logs confirm it: syncService 19/19 skipped, kvDb.sync 10/10
skipped, syncHostService 17 of 24, kvDb 9 of 20, and one `it.skipIf` each
in kvDb.migrations and deviceRegistryService. No other job picked them up,
so the CRDT replication, sync host, and device registry contracts had no
coverage on any runner.

windows-foundation already runs on windows-latest with the vendored
crsqlite.dll present, so it is the one place these can execute. Run the
six suites there. Locally all 88 tests execute with zero skips.

kvDb.rebuildRecovery.test.ts is deliberately excluded: its temp-dir
teardown unlinks a still-open SQLite handle and fails EBUSY on Windows.

Based-on: nsxdavid/ADE#999
(cherry picked from commit e487c79457e66dc86657e5a8bd6c471ef7b23a7d)
`windows-foundation` failed four localRuntimeConnectionPool cases on every
stacked PR, all with the same shape:

    expected 'C:\Users\runneradmin\AppData\Local\Te…'
         to be 'C:\Users\RUNNER~1\AppData\Local\Temp\…'

Same bug class as 106cb1d6. The GitHub runner's account is `runneradmin`, so
`os.tmpdir()` reports the 8.3 short form `C:\Users\RUNNER~1\AppData\Local\Temp`.
Five assertions compared `fs.realpathSync(registered.rootPath)` against
`fs.realpathSync(projectRoot)`, and the JS `fs.realpathSync` resolves symlinks
but leaves 8.3 aliases alone. The runtime registers roots through
`normalizeProjectRootPath` -> `realpathIfExists` -> `fs.realpathSync.native`,
which does expand them, so the two sides named one directory with two
spellings. The earlier 8.3 sweep predated the `resolveMachineAdeLayout`-derived
socket path that let these daemon-backed tests run on Windows at all, so it
never saw them.

This is a fixture defect, not a production one: the value coming back over the
wire is the canonical long form, which is what the registry is supposed to
return. Point the fixtures at the runtime's own `realpathIfExists` through a
single named helper, and route the one assertion that already reached for
`fs.realpathSync.native` through it too, so the file has one canonicalizer
rather than three spellings of the same intent.

Reproduced the runner exactly by pointing `TEMP`/`TMP` at a real 8.3 path: the
suite went 4 failed / 61 passed / 1 skipped before and 65 passed / 1 skipped
after, and is unchanged at 65 passed / 1 skipped under a normal `TEMP`.

Swept the rest of the file and every other suite in the `windows-foundation`
job for the same JS-vs-native mismatch; these five were the only ones. The
remaining `fs.realpathSync` fixture in `apps/ade-cli/src/bootstrap.test.ts`
matches its production counterpart, which also uses the JS realpath, so both
sides agree in either spelling.

Based-on: nsxdavid/ADE#999
(cherry picked from commit f065f68950aa878ea9007ab3ed14bba8c19abf02)
The windows-foundation "service, layout, and IPC contracts" step went red on
a runner that was ~6x slower than its peers: the same 12 files finished in
17.98s on the sibling job for the branch stacked directly on top of this one,
and in 115.50s here. Nothing in the composed tree explains it — the failing
files' import graph contains no behavioural change from this layer — but every
win32-gated probe that waits on a real detached subprocess has a hard-coded
deadline with no headroom, so a slow host turns each of them into a null read:

  - readWindowsParentPid gave powershell.exe + the first CIM call of the
    session 5s. On a loaded host that expires, and because a timeout is
    indistinguishable from a broken mechanism the lookup degrades to
    PARENT_PID_UNKNOWN. That is a product bug, not just a test one: the guard
    fails closed, so a busy machine makes ADE refuse a runtime teardown the
    user is entitled to. The ancestry walk stops at the first unknown, so the
    wider budget is spent at most once per chain.
  - The supervisor, bootstrap, and CRR-worker specs waited 5s/5s/15s on a
    detached PowerShell or a cold tsx child, then asserted on whatever had been
    written by then. The assertions are unchanged; only the patience is.
  - The bootstrap spec's teardown read the pid record once to find the
    supervisor to kill. Losing that race against the supervisor's first
    Write-PidRecord orphaned a process that kept restarting its child for the
    rest of the run, holding the temp tree open (EBUSY on unlink) and starving
    every later suite. Teardown now waits for the record before giving up.

Reproduced by pinning the run to two logical CPUs under contention, which
yields the same "expected null to be +0" and "expected 'unknown' to be <pid>"
failures seen across this branch's runs; the same starved run is green after,
and leaves no orphaned supervisor.

Based-on: nsxdavid/ADE#999
(cherry picked from commit d20d7363826a0108905ab719684ce590322b911f)
…robe

The readiness probe matched the runtime's command line against
'(?:^|\s)serve(?:\s|$)', requiring the verb to sit between whitespace or
string boundaries. Windows quotes spawned arguments, so a live brain's
command line actually ends:

  "...\node.exe" "...\cli.cjs" "serve"

The verb is wrapped in quotes, which are neither whitespace nor a
boundary, so the predicate was always false and the probe exited 4 --
reporting a healthy runtime as "stale or does not match this channel
executable".

Found by running `ade brain start` on Windows, not by a test. It failed
after 17.8s claiming the brain never became ready, while the brain was in
fact running and serving on its named pipe. `ade brain status` then
contradicted itself in one response: the runtime section reported the pid
healthy while the service section called that same pid stale. A user
would reasonably have repaired a working runtime.

Verified against the live brain: with no restart and no other change,
service.running went false -> true and the diagnostic became "ADE per-user
channel brain is ready". Optional quotes still reject a different verb
(serveless) and a different subcommand (rpc --stdio).

Based-on: nsxdavid/ADE#999
`ade brain start` launched the PowerShell supervisor with
`Process.Start` / `ShellExecuteEx`, which makes it an ordinary descendant
of whoever ran the command. On Windows, job-object membership is
inherited and cannot be escaped: `CREATE_BREAKAWAY_FROM_JOB` fails with
ERROR_ACCESS_DENIED unless the job sets `JOB_OBJECT_LIMIT_BREAKAWAY_OK`,
which `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE` jobs do not. Terminals,
editors, CI agents and Electron all place their children in exactly such
jobs, so when the session that installed the brain went away Windows
called TerminateProcess on the supervisor *and* the brain it guards --
no exit code, no log, no restart, and no chance for the supervisor's
`finally` to run. A later `brain status` then cleared the now-stale PID
record and reported "The startup entry has no valid PID record yet",
erasing the last evidence that anything had ever been running.

macOS never had this failure because `launchctl load` hands ownership of
the process to launchd rather than to the invoking shell. Windows now
gets the same handover: the supervisor is started through a transient
one-shot scheduled task, so the Task Scheduler service spawns it and it
is parented to `svchost.exe`, belonging to no job of ours. This also
matches the login path, where `explorer.exe` -- likewise job-free --
runs the HKCU `Run` entry.

Login persistence deliberately stays on the HKCU `Run` key: registering
an ONLOGON task requires elevation (verified: `schtasks /Create /SC
ONLOGON` and `Register-ScheduledTask -AtLogOn` both fail with "Access is
denied" for a standard user), while a one-shot task does not.
`Register-ScheduledTask` is used instead of `schtasks /Create` because
the latter caps `/TR` at 261 characters, which a deep `ADE_HOME`
exceeds, and `ExecutionTimeLimit` is zeroed so the scheduler cannot
terminate an always-on brain after its three-day default.

The supervisor also gained a log file next to its launcher, the
equivalent of launchd's `StandardOutPath`/`StandardErrorPath`. It is
spawned detached with a hidden window and no redirection, so until now
every supervisor death was completely invisible; it now records its own
start, each brain spawn and exit with code and lifetime, each backoff,
and any terminating error that unwinds the supervise loop.

If the Task Scheduler route is unavailable or denied by policy the
in-session launch is still used as a fallback, so the brain always comes
up -- it is just bound to the session, which status reports.

Based-on: nsxdavid/ADE#999
(cherry picked from commit ba0f8f5cd9d9dcd6a38331e8b1fd5b111a6a8161)
`ade brain start` escaped the caller's job object through a transient one-shot
scheduled task. On a machine where Group Policy denies task registration that
route fails and the launch fell back to an in-session `Process.Start`, which
puts the supervisor right back inside the caller's kill-on-close job. The brain
came up, `install` reported "channel brain is ready", `status` reported
`running: true`, and then Windows terminated supervisor and brain together the
moment the session exited -- after which `status` said only "Cleared stale
supervisor PID record", erasing the evidence. Silent degradation of the headline
guarantee, in the shape that looks exactly like success.

Reproduced end to end by shadowing the ScheduledTasks module so
`Register-ScheduledTask` fails with the same "Access is denied." that policy
blocking produces, running `ade brain start` inside a
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE job, and closing the job.

Four launch routes were measured on a real kill-on-close job, not reasoned about:
`Process.Start`/`ShellExecuteEx`, `WScript.Shell.Run` and
`Shell.Application.ShellExecute` all stayed in the caller's job and died with it
-- the shell delegates nothing for a plain executable, so the "explorer.exe is
job-free" intuition does not transfer. The one-shot task produced a supervisor
parented to `svchost.exe`, and `Win32_Process.Create` produced one parented to
`WmiPrvSE.exe` and in no job at all; both outlived the job close.

WMI is now the second escape. This is documented behaviour, not a trick: *Job
Objects* states that child processes created using `Win32_Process.Create` are not
associated with the job. It is the fallback rather than the primary because WMI
process creation is the more commonly blocked of the two -- it is a known
lateral-movement technique that endpoint-protection rules disable -- and the two
failure modes are largely independent, which is what makes chaining them worth
doing. `Win32_ProcessStartup.ShowWindow` is set to SW_HIDE because a process
created this way gets default startup information rather than the caller's.

If a machine refuses both, the in-session launch still runs, but it is no longer
silent. The supervisor probes its own job at startup with
`QueryInformationJobObject(NULL, JobObjectExtendedLimitInformation)` -- documented
to use the job associated with the calling process, so no handle is needed -- and
publishes `sessionBound` in its PID record; `brain start` and `brain status` both
report in full that the always-on guarantee does not hold and why. That is
measured about the running supervisor rather than inferred from which route the
installer took, because the two disagree: the same launcher is started job-free
by `explorer.exe` at the next sign-in, and a record of the installer's intent
would keep warning about a brain that is no longer session-bound.

This is the Windows cost of what launchd gives macOS for free, where process
ownership makes "installed" and "survives this session" the same fact. Here they
are two facts, and reporting only the first is how a session-bound brain came to
look like a healthy one.

Based-on: nsxdavid/ADE#999
(cherry picked from commit be0c0cd40a5e7d73c69d51d443276cb3fa7caaca)
Eight test bodies opened with `if (process.platform === "win32") return;`.
On Windows that reports as a passing test while asserting nothing, so the
Windows suite overstated its own coverage by eight assertions.

Convert each to `it.skipIf(process.platform === "win32")(...)`, the idiom
already used in builtInBrowserSecurity.test.ts and modelPickerStore.test.ts,
so the runner reports them as skipped. All eight are POSIX-only harnesses:
`/bin/sh` wrapper execution, AF_UNIX `listen(path)`, POSIX mode bits, and
`fs.symlinkSync`. No assertion changes.

Shrink scripts/platform-gate-baseline.json by exactly those entries: the
ratchet goes from 8 entries / 14 violations to 4 entries / 6 violations, and
no vacuous-return entry remains.

Based-on: nsxdavid/ADE#999
(cherry picked from commit cd4e0c45537753df8373e809d6feb484ef999fa7)
`npm --prefix apps/<app> install` does not mean "install apps/<app>".
`--prefix` only redirects where npm writes node_modules; the package npm
treats as the one being installed is still the package in the *current
working directory*. Run from the repo root -- which is what
`install:apps` did, seven times -- that package is the root `ade`, so npm
dutifully installed the repo into each sub-app: `"ade": "file:../.."` in the
app's package.json and package-lock.json, plus an
`apps/<app>/node_modules/ade` symlink back to the root.

Confirmed by bisecting the invocation form on this branch: `cd apps/ade-cli
&& npm install` leaves the manifest untouched, `npm --prefix apps/ade-cli
install` from the repo root reproduces the churn every time. Running with
`--prefix` from a cwd that has no package.json fails outright with
`ENOENT ... /package.json`, which is the same fact stated the other way.

Replace `install:apps` with scripts/install-apps.mjs, which spawns
`npm install` with `cwd` set per app -- the same shape
.github/workflows/ci.yml already uses (`(cd apps/<app> && npm ci)`), so CI
was never affected and needs no change. Also fix the two user-facing hints in
adeCliService's shell fallbacks and apps/webhook-relay/README.md, which told
people to run the polluting command, and document the trap in AGENTS.md's
validation section.

`npm --prefix <app> run <script>` and `npm --prefix <app> exec` install
nothing and stay valid.

Verified: `npm run install:apps` across all seven apps leaves zero
package.json changes and creates no node_modules/ade symlink.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 4fe9f9165557cdfe5afa99ff0c11cf648f561ca3)
…ays valid

`build.mac.artifactName` interpolated `${productName}`. app-builder-lib's
`updateInfoBuilder` rewrites the updater feed's `url` to `safeArtifactName`
whenever `publish.provider === "github"` (out/publish/updateInfoBuilder.js:101),
and `computeSafeArtifactNameIfNeeded` produces that name by replacing spaces
with dashes -- returning null only when the name is already GitHub-safe
(out/platformPackager.js:709). electron-builder can do that rewrite because its
own GitHub publisher uploads under the safe name. This repo packages with
`--publish never` and uploads via `gh release upload`, which uses the on-disk
basename. A `productName` with a space would therefore put a name in
latest-mac.yml that nothing ever published, and mac auto-update would 404 on
the first channel release.

`productName` is `ADE` today, so this is latent, not live -- but it becomes
live the moment a channel build (`ADE Beta`) reaches the mac path. Pinning the
literal keeps `safeArtifactName` null forever.

The pinned value renders byte-identically to the current output
(ADE-<version>-<arch>.{dmg,zip}), and every consumer already assumes that
literal prefix:
  - apps/desktop/scripts/validate-mac-artifacts.mjs:756 -- /^ADE-.+-<arch>\.dmg$/
  - apps/desktop/scripts/create-mac-dmg.mjs:68 -- `ADE-${version}-${arch}.dmg`
  - .github/workflows/release-core.yml -- name-agnostic globs (*.dmg, *.zip)
  - .agents/skills/release/SKILL.md:381-385 -- required-assets list
  - release-assets/runtime/SHA256SUMS covers the standalone runtime only
So this is a config-to-consumer alignment, not a rename.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 3b02c3e6cdd6ffddf112a5a58210040800419340)
`openKvDb(...).close()` called `DatabaseSync.close()` directly. cr-sqlite
requires `select crsql_finalize()` first so the extension can tear down its
virtual tables and per-connection state; without it the extension keeps
resources attached to the connection.

On POSIX that is an invisible no-op, which is why it went unnoticed. On
Windows the OS keeps the `ade.db` file handle open, so after a caller has
closed the database the file still cannot be unlinked, renamed or moved --
a Windows user could not delete or relocate their own `.ade` directory, and
any in-process consumer that closes and then replaces the file gets EBUSY.

Route every teardown through a `closeDatabase()` helper that finalizes
best-effort and then closes. This covers the public `close()`, the failed-init
cleanup path, and the three reopen points in `openKvDb` (primary-key retrofit,
foreign-key retrofit, site-id correction), each of which previously abandoned
a live handle to the same file.

Verified on native Windows: before, `openKvDb().close()` followed by
`fs.rmSync` throws `EBUSY: resource busy or locked, unlink ...\ade.db` while
a plain `DatabaseSync` open/close does not; after, both succeed.
`kvDb.rebuildRecovery.test.ts` goes from 4/16 to 16/16 with no test changes.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 6e60d643692d1b6db6073569391fa99f69059948)
`disposeOwnedRuntimeChild` tore down an owned `ade serve` daemon with
`child.kill()`, which signals exactly one pid. A runtime daemon is not a leaf:
observed live on a Windows box, 6 of 8 daemons this code spawns had their own
`node.exe` children at the moment of teardown.

Windows has no process groups for these children and no reaping parent, so
every grandchild survived the daemon and kept holding the runtime named pipe.
That is how `node cli.cjs serve` trees were found still alive ~9.5 hours after
the process that owned them exited, still holding `\.\pipe\ade-runtime`. For
a desktop user this means quitting ADE leaves runtime processes behind that
block the next launch from binding its own pipe.

Route disposal through `signalChildProcessTree` from shared/utils -- the
helper `ptyService` and `agentChatService` already use, which signals the
process group on POSIX and shells out to `taskkill /T` on Windows, falling
back to a direct `child.kill()` if the tree signal fails.

Also spawn the daemon with `detached` on POSIX so the group signal has a group
to hit, matching the convention `spawnAsync` in shared/utils already follows.
Previously the POSIX branch had the same one-pid blind spot, just with orphans
reparented to init rather than stranded.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 1670b6e1c67d283f9d99aaa432e427f9af35f0c9)
The suite spawns real `ade serve` daemons and relied entirely on per-test
`finally` blocks calling `child.kill()`. That left two gaps on Windows: a test
that threw before its `finally` was reached leaked its daemon outright, and
even the blocks that did run killed a single pid while the daemon's `node`
children survived holding the runtime named pipe. Since this suite is a gate
in the `windows-foundation` CI job, a leak also means the job can exit with
live children.

Track every daemon the suite starts in a set, and add an `afterEach` that
tree-kills whatever is still registered, so cleanup no longer depends on any
individual test reaching its own teardown. Route the existing per-test
cleanups through the same `reapDaemonTree` helper so the pipe is released
before the next test starts rather than at end of file, and spawn detached on
POSIX so the group signal has a group.

Verified on native Windows: three consecutive runs, each followed by a
`Win32_Process` scan for `cli.cjs serve`/`brain-service` and a
`\.\pipe\` scan for `ade` pipes, reported zero survivors and zero pipes every
time. Suite result is unchanged at 65 passed / 1 skipped.

Based-on: nsxdavid/ADE#999
(cherry picked from commit 85fda9f31ade873389b7c32872f953728fb8c021)
The suite was excluded because 12 of its 16 tests failed with EBUSY on
Windows. The comment blamed the test's temp-dir teardown; that diagnosis
was wrong. openKvDb's close() never called crsql_finalize(), so the OS
kept the ade.db handle open after every caller believed the database was
closed -- fixed in 6e60d643, with the test file itself untouched.

It now passes 16/16, and this also makes its skipIf(linux) CRR tombstone
compaction case reachable for the first time: the file otherwise only ran
in test-desktop on ubuntu, where that case is skipped.

Based-on: nsxdavid/ADE#999
kvDb.rebuildRecovery.test.ts carries an it.skipIf(linux) gate that ran on
no runner while the file was excluded from the Windows job. Gating it in
that job covers the gate, so its baseline entry is stale and the ratchet
correctly refuses to pass until the baseline shrinks.

Based-on: nsxdavid/ADE#999
A Windows brain skipped every socket-ownership check on its way to
`listen()`. All three guards were gated on `!isAdeRuntimeNamedPipePath`,
and `probeLocalSocketForLiveness` returned `"unknown"` for any pipe
without dialing it, so the brain went straight to a bare bind. When the
endpoint was already owned the raw `EADDRINUSE` escaped, the recovery
classifier could not match Node's wording, and the failure was filed as
`code: "unknown"` with "ADE's background service could not start." and no
next action.

The gating inherited a POSIX assumption that is not just unnecessary on
Windows but backwards. A unix socket leaves a file behind when its owner
dies, so the path existing proves nothing and only a probe can tell.
A named pipe has no filesystem corpse: the name lives exactly as long as
some process holds a handle and the kernel releases it the moment the
last handle closes -- SIGKILL the owner and the next `listen()` succeeds.
So dialing a pipe is decisive where dialing a socket is a hint, and
`ENOENT` on connect is itself the existence check that `existsSync` was
being asked for.

Probe pipes like any other local endpoint, run the ownership check before
binding one (without the unlink step, which has nothing to unlink), and
translate a racing `EADDRINUSE` at the bind into the same
`socket_owned_by_other` error the pre-bind path already raises. Windows
now reports what macOS has always reported, with a cause that describes
Windows' actual semantics rather than hedging about a stale endpoint the
platform cannot produce.

Verified against a scratch ADE_HOME and pipe name: the recorded failure
goes from `code: "unknown"` with Node's raw text to
`code: "socket_owned_by_other"` with a cause and a next action, and a
brain binding a free pipe still starts normally.

Based-on: nsxdavid/ADE#999
…ion-runtime

# Conflicts:
#	apps/desktop/src/renderer/components/app/TopBar.test.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
apps/ade-cli/src/serviceManager/installWindows.ts (1)

771-790: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Uninstall still resolves the service identity without the command environment.

Line 775 calls resolvedServiceName(deps) and line 789 builds the launcher path from the bare env. installWindowsService (line 621) and getWindowsServiceStatus (line 894) both merge serviceCommand.env first. When ADE_PACKAGE_CHANNEL or ADE_HOME exist only in command.env, uninstall computes a different serviceName, taskName, Run-key value name, and launcherPath, then reports success while the real startup entry and launcher remain.

This was flagged in a previous review and marked as addressed, but the current code still shows the unmerged form.

Proposed fix
   const serviceCommand = deps.command ?? resolveAdeServeCommand();
-  const serviceName = resolvedServiceName(deps);
+  const serviceName = resolvedServiceName(deps, serviceCommand);
@@
   const taskName = resolveWindowsTaskName({ serviceName, userName });
-  const launcherPath = deps.launcherPath ?? resolveWindowsServiceLauncherPath({ env, serviceName });
+  const runtimeEnv = { ...env, ...(serviceCommand.env ?? {}) };
+  const launcherPath = deps.launcherPath
+    ?? resolveWindowsServiceLauncherPath({ env: runtimeEnv, serviceName });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/serviceManager/installWindows.ts` around lines 771 - 790,
Update uninstallWindowsService to merge serviceCommand.env with env before
resolving the service identity and launcher path, matching installWindowsService
and getWindowsServiceStatus. Use the merged environment when calling
resolvedServiceName, resolveWindowsTaskUser, and
resolveWindowsServiceLauncherPath so command-specific ADE_PACKAGE_CHANNEL and
ADE_HOME values produce consistent cleanup targets.
🧹 Nitpick comments (7)
apps/ade-cli/src/cli.test.ts (1)

2812-2815: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the rollup position, not only its presence.

The test name states that the rollup leads the output. The assertions only check substring presence, so a rollup printed after the rows still passes. Compare indexes to lock the ordering the test claims.

♻️ Proposed assertion
     expect(notRun).toContain("ADE PR checks - not run");
     expect(notRun).toContain("3 checks reported");
+    expect(notRun.indexOf("ADE PR checks - not run")).toBeLessThan(notRun.indexOf("CodeRabbit"));
     // The raw enum must never reach the reader — the phrase is the point.
     expect(notRun).not.toContain("not_run");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/cli.test.ts` around lines 2812 - 2815, Update the
rollup-output assertions in the affected test to compare the index of “ADE PR
checks - not run” with the index of the detailed check rows, asserting that the
rollup appears first. Retain the existing presence and raw-enum exclusion
checks.
apps/desktop/src/main/services/cli/adeCliService.ts (1)

215-215: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider dropping --prefix from user-facing guidance.

The repository guideline directs contributors away from npm --prefix apps/<app> invocations for dependency work. The build command shown here is not an install, so the guideline is not violated. Still, the message teaches the --prefix shape and users may reuse it for installs. Suggest cd apps/ade-cli && npm run build for both messages.

♻️ Proposed wording
-    "    echo ade: Local source CLI fallback requires repo-local tsx. Run npm run install:apps or npm --prefix apps/ade-cli run build. 1>&2",
+    "    echo ade: Local source CLI fallback requires repo-local tsx. Run npm run install:apps, or build with cd apps/ade-cli ^&^& npm run build. 1>&2",

Note: & requires ^ escaping inside a cmd echo. Verify the rendered shim text if you adopt this wording.

As per coding guidelines: "Install dependencies with npm run install:apps from the repository root or cd apps/<app> && npm install; never use npm --prefix apps/<app> install."

Also applies to: 377-377

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/main/services/cli/adeCliService.ts` at line 215, Update the
user-facing fallback guidance strings in the CLI shim to replace “npm --prefix
apps/ade-cli run build” with “cd apps/ade-cli && npm run build” in both
occurrences. Preserve cmd-compatible escaping for the ampersand and verify the
rendered shim text remains correct.

Source: Coding guidelines

apps/desktop/src/renderer/components/app/TopBar.test.tsx (1)

27-33: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Escape the constant before building the pattern.

THIS_MACHINE_NAME is data, not a pattern. The current value is safe, but a future label with ., (, or + would silently change the match. Escape the string, or pass a predicate to the query instead.

♻️ Proposed change
-const THIS_MACHINE_NAME_PATTERN = new RegExp(THIS_MACHINE_NAME);
+const THIS_MACHINE_NAME_PATTERN = new RegExp(
+  THIS_MACHINE_NAME.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
+);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/app/TopBar.test.tsx` around lines 27 -
33, Update THIS_MACHINE_NAME_PATTERN to escape regex metacharacters in
THIS_MACHINE_NAME before constructing the RegExp, preserving substring matching
for the machine menu’s accessible name.
apps/ade-cli/src/serviceManager/common.test.ts (1)

404-414: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

The ancestry assertion can pass without exercising the query.

isCurrentProcessDescendantOfPid fails closed: it returns true when the lookup returns PARENT_PID_UNKNOWN. On a host where the trusted PowerShell query fails, this test still passes and proves nothing about the win32 branch. Add a negative case that must return false, so a broken query is detected.

♻️ Proposed addition
   it("reports the real parent as an ancestor of this process", () => {
     expect(isCurrentProcessDescendantOfPid({ targetPid: process.ppid })).toBe(true);
   }, 30_000);
+
+  it("does not report an unrelated live pid as an ancestor", () => {
+    // A working query must answer `false` here; a failing query fails closed
+    // with `true` and this assertion catches that.
+    expect(readParentPid(spawnChildSync, process.pid)).toBe(process.ppid);
+    expect(isCurrentProcessDescendantOfPid({
+      targetPid: process.pid,
+      currentPid: process.ppid,
+    })).toBe(false);
+  }, 30_000);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/serviceManager/common.test.ts` around lines 404 - 414, Add a
negative Windows-host test alongside the existing
isCurrentProcessDescendantOfPid assertion that supplies a PID which cannot be an
ancestor and expects false, ensuring the ancestry query is actually exercised
and query failures are detected. Keep the existing real-parent positive case
unchanged.
apps/ade-cli/src/serviceManager/common.ts (1)

107-137: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Each ancestor costs one PowerShell start.

readWindowsParentPid spawns powershell.exe per pid. isCurrentProcessDescendantOfPid walks the chain pid by pid, so a successful deep walk pays the cold-start plus CIM cost repeatedly, with a 15s ceiling each. A single query that returns ProcessId/ParentProcessId for all processes would resolve the whole chain in one spawn.

This is a guard on a teardown path, so the current cost may be acceptable. Consider the single-query form if teardown latency on Windows becomes visible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/serviceManager/common.ts` around lines 107 - 137, The
current implementation performs one PowerShell spawn per ancestor in
readWindowsParentPid, making deep isCurrentProcessDescendantOfPid walks
expensive; if teardown latency requires optimization, replace the per-PID lookup
with one PowerShell/CIM query that retrieves ProcessId and ParentProcessId for
all processes, then resolve the ancestry locally while preserving the existing
unknown and root termination behavior.
apps/ade-cli/src/serviceManager/windowsSupervisor.ts (1)

168-181: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider UTF-8 for the PID record.

Write-PidRecord writes the JSON with [Text.Encoding]::ASCII. lastLaunchError comes from a Windows exception message, which can contain non-ASCII characters on a localized system. ASCII encoding replaces those characters with ?, so the diagnostic that brain status prints is degraded. readWindowsServicePidRecord reads the file as utf8, so UTF-8 output stays compatible.

Proposed change
-    "  [IO.File]::WriteAllText($pidPath, ($record | ConvertTo-Json -Compress), [Text.Encoding]::ASCII)",
+    "  [IO.File]::WriteAllText($pidPath, ($record | ConvertTo-Json -Compress), (New-Object Text.UTF8Encoding($false)))",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/serviceManager/windowsSupervisor.ts` around lines 168 - 181,
Update the PowerShell Write-PidRecord function to write the JSON using UTF-8
encoding instead of ASCII, preserving non-ASCII characters in lastLaunchError
and remaining compatible with readWindowsServicePidRecord’s UTF-8 decoding.
apps/ade-cli/src/serviceManager/installWindows.ts (1)

181-186: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider sharing one PowerShell quoting helper.

powerShellSingleQuotedLiteral exists here and in windowsSupervisor.ts (line 78) with the same behavior and different error text. Both files are security-relevant quoting paths. Export one implementation from common.ts or windowsSupervisor.ts and reuse it, so a future quoting fix cannot land in only one copy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/serviceManager/installWindows.ts` around lines 181 - 186,
Consolidate the duplicate PowerShell quoting logic by exporting a single
powerShellSingleQuotedLiteral implementation from common.ts or
windowsSupervisor.ts, then update installWindows.ts and windowsSupervisor.ts to
reuse it. Preserve NUL-byte rejection and single-quote escaping, using one
consistent error message.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 425-434: Replace the npm --prefix usage in the ADE CLI and desktop
dependency installation steps with per-app commands that change into each app
directory before running npm ci. Apply the same pattern to both typecheck
commands in the “Typecheck Windows runtime foundations” step, using cd
apps/<app> && npm run typecheck while preserving the existing app-specific
commands.

In `@apps/ade-cli/src/services/sync/syncHostSingleton.ts`:
- Around line 220-223: Update the fallback buildQuitCommand call within
safeReadLock to pass its platform parameter instead of relying on
process.platform, keeping the same platform value threaded through
withPidKillFallback so generated commands use consistent syntax.

In `@apps/desktop/src/main/services/chat/cursorSdkHooks.test.ts`:
- Line 114: Add Windows coverage for the fail-closed ADE hook wrapper behavior
in the test describing missing Node runners: select and invoke ade-tool-gate.cmd
on Windows, while retaining ade-tool-gate.sh for POSIX, and assert both wrappers
deny the invocation when no runner is available instead of skipping Windows
entirely.

In `@apps/desktop/src/main/services/state/kvDb.ts`:
- Around line 214-234: Extend closeDatabase() to support readonly connections,
using a readonly-compatible finalization path when needed while preserving
writable cleanup. Update openReadonlyDatabase() lifecycle handling and every
explicit ade.db open to close through closeDatabase(), ensuring no direct
db.close() remains for these connections.

---

Duplicate comments:
In `@apps/ade-cli/src/serviceManager/installWindows.ts`:
- Around line 771-790: Update uninstallWindowsService to merge
serviceCommand.env with env before resolving the service identity and launcher
path, matching installWindowsService and getWindowsServiceStatus. Use the merged
environment when calling resolvedServiceName, resolveWindowsTaskUser, and
resolveWindowsServiceLauncherPath so command-specific ADE_PACKAGE_CHANNEL and
ADE_HOME values produce consistent cleanup targets.

---

Nitpick comments:
In `@apps/ade-cli/src/cli.test.ts`:
- Around line 2812-2815: Update the rollup-output assertions in the affected
test to compare the index of “ADE PR checks - not run” with the index of the
detailed check rows, asserting that the rollup appears first. Retain the
existing presence and raw-enum exclusion checks.

In `@apps/ade-cli/src/serviceManager/common.test.ts`:
- Around line 404-414: Add a negative Windows-host test alongside the existing
isCurrentProcessDescendantOfPid assertion that supplies a PID which cannot be an
ancestor and expects false, ensuring the ancestry query is actually exercised
and query failures are detected. Keep the existing real-parent positive case
unchanged.

In `@apps/ade-cli/src/serviceManager/common.ts`:
- Around line 107-137: The current implementation performs one PowerShell spawn
per ancestor in readWindowsParentPid, making deep
isCurrentProcessDescendantOfPid walks expensive; if teardown latency requires
optimization, replace the per-PID lookup with one PowerShell/CIM query that
retrieves ProcessId and ParentProcessId for all processes, then resolve the
ancestry locally while preserving the existing unknown and root termination
behavior.

In `@apps/ade-cli/src/serviceManager/installWindows.ts`:
- Around line 181-186: Consolidate the duplicate PowerShell quoting logic by
exporting a single powerShellSingleQuotedLiteral implementation from common.ts
or windowsSupervisor.ts, then update installWindows.ts and windowsSupervisor.ts
to reuse it. Preserve NUL-byte rejection and single-quote escaping, using one
consistent error message.

In `@apps/ade-cli/src/serviceManager/windowsSupervisor.ts`:
- Around line 168-181: Update the PowerShell Write-PidRecord function to write
the JSON using UTF-8 encoding instead of ASCII, preserving non-ASCII characters
in lastLaunchError and remaining compatible with readWindowsServicePidRecord’s
UTF-8 decoding.

In `@apps/desktop/src/main/services/cli/adeCliService.ts`:
- Line 215: Update the user-facing fallback guidance strings in the CLI shim to
replace “npm --prefix apps/ade-cli run build” with “cd apps/ade-cli && npm run
build” in both occurrences. Preserve cmd-compatible escaping for the ampersand
and verify the rendered shim text remains correct.

In `@apps/desktop/src/renderer/components/app/TopBar.test.tsx`:
- Around line 27-33: Update THIS_MACHINE_NAME_PATTERN to escape regex
metacharacters in THIS_MACHINE_NAME before constructing the RegExp, preserving
substring matching for the machine menu’s accessible name.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: af962974-f26c-435c-861c-a2e661bfc1c9

📥 Commits

Reviewing files that changed from the base of the PR and between 16c1627 and ca39ec1.

⛔ Files ignored due to path filters (1)
  • AGENTS.md is excluded by !*.md
📒 Files selected for processing (94)
  • .agents/skills/quality/SKILL.md
  • .agents/skills/quality/references/ade-review-rules.md
  • .agents/skills/quality/references/correctness-security-review.md
  • .agents/skills/quality/references/thermo-nuclear-review.md
  • .agents/skills/ship/SKILL.md
  • .agents/skills/test/SKILL.md
  • .github/workflows/ci.yml
  • apps/ade-cli/README.md
  • apps/ade-cli/src/bootstrap.test.ts
  • apps/ade-cli/src/cli.test.ts
  • apps/ade-cli/src/cli.ts
  • apps/ade-cli/src/headlessLinearServices.test.ts
  • apps/ade-cli/src/headlessLinearServices.ts
  • apps/ade-cli/src/lib/trustedWindowsTools.test.ts
  • apps/ade-cli/src/lib/trustedWindowsTools.ts
  • apps/ade-cli/src/multiProjectRpcServer.ts
  • apps/ade-cli/src/serviceManager/common.test.ts
  • apps/ade-cli/src/serviceManager/common.ts
  • apps/ade-cli/src/serviceManager/index.ts
  • apps/ade-cli/src/serviceManager/installWindows.test.ts
  • apps/ade-cli/src/serviceManager/installWindows.ts
  • apps/ade-cli/src/serviceManager/windowsSupervisor.test.ts
  • apps/ade-cli/src/serviceManager/windowsSupervisor.ts
  • apps/ade-cli/src/services/agentRegistry.test.ts
  • apps/ade-cli/src/services/builtInBrowser/desktopBridgeClient.test.ts
  • apps/ade-cli/src/services/credentials/credentialStore.test.ts
  • apps/ade-cli/src/services/modelPickerStore.test.ts
  • apps/ade-cli/src/services/projects/machineLayout.test.ts
  • apps/ade-cli/src/services/projects/machineLayout.ts
  • apps/ade-cli/src/services/projects/projectIconResolver.test.ts
  • apps/ade-cli/src/services/projects/projectRegistry.test.ts
  • apps/ade-cli/src/services/projects/projectRegistry.ts
  • apps/ade-cli/src/services/runtime/brainLoopWatchdog.test.ts
  • apps/ade-cli/src/services/runtime/brainLoopWatchdog.ts
  • apps/ade-cli/src/services/runtime/localIpcListenOptions.test.ts
  • apps/ade-cli/src/services/runtime/localIpcListenOptions.ts
  • apps/ade-cli/src/services/runtime/socketSpawnLock.ts
  • apps/ade-cli/src/services/sync/machineIdentitySigningStore.test.ts
  • apps/ade-cli/src/services/sync/sharedSyncListener.test.ts
  • apps/ade-cli/src/services/sync/sharedSyncListener.ts
  • apps/ade-cli/src/services/sync/syncHostService.test.ts
  • apps/ade-cli/src/services/sync/syncHostService.ts
  • apps/ade-cli/src/services/sync/syncHostSingleton.test.ts
  • apps/ade-cli/src/services/sync/syncHostSingleton.ts
  • apps/ade-cli/src/services/sync/syncLoopbackCollision.test.ts
  • apps/ade-cli/src/services/sync/syncPairingStore.test.ts
  • apps/ade-cli/src/services/sync/syncService.test.ts
  • apps/ade-cli/src/services/sync/syncService.ts
  • apps/ade-cli/src/test/crrModelPickerWorker.ts
  • apps/ade-cli/src/test/filesystem.ts
  • apps/ade-cli/src/tuiClient/app.tsx
  • apps/ade-cli/src/tuiClient/imageTargets.ts
  • apps/desktop/package.json
  • apps/desktop/scripts/dev.cjs
  • apps/desktop/src/main/main.ts
  • apps/desktop/src/main/services/attention/attentionAccountCoordinator.test.ts
  • apps/desktop/src/main/services/attention/attentionAccountCoordinator.ts
  • apps/desktop/src/main/services/attention/attentionNotchHelper.test.ts
  • apps/desktop/src/main/services/attention/attentionNotchHelper.ts
  • apps/desktop/src/main/services/chat/cursorSdkHooks.test.ts
  • apps/desktop/src/main/services/chat/cursorSdkPolicy.test.ts
  • apps/desktop/src/main/services/cli/adeCliService.ts
  • apps/desktop/src/main/services/computerUse/localComputerUse.test.ts
  • apps/desktop/src/main/services/computerUse/localComputerUse.ts
  • apps/desktop/src/main/services/localRuntime/localRuntimeConnectionPool.test.ts
  • apps/desktop/src/main/services/localRuntime/localRuntimeConnectionPool.ts
  • apps/desktop/src/main/services/projects/projectIconResolver.test.ts
  • apps/desktop/src/main/services/projects/projectIconResolver.ts
  • apps/desktop/src/main/services/remoteRuntime/runtimeRpcClient.ts
  • apps/desktop/src/main/services/runtime/projectRecoveryService.ts
  • apps/desktop/src/main/services/shared/utils.ts
  • apps/desktop/src/main/services/state/kvDb.ts
  • apps/desktop/src/main/services/storage/diskPressure.ts
  • apps/desktop/src/main/windowAppearance.test.ts
  • apps/desktop/src/main/windowAppearance.ts
  • apps/desktop/src/renderer/components/activity/ActivitySettingsPopover.test.tsx
  • apps/desktop/src/renderer/components/activity/ActivitySettingsPopover.tsx
  • apps/desktop/src/renderer/components/activity/ActivitySettingsPopover.windows.test.tsx
  • apps/desktop/src/renderer/components/activity/HeaderActivityControl.test.tsx
  • apps/desktop/src/renderer/components/app/TopBar.test.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatPane.test.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
  • apps/desktop/src/renderer/components/lanes/CreateLaneDialogHostBinding.test.tsx
  • apps/desktop/src/renderer/components/lanes/laneMachines.test.ts
  • apps/desktop/src/renderer/components/lanes/laneMachines.ts
  • apps/desktop/src/renderer/components/personalChats/PersonalChatsPage.test.tsx
  • apps/desktop/src/renderer/components/personalChats/ProjectlessSidebar.test.tsx
  • apps/desktop/src/renderer/components/settings/ActivitySection.test.tsx
  • apps/desktop/src/renderer/components/settings/ActivitySettingsControls.tsx
  • apps/desktop/src/renderer/components/terminals/SessionCard.test.tsx
  • apps/desktop/src/renderer/components/terminals/SessionCard.tsx
  • apps/desktop/src/renderer/lib/platform.test.ts
  • apps/desktop/src/renderer/lib/platform.ts
  • apps/desktop/src/renderer/main.tsx
🚧 Files skipped from review as they are similar to previous changes (62)
  • apps/desktop/src/renderer/components/lanes/CreateLaneDialogHostBinding.test.tsx
  • apps/desktop/src/main/services/attention/attentionAccountCoordinator.test.ts
  • apps/ade-cli/src/multiProjectRpcServer.ts
  • apps/desktop/src/renderer/components/activity/HeaderActivityControl.test.tsx
  • apps/desktop/src/renderer/components/activity/ActivitySettingsPopover.test.tsx
  • apps/desktop/src/main/services/shared/utils.ts
  • apps/ade-cli/src/services/projects/projectIconResolver.test.ts
  • apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
  • apps/ade-cli/src/test/filesystem.ts
  • .agents/skills/quality/references/ade-review-rules.md
  • apps/desktop/src/renderer/lib/platform.test.ts
  • apps/ade-cli/src/services/projects/projectRegistry.test.ts
  • apps/desktop/src/renderer/main.tsx
  • apps/desktop/src/renderer/components/lanes/laneMachines.test.ts
  • apps/ade-cli/src/services/sync/syncHostSingleton.test.ts
  • apps/ade-cli/src/services/runtime/localIpcListenOptions.ts
  • apps/ade-cli/src/services/agentRegistry.test.ts
  • apps/ade-cli/src/services/sync/syncHostService.test.ts
  • apps/ade-cli/src/services/sync/syncLoopbackCollision.test.ts
  • apps/desktop/src/renderer/components/settings/ActivitySection.test.tsx
  • apps/ade-cli/src/bootstrap.test.ts
  • apps/ade-cli/src/headlessLinearServices.ts
  • apps/ade-cli/src/services/sync/syncService.test.ts
  • .agents/skills/quality/references/thermo-nuclear-review.md
  • apps/desktop/src/renderer/components/activity/ActivitySettingsPopover.tsx
  • apps/ade-cli/src/services/projects/machineLayout.ts
  • apps/ade-cli/src/services/runtime/localIpcListenOptions.test.ts
  • apps/ade-cli/src/services/sync/syncService.ts
  • apps/desktop/src/renderer/components/activity/ActivitySettingsPopover.windows.test.tsx
  • apps/desktop/scripts/dev.cjs
  • apps/desktop/src/main/services/computerUse/localComputerUse.ts
  • apps/ade-cli/src/services/sync/machineIdentitySigningStore.test.ts
  • apps/ade-cli/src/test/crrModelPickerWorker.ts
  • apps/ade-cli/src/services/builtInBrowser/desktopBridgeClient.test.ts
  • apps/ade-cli/src/tuiClient/imageTargets.ts
  • apps/ade-cli/src/headlessLinearServices.test.ts
  • .agents/skills/quality/references/correctness-security-review.md
  • apps/ade-cli/src/lib/trustedWindowsTools.ts
  • apps/desktop/src/renderer/lib/platform.ts
  • apps/desktop/src/main/windowAppearance.test.ts
  • apps/ade-cli/src/services/modelPickerStore.test.ts
  • apps/desktop/src/main/windowAppearance.ts
  • apps/desktop/src/main/services/computerUse/localComputerUse.test.ts
  • apps/ade-cli/src/services/runtime/brainLoopWatchdog.test.ts
  • apps/desktop/src/main/services/storage/diskPressure.ts
  • apps/desktop/src/main/services/attention/attentionNotchHelper.test.ts
  • apps/ade-cli/src/services/projects/projectRegistry.ts
  • apps/desktop/src/renderer/components/settings/ActivitySettingsControls.tsx
  • apps/desktop/src/renderer/components/lanes/laneMachines.ts
  • apps/ade-cli/src/tuiClient/app.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatPane.test.tsx
  • .agents/skills/ship/SKILL.md
  • apps/desktop/src/main/services/remoteRuntime/runtimeRpcClient.ts
  • apps/ade-cli/src/services/sync/syncHostService.ts
  • apps/ade-cli/src/services/runtime/brainLoopWatchdog.ts
  • apps/desktop/src/main/services/attention/attentionAccountCoordinator.ts
  • .agents/skills/test/SKILL.md
  • apps/desktop/src/main/main.ts
  • apps/ade-cli/src/cli.ts
  • apps/desktop/src/main/services/runtime/projectRecoveryService.ts
  • .agents/skills/quality/SKILL.md
  • apps/ade-cli/src/services/runtime/socketSpawnLock.ts

Comment thread .github/workflows/ci.yml
Comment thread apps/ade-cli/src/services/sync/syncHostSingleton.ts
Comment thread apps/desktop/src/main/services/chat/cursorSdkHooks.test.ts
Comment thread apps/desktop/src/main/services/state/kvDb.ts
@arul28
arul28 merged commit 4163481 into main Aug 3, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants