vektor-slipstream 1.4.4 → 2.0.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 (56) hide show
  1. package/README.md +67 -306
  2. package/package.json +14 -146
  3. package/CHANGELOG.md +0 -139
  4. package/LICENSE +0 -33
  5. package/TENETS.md +0 -189
  6. package/audn-log.js +0 -143
  7. package/axon.js +0 -389
  8. package/boot-patch.js +0 -33
  9. package/boot-screen.html +0 -210
  10. package/briefing.js +0 -150
  11. package/cerebellum.js +0 -439
  12. package/cloak-behaviour.js +0 -596
  13. package/cloak-captcha.js +0 -541
  14. package/cloak-core.js +0 -499
  15. package/cloak-identity.js +0 -484
  16. package/cloak-index.js +0 -261
  17. package/cloak-llms.js +0 -163
  18. package/cloak-pattern-store.js +0 -471
  19. package/cloak-recorder-auto.js +0 -297
  20. package/cloak-recorder-snippet.js +0 -119
  21. package/cloak-turbo-quant.js +0 -357
  22. package/cloak-warmup.js +0 -240
  23. package/cortex.js +0 -221
  24. package/detect-hardware.js +0 -181
  25. package/entity-resolver.js +0 -298
  26. package/errors.js +0 -66
  27. package/examples/example-claude-mcp.js +0 -220
  28. package/examples/example-langchain-researcher.js +0 -82
  29. package/examples/example-openai-assistant.js +0 -84
  30. package/examples/examples-README.md +0 -161
  31. package/export-import.js +0 -221
  32. package/forget.js +0 -148
  33. package/inspect.js +0 -199
  34. package/mistral/README-mistral.md +0 -123
  35. package/mistral/mistral-bridge.js +0 -218
  36. package/mistral/mistral-setup.js +0 -220
  37. package/mistral/vektor-tool-manifest.json +0 -41
  38. package/models/model_quantized.onnx +0 -0
  39. package/models/vocab.json +0 -1
  40. package/namespace.js +0 -186
  41. package/pin.js +0 -91
  42. package/slipstream-core-extended.js +0 -134
  43. package/slipstream-core.js +0 -1
  44. package/slipstream-db.js +0 -140
  45. package/slipstream-embedder.js +0 -338
  46. package/sovereign.js +0 -142
  47. package/token.js +0 -322
  48. package/types/index.d.ts +0 -269
  49. package/vektor-banner-loader.js +0 -109
  50. package/vektor-cli.js +0 -259
  51. package/vektor-licence-prompt.js +0 -128
  52. package/vektor-licence.js +0 -192
  53. package/vektor-setup.js +0 -270
  54. package/vektor-slipstream.dxt +0 -0
  55. package/vektor-tui.js +0 -373
  56. package/visualize.js +0 -235
