clawvault 2.6.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/command-registration.test.js +1 -3
- package/bin/register-core-commands.js +10 -23
- package/bin/register-maintenance-commands.js +3 -20
- package/bin/register-query-commands.js +23 -0
- package/bin/register-task-commands.js +1 -18
- package/bin/register-task-commands.test.js +0 -16
- package/bin/register-vault-operations-commands.js +1 -29
- package/dist/{chunk-QVMXF7FY.js → chunk-3D6BCTP6.js} +39 -1
- package/dist/{chunk-R2MIW5G7.js → chunk-3DHXQHYG.js} +1 -1
- package/dist/{chunk-Q2J5YTUF.js → chunk-3NSBOUT3.js} +73 -36
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/{chunk-AZYOKJYC.js → chunk-62YTUT6J.js} +2 -2
- package/dist/chunk-6U6MK36V.js +205 -0
- package/dist/{chunk-4QYGFWRM.js → chunk-7R7O6STJ.js} +4 -4
- package/dist/{chunk-VXEOHTSL.js → chunk-C7OK5WKP.js} +4 -4
- package/dist/chunk-CMB7UL7C.js +327 -0
- package/dist/chunk-DEFFDRVP.js +938 -0
- package/dist/{chunk-K3CDT7IH.js → chunk-E7MFQB6D.js} +61 -20
- package/dist/{chunk-ME37YNW3.js → chunk-F2JEUD4J.js} +6 -4
- package/dist/chunk-GAJV4IGR.js +82 -0
- package/dist/chunk-GQSLDZTS.js +560 -0
- package/dist/{chunk-4OXMU5S2.js → chunk-GUKMRGM7.js} +1 -1
- package/dist/{chunk-YOSEUUNB.js → chunk-H34S76MB.js} +6 -6
- package/dist/{chunk-4TE4JMLA.js → chunk-JY6FYXIT.js} +10 -5
- package/dist/chunk-K234IDRJ.js +1073 -0
- package/dist/{chunk-IEVLHNLU.js → chunk-LNJA2UGL.js} +86 -9
- package/dist/{chunk-MFAWT5O5.js → chunk-LYHGEHXG.js} +1 -0
- package/dist/chunk-MFM6K7PU.js +374 -0
- package/dist/{chunk-QWQ3TIKS.js → chunk-N2AXRYLC.js} +1 -1
- package/dist/chunk-PAH27GSN.js +108 -0
- package/dist/{chunk-OIWVQYQF.js → chunk-QBLMXKF2.js} +1 -1
- package/dist/{chunk-FHFUXL6G.js → chunk-QK3UCXWL.js} +2 -2
- package/dist/{chunk-2YDBJS7M.js → chunk-SJSFRIYS.js} +1 -1
- package/dist/{chunk-GSD4ALSI.js → chunk-U55BGUAU.js} +2 -2
- package/dist/{chunk-PBEE567J.js → chunk-VGLOTGAS.js} +1 -1
- package/dist/{chunk-F55HGNU4.js → chunk-WAZ3NLWL.js} +47 -0
- package/dist/{chunk-KL4NAOMO.js → chunk-WGRQ6HDV.js} +1 -1
- package/dist/{chunk-UEOUADMO.js → chunk-YKTA5JOJ.js} +13 -10
- package/dist/{chunk-XAVB4GB4.js → chunk-ZVVFWOLW.js} +4 -4
- package/dist/cli/index.cjs +10033 -0
- package/dist/cli/index.d.cts +5 -0
- package/dist/cli/index.js +20 -18
- package/dist/commands/archive.cjs +287 -0
- package/dist/commands/archive.d.cts +11 -0
- package/dist/commands/archive.js +1 -0
- package/dist/commands/backlog.cjs +721 -0
- package/dist/commands/backlog.d.cts +53 -0
- package/dist/commands/backlog.js +3 -2
- package/dist/commands/blocked.cjs +204 -0
- package/dist/commands/blocked.d.cts +26 -0
- package/dist/commands/blocked.js +3 -2
- package/dist/commands/checkpoint.cjs +244 -0
- package/dist/commands/checkpoint.d.cts +41 -0
- package/dist/commands/checkpoint.js +2 -1
- package/dist/commands/compat.cjs +369 -0
- package/dist/commands/compat.d.cts +28 -0
- package/dist/commands/compat.js +2 -1
- package/dist/commands/context.cjs +2989 -0
- package/dist/commands/context.d.cts +2 -0
- package/dist/commands/context.js +5 -4
- package/dist/commands/doctor.cjs +3062 -0
- package/dist/commands/doctor.d.cts +21 -0
- package/dist/commands/doctor.d.ts +6 -1
- package/dist/commands/doctor.js +13 -11
- package/dist/commands/embed.cjs +232 -0
- package/dist/commands/embed.d.cts +17 -0
- package/dist/commands/embed.js +5 -2
- package/dist/commands/entities.cjs +141 -0
- package/dist/commands/entities.d.cts +7 -0
- package/dist/commands/entities.js +1 -0
- package/dist/commands/graph.cjs +501 -0
- package/dist/commands/graph.d.cts +21 -0
- package/dist/commands/graph.js +1 -0
- package/dist/commands/inject.cjs +1636 -0
- package/dist/commands/inject.d.cts +2 -0
- package/dist/commands/inject.d.ts +1 -1
- package/dist/commands/inject.js +4 -2
- package/dist/commands/kanban.cjs +884 -0
- package/dist/commands/kanban.d.cts +63 -0
- package/dist/commands/kanban.js +4 -3
- package/dist/commands/link.cjs +965 -0
- package/dist/commands/link.d.cts +11 -0
- package/dist/commands/link.js +1 -0
- package/dist/commands/migrate-observations.cjs +362 -0
- package/dist/commands/migrate-observations.d.cts +19 -0
- package/dist/commands/migrate-observations.js +3 -2
- package/dist/commands/observe.cjs +4099 -0
- package/dist/commands/observe.d.cts +23 -0
- package/dist/commands/observe.d.ts +1 -0
- package/dist/commands/observe.js +11 -9
- package/dist/commands/project.cjs +1341 -0
- package/dist/commands/project.d.cts +85 -0
- package/dist/commands/project.js +5 -4
- package/dist/commands/rebuild.cjs +3136 -0
- package/dist/commands/rebuild.d.cts +11 -0
- package/dist/commands/rebuild.js +10 -8
- package/dist/commands/recover.cjs +361 -0
- package/dist/commands/recover.d.cts +38 -0
- package/dist/commands/recover.js +3 -2
- package/dist/commands/reflect.cjs +1008 -0
- package/dist/commands/reflect.d.cts +11 -0
- package/dist/commands/reflect.js +6 -4
- package/dist/commands/repair-session.cjs +457 -0
- package/dist/commands/repair-session.d.cts +38 -0
- package/dist/commands/repair-session.js +1 -0
- package/dist/commands/replay.cjs +4103 -0
- package/dist/commands/replay.d.cts +16 -0
- package/dist/commands/replay.js +12 -10
- package/dist/commands/session-recap.cjs +353 -0
- package/dist/commands/session-recap.d.cts +27 -0
- package/dist/commands/session-recap.js +1 -0
- package/dist/commands/setup.cjs +1345 -0
- package/dist/commands/setup.d.cts +100 -0
- package/dist/commands/setup.d.ts +90 -2
- package/dist/commands/setup.js +21 -2
- package/dist/commands/shell-init.cjs +75 -0
- package/dist/commands/shell-init.d.cts +7 -0
- package/dist/commands/shell-init.js +2 -0
- package/dist/commands/sleep.cjs +6028 -0
- package/dist/commands/sleep.d.cts +36 -0
- package/dist/commands/sleep.d.ts +1 -1
- package/dist/commands/sleep.js +17 -15
- package/dist/commands/status.cjs +2736 -0
- package/dist/commands/status.d.cts +52 -0
- package/dist/commands/status.js +12 -10
- package/dist/commands/tailscale.cjs +1532 -0
- package/dist/commands/tailscale.d.cts +52 -0
- package/dist/commands/tailscale.js +1 -0
- package/dist/commands/task.cjs +1236 -0
- package/dist/commands/task.d.cts +97 -0
- package/dist/commands/task.js +4 -3
- package/dist/commands/template.cjs +457 -0
- package/dist/commands/template.d.cts +36 -0
- package/dist/commands/template.js +2 -1
- package/dist/commands/wake.cjs +2626 -0
- package/dist/commands/wake.d.cts +22 -0
- package/dist/commands/wake.d.ts +1 -1
- package/dist/commands/wake.js +12 -11
- package/dist/context-BUGaWpyL.d.cts +46 -0
- package/dist/index.cjs +14526 -0
- package/dist/index.d.cts +858 -0
- package/dist/index.d.ts +192 -7
- package/dist/index.js +101 -75
- package/dist/{inject-x65KXWPk.d.ts → inject-Bzi5E-By.d.cts} +1 -1
- package/dist/inject-Bzi5E-By.d.ts +137 -0
- package/dist/lib/auto-linker.cjs +176 -0
- package/dist/lib/auto-linker.d.cts +26 -0
- package/dist/lib/auto-linker.js +1 -0
- package/dist/lib/canvas-layout.cjs +136 -0
- package/dist/lib/canvas-layout.d.cts +31 -0
- package/dist/lib/canvas-layout.d.ts +16 -100
- package/dist/lib/canvas-layout.js +78 -20
- package/dist/lib/config.cjs +78 -0
- package/dist/lib/config.d.cts +11 -0
- package/dist/lib/config.js +1 -0
- package/dist/lib/entity-index.cjs +84 -0
- package/dist/lib/entity-index.d.cts +26 -0
- package/dist/lib/entity-index.js +1 -0
- package/dist/lib/project-utils.cjs +864 -0
- package/dist/lib/project-utils.d.cts +97 -0
- package/dist/lib/project-utils.js +4 -3
- package/dist/lib/session-repair.cjs +239 -0
- package/dist/lib/session-repair.d.cts +110 -0
- package/dist/lib/session-repair.js +1 -0
- package/dist/lib/session-utils.cjs +209 -0
- package/dist/lib/session-utils.d.cts +63 -0
- package/dist/lib/session-utils.js +1 -0
- package/dist/lib/tailscale.cjs +1183 -0
- package/dist/lib/tailscale.d.cts +225 -0
- package/dist/lib/tailscale.js +1 -0
- package/dist/lib/task-utils.cjs +1137 -0
- package/dist/lib/task-utils.d.cts +208 -0
- package/dist/lib/task-utils.js +3 -2
- package/dist/lib/template-engine.cjs +47 -0
- package/dist/lib/template-engine.d.cts +11 -0
- package/dist/lib/template-engine.js +1 -0
- package/dist/lib/webdav.cjs +568 -0
- package/dist/lib/webdav.d.cts +109 -0
- package/dist/lib/webdav.js +1 -0
- package/dist/plugin/index.cjs +1907 -0
- package/dist/plugin/index.d.cts +36 -0
- package/dist/plugin/index.d.ts +36 -0
- package/dist/plugin/index.js +572 -0
- package/dist/plugin/inject.cjs +356 -0
- package/dist/plugin/inject.d.cts +54 -0
- package/dist/plugin/inject.d.ts +54 -0
- package/dist/plugin/inject.js +17 -0
- package/dist/plugin/observe.cjs +631 -0
- package/dist/plugin/observe.d.cts +39 -0
- package/dist/plugin/observe.d.ts +39 -0
- package/dist/plugin/observe.js +18 -0
- package/dist/plugin/templates.cjs +593 -0
- package/dist/plugin/templates.d.cts +52 -0
- package/dist/plugin/templates.d.ts +52 -0
- package/dist/plugin/templates.js +25 -0
- package/dist/plugin/types.cjs +18 -0
- package/dist/plugin/types.d.cts +209 -0
- package/dist/plugin/types.d.ts +209 -0
- package/dist/plugin/types.js +0 -0
- package/dist/plugin/vault.cjs +927 -0
- package/dist/plugin/vault.d.cts +68 -0
- package/dist/plugin/vault.d.ts +68 -0
- package/dist/plugin/vault.js +22 -0
- package/dist/{types-C74wgGL1.d.ts → types-Y2_Um2Ls.d.cts} +44 -1
- package/dist/types-Y2_Um2Ls.d.ts +205 -0
- package/hooks/clawvault/handler.js +70 -7
- package/hooks/clawvault/handler.test.js +91 -0
- package/openclaw.plugin.json +56 -0
- package/package.json +17 -7
- package/templates/memory-event.md +67 -0
- package/templates/party.md +63 -0
- package/templates/primitive-registry.yaml +551 -0
- package/templates/run.md +68 -0
- package/templates/trigger.md +68 -0
- package/templates/workspace.md +50 -0
- package/dashboard/lib/graph-diff.js +0 -104
- package/dashboard/lib/graph-diff.test.js +0 -75
- package/dashboard/lib/vault-parser.js +0 -556
- package/dashboard/lib/vault-parser.test.js +0 -254
- package/dashboard/public/app.js +0 -796
- package/dashboard/public/index.html +0 -52
- package/dashboard/public/styles.css +0 -221
- package/dashboard/server.js +0 -374
- package/dist/chunk-HA5M6KJB.js +0 -33
- package/dist/chunk-MAKNAHAW.js +0 -375
- package/dist/chunk-MDIH26GC.js +0 -183
- package/dist/chunk-MGDEINGP.js +0 -99
- package/dist/chunk-RVYA52PY.js +0 -363
- package/dist/commands/canvas.d.ts +0 -15
- package/dist/commands/canvas.js +0 -199
- package/dist/commands/sync-bd.d.ts +0 -10
- package/dist/commands/sync-bd.js +0 -9
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Observation } from './observe.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Template-Aware Vault File Writing for ClawVault
|
|
5
|
+
*
|
|
6
|
+
* Writes vault files with proper frontmatter based on template schemas.
|
|
7
|
+
* Validates enum fields, applies defaults, and adds timestamps.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface WriteOptions {
|
|
11
|
+
primitiveType?: string;
|
|
12
|
+
title?: string;
|
|
13
|
+
content?: string;
|
|
14
|
+
extraFields?: Record<string, unknown>;
|
|
15
|
+
source?: string;
|
|
16
|
+
sessionId?: string;
|
|
17
|
+
directory?: string;
|
|
18
|
+
filename?: string;
|
|
19
|
+
overwrite?: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface WriteResult {
|
|
22
|
+
success: boolean;
|
|
23
|
+
path: string;
|
|
24
|
+
primitiveType: string;
|
|
25
|
+
errors: string[];
|
|
26
|
+
created: boolean;
|
|
27
|
+
updated: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface LedgerEntry {
|
|
30
|
+
timestamp: Date;
|
|
31
|
+
category: string;
|
|
32
|
+
actor?: string;
|
|
33
|
+
content: string;
|
|
34
|
+
primitiveType?: string;
|
|
35
|
+
tags?: string[];
|
|
36
|
+
}
|
|
37
|
+
declare function writeVaultFile(vaultPath: string, options: WriteOptions): WriteResult;
|
|
38
|
+
declare function writeObservation(vaultPath: string, observation: Observation, options?: {
|
|
39
|
+
source?: string;
|
|
40
|
+
sessionId?: string;
|
|
41
|
+
}): WriteResult;
|
|
42
|
+
declare function writeObservations(vaultPath: string, observations: Observation[], options?: {
|
|
43
|
+
source?: string;
|
|
44
|
+
sessionId?: string;
|
|
45
|
+
}): WriteResult[];
|
|
46
|
+
declare function appendToLedger(vaultPath: string, entry: LedgerEntry): void;
|
|
47
|
+
declare function appendObservationToLedger(vaultPath: string, observation: Observation, actor?: string): void;
|
|
48
|
+
interface BatchWriteResult {
|
|
49
|
+
total: number;
|
|
50
|
+
successful: number;
|
|
51
|
+
failed: number;
|
|
52
|
+
results: WriteResult[];
|
|
53
|
+
}
|
|
54
|
+
declare function batchWriteObservations(vaultPath: string, observations: Observation[], options?: {
|
|
55
|
+
source?: string;
|
|
56
|
+
sessionId?: string;
|
|
57
|
+
writeLedger?: boolean;
|
|
58
|
+
writeFiles?: boolean;
|
|
59
|
+
actor?: string;
|
|
60
|
+
}): BatchWriteResult;
|
|
61
|
+
declare function ensureVaultStructure(vaultPath: string): void;
|
|
62
|
+
declare function getVaultStats(vaultPath: string): {
|
|
63
|
+
directories: string[];
|
|
64
|
+
fileCount: number;
|
|
65
|
+
primitiveTypes: Record<string, number>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export { type BatchWriteResult, type LedgerEntry, type WriteOptions, type WriteResult, appendObservationToLedger, appendToLedger, batchWriteObservations, ensureVaultStructure, getVaultStats, writeObservation, writeObservations, writeVaultFile };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Observation } from './observe.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Template-Aware Vault File Writing for ClawVault
|
|
5
|
+
*
|
|
6
|
+
* Writes vault files with proper frontmatter based on template schemas.
|
|
7
|
+
* Validates enum fields, applies defaults, and adds timestamps.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface WriteOptions {
|
|
11
|
+
primitiveType?: string;
|
|
12
|
+
title?: string;
|
|
13
|
+
content?: string;
|
|
14
|
+
extraFields?: Record<string, unknown>;
|
|
15
|
+
source?: string;
|
|
16
|
+
sessionId?: string;
|
|
17
|
+
directory?: string;
|
|
18
|
+
filename?: string;
|
|
19
|
+
overwrite?: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface WriteResult {
|
|
22
|
+
success: boolean;
|
|
23
|
+
path: string;
|
|
24
|
+
primitiveType: string;
|
|
25
|
+
errors: string[];
|
|
26
|
+
created: boolean;
|
|
27
|
+
updated: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface LedgerEntry {
|
|
30
|
+
timestamp: Date;
|
|
31
|
+
category: string;
|
|
32
|
+
actor?: string;
|
|
33
|
+
content: string;
|
|
34
|
+
primitiveType?: string;
|
|
35
|
+
tags?: string[];
|
|
36
|
+
}
|
|
37
|
+
declare function writeVaultFile(vaultPath: string, options: WriteOptions): WriteResult;
|
|
38
|
+
declare function writeObservation(vaultPath: string, observation: Observation, options?: {
|
|
39
|
+
source?: string;
|
|
40
|
+
sessionId?: string;
|
|
41
|
+
}): WriteResult;
|
|
42
|
+
declare function writeObservations(vaultPath: string, observations: Observation[], options?: {
|
|
43
|
+
source?: string;
|
|
44
|
+
sessionId?: string;
|
|
45
|
+
}): WriteResult[];
|
|
46
|
+
declare function appendToLedger(vaultPath: string, entry: LedgerEntry): void;
|
|
47
|
+
declare function appendObservationToLedger(vaultPath: string, observation: Observation, actor?: string): void;
|
|
48
|
+
interface BatchWriteResult {
|
|
49
|
+
total: number;
|
|
50
|
+
successful: number;
|
|
51
|
+
failed: number;
|
|
52
|
+
results: WriteResult[];
|
|
53
|
+
}
|
|
54
|
+
declare function batchWriteObservations(vaultPath: string, observations: Observation[], options?: {
|
|
55
|
+
source?: string;
|
|
56
|
+
sessionId?: string;
|
|
57
|
+
writeLedger?: boolean;
|
|
58
|
+
writeFiles?: boolean;
|
|
59
|
+
actor?: string;
|
|
60
|
+
}): BatchWriteResult;
|
|
61
|
+
declare function ensureVaultStructure(vaultPath: string): void;
|
|
62
|
+
declare function getVaultStats(vaultPath: string): {
|
|
63
|
+
directories: string[];
|
|
64
|
+
fileCount: number;
|
|
65
|
+
primitiveTypes: Record<string, number>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export { type BatchWriteResult, type LedgerEntry, type WriteOptions, type WriteResult, appendObservationToLedger, appendToLedger, batchWriteObservations, ensureVaultStructure, getVaultStats, writeObservation, writeObservations, writeVaultFile };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendObservationToLedger,
|
|
3
|
+
appendToLedger,
|
|
4
|
+
batchWriteObservations,
|
|
5
|
+
ensureVaultStructure,
|
|
6
|
+
getVaultStats,
|
|
7
|
+
writeObservation,
|
|
8
|
+
writeObservations,
|
|
9
|
+
writeVaultFile
|
|
10
|
+
} from "../chunk-MFM6K7PU.js";
|
|
11
|
+
import "../chunk-GQSLDZTS.js";
|
|
12
|
+
import "../chunk-3RG5ZIWI.js";
|
|
13
|
+
export {
|
|
14
|
+
appendObservationToLedger,
|
|
15
|
+
appendToLedger,
|
|
16
|
+
batchWriteObservations,
|
|
17
|
+
ensureVaultStructure,
|
|
18
|
+
getVaultStats,
|
|
19
|
+
writeObservation,
|
|
20
|
+
writeObservations,
|
|
21
|
+
writeVaultFile
|
|
22
|
+
};
|
|
@@ -70,6 +70,49 @@ interface SearchOptions {
|
|
|
70
70
|
fullContent?: boolean;
|
|
71
71
|
/** Boost recent documents in ranking */
|
|
72
72
|
temporalBoost?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* v2.7 — Enable chunk-level BM25 pre-filtering before semantic search.
|
|
75
|
+
* Chunks documents into ~600-char sentence windows and ranks chunks by
|
|
76
|
+
* keyword overlap so that relevant content deep in long documents isn't
|
|
77
|
+
* silently dropped by fixed-N embedding limits.
|
|
78
|
+
*/
|
|
79
|
+
chunkPrefilter?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* v2.7 — Exhaustive threshold-based retrieval for aggregation queries.
|
|
82
|
+
* Instead of a fixed top_k, keeps pulling results until the normalised
|
|
83
|
+
* relevance score drops below this threshold (0-1). Set to e.g. 0.01
|
|
84
|
+
* for aggregation / "list all" queries. Overrides `limit` when set.
|
|
85
|
+
*/
|
|
86
|
+
relevanceThreshold?: number;
|
|
87
|
+
/**
|
|
88
|
+
* v2.7 — Maximum results when using relevanceThreshold.
|
|
89
|
+
* Prevents runaway result sets. Default 40.
|
|
90
|
+
*/
|
|
91
|
+
thresholdMaxResults?: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* v2.7 — A date reference extracted from document content at ingest time.
|
|
95
|
+
*/
|
|
96
|
+
interface ExtractedDate {
|
|
97
|
+
/** ISO date string (YYYY-MM-DD) or "duration:<value>" */
|
|
98
|
+
date: string;
|
|
99
|
+
/** Surrounding context snippet (~150 chars) */
|
|
100
|
+
context: string;
|
|
101
|
+
/** Document id the date was extracted from */
|
|
102
|
+
documentId: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* v2.7 — An extracted user preference from conversation content.
|
|
106
|
+
*/
|
|
107
|
+
interface ExtractedPreference {
|
|
108
|
+
/** The preference category (tool, hobby, brand, etc.) */
|
|
109
|
+
category: string;
|
|
110
|
+
/** The preference value */
|
|
111
|
+
value: string;
|
|
112
|
+
/** Document id it was extracted from */
|
|
113
|
+
documentId: string;
|
|
114
|
+
/** Surrounding context snippet */
|
|
115
|
+
context: string;
|
|
73
116
|
}
|
|
74
117
|
interface StoreOptions {
|
|
75
118
|
/** Category to store in */
|
|
@@ -159,4 +202,4 @@ interface SessionRecap {
|
|
|
159
202
|
}
|
|
160
203
|
declare const DEFAULT_CONFIG: Partial<VaultConfig>;
|
|
161
204
|
|
|
162
|
-
export { type Category as C, type Document as D, type HandoffDocument as H, type MemoryType as M, type StoreOptions as S, TYPE_TO_CATEGORY as T, type VaultConfig as V, type SearchOptions as a, type SearchResult as b, type SyncOptions as c, type SyncResult as d, type SessionRecap as e,
|
|
205
|
+
export { type Category as C, type Document as D, type ExtractedDate as E, type HandoffDocument as H, type MemoryType as M, type StoreOptions as S, TYPE_TO_CATEGORY as T, type VaultConfig as V, type SearchOptions as a, type SearchResult as b, type SyncOptions as c, type SyncResult as d, type SessionRecap as e, type ExtractedPreference as f, DEFAULT_CATEGORIES as g, DEFAULT_CONFIG as h, MEMORY_TYPES as i, type VaultMeta as j };
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClawVault Types - The elephant's memory structure
|
|
3
|
+
*/
|
|
4
|
+
interface VaultConfig {
|
|
5
|
+
/** Root path of the vault */
|
|
6
|
+
path: string;
|
|
7
|
+
/** Name of the vault */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Categories to create on init */
|
|
10
|
+
categories: string[];
|
|
11
|
+
/** qmd collection name (defaults to vault name if not set) */
|
|
12
|
+
qmdCollection?: string;
|
|
13
|
+
/** Root path for qmd collection (defaults to vault path) */
|
|
14
|
+
qmdRoot?: string;
|
|
15
|
+
/** Custom templates path (optional) */
|
|
16
|
+
templatesPath?: string;
|
|
17
|
+
}
|
|
18
|
+
interface VaultMeta {
|
|
19
|
+
name: string;
|
|
20
|
+
version: string;
|
|
21
|
+
created: string;
|
|
22
|
+
lastUpdated: string;
|
|
23
|
+
categories: string[];
|
|
24
|
+
documentCount: number;
|
|
25
|
+
/** qmd collection name (defaults to vault name if not set) */
|
|
26
|
+
qmdCollection?: string;
|
|
27
|
+
/** Root path for qmd collection (defaults to vault path) */
|
|
28
|
+
qmdRoot?: string;
|
|
29
|
+
}
|
|
30
|
+
interface Document {
|
|
31
|
+
/** Unique ID (relative path without extension) */
|
|
32
|
+
id: string;
|
|
33
|
+
/** Full file path */
|
|
34
|
+
path: string;
|
|
35
|
+
/** Category (folder name) */
|
|
36
|
+
category: string;
|
|
37
|
+
/** Document title */
|
|
38
|
+
title: string;
|
|
39
|
+
/** Raw content */
|
|
40
|
+
content: string;
|
|
41
|
+
/** Frontmatter metadata */
|
|
42
|
+
frontmatter: Record<string, unknown>;
|
|
43
|
+
/** Extracted wiki-links [[like-this]] */
|
|
44
|
+
links: string[];
|
|
45
|
+
/** Tags extracted from content */
|
|
46
|
+
tags: string[];
|
|
47
|
+
/** Last modified timestamp */
|
|
48
|
+
modified: Date;
|
|
49
|
+
}
|
|
50
|
+
interface SearchResult {
|
|
51
|
+
/** Document that matched */
|
|
52
|
+
document: Document;
|
|
53
|
+
/** Relevance score (0-1) */
|
|
54
|
+
score: number;
|
|
55
|
+
/** Matching snippet */
|
|
56
|
+
snippet: string;
|
|
57
|
+
/** Which terms matched */
|
|
58
|
+
matchedTerms: string[];
|
|
59
|
+
}
|
|
60
|
+
interface SearchOptions {
|
|
61
|
+
/** Max results to return */
|
|
62
|
+
limit?: number;
|
|
63
|
+
/** Minimum score threshold (0-1) */
|
|
64
|
+
minScore?: number;
|
|
65
|
+
/** Filter by category */
|
|
66
|
+
category?: string;
|
|
67
|
+
/** Filter by tags */
|
|
68
|
+
tags?: string[];
|
|
69
|
+
/** Include full content in results */
|
|
70
|
+
fullContent?: boolean;
|
|
71
|
+
/** Boost recent documents in ranking */
|
|
72
|
+
temporalBoost?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* v2.7 — Enable chunk-level BM25 pre-filtering before semantic search.
|
|
75
|
+
* Chunks documents into ~600-char sentence windows and ranks chunks by
|
|
76
|
+
* keyword overlap so that relevant content deep in long documents isn't
|
|
77
|
+
* silently dropped by fixed-N embedding limits.
|
|
78
|
+
*/
|
|
79
|
+
chunkPrefilter?: boolean;
|
|
80
|
+
/**
|
|
81
|
+
* v2.7 — Exhaustive threshold-based retrieval for aggregation queries.
|
|
82
|
+
* Instead of a fixed top_k, keeps pulling results until the normalised
|
|
83
|
+
* relevance score drops below this threshold (0-1). Set to e.g. 0.01
|
|
84
|
+
* for aggregation / "list all" queries. Overrides `limit` when set.
|
|
85
|
+
*/
|
|
86
|
+
relevanceThreshold?: number;
|
|
87
|
+
/**
|
|
88
|
+
* v2.7 — Maximum results when using relevanceThreshold.
|
|
89
|
+
* Prevents runaway result sets. Default 40.
|
|
90
|
+
*/
|
|
91
|
+
thresholdMaxResults?: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* v2.7 — A date reference extracted from document content at ingest time.
|
|
95
|
+
*/
|
|
96
|
+
interface ExtractedDate {
|
|
97
|
+
/** ISO date string (YYYY-MM-DD) or "duration:<value>" */
|
|
98
|
+
date: string;
|
|
99
|
+
/** Surrounding context snippet (~150 chars) */
|
|
100
|
+
context: string;
|
|
101
|
+
/** Document id the date was extracted from */
|
|
102
|
+
documentId: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* v2.7 — An extracted user preference from conversation content.
|
|
106
|
+
*/
|
|
107
|
+
interface ExtractedPreference {
|
|
108
|
+
/** The preference category (tool, hobby, brand, etc.) */
|
|
109
|
+
category: string;
|
|
110
|
+
/** The preference value */
|
|
111
|
+
value: string;
|
|
112
|
+
/** Document id it was extracted from */
|
|
113
|
+
documentId: string;
|
|
114
|
+
/** Surrounding context snippet */
|
|
115
|
+
context: string;
|
|
116
|
+
}
|
|
117
|
+
interface StoreOptions {
|
|
118
|
+
/** Category to store in */
|
|
119
|
+
category: string;
|
|
120
|
+
/** Document title (used for filename) */
|
|
121
|
+
title: string;
|
|
122
|
+
/** Content body */
|
|
123
|
+
content: string;
|
|
124
|
+
/** Frontmatter metadata */
|
|
125
|
+
frontmatter?: Record<string, unknown>;
|
|
126
|
+
/** Override existing file */
|
|
127
|
+
overwrite?: boolean;
|
|
128
|
+
/** Trigger qmd update after storing */
|
|
129
|
+
qmdUpdate?: boolean;
|
|
130
|
+
/** Trigger qmd embed after storing (implies qmdUpdate) */
|
|
131
|
+
qmdEmbed?: boolean;
|
|
132
|
+
/** Optional qmd index name override (defaults to configured/global index) */
|
|
133
|
+
qmdIndexName?: string;
|
|
134
|
+
}
|
|
135
|
+
interface SyncOptions {
|
|
136
|
+
/** Target directory to sync to */
|
|
137
|
+
target: string;
|
|
138
|
+
/** Delete files in target not in source */
|
|
139
|
+
deleteOrphans?: boolean;
|
|
140
|
+
/** Dry run - don't actually sync */
|
|
141
|
+
dryRun?: boolean;
|
|
142
|
+
}
|
|
143
|
+
interface SyncResult {
|
|
144
|
+
copied: string[];
|
|
145
|
+
deleted: string[];
|
|
146
|
+
unchanged: string[];
|
|
147
|
+
errors: string[];
|
|
148
|
+
}
|
|
149
|
+
type Category = 'preferences' | 'decisions' | 'rules' | 'patterns' | 'people' | 'projects' | 'goals' | 'transcripts' | 'inbox' | 'templates' | 'facts' | 'feelings' | 'lessons' | 'commitments' | 'handoffs' | string;
|
|
150
|
+
declare const DEFAULT_CATEGORIES: Category[];
|
|
151
|
+
/**
|
|
152
|
+
* Memory Type Taxonomy (Benthic's 8 categories)
|
|
153
|
+
* Knowing WHAT KIND of thing helps you know WHERE to put it
|
|
154
|
+
*/
|
|
155
|
+
type MemoryType = 'fact' | 'feeling' | 'decision' | 'lesson' | 'commitment' | 'preference' | 'relationship' | 'project';
|
|
156
|
+
declare const MEMORY_TYPES: MemoryType[];
|
|
157
|
+
/**
|
|
158
|
+
* Memory type to category mapping
|
|
159
|
+
*/
|
|
160
|
+
declare const TYPE_TO_CATEGORY: Record<MemoryType, Category>;
|
|
161
|
+
/**
|
|
162
|
+
* Handoff document - bridges sessions
|
|
163
|
+
*/
|
|
164
|
+
interface HandoffDocument {
|
|
165
|
+
/** When this handoff was created */
|
|
166
|
+
created: string;
|
|
167
|
+
/** Session key or identifier */
|
|
168
|
+
sessionKey?: string;
|
|
169
|
+
/** What I was working on */
|
|
170
|
+
workingOn: string[];
|
|
171
|
+
/** What is currently blocked */
|
|
172
|
+
blocked: string[];
|
|
173
|
+
/** What comes next */
|
|
174
|
+
nextSteps: string[];
|
|
175
|
+
/** Emotional state/energy */
|
|
176
|
+
feeling?: string;
|
|
177
|
+
/** Key decisions made */
|
|
178
|
+
decisions?: string[];
|
|
179
|
+
/** Open questions */
|
|
180
|
+
openQuestions?: string[];
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Session recap - who I was when I woke up
|
|
184
|
+
*/
|
|
185
|
+
interface SessionRecap {
|
|
186
|
+
/** When recap was generated */
|
|
187
|
+
generated: string;
|
|
188
|
+
/** Recent handoffs (last N) */
|
|
189
|
+
recentHandoffs: HandoffDocument[];
|
|
190
|
+
/** Active projects */
|
|
191
|
+
activeProjects: string[];
|
|
192
|
+
/** Pending commitments */
|
|
193
|
+
pendingCommitments: string[];
|
|
194
|
+
/** Recent decisions made */
|
|
195
|
+
recentDecisions?: string[];
|
|
196
|
+
/** Recent lessons learned */
|
|
197
|
+
recentLessons: string[];
|
|
198
|
+
/** Key relationships to remember */
|
|
199
|
+
keyRelationships: string[];
|
|
200
|
+
/** Current emotional arc */
|
|
201
|
+
emotionalArc?: string;
|
|
202
|
+
}
|
|
203
|
+
declare const DEFAULT_CONFIG: Partial<VaultConfig>;
|
|
204
|
+
|
|
205
|
+
export { type Category as C, type Document as D, type ExtractedDate as E, type HandoffDocument as H, type MemoryType as M, type StoreOptions as S, TYPE_TO_CATEGORY as T, type VaultConfig as V, type SearchOptions as a, type SearchResult as b, type SyncOptions as c, type SyncResult as d, type SessionRecap as e, type ExtractedPreference as f, DEFAULT_CATEGORIES as g, DEFAULT_CONFIG as h, MEMORY_TYPES as i, type VaultMeta as j };
|
|
@@ -21,7 +21,7 @@ const MAX_CONTEXT_PROMPT_LENGTH = 500;
|
|
|
21
21
|
const MAX_CONTEXT_SNIPPET_LENGTH = 220;
|
|
22
22
|
const MAX_RECAP_RESULTS = 6;
|
|
23
23
|
const MAX_RECAP_SNIPPET_LENGTH = 220;
|
|
24
|
-
const EVENT_NAME_SEPARATOR_RE = /[
|
|
24
|
+
const EVENT_NAME_SEPARATOR_RE = /[._:\/-]+/g;
|
|
25
25
|
const OBSERVE_CURSOR_FILE = 'observe-cursors.json';
|
|
26
26
|
const ONE_KIB = 1024;
|
|
27
27
|
const ONE_MIB = ONE_KIB * ONE_KIB;
|
|
@@ -178,7 +178,7 @@ function shouldObserveActiveSessions(vaultPath, agentId) {
|
|
|
178
178
|
const sessionId = typeof value.sessionId === 'string' ? value.sessionId.trim() : '';
|
|
179
179
|
if (!/^[a-zA-Z0-9._-]{1,200}$/.test(sessionId)) continue;
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
let filePath = path.join(sessionsDir, `${sessionId}.jsonl`);
|
|
182
182
|
let stat;
|
|
183
183
|
try {
|
|
184
184
|
stat = fs.statSync(filePath);
|
|
@@ -187,6 +187,27 @@ function shouldObserveActiveSessions(vaultPath, agentId) {
|
|
|
187
187
|
}
|
|
188
188
|
if (!stat.isFile()) continue;
|
|
189
189
|
|
|
190
|
+
// After /new or /reset, the main .jsonl is emptied — fall back to reset file
|
|
191
|
+
if (stat.size < 100) {
|
|
192
|
+
const resetPrefix = `${sessionId}.jsonl.reset.`;
|
|
193
|
+
try {
|
|
194
|
+
const resetFiles = fs.readdirSync(sessionsDir)
|
|
195
|
+
.filter(f => f.startsWith(resetPrefix))
|
|
196
|
+
.sort()
|
|
197
|
+
.reverse();
|
|
198
|
+
if (resetFiles.length > 0) {
|
|
199
|
+
const resetPath = path.join(sessionsDir, resetFiles[0]);
|
|
200
|
+
const resetStat = fs.statSync(resetPath);
|
|
201
|
+
if (resetStat.isFile() && resetStat.size > stat.size) {
|
|
202
|
+
filePath = resetPath;
|
|
203
|
+
stat = resetStat;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
} catch {
|
|
207
|
+
// Ignore — use original file
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
190
211
|
const fileSize = stat.size;
|
|
191
212
|
const cursorEntry = cursors[sessionId];
|
|
192
213
|
const previousOffset = Number.isFinite(cursorEntry?.lastObservedOffset)
|
|
@@ -366,16 +387,28 @@ function normalizeEventToken(value) {
|
|
|
366
387
|
.trim()
|
|
367
388
|
.toLowerCase()
|
|
368
389
|
.replace(/\s+/g, '')
|
|
369
|
-
.replace(EVENT_NAME_SEPARATOR_RE, ':')
|
|
390
|
+
.replace(EVENT_NAME_SEPARATOR_RE, ':')
|
|
391
|
+
.replace(/^:+|:+$/g, '');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function collapseEventToken(value) {
|
|
395
|
+
return normalizeEventToken(value).replace(/:/g, '');
|
|
370
396
|
}
|
|
371
397
|
|
|
372
398
|
function eventMatches(event, type, action) {
|
|
373
|
-
const normalizedExpected =
|
|
399
|
+
const normalizedExpected = [normalizeEventToken(type), normalizeEventToken(action)]
|
|
400
|
+
.filter(Boolean)
|
|
401
|
+
.join(':');
|
|
402
|
+
const collapsedExpected = collapseEventToken(normalizedExpected);
|
|
374
403
|
const normalizedType = normalizeEventToken(event?.type);
|
|
375
404
|
const normalizedAction = normalizeEventToken(event?.action);
|
|
376
405
|
|
|
377
406
|
if (normalizedType && normalizedAction) {
|
|
378
|
-
|
|
407
|
+
const normalizedEventPair = `${normalizedType}:${normalizedAction}`;
|
|
408
|
+
if (
|
|
409
|
+
normalizedEventPair === normalizedExpected
|
|
410
|
+
|| collapseEventToken(normalizedEventPair) === collapsedExpected
|
|
411
|
+
) {
|
|
379
412
|
return true;
|
|
380
413
|
}
|
|
381
414
|
}
|
|
@@ -391,7 +424,10 @@ function eventMatches(event, type, action) {
|
|
|
391
424
|
for (const alias of aliases) {
|
|
392
425
|
const normalizedAlias = normalizeEventToken(alias);
|
|
393
426
|
if (!normalizedAlias) continue;
|
|
394
|
-
if (
|
|
427
|
+
if (
|
|
428
|
+
normalizedAlias === normalizedExpected
|
|
429
|
+
|| collapseEventToken(normalizedAlias) === collapsedExpected
|
|
430
|
+
) {
|
|
395
431
|
return true;
|
|
396
432
|
}
|
|
397
433
|
}
|
|
@@ -402,6 +438,7 @@ function eventMatches(event, type, action) {
|
|
|
402
438
|
function eventIncludesToken(event, token) {
|
|
403
439
|
const normalizedToken = normalizeEventToken(token);
|
|
404
440
|
if (!normalizedToken) return false;
|
|
441
|
+
const collapsedToken = collapseEventToken(normalizedToken);
|
|
405
442
|
|
|
406
443
|
const values = [
|
|
407
444
|
event?.type,
|
|
@@ -416,7 +453,12 @@ function eventIncludesToken(event, token) {
|
|
|
416
453
|
return values
|
|
417
454
|
.map((value) => normalizeEventToken(value))
|
|
418
455
|
.filter(Boolean)
|
|
419
|
-
.some((value) =>
|
|
456
|
+
.some((value) => {
|
|
457
|
+
if (value.includes(normalizedToken)) {
|
|
458
|
+
return true;
|
|
459
|
+
}
|
|
460
|
+
return collapseEventToken(value).includes(collapsedToken);
|
|
461
|
+
});
|
|
420
462
|
}
|
|
421
463
|
|
|
422
464
|
// Validate vault path - must be absolute and exist
|
|
@@ -450,6 +492,14 @@ function findVaultPath() {
|
|
|
450
492
|
if (process.env.CLAWVAULT_PATH) {
|
|
451
493
|
return validateVaultPath(process.env.CLAWVAULT_PATH);
|
|
452
494
|
}
|
|
495
|
+
const configuredCandidates = [
|
|
496
|
+
process.env.OPENCLAW_MEMORY_PATH,
|
|
497
|
+
process.env.OPENCLAW_VAULT_PATH
|
|
498
|
+
];
|
|
499
|
+
for (const candidate of configuredCandidates) {
|
|
500
|
+
const validated = validateVaultPath(candidate);
|
|
501
|
+
if (validated) return validated;
|
|
502
|
+
}
|
|
453
503
|
|
|
454
504
|
// Walk up from cwd
|
|
455
505
|
let dir = process.cwd();
|
|
@@ -466,6 +516,19 @@ function findVaultPath() {
|
|
|
466
516
|
|
|
467
517
|
dir = path.dirname(dir);
|
|
468
518
|
}
|
|
519
|
+
|
|
520
|
+
// Canonical local-first defaults for OpenClaw users.
|
|
521
|
+
const homeDir = normalizeAbsoluteEnvPath(process.env.HOME) || os.homedir();
|
|
522
|
+
const homeCandidates = [
|
|
523
|
+
path.join(homeDir, 'memory'),
|
|
524
|
+
path.join(homeDir, 'Memory'),
|
|
525
|
+
path.join(homeDir, 'vault'),
|
|
526
|
+
path.join(homeDir, 'Vault')
|
|
527
|
+
];
|
|
528
|
+
for (const candidate of homeCandidates) {
|
|
529
|
+
const validated = validateVaultPath(candidate);
|
|
530
|
+
if (validated) return validated;
|
|
531
|
+
}
|
|
469
532
|
|
|
470
533
|
return null;
|
|
471
534
|
}
|
|
@@ -46,6 +46,8 @@ async function loadHandler() {
|
|
|
46
46
|
afterEach(() => {
|
|
47
47
|
vi.clearAllMocks();
|
|
48
48
|
delete process.env.CLAWVAULT_PATH;
|
|
49
|
+
delete process.env.OPENCLAW_MEMORY_PATH;
|
|
50
|
+
delete process.env.OPENCLAW_VAULT_PATH;
|
|
49
51
|
delete process.env.OPENCLAW_STATE_DIR;
|
|
50
52
|
delete process.env.OPENCLAW_HOME;
|
|
51
53
|
delete process.env.OPENCLAW_AGENT_ID;
|
|
@@ -105,6 +107,28 @@ describe('clawvault hook handler', () => {
|
|
|
105
107
|
fs.rmSync(vaultPath, { recursive: true, force: true });
|
|
106
108
|
});
|
|
107
109
|
|
|
110
|
+
it('supports slash-prefixed command actions for /new', async () => {
|
|
111
|
+
const vaultPath = makeVaultFixture();
|
|
112
|
+
process.env.CLAWVAULT_PATH = vaultPath;
|
|
113
|
+
execFileSyncMock.mockReturnValue('');
|
|
114
|
+
|
|
115
|
+
const handler = await loadHandler();
|
|
116
|
+
await handler({
|
|
117
|
+
type: 'command',
|
|
118
|
+
action: '/new',
|
|
119
|
+
sessionKey: 'agent:clawdious:main',
|
|
120
|
+
context: { commandSource: 'slash' }
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(execFileSyncMock).toHaveBeenCalledWith(
|
|
124
|
+
'clawvault',
|
|
125
|
+
expect.arrayContaining(['checkpoint', '--working-on']),
|
|
126
|
+
expect.objectContaining({ shell: false })
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
fs.rmSync(vaultPath, { recursive: true, force: true });
|
|
130
|
+
});
|
|
131
|
+
|
|
108
132
|
it('injects recap and memory context on session start alias event', async () => {
|
|
109
133
|
const vaultPath = makeVaultFixture();
|
|
110
134
|
process.env.CLAWVAULT_PATH = vaultPath;
|
|
@@ -241,6 +265,73 @@ describe('clawvault hook handler', () => {
|
|
|
241
265
|
fs.rmSync(vaultPath, { recursive: true, force: true });
|
|
242
266
|
});
|
|
243
267
|
|
|
268
|
+
it('supports compaction action separator variants', async () => {
|
|
269
|
+
const vaultPath = makeVaultFixture();
|
|
270
|
+
process.env.CLAWVAULT_PATH = vaultPath;
|
|
271
|
+
execFileSyncMock.mockReturnValue('');
|
|
272
|
+
|
|
273
|
+
const handler = await loadHandler();
|
|
274
|
+
await handler({
|
|
275
|
+
type: 'compaction',
|
|
276
|
+
action: 'memory_flush',
|
|
277
|
+
sessionKey: 'agent:clawdious:main'
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
expect(execFileSyncMock).toHaveBeenCalledWith(
|
|
281
|
+
'clawvault',
|
|
282
|
+
expect.arrayContaining(['observe', '--cron', '--min-new', '1']),
|
|
283
|
+
expect.objectContaining({ shell: false })
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
fs.rmSync(vaultPath, { recursive: true, force: true });
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('discovers canonical ~/memory vault when env and cwd do not provide one', async () => {
|
|
290
|
+
const fakeHome = fs.mkdtempSync(path.join(os.tmpdir(), 'clawvault-home-'));
|
|
291
|
+
const vaultPath = path.join(fakeHome, 'memory');
|
|
292
|
+
fs.mkdirSync(vaultPath, { recursive: true });
|
|
293
|
+
fs.writeFileSync(path.join(vaultPath, '.clawvault.json'), JSON.stringify({ name: 'home' }), 'utf-8');
|
|
294
|
+
const originalHome = process.env.HOME;
|
|
295
|
+
const originalClawvaultPath = process.env.CLAWVAULT_PATH;
|
|
296
|
+
const originalOpenclawMemory = process.env.OPENCLAW_MEMORY_PATH;
|
|
297
|
+
const originalOpenclawVault = process.env.OPENCLAW_VAULT_PATH;
|
|
298
|
+
process.env.HOME = fakeHome;
|
|
299
|
+
delete process.env.CLAWVAULT_PATH;
|
|
300
|
+
delete process.env.OPENCLAW_MEMORY_PATH;
|
|
301
|
+
delete process.env.OPENCLAW_VAULT_PATH;
|
|
302
|
+
// Mock cwd to a temp dir without a vault so walk-up doesn't find one
|
|
303
|
+
const fakeCwd = fs.mkdtempSync(path.join(os.tmpdir(), 'clawvault-cwd-'));
|
|
304
|
+
const originalCwd = process.cwd;
|
|
305
|
+
process.cwd = () => fakeCwd;
|
|
306
|
+
try {
|
|
307
|
+
execFileSyncMock.mockReturnValue('');
|
|
308
|
+
|
|
309
|
+
const handler = await loadHandler();
|
|
310
|
+
await handler({
|
|
311
|
+
eventName: 'compaction:memoryFlush',
|
|
312
|
+
sessionKey: 'agent:main:main'
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
expect(execFileSyncMock).toHaveBeenCalledWith(
|
|
316
|
+
'clawvault',
|
|
317
|
+
expect.arrayContaining(['observe', '--cron', '-v', vaultPath]),
|
|
318
|
+
expect.objectContaining({ shell: false })
|
|
319
|
+
);
|
|
320
|
+
} finally {
|
|
321
|
+
if (originalHome === undefined) {
|
|
322
|
+
delete process.env.HOME;
|
|
323
|
+
} else {
|
|
324
|
+
process.env.HOME = originalHome;
|
|
325
|
+
}
|
|
326
|
+
if (originalClawvaultPath !== undefined) process.env.CLAWVAULT_PATH = originalClawvaultPath;
|
|
327
|
+
if (originalOpenclawMemory !== undefined) process.env.OPENCLAW_MEMORY_PATH = originalOpenclawMemory;
|
|
328
|
+
if (originalOpenclawVault !== undefined) process.env.OPENCLAW_VAULT_PATH = originalOpenclawVault;
|
|
329
|
+
process.cwd = originalCwd;
|
|
330
|
+
fs.rmSync(fakeHome, { recursive: true, force: true });
|
|
331
|
+
fs.rmSync(fakeCwd, { recursive: true, force: true });
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
244
335
|
it('runs weekly reflection on cron.weekly at Sunday midnight', async () => {
|
|
245
336
|
const vaultPath = makeVaultFixture();
|
|
246
337
|
process.env.CLAWVAULT_PATH = vaultPath;
|