@nex-ai/nex 0.1.64 → 0.1.66
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/commands/dispatch.js +4 -10
- package/dist/commands/dispatch.js.map +1 -1
- package/dist/commands/scan.js +4 -0
- package/dist/commands/scan.js.map +1 -1
- package/dist/commands/setup.js +4 -0
- package/dist/commands/setup.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/lib/compounding-worker.d.ts +2 -0
- package/dist/lib/compounding-worker.js +21 -0
- package/dist/lib/compounding-worker.js.map +1 -0
- package/dist/lib/compounding.d.ts +20 -0
- package/dist/lib/compounding.js +45 -0
- package/dist/lib/compounding.js.map +1 -0
- package/dist/lib/installers.js +3 -2
- package/dist/lib/installers.js.map +1 -1
- package/dist/mcp/index.js +0 -0
- package/dist/plugin/adapters/cline-capture.d.ts +7 -0
- package/dist/plugin/adapters/cline-capture.js +25 -0
- package/dist/plugin/adapters/cline-capture.js.map +1 -0
- package/dist/plugin/adapters/cline-recall.d.ts +7 -0
- package/dist/plugin/adapters/cline-recall.js +30 -0
- package/dist/plugin/adapters/cline-recall.js.map +1 -0
- package/dist/plugin/adapters/cline-task-start.d.ts +7 -0
- package/dist/plugin/adapters/cline-task-start.js +30 -0
- package/dist/plugin/adapters/cline-task-start.js.map +1 -0
- package/dist/plugin/adapters/cursor-recall.d.ts +7 -0
- package/dist/plugin/adapters/cursor-recall.js +31 -0
- package/dist/plugin/adapters/cursor-recall.js.map +1 -0
- package/dist/plugin/adapters/cursor-session-start.d.ts +7 -0
- package/dist/plugin/adapters/cursor-session-start.js +30 -0
- package/dist/plugin/adapters/cursor-session-start.js.map +1 -0
- package/dist/plugin/adapters/cursor-stop.d.ts +7 -0
- package/dist/plugin/adapters/cursor-stop.js +25 -0
- package/dist/plugin/adapters/cursor-stop.js.map +1 -0
- package/dist/plugin/adapters/windsurf-capture.d.ts +7 -0
- package/dist/plugin/adapters/windsurf-capture.js +25 -0
- package/dist/plugin/adapters/windsurf-capture.js.map +1 -0
- package/dist/plugin/adapters/windsurf-recall.d.ts +7 -0
- package/dist/plugin/adapters/windsurf-recall.js +31 -0
- package/dist/plugin/adapters/windsurf-recall.js.map +1 -0
- package/dist/plugin/shared.d.ts +39 -0
- package/dist/plugin/shared.js +380 -0
- package/dist/plugin/shared.js.map +1 -0
- package/openclaw-plugin/dist/capture-filter.d.ts +32 -0
- package/openclaw-plugin/dist/capture-filter.d.ts.map +1 -0
- package/openclaw-plugin/dist/capture-filter.js +117 -0
- package/openclaw-plugin/dist/capture-filter.js.map +1 -0
- package/openclaw-plugin/dist/config.d.ts +24 -0
- package/openclaw-plugin/dist/config.d.ts.map +1 -0
- package/openclaw-plugin/dist/config.js +68 -0
- package/openclaw-plugin/dist/config.js.map +1 -0
- package/openclaw-plugin/dist/context-format.d.ts +23 -0
- package/openclaw-plugin/dist/context-format.d.ts.map +1 -0
- package/openclaw-plugin/dist/context-format.js +40 -0
- package/openclaw-plugin/dist/context-format.js.map +1 -0
- package/openclaw-plugin/dist/file-scanner.d.ts +23 -0
- package/openclaw-plugin/dist/file-scanner.d.ts.map +1 -0
- package/openclaw-plugin/dist/file-scanner.js +119 -0
- package/openclaw-plugin/dist/file-scanner.js.map +1 -0
- package/openclaw-plugin/dist/index.d.ts +94 -0
- package/openclaw-plugin/dist/index.d.ts.map +1 -0
- package/openclaw-plugin/dist/index.js +1227 -0
- package/openclaw-plugin/dist/index.js.map +1 -0
- package/openclaw-plugin/dist/nex-client.d.ts +52 -0
- package/openclaw-plugin/dist/nex-client.d.ts.map +1 -0
- package/openclaw-plugin/dist/nex-client.js +129 -0
- package/openclaw-plugin/dist/nex-client.js.map +1 -0
- package/openclaw-plugin/dist/rate-limiter.d.ts +29 -0
- package/openclaw-plugin/dist/rate-limiter.d.ts.map +1 -0
- package/openclaw-plugin/dist/rate-limiter.js +95 -0
- package/openclaw-plugin/dist/rate-limiter.js.map +1 -0
- package/openclaw-plugin/dist/session-store.d.ts +15 -0
- package/openclaw-plugin/dist/session-store.d.ts.map +1 -0
- package/openclaw-plugin/dist/session-store.js +43 -0
- package/openclaw-plugin/dist/session-store.js.map +1 -0
- package/openclaw-plugin/openclaw.plugin.json +85 -0
- package/openclaw-plugin/package.json +29 -0
- package/package.json +2 -1
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared hook logic — platform-agnostic recall, capture, and session-start.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from auto-recall.ts, auto-capture.ts, auto-session-start.ts
|
|
5
|
+
* so adapters for Cursor, Windsurf, Cline, etc. can reuse the same logic
|
|
6
|
+
* without duplicating filter/client/format code.
|
|
7
|
+
*/
|
|
8
|
+
import { loadConfig, loadScanConfig, ConfigError, isHookEnabled } from "./config.js";
|
|
9
|
+
import { NexClient, NexAuthError } from "./nex-client.js";
|
|
10
|
+
import { formatNexContext } from "./context-format.js";
|
|
11
|
+
import { captureFilter } from "./capture-filter.js";
|
|
12
|
+
import { SessionStore } from "./session-store.js";
|
|
13
|
+
import { shouldRecall, recordRecall } from "./recall-filter.js";
|
|
14
|
+
import { RateLimiter } from "./rate-limiter.js";
|
|
15
|
+
import { scanAndIngest } from "./file-scanner.js";
|
|
16
|
+
import { ingestContextFiles } from "./context-files.js";
|
|
17
|
+
import { readManifest, writeManifest, isChanged, markIngested, isScanFresh, markScanned } from "./file-manifest.js";
|
|
18
|
+
import { readdirSync, statSync, readFileSync } from "node:fs";
|
|
19
|
+
import { join, extname } from "node:path";
|
|
20
|
+
import { homedir } from "node:os";
|
|
21
|
+
const sessions = new SessionStore();
|
|
22
|
+
// ── Recall ──────────────────────────────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Run recall logic: filter prompt → query Nex /ask → return formatted context.
|
|
25
|
+
* Returns null if recall is skipped or fails.
|
|
26
|
+
*/
|
|
27
|
+
export async function doRecall(prompt, sessionKey) {
|
|
28
|
+
if (!isHookEnabled("recall"))
|
|
29
|
+
return null;
|
|
30
|
+
const trimmed = prompt?.trim();
|
|
31
|
+
if (!trimmed || trimmed.length < 5)
|
|
32
|
+
return null;
|
|
33
|
+
if (trimmed.startsWith("/"))
|
|
34
|
+
return null;
|
|
35
|
+
const isFirst = sessionKey ? !sessions.get(sessionKey) : true;
|
|
36
|
+
const decision = shouldRecall(trimmed, isFirst);
|
|
37
|
+
if (!decision.shouldRecall)
|
|
38
|
+
return null;
|
|
39
|
+
const cfg = loadConfig();
|
|
40
|
+
const client = new NexClient(cfg.apiKey, cfg.baseUrl);
|
|
41
|
+
let result;
|
|
42
|
+
try {
|
|
43
|
+
const nexSessionId = sessionKey ? sessions.get(sessionKey) : undefined;
|
|
44
|
+
result = await client.ask(trimmed, nexSessionId, 30_000);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
if (err instanceof NexAuthError) {
|
|
48
|
+
return {
|
|
49
|
+
context: "[Nex] API key expired or invalid. Run: nex register --email <email>",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
if (!result.answer)
|
|
55
|
+
return null;
|
|
56
|
+
if (result.session_id && sessionKey) {
|
|
57
|
+
sessions.set(sessionKey, result.session_id);
|
|
58
|
+
}
|
|
59
|
+
recordRecall(result.session_id);
|
|
60
|
+
const entityCount = result.entity_references?.length ?? 0;
|
|
61
|
+
const context = formatNexContext({
|
|
62
|
+
answer: result.answer,
|
|
63
|
+
entityCount,
|
|
64
|
+
sessionId: result.session_id,
|
|
65
|
+
});
|
|
66
|
+
return { context, nexSessionId: result.session_id };
|
|
67
|
+
}
|
|
68
|
+
// ── Capture ─────────────────────────────────────────────────────────────
|
|
69
|
+
const INGEST_TIMEOUT_MS = 3_000;
|
|
70
|
+
const MAX_PLAN_FILES = 2;
|
|
71
|
+
/**
|
|
72
|
+
* Run capture logic: filter message → ingest to Nex + scan plan files.
|
|
73
|
+
*/
|
|
74
|
+
export async function doCapture(input) {
|
|
75
|
+
if (!isHookEnabled("capture"))
|
|
76
|
+
return;
|
|
77
|
+
let cfg;
|
|
78
|
+
try {
|
|
79
|
+
cfg = loadConfig();
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const client = new NexClient(cfg.apiKey, cfg.baseUrl);
|
|
85
|
+
const rateLimiter = new RateLimiter();
|
|
86
|
+
// Conversation capture
|
|
87
|
+
const message = input.message?.trim();
|
|
88
|
+
if (message) {
|
|
89
|
+
const filterResult = captureFilter(message);
|
|
90
|
+
if (!filterResult.skipped) {
|
|
91
|
+
if (rateLimiter.canProceed()) {
|
|
92
|
+
try {
|
|
93
|
+
await client.ingest(filterResult.text, "claude-code-conversation", INGEST_TIMEOUT_MS);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
if (err instanceof NexAuthError) {
|
|
97
|
+
process.stderr.write(`[nex-capture] API key expired or invalid. Run 'nex register --email <email>' to get a new key.\n`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
process.stderr.write(`[nex-capture] Ingest failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Plan file ingestion
|
|
106
|
+
const plansDir = input.planDir ?? join(process.cwd(), ".claude", "plans");
|
|
107
|
+
try {
|
|
108
|
+
await ingestPlanFiles(client, rateLimiter, plansDir);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
process.stderr.write(`[nex-capture] Plan file scan error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
112
|
+
}
|
|
113
|
+
// Transcript ingestion — ingest the full session conversation
|
|
114
|
+
if (input.sessionId) {
|
|
115
|
+
try {
|
|
116
|
+
await ingestTranscript(client, input.sessionId);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// non-fatal
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
async function ingestPlanFiles(client, rateLimiter, plansDir) {
|
|
124
|
+
const scanConfig = loadScanConfig();
|
|
125
|
+
if (!scanConfig.enabled)
|
|
126
|
+
return;
|
|
127
|
+
let entries;
|
|
128
|
+
try {
|
|
129
|
+
entries = readdirSync(plansDir, { withFileTypes: true });
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const manifest = readManifest();
|
|
135
|
+
let ingested = 0;
|
|
136
|
+
for (const entry of entries) {
|
|
137
|
+
if (ingested >= MAX_PLAN_FILES)
|
|
138
|
+
break;
|
|
139
|
+
if (!entry.isFile())
|
|
140
|
+
continue;
|
|
141
|
+
if (extname(entry.name).toLowerCase() !== ".md")
|
|
142
|
+
continue;
|
|
143
|
+
const fullPath = join(plansDir, entry.name);
|
|
144
|
+
try {
|
|
145
|
+
const stat = statSync(fullPath);
|
|
146
|
+
if (!isChanged(fullPath, stat, manifest))
|
|
147
|
+
continue;
|
|
148
|
+
if (!rateLimiter.canProceed())
|
|
149
|
+
break;
|
|
150
|
+
let content = readFileSync(fullPath, "utf-8");
|
|
151
|
+
if (content.length > 100_000) {
|
|
152
|
+
content = content.slice(0, 100_000) + "\n[...truncated]";
|
|
153
|
+
}
|
|
154
|
+
const context = `claude-code-plan:${entry.name}`;
|
|
155
|
+
await client.ingest(content, context, INGEST_TIMEOUT_MS);
|
|
156
|
+
markIngested(fullPath, stat, context, manifest);
|
|
157
|
+
ingested++;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// skip individual file errors
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (ingested > 0)
|
|
164
|
+
writeManifest(manifest);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Read a Claude Code session transcript and ingest the full conversation.
|
|
168
|
+
*
|
|
169
|
+
* Extracts user and assistant messages from the JSONL transcript file,
|
|
170
|
+
* builds a condensed conversation text, and sends it to Nex in one shot.
|
|
171
|
+
* This captures the full context instead of just the last assistant message.
|
|
172
|
+
*/
|
|
173
|
+
const MAX_TRANSCRIPT_LENGTH = 100_000;
|
|
174
|
+
async function ingestTranscript(client, sessionId) {
|
|
175
|
+
const cwd = process.cwd();
|
|
176
|
+
// Claude Code stores transcripts at ~/.claude/projects/<project-hash>/<session-id>.jsonl
|
|
177
|
+
// Project hash is the CWD path with / replaced by -
|
|
178
|
+
const projectHash = "-" + cwd.replace(/\//g, "-");
|
|
179
|
+
const transcriptPath = join(homedir(), ".claude", "projects", projectHash, `${sessionId}.jsonl`);
|
|
180
|
+
let raw;
|
|
181
|
+
try {
|
|
182
|
+
raw = readFileSync(transcriptPath, "utf-8");
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return; // transcript doesn't exist yet or path is wrong
|
|
186
|
+
}
|
|
187
|
+
// Extract user/assistant messages
|
|
188
|
+
const lines = [];
|
|
189
|
+
for (const line of raw.split("\n")) {
|
|
190
|
+
if (!line.trim())
|
|
191
|
+
continue;
|
|
192
|
+
try {
|
|
193
|
+
const entry = JSON.parse(line);
|
|
194
|
+
const role = entry.message?.role;
|
|
195
|
+
if (role !== "user" && role !== "assistant")
|
|
196
|
+
continue;
|
|
197
|
+
let text = "";
|
|
198
|
+
const content = entry.message?.content;
|
|
199
|
+
if (typeof content === "string") {
|
|
200
|
+
text = content;
|
|
201
|
+
}
|
|
202
|
+
else if (Array.isArray(content)) {
|
|
203
|
+
text = content
|
|
204
|
+
.filter((c) => c.type === "text")
|
|
205
|
+
.map((c) => c.text)
|
|
206
|
+
.join("\n");
|
|
207
|
+
}
|
|
208
|
+
if (!text.trim())
|
|
209
|
+
continue;
|
|
210
|
+
// Strip nex-context blocks to avoid feedback loops
|
|
211
|
+
text = text.replace(/<nex-context>[\s\S]*?<\/nex-context>/g, "").trim();
|
|
212
|
+
if (!text)
|
|
213
|
+
continue;
|
|
214
|
+
lines.push(`[${role}]: ${text}`);
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (lines.length < 2)
|
|
221
|
+
return; // need at least one exchange
|
|
222
|
+
let transcript = lines.join("\n\n");
|
|
223
|
+
if (transcript.length > MAX_TRANSCRIPT_LENGTH) {
|
|
224
|
+
// Keep the most recent messages (end of conversation is most valuable)
|
|
225
|
+
transcript = transcript.slice(-MAX_TRANSCRIPT_LENGTH);
|
|
226
|
+
transcript = "[...earlier messages truncated]\n\n" + transcript;
|
|
227
|
+
}
|
|
228
|
+
await client.ingest(transcript, `claude-code-transcript:${sessionId}`, 30_000);
|
|
229
|
+
}
|
|
230
|
+
// ── Session Start ───────────────────────────────────────────────────────
|
|
231
|
+
const SESSION_START_QUERY = "Summarize the key active context, recent interactions, and important updates for this user.";
|
|
232
|
+
/**
|
|
233
|
+
* Run session-start logic: scan files → query Nex baseline → return context.
|
|
234
|
+
* Returns null if disabled. Returns registrationPrompt if no API key.
|
|
235
|
+
*/
|
|
236
|
+
export async function doSessionStart(source, sessionKey) {
|
|
237
|
+
if (!isHookEnabled("session_start"))
|
|
238
|
+
return null;
|
|
239
|
+
let cfg;
|
|
240
|
+
try {
|
|
241
|
+
cfg = loadConfig();
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
if (err instanceof ConfigError) {
|
|
245
|
+
// No API key — return registration instructions
|
|
246
|
+
return {
|
|
247
|
+
context: "",
|
|
248
|
+
registrationPrompt: buildRegistrationPrompt(),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
const client = new NexClient(cfg.apiKey, cfg.baseUrl);
|
|
254
|
+
const contextParts = [];
|
|
255
|
+
// File scan on startup or clear
|
|
256
|
+
const shouldScan = source === "startup" || source === "clear";
|
|
257
|
+
if (shouldScan) {
|
|
258
|
+
// Skip expensive file scanning if a scan completed recently (within 1 hour).
|
|
259
|
+
// The context query below still runs — only the file walk + ingest is skipped.
|
|
260
|
+
const scanManifest = readManifest();
|
|
261
|
+
const scanFresh = isScanFresh(scanManifest);
|
|
262
|
+
if (!scanFresh) {
|
|
263
|
+
const rateLimiter = new RateLimiter();
|
|
264
|
+
const cwd = process.cwd();
|
|
265
|
+
try {
|
|
266
|
+
const ctxResult = await ingestContextFiles(client, rateLimiter, cwd);
|
|
267
|
+
if (ctxResult.ingested > 0) {
|
|
268
|
+
contextParts.push(`[Context files: ${ctxResult.ingested} ingested (${ctxResult.files.join(", ")})]`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// non-fatal
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
const scanConfig = loadScanConfig();
|
|
276
|
+
if (scanConfig.enabled) {
|
|
277
|
+
const scanResult = await scanAndIngest(client, rateLimiter, cwd, scanConfig);
|
|
278
|
+
if (scanResult.ingested > 0) {
|
|
279
|
+
contextParts.push(`[File scan: ${scanResult.ingested} file${scanResult.ingested === 1 ? "" : "s"} ingested, ${scanResult.scanned} scanned]`);
|
|
280
|
+
// Trigger compounding intelligence after ingestion (non-blocking, best-effort)
|
|
281
|
+
triggerCompounding(cfg).catch(() => { });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// non-fatal
|
|
287
|
+
}
|
|
288
|
+
// Mark scan as complete so subsequent sessions skip it
|
|
289
|
+
markScanned(scanManifest);
|
|
290
|
+
writeManifest(scanManifest);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
let result;
|
|
294
|
+
try {
|
|
295
|
+
result = await client.ask(SESSION_START_QUERY, undefined, 30_000);
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
if (err instanceof NexAuthError) {
|
|
299
|
+
return {
|
|
300
|
+
context: "",
|
|
301
|
+
registrationPrompt: buildAuthExpiredPrompt(),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
throw err;
|
|
305
|
+
}
|
|
306
|
+
if (!result.answer && contextParts.length === 0)
|
|
307
|
+
return null;
|
|
308
|
+
if (result.session_id && sessionKey) {
|
|
309
|
+
sessions.set(sessionKey, result.session_id);
|
|
310
|
+
}
|
|
311
|
+
recordRecall(result.session_id);
|
|
312
|
+
const entityCount = result.entity_references?.length ?? 0;
|
|
313
|
+
const context = formatNexContext({
|
|
314
|
+
answer: result.answer,
|
|
315
|
+
entityCount,
|
|
316
|
+
sessionId: result.session_id,
|
|
317
|
+
});
|
|
318
|
+
const fullContext = contextParts.length > 0
|
|
319
|
+
? `${context}\n${contextParts.join("\n")}`
|
|
320
|
+
: context;
|
|
321
|
+
return { context: fullContext, nexSessionId: result.session_id };
|
|
322
|
+
}
|
|
323
|
+
function buildRegistrationPrompt() {
|
|
324
|
+
return [
|
|
325
|
+
"[Nex Memory Plugin] No API key configured. Registration is required to enable persistent memory.",
|
|
326
|
+
"",
|
|
327
|
+
"IMPORTANT: Before proceeding with the user's request, you must set up Nex memory:",
|
|
328
|
+
"1. Ask the user for their email address to register for a Nex account",
|
|
329
|
+
"2. Run: nex register --email <email>",
|
|
330
|
+
"3. Then run: nex setup",
|
|
331
|
+
"",
|
|
332
|
+
"Keep it brief — just ask for the email and register. No restart needed after registration.",
|
|
333
|
+
].join("\n");
|
|
334
|
+
}
|
|
335
|
+
function buildAuthExpiredPrompt() {
|
|
336
|
+
return [
|
|
337
|
+
"[Nex Memory Plugin] API key expired or invalid. Re-registration is required to restore persistent memory.",
|
|
338
|
+
"",
|
|
339
|
+
"IMPORTANT: Before proceeding with the user's request, you must renew the Nex API key:",
|
|
340
|
+
"1. Ask the user for their email address",
|
|
341
|
+
"2. Run: nex register --email <email>",
|
|
342
|
+
"3. Then run: nex setup",
|
|
343
|
+
"",
|
|
344
|
+
"Keep it brief — just ask for the email and register. No restart needed after registration.",
|
|
345
|
+
].join("\n");
|
|
346
|
+
}
|
|
347
|
+
// ── Helpers ─────────────────────────────────────────────────────────────
|
|
348
|
+
/** Read stdin as a string (shared across all hook scripts). */
|
|
349
|
+
export async function readStdin() {
|
|
350
|
+
const chunks = [];
|
|
351
|
+
for await (const chunk of process.stdin) {
|
|
352
|
+
chunks.push(chunk);
|
|
353
|
+
}
|
|
354
|
+
return Buffer.concat(chunks).toString("utf-8");
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Trigger compounding intelligence jobs after content ingestion.
|
|
358
|
+
* Runs consolidation, pattern detection, and playbook synthesis.
|
|
359
|
+
* Best-effort — errors are silently ignored.
|
|
360
|
+
*/
|
|
361
|
+
async function triggerCompounding(cfg) {
|
|
362
|
+
const jobs = ["consolidation", "pattern_detection", "playbook_synthesis"];
|
|
363
|
+
const url = `${cfg.baseUrl}/api/developers/v1/compounding/trigger`;
|
|
364
|
+
await Promise.allSettled(jobs.map((job) => fetch(url, {
|
|
365
|
+
method: "POST",
|
|
366
|
+
headers: { Authorization: `Bearer ${cfg.apiKey}`, "Content-Type": "application/json" },
|
|
367
|
+
body: JSON.stringify({ job_type: job, dry_run: false }),
|
|
368
|
+
signal: AbortSignal.timeout(30_000),
|
|
369
|
+
})));
|
|
370
|
+
}
|
|
371
|
+
/** Wrap output in Claude Code hookSpecificOutput format. */
|
|
372
|
+
export function claudeCodeOutput(hookEventName, additionalContext) {
|
|
373
|
+
return JSON.stringify({
|
|
374
|
+
hookSpecificOutput: {
|
|
375
|
+
hookEventName,
|
|
376
|
+
additionalContext,
|
|
377
|
+
},
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/plugin/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart capture filtering — decides what content to send to Nex for ingestion.
|
|
3
|
+
* Cherry-picked from Supermemory (provider skip), Engram (dedup), MemOS Cloud (capture modes).
|
|
4
|
+
*/
|
|
5
|
+
import type { NexPluginConfig } from "./config.js";
|
|
6
|
+
/** Message shape from OpenClaw agent_end event. */
|
|
7
|
+
export interface AgentMessage {
|
|
8
|
+
role: string;
|
|
9
|
+
content?: string | Array<{
|
|
10
|
+
type: string;
|
|
11
|
+
text?: string;
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
export interface CaptureFilterResult {
|
|
15
|
+
text: string;
|
|
16
|
+
skipped: false;
|
|
17
|
+
}
|
|
18
|
+
export interface CaptureFilterSkip {
|
|
19
|
+
reason: string;
|
|
20
|
+
skipped: true;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Process agent_end event and decide what to capture.
|
|
24
|
+
* Returns cleaned text or a skip reason.
|
|
25
|
+
*/
|
|
26
|
+
export declare function captureFilter(messages: AgentMessage[], config: NexPluginConfig, opts?: {
|
|
27
|
+
messageProvider?: string;
|
|
28
|
+
success?: boolean;
|
|
29
|
+
}): CaptureFilterResult | CaptureFilterSkip;
|
|
30
|
+
/** Reset dedup cache (for testing). */
|
|
31
|
+
export declare function resetDedupCache(): void;
|
|
32
|
+
//# sourceMappingURL=capture-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-filter.d.ts","sourceRoot":"","sources":["../src/capture-filter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3D;AAgED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,YAAY,EAAE,EACxB,MAAM,EAAE,eAAe,EACvB,IAAI,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD,mBAAmB,GAAG,iBAAiB,CA8DzC;AAED,uCAAuC;AACvC,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart capture filtering — decides what content to send to Nex for ingestion.
|
|
3
|
+
* Cherry-picked from Supermemory (provider skip), Engram (dedup), MemOS Cloud (capture modes).
|
|
4
|
+
*/
|
|
5
|
+
import { stripNexContext } from "./context-format.js";
|
|
6
|
+
/** Providers whose messages should never be auto-captured. */
|
|
7
|
+
const SKIP_PROVIDERS = new Set(["exec-event", "cron-event"]);
|
|
8
|
+
const MIN_LENGTH = 10;
|
|
9
|
+
const MAX_LENGTH = 50_000;
|
|
10
|
+
/**
|
|
11
|
+
* Simple content hash for deduplication.
|
|
12
|
+
* Uses a fast string hash — not cryptographic, just collision-resistant enough for dedup.
|
|
13
|
+
*/
|
|
14
|
+
function hashContent(text) {
|
|
15
|
+
let hash = 0;
|
|
16
|
+
for (let i = 0; i < text.length; i++) {
|
|
17
|
+
const ch = text.charCodeAt(i);
|
|
18
|
+
hash = ((hash << 5) - hash + ch) | 0;
|
|
19
|
+
}
|
|
20
|
+
return hash.toString(36);
|
|
21
|
+
}
|
|
22
|
+
const DEDUP_MAX = 50;
|
|
23
|
+
const DEDUP_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
24
|
+
/** In-memory LRU cache for content hash dedup. */
|
|
25
|
+
const dedupCache = [];
|
|
26
|
+
function isDuplicate(hash) {
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
// Evict expired entries
|
|
29
|
+
while (dedupCache.length > 0 && now - dedupCache[0].timestamp > DEDUP_TTL_MS) {
|
|
30
|
+
dedupCache.shift();
|
|
31
|
+
}
|
|
32
|
+
// Check for match
|
|
33
|
+
if (dedupCache.some((e) => e.hash === hash)) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
// Add to cache
|
|
37
|
+
dedupCache.push({ hash, timestamp: now });
|
|
38
|
+
// LIFO eviction if over max
|
|
39
|
+
if (dedupCache.length > DEDUP_MAX) {
|
|
40
|
+
dedupCache.shift();
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
/** Extract text content from an AgentMessage. */
|
|
45
|
+
function extractText(msg) {
|
|
46
|
+
if (typeof msg.content === "string")
|
|
47
|
+
return msg.content;
|
|
48
|
+
if (Array.isArray(msg.content)) {
|
|
49
|
+
return msg.content
|
|
50
|
+
.filter((p) => p.type === "text" && p.text)
|
|
51
|
+
.map((p) => p.text)
|
|
52
|
+
.join("\n");
|
|
53
|
+
}
|
|
54
|
+
return "";
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Process agent_end event and decide what to capture.
|
|
58
|
+
* Returns cleaned text or a skip reason.
|
|
59
|
+
*/
|
|
60
|
+
export function captureFilter(messages, config, opts) {
|
|
61
|
+
// Skip failed agent runs
|
|
62
|
+
if (opts?.success === false) {
|
|
63
|
+
return { skipped: true, reason: "agent run failed" };
|
|
64
|
+
}
|
|
65
|
+
// Skip system event providers
|
|
66
|
+
if (opts?.messageProvider && SKIP_PROVIDERS.has(opts.messageProvider)) {
|
|
67
|
+
return { skipped: true, reason: `provider "${opts.messageProvider}" is in skip list` };
|
|
68
|
+
}
|
|
69
|
+
if (!messages || messages.length === 0) {
|
|
70
|
+
return { skipped: true, reason: "no messages" };
|
|
71
|
+
}
|
|
72
|
+
let text;
|
|
73
|
+
if (config.captureMode === "last_turn") {
|
|
74
|
+
// Extract last user + last assistant message
|
|
75
|
+
const parts = [];
|
|
76
|
+
const reversed = [...messages].reverse();
|
|
77
|
+
const lastAssistant = reversed.find((m) => m.role === "assistant");
|
|
78
|
+
const lastUser = reversed.find((m) => m.role === "user");
|
|
79
|
+
if (lastUser)
|
|
80
|
+
parts.push(`User: ${extractText(lastUser)}`);
|
|
81
|
+
if (lastAssistant)
|
|
82
|
+
parts.push(`Assistant: ${extractText(lastAssistant)}`);
|
|
83
|
+
text = parts.join("\n\n");
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// full_session: capture all user and assistant messages
|
|
87
|
+
text = messages
|
|
88
|
+
.filter((m) => m.role === "user" || m.role === "assistant")
|
|
89
|
+
.map((m) => `${m.role === "user" ? "User" : "Assistant"}: ${extractText(m)}`)
|
|
90
|
+
.join("\n\n");
|
|
91
|
+
}
|
|
92
|
+
// Strip injected context blocks (prevent feedback loop)
|
|
93
|
+
text = stripNexContext(text);
|
|
94
|
+
// Skip slash commands
|
|
95
|
+
if (text.startsWith("User: /")) {
|
|
96
|
+
return { skipped: true, reason: "slash command" };
|
|
97
|
+
}
|
|
98
|
+
// Skip too short
|
|
99
|
+
if (text.length < MIN_LENGTH) {
|
|
100
|
+
return { skipped: true, reason: `too short (${text.length} chars)` };
|
|
101
|
+
}
|
|
102
|
+
// Skip too long
|
|
103
|
+
if (text.length > MAX_LENGTH) {
|
|
104
|
+
return { skipped: true, reason: `too long (${text.length} chars)` };
|
|
105
|
+
}
|
|
106
|
+
// Dedup check
|
|
107
|
+
const hash = hashContent(text);
|
|
108
|
+
if (isDuplicate(hash)) {
|
|
109
|
+
return { skipped: true, reason: "duplicate content" };
|
|
110
|
+
}
|
|
111
|
+
return { skipped: false, text };
|
|
112
|
+
}
|
|
113
|
+
/** Reset dedup cache (for testing). */
|
|
114
|
+
export function resetDedupCache() {
|
|
115
|
+
dedupCache.length = 0;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=capture-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-filter.js","sourceRoot":"","sources":["../src/capture-filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin configuration parsing and validation.
|
|
3
|
+
* Resolves API key from config, env var, or ${VAR} interpolation.
|
|
4
|
+
*/
|
|
5
|
+
export interface NexPluginConfig {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
autoRecall: boolean;
|
|
9
|
+
autoCapture: boolean;
|
|
10
|
+
captureMode: "last_turn" | "full_session";
|
|
11
|
+
maxRecallResults: number;
|
|
12
|
+
sessionTracking: boolean;
|
|
13
|
+
recallTimeoutMs: number;
|
|
14
|
+
debug: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare class ConfigError extends Error {
|
|
17
|
+
constructor(message: string);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse raw plugin config into a validated NexPluginConfig.
|
|
21
|
+
* Falls back to process.env.NEX_API_KEY if no apiKey in config.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseConfig(raw?: Record<string, unknown>): NexPluginConfig;
|
|
24
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,WAAW,GAAG,cAAc,CAAC;IAC1C,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,OAAO,CAAC;CAChB;AAoBD,qBAAa,WAAY,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI5B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe,CA4C1E"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin configuration parsing and validation.
|
|
3
|
+
* Resolves API key from config, env var, or ${VAR} interpolation.
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULTS = {
|
|
6
|
+
baseUrl: "https://app.nex.ai",
|
|
7
|
+
autoRecall: true,
|
|
8
|
+
autoCapture: true,
|
|
9
|
+
captureMode: "last_turn",
|
|
10
|
+
maxRecallResults: 5,
|
|
11
|
+
sessionTracking: true,
|
|
12
|
+
recallTimeoutMs: 1500,
|
|
13
|
+
debug: false,
|
|
14
|
+
};
|
|
15
|
+
/** Resolve ${VAR_NAME} patterns in a string value. */
|
|
16
|
+
function resolveEnvVars(value) {
|
|
17
|
+
return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
|
|
18
|
+
return process.env[varName.trim()] ?? "";
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
export class ConfigError extends Error {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "ConfigError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Parse raw plugin config into a validated NexPluginConfig.
|
|
29
|
+
* Falls back to process.env.NEX_API_KEY if no apiKey in config.
|
|
30
|
+
*/
|
|
31
|
+
export function parseConfig(raw) {
|
|
32
|
+
const cfg = raw ?? {};
|
|
33
|
+
// Resolve API key: config → env var interpolation → NEX_API_KEY env
|
|
34
|
+
let apiKey = typeof cfg.apiKey === "string" ? resolveEnvVars(cfg.apiKey) : undefined;
|
|
35
|
+
if (!apiKey) {
|
|
36
|
+
apiKey = process.env.NEX_API_KEY;
|
|
37
|
+
}
|
|
38
|
+
if (!apiKey) {
|
|
39
|
+
throw new ConfigError("No API key configured. Set 'apiKey' in plugin config or export NEX_API_KEY environment variable.");
|
|
40
|
+
}
|
|
41
|
+
let baseUrl = process.env.NEX_DEV_URL
|
|
42
|
+
?? (typeof cfg.baseUrl === "string" ? resolveEnvVars(cfg.baseUrl).replace(/\/+$/, "") : undefined)
|
|
43
|
+
?? DEFAULTS.baseUrl;
|
|
44
|
+
const captureMode = cfg.captureMode;
|
|
45
|
+
if (captureMode !== undefined && captureMode !== "last_turn" && captureMode !== "full_session") {
|
|
46
|
+
throw new ConfigError(`Invalid captureMode: "${captureMode}". Must be "last_turn" or "full_session".`);
|
|
47
|
+
}
|
|
48
|
+
const maxRecallResults = typeof cfg.maxRecallResults === "number" ? cfg.maxRecallResults : DEFAULTS.maxRecallResults;
|
|
49
|
+
if (maxRecallResults < 1 || maxRecallResults > 20) {
|
|
50
|
+
throw new ConfigError(`maxRecallResults must be between 1 and 20, got ${maxRecallResults}.`);
|
|
51
|
+
}
|
|
52
|
+
const recallTimeoutMs = typeof cfg.recallTimeoutMs === "number" ? cfg.recallTimeoutMs : DEFAULTS.recallTimeoutMs;
|
|
53
|
+
if (recallTimeoutMs < 500 || recallTimeoutMs > 10000) {
|
|
54
|
+
throw new ConfigError(`recallTimeoutMs must be between 500 and 10000, got ${recallTimeoutMs}.`);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
apiKey,
|
|
58
|
+
baseUrl,
|
|
59
|
+
autoRecall: typeof cfg.autoRecall === "boolean" ? cfg.autoRecall : DEFAULTS.autoRecall,
|
|
60
|
+
autoCapture: typeof cfg.autoCapture === "boolean" ? cfg.autoCapture : DEFAULTS.autoCapture,
|
|
61
|
+
captureMode: captureMode ?? DEFAULTS.captureMode,
|
|
62
|
+
maxRecallResults,
|
|
63
|
+
sessionTracking: typeof cfg.sessionTracking === "boolean" ? cfg.sessionTracking : DEFAULTS.sessionTracking,
|
|
64
|
+
recallTimeoutMs,
|
|
65
|
+
debug: typeof cfg.debug === "boolean" ? cfg.debug : DEFAULTS.debug,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|