@sdotwinter/openclaw-deterministic 0.11.0 → 0.13.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/install.js
CHANGED
|
@@ -1,70 +1,93 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require("fs");
|
|
4
|
+
const os = require("os");
|
|
4
5
|
const path = require("path");
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const openclawRoot = path.join(HOME, ".openclaw");
|
|
10
|
-
const workspace = path.join(openclawRoot, "workspace");
|
|
11
|
-
const backupsRoot = path.join(openclawRoot, "backups", "deterministic");
|
|
12
|
-
|
|
7
|
+
// -----------------------------
|
|
8
|
+
// Args
|
|
9
|
+
// -----------------------------
|
|
13
10
|
const args = process.argv.slice(2);
|
|
14
11
|
const DRY_RUN = args.includes("--dry-run");
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
// -----------------------------
|
|
14
|
+
// Version + markers
|
|
15
|
+
// -----------------------------
|
|
16
|
+
const pkg = require(path.join(__dirname, "..", "package.json"));
|
|
17
|
+
const CLI_VERSION = pkg.version;
|
|
18
|
+
|
|
19
|
+
const VERSION_STAMP = `<!-- Installed by openclaw-deterministic v${CLI_VERSION} -->`;
|
|
20
|
+
|
|
21
|
+
// NOTE: This block is intentionally minimal and deterministic.
|
|
22
|
+
// It only declares the overlay and does not replace user SOUL content.
|
|
23
|
+
const OVERLAY_BLOCK = `
|
|
24
|
+
## Deterministic Governance Overlay
|
|
25
|
+
|
|
26
|
+
This system loads and adheres to SOUL.deterministic.md as a governing philosophical constraint.
|
|
27
|
+
`.trim();
|
|
28
|
+
|
|
29
|
+
// -----------------------------
|
|
30
|
+
// Paths
|
|
31
|
+
// -----------------------------
|
|
32
|
+
const home = os.homedir();
|
|
33
|
+
const openclawRoot = path.join(home, ".openclaw");
|
|
34
|
+
const workspace = path.join(openclawRoot, "workspace");
|
|
35
|
+
|
|
36
|
+
const backupsRoot = path.join(openclawRoot, "backups", "deterministic");
|
|
17
37
|
|
|
18
38
|
const target = {
|
|
19
39
|
operating: path.join(workspace, "OPERATING_RULES.md"),
|
|
20
40
|
detSoul: path.join(workspace, "SOUL.deterministic.md"),
|
|
21
41
|
soul: path.join(workspace, "SOUL.md"),
|
|
22
42
|
compactor: path.join(workspace, "skills", "memory-compactor", "SKILL.md"),
|
|
43
|
+
config: path.join(openclawRoot, ".deterministic.json"),
|
|
23
44
|
};
|
|
24
45
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
This system loads and adheres to SOUL.deterministic.md as a governing philosophical constraint.
|
|
29
|
-
`;
|
|
46
|
+
function tpl(rel) {
|
|
47
|
+
return path.join(__dirname, "..", "templates", rel);
|
|
48
|
+
}
|
|
30
49
|
|
|
50
|
+
const configTemplatePath = path.join(
|
|
51
|
+
__dirname,
|
|
52
|
+
"..",
|
|
53
|
+
"templates",
|
|
54
|
+
"config",
|
|
55
|
+
".deterministic.json"
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
// -----------------------------
|
|
59
|
+
// Helpers
|
|
60
|
+
// -----------------------------
|
|
31
61
|
function exists(p) {
|
|
32
62
|
try {
|
|
33
|
-
fs.accessSync(p);
|
|
63
|
+
fs.accessSync(p, fs.constants.F_OK);
|
|
34
64
|
return true;
|
|
35
65
|
} catch {
|
|
36
66
|
return false;
|
|
37
67
|
}
|
|
38
68
|
}
|
|
39
69
|
|
|
40
|
-
function ensureDir(
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
}
|
|
70
|
+
function ensureDir(dirPath) {
|
|
71
|
+
if (exists(dirPath)) return;
|
|
72
|
+
if (DRY_RUN) return;
|
|
73
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
44
74
|
}
|
|
45
75
|
|
|
46
76
|
function writeFile(p, content) {
|
|
77
|
+
ensureDir(path.dirname(p));
|
|
47
78
|
if (DRY_RUN) {
|
|
48
79
|
console.log(`[DRY-RUN] Would write: ${p}`);
|
|
49
80
|
return;
|
|
50
81
|
}
|
|
51
|
-
|
|
52
|
-
fs.writeFileSync(p, content);
|
|
82
|
+
fs.writeFileSync(p, content, "utf8");
|
|
53
83
|
}
|
|
54
84
|
|
|
55
|
-
function
|
|
56
|
-
|
|
57
|
-
const content = fs.readFileSync(templatePath, "utf8");
|
|
58
|
-
const stamped = versionStamp + content;
|
|
59
|
-
|
|
60
|
-
if (DRY_RUN) {
|
|
61
|
-
console.log(`[DRY-RUN] Would install: ${targetPath}`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
writeFile(targetPath, stamped);
|
|
85
|
+
function readFile(p) {
|
|
86
|
+
return fs.readFileSync(p, "utf8");
|
|
65
87
|
}
|
|
66
88
|
|
|
67
89
|
function timestamp() {
|
|
90
|
+
// keep filesystem-safe
|
|
68
91
|
return new Date().toISOString().replace(/:/g, "-");
|
|
69
92
|
}
|
|
70
93
|
|
|
@@ -91,29 +114,79 @@ function backupSnapshot(pathsToBackup) {
|
|
|
91
114
|
return snap;
|
|
92
115
|
}
|
|
93
116
|
|
|
117
|
+
function copyWithVersionStamp(src, dest) {
|
|
118
|
+
const raw = readFile(src);
|
|
119
|
+
const stamped = `${VERSION_STAMP}\n${raw.replace(/^\uFEFF/, "")}`;
|
|
120
|
+
writeFile(dest, stamped);
|
|
121
|
+
|
|
122
|
+
if (!DRY_RUN) {
|
|
123
|
+
// keep output consistent with your CLI style
|
|
124
|
+
const pretty = dest.startsWith(workspace)
|
|
125
|
+
? dest.replace(workspace + path.sep, "")
|
|
126
|
+
: dest;
|
|
127
|
+
console.log(`Installed: ${pretty}`);
|
|
128
|
+
} else {
|
|
129
|
+
console.log(`[DRY-RUN] Would install: ${dest}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// -----------------------------
|
|
134
|
+
// Install steps
|
|
135
|
+
// -----------------------------
|
|
94
136
|
function installTemplates() {
|
|
137
|
+
// Ensure skill directory exists
|
|
138
|
+
ensureDir(path.dirname(target.compactor));
|
|
139
|
+
|
|
95
140
|
copyWithVersionStamp(tpl("OPERATING_RULES.md"), target.operating);
|
|
96
141
|
copyWithVersionStamp(tpl("SOUL.deterministic.md"), target.detSoul);
|
|
97
142
|
copyWithVersionStamp(tpl("memory-compactor.SKILL.md"), target.compactor);
|
|
98
143
|
}
|
|
99
144
|
|
|
145
|
+
function installConfigIfMissing() {
|
|
146
|
+
if (exists(target.config)) {
|
|
147
|
+
console.log("Config exists — NOT modified.");
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!exists(configTemplatePath)) {
|
|
152
|
+
console.error(
|
|
153
|
+
`Config template missing in package: ${configTemplatePath}\n` +
|
|
154
|
+
"Refusing to create an empty config."
|
|
155
|
+
);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (DRY_RUN) {
|
|
160
|
+
console.log(`[DRY-RUN] Would write: ${target.config}`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
fs.copyFileSync(configTemplatePath, target.config);
|
|
165
|
+
console.log(`Installed: ${target.config}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
100
168
|
function bootstrapSoulIfMissing() {
|
|
101
169
|
if (exists(target.soul)) {
|
|
102
170
|
console.log("User SOUL.md exists — NOT modified.");
|
|
103
171
|
return;
|
|
104
172
|
}
|
|
105
173
|
|
|
106
|
-
console.log(
|
|
174
|
+
console.log(
|
|
175
|
+
"No SOUL.md detected — bootstrapping fresh SOUL.md with deterministic overlay."
|
|
176
|
+
);
|
|
107
177
|
|
|
108
178
|
if (DRY_RUN) {
|
|
109
179
|
console.log("[DRY-RUN] Would create SOUL.md with deterministic overlay.");
|
|
110
180
|
return;
|
|
111
181
|
}
|
|
112
182
|
|
|
113
|
-
writeFile(target.soul, OVERLAY_BLOCK
|
|
183
|
+
writeFile(target.soul, OVERLAY_BLOCK + "\n");
|
|
114
184
|
console.log("Created: SOUL.md (deterministic overlay enabled by default)");
|
|
115
185
|
}
|
|
116
186
|
|
|
187
|
+
// -----------------------------
|
|
188
|
+
// Main
|
|
189
|
+
// -----------------------------
|
|
117
190
|
if (!exists(openclawRoot)) {
|
|
118
191
|
console.error("OpenClaw not found at ~/.openclaw");
|
|
119
192
|
process.exit(1);
|
|
@@ -126,28 +199,32 @@ if (!exists(workspace)) {
|
|
|
126
199
|
|
|
127
200
|
if (DRY_RUN) {
|
|
128
201
|
console.log("\nRunning deterministic install (dry-run mode)...\n");
|
|
129
|
-
} else {
|
|
130
|
-
console.log("Creating deterministic backup snapshot...");
|
|
131
202
|
}
|
|
132
203
|
|
|
133
|
-
const
|
|
204
|
+
const pathsToBackup = [
|
|
134
205
|
target.operating,
|
|
135
206
|
target.detSoul,
|
|
136
|
-
target.soul,
|
|
137
207
|
target.compactor,
|
|
138
|
-
|
|
208
|
+
// NOTE: we do NOT back up SOUL.md here because install never modifies it.
|
|
209
|
+
// If you later add an "enable" flow that edits SOUL.md, that command should back it up there.
|
|
210
|
+
target.config,
|
|
211
|
+
];
|
|
212
|
+
|
|
213
|
+
const snap = backupSnapshot(pathsToBackup);
|
|
139
214
|
|
|
140
|
-
if (
|
|
215
|
+
if (!DRY_RUN) {
|
|
216
|
+
console.log("Creating deterministic backup snapshot...");
|
|
141
217
|
console.log(`Backup location: ${snap}`);
|
|
142
218
|
}
|
|
143
219
|
|
|
144
220
|
installTemplates();
|
|
221
|
+
installConfigIfMissing();
|
|
145
222
|
bootstrapSoulIfMissing();
|
|
146
223
|
|
|
147
224
|
if (DRY_RUN) {
|
|
148
225
|
console.log("\nDry-run complete. No changes were written.\n");
|
|
149
226
|
} else {
|
|
150
|
-
console.log("\nDeterministic governance installed successfully
|
|
227
|
+
console.log("\nDeterministic governance installed successfully.");
|
|
151
228
|
}
|
|
152
229
|
|
|
153
230
|
process.exit(0);
|
package/package.json
CHANGED