@sdotwinter/openclaw-deterministic 0.7.0 → 0.9.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/doctor.js +114 -46
- package/bin/install.js +48 -24
- package/package.json +1 -1
package/bin/doctor.js
CHANGED
|
@@ -5,6 +5,9 @@ const path = require("path");
|
|
|
5
5
|
|
|
6
6
|
const pkg = require("../package.json");
|
|
7
7
|
|
|
8
|
+
const args = process.argv.slice(2);
|
|
9
|
+
const JSON_MODE = args.includes("--json");
|
|
10
|
+
|
|
8
11
|
const HOME = process.env.HOME;
|
|
9
12
|
const openclawRoot = path.join(HOME, ".openclaw");
|
|
10
13
|
const workspace = path.join(openclawRoot, "workspace");
|
|
@@ -34,27 +37,6 @@ function versionFromFile(content) {
|
|
|
34
37
|
return match ? match[1] : null;
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
function checkVersion(filePath, label) {
|
|
38
|
-
if (!exists(filePath)) {
|
|
39
|
-
console.log(`❌ ${label} missing.`);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const content = read(filePath);
|
|
44
|
-
const version = versionFromFile(content);
|
|
45
|
-
|
|
46
|
-
if (!version) {
|
|
47
|
-
console.log(`⚠ ${label} version stamp missing.`);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (version === pkg.version) {
|
|
52
|
-
console.log(`✅ ${label} version matches CLI (${version})`);
|
|
53
|
-
} else {
|
|
54
|
-
console.log(`⚠ ${label} version mismatch (installed ${version}, CLI ${pkg.version})`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
40
|
function overlayEnabled() {
|
|
59
41
|
if (!exists(files.soul)) return false;
|
|
60
42
|
const content = read(files.soul);
|
|
@@ -76,43 +58,129 @@ function estimateSemanticTokens() {
|
|
|
76
58
|
return Math.ceil(content.length / 4);
|
|
77
59
|
}
|
|
78
60
|
|
|
79
|
-
|
|
61
|
+
function evaluateVersion(filePath) {
|
|
62
|
+
if (!exists(filePath)) {
|
|
63
|
+
return { status: "missing", version: null };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const content = read(filePath);
|
|
67
|
+
const version = versionFromFile(content);
|
|
68
|
+
|
|
69
|
+
if (!version) {
|
|
70
|
+
return { status: "no-stamp", version: null };
|
|
71
|
+
}
|
|
80
72
|
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
if (version === pkg.version) {
|
|
74
|
+
return { status: "match", version };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { status: "mismatch", version };
|
|
84
78
|
}
|
|
85
79
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
function evaluate() {
|
|
81
|
+
const result = {
|
|
82
|
+
cliVersion: pkg.version,
|
|
83
|
+
openclawDetected: exists(openclawRoot),
|
|
84
|
+
workspaceDetected: exists(workspace),
|
|
85
|
+
files: {},
|
|
86
|
+
overlayEnabled: false,
|
|
87
|
+
semanticTokens: 0,
|
|
88
|
+
semanticStatus: "safe",
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (!result.openclawDetected || !result.workspaceDetected) {
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
result.files.operating = evaluateVersion(files.operating);
|
|
96
|
+
result.files.detSoul = evaluateVersion(files.detSoul);
|
|
97
|
+
result.files.compactor = evaluateVersion(files.compactor);
|
|
98
|
+
|
|
99
|
+
result.overlayEnabled = overlayEnabled();
|
|
100
|
+
|
|
101
|
+
const tokens = estimateSemanticTokens();
|
|
102
|
+
result.semanticTokens = tokens;
|
|
103
|
+
|
|
104
|
+
if (tokens > 1200) {
|
|
105
|
+
result.semanticStatus = "hard-limit-exceeded";
|
|
106
|
+
} else if (tokens > 1020) {
|
|
107
|
+
result.semanticStatus = "risk-threshold";
|
|
108
|
+
} else {
|
|
109
|
+
result.semanticStatus = "safe";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return result;
|
|
89
113
|
}
|
|
90
114
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
115
|
+
function printHuman(result) {
|
|
116
|
+
console.log("\nRunning deterministic doctor...\n");
|
|
117
|
+
|
|
118
|
+
if (!result.openclawDetected) {
|
|
119
|
+
console.log("❌ OpenClaw directory not found.");
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!result.workspaceDetected) {
|
|
124
|
+
console.log("❌ Workspace missing.");
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
for (const [name, info] of Object.entries(result.files)) {
|
|
129
|
+
const label =
|
|
130
|
+
name === "operating"
|
|
131
|
+
? "OPERATING_RULES.md"
|
|
132
|
+
: name === "detSoul"
|
|
133
|
+
? "SOUL.deterministic.md"
|
|
134
|
+
: "memory-compactor SKILL.md";
|
|
135
|
+
|
|
136
|
+
if (info.status === "missing") {
|
|
137
|
+
console.log(`❌ ${label} missing.`);
|
|
138
|
+
} else if (info.status === "no-stamp") {
|
|
139
|
+
console.log(`⚠ ${label} version stamp missing.`);
|
|
140
|
+
} else if (info.status === "mismatch") {
|
|
141
|
+
console.log(
|
|
142
|
+
`⚠ ${label} version mismatch (installed ${info.version}, CLI ${pkg.version})`
|
|
143
|
+
);
|
|
144
|
+
} else {
|
|
145
|
+
console.log(`✅ ${label} version matches CLI (${info.version})`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
94
148
|
|
|
95
|
-
if (exists(files.soul)) {
|
|
96
149
|
console.log("✅ SOUL.md present.");
|
|
97
|
-
|
|
98
|
-
|
|
150
|
+
console.log(
|
|
151
|
+
result.overlayEnabled
|
|
152
|
+
? "✅ Deterministic overlay ENABLED in SOUL.md."
|
|
153
|
+
: "⚠ Deterministic overlay NOT enabled in SOUL.md."
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
console.log(`\nSemantic memory tokens (est): ${result.semanticTokens}`);
|
|
157
|
+
|
|
158
|
+
if (result.semanticStatus === "hard-limit-exceeded") {
|
|
159
|
+
console.log("❌ Semantic memory exceeds HARD_LIMIT (1200).");
|
|
160
|
+
} else if (result.semanticStatus === "risk-threshold") {
|
|
161
|
+
console.log("⚠ Semantic memory above risk threshold (1020).");
|
|
99
162
|
} else {
|
|
100
|
-
console.log("
|
|
163
|
+
console.log("✅ Semantic memory within safe bounds.");
|
|
101
164
|
}
|
|
102
|
-
|
|
103
|
-
console.log("
|
|
165
|
+
|
|
166
|
+
console.log("\nDoctor complete.\n");
|
|
104
167
|
}
|
|
105
168
|
|
|
106
|
-
const
|
|
107
|
-
|
|
169
|
+
const result = evaluate();
|
|
170
|
+
|
|
171
|
+
if (JSON_MODE) {
|
|
172
|
+
console.log(JSON.stringify(result, null, 2));
|
|
173
|
+
|
|
174
|
+
if (!result.openclawDetected || !result.workspaceDetected) {
|
|
175
|
+
process.exit(2);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (result.semanticStatus === "hard-limit-exceeded") {
|
|
179
|
+
process.exit(3);
|
|
180
|
+
}
|
|
108
181
|
|
|
109
|
-
|
|
110
|
-
console.log("❌ Semantic memory exceeds HARD_LIMIT (1200).");
|
|
111
|
-
} else if (semanticTokens > 1020) {
|
|
112
|
-
console.log("⚠ Semantic memory above risk threshold (1020).");
|
|
113
|
-
} else {
|
|
114
|
-
console.log("✅ Semantic memory within safe bounds.");
|
|
182
|
+
process.exit(0);
|
|
115
183
|
}
|
|
116
184
|
|
|
117
|
-
|
|
185
|
+
printHuman(result);
|
|
118
186
|
process.exit(0);
|
package/bin/install.js
CHANGED
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const path = require("path");
|
|
5
5
|
|
|
6
|
+
const pkg = require("../package.json");
|
|
7
|
+
|
|
6
8
|
const HOME = process.env.HOME;
|
|
7
9
|
const openclawRoot = path.join(HOME, ".openclaw");
|
|
8
10
|
const workspace = path.join(openclawRoot, "workspace");
|
|
9
11
|
const backupsRoot = path.join(openclawRoot, "backups", "deterministic");
|
|
10
12
|
|
|
11
|
-
const
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const DRY_RUN = args.includes("--dry-run");
|
|
12
15
|
|
|
13
16
|
const tpl = (name) => path.join(__dirname, "..", "templates", name);
|
|
14
17
|
|
|
@@ -35,10 +38,16 @@ function exists(p) {
|
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
function ensureDir(p) {
|
|
38
|
-
|
|
41
|
+
if (!DRY_RUN) {
|
|
42
|
+
fs.mkdirSync(p, { recursive: true });
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
function writeFile(p, content) {
|
|
47
|
+
if (DRY_RUN) {
|
|
48
|
+
console.log(`[DRY-RUN] Would write: ${p}`);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
42
51
|
ensureDir(path.dirname(p));
|
|
43
52
|
fs.writeFileSync(p, content);
|
|
44
53
|
}
|
|
@@ -47,6 +56,11 @@ function copyWithVersionStamp(templatePath, targetPath) {
|
|
|
47
56
|
const versionStamp = `<!-- Installed by openclaw-deterministic v${pkg.version} -->\n`;
|
|
48
57
|
const content = fs.readFileSync(templatePath, "utf8");
|
|
49
58
|
const stamped = versionStamp + content;
|
|
59
|
+
|
|
60
|
+
if (DRY_RUN) {
|
|
61
|
+
console.log(`[DRY-RUN] Would install: ${targetPath}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
50
64
|
writeFile(targetPath, stamped);
|
|
51
65
|
}
|
|
52
66
|
|
|
@@ -55,14 +69,21 @@ function timestamp() {
|
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
function backupSnapshot(pathsToBackup) {
|
|
72
|
+
if (DRY_RUN) {
|
|
73
|
+
console.log("[DRY-RUN] Would create backup snapshot.");
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
58
77
|
ensureDir(backupsRoot);
|
|
59
78
|
const snap = path.join(backupsRoot, timestamp());
|
|
60
79
|
ensureDir(snap);
|
|
61
80
|
|
|
62
81
|
for (const p of pathsToBackup) {
|
|
63
82
|
if (!exists(p)) continue;
|
|
83
|
+
|
|
64
84
|
const relative = path.relative(openclawRoot, p);
|
|
65
85
|
const destination = path.join(snap, relative);
|
|
86
|
+
|
|
66
87
|
ensureDir(path.dirname(destination));
|
|
67
88
|
fs.copyFileSync(p, destination);
|
|
68
89
|
}
|
|
@@ -71,23 +92,9 @@ function backupSnapshot(pathsToBackup) {
|
|
|
71
92
|
}
|
|
72
93
|
|
|
73
94
|
function installTemplates() {
|
|
74
|
-
copyWithVersionStamp(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
);
|
|
78
|
-
console.log("Installed: OPERATING_RULES.md");
|
|
79
|
-
|
|
80
|
-
copyWithVersionStamp(
|
|
81
|
-
tpl("SOUL.deterministic.md"),
|
|
82
|
-
target.detSoul
|
|
83
|
-
);
|
|
84
|
-
console.log("Installed: SOUL.deterministic.md");
|
|
85
|
-
|
|
86
|
-
copyWithVersionStamp(
|
|
87
|
-
tpl("memory-compactor.SKILL.md"),
|
|
88
|
-
target.compactor
|
|
89
|
-
);
|
|
90
|
-
console.log("Installed: skills/memory-compactor/SKILL.md");
|
|
95
|
+
copyWithVersionStamp(tpl("OPERATING_RULES.md"), target.operating);
|
|
96
|
+
copyWithVersionStamp(tpl("SOUL.deterministic.md"), target.detSoul);
|
|
97
|
+
copyWithVersionStamp(tpl("memory-compactor.SKILL.md"), target.compactor);
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
function bootstrapSoulIfMissing() {
|
|
@@ -97,33 +104,50 @@ function bootstrapSoulIfMissing() {
|
|
|
97
104
|
}
|
|
98
105
|
|
|
99
106
|
console.log("No SOUL.md detected — bootstrapping fresh SOUL.md with deterministic overlay.");
|
|
107
|
+
|
|
108
|
+
if (DRY_RUN) {
|
|
109
|
+
console.log("[DRY-RUN] Would create SOUL.md with deterministic overlay.");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
100
113
|
writeFile(target.soul, OVERLAY_BLOCK.trim() + "\n");
|
|
101
114
|
console.log("Created: SOUL.md (deterministic overlay enabled by default)");
|
|
102
115
|
}
|
|
103
116
|
|
|
104
117
|
if (!exists(openclawRoot)) {
|
|
105
118
|
console.error("OpenClaw not found at ~/.openclaw");
|
|
106
|
-
console.error("Install OpenClaw first, then rerun oc-deterministic install.");
|
|
107
119
|
process.exit(1);
|
|
108
120
|
}
|
|
109
121
|
|
|
110
122
|
if (!exists(workspace)) {
|
|
111
123
|
console.error("OpenClaw workspace missing at ~/.openclaw/workspace");
|
|
112
|
-
console.error("OpenClaw may not be fully initialized. Run `openclaw onboard` then retry.");
|
|
113
124
|
process.exit(1);
|
|
114
125
|
}
|
|
115
126
|
|
|
116
|
-
|
|
127
|
+
if (DRY_RUN) {
|
|
128
|
+
console.log("\nRunning deterministic install (dry-run mode)...\n");
|
|
129
|
+
} else {
|
|
130
|
+
console.log("Creating deterministic backup snapshot...");
|
|
131
|
+
}
|
|
132
|
+
|
|
117
133
|
const snap = backupSnapshot([
|
|
118
134
|
target.operating,
|
|
119
135
|
target.detSoul,
|
|
120
136
|
target.soul,
|
|
121
137
|
target.compactor,
|
|
122
138
|
]);
|
|
123
|
-
|
|
139
|
+
|
|
140
|
+
if (snap) {
|
|
141
|
+
console.log(`Backup location: ${snap}`);
|
|
142
|
+
}
|
|
124
143
|
|
|
125
144
|
installTemplates();
|
|
126
145
|
bootstrapSoulIfMissing();
|
|
127
146
|
|
|
128
|
-
|
|
147
|
+
if (DRY_RUN) {
|
|
148
|
+
console.log("\nDry-run complete. No changes were written.\n");
|
|
149
|
+
} else {
|
|
150
|
+
console.log("\nDeterministic governance installed successfully.\n");
|
|
151
|
+
}
|
|
152
|
+
|
|
129
153
|
process.exit(0);
|