@hyperspell/openclaw-hyperspell 0.12.0 → 0.13.1
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/README.md +37 -1
- package/dist/client.js +341 -0
- package/dist/commands/setup.js +568 -0
- package/dist/commands/slash.js +159 -0
- package/dist/config.js +349 -0
- package/{graph/cron.ts → dist/graph/cron.js} +11 -15
- package/dist/graph/index.js +4 -0
- package/dist/graph/ops.js +221 -0
- package/dist/graph/state.js +68 -0
- package/dist/graph/tools.js +87 -0
- package/dist/hooks/auto-context.js +199 -0
- package/dist/hooks/auto-trace.js +143 -0
- package/dist/hooks/emotional-state.js +155 -0
- package/dist/hooks/memory-sync.js +54 -0
- package/dist/hooks/startup-orientation.js +236 -0
- package/dist/index.js +132 -0
- package/dist/lib/browser.js +29 -0
- package/dist/lib/sender.js +173 -0
- package/dist/lib/voice-id.js +22 -0
- package/dist/logger.js +32 -0
- package/dist/sync/markdown.js +151 -0
- package/dist/tools/remember.js +97 -0
- package/dist/tools/search.js +87 -0
- package/openclaw.plugin.json +25 -1
- package/package.json +7 -12
- package/client.ts +0 -566
- package/commands/setup.ts +0 -673
- package/commands/slash.ts +0 -198
- package/config.test.ts +0 -202
- package/config.ts +0 -497
- package/graph/index.ts +0 -5
- package/graph/ops.ts +0 -259
- package/graph/state.ts +0 -79
- package/graph/tools.ts +0 -117
- package/hooks/auto-context.ts +0 -272
- package/hooks/auto-trace.test.ts +0 -81
- package/hooks/auto-trace.ts +0 -197
- package/hooks/emotional-state.test.ts +0 -160
- package/hooks/emotional-state.ts +0 -179
- package/hooks/memory-sync.ts +0 -65
- package/index.ts +0 -152
- package/lib/browser.ts +0 -31
- package/lib/sender.test.ts +0 -234
- package/lib/sender.ts +0 -234
- package/lib/voice-id.ts +0 -39
- package/logger.ts +0 -41
- package/sync/markdown.ts +0 -186
- package/tools/remember.ts +0 -132
- package/tools/search.ts +0 -131
- package/types/openclaw.d.ts +0 -76
package/config.ts
DELETED
|
@@ -1,497 +0,0 @@
|
|
|
1
|
-
export type HyperspellSource =
|
|
2
|
-
| "reddit"
|
|
3
|
-
| "notion"
|
|
4
|
-
| "slack"
|
|
5
|
-
| "google_calendar"
|
|
6
|
-
| "google_mail"
|
|
7
|
-
| "box"
|
|
8
|
-
| "google_drive"
|
|
9
|
-
| "vault"
|
|
10
|
-
| "web_crawler"
|
|
11
|
-
| "dropbox"
|
|
12
|
-
| "github"
|
|
13
|
-
| "trace"
|
|
14
|
-
| "microsoft_teams";
|
|
15
|
-
|
|
16
|
-
export type KnowledgeGraphConfig = {
|
|
17
|
-
enabled: boolean;
|
|
18
|
-
scanIntervalMinutes: number;
|
|
19
|
-
batchSize: number;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export type AutoTraceConfig = {
|
|
23
|
-
enabled: boolean;
|
|
24
|
-
extract: Array<"procedure" | "memory" | "mood">;
|
|
25
|
-
metadata?: Record<string, string | number | boolean>;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export type UserProfile = {
|
|
29
|
-
userId: string;
|
|
30
|
-
name: string;
|
|
31
|
-
context?: string;
|
|
32
|
-
role?: string;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export type ScopeName = string;
|
|
36
|
-
export type CanReadScope = ScopeName | "*" | "self";
|
|
37
|
-
|
|
38
|
-
export type Role = {
|
|
39
|
-
canRead: CanReadScope[];
|
|
40
|
-
defaultWriteScope: ScopeName;
|
|
41
|
-
canWriteScopes?: ScopeName[];
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export type VoiceIdConfig = {
|
|
45
|
-
enabled: boolean;
|
|
46
|
-
adapter?: string;
|
|
47
|
-
confidenceThreshold?: number;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export type ScopingConfig = {
|
|
51
|
-
enabled: boolean;
|
|
52
|
-
defaultScope: ScopeName;
|
|
53
|
-
scopes: ScopeName[];
|
|
54
|
-
roles: Record<string, Role>;
|
|
55
|
-
users: Record<string, { role: string }>;
|
|
56
|
-
collections?: Record<ScopeName, string>;
|
|
57
|
-
voiceId?: VoiceIdConfig;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export type MultiUserConfig = {
|
|
61
|
-
senderMap: Record<string, UserProfile>;
|
|
62
|
-
sharedUserId: string;
|
|
63
|
-
includeSharedInSearch: boolean;
|
|
64
|
-
scoping?: ScopingConfig;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Convert user-facing scope names (which may contain hyphens) to SDK-safe
|
|
69
|
-
* metadata values (alphanumeric + underscore only). Must be applied at every
|
|
70
|
-
* boundary where scopes cross into Hyperspell metadata — writes and reads —
|
|
71
|
-
* or filters will silently miss.
|
|
72
|
-
*/
|
|
73
|
-
export function normalizeScope(scope: ScopeName): string {
|
|
74
|
-
return scope.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export type HyperspellConfig = {
|
|
78
|
-
apiKey: string;
|
|
79
|
-
userId?: string;
|
|
80
|
-
autoContext: boolean;
|
|
81
|
-
autoTrace: AutoTraceConfig;
|
|
82
|
-
emotionalContext: boolean;
|
|
83
|
-
relationshipId?: string;
|
|
84
|
-
syncMemories: boolean;
|
|
85
|
-
sources: HyperspellSource[];
|
|
86
|
-
maxResults: number;
|
|
87
|
-
relevanceThreshold: number;
|
|
88
|
-
debug: boolean;
|
|
89
|
-
knowledgeGraph: KnowledgeGraphConfig;
|
|
90
|
-
multiUser?: MultiUserConfig;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const ALLOWED_KEYS = [
|
|
94
|
-
"apiKey",
|
|
95
|
-
"userId",
|
|
96
|
-
"autoContext",
|
|
97
|
-
"autoTrace",
|
|
98
|
-
"emotionalContext",
|
|
99
|
-
"relationshipId",
|
|
100
|
-
"syncMemories",
|
|
101
|
-
"sources",
|
|
102
|
-
"maxResults",
|
|
103
|
-
"relevanceThreshold",
|
|
104
|
-
"debug",
|
|
105
|
-
"knowledgeGraph",
|
|
106
|
-
"multiUser",
|
|
107
|
-
];
|
|
108
|
-
|
|
109
|
-
const VALID_SOURCES: HyperspellSource[] = [
|
|
110
|
-
"reddit",
|
|
111
|
-
"notion",
|
|
112
|
-
"slack",
|
|
113
|
-
"google_calendar",
|
|
114
|
-
"google_mail",
|
|
115
|
-
"box",
|
|
116
|
-
"google_drive",
|
|
117
|
-
"vault",
|
|
118
|
-
"web_crawler",
|
|
119
|
-
"dropbox",
|
|
120
|
-
"github",
|
|
121
|
-
"trace",
|
|
122
|
-
"microsoft_teams",
|
|
123
|
-
];
|
|
124
|
-
|
|
125
|
-
function assertAllowedKeys(
|
|
126
|
-
value: Record<string, unknown>,
|
|
127
|
-
allowed: string[],
|
|
128
|
-
label: string,
|
|
129
|
-
): void {
|
|
130
|
-
const unknown = Object.keys(value).filter((k) => !allowed.includes(k));
|
|
131
|
-
if (unknown.length > 0) {
|
|
132
|
-
throw new Error(`${label} has unknown keys: ${unknown.join(", ")}`);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function resolveEnvVars(value: string): string {
|
|
137
|
-
return value.replace(/\$\{([^}]+)\}/g, (_, envVar: string) => {
|
|
138
|
-
const envValue = process.env[envVar];
|
|
139
|
-
if (!envValue) {
|
|
140
|
-
throw new Error(`Environment variable ${envVar} is not set`);
|
|
141
|
-
}
|
|
142
|
-
return envValue;
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function parseSources(raw: string | string[] | undefined): HyperspellSource[] {
|
|
147
|
-
if (!raw) {
|
|
148
|
-
return [];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Handle array input
|
|
152
|
-
if (Array.isArray(raw)) {
|
|
153
|
-
const sources = raw
|
|
154
|
-
.map((s) => String(s).trim().toLowerCase())
|
|
155
|
-
.filter((s) => s.length > 0) as HyperspellSource[];
|
|
156
|
-
|
|
157
|
-
for (const source of sources) {
|
|
158
|
-
if (!VALID_SOURCES.includes(source)) {
|
|
159
|
-
throw new Error(
|
|
160
|
-
`Invalid source "${source}". Valid sources: ${VALID_SOURCES.join(", ")}`,
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return sources;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Handle string input (comma-separated)
|
|
169
|
-
if (typeof raw === "string" && raw.trim() === "") {
|
|
170
|
-
return [];
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const sources = raw
|
|
174
|
-
.split(",")
|
|
175
|
-
.map((s) => s.trim().toLowerCase())
|
|
176
|
-
.filter((s) => s.length > 0) as HyperspellSource[];
|
|
177
|
-
|
|
178
|
-
for (const source of sources) {
|
|
179
|
-
if (!VALID_SOURCES.includes(source)) {
|
|
180
|
-
throw new Error(
|
|
181
|
-
`Invalid source "${source}". Valid sources: ${VALID_SOURCES.join(", ")}`,
|
|
182
|
-
);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return sources;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function parseScoping(raw: unknown): ScopingConfig | undefined {
|
|
190
|
-
if (!raw || typeof raw !== "object") return undefined;
|
|
191
|
-
const sc = raw as Record<string, unknown>;
|
|
192
|
-
|
|
193
|
-
if (sc.enabled !== true) return undefined;
|
|
194
|
-
|
|
195
|
-
const scopes = Array.isArray(sc.scopes)
|
|
196
|
-
? (sc.scopes.filter((s) => typeof s === "string") as ScopeName[])
|
|
197
|
-
: [];
|
|
198
|
-
if (scopes.length === 0) {
|
|
199
|
-
throw new Error("scoping.scopes must be a non-empty array of scope names");
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const defaultScope =
|
|
203
|
-
typeof sc.defaultScope === "string" ? sc.defaultScope : "private";
|
|
204
|
-
if (!scopes.includes(defaultScope)) {
|
|
205
|
-
throw new Error(
|
|
206
|
-
`scoping.defaultScope "${defaultScope}" must be one of scopes: ${scopes.join(", ")}`,
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const rolesRaw =
|
|
211
|
-
sc.roles && typeof sc.roles === "object"
|
|
212
|
-
? (sc.roles as Record<string, unknown>)
|
|
213
|
-
: {};
|
|
214
|
-
const roles: Record<string, Role> = {};
|
|
215
|
-
for (const [roleName, rRaw] of Object.entries(rolesRaw)) {
|
|
216
|
-
if (!rRaw || typeof rRaw !== "object") continue;
|
|
217
|
-
const r = rRaw as Record<string, unknown>;
|
|
218
|
-
|
|
219
|
-
const canRead = Array.isArray(r.canRead)
|
|
220
|
-
? (r.canRead.filter((s) => typeof s === "string") as CanReadScope[])
|
|
221
|
-
: [];
|
|
222
|
-
for (const s of canRead) {
|
|
223
|
-
if (s === "*" || s === "self") continue;
|
|
224
|
-
if (!scopes.includes(s)) {
|
|
225
|
-
throw new Error(
|
|
226
|
-
`scoping.roles.${roleName}.canRead contains unknown scope "${s}"`,
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const defaultWriteScope =
|
|
232
|
-
typeof r.defaultWriteScope === "string"
|
|
233
|
-
? r.defaultWriteScope
|
|
234
|
-
: defaultScope;
|
|
235
|
-
if (!scopes.includes(defaultWriteScope)) {
|
|
236
|
-
throw new Error(
|
|
237
|
-
`scoping.roles.${roleName}.defaultWriteScope "${defaultWriteScope}" must be one of scopes: ${scopes.join(", ")}`,
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
let canWriteScopes: ScopeName[] | undefined;
|
|
242
|
-
if (Array.isArray(r.canWriteScopes)) {
|
|
243
|
-
canWriteScopes = r.canWriteScopes.filter(
|
|
244
|
-
(s): s is ScopeName => typeof s === "string",
|
|
245
|
-
);
|
|
246
|
-
for (const s of canWriteScopes) {
|
|
247
|
-
if (!scopes.includes(s)) {
|
|
248
|
-
throw new Error(
|
|
249
|
-
`scoping.roles.${roleName}.canWriteScopes contains unknown scope "${s}"`,
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
roles[roleName] = { canRead, defaultWriteScope, canWriteScopes };
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const usersRaw =
|
|
259
|
-
sc.users && typeof sc.users === "object"
|
|
260
|
-
? (sc.users as Record<string, unknown>)
|
|
261
|
-
: {};
|
|
262
|
-
const users: Record<string, { role: string }> = {};
|
|
263
|
-
for (const [uid, uRaw] of Object.entries(usersRaw)) {
|
|
264
|
-
if (!uRaw || typeof uRaw !== "object") continue;
|
|
265
|
-
const u = uRaw as Record<string, unknown>;
|
|
266
|
-
if (typeof u.role !== "string") continue;
|
|
267
|
-
if (!roles[u.role]) {
|
|
268
|
-
throw new Error(
|
|
269
|
-
`scoping.users.${uid}.role "${u.role}" does not key into scoping.roles`,
|
|
270
|
-
);
|
|
271
|
-
}
|
|
272
|
-
users[uid] = { role: u.role };
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const collectionsRaw =
|
|
276
|
-
sc.collections && typeof sc.collections === "object"
|
|
277
|
-
? (sc.collections as Record<string, unknown>)
|
|
278
|
-
: undefined;
|
|
279
|
-
let collections: Record<ScopeName, string> | undefined;
|
|
280
|
-
if (collectionsRaw) {
|
|
281
|
-
collections = {};
|
|
282
|
-
for (const [scopeName, coll] of Object.entries(collectionsRaw)) {
|
|
283
|
-
if (typeof coll === "string" && scopes.includes(scopeName)) {
|
|
284
|
-
collections[scopeName] = coll;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
let voiceId: VoiceIdConfig | undefined;
|
|
290
|
-
if (sc.voiceId && typeof sc.voiceId === "object") {
|
|
291
|
-
const v = sc.voiceId as Record<string, unknown>;
|
|
292
|
-
voiceId = {
|
|
293
|
-
enabled: v.enabled === true,
|
|
294
|
-
adapter: typeof v.adapter === "string" ? v.adapter : undefined,
|
|
295
|
-
confidenceThreshold:
|
|
296
|
-
typeof v.confidenceThreshold === "number"
|
|
297
|
-
? v.confidenceThreshold
|
|
298
|
-
: undefined,
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
return {
|
|
303
|
-
enabled: true,
|
|
304
|
-
defaultScope,
|
|
305
|
-
scopes,
|
|
306
|
-
roles,
|
|
307
|
-
users,
|
|
308
|
-
collections,
|
|
309
|
-
voiceId,
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function parseMultiUser(raw: unknown): MultiUserConfig | undefined {
|
|
314
|
-
if (!raw || typeof raw !== "object") return undefined;
|
|
315
|
-
const mu = raw as Record<string, unknown>;
|
|
316
|
-
|
|
317
|
-
const senderMap: Record<string, UserProfile> = {};
|
|
318
|
-
const rawMap = mu.senderMap as Record<string, unknown> | undefined;
|
|
319
|
-
if (rawMap && typeof rawMap === "object") {
|
|
320
|
-
for (const [handle, profile] of Object.entries(rawMap)) {
|
|
321
|
-
if (profile && typeof profile === "object") {
|
|
322
|
-
const p = profile as Record<string, unknown>;
|
|
323
|
-
if (typeof p.userId === "string" && typeof p.name === "string") {
|
|
324
|
-
senderMap[handle] = {
|
|
325
|
-
userId: p.userId,
|
|
326
|
-
name: p.name,
|
|
327
|
-
context: typeof p.context === "string" ? p.context : undefined,
|
|
328
|
-
role: typeof p.role === "string" ? p.role : undefined,
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
if (Object.keys(senderMap).length === 0) return undefined;
|
|
336
|
-
|
|
337
|
-
return {
|
|
338
|
-
senderMap,
|
|
339
|
-
sharedUserId:
|
|
340
|
-
typeof mu.sharedUserId === "string" ? mu.sharedUserId : "shared",
|
|
341
|
-
includeSharedInSearch:
|
|
342
|
-
typeof mu.includeSharedInSearch === "boolean"
|
|
343
|
-
? mu.includeSharedInSearch
|
|
344
|
-
: true,
|
|
345
|
-
scoping: parseScoping(mu.scoping),
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export function parseConfig(raw: unknown): HyperspellConfig {
|
|
350
|
-
const cfg =
|
|
351
|
-
raw && typeof raw === "object" && !Array.isArray(raw)
|
|
352
|
-
? (raw as Record<string, unknown>)
|
|
353
|
-
: {};
|
|
354
|
-
|
|
355
|
-
if (Object.keys(cfg).length > 0) {
|
|
356
|
-
assertAllowedKeys(cfg, ALLOWED_KEYS, "hyperspell config");
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const apiKey =
|
|
360
|
-
typeof cfg.apiKey === "string" && cfg.apiKey.length > 0
|
|
361
|
-
? resolveEnvVars(cfg.apiKey)
|
|
362
|
-
: process.env.HYPERSPELL_API_KEY;
|
|
363
|
-
|
|
364
|
-
if (!apiKey) {
|
|
365
|
-
throw new Error(
|
|
366
|
-
"hyperspell: apiKey is required (set in plugin config or HYPERSPELL_API_KEY env var)",
|
|
367
|
-
);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const kgRaw = (cfg.knowledgeGraph ?? {}) as Record<string, unknown>;
|
|
371
|
-
const atRaw = (cfg.autoTrace ?? {}) as Record<string, unknown>;
|
|
372
|
-
|
|
373
|
-
return {
|
|
374
|
-
apiKey,
|
|
375
|
-
userId: cfg.userId as string | undefined,
|
|
376
|
-
autoContext: (cfg.autoContext as boolean) ?? true,
|
|
377
|
-
autoTrace: {
|
|
378
|
-
enabled: (atRaw.enabled as boolean) ?? false,
|
|
379
|
-
extract: (atRaw.extract as Array<"procedure" | "memory" | "mood">) ?? [
|
|
380
|
-
"procedure",
|
|
381
|
-
],
|
|
382
|
-
metadata: atRaw.metadata as
|
|
383
|
-
| Record<string, string | number | boolean>
|
|
384
|
-
| undefined,
|
|
385
|
-
},
|
|
386
|
-
emotionalContext: (cfg.emotionalContext as boolean) ?? false,
|
|
387
|
-
relationshipId: cfg.relationshipId as string | undefined,
|
|
388
|
-
syncMemories: (cfg.syncMemories as boolean) ?? false,
|
|
389
|
-
sources: parseSources(cfg.sources as string | string[] | undefined),
|
|
390
|
-
maxResults: (cfg.maxResults as number) ?? 10,
|
|
391
|
-
relevanceThreshold: (cfg.relevanceThreshold as number) ?? 0.6,
|
|
392
|
-
debug: (cfg.debug as boolean) ?? false,
|
|
393
|
-
knowledgeGraph: {
|
|
394
|
-
enabled: (kgRaw.enabled as boolean) ?? false,
|
|
395
|
-
scanIntervalMinutes: (kgRaw.scanIntervalMinutes as number) ?? 60,
|
|
396
|
-
batchSize: (kgRaw.batchSize as number) ?? 20,
|
|
397
|
-
},
|
|
398
|
-
multiUser: parseMultiUser(cfg.multiUser),
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
export const hyperspellConfigSchema = {
|
|
403
|
-
parse: parseConfig,
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Resolve OpenClaw state directory (matches OpenClaw's own logic).
|
|
408
|
-
*/
|
|
409
|
-
export function resolveStateDir(): string {
|
|
410
|
-
const { homedir } = require("node:os");
|
|
411
|
-
const path = require("node:path");
|
|
412
|
-
|
|
413
|
-
const override =
|
|
414
|
-
process.env.OPENCLAW_STATE_DIR?.trim() ||
|
|
415
|
-
process.env.CLAWDBOT_STATE_DIR?.trim();
|
|
416
|
-
if (override) {
|
|
417
|
-
return override.startsWith("~")
|
|
418
|
-
? override.replace(/^~(?=$|[\\/])/, homedir())
|
|
419
|
-
: path.resolve(override);
|
|
420
|
-
}
|
|
421
|
-
return path.join(homedir(), ".openclaw");
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Resolve OpenClaw config file path (matches OpenClaw's own logic).
|
|
426
|
-
*/
|
|
427
|
-
export function resolveConfigPath(): string {
|
|
428
|
-
const path = require("node:path");
|
|
429
|
-
|
|
430
|
-
const override =
|
|
431
|
-
process.env.OPENCLAW_CONFIG_PATH?.trim() ||
|
|
432
|
-
process.env.CLAWDBOT_CONFIG_PATH?.trim();
|
|
433
|
-
if (override) {
|
|
434
|
-
const { homedir } = require("node:os");
|
|
435
|
-
return override.startsWith("~")
|
|
436
|
-
? override.replace(/^~(?=$|[\\/])/, homedir())
|
|
437
|
-
: path.resolve(override);
|
|
438
|
-
}
|
|
439
|
-
return path.join(resolveStateDir(), "openclaw.json");
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Get the workspace directory from OpenClaw config
|
|
444
|
-
*/
|
|
445
|
-
export function getWorkspaceDir(): string {
|
|
446
|
-
const { homedir } = require("node:os");
|
|
447
|
-
const fs = require("node:fs");
|
|
448
|
-
const path = require("node:path");
|
|
449
|
-
|
|
450
|
-
// Resolve config path
|
|
451
|
-
const override =
|
|
452
|
-
process.env.OPENCLAW_CONFIG_PATH?.trim() ||
|
|
453
|
-
process.env.CLAWDBOT_CONFIG_PATH?.trim();
|
|
454
|
-
let configPath: string;
|
|
455
|
-
if (override) {
|
|
456
|
-
configPath = override.startsWith("~")
|
|
457
|
-
? override.replace(/^~(?=$|[\\/])/, homedir())
|
|
458
|
-
: path.resolve(override);
|
|
459
|
-
} else {
|
|
460
|
-
const stateDir =
|
|
461
|
-
process.env.OPENCLAW_STATE_DIR?.trim() ||
|
|
462
|
-
process.env.CLAWDBOT_STATE_DIR?.trim();
|
|
463
|
-
const resolvedStateDir = stateDir
|
|
464
|
-
? stateDir.startsWith("~")
|
|
465
|
-
? stateDir.replace(/^~(?=$|[\\/])/, homedir())
|
|
466
|
-
: path.resolve(stateDir)
|
|
467
|
-
: path.join(homedir(), ".openclaw");
|
|
468
|
-
configPath = path.join(resolvedStateDir, "openclaw.json");
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Read workspace from config
|
|
472
|
-
if (fs.existsSync(configPath)) {
|
|
473
|
-
try {
|
|
474
|
-
const content = fs.readFileSync(configPath, "utf-8");
|
|
475
|
-
const config = JSON.parse(content);
|
|
476
|
-
const workspace = config?.agents?.defaults?.workspace;
|
|
477
|
-
if (workspace) {
|
|
478
|
-
return workspace.startsWith("~")
|
|
479
|
-
? workspace.replace(/^~(?=$|[\\/])/, homedir())
|
|
480
|
-
: workspace;
|
|
481
|
-
}
|
|
482
|
-
} catch (_e) {
|
|
483
|
-
// Fall back to default
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// Default workspace
|
|
488
|
-
const stateDir =
|
|
489
|
-
process.env.OPENCLAW_STATE_DIR?.trim() ||
|
|
490
|
-
process.env.CLAWDBOT_STATE_DIR?.trim();
|
|
491
|
-
const resolvedStateDir = stateDir
|
|
492
|
-
? stateDir.startsWith("~")
|
|
493
|
-
? stateDir.replace(/^~(?=$|[\\/])/, homedir())
|
|
494
|
-
: path.resolve(stateDir)
|
|
495
|
-
: path.join(homedir(), ".openclaw");
|
|
496
|
-
return path.join(resolvedStateDir, "workspace");
|
|
497
|
-
}
|
package/graph/index.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { NetworkStateManager } from "./state.ts"
|
|
2
|
-
export { registerNetworkTools } from "./tools.ts"
|
|
3
|
-
export { scanMemories, formatScanResults, writeEntity, completeMemories, slugify } from "./ops.ts"
|
|
4
|
-
export type { EntityType, SourceMemories, ScannedMemory, WriteEntityParams } from "./ops.ts"
|
|
5
|
-
export { buildExtractionPrompt, getCronSetupCommand, getCronRemoveCommand, CRON_JOB_NAME } from "./cron.ts"
|