@memtensor/memos-local-openclaw-plugin 1.0.4-beta.2 → 1.0.4-beta.20
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/.env.example +7 -0
- package/README.md +111 -44
- package/dist/capture/index.d.ts +1 -1
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +36 -2
- package/dist/capture/index.js.map +1 -1
- package/dist/client/connector.d.ts +6 -2
- package/dist/client/connector.d.ts.map +1 -1
- package/dist/client/connector.js +160 -26
- package/dist/client/connector.js.map +1 -1
- package/dist/client/hub.d.ts.map +1 -1
- package/dist/client/hub.js +22 -0
- package/dist/client/hub.js.map +1 -1
- package/dist/client/skill-sync.d.ts +7 -0
- package/dist/client/skill-sync.d.ts.map +1 -1
- package/dist/client/skill-sync.js +10 -0
- package/dist/client/skill-sync.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -3
- package/dist/config.js.map +1 -1
- package/dist/hub/server.d.ts +9 -0
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +500 -112
- package/dist/hub/server.js.map +1 -1
- package/dist/hub/user-manager.d.ts +11 -0
- package/dist/hub/user-manager.d.ts.map +1 -1
- package/dist/hub/user-manager.js +31 -3
- package/dist/hub/user-manager.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/ingest/chunker.d.ts +2 -1
- package/dist/ingest/chunker.d.ts.map +1 -1
- package/dist/ingest/chunker.js +14 -10
- package/dist/ingest/chunker.js.map +1 -1
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +37 -6
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/recall/engine.d.ts.map +1 -1
- package/dist/recall/engine.js +96 -1
- package/dist/recall/engine.js.map +1 -1
- package/dist/shared/llm-call.d.ts +1 -0
- package/dist/shared/llm-call.d.ts.map +1 -1
- package/dist/shared/llm-call.js +84 -9
- package/dist/shared/llm-call.js.map +1 -1
- package/dist/sharing/types.d.ts +1 -1
- package/dist/sharing/types.d.ts.map +1 -1
- package/dist/skill/evolver.d.ts +4 -0
- package/dist/skill/evolver.d.ts.map +1 -1
- package/dist/skill/evolver.js +59 -5
- package/dist/skill/evolver.js.map +1 -1
- package/dist/skill/generator.d.ts +2 -0
- package/dist/skill/generator.d.ts.map +1 -1
- package/dist/skill/generator.js +45 -3
- package/dist/skill/generator.js.map +1 -1
- package/dist/skill/installer.d.ts +26 -0
- package/dist/skill/installer.d.ts.map +1 -1
- package/dist/skill/installer.js +80 -4
- package/dist/skill/installer.js.map +1 -1
- package/dist/skill/upgrader.d.ts +2 -0
- package/dist/skill/upgrader.d.ts.map +1 -1
- package/dist/skill/upgrader.js +139 -1
- package/dist/skill/upgrader.js.map +1 -1
- package/dist/skill/validator.d.ts +3 -0
- package/dist/skill/validator.d.ts.map +1 -1
- package/dist/skill/validator.js +75 -0
- package/dist/skill/validator.js.map +1 -1
- package/dist/storage/ensure-binding.d.ts +12 -0
- package/dist/storage/ensure-binding.d.ts.map +1 -0
- package/dist/storage/ensure-binding.js +53 -0
- package/dist/storage/ensure-binding.js.map +1 -0
- package/dist/storage/sqlite.d.ts +115 -20
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +458 -110
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/telemetry.d.ts +12 -5
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +156 -40
- package/dist/telemetry.js.map +1 -1
- package/dist/tools/memory-search.d.ts +3 -1
- package/dist/tools/memory-search.d.ts.map +1 -1
- package/dist/tools/memory-search.js +3 -1
- package/dist/tools/memory-search.js.map +1 -1
- package/dist/types.d.ts +11 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +2952 -910
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +39 -8
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +1198 -227
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +774 -74
- package/openclaw.plugin.json +2 -2
- package/package.json +3 -2
- package/scripts/postinstall.cjs +1 -1
- package/skill/memos-memory-guide/SKILL.md +64 -26
- package/src/capture/index.ts +40 -1
- package/src/client/connector.ts +161 -28
- package/src/client/hub.ts +18 -0
- package/src/client/skill-sync.ts +14 -0
- package/src/config.ts +2 -3
- package/src/hub/server.ts +481 -107
- package/src/hub/user-manager.ts +48 -8
- package/src/index.ts +10 -2
- package/src/ingest/chunker.ts +19 -13
- package/src/ingest/providers/index.ts +41 -7
- package/src/recall/engine.ts +89 -1
- package/src/shared/llm-call.ts +99 -10
- package/src/sharing/types.ts +1 -1
- package/src/skill/evolver.ts +63 -6
- package/src/skill/generator.ts +44 -5
- package/src/skill/installer.ts +107 -4
- package/src/skill/upgrader.ts +139 -1
- package/src/skill/validator.ts +79 -0
- package/src/storage/ensure-binding.ts +52 -0
- package/src/storage/sqlite.ts +498 -137
- package/src/telemetry.ts +172 -41
- package/src/tools/memory-search.ts +2 -1
- package/src/types.ts +12 -2
- package/src/viewer/html.ts +2952 -910
- package/src/viewer/server.ts +1109 -212
package/src/telemetry.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Telemetry module — anonymous usage analytics via
|
|
2
|
+
* Telemetry module — anonymous usage analytics via Aliyun ARMS RUM.
|
|
3
3
|
*
|
|
4
4
|
* Privacy-first design:
|
|
5
5
|
* - Enabled by default with anonymous data only; opt-out via TELEMETRY_ENABLED=false
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
* - Only sends aggregate counts, tool names, latencies, and version info
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { PostHog } from "posthog-node";
|
|
12
11
|
import * as fs from "fs";
|
|
13
12
|
import * as path from "path";
|
|
14
13
|
import * as os from "os";
|
|
@@ -17,45 +16,79 @@ import type { Logger } from "./types";
|
|
|
17
16
|
|
|
18
17
|
export interface TelemetryConfig {
|
|
19
18
|
enabled?: boolean;
|
|
20
|
-
posthogApiKey?: string;
|
|
21
|
-
posthogHost?: string;
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
function loadTelemetryCredentials(): { endpoint: string; pid: string; env: string } {
|
|
22
|
+
if (process.env.MEMOS_ARMS_ENDPOINT) {
|
|
23
|
+
return {
|
|
24
|
+
endpoint: process.env.MEMOS_ARMS_ENDPOINT,
|
|
25
|
+
pid: process.env.MEMOS_ARMS_PID ?? "",
|
|
26
|
+
env: process.env.MEMOS_ARMS_ENV ?? "prod",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const credPath = path.resolve(__dirname, "..", "telemetry.credentials.json");
|
|
31
|
+
const raw = fs.readFileSync(credPath, "utf-8");
|
|
32
|
+
const creds = JSON.parse(raw);
|
|
33
|
+
if (creds.endpoint) return { endpoint: creds.endpoint, pid: creds.pid ?? "", env: creds.env ?? "prod" };
|
|
34
|
+
} catch {}
|
|
35
|
+
return { endpoint: "", pid: "", env: "prod" };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const _creds = loadTelemetryCredentials();
|
|
39
|
+
const ARMS_ENDPOINT = _creds.endpoint;
|
|
40
|
+
const ARMS_PID = _creds.pid;
|
|
41
|
+
const ARMS_ENV = _creds.env;
|
|
42
|
+
|
|
43
|
+
const FLUSH_AT = 10;
|
|
44
|
+
const FLUSH_INTERVAL_MS = 30_000;
|
|
45
|
+
const SEND_TIMEOUT_MS = 30_000;
|
|
46
|
+
const SESSION_TTL_MS = 30 * 60_000; // 30 min inactivity → new session
|
|
47
|
+
interface ArmsEvent {
|
|
48
|
+
event_type: "custom";
|
|
49
|
+
type: string;
|
|
50
|
+
name: string;
|
|
51
|
+
group: string;
|
|
52
|
+
value: number;
|
|
53
|
+
properties: Record<string, string | number | boolean>;
|
|
54
|
+
timestamp: number;
|
|
55
|
+
event_id: string;
|
|
56
|
+
times: number;
|
|
57
|
+
}
|
|
26
58
|
|
|
27
59
|
export class Telemetry {
|
|
28
|
-
private client: PostHog | null = null;
|
|
29
60
|
private distinctId: string;
|
|
30
61
|
private enabled: boolean;
|
|
31
62
|
private pluginVersion: string;
|
|
32
63
|
private log: Logger;
|
|
33
64
|
private dailyPingSent = false;
|
|
34
65
|
private dailyPingDate = "";
|
|
66
|
+
private buffer: ArmsEvent[] = [];
|
|
67
|
+
private flushTimer: ReturnType<typeof setInterval> | null = null;
|
|
68
|
+
private sessionId: string;
|
|
69
|
+
private firstSeenDate: string;
|
|
35
70
|
|
|
36
71
|
constructor(config: TelemetryConfig, stateDir: string, pluginVersion: string, log: Logger) {
|
|
37
72
|
this.log = log;
|
|
38
73
|
this.pluginVersion = pluginVersion;
|
|
39
74
|
this.enabled = config.enabled !== false;
|
|
40
75
|
this.distinctId = this.loadOrCreateAnonymousId(stateDir);
|
|
76
|
+
this.firstSeenDate = this.loadOrCreateFirstSeen(stateDir);
|
|
77
|
+
this.sessionId = this.loadOrCreateSessionId(stateDir);
|
|
41
78
|
|
|
42
|
-
if (!this.enabled) {
|
|
43
|
-
this.
|
|
79
|
+
if (!this.enabled || !ARMS_ENDPOINT) {
|
|
80
|
+
this.enabled = false;
|
|
81
|
+
this.log.debug(
|
|
82
|
+
!ARMS_ENDPOINT
|
|
83
|
+
? "Telemetry disabled (no credentials configured)"
|
|
84
|
+
: "Telemetry disabled (opt-out)",
|
|
85
|
+
);
|
|
44
86
|
return;
|
|
45
87
|
}
|
|
46
88
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
host: config.posthogHost || DEFAULT_POSTHOG_HOST,
|
|
51
|
-
flushAt: 10,
|
|
52
|
-
flushInterval: 30_000,
|
|
53
|
-
});
|
|
54
|
-
this.log.debug("Telemetry initialized (PostHog)");
|
|
55
|
-
} catch (err) {
|
|
56
|
-
this.log.warn(`Telemetry init failed: ${err}`);
|
|
57
|
-
this.enabled = false;
|
|
58
|
-
}
|
|
89
|
+
this.flushTimer = setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
|
|
90
|
+
if (this.flushTimer.unref) this.flushTimer.unref();
|
|
91
|
+
this.log.debug("Telemetry initialized (ARMS)");
|
|
59
92
|
}
|
|
60
93
|
|
|
61
94
|
private loadOrCreateAnonymousId(stateDir: string): string {
|
|
@@ -81,24 +114,113 @@ export class Telemetry {
|
|
|
81
114
|
return newId;
|
|
82
115
|
}
|
|
83
116
|
|
|
117
|
+
private loadOrCreateSessionId(stateDir: string): string {
|
|
118
|
+
const filePath = path.join(stateDir, "memos-local", ".session");
|
|
119
|
+
try {
|
|
120
|
+
const raw = fs.readFileSync(filePath, "utf-8").trim();
|
|
121
|
+
const sep = raw.indexOf("|");
|
|
122
|
+
if (sep > 0) {
|
|
123
|
+
const ts = parseInt(raw.slice(0, sep), 10);
|
|
124
|
+
const id = raw.slice(sep + 1);
|
|
125
|
+
if (id.length > 10 && Date.now() - ts < SESSION_TTL_MS) {
|
|
126
|
+
this.touchSession(filePath, id);
|
|
127
|
+
return id;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
} catch {}
|
|
131
|
+
const newId = uuidv4();
|
|
132
|
+
this.touchSession(filePath, newId);
|
|
133
|
+
return newId;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
private touchSession(filePath: string, id: string): void {
|
|
137
|
+
try {
|
|
138
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
139
|
+
fs.writeFileSync(filePath, `${Date.now()}|${id}`, "utf-8");
|
|
140
|
+
} catch {}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private loadOrCreateFirstSeen(stateDir: string): string {
|
|
144
|
+
const filePath = path.join(stateDir, "memos-local", ".first-seen");
|
|
145
|
+
try {
|
|
146
|
+
const existing = fs.readFileSync(filePath, "utf-8").trim();
|
|
147
|
+
if (existing.length === 10) return existing;
|
|
148
|
+
} catch {}
|
|
149
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
150
|
+
try {
|
|
151
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
152
|
+
fs.writeFileSync(filePath, today, "utf-8");
|
|
153
|
+
} catch {}
|
|
154
|
+
return today;
|
|
155
|
+
}
|
|
156
|
+
|
|
84
157
|
private capture(event: string, properties?: Record<string, unknown>): void {
|
|
85
|
-
if (!this.enabled
|
|
158
|
+
if (!this.enabled) return;
|
|
159
|
+
|
|
160
|
+
const safeProps: Record<string, string | number | boolean> = {
|
|
161
|
+
plugin_version: this.pluginVersion,
|
|
162
|
+
os: os.platform(),
|
|
163
|
+
os_version: os.release(),
|
|
164
|
+
node_version: process.version,
|
|
165
|
+
arch: os.arch(),
|
|
166
|
+
};
|
|
167
|
+
if (properties) {
|
|
168
|
+
for (const [k, v] of Object.entries(properties)) {
|
|
169
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") {
|
|
170
|
+
safeProps[k] = v;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
this.buffer.push({
|
|
176
|
+
event_type: "custom",
|
|
177
|
+
type: "memos_plugin",
|
|
178
|
+
name: event,
|
|
179
|
+
group: "memos_local",
|
|
180
|
+
value: 1,
|
|
181
|
+
properties: safeProps,
|
|
182
|
+
timestamp: Date.now(),
|
|
183
|
+
event_id: uuidv4(),
|
|
184
|
+
times: 1,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
if (this.buffer.length >= FLUSH_AT) {
|
|
188
|
+
this.flush();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private buildPayload(events: ArmsEvent[]): Record<string, unknown> {
|
|
193
|
+
return {
|
|
194
|
+
app: {
|
|
195
|
+
id: ARMS_PID,
|
|
196
|
+
env: ARMS_ENV,
|
|
197
|
+
version: this.pluginVersion,
|
|
198
|
+
type: "node",
|
|
199
|
+
},
|
|
200
|
+
user: { id: this.distinctId },
|
|
201
|
+
session: { id: this.sessionId },
|
|
202
|
+
net: {},
|
|
203
|
+
view: { id: "plugin", name: "memos-local-openclaw" },
|
|
204
|
+
events,
|
|
205
|
+
_v: "1.0.0",
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private async flush(): Promise<void> {
|
|
210
|
+
if (this.buffer.length === 0) return;
|
|
211
|
+
const batch = this.buffer.splice(0);
|
|
212
|
+
const payload = this.buildPayload(batch);
|
|
86
213
|
|
|
87
214
|
try {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
os: os.platform(),
|
|
94
|
-
os_version: os.release(),
|
|
95
|
-
node_version: process.version,
|
|
96
|
-
arch: os.arch(),
|
|
97
|
-
...properties,
|
|
98
|
-
},
|
|
215
|
+
const resp = await fetch(ARMS_ENDPOINT, {
|
|
216
|
+
method: "POST",
|
|
217
|
+
headers: { "Content-Type": "text/plain" },
|
|
218
|
+
body: JSON.stringify(payload),
|
|
219
|
+
signal: AbortSignal.timeout(SEND_TIMEOUT_MS),
|
|
99
220
|
});
|
|
100
|
-
|
|
101
|
-
|
|
221
|
+
this.log.debug(`Telemetry flush: ${batch.length} events → ${resp.status}`);
|
|
222
|
+
} catch (err) {
|
|
223
|
+
this.log.debug(`Telemetry flush failed: ${err}`);
|
|
102
224
|
}
|
|
103
225
|
}
|
|
104
226
|
|
|
@@ -131,7 +253,7 @@ export class Telemetry {
|
|
|
131
253
|
});
|
|
132
254
|
}
|
|
133
255
|
|
|
134
|
-
trackSkillEvolved(skillName: string, upgradeType:
|
|
256
|
+
trackSkillEvolved(skillName: string, upgradeType: "created" | "upgraded"): void {
|
|
135
257
|
this.capture("skill_evolved", {
|
|
136
258
|
skill_name: skillName,
|
|
137
259
|
upgrade_type: upgradeType,
|
|
@@ -150,19 +272,28 @@ export class Telemetry {
|
|
|
150
272
|
});
|
|
151
273
|
}
|
|
152
274
|
|
|
275
|
+
trackError(source: string, errorType: string): void {
|
|
276
|
+
this.capture("plugin_error", {
|
|
277
|
+
error_source: source,
|
|
278
|
+
error_type: errorType,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
153
282
|
private maybeSendDailyPing(): void {
|
|
154
283
|
const today = new Date().toISOString().slice(0, 10);
|
|
155
284
|
if (this.dailyPingSent && this.dailyPingDate === today) return;
|
|
156
285
|
this.dailyPingSent = true;
|
|
157
286
|
this.dailyPingDate = today;
|
|
158
|
-
this.capture("daily_active"
|
|
287
|
+
this.capture("daily_active", {
|
|
288
|
+
first_seen_date: this.firstSeenDate,
|
|
289
|
+
});
|
|
159
290
|
}
|
|
160
291
|
|
|
161
292
|
async shutdown(): Promise<void> {
|
|
162
|
-
if (this.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
} catch {}
|
|
293
|
+
if (this.flushTimer) {
|
|
294
|
+
clearInterval(this.flushTimer);
|
|
295
|
+
this.flushTimer = null;
|
|
166
296
|
}
|
|
297
|
+
await this.flush();
|
|
167
298
|
}
|
|
168
299
|
}
|
|
@@ -24,7 +24,7 @@ function emptyHubResult(scope: HubScope): HubSearchResult {
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function createMemorySearchTool(engine: RecallEngine, store?: SqliteStore, ctx?: PluginContext): ToolDefinition {
|
|
27
|
+
export function createMemorySearchTool(engine: RecallEngine, store?: SqliteStore, ctx?: PluginContext, sharedState?: { lastSearchTime: number }): ToolDefinition {
|
|
28
28
|
return {
|
|
29
29
|
name: "memory_search",
|
|
30
30
|
description:
|
|
@@ -60,6 +60,7 @@ export function createMemorySearchTool(engine: RecallEngine, store?: SqliteStore
|
|
|
60
60
|
},
|
|
61
61
|
},
|
|
62
62
|
handler: async (input) => {
|
|
63
|
+
if (sharedState) sharedState.lastSearchTime = Date.now();
|
|
63
64
|
const query = (input.query as string) ?? "";
|
|
64
65
|
const maxResults = input.maxResults as number | undefined;
|
|
65
66
|
const minScore = input.minScore as number | undefined;
|
package/src/types.ts
CHANGED
|
@@ -66,6 +66,8 @@ export interface ChunkRef {
|
|
|
66
66
|
|
|
67
67
|
// ─── Search / Recall ───
|
|
68
68
|
|
|
69
|
+
export type SearchHitOrigin = "local" | "local-shared" | "hub-memory" | "hub-remote";
|
|
70
|
+
|
|
69
71
|
export interface SearchHit {
|
|
70
72
|
summary: string;
|
|
71
73
|
original_excerpt: string;
|
|
@@ -74,6 +76,7 @@ export interface SearchHit {
|
|
|
74
76
|
taskId: string | null;
|
|
75
77
|
skillId: string | null;
|
|
76
78
|
owner?: string;
|
|
79
|
+
origin?: SearchHitOrigin;
|
|
77
80
|
source: {
|
|
78
81
|
ts: number;
|
|
79
82
|
role: Role;
|
|
@@ -249,14 +252,16 @@ export interface SkillEvolutionConfig {
|
|
|
249
252
|
minConfidence?: number;
|
|
250
253
|
maxSkillLines?: number;
|
|
251
254
|
autoInstall?: boolean;
|
|
255
|
+
autoRecallSkills?: boolean;
|
|
256
|
+
autoRecallSkillLimit?: number;
|
|
257
|
+
preferUpgradeExisting?: boolean;
|
|
258
|
+
redactSensitiveInSkill?: boolean;
|
|
252
259
|
/** Optional independent LLM config for skill evaluation/validation. Falls back to main summarizer if not set. */
|
|
253
260
|
summarizer?: SummarizerConfig;
|
|
254
261
|
}
|
|
255
262
|
|
|
256
263
|
export interface TelemetryConfig {
|
|
257
264
|
enabled?: boolean;
|
|
258
|
-
posthogApiKey?: string;
|
|
259
|
-
posthogHost?: string;
|
|
260
265
|
}
|
|
261
266
|
|
|
262
267
|
export type SharingRole = "hub" | "client";
|
|
@@ -277,6 +282,7 @@ export interface ClientModeConfig {
|
|
|
277
282
|
hubAddress?: string;
|
|
278
283
|
userToken?: string;
|
|
279
284
|
teamToken?: string;
|
|
285
|
+
nickname?: string;
|
|
280
286
|
pendingUserId?: string;
|
|
281
287
|
}
|
|
282
288
|
|
|
@@ -345,6 +351,10 @@ export const DEFAULTS = {
|
|
|
345
351
|
skillMinConfidence: 0.7,
|
|
346
352
|
skillMaxLines: 400,
|
|
347
353
|
skillAutoInstall: false,
|
|
354
|
+
skillAutoRecall: true,
|
|
355
|
+
skillAutoRecallLimit: 2,
|
|
356
|
+
skillPreferUpgrade: true,
|
|
357
|
+
skillRedactSensitive: true,
|
|
348
358
|
} as const;
|
|
349
359
|
|
|
350
360
|
// ─── Plugin Hooks (OpenClaw integration) ───
|