@sdotwinter/openclaw-deterministic 0.1.2 → 0.1.3
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/doctor.js +43 -30
- package/bin/install.js +71 -66
- package/bin/revert.js +58 -0
- package/package.json +1 -1
package/bin/doctor.js
CHANGED
|
@@ -1,46 +1,59 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require("fs");
|
|
4
|
-
const os = require("os");
|
|
5
4
|
const path = require("path");
|
|
5
|
+
const os = require("os");
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const pkg = require("../package.json");
|
|
8
|
+
|
|
9
|
+
const OPENCLAW_DIR = path.join(os.homedir(), ".openclaw");
|
|
9
10
|
const WORKSPACE_DIR = path.join(OPENCLAW_DIR, "workspace");
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
function checkFile(filePath, label) {
|
|
13
|
+
if (!fs.existsSync(filePath)) {
|
|
14
|
+
console.log(`❌ Missing: ${label}`);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
console.log("❌ ~/.openclaw not found.");
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
18
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
17
19
|
|
|
18
|
-
if (!
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
if (!content.includes("Installed by openclaw-deterministic")) {
|
|
21
|
+
console.log(`⚠️ ${label} exists but is not deterministic-managed.`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!content.includes(`v${pkg.version}`)) {
|
|
26
|
+
console.log(`⚠️ ${label} version drift detected.`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
console.log(`✅ ${label} OK (v${pkg.version})`);
|
|
21
31
|
}
|
|
22
32
|
|
|
23
|
-
|
|
24
|
-
console.log("
|
|
33
|
+
function runDoctor() {
|
|
34
|
+
console.log("Running deterministic doctor...\n");
|
|
25
35
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
);
|
|
36
|
+
if (!fs.existsSync(OPENCLAW_DIR)) {
|
|
37
|
+
console.log("❌ OpenClaw not installed.");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
29
40
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
checkFile(
|
|
42
|
+
path.join(WORKSPACE_DIR, "OPERATING_RULES.md"),
|
|
43
|
+
"OPERATING_RULES.md"
|
|
44
|
+
);
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
);
|
|
46
|
+
checkFile(
|
|
47
|
+
path.join(WORKSPACE_DIR, "SOUL.deterministic.md"),
|
|
48
|
+
"SOUL.deterministic.md"
|
|
49
|
+
);
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
51
|
+
checkFile(
|
|
52
|
+
path.join(WORKSPACE_DIR, "skills", "memory-compactor", "SKILL.md"),
|
|
53
|
+
"memory-compactor SKILL.md"
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
console.log("\nDoctor complete.");
|
|
57
|
+
}
|
|
45
58
|
|
|
46
|
-
|
|
59
|
+
runDoctor();
|
package/bin/install.js
CHANGED
|
@@ -4,95 +4,100 @@ const fs = require("fs");
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
const OPENCLAW_DIR = path.join(HOME, ".openclaw");
|
|
9
|
-
const WORKSPACE_DIR = path.join(OPENCLAW_DIR, "workspace");
|
|
10
|
-
const TEMPLATE_DIR = path.join(__dirname, "..", "templates");
|
|
11
|
-
|
|
12
|
-
function log(msg) {
|
|
13
|
-
console.log(msg);
|
|
14
|
-
}
|
|
7
|
+
const pkg = require("../package.json");
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
9
|
+
const OPENCLAW_DIR = path.join(os.homedir(), ".openclaw");
|
|
10
|
+
const WORKSPACE_DIR = path.join(OPENCLAW_DIR, "workspace");
|
|
11
|
+
const BACKUP_ROOT = path.join(OPENCLAW_DIR, "backups", "deterministic");
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
return fs.existsSync(p);
|
|
23
|
-
}
|
|
13
|
+
const TEMPLATES_DIR = path.join(__dirname, "..", "templates");
|
|
24
14
|
|
|
25
|
-
function ensureDir(
|
|
26
|
-
if (!
|
|
27
|
-
fs.mkdirSync(
|
|
15
|
+
function ensureDir(dir) {
|
|
16
|
+
if (!fs.existsSync(dir)) {
|
|
17
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
28
18
|
}
|
|
29
19
|
}
|
|
30
20
|
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
fs.copyFileSync(src, dest);
|
|
34
|
-
log(`✅ Installed: ${path.basename(dest)}`);
|
|
35
|
-
} else {
|
|
36
|
-
log(`⚠️ Skipped (already exists): ${path.basename(dest)}`);
|
|
37
|
-
}
|
|
21
|
+
function timestamp() {
|
|
22
|
+
return new Date().toISOString().replace(/:/g, "-");
|
|
38
23
|
}
|
|
39
24
|
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const dest = path.join(backupDir, filename);
|
|
45
|
-
fs.copyFileSync(filePath, dest);
|
|
46
|
-
log(`🗂️ Backed up: ${filename}`);
|
|
47
|
-
}
|
|
25
|
+
function addHeader(content) {
|
|
26
|
+
const header =
|
|
27
|
+
`# Installed by openclaw-deterministic v${pkg.version}
|
|
28
|
+
# Installed at: ${new Date().toISOString()}
|
|
48
29
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return now.toISOString().replace(/[:.]/g, "-");
|
|
30
|
+
`;
|
|
31
|
+
return header + content;
|
|
52
32
|
}
|
|
53
33
|
|
|
54
|
-
function
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (!exists(WORKSPACE_DIR)) {
|
|
60
|
-
exitWith("❌ OpenClaw workspace not detected.\nExpected directory: " + WORKSPACE_DIR);
|
|
34
|
+
function backupFile(filePath, backupDir) {
|
|
35
|
+
if (fs.existsSync(filePath)) {
|
|
36
|
+
const fileName = path.basename(filePath);
|
|
37
|
+
fs.copyFileSync(filePath, path.join(backupDir, fileName));
|
|
61
38
|
}
|
|
62
39
|
}
|
|
63
40
|
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
validateWorkspace();
|
|
41
|
+
function installFile(templateName, targetPath, backupDir) {
|
|
42
|
+
const templatePath = path.join(TEMPLATES_DIR, templateName);
|
|
68
43
|
|
|
69
|
-
|
|
70
|
-
|
|
44
|
+
if (!fs.existsSync(templatePath)) {
|
|
45
|
+
console.error(`Template not found: ${templateName}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
71
48
|
|
|
72
|
-
|
|
73
|
-
backupFile(path.join(WORKSPACE_DIR, "OPERATING_RULES.md"), backupDir);
|
|
74
|
-
backupFile(path.join(WORKSPACE_DIR, "SOUL.md"), backupDir);
|
|
49
|
+
backupFile(targetPath, backupDir);
|
|
75
50
|
|
|
76
|
-
|
|
51
|
+
const templateContent = fs.readFileSync(templatePath, "utf8");
|
|
52
|
+
const stampedContent = addHeader(templateContent);
|
|
77
53
|
|
|
78
|
-
|
|
79
|
-
const operatingSrc = path.join(TEMPLATE_DIR, "OPERATING_RULES.md");
|
|
80
|
-
const operatingDest = path.join(WORKSPACE_DIR, "OPERATING_RULES.md");
|
|
81
|
-
copyFileSafe(operatingSrc, operatingDest);
|
|
54
|
+
fs.writeFileSync(targetPath, stampedContent, "utf8");
|
|
82
55
|
|
|
83
|
-
log(
|
|
56
|
+
console.log(`Installed: ${targetPath}`);
|
|
57
|
+
}
|
|
84
58
|
|
|
85
|
-
|
|
86
|
-
|
|
59
|
+
function runInstall() {
|
|
60
|
+
if (!fs.existsSync(OPENCLAW_DIR)) {
|
|
61
|
+
console.error("OpenClaw directory not found.");
|
|
62
|
+
console.error("Install OpenClaw first: npm i -g openclaw && openclaw onboard");
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
87
65
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
copyFileSafe(skillSrc, skillDest);
|
|
66
|
+
ensureDir(WORKSPACE_DIR);
|
|
67
|
+
ensureDir(BACKUP_ROOT);
|
|
91
68
|
|
|
92
|
-
|
|
93
|
-
|
|
69
|
+
const backupDir = path.join(BACKUP_ROOT, timestamp());
|
|
70
|
+
ensureDir(backupDir);
|
|
94
71
|
|
|
95
|
-
log("
|
|
72
|
+
console.log("Creating deterministic backup snapshot...");
|
|
73
|
+
console.log(`Backup location: ${backupDir}`);
|
|
74
|
+
|
|
75
|
+
// Install OPERATING_RULES.md
|
|
76
|
+
installFile(
|
|
77
|
+
"OPERATING_RULES.md",
|
|
78
|
+
path.join(WORKSPACE_DIR, "OPERATING_RULES.md"),
|
|
79
|
+
backupDir
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Install deterministic SOUL overlay
|
|
83
|
+
installFile(
|
|
84
|
+
"SOUL.deterministic.md",
|
|
85
|
+
path.join(WORKSPACE_DIR, "SOUL.deterministic.md"),
|
|
86
|
+
backupDir
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// Install memory-compactor skill
|
|
90
|
+
const skillsDir = path.join(WORKSPACE_DIR, "skills", "memory-compactor");
|
|
91
|
+
ensureDir(skillsDir);
|
|
92
|
+
|
|
93
|
+
installFile(
|
|
94
|
+
"memory-compactor.SKILL.md",
|
|
95
|
+
path.join(skillsDir, "SKILL.md"),
|
|
96
|
+
backupDir
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
console.log("\nDeterministic governance installed successfully.");
|
|
100
|
+
console.log("User SOUL.md was NOT modified.");
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
runInstall();
|
package/bin/revert.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const os = require("os");
|
|
6
|
+
|
|
7
|
+
const OPENCLAW_DIR = path.join(os.homedir(), ".openclaw");
|
|
8
|
+
const WORKSPACE_DIR = path.join(OPENCLAW_DIR, "workspace");
|
|
9
|
+
const BACKUP_ROOT = path.join(OPENCLAW_DIR, "backups", "deterministic");
|
|
10
|
+
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
|
|
13
|
+
function listBackups() {
|
|
14
|
+
if (!fs.existsSync(BACKUP_ROOT)) {
|
|
15
|
+
console.log("No backups found.");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const dirs = fs.readdirSync(BACKUP_ROOT);
|
|
20
|
+
if (dirs.length === 0) {
|
|
21
|
+
console.log("No backups found.");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.log("Available backups:");
|
|
26
|
+
dirs.forEach(d => console.log(`- ${d}`));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function restoreBackup(timestamp) {
|
|
30
|
+
const backupDir = path.join(BACKUP_ROOT, timestamp);
|
|
31
|
+
|
|
32
|
+
if (!fs.existsSync(backupDir)) {
|
|
33
|
+
console.log("Backup not found.");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const files = fs.readdirSync(backupDir);
|
|
38
|
+
|
|
39
|
+
files.forEach(file => {
|
|
40
|
+
const src = path.join(backupDir, file);
|
|
41
|
+
const dest = path.join(WORKSPACE_DIR, file);
|
|
42
|
+
|
|
43
|
+
fs.copyFileSync(src, dest);
|
|
44
|
+
console.log(`Restored: ${file}`);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
console.log("Revert complete.");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (args[0] === "--list") {
|
|
51
|
+
listBackups();
|
|
52
|
+
} else if (args[0] === "--to" && args[1]) {
|
|
53
|
+
restoreBackup(args[1]);
|
|
54
|
+
} else {
|
|
55
|
+
console.log("Usage:");
|
|
56
|
+
console.log(" oc-deterministic revert --list");
|
|
57
|
+
console.log(" oc-deterministic revert --to <timestamp>");
|
|
58
|
+
}
|