hippo-memory 1.27.0 → 1.29.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.
Files changed (99) hide show
  1. package/README.md +4 -2
  2. package/dist/api.d.ts +25 -1
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +103 -4
  5. package/dist/api.js.map +1 -1
  6. package/dist/capture.d.ts +49 -2
  7. package/dist/capture.d.ts.map +1 -1
  8. package/dist/capture.js +464 -1
  9. package/dist/capture.js.map +1 -1
  10. package/dist/cli.d.ts +5 -0
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +266 -21
  13. package/dist/cli.js.map +1 -1
  14. package/dist/dag.d.ts.map +1 -1
  15. package/dist/dag.js +10 -1
  16. package/dist/dag.js.map +1 -1
  17. package/dist/db.d.ts.map +1 -1
  18. package/dist/db.js +75 -1
  19. package/dist/db.js.map +1 -1
  20. package/dist/embedding-provider.d.ts +1 -1
  21. package/dist/embedding-provider.js +1 -1
  22. package/dist/embeddings.d.ts +2 -2
  23. package/dist/embeddings.d.ts.map +1 -1
  24. package/dist/embeddings.js +38 -37
  25. package/dist/embeddings.js.map +1 -1
  26. package/dist/hooks.d.ts +24 -0
  27. package/dist/hooks.d.ts.map +1 -1
  28. package/dist/hooks.js +85 -1
  29. package/dist/hooks.js.map +1 -1
  30. package/dist/invalidation.d.ts +20 -2
  31. package/dist/invalidation.d.ts.map +1 -1
  32. package/dist/invalidation.js +50 -18
  33. package/dist/invalidation.js.map +1 -1
  34. package/dist/mcp/server.d.ts.map +1 -1
  35. package/dist/mcp/server.js +17 -4
  36. package/dist/mcp/server.js.map +1 -1
  37. package/dist/postinstall.js +35 -2
  38. package/dist/postinstall.js.map +1 -1
  39. package/dist/recall-trace.d.ts +117 -0
  40. package/dist/recall-trace.d.ts.map +1 -0
  41. package/dist/recall-trace.js +179 -0
  42. package/dist/recall-trace.js.map +1 -0
  43. package/dist/rerankers/cross-encoder.d.ts +1 -1
  44. package/dist/rerankers/cross-encoder.d.ts.map +1 -1
  45. package/dist/rerankers/cross-encoder.js +38 -10
  46. package/dist/rerankers/cross-encoder.js.map +1 -1
  47. package/dist/secret-detect.d.ts +8 -0
  48. package/dist/secret-detect.d.ts.map +1 -1
  49. package/dist/secret-detect.js +25 -0
  50. package/dist/secret-detect.js.map +1 -1
  51. package/dist/server.js +1 -1
  52. package/dist/server.js.map +1 -1
  53. package/dist/src/api.js +103 -4
  54. package/dist/src/api.js.map +1 -1
  55. package/dist/src/capture.js +464 -1
  56. package/dist/src/capture.js.map +1 -1
  57. package/dist/src/cli.js +266 -21
  58. package/dist/src/cli.js.map +1 -1
  59. package/dist/src/dag.js +10 -1
  60. package/dist/src/dag.js.map +1 -1
  61. package/dist/src/db.js +75 -1
  62. package/dist/src/db.js.map +1 -1
  63. package/dist/src/embedding-provider.js +1 -1
  64. package/dist/src/embeddings.js +38 -37
  65. package/dist/src/embeddings.js.map +1 -1
  66. package/dist/src/hooks.js +85 -1
  67. package/dist/src/hooks.js.map +1 -1
  68. package/dist/src/invalidation.js +50 -18
  69. package/dist/src/invalidation.js.map +1 -1
  70. package/dist/src/mcp/server.js +17 -4
  71. package/dist/src/mcp/server.js.map +1 -1
  72. package/dist/src/postinstall.js +35 -2
  73. package/dist/src/postinstall.js.map +1 -1
  74. package/dist/src/recall-trace.js +179 -0
  75. package/dist/src/recall-trace.js.map +1 -0
  76. package/dist/src/rerankers/cross-encoder.js +38 -10
  77. package/dist/src/rerankers/cross-encoder.js.map +1 -1
  78. package/dist/src/secret-detect.js +25 -0
  79. package/dist/src/secret-detect.js.map +1 -1
  80. package/dist/src/server.js +1 -1
  81. package/dist/src/server.js.map +1 -1
  82. package/dist/src/store.js +55 -4
  83. package/dist/src/store.js.map +1 -1
  84. package/dist/src/version.js +7 -6
  85. package/dist/src/version.js.map +1 -1
  86. package/dist/store.d.ts +15 -0
  87. package/dist/store.d.ts.map +1 -1
  88. package/dist/store.js +55 -4
  89. package/dist/store.js.map +1 -1
  90. package/dist/version.d.ts +1 -1
  91. package/dist/version.js +7 -6
  92. package/dist/version.js.map +1 -1
  93. package/dist-ui/assets/{index-DbMxaBZ3.js → index-Cxa4RcAh.js} +2 -2
  94. package/dist-ui/assets/{react-DS1lvn1H.js → react-CEUiQZj-.js} +2 -2
  95. package/dist-ui/index.html +2 -2
  96. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  97. package/extensions/openclaw-plugin/package.json +1 -1
  98. package/openclaw.plugin.json +1 -1
  99. package/package.json +8 -5
