Skip to content

feat: rewrite in Node.js for cross-platform support (v1.1.0)#6

Merged
JonyanDunh merged 2 commits into
mainfrom
feat/nodejs-rewrite-v1.1.0
Apr 10, 2026
Merged

feat: rewrite in Node.js for cross-platform support (v1.1.0)#6
JonyanDunh merged 2 commits into
mainfrom
feat/nodejs-rewrite-v1.1.0

Conversation

@JonyanDunh
Copy link
Copy Markdown
Owner

Summary

Complete rewrite of the Watchdog plugin from Bash + jq + POSIX coreutils to Node.js. Runs natively on Linux, macOS, and Windows (including PowerShell / cmd — no WSL2 needed). Only runtime dependency is node 18+ and the claude CLI.

Architecture

Three thin entry points consume six shared lib/ modules:

lib/constants.js    — state file path pattern, marker tokens, prompt templates
lib/log.js          — stderr diagnostics
lib/stdin.js        — cross-platform synchronous stdin reader
lib/state.js        — atomic state file lifecycle (temp file + rename)
lib/transcript.js   — JSONL parser + current-turn tool extraction
lib/judge.js        — headless Haiku subprocess + verdict parser

hooks/stop-hook.js         — 186 lines (was stop-hook.sh at 287 lines of bash)
scripts/setup-watchdog.js  — 119 lines (was setup-watchdog.sh at 140 lines)
scripts/stop-watchdog.js   — 39 lines (was stop-watchdog.sh at 36 lines)

738 lines total of production JavaScript, replacing 463 lines of bash. The extra lines buy full modularization, cross-platform support, and a real test suite.

Test suite (53 tests, all green)

Uses Node's built-in `node:test` runner — zero external dependencies.

  • `test/transcript.test.js` — 11 tests — JSONL parsing, real-vs-tool_result turn detection, tool_use extraction, malformed-line resilience
  • `test/state.test.js` — 11 tests — atomic writes, merge updates, validation, path keying, parent dir creation
  • `test/judge.test.js` — 11 tests — verdict parser (FILE_CHANGES substring trap, ambiguous, empty, multi-token)
  • `test/setup.test.js` — 10 tests — end-to-end `scripts/setup-watchdog.js` subprocess invocations
  • `test/stop-watchdog.test.js` — 3 tests — end-to-end `scripts/stop-watchdog.js` subprocess invocations
  • `test/stop-hook.test.js` — 8 tests — end-to-end `hooks/stop-hook.js` including owner_session_id recursion guard, ownership claim, max iterations cap, missing transcript, pure-text turn

Run with: `node --test 'test/*.test.js'`

CI matrix

Dropped shellcheck (no shell scripts left). CI now runs:

Job Matrix
`nodejs-tests` `ubuntu-latest` × `macos-latest` × `windows-latest` × Node 18 / 20 / 22 (9 jobs)
`jsonlint` ubuntu, now uses `node -e JSON.parse` instead of `jq`
`markdownlint` ubuntu, unchanged

READMEs (all 7 languages)

All 7 READMEs updated in this PR — English authored directly, then 6 parallel subagents translated the new sections into `zh` / `ja` / `ko` / `es` / `vi` / `pt` while preserving each file's existing colloquial tone.

Verified structural parity across all 7 files: same h2/h3 counts, same number of tables, same number of install blocks (`winget`, `scoop`, `node --test`, etc.).

Behavior compatibility

Same semantics as 1.0.x:

  • Haiku-classifier convergence detection
  • Tool-call exit precondition (pure-text turn never exits)
  • `owner_session_id` recursion guard (fixed in v1.0.1)
  • Per-session state keyed by `TERM_SESSION_ID`
  • Slash command surface: `/watchdog:start`, `/watchdog:stop`, `/watchdog:help`
  • State file format (JSON) unchanged

Breaking changes

None for end users who installed via `npm install -g @anthropic-ai/claude-code` — they already have `node` in `PATH`. Users who installed Claude Code via standalone binary / homebrew without Node.js will now need to install Node.js 18+ to use Watchdog.

NOTICE updated

Added the Node.js rewrite as a new modification entry per Apache 2.0 § 4, with the updated file list.

