@nex-ai/nex 0.1.65 → 0.1.67
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/upgrade.d.ts +9 -0
- package/dist/commands/upgrade.js +87 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- 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/auto-session-start.js +39 -1
- package/dist/plugin/auto-session-start.js.map +1 -1
- package/dist/plugin/shared.d.ts +39 -0
- package/dist/plugin/shared.js +380 -0
- package/dist/plugin/shared.js.map +1 -0
- package/dist/plugin/update-check.d.ts +13 -0
- package/dist/plugin/update-check.js +134 -0
- package/dist/plugin/update-check.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,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* nex-update-check — lightweight version check with caching.
|
|
4
|
+
*
|
|
5
|
+
* Outputs one of:
|
|
6
|
+
* UPGRADE_AVAILABLE <current> <latest>
|
|
7
|
+
* (nothing — up to date, snoozed, disabled, or cached)
|
|
8
|
+
*
|
|
9
|
+
* Designed to run inline in session start hooks with minimal latency.
|
|
10
|
+
* Caches results to ~/.nex/last-update-check (60 min TTL for "up to date",
|
|
11
|
+
* 720 min for "upgrade available"). Supports snooze with escalating backoff.
|
|
12
|
+
*/
|
|
13
|
+
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { homedir } from "node:os";
|
|
16
|
+
import { execFileSync } from "node:child_process";
|
|
17
|
+
import { createRequire } from "node:module";
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
const pkg = require("../../package.json");
|
|
20
|
+
const NEX_DIR = join(homedir(), ".nex");
|
|
21
|
+
const CACHE_PATH = join(NEX_DIR, "last-update-check");
|
|
22
|
+
const SNOOZE_PATH = join(NEX_DIR, "update-snoozed");
|
|
23
|
+
const UPGRADED_PATH = join(NEX_DIR, "just-upgraded-from");
|
|
24
|
+
const UP_TO_DATE_TTL_MS = 60 * 60 * 1000; // 60 min
|
|
25
|
+
const UPGRADE_AVAIL_TTL_MS = 12 * 60 * 60 * 1000; // 12 hours
|
|
26
|
+
// Snooze escalation: 24h → 48h → 7d
|
|
27
|
+
const SNOOZE_LEVELS_MS = [
|
|
28
|
+
24 * 60 * 60 * 1000,
|
|
29
|
+
48 * 60 * 60 * 1000,
|
|
30
|
+
7 * 24 * 60 * 60 * 1000,
|
|
31
|
+
];
|
|
32
|
+
function compareVersions(a, b) {
|
|
33
|
+
const pa = a.split(".").map(Number);
|
|
34
|
+
const pb = b.split(".").map(Number);
|
|
35
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
36
|
+
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
37
|
+
if (diff !== 0)
|
|
38
|
+
return diff;
|
|
39
|
+
}
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
function readJson(path) {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function writeJson(path, data) {
|
|
51
|
+
mkdirSync(NEX_DIR, { recursive: true });
|
|
52
|
+
writeFileSync(path, JSON.stringify(data) + "\n", "utf-8");
|
|
53
|
+
}
|
|
54
|
+
/** Check if snoozed for current latest version. */
|
|
55
|
+
function isSnoozed(latestVersion) {
|
|
56
|
+
const snooze = readJson(SNOOZE_PATH);
|
|
57
|
+
if (!snooze)
|
|
58
|
+
return false;
|
|
59
|
+
if (snooze.version !== latestVersion)
|
|
60
|
+
return false; // new version resets snooze
|
|
61
|
+
const level = Math.min(snooze.level, SNOOZE_LEVELS_MS.length - 1);
|
|
62
|
+
const elapsed = Date.now() - snooze.snoozed_at;
|
|
63
|
+
return elapsed < SNOOZE_LEVELS_MS[level];
|
|
64
|
+
}
|
|
65
|
+
/** Check if we just upgraded (marker left by upgrade command). */
|
|
66
|
+
function checkJustUpgraded() {
|
|
67
|
+
try {
|
|
68
|
+
const old = readFileSync(UPGRADED_PATH, "utf-8").trim();
|
|
69
|
+
// Clean up the marker
|
|
70
|
+
try {
|
|
71
|
+
writeFileSync(UPGRADED_PATH, "", "utf-8");
|
|
72
|
+
}
|
|
73
|
+
catch { /* ignore */ }
|
|
74
|
+
return old;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function fetchLatestVersion() {
|
|
81
|
+
try {
|
|
82
|
+
const raw = execFileSync("curl", ["-sf", "--max-time", "5", "https://registry.npmjs.org/@nex-ai/nex/latest"], { encoding: "utf-8", timeout: 6000 });
|
|
83
|
+
const data = JSON.parse(raw);
|
|
84
|
+
const ver = data.version;
|
|
85
|
+
if (typeof ver === "string" && /^\d+\.\d+\.\d+/.test(ver))
|
|
86
|
+
return ver;
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function main() {
|
|
94
|
+
const current = pkg.version;
|
|
95
|
+
// Check if update checking is disabled
|
|
96
|
+
try {
|
|
97
|
+
const config = readJson(join(NEX_DIR, "config.json"));
|
|
98
|
+
if (config?.update_check === false)
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
catch { /* continue */ }
|
|
102
|
+
// Check for just-upgraded marker
|
|
103
|
+
const upgradedFrom = checkJustUpgraded();
|
|
104
|
+
if (upgradedFrom && upgradedFrom !== current) {
|
|
105
|
+
console.log(`JUST_UPGRADED ${upgradedFrom} ${current}`);
|
|
106
|
+
// Clear stale cache
|
|
107
|
+
writeJson(CACHE_PATH, { current, latest: current, status: "up_to_date", checked_at: Date.now() });
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// Fast path: check cache
|
|
111
|
+
const cached = readJson(CACHE_PATH);
|
|
112
|
+
if (cached && cached.current === current) {
|
|
113
|
+
const age = Date.now() - cached.checked_at;
|
|
114
|
+
const ttl = cached.status === "up_to_date" ? UP_TO_DATE_TTL_MS : UPGRADE_AVAIL_TTL_MS;
|
|
115
|
+
if (age < ttl) {
|
|
116
|
+
if (cached.status === "upgrade_available" && !isSnoozed(cached.latest)) {
|
|
117
|
+
console.log(`UPGRADE_AVAILABLE ${current} ${cached.latest}`);
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Slow path: fetch from registry
|
|
123
|
+
const latest = fetchLatestVersion();
|
|
124
|
+
if (!latest)
|
|
125
|
+
return; // network error — fail silently
|
|
126
|
+
const status = compareVersions(latest, current) > 0 ? "upgrade_available" : "up_to_date";
|
|
127
|
+
// Write cache
|
|
128
|
+
writeJson(CACHE_PATH, { current, latest, status, checked_at: Date.now() });
|
|
129
|
+
if (status === "upgrade_available" && !isSnoozed(latest)) {
|
|
130
|
+
console.log(`UPGRADE_AVAILABLE ${current} ${latest}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
main();
|
|
134
|
+
//# sourceMappingURL=update-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-check.js","sourceRoot":"","sources":["../../src/plugin/update-check.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":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAStD,8DAA8D;AAC9D,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;AAE7D,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,UAAU,GAAG,MAAM,CAAC;AAE1B;;;GAGG;AACH,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC;AAQD,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,YAAY,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAE9C,kDAAkD;AAClD,MAAM,UAAU,GAAiB,EAAE,CAAC;AAEpC,SAAS,WAAW,CAAC,IAAY;IAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,wBAAwB;IACxB,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,GAAG,YAAY,EAAE,CAAC;QAC7E,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IACD,kBAAkB;IAClB,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,eAAe;IACf,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IAC1C,4BAA4B;IAC5B,IAAI,UAAU,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAClC,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iDAAiD;AACjD,SAAS,WAAW,CAAC,GAAiB;IACpC,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IACxD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,OAAO,GAAG,CAAC,OAAO;aACf,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC;aAC1C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAK,CAAC;aACnB,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAYD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,QAAwB,EACxB,MAAuB,EACvB,IAAsD;IAEtD,yBAAyB;IACzB,IAAI,IAAI,EAAE,OAAO,KAAK,KAAK,EAAE,CAAC;QAC5B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IACvD,CAAC;IAED,8BAA8B;IAC9B,IAAI,IAAI,EAAE,eAAe,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;QACtE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,IAAI,CAAC,eAAe,mBAAmB,EAAE,CAAC;IACzF,CAAC;IAED,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,IAAY,CAAC;IAEjB,IAAI,MAAM,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;QACvC,6CAA6C;QAC7C,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;QAEzC,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;QACnE,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;QAEzD,IAAI,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC3D,IAAI,aAAa;YAAE,KAAK,CAAC,IAAI,CAAC,cAAc,WAAW,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QAE1E,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,wDAAwD;QACxD,IAAI,GAAG,QAAQ;aACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC;aAC1D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;aAC5E,IAAI,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;IAED,wDAAwD;IACxD,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAE7B,sBAAsB;IACtB,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACpD,CAAC;IAED,iBAAiB;IACjB,IAAI,IAAI,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,IAAI,CAAC,MAAM,SAAS,EAAE,CAAC;IACvE,CAAC;IAED,gBAAgB;IAChB,IAAI,IAAI,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,IAAI,CAAC,MAAM,SAAS,EAAE,CAAC;IACtE,CAAC;IAED,cAAc;IACd,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IACxD,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,eAAe;IAC7B,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;AACxB,CAAC"}
|
|
@@ -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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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML context formatting and stripping for recall injection.
|
|
3
|
+
* Wraps Nex answers in <nex-context> tags and strips them before capture.
|
|
4
|
+
*/
|
|
5
|
+
export interface NexRecallResult {
|
|
6
|
+
answer: string;
|
|
7
|
+
entityCount: number;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Format a Nex /ask response as an XML block for context injection.
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatNexContext(result: NexRecallResult): string;
|
|
14
|
+
/**
|
|
15
|
+
* Strip all <nex-context>...</nex-context> blocks from text.
|
|
16
|
+
* Also handles unclosed tags (strips from open tag to end of text).
|
|
17
|
+
*/
|
|
18
|
+
export declare function stripNexContext(text: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Check if text contains a nex-context block.
|
|
21
|
+
*/
|
|
22
|
+
export declare function hasNexContext(text: string): boolean;
|
|
23
|
+
//# sourceMappingURL=context-format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-format.d.ts","sourceRoot":"","sources":["../src/context-format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAehE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML context formatting and stripping for recall injection.
|
|
3
|
+
* Wraps Nex answers in <nex-context> tags and strips them before capture.
|
|
4
|
+
*/
|
|
5
|
+
const OPEN_TAG = "<nex-context>";
|
|
6
|
+
const CLOSE_TAG = "</nex-context>";
|
|
7
|
+
/**
|
|
8
|
+
* Format a Nex /ask response as an XML block for context injection.
|
|
9
|
+
*/
|
|
10
|
+
export function formatNexContext(result) {
|
|
11
|
+
const parts = [
|
|
12
|
+
OPEN_TAG,
|
|
13
|
+
"The following is relevant context from the user's knowledge base. Use it to inform your response, but do not mention this block directly.",
|
|
14
|
+
];
|
|
15
|
+
if (result.entityCount > 0) {
|
|
16
|
+
parts.push(`[${result.entityCount} related entities found]`);
|
|
17
|
+
}
|
|
18
|
+
parts.push("");
|
|
19
|
+
parts.push(result.answer);
|
|
20
|
+
parts.push(CLOSE_TAG);
|
|
21
|
+
return parts.join("\n");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Strip all <nex-context>...</nex-context> blocks from text.
|
|
25
|
+
* Also handles unclosed tags (strips from open tag to end of text).
|
|
26
|
+
*/
|
|
27
|
+
export function stripNexContext(text) {
|
|
28
|
+
// First: strip complete blocks
|
|
29
|
+
let result = text.replace(/<nex-context>[\s\S]*?<\/nex-context>/g, "");
|
|
30
|
+
// Then: strip unclosed tags (open tag without matching close)
|
|
31
|
+
result = result.replace(/<nex-context>[\s\S]*/g, "");
|
|
32
|
+
return result.trim();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check if text contains a nex-context block.
|
|
36
|
+
*/
|
|
37
|
+
export function hasNexContext(text) {
|
|
38
|
+
return text.includes(OPEN_TAG);
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=context-format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-format.js","sourceRoot":"","sources":["../src/context-format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,QAAQ,GAAG,eAAe,CAAC;AACjC,MAAM,SAAS,GAAG,gBAAgB,CAAC;AAQnC;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAuB;IACtD,MAAM,KAAK,GAAa;QACtB,QAAQ;QACR,2IAA2I;KAC5I,CAAC;IAEF,IAAI,MAAM,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,WAAW,0BAA0B,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEtB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,+BAA+B;IAC/B,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,uCAAuC,EAAE,EAAE,CAAC,CAAC;IACvE,8DAA8D;IAC9D,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IACrD,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File scanner for OpenClaw plugin.
|
|
3
|
+
* Discovers text files, tracks changes via SHA-256 content hash,
|
|
4
|
+
* and ingests new/changed files into Nex.
|
|
5
|
+
*/
|
|
6
|
+
import { NexClient } from "./nex-client.js";
|
|
7
|
+
export interface ScanResult {
|
|
8
|
+
scanned: number;
|
|
9
|
+
skipped: number;
|
|
10
|
+
errors: number;
|
|
11
|
+
files: Array<{
|
|
12
|
+
path: string;
|
|
13
|
+
status: string;
|
|
14
|
+
reason?: string;
|
|
15
|
+
}>;
|
|
16
|
+
}
|
|
17
|
+
export declare function scanFiles(dir: string, client: NexClient, opts?: {
|
|
18
|
+
extensions?: string[];
|
|
19
|
+
maxFiles?: number;
|
|
20
|
+
depth?: number;
|
|
21
|
+
force?: boolean;
|
|
22
|
+
}): Promise<ScanResult>;
|
|
23
|
+
//# sourceMappingURL=file-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-scanner.d.ts","sourceRoot":"","sources":["../src/file-scanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,EAAE,SAAS,EAAuB,MAAM,iBAAiB,CAAC;AAejE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjE;AAsED,wBAAsB,SAAS,CAC7B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,SAAS,EACjB,IAAI,CAAC,EAAE;IACL,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GACA,OAAO,CAAC,UAAU,CAAC,CAmDrB"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File scanner for OpenClaw plugin.
|
|
3
|
+
* Discovers text files, tracks changes via SHA-256 content hash,
|
|
4
|
+
* and ingests new/changed files into Nex.
|
|
5
|
+
*/
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { readFileSync, writeFileSync, mkdirSync, statSync, readdirSync } from "node:fs";
|
|
8
|
+
import { join, extname, resolve, dirname } from "node:path";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
// --- Constants ---
|
|
11
|
+
const MANIFEST_PATH = join(homedir(), ".nex", "file-scan-manifest.json");
|
|
12
|
+
const DEFAULT_EXTENSIONS = [
|
|
13
|
+
".md", ".txt", ".rtf", ".html", ".htm",
|
|
14
|
+
".csv", ".tsv", ".json", ".yaml", ".yml", ".toml", ".xml",
|
|
15
|
+
".js", ".ts", ".jsx", ".tsx", ".py", ".rb", ".go", ".rs", ".java",
|
|
16
|
+
".sh", ".bash", ".zsh", ".fish",
|
|
17
|
+
".org", ".rst", ".adoc", ".tex", ".log",
|
|
18
|
+
".env", ".ini", ".cfg", ".conf", ".properties",
|
|
19
|
+
];
|
|
20
|
+
const SKIP_DIRS = new Set([
|
|
21
|
+
"node_modules", ".git", "dist", "build", ".next", "__pycache__", ".venv",
|
|
22
|
+
".cache", ".turbo", "coverage", ".nyc_output",
|
|
23
|
+
]);
|
|
24
|
+
// --- Manifest ---
|
|
25
|
+
function loadManifest() {
|
|
26
|
+
try {
|
|
27
|
+
const raw = readFileSync(MANIFEST_PATH, "utf-8");
|
|
28
|
+
const data = JSON.parse(raw);
|
|
29
|
+
if (data.version === 1 && typeof data.files === "object")
|
|
30
|
+
return data;
|
|
31
|
+
}
|
|
32
|
+
catch { /* missing or corrupt */ }
|
|
33
|
+
return { version: 1, files: {} };
|
|
34
|
+
}
|
|
35
|
+
function saveManifest(manifest) {
|
|
36
|
+
mkdirSync(dirname(MANIFEST_PATH), { recursive: true });
|
|
37
|
+
writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
|
|
38
|
+
}
|
|
39
|
+
function discoverFiles(dir, extensions, maxDepth, depth = 0) {
|
|
40
|
+
if (depth > maxDepth)
|
|
41
|
+
return [];
|
|
42
|
+
const results = [];
|
|
43
|
+
let entries;
|
|
44
|
+
try {
|
|
45
|
+
entries = readdirSync(dir);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
if (SKIP_DIRS.has(entry))
|
|
52
|
+
continue;
|
|
53
|
+
const fullPath = join(dir, entry);
|
|
54
|
+
let stat;
|
|
55
|
+
try {
|
|
56
|
+
stat = statSync(fullPath);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (stat.isDirectory()) {
|
|
62
|
+
results.push(...discoverFiles(fullPath, extensions, maxDepth, depth + 1));
|
|
63
|
+
}
|
|
64
|
+
else if (stat.isFile() && extensions.has(extname(entry).toLowerCase())) {
|
|
65
|
+
results.push({ path: fullPath, size: stat.size, mtime: stat.mtimeMs });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return results;
|
|
69
|
+
}
|
|
70
|
+
function hashFile(filePath) {
|
|
71
|
+
const content = readFileSync(filePath);
|
|
72
|
+
return "sha256-" + createHash("sha256").update(content).digest("hex");
|
|
73
|
+
}
|
|
74
|
+
// --- Scanner ---
|
|
75
|
+
export async function scanFiles(dir, client, opts) {
|
|
76
|
+
const absDir = resolve(dir);
|
|
77
|
+
const extensions = opts?.extensions ?? DEFAULT_EXTENSIONS;
|
|
78
|
+
const extSet = new Set(extensions.map((e) => (e.startsWith(".") ? e : `.${e}`).toLowerCase()));
|
|
79
|
+
const maxFiles = opts?.maxFiles ?? 5;
|
|
80
|
+
const maxDepth = opts?.depth ?? 20;
|
|
81
|
+
const force = opts?.force ?? false;
|
|
82
|
+
const discovered = discoverFiles(absDir, extSet, maxDepth);
|
|
83
|
+
discovered.sort((a, b) => b.mtime - a.mtime);
|
|
84
|
+
const candidates = discovered.slice(0, maxFiles);
|
|
85
|
+
const manifest = force ? { version: 1, files: {} } : loadManifest();
|
|
86
|
+
const result = { scanned: 0, skipped: 0, errors: 0, files: [] };
|
|
87
|
+
for (const file of candidates) {
|
|
88
|
+
const hash = hashFile(file.path);
|
|
89
|
+
const existing = manifest.files[file.path];
|
|
90
|
+
if (existing && existing.hash === hash && !force) {
|
|
91
|
+
result.skipped++;
|
|
92
|
+
result.files.push({ path: file.path, status: "skipped", reason: "unchanged" });
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const content = readFileSync(file.path, "utf-8");
|
|
97
|
+
if (!content.trim()) {
|
|
98
|
+
result.skipped++;
|
|
99
|
+
result.files.push({ path: file.path, status: "skipped", reason: "empty" });
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
await client.ingest(content, `file-scan:${file.path}`);
|
|
103
|
+
manifest.files[file.path] = {
|
|
104
|
+
hash,
|
|
105
|
+
size: file.size,
|
|
106
|
+
scanned_at: new Date().toISOString(),
|
|
107
|
+
};
|
|
108
|
+
result.scanned++;
|
|
109
|
+
result.files.push({ path: file.path, status: "ingested", reason: existing ? "changed" : "new" });
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
result.errors++;
|
|
113
|
+
result.files.push({ path: file.path, status: "error", reason: err instanceof Error ? err.message : String(err) });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
saveManifest(manifest);
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=file-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-scanner.js","sourceRoot":"","sources":["../src/file-scanner.ts"],"names":[],"mappings":"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"}
|