@@ -0,0 +1,179 @@
1
+ /**
2
+ * LC1 — retrieval-trace persistence
3
+ * (docs/plans/2026-08-02-lc1-recall-trace-persistence.md).
4
+ *
5
+ * Single producer for the `recall_traces` / `recall_trace_results` /
6
+ * `recall_trace_outcomes` tables (schema v40). Every recall on the three
7
+ * wired paths (api.recall, api.getContext, CLI cmdRecall) writes a trace
8
+ * row: the ids + ranks + scores actually returned. Outcome events that
9
+ * resolve their targets from last-retrieval state link back to the trace
10
+ * they judge via `recordTraceOutcome`. This is the (query, shown, outcome)
11
+ * training triple every Track LC learned component needs.
12
+ *
13
+ * All writes here are fail-soft: a broken trace write must never break the
14
+ * surrounding recall or outcome call. Failures are logged to stderr and
15
+ * swallowed (matches the api.ts ~2843 "audit emit failed" precedent — no
16
+ * new debug env var).
17
+ */
18
+ import { createHash } from 'node:crypto';
19
+ import { openHippoDb, closeHippoDb } from './db.js';
20
+ /**
21
+ * Strip a RerankStep down to {stage, multiplier, scoreBefore, scoreAfter}
22
+ * before persisting (F3 privacy fix, codex cross-model finding). `note` is
23
+ * free-form human text — the CLI's goal-boost step embeds matched goal tag
24
+ * text there, so persisting it verbatim would leak raw user content into
25
+ * training data via `rerank_json`. Only the four structured fields survive;
26
+ * any other/future free-form field is dropped by construction (allowlist,
27
+ * not a denylist).
28
+ */
29
+ function sanitizeRerankSteps(steps) {
30
+ return steps.map((s) => ({
31
+ stage: s.stage,
32
+ multiplier: s.multiplier,
33
+ scoreBefore: s.scoreBefore,
34
+ scoreAfter: s.scoreAfter,
35
+ }));
36
+ }
37
+ /**
38
+ * Insert a `recall_traces` row + its `recall_trace_results` rows in ONE
39
+ * transaction, on the connection handed in. Fail-soft: never throws —
40
+ * logs to stderr and returns null on any failure.
41
+ *
42
+ * Connection policy (per the plan): api.recall calls this directly on its
43
+ * own already-open handle. api.getContext and CLI cmdRecall go through
44
+ * `writeRecallTraceAtRoot` instead, since their audit handles are already
45
+ * closed by the time tracing runs.
46
+ */
47
+ export function writeRecallTrace(db, input) {
48
+ try {
49
+ const queryHash = createHash('sha256').update(input.query).digest('hex').slice(0, 16);
50
+ const ts = new Date().toISOString();
51
+ db.exec('BEGIN');
52
+ try {
53
+ const insertTrace = db.prepare(`
54
+ INSERT INTO recall_traces (ts, tenant_id, session_id, pipeline, query_hash, query_length, result_count, explain_mode)
55
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
56
+ `);
57
+ const traceResult = insertTrace.run(ts, input.tenantId, input.sessionId ?? null, input.pipeline, queryHash, input.query.length, input.results.length, input.explainMode ? 1 : 0);
58
+ const traceId = Number(traceResult.lastInsertRowid);
59
+ const insertResult = db.prepare(`
60
+ INSERT INTO recall_trace_results (trace_id, tenant_id, memory_id, result_rank, score, rerank_json)
61
+ VALUES (?, ?, ?, ?, ?, ?)
62
+ `);
63
+ input.results.forEach((r, i) => {
64
+ insertResult.run(traceId, input.tenantId, r.memoryId, i + 1, r.score, r.rerankSteps && r.rerankSteps.length > 0 ? JSON.stringify(sanitizeRerankSteps(r.rerankSteps)) : null);
65
+ });
66
+ db.exec('COMMIT');
67
+ return traceId;
68
+ }
69
+ catch (error) {
70
+ db.exec('ROLLBACK');
71
+ throw error;
72
+ }
73
+ }
74
+ catch (error) {
75
+ // eslint-disable-next-line no-console
76
+ console.error(`[hippo] recall trace write failed: ${error.message}`);
77
+ return null;
78
+ }
79
+ }
80
+ /**
81
+ * Convenience wrapper: opens a fresh short-lived connection at `root`,
82
+ * writes the trace, and closes. Returns the new trace id, or null on any
83
+ * failure (fail-soft).
84
+ *
85
+ * Used at api.getContext and CLI cmdRecall — sites where the block's own
86
+ * convention is per-call handles (writeEntry, saveIndex) and the earlier
87
+ * audit handles are already closed. NOT used by api.recall, which must
88
+ * reuse the caller's open handle (v1.11.5 no-side-effects contract,
89
+ * tests/api-recall-no-side-effects.test.ts).
90
+ *
91
+ * F1 structural fix (replaces the earlier stamp-then-clear design): this
92
+ * function does NOT touch the `last_trace_id` meta key. Stamping lived here
93
+ * originally, on its own connection, separate from the `last_retrieval_ids`
94
+ * write in `saveIndex` — two connections meant two commits, so a crash or
95
+ * a failed second write could advance one without the other. LOCKSTEP
96
+ * INVARIANT: `last_trace_id` must only ever advance in the SAME write as
97
+ * `last_retrieval_ids`. The caller now does: call this function FIRST, set
98
+ * `localIndex.last_trace_id` from the returned id, THEN call `saveIndex`
99
+ * once — `saveIndex` persists both meta keys in one transaction
100
+ * (store.ts). Call sites that trace WITHOUT advancing `last_retrieval_ids`
101
+ * (CLI cmdRecall's zero-result path, getContext's empty-result path) simply
102
+ * never touch `localIndex` at all — they can't desync by construction.
103
+ *
104
+ * Fail-soft: never throws, including on connection failure.
105
+ */
106
+ export function writeRecallTraceAtRoot(root, input) {
107
+ let db;
108
+ try {
109
+ db = openHippoDb(root);
110
+ }
111
+ catch (error) {
112
+ // eslint-disable-next-line no-console
113
+ console.error(`[hippo] recall trace connection failed: ${error.message}`);
114
+ return null;
115
+ }
116
+ try {
117
+ return writeRecallTrace(db, input);
118
+ }
119
+ finally {
120
+ closeHippoDb(db);
121
+ }
122
+ }
123
+ /**
124
+ * Record an outcome event against a trace, linking the (query, shown,
125
+ * outcome) triple. Called ONLY where the credited ids actually come from
126
+ * the last-retrieval mechanism (api.outcomeForLastRecall and any outcome
127
+ * flow that resolves its targets from last-retrieval state) or from an
128
+ * SDK caller's explicit `traceId` opt — never unconditionally from
129
+ * api.outcome, which would mislink an explicit-id caller to a stale,
130
+ * unrelated trace.
131
+ *
132
+ * Lives in its own append-only table, not audit_log metadata: audit_log is
133
+ * pruned by `pruneAuditLog`, and pruning must never erase training data.
134
+ *
135
+ * F4 validation (codex cross-model finding): `traceId`/`memoryIds` reach
136
+ * this function from caller-side state (`last_trace_id` / applied outcome
137
+ * ids) that can go stale relative to the trace it names — a forgotten
138
+ * memory, a tenant switch mid-session, or a race between two callers. Two
139
+ * checks run before the insert, both skip silently (console.error one
140
+ * line) rather than throw:
141
+ * 1. The named trace must exist and belong to `input.tenantId` — a
142
+ * tenant mismatch or a dangling id (deleted trace) skips.
143
+ * 2. `input.memoryIds` is intersected against the trace's OWN
144
+ * `recall_trace_results.memory_id` set — only ids that trace actually
145
+ * returned are recorded. An id that was never in this trace's result
146
+ * set (stale caller state) is silently dropped rather than recorded
147
+ * as a false credit. If the intersection is empty, no row is written.
148
+ *
149
+ * Fail-soft: never throws.
150
+ */
151
+ export function recordTraceOutcome(db, input) {
152
+ try {
153
+ const trace = db.prepare(`SELECT tenant_id FROM recall_traces WHERE id = ?`).get(input.traceId);
154
+ if (!trace || trace.tenant_id !== input.tenantId) {
155
+ // eslint-disable-next-line no-console
156
+ console.error(`[hippo] recall trace outcome skipped: trace ${input.traceId} missing or tenant mismatch`);
157
+ return;
158
+ }
159
+ const memberRows = db
160
+ .prepare(`SELECT memory_id FROM recall_trace_results WHERE trace_id = ?`)
161
+ .all(input.traceId);
162
+ const members = new Set(memberRows.map((r) => r.memory_id));
163
+ const credited = input.memoryIds.filter((id) => members.has(id));
164
+ if (credited.length === 0) {
165
+ // eslint-disable-next-line no-console
166
+ console.error(`[hippo] recall trace outcome skipped: no credited ids intersect trace ${input.traceId}'s results`);
167
+ return;
168
+ }
169
+ db.prepare(`
170
+ INSERT INTO recall_trace_outcomes (trace_id, ts, tenant_id, outcome, memory_ids_json)
171
+ VALUES (?, ?, ?, ?, ?)
172
+ `).run(input.traceId, new Date().toISOString(), input.tenantId, input.outcome, JSON.stringify(credited));
173
+ }
174
+ catch (error) {
175
+ // eslint-disable-next-line no-console
176
+ console.error(`[hippo] recall trace outcome write failed: ${error.message}`);
177
+ }
178
+ }
179
+ //# sourceMappingURL=recall-trace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall-trace.js","sourceRoot":"","sources":["../../src/recall-trace.ts"],"names":[],"mappings":"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"}
@@ -1,30 +1,58 @@
1
+ import { createRequire } from 'node:module';
1
2
  const MODEL_NAME = 'Xenova/ms-marco-MiniLM-L-6-v2';
