cipher-security 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.
- package/bin/cipher.js +566 -0
- package/lib/api/billing.js +321 -0
- package/lib/api/compliance.js +693 -0
- package/lib/api/controls.js +1401 -0
- package/lib/api/index.js +49 -0
- package/lib/api/marketplace.js +467 -0
- package/lib/api/openai-proxy.js +383 -0
- package/lib/api/server.js +685 -0
- package/lib/autonomous/feedback-loop.js +554 -0
- package/lib/autonomous/framework.js +512 -0
- package/lib/autonomous/index.js +97 -0
- package/lib/autonomous/leaderboard.js +594 -0
- package/lib/autonomous/modes/architect.js +412 -0
- package/lib/autonomous/modes/blue.js +386 -0
- package/lib/autonomous/modes/incident.js +684 -0
- package/lib/autonomous/modes/privacy.js +369 -0
- package/lib/autonomous/modes/purple.js +294 -0
- package/lib/autonomous/modes/recon.js +250 -0
- package/lib/autonomous/parallel.js +587 -0
- package/lib/autonomous/researcher.js +583 -0
- package/lib/autonomous/runner.js +955 -0
- package/lib/autonomous/scheduler.js +615 -0
- package/lib/autonomous/task-parser.js +127 -0
- package/lib/autonomous/validators/forensic.js +266 -0
- package/lib/autonomous/validators/osint.js +216 -0
- package/lib/autonomous/validators/privacy.js +296 -0
- package/lib/autonomous/validators/purple.js +298 -0
- package/lib/autonomous/validators/sigma.js +248 -0
- package/lib/autonomous/validators/threat-model.js +363 -0
- package/lib/benchmark/agent.js +119 -0
- package/lib/benchmark/baselines.js +43 -0
- package/lib/benchmark/builder.js +143 -0
- package/lib/benchmark/config.js +35 -0
- package/lib/benchmark/coordinator.js +91 -0
- package/lib/benchmark/index.js +20 -0
- package/lib/benchmark/llm.js +58 -0
- package/lib/benchmark/models.js +137 -0
- package/lib/benchmark/reporter.js +103 -0
- package/lib/benchmark/runner.js +103 -0
- package/lib/benchmark/sandbox.js +96 -0
- package/lib/benchmark/scorer.js +32 -0
- package/lib/benchmark/solver.js +166 -0
- package/lib/benchmark/tools.js +62 -0
- package/lib/bot/bot.js +238 -0
- package/lib/brand.js +105 -0
- package/lib/commands.js +100 -0
- package/lib/complexity.js +377 -0
- package/lib/config.js +213 -0
- package/lib/gateway/client.js +309 -0
- package/lib/gateway/commands.js +991 -0
- package/lib/gateway/config-validate.js +109 -0
- package/lib/gateway/gateway.js +367 -0
- package/lib/gateway/index.js +62 -0
- package/lib/gateway/mode.js +309 -0
- package/lib/gateway/plugins.js +222 -0
- package/lib/gateway/prompt.js +214 -0
- package/lib/mcp/server.js +262 -0
- package/lib/memory/compressor.js +425 -0
- package/lib/memory/engine.js +763 -0
- package/lib/memory/evolution.js +668 -0
- package/lib/memory/index.js +58 -0
- package/lib/memory/orchestrator.js +506 -0
- package/lib/memory/retriever.js +515 -0
- package/lib/memory/synthesizer.js +333 -0
- package/lib/pipeline/async-scanner.js +510 -0
- package/lib/pipeline/binary-analysis.js +1043 -0
- package/lib/pipeline/dom-xss-scanner.js +435 -0
- package/lib/pipeline/github-actions.js +792 -0
- package/lib/pipeline/index.js +124 -0
- package/lib/pipeline/osint.js +498 -0
- package/lib/pipeline/sarif.js +373 -0
- package/lib/pipeline/scanner.js +880 -0
- package/lib/pipeline/template-manager.js +525 -0
- package/lib/pipeline/xss-scanner.js +353 -0
- package/lib/setup-wizard.js +288 -0
- package/package.json +31 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Copyright (c) 2026 defconxt. All rights reserved.
|
|
2
|
+
// Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
3
|
+
// CIPHER is a trademark of defconxt.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CIPHER Memory Core — Tri-Stage Pipeline + Evolution Engine
|
|
7
|
+
*
|
|
8
|
+
* Public API surface for the memory module. All downstream consumers
|
|
9
|
+
* (gateway, API, MCP) import from this barrel.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Core engine
|
|
13
|
+
export {
|
|
14
|
+
CipherMemory,
|
|
15
|
+
MemoryEntry,
|
|
16
|
+
MemoryType,
|
|
17
|
+
Confidence,
|
|
18
|
+
SymbolicStore,
|
|
19
|
+
MemoryConsolidator,
|
|
20
|
+
reciprocalRankFusion,
|
|
21
|
+
} from './engine.js';
|
|
22
|
+
|
|
23
|
+
// Stage 1: Compressor
|
|
24
|
+
export {
|
|
25
|
+
SemanticCompressor,
|
|
26
|
+
DensityGate,
|
|
27
|
+
DialogueTurn,
|
|
28
|
+
CompressedEntry,
|
|
29
|
+
extractSecurityEntities,
|
|
30
|
+
} from './compressor.js';
|
|
31
|
+
|
|
32
|
+
// Stage 2: Synthesizer
|
|
33
|
+
export {
|
|
34
|
+
SemanticSynthesizer,
|
|
35
|
+
SynthesisResult,
|
|
36
|
+
} from './synthesizer.js';
|
|
37
|
+
|
|
38
|
+
// Stage 3: Retriever
|
|
39
|
+
export {
|
|
40
|
+
AdaptiveRetriever,
|
|
41
|
+
IntentClassifier,
|
|
42
|
+
QueryDecomposer,
|
|
43
|
+
ContextBuilder,
|
|
44
|
+
RetrievalPlan,
|
|
45
|
+
} from './retriever.js';
|
|
46
|
+
|
|
47
|
+
// Evolution
|
|
48
|
+
export {
|
|
49
|
+
ResponseScorer,
|
|
50
|
+
SkillEvolver,
|
|
51
|
+
ScoredResponse,
|
|
52
|
+
} from './evolution.js';
|
|
53
|
+
|
|
54
|
+
// Orchestrator
|
|
55
|
+
export {
|
|
56
|
+
CipherOrchestrator,
|
|
57
|
+
createOrchestrator,
|
|
58
|
+
} from './orchestrator.js';
|
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
// Copyright (c) 2026 defconxt. All rights reserved.
|
|
2
|
+
// Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
3
|
+
// CIPHER is a trademark of defconxt.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* CIPHER Memory — Session Orchestrator
|
|
7
|
+
*
|
|
8
|
+
* Ties together the 3-stage memory pipeline + evolution engine:
|
|
9
|
+
* Stage 1: SemanticCompressor (dialogue → atomic entries)
|
|
10
|
+
* Stage 2: SemanticSynthesizer (dedup, merge, link)
|
|
11
|
+
* Stage 3: AdaptiveRetriever (intent-aware search + context building)
|
|
12
|
+
* Evolution: ResponseScorer + SkillEvolver (learn from failures)
|
|
13
|
+
*
|
|
14
|
+
* Manages the full session lifecycle:
|
|
15
|
+
* startSession → recordTurn / recordToolUse / scoreResponse → stopSession
|
|
16
|
+
*
|
|
17
|
+
* Ported from Python memory/core/orchestrator.py.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { randomUUID } from 'node:crypto';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import { homedir } from 'node:os';
|
|
23
|
+
|
|
24
|
+
import { CipherMemory, MemoryEntry, MemoryType, Confidence } from './engine.js';
|
|
25
|
+
import { SemanticCompressor, CompressedEntry, DialogueTurn } from './compressor.js';
|
|
26
|
+
import { SemanticSynthesizer } from './synthesizer.js';
|
|
27
|
+
import { AdaptiveRetriever, ContextBuilder } from './retriever.js';
|
|
28
|
+
import { ResponseScorer, SkillEvolver } from './evolution.js';
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Session data structures
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a new SessionState object.
|
|
36
|
+
* @param {{ sessionId: string, engagementId: string, startedAt: string }} opts
|
|
37
|
+
* @returns {object}
|
|
38
|
+
*/
|
|
39
|
+
function createSessionState(opts) {
|
|
40
|
+
return {
|
|
41
|
+
sessionId: opts.sessionId,
|
|
42
|
+
engagementId: opts.engagementId,
|
|
43
|
+
startedAt: opts.startedAt,
|
|
44
|
+
turns: [],
|
|
45
|
+
scoredResponses: [],
|
|
46
|
+
entriesStored: 0,
|
|
47
|
+
active: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Create a SessionReport from processing results.
|
|
53
|
+
* @param {object} opts
|
|
54
|
+
* @returns {object}
|
|
55
|
+
*/
|
|
56
|
+
function createSessionReport(opts) {
|
|
57
|
+
return {
|
|
58
|
+
sessionId: opts.sessionId ?? '',
|
|
59
|
+
engagementId: opts.engagementId ?? '',
|
|
60
|
+
durationSeconds: opts.durationSeconds ?? 0,
|
|
61
|
+
turnsRecorded: opts.turnsRecorded ?? 0,
|
|
62
|
+
entriesStored: opts.entriesStored ?? 0,
|
|
63
|
+
entriesDeduplicated: opts.entriesDeduplicated ?? 0,
|
|
64
|
+
entriesMerged: opts.entriesMerged ?? 0,
|
|
65
|
+
evolutionTriggered: opts.evolutionTriggered ?? false,
|
|
66
|
+
skillsGenerated: opts.skillsGenerated ?? 0,
|
|
67
|
+
memoryStats: opts.memoryStats ?? {},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// MemoryType / Confidence value lookup helpers
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
/** Set of valid MemoryType values for fast lookup. */
|
|
76
|
+
const _VALID_MEMORY_TYPES = new Set(Object.values(MemoryType));
|
|
77
|
+
|
|
78
|
+
/** Set of valid Confidence values for fast lookup. */
|
|
79
|
+
const _VALID_CONFIDENCE = new Set(Object.values(Confidence));
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Resolve a string to a MemoryType value, defaulting to NOTE if invalid.
|
|
83
|
+
* @param {string} value
|
|
84
|
+
* @returns {string}
|
|
85
|
+
*/
|
|
86
|
+
function _resolveMemoryType(value) {
|
|
87
|
+
return _VALID_MEMORY_TYPES.has(value) ? value : MemoryType.NOTE;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Resolve a string to a Confidence value, defaulting to CONFIRMED if invalid.
|
|
92
|
+
* @param {string} value
|
|
93
|
+
* @returns {string}
|
|
94
|
+
*/
|
|
95
|
+
function _resolveConfidence(value) {
|
|
96
|
+
return _VALID_CONFIDENCE.has(value) ? value : Confidence.CONFIRMED;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// CipherOrchestrator
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Full session lifecycle orchestrator for CIPHER memory.
|
|
105
|
+
*
|
|
106
|
+
* Usage:
|
|
107
|
+
* const orch = new CipherOrchestrator({ memoryDir: '/tmp/mem' });
|
|
108
|
+
* const ctx = orch.startSession('ENG-001', 'Pentest of ACME Corp');
|
|
109
|
+
* orch.recordTurn(ctx.sessionId, 'user', 'Scan 10.10.14.5 for open ports');
|
|
110
|
+
* orch.recordTurn(ctx.sessionId, 'assistant', 'Found ports 22, 80, 443...');
|
|
111
|
+
* orch.recordToolUse(ctx.sessionId, 'nmap', '-sV 10.10.14.5', '22/tcp ssh...');
|
|
112
|
+
* orch.scoreResponse(ctx.sessionId, query, response, 'RED');
|
|
113
|
+
* const report = await orch.stopSession(ctx.sessionId);
|
|
114
|
+
* orch.close();
|
|
115
|
+
*/
|
|
116
|
+
class CipherOrchestrator {
|
|
117
|
+
/**
|
|
118
|
+
* @param {{
|
|
119
|
+
* memoryDir?: string,
|
|
120
|
+
* skillsDir?: string,
|
|
121
|
+
* llmClient?: any,
|
|
122
|
+
* enableEvolution?: boolean,
|
|
123
|
+
* evolutionThreshold?: number,
|
|
124
|
+
* contextTokens?: number,
|
|
125
|
+
* }} opts
|
|
126
|
+
*/
|
|
127
|
+
constructor(opts = {}) {
|
|
128
|
+
const {
|
|
129
|
+
memoryDir,
|
|
130
|
+
skillsDir = 'skills',
|
|
131
|
+
llmClient = null,
|
|
132
|
+
enableEvolution = true,
|
|
133
|
+
evolutionThreshold = 0.4,
|
|
134
|
+
contextTokens = 4000,
|
|
135
|
+
} = opts;
|
|
136
|
+
|
|
137
|
+
if (!memoryDir) {
|
|
138
|
+
throw new Error('CipherOrchestrator requires memoryDir');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Core memory engine
|
|
142
|
+
this.memory = new CipherMemory(memoryDir);
|
|
143
|
+
|
|
144
|
+
// Stage 1: Compressor
|
|
145
|
+
this.compressor = new SemanticCompressor({ llmClient });
|
|
146
|
+
|
|
147
|
+
// Stage 2: Synthesizer
|
|
148
|
+
this.synthesizer = new SemanticSynthesizer();
|
|
149
|
+
|
|
150
|
+
// Stage 3: Retriever
|
|
151
|
+
this.retriever = new AdaptiveRetriever(this.memory, {
|
|
152
|
+
enableReflection: true,
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Context builder
|
|
156
|
+
this.contextBuilder = new ContextBuilder({ maxTokens: contextTokens });
|
|
157
|
+
|
|
158
|
+
// Evolution engine
|
|
159
|
+
this.scorer = new ResponseScorer({ llmClient });
|
|
160
|
+
this.evolver = enableEvolution
|
|
161
|
+
? new SkillEvolver({
|
|
162
|
+
skillsDir,
|
|
163
|
+
llmClient,
|
|
164
|
+
historyPath: join(memoryDir, 'evolution_history.jsonl'),
|
|
165
|
+
})
|
|
166
|
+
: null;
|
|
167
|
+
this.evolutionThreshold = evolutionThreshold;
|
|
168
|
+
|
|
169
|
+
// Active sessions
|
|
170
|
+
this._sessions = new Map();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// -------------------------------------------------------------------------
|
|
174
|
+
// Session lifecycle
|
|
175
|
+
// -------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Start a new memory session.
|
|
179
|
+
*
|
|
180
|
+
* Automatically retrieves and injects context from previous sessions
|
|
181
|
+
* for the same engagement.
|
|
182
|
+
*
|
|
183
|
+
* @param {string} [engagementId='']
|
|
184
|
+
* @param {string} [userPrompt='']
|
|
185
|
+
* @returns {{ sessionId: string, engagementId: string, context: string, contextEntries: number }}
|
|
186
|
+
*/
|
|
187
|
+
startSession(engagementId = '', userPrompt = '') {
|
|
188
|
+
const sessionId = randomUUID();
|
|
189
|
+
const now = new Date().toISOString();
|
|
190
|
+
|
|
191
|
+
const effectiveEngagement = engagementId || `session-${sessionId.slice(0, 8)}`;
|
|
192
|
+
|
|
193
|
+
const state = createSessionState({
|
|
194
|
+
sessionId,
|
|
195
|
+
engagementId: effectiveEngagement,
|
|
196
|
+
startedAt: now,
|
|
197
|
+
});
|
|
198
|
+
this._sessions.set(sessionId, state);
|
|
199
|
+
|
|
200
|
+
// Retrieve context from previous sessions
|
|
201
|
+
let context = '';
|
|
202
|
+
if (userPrompt || engagementId) {
|
|
203
|
+
const query = userPrompt || `engagement ${engagementId}`;
|
|
204
|
+
const entries = this.retriever.retrieve(query, engagementId, 20);
|
|
205
|
+
if (entries.length > 0) {
|
|
206
|
+
context = this.contextBuilder.build(entries, query);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
sessionId,
|
|
212
|
+
engagementId: effectiveEngagement,
|
|
213
|
+
context,
|
|
214
|
+
contextEntries: context ? context.split('\n').length : 0,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Record a dialogue turn in the session.
|
|
220
|
+
* @param {string} sessionId
|
|
221
|
+
* @param {string} role
|
|
222
|
+
* @param {string} content
|
|
223
|
+
* @param {string} [timestamp='']
|
|
224
|
+
* @returns {boolean}
|
|
225
|
+
*/
|
|
226
|
+
recordTurn(sessionId, role, content, timestamp = '') {
|
|
227
|
+
const state = this._sessions.get(sessionId);
|
|
228
|
+
if (!state || !state.active) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const turn = new DialogueTurn({
|
|
233
|
+
turnId: state.turns.length + 1,
|
|
234
|
+
role,
|
|
235
|
+
content,
|
|
236
|
+
timestamp: timestamp || new Date().toISOString(),
|
|
237
|
+
});
|
|
238
|
+
state.turns.push(turn);
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Record a tool use event in the session.
|
|
244
|
+
* @param {string} sessionId
|
|
245
|
+
* @param {string} toolName
|
|
246
|
+
* @param {string} toolInput
|
|
247
|
+
* @param {string} toolOutput
|
|
248
|
+
* @returns {boolean}
|
|
249
|
+
*/
|
|
250
|
+
recordToolUse(sessionId, toolName, toolInput, toolOutput) {
|
|
251
|
+
const state = this._sessions.get(sessionId);
|
|
252
|
+
if (!state || !state.active) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const turn = new DialogueTurn({
|
|
257
|
+
turnId: state.turns.length + 1,
|
|
258
|
+
role: 'tool',
|
|
259
|
+
content: `Used ${toolName}: ${toolInput}`,
|
|
260
|
+
toolName,
|
|
261
|
+
toolOutput,
|
|
262
|
+
timestamp: new Date().toISOString(),
|
|
263
|
+
});
|
|
264
|
+
state.turns.push(turn);
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Score a response and track for evolution.
|
|
270
|
+
* @param {string} sessionId
|
|
271
|
+
* @param {string} query
|
|
272
|
+
* @param {string} response
|
|
273
|
+
* @param {string} [mode='']
|
|
274
|
+
* @param {string} [skillUsed='']
|
|
275
|
+
* @returns {import('./evolution.js').ScoredResponse}
|
|
276
|
+
*/
|
|
277
|
+
scoreResponse(sessionId, query, response, mode = '', skillUsed = '') {
|
|
278
|
+
const scored = this.scorer.score(query, response, mode, skillUsed);
|
|
279
|
+
|
|
280
|
+
const state = this._sessions.get(sessionId);
|
|
281
|
+
if (state) {
|
|
282
|
+
state.scoredResponses.push(scored);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return scored;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// -------------------------------------------------------------------------
|
|
289
|
+
// Session finalization (async — compressor.compress is async)
|
|
290
|
+
// -------------------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Finalize session: compress, synthesize, store, and optionally evolve.
|
|
294
|
+
*
|
|
295
|
+
* This is the main processing step that converts dialogue into
|
|
296
|
+
* persistent memory entries.
|
|
297
|
+
*
|
|
298
|
+
* @param {string} sessionId
|
|
299
|
+
* @returns {Promise<object>} SessionReport
|
|
300
|
+
*/
|
|
301
|
+
async stopSession(sessionId) {
|
|
302
|
+
const state = this._sessions.get(sessionId);
|
|
303
|
+
if (!state) {
|
|
304
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
state.active = false;
|
|
308
|
+
const started = new Date(state.startedAt);
|
|
309
|
+
const duration = (Date.now() - started.getTime()) / 1000;
|
|
310
|
+
|
|
311
|
+
// Stage 1: Compress dialogue into atomic entries
|
|
312
|
+
const compressed = await this.compressor.compress(
|
|
313
|
+
state.turns,
|
|
314
|
+
state.engagementId,
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
// Stage 2: Synthesize with existing memory
|
|
318
|
+
const existing = this.memory.getEngagementContext(state.engagementId);
|
|
319
|
+
const existingCompressed = existing.map(
|
|
320
|
+
(e) =>
|
|
321
|
+
new CompressedEntry({
|
|
322
|
+
entryId: e.entryId,
|
|
323
|
+
losslessRestatement: e.content,
|
|
324
|
+
memoryType: e.memoryType,
|
|
325
|
+
targets: e.targets,
|
|
326
|
+
cveIds: e.cveIds,
|
|
327
|
+
mitreAttack: e.mitreAttack,
|
|
328
|
+
keywords: e.keywords,
|
|
329
|
+
}),
|
|
330
|
+
);
|
|
331
|
+
const synthesis = this.synthesizer.synthesize(compressed, existingCompressed);
|
|
332
|
+
|
|
333
|
+
// Store new entries
|
|
334
|
+
let stored = 0;
|
|
335
|
+
for (const entry of synthesis.newEntries) {
|
|
336
|
+
const memEntry = new MemoryEntry({
|
|
337
|
+
entryId: entry.entryId,
|
|
338
|
+
content: entry.losslessRestatement,
|
|
339
|
+
memoryType: _resolveMemoryType(entry.memoryType),
|
|
340
|
+
confidence: _resolveConfidence(entry.confidence),
|
|
341
|
+
engagementId: entry.engagementId,
|
|
342
|
+
sourceSkill: entry.sourceSkill,
|
|
343
|
+
timestamp: entry.timestamp,
|
|
344
|
+
targets: entry.targets,
|
|
345
|
+
mitreAttack: entry.mitreAttack,
|
|
346
|
+
cveIds: entry.cveIds,
|
|
347
|
+
severity: entry.severity,
|
|
348
|
+
keywords: entry.keywords,
|
|
349
|
+
});
|
|
350
|
+
this.memory.store(memEntry);
|
|
351
|
+
stored++;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Update merged entries
|
|
355
|
+
for (const merged of synthesis.mergedEntries) {
|
|
356
|
+
const memEntry = new MemoryEntry({
|
|
357
|
+
entryId: merged.entryId,
|
|
358
|
+
content: merged.losslessRestatement,
|
|
359
|
+
memoryType: _resolveMemoryType(merged.memoryType),
|
|
360
|
+
engagementId: merged.engagementId,
|
|
361
|
+
targets: merged.targets,
|
|
362
|
+
mitreAttack: merged.mitreAttack,
|
|
363
|
+
cveIds: merged.cveIds,
|
|
364
|
+
keywords: merged.keywords,
|
|
365
|
+
});
|
|
366
|
+
this.memory.store(memEntry);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
state.entriesStored = stored;
|
|
370
|
+
|
|
371
|
+
// Evolution check
|
|
372
|
+
let evolutionTriggered = false;
|
|
373
|
+
let skillsGenerated = 0;
|
|
374
|
+
if (this.evolver && state.scoredResponses.length > 0) {
|
|
375
|
+
const failed = state.scoredResponses.filter((r) => r.score <= 0);
|
|
376
|
+
if (this.evolver.shouldEvolve(state.scoredResponses, this.evolutionThreshold)) {
|
|
377
|
+
const generated = this.evolver.evolve(failed);
|
|
378
|
+
skillsGenerated = generated.length;
|
|
379
|
+
evolutionTriggered = true;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Memory maintenance
|
|
384
|
+
this.memory.consolidate();
|
|
385
|
+
|
|
386
|
+
const report = createSessionReport({
|
|
387
|
+
sessionId,
|
|
388
|
+
engagementId: state.engagementId,
|
|
389
|
+
durationSeconds: duration,
|
|
390
|
+
turnsRecorded: state.turns.length,
|
|
391
|
+
entriesStored: stored,
|
|
392
|
+
entriesDeduplicated: synthesis.stats.deduplicated ?? 0,
|
|
393
|
+
entriesMerged: synthesis.stats.merged ?? 0,
|
|
394
|
+
evolutionTriggered,
|
|
395
|
+
skillsGenerated,
|
|
396
|
+
memoryStats: this.memory.stats(),
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
return report;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// -------------------------------------------------------------------------
|
|
403
|
+
// Search & context
|
|
404
|
+
// -------------------------------------------------------------------------
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Search memory with intent-aware retrieval.
|
|
408
|
+
* @param {string} query
|
|
409
|
+
* @param {string} [engagementId='']
|
|
410
|
+
* @param {number} [limit=10]
|
|
411
|
+
* @returns {MemoryEntry[]}
|
|
412
|
+
*/
|
|
413
|
+
search(query, engagementId = '', limit = 10) {
|
|
414
|
+
return this.retriever.retrieve(query, engagementId, limit);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Get formatted context for prompt injection.
|
|
419
|
+
* @param {string} query
|
|
420
|
+
* @param {string} [engagementId='']
|
|
421
|
+
* @param {number} [maxTokens=4000]
|
|
422
|
+
* @returns {string}
|
|
423
|
+
*/
|
|
424
|
+
getContext(query, engagementId = '', maxTokens = 4000) {
|
|
425
|
+
const entries = this.retriever.retrieve(query, engagementId);
|
|
426
|
+
const builder = new ContextBuilder({ maxTokens });
|
|
427
|
+
return builder.build(entries, query);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// -------------------------------------------------------------------------
|
|
431
|
+
// Diagnostics
|
|
432
|
+
// -------------------------------------------------------------------------
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Get orchestrator statistics.
|
|
436
|
+
* @returns {{ memory: object, evolution: object, active_sessions: number }}
|
|
437
|
+
*/
|
|
438
|
+
stats() {
|
|
439
|
+
const memoryStats = this.memory.stats();
|
|
440
|
+
const evolutionStats = this.evolver ? this.evolver.getSummary() : {};
|
|
441
|
+
return {
|
|
442
|
+
memory: memoryStats,
|
|
443
|
+
evolution: evolutionStats,
|
|
444
|
+
active_sessions: [...this._sessions.values()].filter((s) => s.active).length,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Clean up session state without closing memory.
|
|
450
|
+
* @param {string} sessionId
|
|
451
|
+
*/
|
|
452
|
+
endSession(sessionId) {
|
|
453
|
+
this._sessions.delete(sessionId);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Clean up all resources.
|
|
458
|
+
*/
|
|
459
|
+
close() {
|
|
460
|
+
this.memory.close();
|
|
461
|
+
this._sessions.clear();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// ---------------------------------------------------------------------------
|
|
466
|
+
// Factory function
|
|
467
|
+
// ---------------------------------------------------------------------------
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Factory function to create a configured CipherOrchestrator.
|
|
471
|
+
*
|
|
472
|
+
* @param {{
|
|
473
|
+
* project?: string,
|
|
474
|
+
* memoryDir?: string,
|
|
475
|
+
* skillsDir?: string,
|
|
476
|
+
* [key: string]: any,
|
|
477
|
+
* }} opts
|
|
478
|
+
* @returns {CipherOrchestrator}
|
|
479
|
+
*/
|
|
480
|
+
function createOrchestrator(opts = {}) {
|
|
481
|
+
const {
|
|
482
|
+
project = 'cipher',
|
|
483
|
+
memoryDir,
|
|
484
|
+
skillsDir = 'skills',
|
|
485
|
+
...rest
|
|
486
|
+
} = opts;
|
|
487
|
+
|
|
488
|
+
const effectiveDir = memoryDir || join(homedir(), '.cipher', 'memory', project);
|
|
489
|
+
|
|
490
|
+
return new CipherOrchestrator({
|
|
491
|
+
memoryDir: effectiveDir,
|
|
492
|
+
skillsDir,
|
|
493
|
+
...rest,
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// ---------------------------------------------------------------------------
|
|
498
|
+
// Exports
|
|
499
|
+
// ---------------------------------------------------------------------------
|
|
500
|
+
|
|
501
|
+
export {
|
|
502
|
+
CipherOrchestrator,
|
|
503
|
+
createOrchestrator,
|
|
504
|
+
createSessionState,
|
|
505
|
+
createSessionReport,
|
|
506
|
+
};
|