Skip to content

feat: native Windows support (detection, spawning, scheduling)#1

Merged
9thLevelSoftware merged 5 commits into
mainfrom
feat/windows-support
Jun 21, 2026
Merged

feat: native Windows support (detection, spawning, scheduling)#1
9thLevelSoftware merged 5 commits into
mainfrom
feat/windows-support

Conversation

@9thLevelSoftware

Copy link
Copy Markdown
Owner

Makes codealmanac work end-to-end on native Windows / PowerShell. Fixes the Codex/Claude "not found on PATH" problem from AlmanacCode#1 and adds the missing platform layers behind it.

Re-applies the approach from the stale draft AlmanacCode#2 onto the current (refactored) codebase, and fixes the layers that PR never touched: the live agent/readiness detection path, agent/auth/claude.ts, and process-group termination.

Root causes fixed

  • Detection (issue feat: native Windows support (detection, spawning, scheduling) #1): code shelled out to sh -lc 'command -v X' — no sh on native Windows, so every provider read "not found". Replaced with a pure-Node PATH/PATHEXT scan (src/process/exec.ts); 3 duplicate copies collapsed into 1.
  • Spawning: spawn() couldn't launch npm's .cmd/.ps1 shims. crossSpawn now runs shims via cmd.exe /d /s /c with windowsVerbatimArguments (avoids shell:true, which trips Node's DEP0190 and doesn't escape args).
  • Termination: process.kill(-pgid) is POSIX-only → taskkill /T /F on Windows; no detached (it broke piped stdio).
  • Scheduling: launchd-only → new automation/windows.ts using schtasks + per-task JSON manifests, behind a platform switch across install/status/uninstall/setup/uninstall/doctor.
  • Walk-up isolation bug: the .almanac walk-up ascended above the home dir; bounded at home (the global ~/.almanac was already skipped). Also makes tests hermetic on Windows, where the OS temp dir lives under home.

Verification

  • npm run lint, npm run build, and npm test (540/540) all green on native Windows.
  • almanac doctor detects Codex ("Logged in using ChatGPT") and Claude, with no deprecation noise.
  • CI now runs ubuntu-latest + windows-latest across Node 20 and 22.

Implementation plan: docs/plans/2026-06-21-windows-support.md.

🤖 Generated with Claude Code

9thLevelSoftware and others added 4 commits June 21, 2026 14:31
Native Windows/PowerShell could not detect or run the agent CLIs because
the codebase shelled out to `sh -lc 'command -v X'` (no `sh` on Windows)
and spawned npm `.cmd`/`.ps1` shims without `shell: true` (refused by
Node >=20). Fixes AlmanacCode#1.

- Add src/process/exec.ts: pure-Node PATH/PATHEXT resolution
  (commandExists/resolveExecutable) and crossSpawn, which uses a shell
  only for Windows shims. Removes the `sh` dependency on every platform.
- Route claude auth, codex readiness/status, and codex exec spawns through
  the shared module, collapsing three duplicate `commandExists` copies.
- process-group: terminate via `taskkill /T /F` on Windows (POSIX
  `process.kill(-pgid)` is unavailable) and do not detach (a new console
  breaks piped stdio; the tree is killed by pid instead).
- paths: stop the `.almanac` walk-up at the home directory. The global
  `~/.almanac` is already skipped; this also keeps tests hermetic on
  Windows, where the OS temp dir lives under the home dir.
- Make the test suite portable on Windows: dirname() instead of
  slash-only regex, separator-agnostic path assertions, and a `.cmd`
  shim + path.delimiter for the fake codex CLI fixtures.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
macOS schedules auto-capture/garden/update via launchd plists; Windows had
no equivalent, so `almanac setup`/`automation` failed natively.

- Add src/commands/automation/windows.ts: install/status/uninstall via
  `schtasks`, recording a JSON manifest per task under
  `~/.almanac/automation/` so status/doctor can report what was installed.
- Branch runAutomationInstall/Uninstall/Status on a `platform` option
  (defaults to process.platform), delegating to the Windows adapter.
- setup/automation-step: thread `platform`; ephemeral installs use
  `almanac.cmd` program args on Windows instead of `/usr/bin/env almanac`.
- uninstall: thread `platform` to the scheduler uninstall.
- Tests pin launchd cases to platform "darwin" (so they keep exercising
  launchd on any host) and add a Windows Task Scheduler suite.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add src/install/ephemeral.ts (shared by setup and doctor) recognizing
  npx/dlx caches and OS temp dirs including Windows %TEMP%/%TMP%.
- doctor: report the Windows Task Scheduler task (via the JSON manifest +
  `schtasks /Query`) instead of always probing a launchd plist.
- install-path: install globally via `cmd.exe /d /s /c npm.cmd ...` on
  Windows, since npm is a `.cmd` shim that won't spawn without a shell.
- CLI: describe automation as the platform scheduler, not macOS launchd.
- CI: run the build/typecheck/test loop on windows-latest as well as
  ubuntu-latest, across Node 20 and 22.
- README: document macOS/Linux/Windows support and the per-OS scheduler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`shell: true` with an args array triggers Node's DEP0190 deprecation
(args are concatenated, not escaped) and printed a warning on every Codex
invocation. Launch shims through `cmd.exe /d /s /c` with
windowsVerbatimArguments and a hand-quoted command line instead, and spawn
the resolved executable directly for non-shim targets.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 21, 2026 18:57

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces comprehensive native Windows support for CodeAlmanac, including cross-platform process execution, Windows Task Scheduler integration, and platform-aware setup and doctor checks. The feedback highlights critical Windows-specific edge cases that need to be addressed: stripping double quotes from directories in the PATH environment variable, correctly handling trailing backslashes in Windows argument quoting functions to prevent escaping closing quotes, and performing case-insensitive path comparisons to ensure the home directory boundary check works reliably on Windows.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/process/exec.ts Outdated
Comment thread src/process/exec.ts
Comment thread src/commands/automation/windows.ts
Comment thread src/paths.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e5c30bfee4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/install/ephemeral.ts
Comment thread src/commands/automation/windows.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Jun 21, 2026

Copy link
Copy Markdown

Code Review Roast 🔥

Verdict: All Issues Resolved | Recommendation: Merge

Overview

Severity Count
🚨 critical 0
⚠️ warning 0
💡 suggestion 0
🤏 nitpick 0
Resolved Issues
File Line Was Now
src/process/exec.ts 99/101 Quoted PATH entries broke path resolution Strips " from PATH entries ✅
src/process/exec.ts 131/138 Trailing backslashes escaped closing quote Doubles trailing backslashes in quoteWindowsArg
src/commands/automation/windows.ts 291/303 Same quoting bug in quoteWindowsTaskArg Doubles trailing backslashes in quoteWindowsTaskArg
src/paths.ts 76/81 Case-sensitive home comparison samePath() — case-insensitive on Windows ✅
src/install/ephemeral.ts 24/27 Missing Windows npm cache path Reads npm_config_cache / %LocalAppData%\npm-cache
src/commands/automation/windows.ts 132/136 Uninstall skipped tasks without manifest Always attempts deletion, returns boolean

🏆 Best part: The backslash-fix was applied consistently across both quoteWindowsArg and quoteWindowsTaskArg — no half-measures, no orphaned footguns.

💀 Worst part: There isn't one. I'm almost disappointed. I sharpened my knives for this review.

📊 Overall: Like watching a junior dev grow into a senior — the bugs from the last review are gone, the tests are comprehensive, and the quoting logic is now bulletproof. This PR is clean.

Files Reviewed (6 files, incremental)
  • src/process/exec.ts — 2 fixes + tests
  • src/commands/automation/windows.ts — 2 fixes + test
  • src/install/ephemeral.ts — 1 fix + tests
  • src/paths.ts — 1 fix
  • test/process-exec.test.ts — new tests
  • test/automation.test.ts — new test
  • test/install-paths.test.ts — new tests

Fix these issues in Kilo Cloud

Previous Review Summary (commit e5c30bf)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit e5c30bf)