2
3
  // Use Function constructor to bypass TypeScript static module resolution
3
4
  // for optional peer dependencies that may not be installed (mirrors the
4
5
  // pattern in src/embeddings.ts).
5
6
  const _dynImport = new Function('s', 'return import(s)');
7
+ const _require = createRequire(import.meta.url);
8
+ const TRANSFORMERS_PACKAGES = ['@huggingface/transformers', '@xenova/transformers'];
9
+ function resolveTransformersPackage() {
10
+ for (const name of TRANSFORMERS_PACKAGES) {
11
+ try {
12
+ _require.resolve(name);
13
+ return name;
14
+ }
15
+ catch {
16
+ // Try the legacy fallback only when the preferred package is not installed.
17
+ }
18
+ }
19
+ return null;
20
+ }
21
+ async function loadTransformersModule() {
22
+ // Import one backend only. Loading both native ONNX runtimes in one process
23
+ // can abort during finalization; Hugging Face is the maintained default.
24
+ const name = resolveTransformersPackage();
25
+ if (!name)
26
+ return null;
27
+ try {
28
+ const mod = (await _dynImport(name));
29
+ const pipeline = mod.pipeline ?? mod.default?.pipeline;
30
+ return typeof pipeline === 'function'
31
+ ? { pipeline }
32
+ : null;
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
6
38
  let cachedPipeline = null;
7
39
  let warnedOnFallback = false;
8
40
  /**
9
- * True if @xenova/transformers is importable. Note: this does NOT confirm
41
+ * True if a Transformers.js backend is importable. Note: this does NOT confirm
10
42
  * that the model is downloadable from Hugging Face CDN — in sandboxed
11
43
  * environments the package may import but the model fetch may be blocked.
12
44
  * The reranker silently falls back to identity ordering in that case.
13
45
  */
14
46
  export async function isCrossEncoderAvailable() {
15
- try {
16
- const t = (await _dynImport('@xenova/transformers'));
17
- return typeof t.pipeline === 'function';
18
- }
19
- catch {
20
- return false;
21
- }
47
+ return (await loadTransformersModule()) !== null;
22
48
  }
23
49
  async function loadPipeline() {
24
50
  if (cachedPipeline)
25
51
  return cachedPipeline;
26
52
  try {
27
- const mod = (await _dynImport('@xenova/transformers'));
53
+ const mod = await loadTransformersModule();
54
+ if (!mod)
55
+ return null;
28
56
  const p = (await mod.pipeline('text-classification', MODEL_NAME));
29
57
  cachedPipeline = async (query, candidate) => {
30
58
  const out = (await p(`${query} [SEP] ${candidate}`));
@@ -55,7 +83,7 @@ export const crossEncoderReranker = async (query, results, options) => {
55
83
  if (!warnedOnFallback) {
56
84
  warnedOnFallback = true;
57
85
  // eslint-disable-next-line no-console
58
- console.warn('[hippo] cross-encoder reranker unavailable (no @xenova/transformers, or model fetch blocked); falling back to identity ordering. Subsequent calls will not repeat this warning.');
86
+ console.warn('[hippo] cross-encoder reranker unavailable (no Transformers.js backend, or model fetch blocked); falling back to identity ordering. Subsequent calls will not repeat this warning.');
59
87
  }
60
88
  return head.map((r, i) => ({
61
89
  ...r,
@@ -1 +1 @@
1
- {"version":3,"file":"cross-encoder.js","sourceRoot":"","sources":["../../../src/rerankers/cross-encoder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cross-encoder.js","sourceRoot":"","sources":["../../../src/rerankers/cross-encoder.ts"],"names":[],"mappings":"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"}
@@ -67,4 +67,29 @@ export function detectSecret(entry) {
67
67
  }
68
68
  return { flagged: false, reason: null };
69
69
  }
70
+ /**
71
+ * Replace secret-shaped substrings in free text with a redaction marker.
72
+ * Reuses the same `SECRET_PATTERNS` / co-occurrence guard as `detectSecret`
73
+ * (which only flags whole-entry content) so callers that must persist raw
74
+ * text that never passes through the normal capture content gate — e.g. the
75
+ * CS1 pre-compact snapshot fields — can scrub it in place instead.
76
+ */
77
+ export function redactSecrets(text) {
78
+ if (!text)
79
+ return text;
80
+ let result = text;
81
+ // PEM/OpenSSH blocks first: the pattern-table entry matches only the
82
+ // BEGIN delimiter, which is fine for detectSecret's flag-or-not decision
83
+ // but would leave the base64 payload behind here. Consume through the
84
+ // matching END delimiter; a truncated block with no END is redacted to
85
+ // the end of the text (codex round 3).
86
+ result = result.replace(/-----BEGIN [A-Z ]*PRIVATE KEY-----(?:[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----|[\s\S]*$)/g, '[REDACTED]');
87
+ for (const { name, re } of SECRET_PATTERNS) {
88
+ if (CO_OCCURRENCE_GUARDED.has(name) && !KEYISH_CONTEXT_RE.test(text))
89
+ continue;
90
+ const flags = re.flags.includes('g') ? re.flags : `${re.flags}g`;
91
+ result = result.replace(new RegExp(re.source, flags), '[REDACTED]');
92
+ }
93
+ return result;
94
+ }
70
95
  //# sourceMappingURL=secret-detect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"secret-detect.js","sourceRoot":"","sources":["../../src/secret-detect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC;IAC1B,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa;IAC1D,OAAO,EAAE,UAAU,EAAE,aAAa;CACnC,CAAC,CAAC;AAEH,MAAM,eAAe,GAAgD;IACnE,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,EAAE,sBAAsB,EAAE;IACtD,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,6CAA6C,EAAE;IAC3E,EAAE,IAAI,EAAE,yBAAyB,EAAE,EAAE,EAAE,kCAAkC,EAAE;IAC3E,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,kCAAkC,EAAE;IAC/D,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,0CAA0C,EAAE;IACtE,EAAE,IAAI,EAAE,gBAAgB,EAAE,EAAE,EAAE,2BAA2B,EAAE;IAC3D,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,oCAAoC,EAAE;IACvE,2EAA2E;IAC3E,yEAAyE;IACzE,yEAAyE;IACzE,uEAAuE;IACvE,QAAQ;IACR,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,2BAA2B,EAAE;IACzD,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,sCAAsC,EAAE;IACzE,0EAA0E;IAC1E,oEAAoE;IACpE,wEAAwE;IACxE,oEAAoE;IACpE,wEAAwE;IACxE,yEAAyE;IACzE,kEAAkE;IAClE,mCAAmC;IACnC,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,uGAAuG,EAAE;CAC3I,CAAC;AAEF,MAAM,iBAAiB,GAAG,mDAAmD,CAAC;AAC9E,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,CAAC;AAE7E;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAA0C;IACrE,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;YACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAG,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC;QAC/D,CAAC;IACH,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,eAAe,EAAE,CAAC;QAC3C,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,IAAI,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;YAAE,SAAS;QACxF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,IAAI,EAAE,EAAE,CAAC;IACtD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1C,CAAC"}
1
+ {"version":3,"file":"secret-detect.js","sourceRoot":"","sources":["../../src/secret-detect.ts"],"names":[],"mappings":"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"}
@@ -758,7 +758,7 @@ async function handleRequest(req, res, opts, startedAt, limiter) {
758
758
  if (depthRaw !== null) {
759
759
  const parsed = Number(depthRaw);
760
760
  // L4 fold: reject out-of-range explicitly (no silent clamp).
761
- if (!Number.isFinite(parsed) || parsed < 1 || parsed > 10) {
761
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 10) {
762
762
  throw new HttpError(400, 'depth must be a positive integer between 1 and 10');
763
763
  }
764
764
  depth = parsed;