github mksglu/context-mode v1.0.108

latest releases: v1.0.111, v1.0.110, v1.0.109...
7 hours ago

v1.0.108 — Distribution unblocked, hooks made non-destructive, Windows hardened

One-line headline: /ctx-upgrade finally advances the marketplace clone — without that single fix, none of the other six fixes in this release would actually reach users. Then we fixed the other six.

This is a major bug-fix release addressing 7 distinct user-reported issues plus operational hardening. The release closes 3 critical, 2 high, and 2 medium items and merges a community PR. Every change has new behavioral test coverage. No breaking changes. No adapter behavior change.

Upgrade

npm update -g context-mode

Then run /ctx-upgrade inside Claude Code. In v1.0.108 this command actually does what its name says — see #418 below.

If you are stuck on v1.0.107 and /ctx-upgrade reports success but version never moves, that is exactly the bug #418 fixes. Bootstrap by running npm update -g context-mode from a terminal first; from the next release on, in-product upgrade self-heals.


Critical fixes

[CRITICAL · DATA LOSS] #415pretooluse.mjs no longer destroys co-located user hooks

Reported by @asherepenko (Andrew Sherepenko) — #415.

What broke: Whenever a user's ~/.claude/settings.json placed a SessionStart hook in the same matcher entry as a context-mode hook, pretooluse.mjs ran an entries.filter(... !some(isCtxMode)) block that wiped the entire entry — including the user's sibling hooks. Fired once per machine per version (per-version marker), the destruction was silent and irreversible from the running session.

What changed (commit 10ce5fb):

  • pretooluse.mjs: removed the destructive entry-level filter
  • src/adapters/claude-code/index.ts: replaced entry-level filter at the allCovered branch with inner-hook-level strip + empty-entry prune
  • The safe block at lines 357–385 (stale-path cleanup, gated by isAnyContextModeHook) is intentionally untouched
  • 2 new co-location preservation tests added — they fail on main, pass on this branch
  • Direct repro /tmp/repro-415.sh exits 1 on this build (bug eliminated)

[CRITICAL · DISTRIBUTION] #418/ctx-upgrade now syncs the marketplace clone

Reported by @cjduncana (Christopher John Duncan Araúz) — #418. Diagnosis was unusually well-instrumented; thank you.

Why this is the headline fix: Claude Code reads plugin metadata from ~/.claude/plugins/marketplaces/context-mode/, which /ctx-upgrade never advanced past its install-time commit. Users saw "ctx-upgrade succeeded" while the plugin system continued to treat them as the previous version forever. This compounded #411 / #181: every fix we shipped after install was invisible to the user until they manually re-installed the marketplace.

What changed (commit 7c159c2):

A new Step 0 runs before the existing /tmp clone in the upgrade pipeline:

  1. Detect the marketplace dir at ~/.claude/plugins/marketplaces/context-mode/
  2. Skip if no .git (tarball install path)
  3. Run git status --porcelain first — if uncommitted edits exist (Mert-class users symlink the clone to a dev worktree), skip the destructive reset and surface a manual recovery command
  4. Otherwise: git fetch --tags origin + git reset --hard origin/HEAD
  5. Failures land as a yellow log line; cache-dir update flow continues regardless

