github mksglu/context-mode v1.0.127

latest releases: v1.0.129, v1.0.128
3 hours ago

v1.0.127

Closes 1 community-reported security regression (#558) plus 1 contributed PR (#555). The security fix follows the algorithmic playbook from v1.0.124/125/126 — bundle-first resolution + algorithmic Algo-D4 derivation. Adapter #16 inherits the integrity check automatically.

What broke

#558permissions.deny silently fail-open on every marketplace install (security regression)

@AKhozya delivered a staff-grade report verified end-to-end against refs/platforms/claude-code/:

  • Marketplace install path = git clone only (refs/platforms/claude-code/src/utils/plugins/pluginLoader.ts:563 installFromGit — no npm install, no npm run build, cross-OS uniform)
  • .gitignore excludes build/ (line 2)
  • scripts/postinstall.mjs only heals better-sqlite3; never runs tsc
  • prepublishOnly: "npm run build" only fires on npm publish — never on the marketplace path

Result: build/security.js (and build/adapters/gemini-cli/index.js) never materialize on marketplace installs. hooks/core/routing.mjs:263 initSecurity() couldn't resolve the security module → permissions.deny silently became no-op. The #466 stderr warning fires but Claude Code's adapter doesn't surface hook stderr to the agent UI, so users have zero signal that policy enforcement is disabled.

Severity timeline: security module added 2026-03-03 (commit b3f93eb) → ~71 days × 121 releases of marketplace installs silently fail-open. v1.0.126's Algo-D4 (assertPluginCacheIntegrity) didn't catch because REQUIRED_RUNTIME_SIBLINGS shipped HARDCODED — my v1.0.126 algorithmic intent (derive from package.json files[]) materialized only halfway: derivePluginManifest exists in the same file but only the doctor surface consumed it; the boot gate kept the hardcoded list.

The 4-slice algorithmic fix

Slice 1 — hooks/security.bundle.mjs bundle-first (mirrors #249/#117 session-loaders pattern)

src/security.ts is now an esbuild bundle target → hooks/security.bundle.mjs (5.0 kB, committed to git). hooks/core/routing.mjs initSecurity() becomes bundle-first / build-fallback:

  1. Try <pluginRoot>/hooks/security.bundle.mjs (ships in marketplace git clone AND npm tarball)
  2. Fall back to <pluginRoot>/build/security.js (npm install / dev environment)
  3. Both missing → loud stderr warning + securityInitFailed = true + fail-open (or fail-closed if CONTEXT_MODE_REQUIRE_SECURITY=1)

Marketplace clone gets the bundle for free (hooks/ not in .gitignore). permissions.deny enforcement now works on every install path.

Slice 2 — Excise dead gemini-cli.writeRoutingInstructions block

Recon spotted that GeminiCLIAdapter.writeRoutingInstructions was REMOVED in commit 6dae20c ("refactor: remove writeRoutingInstructions from all adapters"). The proposed bundle would have shipped a method that doesn't exist. Per Mert's no-dead-code rule, the dead try/catch block in hooks/gemini-cli/sessionstart.mjs:93 was deleted instead. Restoring GEMINI.md auto-write is out-of-scope (separate PRD).

Slice 3 — Algorithmic Algo-D4 (realize v1.0.126 intent)

scripts/plugin-cache-integrity.mjs REQUIRED_RUNTIME_SIBLINGS is now derived from package.json scripts.bundle (the publish-time source of truth for "what bundles must exist"), parsed via --outfile= argument extraction, with an explicit SOFT_FALLBACK_BUNDLES whitelist for session-* (which have bundle-first/build-fallback in session-loaders.mjs and so are warn-class, not boot-fast).

Adding adapter #16's bundle to package.json scripts.bundle auto-extends the integrity check. Adapter #16 inherits the algorithmic protection without anyone remembering to extend a hardcoded list.

Slice 4 — additionalContext surfacing on security init failure

hooks/sessionstart.mjs now checks isSecurityInitFailed() (already exported from routing.mjs:288) on session start. If true, prepends a structured additionalContext block to the SessionStart payload:

[context-mode] WARNING: security module unavailable on this install.
permissions.deny patterns are NOT being enforced. Run `npm run build` in
the plugin root or upgrade to v1.0.127+. Install path: <pluginRoot>

The agent sees this on first session — no longer relegated to swallowed stderr. Reporter @AKhozya's proposal #3, shipped verbatim.

#555fix(project-dir): ignore stale Claude transcript cwd (by @nodnarbnitram)

5-minute freshness window for the Claude Code transcript-based project-dir recovery heuristic. Fixes a class of bug where stale transcripts (e.g., week-old session jsonls) hijacked project root for non-Claude adapters when host detection was ambiguous. +23/-2 src + 3 test cases extended in existing tests/util/project-dir.test.ts (CONTRIBUTING L275 compliance). Boundary > (strict) — exactly-at-window passes, off-by-one safe.

15-adapter audit: transcriptsRoot is set only when detectPlatform() === "claude-code" — other 14 adapters skip the heuristic entirely. Zero behavioral change for them. v1.0.124 strict-mode strictPlatform cascade and PR #555's freshness window compose orthogonally.

Why algorithmic, not per-adapter

v1.0.124 (#545 env-leakage) → PLATFORM_ENV_VARS registry + 15×14×3 leak matrix. v1.0.125 (#547 Codex regex) → is_exact_matcher charset + drift-guard. v1.0.126 (#548 + #550 doctor/start.mjs) → HealthCheck protocol + bundle-derived integrity (PARTIAL — fixed in v1.0.127). v1.0.127 closes the loop: derivePluginManifest algorithmic helper now drives the boot gate too. Adapter #16 with new bundle = one line in package.json scripts.bundle, integrity check auto-extends.

Tests

253/253 pass on touched test files (per Mert's "only run new tests" directive — full suite skipped to avoid time waste; pre-existing baseline preserved). Targeted runs:

  • tests/hooks/require-security.test.ts: 7/7 (3 new + 4 amended for bundle-first)
  • tests/hooks/gemini-hooks.test.ts: 17/17 (3 new for dead-code excision)
  • tests/core/cli.test.ts: 152/152 (3 new for algorithmic Algo-D4)
  • tests/hooks/core-routing.test.ts: 77/77 (3 new for initSecurity bundle-first)

npm run typecheck: PASS after every slice.
npm run assert-bundle: 6/6 OK (security bundle joined the validated set).
ZERO new test files created (CONTRIBUTING L275).

Compatibility

15 adapters / 3 OS. Zero observable behavior change on healthy installs. Bundle-first is additive (build/ fallback preserved). Algorithmic Algo-D4 is a strict superset of the v1.0.126 hardcoded set — the 7 originals stay covered, plus hooks/security.bundle.mjs now joins. Marketplace install AND npm install paths both work end-to-end:

Install path Pre-v1.0.127 v1.0.127
Marketplace (git clone) build/security.js MISSING → silent fail-open hooks/security.bundle.mjs present (committed) → security enforced
npm install (tarball) build/security.js present → works both present, bundle-first → works
Dev environment (npm run build) both present → works both present → works

Upgrade

npm install -g context-mode@latest
# inside Claude Code / Codex / etc:
/ctx-upgrade
# restart your session — fully (Cmd+Q + reopen, /reload-plugins doesn't cycle MCP children)
/ctx-doctor   # new "Plugin cache integrity" panel now flags missing security bundle

If you've been running with permissions.deny configured but suspected they weren't enforced, v1.0.127 is the fix. The new SessionStart additionalContext will tell you immediately if your install is missing the security module.

Thanks

@AKhozya for the staff-grade #558 report — refs/platforms/claude-code/ cited, root cause traced through .gitignore + postinstall.mjs + prepublishOnly, prior debunk #249 explicitly distinguished, severity timeline calculated, 3 concrete fix proposals all evaluated. The additionalContext surfacing (Slice 4) is your proposal #3 shipped verbatim.

@nodnarbnitram for PR #555 — clean +23/-2, regression test included, CONTRIBUTING-compliant, 15-adapter parity preserved. Surfaced a deeper Pi detection precedence concern (tracked separately) without blocking this PR.

Don't miss a new context-mode release

NewReleases is sending notifications on new releases.