Verdict: 6 Issues Found | Recommendation: Address before merge

Overview

Severity Count
🚨 critical 4
⚠️ warning 0
💡 suggestion 0
🤏 nitpick 2
Issue Details (click to expand)
File Line Roast
src/process/exec.ts 99 PATH entries with quotes break path resolution on Windows
src/process/exec.ts 131 Trailing backslashes escape closing quotes in cmd.exe
src/commands/automation/windows.ts 291 Same quoting bug for Windows scheduled task args
src/paths.ts 74 Case-sensitive home comparison fails on Windows
src/install/ephemeral.ts 24 Missing Windows npm cache path
src/commands/automation/windows.ts 132 Uninstall skips deleting tasks when manifest is missing

🏆 Best part: The architecture decision to centralize cross-platform process spawning into a single module is solid. Collapsing 3 duplicated commandExists implementations into one is a win.

💀 Worst part: The Windows quoting logic has a classic cmd.exe footgun - trailing backslashes in paths silently break argument escaping. This is the kind of bug that only shows up in production when someone's npm bin is under C:\Program Files\.

📊 Overall: Like teaching a fish to ride a bicycle — impressive center of gravity, but those backslash wounds are gonna leave a mark.

Files Reviewed (15 files)
  • src/process/exec.ts — 4 issues (new file)
  • src/commands/automation/windows.ts — 2 issues (new file)
  • src/install/ephemeral.ts — 1 issue (new file)
  • src/paths.ts — 1 issue
  • src/agent/auth/claude.ts — migrated to crossSpawn
  • src/agent/readiness/providers/cli-status.ts — migrated to crossSpawn
  • src/harness/providers/codex/exec.ts — migrated to crossSpawn
  • src/harness/providers/codex/status.ts — migrated to crossSpawn
  • src/process/process-group.ts — Windows taskkill integration
  • src/commands/automation.ts — Windows branch
  • src/commands/setup.ts, setup/automation-step.ts, setup/install-path.ts — platform param
  • src/commands/doctor-checks/ — Windows automation detection
  • src/commands/uninstall.ts — platform param