Tests in tests/core/cli.test.ts (Issue #418 describe block): targets correct path, runs fetch + reset, guards on .git existence, preserves user dev edits via porcelain check.

[CRITICAL · MCP] #411 — Cached .mcp.json no longer points to the previous version

Reported by @mateuszruszkowski (Mateusz Ruszkowski) — #411.

What broke: The upgrade flow wrote an absolute start.mjs path into the cached .mcp.json at write time. Once #181 lazy cleanup removed that old version directory, every MCP reconnect attempt failed because the file it was pointing to no longer existed.

What changed (commit 10ce5fb):

  • src/cli.ts upgrade() now writes the literal ${CLAUDE_PLUGIN_ROOT}/start.mjs placeholder instead of resolve(pluginRoot, "start.mjs")
  • Matches the Anthropic canonical pattern (claude-mem, our own .claude-plugin/plugin.json:23-29)
  • Inverted regression test added — confirms the absolute path is never written

High-severity fixes

[HIGH · WINDOWS] #414 — Crash-resilient hook wrapper, no more silent ghost hooks

Reported by @Asureu#414.

What broke: Intermittent cjs/loader:1479 crashes on Windows during UserPromptSubmit and SessionStart while ctx-doctor reported clean. Static top-level side-effect imports (suppress-stderr, ensure-deps) threw at parse time and bypassed every try/catch block downstream. The hook then exited silently — no log, no diagnostic, no user-visible signal — while ctx-doctor still passed because it didn't exercise the crashing import path.

What changed (commit 10ce5fb):

  • NEW hooks/run-hook.mjs — universal crash-resilient wrapper. Installs uncaughtException + unhandledRejection handlers before handler invocation
  • Side-effect modules are now dynamic-imported inside try/catch (architect's critical finding — static top-level imports were the silent killer)
  • All 5 hook entries (sessionstart, userpromptsubmit, pretooluse, posttooluse, precompact) refactored to one-line runHook(async () => {...}) pattern. Zero top-level static side-effect imports remain
  • Logs to ~/.claude/context-mode/hook-errors.log before exit 0 — silent ghost hooks are no longer architecturally possible
  • scripts/postinstall.mjs now also normalizes hooks.json at install time (was only normalized on MCP boot — but hooks fire independently of MCP)
  • 4 new behavioral tests in tests/hooks/run-hook.test.ts (subprocess + poisoned-import staging)

[HIGH · WINDOWS] #408 — better-sqlite3 binding self-heals on Windows

Reported by @Asureu#408.
Fixed by PR #410 from @ousamabenyounes (Ben Younes)6th merged community PR. Thank you.

What broke: Windows installs of v1.0.107 could land with a missing better-sqlite3 native binding, killing FTS5 indexing and ctx tooling without an actionable error.

What changed (commit 5432575):

3-layer self-heal in scripts/heal-better-sqlite3.mjs:

  1. prebuild-install via process.execPath (uses the active Node version, not whichever is on PATH)
  2. npm install fallback
  3. Actionable stderr if both fail

Wired into postinstall, ensure-deps, and cli doctor hint. CI green across the 3-OS matrix.

[HIGH · /resume] #413 — Snapshot fallback in SessionStart hook

Reported by @JewelSamAmy#413.

What broke: Per Claude Code docs, --continue, --resume, and /resume all fire SessionStart with source="resume" plus the active session_id. For /resume, that active id is a fresh uuid for the resumed conversation, so live-events lookup missed every time — even when prior context obviously existed. Users picking a non-latest session through /resume got a blank slate.

What changed (commit c3d0467):

  • The resume branch in hooks/sessionstart.mjs now falls back to db.claimLatestUnconsumedResume(currentSessionId) — same pattern OpenCode and OpenClaw plugins already use (opencode-plugin.ts:454)
  • Live-events path keeps precedence; snapshot only surfaces when no live rows match the incoming session_id (the /resume case, or when the prior session was previously compacted) — --continue behavior is unchanged
  • Tests:
    • "falls back to snapshot when resumed session has no live events"
    • "prefers live events over snapshot when both exist (--continue stays correct)"
  • README updated: Session Continuity intro now lists --continue, --resume, and /resume

Medium-severity fixes

[MED · STATUSLINE] Heartbeat liveness + post-upgrade self-locate fallback

Commit c6d9cfd. Two related failure modes.

(1) False-stale during MCP idle / post-/compactbin/statusline.mjs flips red when stats.updated_at > 30 min. Pre-fix, updated_at only advanced on MCP tool calls — long Bash/Read/Edit stretches or post-/compact pauses crossed the cliff while the server was healthy. Fix: setInterval(persistStats, 60_000).unref() in the MCP server. The 30-min threshold now reflects true server death, not user idle.

(2) Statusline disappears after upgradestatuslineForward used only getPluginRoot() + bin/statusline.mjs. After ctx-upgrade, that path could resolve to a cache dir that sessionstart.mjs (#181) had cleaned. Fix: the resolver now tries (a) getPluginRoot, (b) marketplace clone (stable across upgrades, refreshed by #418 fix), (c) every installPath listed in installed_plugins.json. Total miss exits silently — statusline output is the user-facing surface; stderr would be visual noise.

6 new tests in tests/core/cli.test.ts cover heartbeat scheduling, threshold ordering, .unref()-ness, and all three resolver branches.

[MED · STATS] Lifetime monotonicity + value-forward Parallel I/O copy

Commit 3f204f2. Closes internal issues #2 and #3.

  • #2 lifetime always ≥ sessionctx-stats lifetime line + footer now combine disk-aggregated lifetime (events × 256 tokens) with current-session in-memory token savings at the render edge. Two accounting pipelines (server bytes vs hook session_events) unified so a fresh user / pre-flush session / pre-b8e11bf v1.0.103 sidecar no longer surfaces the surprising "$X this session · $0.00 lifetime"
  • #3 value-forward copy — the engineer-speak block becomes:

    Parallel I/O — one call did the work of many — faster runs, lower bill, same answer.

  • mcp__*__ namespace stripped via non-greedy regex; section suppressed entirely when max_concurrency<=1 (no false parallelism claim)
  • Renders identically across all 14 adapters via formatReport(). Display-only — zero OS / runtime impact
  • 5 new format-report tests (3 monotonic, 2 copy/suppression). 50/50 analytics green

[MED · ROUTING BLOCK] Forbidden-actions template variable fix (#416)

PR #416 — commit dc892b1. Replaced hardcoded ctx_execute_file / ctx_execute strings in hooks/routing-block.mjs with proper template interpolation so toolname-prefixed adapters render the correct fully-qualified names.


Operational discipline (non-runtime)

Owner operating directive embedded at the top of /context-mode-ops

Commit 9c94232. The maintainer's standing directive (parallel agent army, ULTRATHINK posture, anti-hallucination via refs/, PO/OSS/Distribution hats, /tdd discipline, business-over-code reasoning, MUST-language for subagents, Windows-as-trust-cliff, sales-pressure context) is now a non-negotiable preamble at the top of skills/context-mode-ops/SKILL.md. Every future invocation loads it automatically; operating posture survives across sessions instead of resetting.

5 mattpocock operating-discipline skills vendored

Commit 89c0e83. The owner directive treats /diagnose, /tdd, /grill-me, /grill-with-docs, and /improve-codebase-architecture as MANDATORY tools — not advisory references. Without them locally available, every fresh invocation of /context-mode-ops would point users at skills they have never installed and the discipline collapses.

Vendored from mattpocock/skills @ b843cb5 (MIT, © 2026 Matt Pocock — license preserved upstream and referenced via skills/UPSTREAM-CREDITS.md). Each vendored SKILL.md carries a one-line attribution footer linking back to source. Refresh path documented for periodic upstream sync. No content modified — files are byte-for-byte from upstream plus the attribution footer.


Migration / Action Required

If you were affected by #415 (settings.json data loss)

If you ran v1.0.107 with co-located user SessionStart hooks in the same matcher entry as a context-mode hook, your prior ~/.claude/settings.json may have been silently truncated. Recovery options:

  1. Restore from your dotfiles repo or backup
  2. Recover via git history if you version-control your ~/.claude/:
    cd ~/.claude
    git log -p settings.json
  3. Re-create the lost user hooks; v1.0.108 preserves them on every PreToolUse fire

Everyone

Run /ctx-upgrade inside Claude Code after npm update -g context-mode. v1.0.108 is the first release where /ctx-upgrade actually advances the marketplace clone — without this round-trip, future fixes won't reach you in-product.

If you are a dev-mode user symlinking the marketplace clone to a worktree, the new Step 0 detects uncommitted edits via git status --porcelain and skips the destructive reset, surfacing a manual recovery command instead. Your edits are safe.


Compatibility

  • Adapters: No behavior change across all 14 adapters (Claude Code, OpenCode, OpenClaw, Cursor, Kiro, VSCode Copilot, Pi, Qwen Code, Gemini CLI, JetBrains Copilot, Codex, Antigravity, Zed, Kilo). Display-only stats changes render identically via formatReport()
  • Operating systems: macOS, Linux, Windows. CI green across the 3-OS matrix. Windows hook resilience and sqlite self-heal are net improvements
  • Breaking changes: none
  • Public API / MCP tool surface: unchanged

Test counts

  • 4 new run-hook behavioral tests (subprocess + poisoned-import staging)
  • 2 new co-location preservation tests for #415
  • Inverted .mcp.json placeholder test for #411
  • 6 new statusline tests (heartbeat × 3 + resolver fallback × 3)
  • 5 new format-report tests for stats monotonicity + copy
  • 2 new continuity tests for #413 (/resume snapshot fallback)
  • Updated cli.test.ts anchors for the new runHook architecture
  • 9 pre-existing failures unrelated and confirmed pre-existing in main (8 opencode adapter tsx subprocess infra issue + 1 continuity parallel-spawn flake — both pass in isolation)
  • TypeScript: clean

Contributors

Community wins drove this entire release. Six users, six commits worth of pressure on the fix list:

  • @cjduncana (Christopher John Duncan Araúz) — #418: well-instrumented diagnosis of the marketplace-clone freeze. This is the fix that unlocks delivery of every other fix in this release
  • @asherepenko (Andrew Sherepenko) — #415: caught the most damaging bug in v1.0.107 — silent destruction of co-located user hooks. Critical user-data report
  • @mateuszruszkowski (Mateusz Ruszkowski) — #411: hardcoded path baked into cached .mcp.json breaking MCP reconnect post-cleanup
  • @Asureu#414 and #408: two distinct, high-quality Windows reports — silent hook crashes and missing better-sqlite3 binding
  • @JewelSamAmy#413: surfaced the /resume capability gap that the existing SessionStart snapshot pattern already had the primitive for
  • @ousamabenyounes (Ben Younes) — PR #410 for #4086th merged community PR. Ben has now contributed more PRs than any other external contributor

Special thanks to Matt Pocock (@mattpocock) for the MIT-licensed operating-discipline skills (/diagnose, /tdd, /grill-me, /grill-with-docs, /improve-codebase-architecture) vendored in this release.


What ships in this commit range

89c0e83 docs(skills): vendor 5 mattpocock operating-discipline skills referenced by ops directive
9c94232 docs(skill): embed owner operating directive at top of context-mode-ops
c6d9cfd fix(statusline): heartbeat liveness + post-upgrade self-locate fallback
3f204f2 fix(stats): lifetime monotonic + Parallel I/O PO copy (#2 #3)
7c159c2 fix(#418): /ctx-upgrade now syncs the marketplace clone (git fetch + reset)
c3d0467 fix(#413): /resume snapshot fallback in SessionStart hook
dc892b1 Fix/missing toolname prefix (#416)
10ce5fb fix(v1.0.108): #415 hook destruction + #411 mcp path + #414 win hook resilience
5432575 fix(install): self-heal missing better-sqlite3 binding on Windows (#408) (#410)

Full diff: v1.0.107...v1.0.108

Don't miss a new context-mode release

NewReleases is sending notifications on new releases.