mindkeeper-openclaw 0.2.28 → 0.2.30
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/LICENSE +21 -0
- package/dist/index.js +70 -13
- package/package.json +9 -10
- package/skills/mindkeeper/SKILL.md +2 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 context-vault contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.js
CHANGED
|
@@ -678,11 +678,13 @@ function generateTemplateMessage(changedFiles, options) {
|
|
|
678
678
|
}
|
|
679
679
|
|
|
680
680
|
// ../core/src/message/llm.ts
|
|
681
|
-
async function generateLlmMessage(diffs, provider) {
|
|
681
|
+
async function generateLlmMessage(diffs, provider, log) {
|
|
682
682
|
if (!provider) return null;
|
|
683
683
|
try {
|
|
684
684
|
return await provider.generateCommitMessage(diffs);
|
|
685
|
-
} catch {
|
|
685
|
+
} catch (err) {
|
|
686
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
687
|
+
log?.warn?.(`[mindkeeper] LLM commit message error: ${msg}`);
|
|
686
688
|
return null;
|
|
687
689
|
}
|
|
688
690
|
}
|
|
@@ -698,6 +700,7 @@ var Tracker = class {
|
|
|
698
700
|
workDir;
|
|
699
701
|
gitDir;
|
|
700
702
|
configOverrides;
|
|
703
|
+
log;
|
|
701
704
|
constructor(options) {
|
|
702
705
|
this.workDir = import_node_path3.default.resolve(options.workDir);
|
|
703
706
|
this.gitDir = options.gitDir ? import_node_path3.default.resolve(options.gitDir) : import_node_path3.default.join(this.workDir, GITDIR_NAME);
|
|
@@ -705,6 +708,7 @@ var Tracker = class {
|
|
|
705
708
|
this.configLoaded = options.config !== void 0;
|
|
706
709
|
this.configOverrides = options.configOverrides;
|
|
707
710
|
this.llmProvider = options.llmProvider;
|
|
711
|
+
this.log = options.log;
|
|
708
712
|
this.store = new IsomorphicGitStore({
|
|
709
713
|
workDir: this.workDir,
|
|
710
714
|
gitDir: this.gitDir
|
|
@@ -756,8 +760,8 @@ var Tracker = class {
|
|
|
756
760
|
}
|
|
757
761
|
async diff(options) {
|
|
758
762
|
const to = options.to ?? "HEAD";
|
|
759
|
-
const fromOid =
|
|
760
|
-
const toOid =
|
|
763
|
+
const fromOid = await this.resolveOid(options.from);
|
|
764
|
+
const toOid = await this.resolveOid(to);
|
|
761
765
|
if (!fromOid || !toOid) {
|
|
762
766
|
throw new Error("Could not resolve commit references");
|
|
763
767
|
}
|
|
@@ -772,7 +776,11 @@ var Tracker = class {
|
|
|
772
776
|
});
|
|
773
777
|
}
|
|
774
778
|
async rollback(options) {
|
|
775
|
-
await this.
|
|
779
|
+
const toOid = await this.resolveOid(options.to);
|
|
780
|
+
if (!toOid) {
|
|
781
|
+
throw new Error(`Could not resolve commit: ${options.to}`);
|
|
782
|
+
}
|
|
783
|
+
await this.store.restoreFile(options.file, toOid);
|
|
776
784
|
await this.store.addFiles([options.file]);
|
|
777
785
|
const shortHash = options.to.slice(0, 8);
|
|
778
786
|
const message = generateTemplateMessage([options.file], {
|
|
@@ -810,20 +818,47 @@ var Tracker = class {
|
|
|
810
818
|
const filesToCommit = changed.map((e) => e.filepath);
|
|
811
819
|
await this.store.addFiles(filesToCommit);
|
|
812
820
|
const diffs = [];
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
821
|
+
let headOid = null;
|
|
822
|
+
try {
|
|
823
|
+
headOid = await this.resolveHead();
|
|
824
|
+
} catch {
|
|
825
|
+
}
|
|
826
|
+
if (headOid) {
|
|
827
|
+
for (const file of filesToCommit) {
|
|
828
|
+
try {
|
|
829
|
+
const oldContent = await this.store.readFile(file, headOid) ?? "";
|
|
830
|
+
let newContent;
|
|
831
|
+
try {
|
|
832
|
+
newContent = await import_promises3.default.readFile(
|
|
833
|
+
import_node_path3.default.join(this.workDir, file),
|
|
834
|
+
"utf-8"
|
|
835
|
+
);
|
|
836
|
+
} catch {
|
|
837
|
+
newContent = "";
|
|
838
|
+
}
|
|
839
|
+
const d = computeDiff({
|
|
840
|
+
file,
|
|
841
|
+
fromVersion: headOid.slice(0, 8),
|
|
842
|
+
toVersion: "(staged)",
|
|
843
|
+
oldContent,
|
|
844
|
+
newContent
|
|
845
|
+
});
|
|
846
|
+
if (d.additions > 0 || d.deletions > 0) {
|
|
847
|
+
diffs.push(d);
|
|
848
|
+
}
|
|
849
|
+
} catch {
|
|
818
850
|
}
|
|
819
|
-
} catch {
|
|
820
851
|
}
|
|
821
852
|
}
|
|
822
853
|
let message = null;
|
|
823
854
|
if (this.config.commitMessage.mode === "llm" && diffs.length > 0) {
|
|
824
|
-
message = await generateLlmMessage(diffs, this.llmProvider);
|
|
855
|
+
message = await generateLlmMessage(diffs, this.llmProvider, this.log);
|
|
825
856
|
}
|
|
826
857
|
if (!message) {
|
|
858
|
+
if (this.config.commitMessage.mode === "llm" && this.log?.warn) {
|
|
859
|
+
const reason = diffs.length === 0 ? "No diff available (first commit or no file changes), using template" : "LLM failed, falling back to template";
|
|
860
|
+
this.log.warn(`[mindkeeper] ${reason}`);
|
|
861
|
+
}
|
|
827
862
|
message = generateTemplateMessage(filesToCommit);
|
|
828
863
|
}
|
|
829
864
|
const oid = await this.store.commit(message);
|
|
@@ -890,6 +925,27 @@ var Tracker = class {
|
|
|
890
925
|
ref: "HEAD"
|
|
891
926
|
});
|
|
892
927
|
}
|
|
928
|
+
/**
|
|
929
|
+
* Resolves a ref (HEAD, short hash, or full oid) to a full commit oid.
|
|
930
|
+
* Uses expandOid for short hashes since isomorphic-git readBlob may not support them.
|
|
931
|
+
*/
|
|
932
|
+
async resolveOid(ref) {
|
|
933
|
+
if (ref === "HEAD") {
|
|
934
|
+
return this.resolveHead();
|
|
935
|
+
}
|
|
936
|
+
const git2 = await import("isomorphic-git");
|
|
937
|
+
const fs2 = await import("node:fs");
|
|
938
|
+
try {
|
|
939
|
+
return await git2.default.expandOid({
|
|
940
|
+
fs: fs2.default,
|
|
941
|
+
dir: this.workDir,
|
|
942
|
+
gitdir: this.gitDir,
|
|
943
|
+
oid: ref
|
|
944
|
+
});
|
|
945
|
+
} catch {
|
|
946
|
+
return null;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
893
949
|
async ensureGitignore() {
|
|
894
950
|
const gitignorePath = import_node_path3.default.join(this.workDir, ".gitignore");
|
|
895
951
|
const entry = ".mindkeeper/";
|
|
@@ -1246,7 +1302,8 @@ function createWatcherService(api, trackerRef) {
|
|
|
1246
1302
|
const tracker = new Tracker({
|
|
1247
1303
|
workDir: workspaceDir,
|
|
1248
1304
|
llmProvider: llmProvider ?? void 0,
|
|
1249
|
-
configOverrides: api.pluginConfig
|
|
1305
|
+
configOverrides: api.pluginConfig,
|
|
1306
|
+
log
|
|
1250
1307
|
});
|
|
1251
1308
|
await tracker.init();
|
|
1252
1309
|
trackerRef.current = tracker;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mindkeeper-openclaw",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.30",
|
|
4
4
|
"description": "OpenClaw plugin for mindkeeper: auto-snapshot, diff, and rollback for agent context files",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"openclaw",
|
|
@@ -29,14 +29,6 @@
|
|
|
29
29
|
"scripts/postinstall-merge-config.cjs",
|
|
30
30
|
"README.md"
|
|
31
31
|
],
|
|
32
|
-
"scripts": {
|
|
33
|
-
"build": "node build.mjs",
|
|
34
|
-
"test": "vitest run",
|
|
35
|
-
"typecheck": "tsc --noEmit",
|
|
36
|
-
"clean": "rm -rf dist",
|
|
37
|
-
"prepublishOnly": "npm run clean && npm run build",
|
|
38
|
-
"postinstall": "node scripts/postinstall-merge-config.cjs"
|
|
39
|
-
},
|
|
40
32
|
"openclaw": {
|
|
41
33
|
"extensions": [
|
|
42
34
|
"./dist/index.js"
|
|
@@ -59,5 +51,12 @@
|
|
|
59
51
|
},
|
|
60
52
|
"publishConfig": {
|
|
61
53
|
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "node build.mjs",
|
|
57
|
+
"test": "vitest run",
|
|
58
|
+
"typecheck": "tsc --noEmit",
|
|
59
|
+
"clean": "rm -rf dist",
|
|
60
|
+
"postinstall": "node scripts/postinstall-merge-config.cjs"
|
|
62
61
|
}
|
|
63
|
-
}
|
|
62
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mindkeeper
|
|
3
3
|
description: Time Machine for Your AI's Brain — version control for agent context files. Use when the user asks about changes in SOUL.md, AGENTS.md, MEMORY.md, or other agent context files; when they want to undo, rollback, or compare versions; or when they need a checkpoint before risky edits.
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.7
|
|
5
5
|
homepage: https://github.com/seekcontext/mindkeeper
|
|
6
6
|
repository: https://github.com/seekcontext/mindkeeper
|
|
7
7
|
---
|
|
@@ -102,6 +102,7 @@ mind_history({ file: "SOUL.md", limit: 20 })
|
|
|
102
102
|
### mind_diff
|
|
103
103
|
Compares two versions of a file. `from` and `to` are short or full commit hashes from `mind_history`.
|
|
104
104
|
- Omit `to` to compare `from` against the current version (HEAD).
|
|
105
|
+
- **To see what changed in the latest commit**: use `from: entries[1].oid` (the parent) and `to: entries[0].oid` or omit `to` for HEAD. Do NOT use `from: entries[0].oid` with `to: HEAD` — that compares the same commit to itself and yields an empty diff.
|
|
105
106
|
|
|
106
107
|
```
|
|
107
108
|
mind_diff({ file: "SOUL.md", from: "a1b2c3d4" })
|