Reviewed by step-3.7-flash-20260528 · Input: 124.1K · Output: 4.3K · Cached: 27.2K

… tasks

Resolves automated review findings on the Windows support PR:

- exec.ts: strip surrounding double quotes from PATH entries (Windows can
  wrap dirs in quotes), so resolveExecutable doesn't build quoted paths.
- exec.ts/windows.ts: fix cmd.exe arg quoting — double backslash runs that
  precede a quote and trailing backslash runs, so a path like
  `C:\My Projects\` can't escape the closing quote.
- paths.ts: compare the home-dir walk-up boundary case-insensitively on
  Windows (drive-letter/path casing can differ), preserving the isolation.
- install/ephemeral.ts: recognize the Windows npm-cache `_npx` location
  (via npm_config_cache / %LocalAppData%\npm-cache) as ephemeral so npx
  setups aren't treated as durable.
- automation/windows.ts: uninstall attempts deletion of the deterministic
  task names even when the manifest is missing, so an orphaned schtasks job
  can't keep running.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 11d880b5a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +138 to +143
if ((options.platform ?? process.platform) === "win32") {
return installWindowsAutomation({
home: options.homeDir ?? homedir(),
jobs: plan.value.jobs.map(toWindowsJob),
disabledTaskIds: plan.value.disabledGardenPlistPath !== null ? ["garden"] : [],
captureSince,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Record capture baseline only after install succeeds

On Windows this branch calls installWindowsAutomation only after ensureAutomationCaptureSince has already written automation.capture_since. If windowsSchedule rejects the interval (for example almanac automation install --every 30s) or schtasks /Create fails, the command exits non-zero but the baseline has advanced, so a later successful install skips transcripts from before the failed attempt. Validate/create the Windows tasks before recording the capture baseline, or roll the baseline back on failure.

Useful? React with 👍 / 👎.

Comment on lines +172 to +176
} catch {
// schtasks exits non-zero when the task does not exist; treat as
// "nothing to delete" rather than an error.
}
await rm(windowsManifestPath(taskId, home), { force: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Surface unexpected schtasks delete failures

When schtasks /Delete fails for anything other than an absent task, such as access denied or the scheduler service being unavailable, this catch still removes the manifest below; uninstallWindowsAutomation then reports success whenever the manifest existed, leaving a live task with no manifest for status/doctor. Microsoft documents /f as only suppressing the confirmation message (docs), so preserve the manifest and surface unexpected delete errors instead of swallowing every non-zero exit.

Useful? React with 👍 / 👎.

Comment thread src/paths.ts
@@ -60,6 +75,12 @@ export function findNearestAlmanacDir(startDir: string): string | null {
if (candidate !== globalDir && existsSync(candidate)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Compare global wiki paths case-insensitively

On Windows this comparison still uses strict string equality for the global ~\.almanac skip. If process.cwd() reaches the home directory with different casing than homedir() (for example c:\users\dev vs C:\Users\Dev), existsSync(candidate) succeeds against the global state directory and the function returns the home directory as a wiki root, causing plain directories under home to be auto-registered as a repo. Use the new samePath(candidate, globalDir) check here too.

Useful? React with 👍 / 👎.

@9thLevelSoftware 9thLevelSoftware merged commit 60b4388 into main Jun 21, 2026
9 checks passed
@9thLevelSoftware 9thLevelSoftware deleted the feat/windows-support branch June 21, 2026 20:12
@9thLevelSoftware 9thLevelSoftware restored the feat/windows-support branch June 21, 2026 20:14
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.

2 participants