@compr/opscontext-mcp 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,10 +2,125 @@
2
2
 
3
3
  All notable changes to OpsContext for AI Agents (previously ContextEngine — MCP server + CLI) are documented here.
4
4
 
5
- ## [2.1.1] — 2026-06-23Phase 1c: one-command install + Claude Code terminal capture
5
+ ## [2.1.3] — 2026-06-26Tool manifest as single source of truth + server-meta.json for VS Code extension
6
+
7
+ Tactical fix for a class of silent display drift: the VS Code info panel hardcoded "Active on all 17 MCP tools" while the npm package was at 21 tools. The README was at 20. None of these were tied to the actual `server.tool(...)` registrations, so adding a tool (e.g. `drift_status` in 2.1.0) left all displays stale.
8
+
9
+ ### Added
10
+
11
+ - **`src/tools-manifest.ts`** — single source of truth for the tool catalog. Exports `ALL_TOOLS` (21 names), `PREMIUM_TOOL_NAMES` (4), `TOOL_COUNT`, `FREE_TOOL_COUNT`. Every `server.tool(...)` registration must appear in `ALL_TOOLS`.
12
+
13
+ - **`~/.contextengine/server-meta.json`** written on MCP server startup with `{ toolCount, freeCount, premiumCount, version, generatedAt }`. The VS Code extension reads this file (no active MCP session required) and uses it to render the info panel's tool-count claim dynamically. Falls back to "all MCP tools" (no number) if the file is missing.
14
+
15
+ - **`tests/tools-manifest.test.ts`** — 7 regression tests enforcing: `ALL_TOOLS.length === count(server.tool(...) in index.ts)`, every name in `ALL_TOOLS` is registered, every registered name is in `ALL_TOOLS`, `TOOL_COUNT` matches, `FREE_TOOL_COUNT` matches, `PREMIUM_TOOL_NAMES` is a subset of `ALL_TOOLS`, and `PREMIUM_TOOLS` (re-exported from activation.ts) equals `PREMIUM_TOOL_NAMES`. Adding/removing a tool requires updating both `src/index.ts` AND `src/tools-manifest.ts` together — no silent drift possible.
16
+
17
+ ### Changed
18
+
19
+ - **`src/activation.ts`** — `PREMIUM_TOOLS` is now a re-export of `PREMIUM_TOOL_NAMES` from the manifest (was a duplicate const). DRY without breaking the public API.
20
+
21
+ ### Why this isn't a feature, it's an anti-drift fix
22
+
23
+ The same class of drift hit the README ("20 tools" vs reality 21) and the info panel ("17 tools" vs reality 21). Both displays existed BEFORE `drift_status` shipped in 2.1.0; neither was updated. The fix isn't "remember to update the displays" — it's "make the displays read from the source of truth so they can't drift in the first place." The regression test makes it mechanical: tool added without manifest entry = CI red.
24
+
25
+ ---
26
+
27
+ ## [2.1.2] — 2026-06-25 — Audit-chain race fix + cliInit nudge + ESM install-autostart bug + LOCKED marketing-isolation + shared-learnings v1
28
+
29
+ Overnight pass on the Session 13 carry-forward queue. Several user-visible bug fixes + a load-bearing compliance hardening + Sprint-5's shared-learnings hybrid landing as v1.
30
+
31
+ ### Fixed
32
+
33
+ - **`audit-001-write-race` chain corruption** (carry-forward from Sessions 11–13 where the local audit log was broken at index 2826). `src/audit.ts` now uses file-lock + size-mismatch cache invalidation. Concurrent writers (activation server + main MCP) no longer race on `cachedLastHash`. LOCK `[AUDIT-001-WRITE-RACE-FIX]` documents the invariants. NEW test "concurrent-writer race" spawns 2 Node child processes that fire 20 appends each via `Promise.all` — without the lock the chain breaks at the first interleave; with the lock, verifyChain() stays clean (40 records, both workers represented). 197 → 276 tests after the shared-learnings additions; all green. Does NOT retroactively heal the existing broken chain (by design — tamper-evident); operators who need a clean anchor will get an `opscontext audit-rotate` subcommand in a follow-up.
34
+
35
+ - **`install-autostart` silent failure under ESM + npx** (audit M2). Package is `"type": "module"` so bare `__filename` was `undefined`; `dirname(__filename || "")` returned ".", silently breaking the dev-tree fallback. Users running `npx -y @compr/opscontext-mcp install-autostart` hit "Could not locate opscontext entrypoint" with no useful diagnostic. Fixed via `fileURLToPath(import.meta.url)` plus a NEW third resolver branch using `createRequire(import.meta.url).resolve("@compr/opscontext-mcp/dist/index.js")` (works inside npx's transient install cache). NEW `--entry=/path/to/dist/index.js` flag as explicit override for monorepo / private-registry / unconventional layouts. When all 3 detection paths fail, the error message now enumerates each path tried + suggests 3 user fixes (install globally, build a clone, pin `--entry`). LOCK `[M2-ESM-FILENAME-FIX]`.
36
+
37
+ ### Added
38
+
39
+ - **`opscontext export-learnings --tier <A|B>` + `opscontext sync-community-rules`** (Sprint-5 shared-learnings hybrid). The cross-machine learning-sharing pipeline:
40
+ - Tier A: free, MIT-licensed, ~100 sanitized "general-developer-pain" rules fetched from the future `github.com/FASTPROD/opscontext-community-rules` repo. Loss-leader for adoption.
41
+ - Tier B: PRO-gated, proprietary corpus daily-fetched from `api.compr.ch/contextengine/community-rules/fetch` using the existing Ed25519 license heartbeat. Subscription cancel → cache stales within 24h.
42
+ - `src/community-export.ts`: 13 sensitive-shape patterns + PII + personal-identifier + brand-name + path scrubbing. Tier A allow-list of categories (rejects security/deployment/infrastructure by default). Deterministic sha256 IDs for public stability. LOCK `[COMMUNITY-EXPORT-SAFETY]` guards the redactor coverage.
43
+ - `src/community-sync.ts`: Node built-in https. Tier A respects ETag/304. Tier B verifies Ed25519 signature + binds to `licenseToken` + `getMachineId()` + 36h freshness ceiling — closes the captured-once-replay-forever surface. LOCK `[COMMUNITY-SYNC-REPLAY-GUARD]`.
44
+ - `server/src/community-rules-server.ts`: POST endpoint with the same auth pattern as `/heartbeat` against `licenses.db`. Free-tier returns 403. Rate-limited 10/day/machine. **NOT YET DEPLOYED** to `api.compr.ch` — server code is in `server/src/` and requires manual rsync; until deployed, Tier B fetches fall back to cached store (graceful degradation by design).
45
+ - 75 new tests across the 3 components.
46
+
47
+ - **`opscontext init` cliInit nudge** (audit B3): when the existing init body completes, prints `💡 Next: run \`opscontext init-extension-secret\` to enable browser capture` if the secret file is missing. Doesn't fail init; just informs. Closes the README → Step-3 funnel without requiring the user to read the README first.
48
+
49
+ - **`learning.export` event kind** in the `AuditEvent` union. Every `opscontext export-learnings` invocation appends a `learning.export` record (tier, count, dropped, output-path-hash) so exports are themselves auditable — useful for the deploying org's compliance team.
50
+
51
+ ### Changed
52
+
53
+ - **`README.md`**: added a "Browser Capture" teaser callout near the top + a NEW "### 3. Capture browser + Claude Code events (optional)" section in Quick Start. Three subsections (browser secret, autostart, claude-code hook) with concrete commands and verification steps. Audit B3.
54
+
55
+ - **`src/audit.ts`** module banner reworded: SOC 2 / ISO 27001 framing now uses the "evidence aligned with..., not a certification" hedge (Session 13 H4 sweep follow-through into the comments + LOCK rationale).
56
+
57
+ - **`src/cli.ts`** `audit-export --help`: SOC 2 / ISO 27001 references hedged per the H4 sweep.
58
+
59
+ - **`src/index.ts`**: `audit_verify` MCP tool description hedged per the H4 sweep. Every connected AI agent at tool-discovery time now sees the "evidence artifacts, not a certification" framing.
60
+
61
+ ### Security
62
+
63
+ - **`src/activation.ts` LOCK `[ACTIVATION-PAYLOAD-NO-USAGE-DATA]`** (Session 13, included in this release): explicit forbiddance on adding a 7th field to the activation POST body. The 6 fields (`key, email, machineId, version, platform, arch`) are the COMPLETE set by deliberate product commitment. Marketing-isolation enforcement at the most likely silent-drift attack surface. Documented publicly in `docs/about.md § "Marketing-data isolation (LOCKED commitment)"`.
64
+
65
+ ### Known limitations (intentional carry-forward)
66
+
67
+ - The pre-existing audit-chain break at index 2826 is NOT retroactively healed (tamper-evident property must be preserved). `opscontext audit-rotate` is a follow-up.
68
+ - `learning.export`'s output JSON shape may evolve in a future release; the v1 schema is documented in `src/community-export.ts`.
69
+ - Server-side ETag/If-None-Match response support for the community-rules endpoint is not yet wired (the client respects ETag/304 from any server that sends it).
70
+ - The `chrome-extension/src/content/shared/redact.ts` redactor is not yet mirrored with the new PROJECT_BRAND_NAMES + CONTACT_IDENTIFIERS lists. Filed as a follow-up.
71
+
72
+ ## [vscode-ext 0.11.0] — 2026-06-24 — Drift alerts surfaced in VS Code UI (L2 → in-editor gap closed)
73
+
74
+ Closes the last gap in the L1→L2→L3 drift pipeline:
75
+
76
+ - **L1 (already shipped, 2.1.0):** `opscontext watch` CLI runs the 8-heuristic drift detector against the live `~/.contextengine/audit.log` and writes `drift.detected` records back into the same log (`src/detector.ts:387` → `safeAppend("drift.detected", ...)`).
77
+ - **L2 (NEW — this release):** `vscode-extension/src/driftAlertPoller.ts` tails the audit log on a 15s interval, parses each new `drift.detected` record, dedupes by byte-offset cursor + per-record hash LRU + per-kind time throttle, and forwards survivors to the notification layer.
78
+ - **L3 (NEW — this release):** `NotificationManager.showDriftAlert()` routes severity → VS Code dialog tier: `info` → info popup, `warn` → non-modal warning, `critical` → MODAL warning (OS-level interrupt). Each notification offers **Show Audit Log** / **Mute this kind** / **Dismiss** actions.
79
+
80
+ Before 0.11.0, drift signals fired by the CLI watcher were visible only in the terminal (`opscontext watch --json | log-aggregator`) or via the `drift_status` MCP tool. The VS Code extension had a perfectly good `NotificationManager` for git-dirty escalations and stale-doc warnings, but no surface for drift alerts. So a user with the extension running and the CLI watcher running could have a `silent_failure` or `fabrication_suspect` signal sitting in their audit log for 20 minutes and never see a popup. That's the gap this release closes.
81
+
82
+ ### Added
83
+ - **`vscode-extension/src/driftAlertPoller.ts`** — new `vscode.Disposable` that tails `~/.contextengine/audit.log` (resolution mirrors `src/audit.ts auditDir()` — `process.env.CONTEXTENGINE_HOME || homedir()/.contextengine`). Polls every 15 s (mirroring `StatsPoller`'s interval). Persists byte-offset cursor + mute list in `vscode.ExtensionContext.workspaceState` (falls back to `~/.contextengine/vscode-drift-cursor.json` when run outside an extension host — keeps tests + integration scripts honest). Handles audit-log truncation / rotation by resetting the cursor when the file shrinks. Tracks the last 500 seen record hashes as a bounded-LRU safety net for fs-watcher races + partial-line reads.
84
+ - **`NotificationManager.showDriftAlert(rec, opts)`** — added to `vscode-extension/src/notifications.ts`. Gated by `contextengine.enableNotifications` (master switch) AND `contextengine.enableDriftAlerts` (new, defaults true — gives users a single-toggle opt-out for drift specifically without losing git-dirty warnings).
85
+ - **`contextengine.showDriftLog`** command — registered as the click target for the "Show Audit Log" action on drift-alert popups. Reads `~/.contextengine/audit.log`, filters to `event === "drift.detected"`, renders the last 200 records to the OpsContext output channel newest-first.
86
+ - **`contextengine.alertHistory`** command — palette-driven entry point to the same drift history viewer. Two commands, one implementation, so the notification action and the user-facing palette entry can evolve independently.
87
+ - **`contextengine.enableDriftAlerts`** setting — boolean, default `true`. Disables ONLY drift surfacing; the poller still tails the log and the in-extension EventEmitter still fires (so future surfaces — info panel, future webview — keep working), but no popups appear.
88
+ - **`vscode-extension/src/driftAlertPoller.test.ts`** — first test file inside `vscode-extension/`. Uses a tiny in-file `vscode` mock + Node's built-in `node:assert/strict` + `node:test` so we don't pull a new dev dependency. Covers the four invariants from the spec: (1) synthetic `drift.detected` line → `NotificationManager.showDriftAlert` fired with correct severity + message; (2) second poll on the same line does NOT re-fire (hash dedup); (3) muting a kind suppresses subsequent popups; (4) `dispose()` is clean (timer stopped, cursor persisted, no throws).
89
+
90
+ ### Dedup strategy (in priority order)
91
+ 1. **Byte-offset cursor** (primary, persisted). Stat the file, read only the tail bytes added since last poll, advance cursor to the last full newline so records never split. Reset to 0 on truncation.
92
+ 2. **Per-record hash LRU** (in-memory, bounded at 500). Catches fs-watch double-fire + the rare "poll saw a partial line then re-saw the same record after the newline arrived" race.
93
+ 3. **Per-kind time throttle** (5 min, mirroring `NotificationManager.MIN_INTERVAL_MS`). Non-critical alerts of the same kind within the window are suppressed at the popup layer but still fire the `onDrift` EventEmitter (so the info panel / future webview still updates). `severity === "critical"` bypasses — those are OS-level interrupts.
94
+ 4. **User mute list** (persisted). Clicking "Mute this kind" on a popup adds the `DriftKind` to a mute set; that kind never surfaces a popup again on this machine until the user removes it (still logged to output channel for auditability).
95
+
96
+ ### No conflict with `terminalWatcher.ts`
97
+ The existing `terminalWatcher.ts` notifies on consecutive terminal-command exit-code failures inside the VS Code process. It does NOT read `audit.log` and does NOT write `drift.detected`. The new `DriftAlertPoller` exclusively consumes `event === "drift.detected"` records written by the separate `opscontext watch` CLI. Disjoint event sources, disjoint UI paths, no dedup needed between them.
98
+
99
+ ### Why minor (0.10 → 0.11)
100
+ Net-new in-editor capability: a surface that previously had no drift-alert UI now has popup notifications + audit-log viewer commands. No breaking changes — existing commands, settings, chat handle behave identically.
101
+
102
+ ## [chrome-ext 0.1.3] — 2026-06-23 — streaming-dedupe polish (response over-emit fix)
103
+
104
+ Companion to 2.1.1. Chrome-ext-only release; not on Web Store yet — users reload the unpacked dir.
105
+
106
+ ### Fixed
107
+ - **`chrome-extension/src/content/claude.ts`** — single response no longer fires 6× during streaming. Root cause: the dedupe key included `text.length` (`r:${i}:${text.length}:${text.slice(0,64)}`). debounceSettle (750 ms) fired multiple times as Claude's response grew; each settle saw a longer text, so the length-in-key differed, the Set check missed, and the same response re-emitted on every settle observation. Fix: drop length from the key + replace document-wide `anyDone` with a per-block `isBlockDone` that walks up 5 ancestor levels looking for an `action-bar-copy` button. Per-block scoping is critical: while turn N+1 is mid-stream, turn N still has its copy button → document-wide check would emit turn N+1 partial. LOCK `[RESPONSE-DEDUPE]`.
108
+ - **`chrome-extension/src/content/chatgpt.ts`** — same bug class fixed in mirror file. `captureResponses` had the same length-in-key pattern; `captureToolCalls` had no done-marker check at all, so tool args streamed → emit on every characterData mutation. Both now use the existing `data-message-author-role="assistant"` turn ancestor + copy button check + prefix-only key. LOCK `[RESPONSE-DEDUPE-CHATGPT]`.
109
+
110
+ ### Process note
111
+ - Designed via a Workflow run (`wf_f9bf9bbc-46a`) with 3 parallel design proposals (length-stability, longer-debounce, hybrid-stability) + audit of chatgpt.ts + adversarial verification from 3 lenses (miss responses / dedupe preservation / chatgpt generalization). All 3 verifiers blocked the synthesizer's chosen "two-settle stability gate" design — concrete failure: a stream that finishes generates ONE final settle, not two, so the gate never fires and the response is silently dropped. All three verifiers converged on the same suggested fix (per-block done-marker check). That's what shipped here.
112
+ - 8 agents, 236K tokens, ~6.7 min. The adversarial verification phase paid for itself by catching the silent-drop failure mode before it shipped.
113
+
114
+ ## [2.1.1] — 2026-06-23 — Phase 1c: one-command install + Claude Code terminal capture + browser-capture end-to-end
115
+
116
+ **Published to npm** as `@compr/opscontext-mcp@2.1.1` on 2026-06-23 after end-to-end live verification on the maintainer's machine. Tarball 162.3 kB / 57 files. Latest dist-tag confirmed.
6
117
 
7
118
  Closes the last surface gap from 2.1.0. Before this patch, "use OpsContext" meant running `nohup npx ...` every time the Mac restarted and hand-editing `~/.claude/settings.json` to wire Claude Code hooks. Now both are single commands. This is the release that lets non-technical users actually adopt OpsContext.
8
119
 
120
+ ### Browser-capture surface verified live
121
+
122
+ End-to-end verified on the maintainer's machine 2026-06-23: prompts typed on https://claude.ai land in `~/.contextengine/audit.log` as `browser.prompt` events, Claude's responses land as `browser.response` events. Required several mid-day fixes (Chrome MV3 module-import bug, selector drift on Anthropic's DOM, React-clear race on input intercept). All fixed in companion `@compr/opscontext-chrome@0.1.2` (repo-only, unpacked install).
123
+
9
124
  ### Added
10
125
  - **`src/install-autostart.ts`** (LOCK `[AUTOSTART-INSTALL]`) — installs a macOS LaunchAgent at `~/Library/LaunchAgents/com.opscontext.mcp.plist`. Set-and-forget — server starts at every login, KeepAlive restarts on crash, logs to `~/.contextengine/logs/mcp-{stdout,stderr}.log`. Companion `uninstall-autostart` + `autostart-status` commands. Auto-detects either a global npm install or a dev tree; pins node path absolutely (launchd has no PATH).
11
126
  - **`src/install-claude-hook.ts`** (LOCK `[CLAUDE-HOOK-INSTALL]`) — copies `defaults/claude-code-hook.sh` to `~/.claude/hooks/opscontext-emit.sh` and splices three entries into `~/.claude/settings.json` under `hooks`: `UserPromptSubmit` → `vscode.prompt_submit`, `PostToolUse` (`.*` matcher) → `vscode.tool_call`, `SessionStart` → `vscode.session_start`. **Idempotent + preserves every existing hook entry** (backs up settings.json before any change). Closes the terminal-side capture gap — every Claude Code session in any project now feeds the audit log.
@@ -235,7 +350,7 @@ Highlights, in dependency order:
235
350
 
236
351
  ### Added (audit log workstream — P0 #3, part 1 of 2)
237
352
  - **`src/audit.ts`** — hash-chained JSONL audit log at `~/.contextengine/audit.log`. Every state-changing operation appends one canonically-serialized record with `{ts, event, actor, payload, prev_hash, hash}`. The chain is rooted at a 64-zero genesis hash; each record's hash covers the canonical bytes of itself plus its `prev_hash`, so any historical mutation breaks chain verification at the mutated index.
238
- - Compliance basis: SOC2 CC7.2 (audit logging), ISO 27001 A.12.4.1 (event logs).
353
+ - Compliance: produces evidence aligned with SOC 2 CC7.2 (change monitoring) + ISO 27001 A.12.4.1 (event logging). **Evidence artifacts, not a certification** — OpsContext is not itself SOC 2– or ISO 27001–certified. (Wording updated 2026-06-23, Session 12 H4 sweep.)
239
354
  - Privacy: records carry **metadata only** — IDs, categories, projects, lengths. Never the rule text, session value content, or license signature.
240
355
  - `safeAppend()` wrapper isolates audit failures from production hot paths (failed appends log to stderr only — they cannot break a learning save or session write).
241
356
  - Paths injectable via `CONTEXTENGINE_HOME` env var so tests run against `mkdtempSync` without touching real `~/.contextengine`.
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # OpsContext for AI Agents
2
2
 
3
- **The ops + compliance layer Claude Code can't grow natively.** Read-only visibility into PM2 / nginx / Docker / git / cron — plus a tamper-evident audit log and policy-as-code git hooks.
3
+ **AI that doesn't break what it can't see.**
4
+
5
+ Claude Code, Cursor, and Copilot write code without seeing your servers — so they suggest the wrong port, restart the wrong service, deploy into the wrong env. OpsContext gives them eyes on what's actually running, plus a tamper-proof log of every change they make. Free core, no signup, runs entirely on your machine.
4
6
 
5
7
  > Previously published as `@compr/contextengine-mcp`. The 2.0 rename reflects what the project actually does: Claude Code sees the **code**, OpsContext sees the **infra that runs it**.
6
8
 
@@ -10,6 +12,8 @@
10
12
 
11
13
  OpsContext is an [MCP](https://modelcontextprotocol.io) server. It runs locally, snapshots your live infra (PM2 processes, nginx config, Docker containers, git status, cron jobs, redacted env), and exposes it via tools your AI coding agents (Claude Code, Cursor, Copilot, Windsurf, OpenClaw) can call in real time. Everything stays on your machine — no telemetry, no code uploads.
12
14
 
15
+ > **🌐 Browser Capture (Phase 1, shipped 2026-06):** OpsContext now captures prompts + assistant responses + tool calls from **Claude.ai**, **ChatGPT.com**, *and* your **Claude Code** terminal sessions into the same hash-chained audit log. Cross-surface drift detection becomes possible (e.g. catch when a model says one thing in the browser and another in the terminal). See [Step 3](#3-capture-browser--claude-code-events-optional) below.
16
+
13
17
  ## Why
14
18
 
15
19
  Claude Code already reads your `CLAUDE.md`, `copilot-instructions.md`, and source files. It has hooks, skills, and native memory. It does not — and structurally cannot — see what's running on your servers. Live process state, nginx routes, port conflicts across fleets, git working-tree drift across 30+ repos — that's the operational context AI agents lack.
@@ -17,7 +21,7 @@ Claude Code already reads your `CLAUDE.md`, `copilot-instructions.md`, and sourc
17
21
  OpsContext fills that gap, plus two compliance layers regulated industries demand from any agent stack:
18
22
 
19
23
  1. **Operational visibility (the moat)** — collectors for PM2 / nginx / Docker / git / cron / .env (redacted) / composer / systemd. Cross-project + check_ports + fleet HTML scoring. Claude Code can't see this; we feed it cleanly.
20
- 2. **Tamper-evident audit log (compliance)** — hash-chained JSONL at `~/.contextengine/audit.log`. Every state change recorded with `prev_hash`/`hash`. SOC2 CC7.2 and ISO 27001 A.12.4.1 evidence out of the box.
24
+ 2. **Tamper-evident audit log (compliance)** — hash-chained JSONL at `~/.contextengine/audit.log`. Every state change recorded with `prev_hash`/`hash`. Designed to produce evidence aligned with [SOC 2 CC7.2 (change monitoring)](docs/compliance/cc7.2.md) and [ISO 27001 A.12.4.1 (event logging)](docs/compliance/a.12.4.1.md). **These are evidence artifacts, not a certification.** OpsContext is not itself SOC 2– or ISO 27001–certified; the audit log helps *your* org's auditor satisfy *those* controls.
21
25
  3. **Policy-as-code hooks (enforcement)** — declarative `.contextengine/policy.json` for secret patterns (with `paths` scoping), diff-aware doc coverage (replaces the workaround-y 4-hour staleness gate), deploy-verify hosts, and signed bypass tokens. Runs as a pre-commit hook layer alongside gitleaks.
22
26
 
23
27
  Plus the persistent-memory + search features carried forward from the contextengine era:
@@ -121,7 +125,54 @@ cp -r node_modules/@compr/opscontext-mcp/skills/contextengine ~/.openclaw/worksp
121
125
  }
122
126
  ```
123
127
 
124
- ### 3. Pin your config (recommended)
128
+ ### 3. Capture browser + Claude Code events (optional)
129
+
130
+ Phase-1 browser capture wires Claude.ai / ChatGPT.com / Claude Code into the same hash-chained audit log the MCP server already writes to. Three small commands; each one is independent.
131
+
132
+ **3a. Generate the browser extension secret**
133
+
134
+ ```bash
135
+ npx @compr/opscontext-mcp init-extension-secret
136
+ ```
137
+
138
+ Writes a 32-byte hex token to `~/.contextengine/extension-secret` (mode `0600`). The Chrome extension authenticates to your local MCP server with this secret — nobody else on your network can post events.
139
+
140
+ Verify:
141
+ ```bash
142
+ ls -la ~/.contextengine/extension-secret # → -rw------- (0600)
143
+ ```
144
+
145
+ Then load the unpacked extension and paste the secret into its Options page. Full install steps (build, load unpacked, paste secret): [chrome-extension/README.md](chrome-extension/README.md). *(Chrome Web Store listing coming.)*
146
+
147
+ **3b. Auto-start the local server (macOS)**
148
+
149
+ ```bash
150
+ npx @compr/opscontext-mcp install-autostart
151
+ ```
152
+
153
+ Installs a LaunchAgent so OpsContext binds `127.0.0.1:7842` on every login — that's the port the browser extension and the Claude Code hook both post to.
154
+
155
+ Verify:
156
+ ```bash
157
+ curl http://127.0.0.1:7842/health # → {"ok":true,...}
158
+ ```
159
+
160
+ Companion commands: `uninstall-autostart`, `autostart-status`.
161
+
162
+ **3c. Wire Claude Code terminal sessions**
163
+
164
+ ```bash
165
+ npx @compr/opscontext-mcp install-claude-hook
166
+ ```
167
+
168
+ Adds `UserPromptSubmit`, `PostToolUse`, and `SessionStart` hook entries to `~/.claude/settings.json` so every Claude Code prompt + tool call lands in the same audit log as the browser events.
169
+
170
+ Verify:
171
+ ```bash
172
+ npx @compr/opscontext-mcp watch --once # → tails recent events; should show claude_code_* kinds after one prompt
173
+ ```
174
+
175
+ ### 4. Pin your config (recommended)
125
176
 
126
177
  If you have a `contextengine.json` with custom sources, add this to your shell profile (`~/.zshrc` or `~/.bashrc`):
127
178
 
@@ -150,7 +201,7 @@ The extension reads live metrics from the MCP server (via `~/.contextengine/sess
150
201
 
151
202
  ## ⭐ PRO Features
152
203
 
153
- ContextEngine is **free and open-core**. The free tier covers everything agents need — search, memory, sessions, and compliance enforcement. PRO adds **team and ops intelligence** across multiple projects:
204
+ OpsContext is **source-available with a free tier**. The free tier covers everything agents need — search, memory, sessions, and compliance enforcement. PRO adds **team and ops intelligence** across multiple projects. Licensed under [BSL-1.1](LICENSE), which is *not* OSI-approved open source (converts to AGPL-3.0 on 2030-02-22). See [docs/about.md](docs/about.md) for the full publisher disclosure and licensing intent.
154
205
 
155
206
  | Feature | Free | PRO |
156
207
  |---------|------|-----|
@@ -241,7 +292,7 @@ CLI mode uses keyword search (BM25) which is instant — no model loading requir
241
292
  | `list_learnings` | List all permanent learnings, optionally by category | Free |
242
293
  | `delete_learning` | Remove a learning by ID | Free |
243
294
  | `import_learnings` | Bulk-import learnings from Markdown or JSON files | Free |
244
- | `audit_verify` | Verify tamper-evident audit log chain (SOC2 CC7.2, ISO 27001 A.12.4.1) | Free |
295
+ | `audit_verify` | Verify tamper-evident audit log chain (evidence aligned with [SOC 2 CC7.2](docs/compliance/cc7.2.md), [ISO 27001 A.12.4.1](docs/compliance/a.12.4.1.md) — not a certification) | Free |
245
296
  | `activate` | Activate a PRO license on this machine | Free |
246
297
  | `activation_status` | Check current license status | Free |
247
298
  | `list_projects` | Discover and analyze all projects (tech stack, git, docker) | PRO |
@@ -464,7 +515,21 @@ For commercial licensing: [yannick@compr.ch](mailto:yannick@compr.ch)
464
515
 
465
516
  ---
466
517
 
467
- ## Built by [PROD LLC](https://compr.fr)
518
+ ## Publisher
468
519
 
469
- ContextEngine is built by the team behind
470
- [compr.app](https://compr.app) · [crowlr.io](https://crowlr.io) · [crowlr.com](https://crowlr.com) · [invoc.io](https://invoc.io) · [plank.io](https://plank.io) · [konive.com](https://konive.com) · [invoc.me](https://invoc.me)
520
+ **OpsContext is built by PROD LLC**, an operating brand of **[CSS LLC](https://compr.fr)** — a Swiss company incorporated in 2005.
521
+
522
+ The VS Code Marketplace lists the extension under the legal-parent publisher ID `css-llc`; the npm package is published under the `@compr` scope. Both belong to the same entity.
523
+
524
+ PROD LLC also operates these product brands:
525
+
526
+ | Brand | What it does | Site |
527
+ |---|---|---|
528
+ | **FASTPROD** | DevOps + sysadmin operator (the team behind this project) | [fast-prod.com](https://fast-prod.com) |
529
+ | **CROWLR** | Crawling + monitoring platform | [crowlr.io](https://crowlr.io) · [admin.crowlr.com](https://admin.crowlr.com) |
530
+ | **KONIVE** | (product) | [konive.com](https://konive.com) |
531
+ | **INVOC** | (product) | [invoc.io](https://invoc.io) · [invoc.me](https://invoc.me) |
532
+ | **PLANK** | (product) | [plank.io](https://plank.io) |
533
+ | **compR** | Portfolio + benchmark widget | [compr.fr](https://compr.fr) · [compr.app](https://compr.app) |
534
+
535
+ Contact: [yannick@compr.ch](mailto:yannick@compr.ch). Full corporate disclosure at [docs/about.md](docs/about.md).
@@ -51,13 +51,12 @@ export const PREMIUM_MODULES = [
51
51
  "agents", // scorer, auditor, port checker, HTML report formatters
52
52
  "search-adv", // advanced BM25 with tuned parameters
53
53
  ];
54
- // Tools that require activation
55
- export const PREMIUM_TOOLS = [
56
- "score_project",
57
- "run_audit",
58
- "check_ports",
59
- "list_projects",
60
- ];
54
+ // Tools that require activation. Re-exported from the central manifest so
55
+ // the count and the name list have a SINGLE source of truth. Adding a new
56
+ // PRO tool requires editing src/tools-manifest.ts (which also feeds the
57
+ // VS Code extension's info panel via ~/.contextengine/server-meta.json).
58
+ import { PREMIUM_TOOL_NAMES } from "./tools-manifest.js";
59
+ export const PREMIUM_TOOLS = PREMIUM_TOOL_NAMES;
61
60
  // ---------------------------------------------------------------------------
62
61
  // Machine fingerprint (non-PII)
63
62
  // ---------------------------------------------------------------------------
@@ -132,6 +131,27 @@ function saveLicense(license) {
132
131
  // ---------------------------------------------------------------------------
133
132
  // Activation flow
134
133
  // ---------------------------------------------------------------------------
134
+ // 🔒 LOCKED [ACTIVATION-PAYLOAD-NO-USAGE-DATA] — 2026-06-24
135
+ // ⛔ NEVER add fields to the activation POST body that reflect user
136
+ // USAGE — no project paths, no prompt text, no response text, no
137
+ // tool-call inventory, no file lists, no learning IDs, no audit-log
138
+ // sample, no anything that describes what the customer is doing with
139
+ // OpsContext. The activation server's job is license validation,
140
+ // nothing else.
141
+ // ⛔ NEVER share this list with marketing tools (Stripe customer record
142
+ // is the ONLY place email lands; never join it to usage data).
143
+ // WHY: This is the LOAD-BEARING commitment of docs/about.md §
144
+ // "Marketing-data isolation". Customers using OpsContext are NOT and
145
+ // WILL NOT be associated with any marketing audience operated by
146
+ // PROD LLC or any sibling brand (CROWLR, KONIVE, INVOC, FASTPROD,
147
+ // compR). Adding a single usage field here breaks that contract
148
+ // silently and starts a slow drift toward telemetry — exactly the
149
+ // posture this product was designed to NOT have.
150
+ // FIX: If a future feature legitimately needs server-side telemetry
151
+ // (e.g. a "drift alerts emailed daily" subscription), it requires
152
+ // EXPLICIT per-user opt-in via a separate endpoint with its own
153
+ // payload schema — NOT bundling fields into the license-activation
154
+ // path that every PRO customer hits unconditionally.
135
155
  export async function activate(licenseKey, email) {
136
156
  try {
137
157
  const machineId = getMachineId();
@@ -139,6 +159,8 @@ export async function activate(licenseKey, email) {
139
159
  method: "POST",
140
160
  headers: { "Content-Type": "application/json" },
141
161
  body: JSON.stringify({
162
+ // The 6 fields below are the COMPLETE set the activation server
163
+ // ever sees. Read the LOCK above before adding a 7th.
142
164
  key: licenseKey,
143
165
  email,
144
166
  machineId,
package/dist/agents.d.ts CHANGED
@@ -102,9 +102,27 @@ export interface ScoreCheck {
102
102
  category: string;
103
103
  points: number;
104
104
  maxPoints: number;
105
- status: "pass" | "partial" | "fail";
105
+ status: "pass" | "partial" | "fail" | "unknown";
106
106
  detail: string;
107
107
  }
108
+ /**
109
+ * 🔒 LOCKED [ABSENCE-IS-NOT-A-VERDICT] — 2026-08-13
110
+ * ⛔ NEVER emit "pass" or "fail" for a condition the check could not actually determine,
111
+ * and NEVER write a detail string that hides WHICH locations were inspected.
112
+ * WHY: three live bugs, all the same shape — the scorer wrote *absence of evidence* down as
113
+ * a *verdict*, and the verdict pointed at the wrong fix.
114
+ * 1. `copilot-instructions.md`/`SKILLS.md` looked only in .github/ and reported files that
115
+ * existed at the repo root as "Missing" (fixed ffa5914, [DOC-PATH-DUAL]).
116
+ * 2. `Git hooks` reported "No hooks — consider auto-push" for a hook that WAS installed but
117
+ * whose symlink target had been deleted. existsSync() follows symlinks, so dangling and
118
+ * absent are indistinguishable. CE's own Drive backup drifted while the row said
119
+ * "consider auto-push" — advice for a problem the repo did not have.
120
+ * 3. `Secrets exposure` awarded a full 6/6 PASS with the detail "No .env or not a git repo" —
121
+ * full marks for a state it openly could not distinguish.
122
+ * FIX: a check that cannot determine its condition emits status "unknown" (0 points, rendered ❔,
123
+ * excluded from the remediation list — it is a gap in the CHECK, not in the project). Every
124
+ * pass/fail detail must name what was inspected. Absence is a measurement, not a decision.
125
+ */
108
126
  export interface ProjectScore {
109
127
  project: string;
110
128
  path: string;
@@ -114,6 +132,14 @@ export interface ProjectScore {
114
132
  grade: string;
115
133
  checks: ScoreCheck[];
116
134
  }
135
+ export interface CanaryResult {
136
+ ok: boolean;
137
+ /** Human-readable deviations from the pinned expectation. Empty when ok. */
138
+ deviations: string[];
139
+ /** True when the canary itself could not be built — an unknown, not a failure. */
140
+ inconclusive: boolean;
141
+ }
142
+ export declare function runScoreCanary(): CanaryResult;
117
143
  /**
118
144
  * Score a project's AI-readiness (0-100%).
119
145
  * Checks how well-prepared a project is for AI coding agents.