package/briefing.js DELETED
@@ -1,150 +0,0 @@
1
- /**
2
- * VEKTOR briefing() date scoping — v1.3.7
3
- * Adds `since` param to briefing() — filter to last N days/hours
4
- * or an explicit ISO timestamp.
5
- *
6
- * Drop-in replacement for existing briefing() implementation.
7
- */
8
-
9
- import { VektorError, ERR } from './errors.js';
10
-
11
- /**
12
- * Parse a `since` value into a Unix timestamp (seconds).
13
- * Accepts:
14
- * '1d' → last 1 day
15
- * '7d' → last 7 days
16
- * '12h' → last 12 hours
17
- * '30m' → last 30 minutes
18
- * '2026-01-01T00:00:00Z' → explicit ISO date
19
- * 1735689600 → raw unix timestamp
20
- */
21
- export function parseSince(since) {
22
- if (!since) return null;
23
-
24
- // Raw unix timestamp — guard against Date.now() (ms) being passed accidentally
25
- // If number > 9999999999 it's milliseconds (year ~2001 in seconds) — convert it
26
- if (typeof since === 'number') {
27
- return since > 9_999_999_999 ? Math.floor(since / 1000) : since;
28
- }
29
-
30
- // Relative shorthand: 7d, 12h, 30m
31
- const rel = String(since).match(/^(\d+)(d|h|m)$/);
32
- if (rel) {
33
- const n = parseInt(rel[1]);
34
- const unit = rel[2];
35
- const seconds = unit === 'd' ? n * 86400 : unit === 'h' ? n * 3600 : n * 60;
36
- return Math.floor(Date.now() / 1000) - seconds;
37
- }
38
-
39
- // ISO date string
40
- const ts = Date.parse(since);
41
- if (!isNaN(ts)) return Math.floor(ts / 1000);
42
-
43
- throw new VektorError(
44
- ERR.MEMORY_READ_FAILED,
45
- `Invalid since value: "${since}". Use "7d", "12h", "30m", ISO date, or unix timestamp.`
46
- );
47
- }
48
-
49
- /**
50
- * briefing({ since, limit, minImportance })
51
- * Returns a structured summary of recent memories for agent context injection.
52
- *
53
- * @param {object} db
54
- * @param {string} agentId
55
- * @param {string} namespace
56
- * @param {Function} summariseFn - LLM summarise function (existing REM summariser)
57
- * @param {object} opts
58
- * @param {string|number} opts.since - time filter (default: '1d')
59
- * @param {number} opts.limit - max memories (default: 20)
60
- * @param {number} opts.minImportance - filter by importance score (default: 0)
61
- * @param {boolean} opts.raw - return raw memories, skip LLM summary
62
- * @returns {object} { period, memoryCount, pinned, summary, memories }
63
- */
64
- export async function briefing(db, agentId, namespace, summariseFn, opts = {}) {
65
- const {
66
- since = '1d',
67
- limit = 20,
68
- minImportance = 0,
69
- raw = false
70
- } = opts;
71
-
72
- const sinceTs = parseSince(since);
73
- const sinceClause = sinceTs ? `AND created_at >= ${sinceTs}` : '';
74
- const importanceClause = minImportance > 0 ? `AND importance >= ${minImportance}` : '';
75
-
76
- // Fetch scoped memories
77
- const memories = db.prepare(`
78
- SELECT id, content, summary, importance, pinned, created_at
79
- FROM memories
80
- WHERE agent_id = ? AND namespace = ?
81
- ${sinceClause}
82
- ${importanceClause}
83
- ORDER BY importance DESC, created_at DESC
84
- LIMIT ?
85
- `).all(agentId, namespace, limit);
86
-
87
- // Always fetch pinned regardless of time window — hard cap 50 to prevent context bomb
88
- // (an agent running for months could accumulate hundreds of pinned memories)
89
- const pinnedLimit = 50;
90
- const pinned = db.prepare(`
91
- SELECT id, content, summary, importance, created_at
92
- FROM memories
93
- WHERE agent_id = ? AND namespace = ? AND pinned = 1
94
- ORDER BY importance DESC
95
- LIMIT ${pinnedLimit}
96
- `).all(agentId, namespace);
97
-
98
- if (raw) {
99
- return {
100
- period: since,
101
- memoryCount: memories.length,
102
- pinned,
103
- memories
104
- };
105
- }
106
-
107
- // Build prompt context for LLM summary
108
- const context = [
109
- pinned.length > 0
110
- ? `PINNED (permanent):\n${pinned.map(m => `- ${m.summary || m.content}`).join('\n')}`
111
- : null,
112
- memories.length > 0
113
- ? `RECENT (${since}):\n${memories.map(m => `- [${m.importance?.toFixed(2)}] ${m.summary || m.content}`).join('\n')}`
114
- : 'No recent memories in this period.'
115
- ].filter(Boolean).join('\n\n');
116
-
117
- const summary = await summariseFn(
118
- `Produce a concise agent briefing from these memories. Lead with pinned facts, then recent activity.\n\n${context}`
119
- );
120
-
121
- return {
122
- period: since,
123
- memoryCount: memories.length,
124
- pinnedCount: pinned.length,
125
- pinned,
126
- memories,
127
- summary
128
- };
129
- }
130
-
131
- /**
132
- * Integration into Memory class:
133
- *
134
- * async briefing(opts = {}) {
135
- * return briefing(this.db, this.agentId, this.namespace, this._summarise.bind(this), opts);
136
- * }
137
- *
138
- * Usage:
139
- * await memory.briefing();
140
- * // → last 24h summary (default)
141
- *
142
- * await memory.briefing({ since: '7d' });
143
- * // → last 7 days
144
- *
145
- * await memory.briefing({ since: '2026-01-01', minImportance: 0.7 });
146
- * // → since Jan 1st, high importance only
147
- *
148
- * await memory.briefing({ raw: true, since: '1h' });
149
- * // → raw memory objects, no LLM call
150
- */
package/cerebellum.js DELETED
@@ -1,439 +0,0 @@
1
- /**
2
- * cloak_cerebellum.js
3
- * Pre-write enforcer — checks every write against known error patterns in
4
- * Vektor's causal graph. Auto-creates [RESOLVED_BY] edges when a fix matches
5
- * an open error node. Zero extra tool calls from Claude.
6
- *
7
- * Two responsibilities:
8
- * 1. CHECK — before a write, recall causal error patterns and warn if matched
9
- * 2. RESOLVE — if new write content matches an error pattern, auto-write
10
- * [RESOLVED_BY] causal edge to close the loop
11
- *
12
- * Architecture: CLOAK layer → Vektor causal graph (MAGMA §3.4)
13
- * Research: MAGMA arXiv:2601.03236, OpenWolf cerebrum Do-Not-Repeat pattern
14
- *
15
- * Key design decision: cerebellum NEVER blocks a write, it only warns.
16
- * Claude Code must remain in control — cerebellum is advisory, not a gatekeeper.
17
- */
18
-
19
- 'use strict';
20
-
21
- const crypto = require('crypto');
22
-
23
- // ---------------------------------------------------------------------------
24
- // Similarity threshold for pattern matching
25
- // ---------------------------------------------------------------------------
26
- const SIMILARITY_THRESHOLD = 0.72;
27
-
28
- // Max error patterns to check per write
29
- const MAX_PATTERNS_TO_CHECK = 8;
30
-
31
- // Minimum content length to bother checking — skip tiny edits (console.log,
32
- // closing braces, single-line comments). Not worth a Vektor round-trip.
33
- const MIN_CHECK_LENGTH = 50;
34
-
35
- // ---------------------------------------------------------------------------
36
- // LRU warning cache — prevents slamming Vektor on rapid multi-file writes
37
- // (MultiEdit, code generation loops, etc.)
38
- //
39
- // Key: SHA-1 of content.slice(0,300) — cheap, collision-safe for this use
40
- // Value: { warnings, cachedAt }
41
- // TTL: 60 seconds — patterns don't change that fast within a session
42
- // Max: 100 entries — bounded memory, evicts oldest on overflow
43
- // ---------------------------------------------------------------------------
44
- const CACHE_TTL_MS = 60_000;
45
- const CACHE_MAX = 100;
46
- const _warningCache = new Map(); // key → { warnings, cachedAt }
47
-
48
- function _cacheKey(content) {
49
- return crypto.createHash('sha1').update(content.slice(0, 300)).digest('hex');
50
- }
51
-
52
- function _cacheGet(key) {
53
- const entry = _warningCache.get(key);
54
- if (!entry) return null;
55
- if (Date.now() - entry.cachedAt > CACHE_TTL_MS) {
56
- _warningCache.delete(key);
57
- return null;
58
- }
59
- return entry.warnings;
60
- }
61
-
62
- function _cacheSet(key, warnings) {
63
- // Evict oldest entry if at capacity
64
- if (_warningCache.size >= CACHE_MAX) {
65
- _warningCache.delete(_warningCache.keys().next().value);
66
- }
67
- _warningCache.set(key, { warnings, cachedAt: Date.now() });
68
- }
69
-
70
- // ---------------------------------------------------------------------------
71
- // Pattern storage key prefix — namespaces cerebellum nodes in Vektor
72
- // ---------------------------------------------------------------------------
73
- const ERROR_PREFIX = '[CLOAK_CEREBELLUM_ERROR]';
74
- const RESOLVED_PREFIX = '[CLOAK_CEREBELLUM_RESOLVED]';
75
- const DNR_PREFIX = '[CLOAK_CEREBELLUM_DNR]'; // Do-Not-Repeat
76
-
77
- // ---------------------------------------------------------------------------
78
- // Core: check a write against known error patterns
79
- // ---------------------------------------------------------------------------
80
-
81
- /**
82
- * checkWrite({ content, filePath, memory })
83
- * Called from the PreToolUse hook before every write.
84
- * Returns warnings if the write matches known error patterns.
85
- *
86
- * @param {string} content - The content being written
87
- * @param {string} filePath - The file being written to
88
- * @param {object} memory - Vektor memory instance
89
- * @returns {object} - { warnings: [], shouldProceed: true }
90
- */
91
- async function checkWrite({ content, filePath, memory } = {}) {
92
- if (!memory) throw new Error('cloak_cerebellum: memory instance is required');
93
- if (!content) return { warnings: [], shouldProceed: true, cached: false };
94
-
95
- // Bypass: tiny writes aren't worth a Vektor round-trip
96
- // (closing braces, console.logs, single-line cosmetic edits)
97
- if (content.length < MIN_CHECK_LENGTH) {
98
- return { warnings: [], shouldProceed: true, bypassed: 'too_small' };
99
- }
100
-
101
- // Cache hit: same content checked recently — return instantly, no Vektor call
102
- const key = _cacheKey(content);
103
- const cached = _cacheGet(key);
104
- if (cached !== null) {
105
- return {
106
- warnings : cached,
107
- shouldProceed: true,
108
- hasBlockers : cached.some(w => w.severity === 'block'),
109
- cached : true,
110
- };
111
- }
112
-
113
- const warnings = [];
114
-
115
- try {
116
- // Query causal error graph for patterns similar to this write
117
- const errorPatterns = await memory.recall(
118
- `${ERROR_PREFIX} ${content.slice(0, 300)}`,
119
- MAX_PATTERNS_TO_CHECK
120
- );
121
-
122
- if (!errorPatterns || errorPatterns.length === 0) {
123
- _cacheSet(key, []); // cache the empty result too — prevents repeat Vektor calls
124
- return { warnings: [], shouldProceed: true, cached: false };
125
- }
126
-
127
- for (const pattern of errorPatterns) {
128
- if (pattern.score < SIMILARITY_THRESHOLD) continue;
129
-
130
- // Parse the stored pattern
131
- const parsed = parsePatternNode(pattern.content);
132
- if (!parsed) continue;
133
-
134
- // Skip if this pattern is already resolved
135
- if (parsed.resolvedBy) continue;
136
-
137
- warnings.push({
138
- patternId : pattern.id,
139
- description : parsed.description,
140
- originalFile: parsed.file,
141
- severity : parsed.severity || 'warn',
142
- hint : parsed.fix || 'See error pattern for details',
143
- score : Math.round(pattern.score * 100) / 100,
144
- });
145
- }
146
-
147
- // Also check Do-Not-Repeat rules (always enforced regardless of similarity)
148
- const dnrRules = await memory.recall(
149
- `${DNR_PREFIX}`,
150
- 5
151
- );
152
-
153
- if (dnrRules) {
154
- for (const rule of dnrRules) {
155
- const parsed = parseDNRNode(rule.content);
156
- if (!parsed) continue;
157
-
158
- // Check if the pattern keyword appears in the write content
159
- if (content.toLowerCase().includes(parsed.keyword.toLowerCase())) {
160
- warnings.push({
161
- patternId : rule.id,
162
- description : `Do-Not-Repeat: ${parsed.rule}`,
163
- severity : 'block',
164
- hint : parsed.alternative || 'Avoid this pattern',
165
- score : 1.0,
166
- });
167
- }
168
- }
169
- }
170
-
171
- } catch (err) {
172
- // Non-fatal — Vektor query failure should not block writes
173
- console.warn('[cloak_cerebellum] Pattern check failed:', err.message);
174
- }
175
-
176
- // Cache the result for 60s — rapid multi-file writes skip Vektor entirely
177
- _cacheSet(key, warnings);
178
-
179
- return {
180
- warnings,
181
- shouldProceed: true,
182
- hasBlockers : warnings.some(w => w.severity === 'block'),
183
- cached : false,
184
- };
185
- }
186
-
187
- // ---------------------------------------------------------------------------
188
- // Core: record a new error pattern into the causal graph
189
- // ---------------------------------------------------------------------------
190
-
191
- /**
192
- * recordError({ description, filePath, errorType, fix, severity, memory })
193
- * Store a new error pattern so future writes can be warned.
194
- *
195
- * @param {string} description - Human-readable description of the error
196
- * @param {string} filePath - File where error occurred
197
- * @param {string} errorType - e.g. 'null_reference', 'type_mismatch'
198
- * @param {string} fix - What fixed it (optional)
199
- * @param {'warn'|'block'} severity
200
- * @param {object} memory - Vektor memory instance
201
- * @returns {object} - { id, written }
202
- */
203
- async function recordError({ description, filePath, errorType, fix, severity = 'warn', memory } = {}) {
204
- if (!memory) throw new Error('cloak_cerebellum: memory instance is required');
205
- if (!description) throw new Error('cloak_cerebellum: description is required');
206
-
207
- const patternStr = [
208
- ERROR_PREFIX,
209
- `error_type:${errorType || 'unknown'}`,
210
- `file:${filePath || 'unknown'}`,
211
- `description:${description}`,
212
- `severity:${severity}`,
213
- fix ? `fix:${fix}` : null,
214
- `recorded_at:${new Date().toISOString()}`,
215
- `resolved:false`,
216
- ].filter(Boolean).join(' | ');
217
-
218
- try {
219
- await memory.remember(patternStr);
220
- return { written: true, pattern: patternStr };
221
- } catch (err) {
222
- console.error('[cloak_cerebellum] Failed to record error:', err.message);
223
- return { written: false, error: err.message };
224
- }
225
- }
226
-
227
- // ---------------------------------------------------------------------------
228
- // Core: auto-resolve — detect when a write fixes an open error
229
- // Called from PostToolUse after a successful write.
230
- // This is the key improvement over OpenWolf — resolution is automatic,
231
- // not dependent on Claude remembering to call a separate tool.
232
- // ---------------------------------------------------------------------------
233
-
234
- /**
235
- * autoResolve({ content, filePath, memory })
236
- * After a successful write, check if it resolves any open error patterns.
237
- * If yes, write a [RESOLVED_BY] causal edge to close the loop.
238
- * This feeds the decay weighting in MAGMA's causal graph.
239
- *
240
- * @param {string} content - Content that was written
241
- * @param {string} filePath - File that was written
242
- * @param {object} memory - Vektor memory instance
243
- * @returns {object} - { resolved: [], written: number }
244
- */
245
- async function autoResolve({ content, filePath, memory } = {}) {
246
- if (!memory || !filePath) return { resolved: [], written: 0 };
247
-
248
- const resolved = [];
249
-
250
- try {
251
- // Query by FILE PATH not content — avoids the semantic gap where
252
- // "Null reference on user.id" and "if (user && user.id)" have
253
- // completely different embeddings despite one fixing the other.
254
- // Pull all open errors on this file, then let REM cycle verify.
255
- const candidates = await memory.recall(
256
- `${ERROR_PREFIX} file:${filePath}`,
257
- MAX_PATTERNS_TO_CHECK
258
- );
259
-
260
- if (!candidates || candidates.length === 0) return { resolved: [], written: 0 };
261
-
262
- for (const candidate of candidates) {
263
- // File path match is already a strong signal — use lower threshold
264
- // than content matching. 0.5 avoids completely unrelated file path
265
- // substring matches while catching real file-based errors.
266
- if (candidate.score < 0.5) continue;
267
-
268
- const parsed = parsePatternNode(candidate.content);
269
- if (!parsed || parsed.resolvedBy) continue; // already resolved
270
-
271
- // Only auto-resolve if the stored error references this exact file
272
- if (parsed.file && parsed.file !== filePath &&
273
- parsed.file !== require('path').basename(filePath)) continue;
274
-
275
- // Write resolution node — this is the [RESOLVED_BY] causal edge
276
- const resolutionStr = [
277
- RESOLVED_PREFIX,
278
- `resolves_pattern:${candidate.id}`,
279
- `original_error:${parsed.description}`,
280
- `resolved_by_file:${filePath || 'unknown'}`,
281
- `resolved_at:${new Date().toISOString()}`,
282
- `[RESOLVED_BY]`, // explicit causal edge marker for HippoRAG decay weighting
283
- ].join(' | ');
284
-
285
- try {
286
- await memory.remember(resolutionStr);
287
- resolved.push({
288
- patternId : candidate.id,
289
- description: parsed.description,
290
- resolution : resolutionStr,
291
- });
292
- } catch (err) {
293
- console.warn('[cloak_cerebellum] Failed to write resolution:', err.message);
294
- }
295
- }
296
-
297
- } catch (err) {
298
- console.warn('[cloak_cerebellum] Auto-resolve query failed:', err.message);
299
- }
300
-
301
- return { resolved, written: resolved.length };
302
- }
303
-
304
- // ---------------------------------------------------------------------------
305
- // Do-Not-Repeat rules — project-level conventions
306
- // ---------------------------------------------------------------------------
307
-
308
- /**
309
- * addDNRRule({ keyword, rule, alternative, memory })
310
- * Store a Do-Not-Repeat rule. Checked on every write regardless of similarity.
311
- *
312
- * @param {string} keyword - Trigger keyword/pattern to watch for
313
- * @param {string} rule - Human description of what not to do
314
- * @param {string} alternative - What to do instead
315
- * @param {object} memory
316
- */
317
- async function addDNRRule({ keyword, rule, alternative, memory } = {}) {
318
- if (!memory) throw new Error('cloak_cerebellum: memory instance is required');
319
- if (!keyword) throw new Error('cloak_cerebellum: keyword is required');
320
- if (!rule) throw new Error('cloak_cerebellum: rule is required');
321
-
322
- const dnrStr = [
323
- DNR_PREFIX,
324
- `keyword:${keyword}`,
325
- `rule:${rule}`,
326
- alternative ? `alternative:${alternative}` : null,
327
- `added_at:${new Date().toISOString()}`,
328
- ].filter(Boolean).join(' | ');
329
-
330
- try {
331
- await memory.remember(dnrStr);
332
- return { written: true };
333
- } catch (err) {
334
- console.error('[cloak_cerebellum] Failed to add DNR rule:', err.message);
335
- return { written: false, error: err.message };
336
- }
337
- }
338
-
339
- // ---------------------------------------------------------------------------
340
- // Claude Code hook integration
341
- // ---------------------------------------------------------------------------
342
-
343
- /**
344
- * handleHookPayload({ payload, memory })
345
- * Routes Claude Code PreToolUse/PostToolUse hooks to checkWrite / autoResolve.
346
- */
347
- async function handleHookPayload({ payload, memory } = {}) {
348
- if (!memory || !payload) return null;
349
-
350
- const hookName = payload?.hook_event_name || payload?.event;
351
- const tool = payload?.tool_name;
352
- const input = payload?.tool_input;
353
- const output = payload?.tool_response;
354
-
355
- const isWrite = ['Write', 'Edit', 'MultiEdit', 'Bash'].includes(tool);
356
-
357
- switch (hookName) {
358
- case 'PreToolUse':
359
- case 'pre_tool_use': {
360
- if (!isWrite) return null;
361
-
362
- // Bug fix: MultiEdit sends input.edits = [{ old_string, new_string }]
363
- // not a flat input.new_string. Concatenate all new_string blocks so
364
- // cerebellum actually sees the content being written in refactors.
365
- let content = input?.new_string || input?.content || input?.command || '';
366
- if (!content && input?.edits && Array.isArray(input.edits)) {
367
- content = input.edits.map(e => e.new_string || '').filter(Boolean).join('\n');
368
- }
369
-
370
- const filePath = input?.file_path || input?.path || '';
371
- return checkWrite({ content, filePath, memory });
372
- }
373
-
374
- case 'PostToolUse':
375
- case 'post_tool_use': {
376
- if (!isWrite) return null;
377
- const success = !output?.error;
378
- if (!success) return null;
379
-
380
- // Same MultiEdit fix on the post-write resolve path
381
- let content = input?.new_string || input?.content || '';
382
- if (!content && input?.edits && Array.isArray(input.edits)) {
383
- content = input.edits.map(e => e.new_string || '').filter(Boolean).join('\n');
384
- }
385
-
386
- const filePath = input?.file_path || input?.path || '';
387
- return autoResolve({ content, filePath, memory });
388
- }
389
-
390
- default:
391
- return null;
392
- }
393
- }
394
-
395
- // ---------------------------------------------------------------------------
396
- // Parsers — extract structured data from Vektor node strings
397
- // ---------------------------------------------------------------------------
398
- function parsePatternNode(str) {
399
- if (!str || !str.includes(ERROR_PREFIX)) return null;
400
- const parts = str.split(' | ');
401
- const get = key => {
402
- const part = parts.find(p => p.startsWith(`${key}:`));
403
- return part ? part.slice(key.length + 1) : null;
404
- };
405
- return {
406
- errorType : get('error_type'),
407
- file : get('file'),
408
- description: get('description'),
409
- severity : get('severity'),
410
- fix : get('fix'),
411
- resolvedBy: str.includes(RESOLVED_PREFIX) || get('resolved') === 'true' ? true : null,
412
- };
413
- }
414
-
415
- function parseDNRNode(str) {
416
- if (!str || !str.includes(DNR_PREFIX)) return null;
417
- const parts = str.split(' | ');
418
- const get = key => {
419
- const part = parts.find(p => p.startsWith(`${key}:`));
420
- return part ? part.slice(key.length + 1) : null;
421
- };
422
- return {
423
- keyword : get('keyword'),
424
- rule : get('rule'),
425
- alternative: get('alternative'),
426
- };
427
- }
428
-
429
- module.exports = {
430
- checkWrite,
431
- recordError,
432
- autoResolve,
433
- addDNRRule,
434
- handleHookPayload,
435
- SIMILARITY_THRESHOLD,
436
- ERROR_PREFIX,
437
- RESOLVED_PREFIX,
438
- DNR_PREFIX,
439
- };