@compr/opscontext-mcp 2.5.2 → 2.5.4

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/dist/index.js CHANGED
@@ -10,9 +10,10 @@ import { collectProjectOps, collectSystemOps } from "./collectors.js";
10
10
  import { loadCache, saveCache } from "./cache.js";
11
11
  import { listProjects, checkPorts, runComplianceAudit, formatProjectList, formatPortMap, formatPlan, scoreProject, formatScoreReport, runScoreCanary, } from "./agents.js";
12
12
  import { saveSession, loadSession, listSessions, deleteSession, formatSession, formatSessionList, } from "./sessions.js";
13
- import { verifyChain, readAuditLog, filterByRange } from "./audit.js";
13
+ import { verifyChain, readAuditLog, filterByRange, autoRotateAuditLog } from "./audit.js";
14
14
  import { startEventIngestServer } from "./http-server.js";
15
15
  import { detect } from "./detector.js";
16
+ import { buildCostReport } from "./cost-report.js";
16
17
  import { saveLearning, searchLearnings, listLearnings, deleteLearning, learningsToChunks, learningsStats, formatLearnings, importLearningsFromFile, autoImportFromSources, LEARNING_CATEGORIES, } from "./learnings.js";
17
18
  import { communityRulesToChunks, mergeWithDedup, loadCommunityStore, } from "./community-sync.js";
18
19
  import { readFileSync, existsSync, watch, statSync, writeFileSync, mkdirSync } from "fs";
@@ -609,6 +610,9 @@ server.tool("audit_verify", "Verify the integrity of the local audit log chain.
609
610
  const summary = [];
610
611
  summary.push(`Audit chain: ${report.ok ? "✅ INTACT" : "❌ BROKEN"}`);
611
612
  summary.push(`Total records: ${report.total}`);
613
+ if ((report.redactedIndices ?? []).length > 0) {
614
+ summary.push(`Redacted and acknowledged on the chain: ${report.redactedIndices.length} record(s), not counted as altered`);
615
+ }
612
616
  if (since || until) {
613
617
  summary.push(`Range filter: ${since ?? "start"} → ${until ?? "now"} (${filtered.length} record(s) in range)`);
614
618
  }
@@ -623,6 +627,28 @@ server.tool("audit_verify", "Verify the integrity of the local audit log chain.
623
627
  return respond("audit_verify", summary.join("\n"));
624
628
  });
625
629
  // ---------------------------------------------------------------------------
630
+ // Tool: agent_cost (multi-agent token / cost / capacity report)
631
+ // ---------------------------------------------------------------------------
632
+ // Same renderer as `contextengine cost`. [LOCK] [COST-REPORT-ONE-RENDERER]
633
+ // Free tool: it reads the caller's own Claude Code transcripts on this machine,
634
+ // nothing leaves it. Added 2026-08-21, one day after the CLI (707fcc8).
635
+ server.tool("agent_cost", "Multi-agent cost report from Claude Code's own transcripts on this machine: tokens moved (cache read/write, fresh input, output), valued cost at API list prices (marked NOTIONAL on a subscription, UNPRICED when no rate matches), capacity intensity (subagents, failed, died at window, tool calls per agent, cache reuse), top runs, and context_burn / fanout_without_canary signals. Call it after a fan-out to read what it consumed, or before one to compare with the last. Thresholds come from .contextengine/policy.json agent_cost, else built-in defaults.", {
636
+ days: z.number().int().positive().optional().describe("Only runs started within the last N days"),
637
+ project: z.string().optional().describe("Filter by project slug as it appears in ~/.claude/projects (e.g. -Users-yan-Projects-ContextEngine)"),
638
+ session: z.string().optional().describe("Filter by parent session id"),
639
+ run: z.string().optional().describe("Filter by run id (wf_... or task group id)"),
640
+ top: z.number().int().positive().max(50).optional().describe("How many runs to list (default 10)"),
641
+ json: z.boolean().optional().describe("Return the structured JSON report instead of the text one"),
642
+ policy_dir: z.string().optional().describe("Absolute path of the repo whose .contextengine/policy.json supplies agent_cost thresholds and rates. Default: the MCP server's working directory, which under launchd is the home dir, not a repo; the report names which source it used on its 'thresholds:' line"),
643
+ }, async ({ days, project, session, run, top, json, policy_dir }) => {
644
+ // [COST-POLICY-DIR-IS-EXPLICIT] — the daemon's cwd is not a project. Without this the MCP
645
+ // surface silently priced with built-in defaults while the CLI in the repo read policy.json.
646
+ const report = buildCostReport({ days, project, session, run, top }, policy_dir || process.cwd());
647
+ if (json && report.json)
648
+ return respond("agent_cost", JSON.stringify(report.json, null, 2));
649
+ return respond("agent_cost", report.text);
650
+ });
651
+ // ---------------------------------------------------------------------------
626
652
  // Tool: drift_status (Detector — read current drift signals)