Test plan

  • `node --test 'test/*.test.js'` — 53/53 passing
  • `node --check` on every `.js` file — all clean
  • All 7 READMEs structurally consistent (`grep` counts match)
  • `.claude-plugin/plugin.json` bumped to 1.1.0
  • `.claude-plugin/marketplace.json` bumped to 1.1.0
  • `hooks/hooks.json` invokes `node` instead of `bash`
  • CI will confirm Linux/macOS/Windows × Node 18/20/22 parity

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

JonyanDunh and others added 2 commits April 11, 2026 03:37
Complete rewrite of the Watchdog plugin from Bash + jq + POSIX
coreutils to Node.js. Zero shell dependencies — runs natively on
Linux, macOS, and native Windows (PowerShell / cmd) with only
`node` 18+ required. No more WSL2 requirement for Windows users,
no more jq install, no more "bash in PATH" gotcha.

## What changed

- **Three thin entry points** (`hooks/stop-hook.js`,
  `scripts/setup-watchdog.js`, `scripts/stop-watchdog.js`) that all
  consume shared logic from six `lib/` modules:
  - `lib/constants.js`  — state path pattern, marker tokens, prompt templates
  - `lib/log.js`        — stderr diagnostics
  - `lib/stdin.js`      — cross-platform sync stdin reader
  - `lib/state.js`      — atomic state file lifecycle
  - `lib/transcript.js` — JSONL parser + current-turn tool extraction
  - `lib/judge.js`      — headless Haiku subprocess + verdict parser

- **738 lines** of production JavaScript replacing the combined
  287 + 140 + 36 = 463 lines of bash — the extra lines buy full
  modularization, cross-platform support, and a real test suite.

- **53 automated tests** using Node's built-in `node:test` runner.
  No external test dependencies. The suite exercises:
  - JSONL transcript parsing (real vs tool_result user turn boundaries,
    tool_use extraction, malformed-line resilience)
  - State file lifecycle (atomic writes, merge updates, validation,
    per-session path keying, parent dir creation)
  - Verdict parser (FILE_CHANGES substring trap, ambiguous, empty,
    multi-token)
  - End-to-end setup-watchdog.js subprocess invocations
  - End-to-end stop-watchdog.js subprocess invocations
  - End-to-end stop-hook.js including the owner_session_id recursion
    guard, ownership claim, max iterations cap, missing transcript,
    and pure-text turn branches

- **CI rewritten** to drop shellcheck (no shell scripts left) and run
  `node --test` on a 3x3 matrix: `ubuntu-latest`, `macos-latest`,
  `windows-latest` × Node 18 / 20 / 22. Also dropped `jq` from the
  jsonlint job in favor of `node -e JSON.parse`.

- **All 7 READMEs updated** (English + zh / ja / ko / es / vi / pt)
  via 6 parallel subagent translations. New Requirements section
  drops bash/jq, adds node 18+. New Install dependencies subsection
  has native Windows install commands. Platform support matrix now
  shows Linux / macOS / Windows all ✅ tested in CI.

- **NOTICE updated** with the Node.js rewrite as a new modification
  entry and the new file list.

- **CONTRIBUTING updated** to replace shellcheck references with
  `node --test` instructions and a description of the test suite.

- **plugin.json + marketplace.json bumped to 1.1.0**.

Same semantics as 1.0.x: Haiku-classifier convergence detection,
tool-call exit precondition, owner_session_id recursion guard,
per-session state keyed by TERM_SESSION_ID. The state file format
and slash command surface are unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Node's --test runner only gained glob pattern support in v21, so
on Node 18 and 20 'test/*.test.js' is treated as a literal filename
and CI fails with "Could not find 'test/*.test.js'". Fix the CI
workflow to list each test file explicitly.

Also update all 7 READMEs + CONTRIBUTING.md to show both forms —
the Node 22+ glob syntax and the Node 18/20 unquoted (shell-
expanded) form. Plus fix a stale "shellcheck → node --test"
transition comment in the Plugin Layout tree across all languages
to describe the actual CI jobs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JonyanDunh JonyanDunh merged commit 634fb34 into main Apr 10, 2026
11 checks passed
@JonyanDunh JonyanDunh deleted the feat/nodejs-rewrite-v1.1.0 branch April 10, 2026 17:43
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.

1 participant