auxilo-mcp 0.9.2 → 0.9.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.
@@ -0,0 +1,35 @@
1
+ /**
2
+ * scripts/sources/roo-code.js — Roo Code (VS Code extension) Transcript Source (UC-3)
3
+ *
4
+ * Roo Code is a maintained fork of Cline and preserves its storage layout:
5
+ *
6
+ * <vscode-user-dir>/globalStorage/<publisher>/tasks/<taskId>/
7
+ * api_conversation_history.json
8
+ *
9
+ * Publisher dirs probed (the extension id changed across releases):
10
+ * rooveterinaryinc.roo-cline (original "Roo Cline" id, still used)
11
+ * rooveterinaryinc.roo-code (post-rename id)
12
+ *
13
+ * Everything else — discovery, the Anthropic-messages format probe,
14
+ * normalization, fail-silent refusal — is inherited from ClineSource.
15
+ *
16
+ * NOTE (2026-07-19): like cline.js, built from the documented fork layout;
17
+ * no Roo Code installation existed on the build machine to verify against.
18
+ * Strict probe + fail-silent (UC §5). Publicly labeled best-effort (UC-3).
19
+ *
20
+ * @module sources/roo-code
21
+ */
22
+
23
+ 'use strict';
24
+
25
+ const { ClineSource } = require('./cline');
26
+
27
+ class RooCodeSource extends ClineSource {
28
+ static id = 'roo-code';
29
+ static displayName = 'Roo Code (VS Code)';
30
+ static version = '1.0.0';
31
+
32
+ static publisherDirs = ['rooveterinaryinc.roo-cline', 'rooveterinaryinc.roo-code'];
33
+ }
34
+
35
+ module.exports = { RooCodeSource };
@@ -13,6 +13,50 @@
13
13
 
14
14
  'use strict';
15
15
 
16
+ const fs = require('fs');
17
+
18
+ // ─── Session read-size cap (Wave 5C N1) ─────────────────────────────────────
19
+ //
20
+ // discoverSessions() returns `bytes` per the contract above, but nothing ever
21
+ // enforced a ceiling: every adapter's readSession() did an unbounded
22
+ // fs.readFileSync (54MB observed in the wild; a multi-GB transcript OOMs a
23
+ // constrained sweeper node) — all to feed a pipeline that truncates to 30k
24
+ // chars anyway (runner.js MAX_CHARS).
25
+ //
26
+ // Why 64MB: the ceiling's job is OOM-protection, not thrift. 54MB was proven
27
+ // in the wild AND extracted successfully — a cap below that silently regresses
28
+ // real coverage (the exact silent-loss class Wave 5C closes). 64MB = proven
29
+ // max + ~18% headroom; worst-case read peaks at low-hundreds-MB RSS
30
+ // (survivable on a 512MB node) while multi-GB is structurally refused.
31
+ // Constrained sweepers tighten via AUXILO_MAX_SESSION_BYTES.
32
+
33
+ const DEFAULT_MAX_SESSION_BYTES = 64 * 1024 * 1024;
34
+
35
+ /**
36
+ * Resolve the effective cap. Env override AUXILO_MAX_SESSION_BYTES must be a
37
+ * positive integer; anything else (absent, garbage, zero, negative) falls back
38
+ * to the default. Read at CALL time, not module load, so sweepers and tests
39
+ * can tune per-invocation.
40
+ */
41
+ function resolveMaxSessionBytes(env = process.env) {
42
+ const raw = env.AUXILO_MAX_SESSION_BYTES;
43
+ if (raw === undefined || raw === null || raw === '') return DEFAULT_MAX_SESSION_BYTES;
44
+ const n = Number(raw);
45
+ if (!Number.isInteger(n) || n <= 0) return DEFAULT_MAX_SESSION_BYTES;
46
+ return n;
47
+ }
48
+
49
+ /** Thrown by readSessionCapped BEFORE any read when a session exceeds the cap. */
50
+ class SessionTooLargeError extends Error {
51
+ constructor(sessionRef, bytes, maxBytes) {
52
+ super(`Session ${sessionRef && sessionRef.sessionId ? sessionRef.sessionId : '(unknown)'} is ${bytes} bytes — exceeds the ${maxBytes}-byte cap (AUXILO_MAX_SESSION_BYTES)`);
53
+ this.name = 'SessionTooLargeError';
54
+ this.code = 'SESSION_TOO_LARGE';
55
+ this.bytes = bytes;
56
+ this.maxBytes = maxBytes;
57
+ }
58
+ }
59
+
16
60
  /**
17
61
  * Abstract base class for transcript source adapters.
18
62
  *
@@ -67,6 +111,40 @@ class TranscriptSource {
67
111
  throw new Error('TranscriptSource.readSession() must be implemented by subclass');
68
112
  }
69
113
 
114
+ /**
115
+ * Size-capped session read — the ONLY entry point the runner uses (N1).
116
+ *
117
+ * CONCRETE on the base class so every adapter (including the generic-jsonl
118
+ * fallback and any future self-registered UC-3 adapter) inherits the cap
119
+ * through the shared path — no per-adapter copies. Size resolution: a fresh
120
+ * fs.statSync of sessionRef.path when the file stats (authoritative, costs
121
+ * nothing), else the discoverSessions-supplied sessionRef.bytes. Over-cap
122
+ * throws SessionTooLargeError BEFORE any byte is read; callers treat
123
+ * code === 'SESSION_TOO_LARGE' as a counted skip, never a failure.
124
+ *
125
+ * Subclasses must NOT override this — override readSession() only.
126
+ *
127
+ * @param {object} sessionRef - A session reference from discoverSessions()
128
+ * @returns {Promise<{transcript: string, metadata: object}>}
129
+ * @throws {SessionTooLargeError} when the session exceeds the cap
130
+ */
131
+ async readSessionCapped(sessionRef) {
132
+ const maxBytes = resolveMaxSessionBytes();
133
+ let bytes = null;
134
+ if (sessionRef && sessionRef.path) {
135
+ try { bytes = fs.statSync(sessionRef.path).size; } catch { /* fall through */ }
136
+ }
137
+ if (bytes === null && sessionRef && Number.isFinite(sessionRef.bytes)) {
138
+ bytes = sessionRef.bytes;
139
+ }
140
+ // Gate-A 5C F1: unknown size fails CLOSED — a future adapter without byte
141
+ // metadata must not silently reopen the unbounded-read OOM class this cap exists for.
142
+ if (bytes === null || bytes > maxBytes) {
143
+ throw new SessionTooLargeError(sessionRef, bytes === null ? -1 : bytes, maxBytes);
144
+ }
145
+ return this.readSession(sessionRef);
146
+ }
147
+
70
148
  /**
71
149
  * Register a callback for session-end events (live hook mode).
72
150
  *
@@ -82,4 +160,9 @@ class TranscriptSource {
82
160
  }
83
161
  }
84
162
 
85
- module.exports = { TranscriptSource };
163
+ module.exports = {
164
+ TranscriptSource,
165
+ SessionTooLargeError,
166
+ DEFAULT_MAX_SESSION_BYTES,
167
+ resolveMaxSessionBytes,
168
+ };