627
653
  // ---------------------------------------------------------------------------
628
654
  // Agents should call this between major task phases. If any 'critical' signal
@@ -1131,6 +1157,24 @@ async function main() {
1131
1157
  const transport = new StdioServerTransport();
1132
1158
  await server.connect(transport);
1133
1159
  console.error("[ContextEngine] 🚀 MCP server running on stdio (keyword search ready)");
1160
+ // 3a. Audit log auto-rotation. Deferred so the first requests are answered before the
1161
+ // synchronous verify + rewrite (a few seconds on a 500k-record chain) blocks the loop.
1162
+ // [LOCK] [AUTO-ROTATE-HYSTERESIS-AND-ONE-RUNNER]
1163
+ // Measured 2026-08-21: ~13k records/hour on this machine, so the 100k trigger is hours
1164
+ // away, not a day; a server that is never restarted must still rotate. Hourly recheck.
1165
+ const runAutoRotate = () => {
1166
+ try {
1167
+ const o = autoRotateAuditLog();
1168
+ if (o.action === "rotated" || o.action === "refused" || o.action === "error" || o.action === "in_progress") {
1169
+ console.error(`[ContextEngine] 📦 audit auto-rotate (${o.action}): ${o.detail}`);
1170
+ }
1171
+ }
1172
+ catch (err) {
1173
+ console.error(`[ContextEngine] ⚠ audit auto-rotate failed: ${err.message}`);
1174
+ }
1175
+ };
1176
+ setTimeout(runAutoRotate, 3_000).unref();
1177
+ setInterval(runAutoRotate, 60 * 60_000).unref();
1134
1178
  // 3b. Write server-meta.json so the VS Code extension can read tool count
1135
1179
  // without needing an active MCP session. Single source of truth =
1136
1180
  // src/tools-manifest.ts (asserted by tests/tools-manifest.test.ts).
@@ -24,14 +24,14 @@
24
24
  * Every tool name registered on the MCP server, in registration order.
25
25
  * Order is not load-bearing — kept stable for easier diffs.
26
26
  */
27
- export declare const ALL_TOOLS: readonly ["search_context", "list_sources", "read_source", "reindex", "list_projects", "check_ports", "run_audit", "score_project", "save_session", "load_session", "list_sessions", "delete_session", "audit_verify", "drift_status", "end_session", "save_learning", "list_learnings", "delete_learning", "import_learnings", "activate", "activation_status"];
27
+ export declare const ALL_TOOLS: readonly ["search_context", "list_sources", "read_source", "reindex", "list_projects", "check_ports", "run_audit", "score_project", "save_session", "load_session", "list_sessions", "delete_session", "audit_verify", "drift_status", "agent_cost", "end_session", "save_learning", "list_learnings", "delete_learning", "import_learnings", "activate", "activation_status"];
28
28
  /**
29
29
  * The 4 tools gated behind PRO activation. Subset of `ALL_TOOLS`.
30
30
  * Must match `PREMIUM_TOOLS` in `src/activation.ts` (asserted by test).
31
31
  */
32
32
  export declare const PREMIUM_TOOL_NAMES: readonly ["score_project", "run_audit", "check_ports", "list_projects"];
33
33
  /** Total count — what users see as "Active on all N MCP tools". */
34
- export declare const TOOL_COUNT: 21;
34
+ export declare const TOOL_COUNT: 22;
35
35
  /** Free-tier tool count — everything except `PREMIUM_TOOL_NAMES`. */
36
36
  export declare const FREE_TOOL_COUNT: number;
37
37
  //# sourceMappingURL=tools-manifest.d.ts.map
@@ -39,6 +39,7 @@ export const ALL_TOOLS = [
39
39
  "delete_session",
40
40
  "audit_verify",
41
41
  "drift_status",
42
+ "agent_cost",
42
43
  "end_session",
43
44
  "save_learning",
44
45
  "list_learnings",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compr/opscontext-mcp",
3
- "version": "2.5.2",
3
+ "version": "2.5.4",
4
4
  "description": "OpsContext for AI Agents — read-only fleet visibility (PM2/nginx/Docker/git/cron) + tamper-evident audit log + policy-as-code hooks. The ops + compliance layer Claude Code can't grow natively.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",