sloppydisk 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/lib/patcher.js CHANGED
@@ -2,30 +2,28 @@ const crypto = require("node:crypto");
2
2
  const fs = require("node:fs");
3
3
  const os = require("node:os");
4
4
  const path = require("node:path");
5
- const { Readable } = require("node:stream");
6
- const { pipeline } = require("node:stream/promises");
7
5
  const { spawnSync } = require("node:child_process");
8
6
 
9
7
  const PACKAGE_ROOT = path.resolve(__dirname, "..");
10
8
  const PACKAGE_JSON = require(path.join(PACKAGE_ROOT, "package.json"));
11
- const WORK_ROOT = path.join(os.homedir(), ".slopex");
9
+ const WORK_ROOT = path.join(os.homedir(), ".sloppydisk");
10
+ const SRC_ROOT = path.join(WORK_ROOT, "src");
12
11
  const BACKUP_ROOT = path.join(WORK_ROOT, "backups");
13
12
  const ARTIFACT_ROOT = path.join(WORK_ROOT, "artifacts");
14
- const BUNDLED_ARTIFACT_ROOT = path.join(PACKAGE_ROOT, "artifacts");
15
13
  const INSTALL_STATE_PATH = path.join(WORK_ROOT, "install-state.json");
16
14
  const CONFIG_PATH = path.join(os.homedir(), ".codex", "config.toml");
17
15
  const CONTINUITY_ROOT = path.join(os.homedir(), ".codex", "obsidian_graph");
18
16
  const CHILD_ENV = createChildEnv();
19
17
 
20
18
  const SUPPORTED_CODEX_VERSIONS = ["0.117.0"];
19
+ const CODEX_SRC_URL = "https://github.com/openai/codex.git";
21
20
 
22
21
  async function installSlopex({ postinstall = false } = {}) {
23
22
  ensureDir(WORK_ROOT);
24
23
 
25
24
  const codexInstall = resolveCodexInstall();
26
25
  if (!codexInstall) {
27
- const message =
28
- "Codex is not installed globally. Install it first with: npm install -g @openai/codex";
26
+ const message = "Codex is not installed globally. Install it first with: npm install -g @openai/codex";
29
27
  if (postinstall) {
30
28
  console.warn(`[sloppydisk] ${message}`);
31
29
  return;
@@ -35,35 +33,12 @@ async function installSlopex({ postinstall = false } = {}) {
35
33
 
36
34
  assertSupportedCodexVersion(codexInstall.version);
37
35
 
38
- const patchedBinary = await resolvePatchedBinary(codexInstall.version);
39
- if (!patchedBinary) {
40
- const message = [
41
- `No prebuilt sloppydisk binary is available for Codex ${codexInstall.version} on ${artifactPlatformKey()}.`,
42
- "Install a slopex release that publishes this artifact, or place a matching binary under ~/.slopex/artifacts and rerun `sloppydisk patch`."
43
- ].join(" ");
44
- if (postinstall) {
45
- console.warn(`[sloppydisk] ${message}`);
46
- return;
47
- }
48
- throw new Error(message);
49
- }
36
+ console.log(`[sloppydisk] Preparing to patch Codex ${codexInstall.version} locally...`);
37
+ const patchedBinary = await buildPatchedBinaryLocally(codexInstall.version);
50
38
 
51
39
  ensureDir(BACKUP_ROOT);
52
40
  const backupBinary = path.join(BACKUP_ROOT, `codex-${codexInstall.version}.original`);
53
- const originalBinarySha256 = sha256File(codexInstall.vendorBinary);
54
- const patchedBinarySha256 = sha256File(patchedBinary);
55
41
  if (!fs.existsSync(backupBinary)) {
56
- if (originalBinarySha256 === patchedBinarySha256) {
57
- const message = [
58
- "Codex already appears to be patched, but slopex could not find an original backup to restore later.",
59
- "Refusing to overwrite the only copy. Reinstall @openai/codex first, then rerun `sloppydisk patch`."
60
- ].join(" ");
61
- if (postinstall) {
62
- console.warn(`[sloppydisk] ${message}`);
63
- return;
64
- }
65
- throw new Error(message);
66
- }
67
42
  fs.copyFileSync(codexInstall.vendorBinary, backupBinary);
68
43
  }
69
44
 
@@ -72,24 +47,67 @@ async function installSlopex({ postinstall = false } = {}) {
72
47
 
73
48
  const state = {
74
49
  installedAt: new Date().toISOString(),
75
- slopexVersion: PACKAGE_JSON.version,
50
+ version: PACKAGE_JSON.version,
76
51
  codexVersion: codexInstall.version,
77
- codexDir: codexInstall.codexDir,
78
52
  vendorBinary: codexInstall.vendorBinary,
79
53
  backupBinary,
80
54
  artifactBinary: patchedBinary,
81
- originalBinarySha256,
82
- patchedBinarySha256: sha256File(codexInstall.vendorBinary),
83
55
  binarySha256: sha256File(codexInstall.vendorBinary)
84
56
  };
85
57
  fs.writeFileSync(INSTALL_STATE_PATH, `${JSON.stringify(state, null, 2)}\n`);
86
58
 
87
59
  console.log(`sloppydisk patched Codex ${codexInstall.version}`);
88
60
  console.log(`patched binary: ${codexInstall.vendorBinary}`);
89
- console.log(`artifact source: ${patchedBinary}`);
90
61
  console.log(`continuity root: ${CONTINUITY_ROOT}`);
91
62
  }
92
63
 
64
+ async function buildPatchedBinaryLocally(version) {
65
+ const repoDir = path.join(SRC_ROOT, `rust-v${version}`);
66
+ const artifactPath = path.join(ARTIFACT_ROOT, version, artifactPlatformKey(), executableName("codex"));
67
+ const devSourceDir = "/root/codex-src-main"; // Known local dev source
68
+
69
+ if (fs.existsSync(artifactPath)) {
70
+ console.log(`[sloppydisk] Using cached patched binary at ${artifactPath}`);
71
+ return artifactPath;
72
+ }
73
+
74
+ ensureDir(path.dirname(artifactPath));
75
+ ensureDir(SRC_ROOT);
76
+
77
+ if (!fs.existsSync(repoDir)) {
78
+ if (fs.existsSync(devSourceDir)) {
79
+ console.log(`[sloppydisk] Linking local development source from ${devSourceDir}...`);
80
+ fs.symlinkSync(devSourceDir, repoDir, 'dir');
81
+ } else {
82
+ console.log(`[sloppydisk] Cloning Codex source to ${repoDir}...`);
83
+ // Note: Standard OpenAI codex tags are often just 'vX.Y.Z'
84
+ runChecked("git", ["clone", "--depth", "1", "--branch", `v${version}`, CODEX_SRC_URL, repoDir]);
85
+ }
86
+ }
87
+
88
+ const patchFile = path.join(PACKAGE_ROOT, "patches", `rust-v${version}.patch`);
89
+ if (!fs.existsSync(patchFile)) {
90
+ throw new Error(`Missing patch file for version ${version} at ${patchFile}`);
91
+ }
92
+
93
+ console.log(`[sloppydisk] Applying patch ${path.basename(patchFile)}...`);
94
+ runChecked("git", ["reset", "--hard"], { cwd: repoDir });
95
+ runChecked("patch", ["-p1", "-i", patchFile], { cwd: repoDir });
96
+
97
+ console.log(`[sloppydisk] Compiling patched Codex (this may take a few minutes)...`);
98
+ const crateDir = path.join(repoDir, "codex-rs");
99
+ runChecked("cargo", ["build", "--release", "-p", "codex-cli", "--bin", "codex"], { cwd: crateDir });
100
+
101
+ const buildOutput = path.join(crateDir, "target", "release", executableName("codex"));
102
+ if (!fs.existsSync(buildOutput)) {
103
+ throw new Error(`Build failed: could not find output at ${buildOutput}`);
104
+ }
105
+
106
+ fs.copyFileSync(buildOutput, artifactPath);
107
+ console.log(`[sloppydisk] Successfully built and cached patched binary.`);
108
+ return artifactPath;
109
+ }
110
+
93
111
  async function printStatus() {
94
112
  const codexInstall = resolveCodexInstall();
95
113
  if (!codexInstall) {
@@ -103,94 +121,56 @@ async function printStatus() {
103
121
 
104
122
  console.log(`codex version: ${codexInstall.version}`);
105
123
  console.log(`codex dir: ${codexInstall.codexDir}`);
106
- console.log(`codex vendor binary: ${codexInstall.vendorBinary}`);
107
124
  console.log(`supported by sloppydisk: ${SUPPORTED_CODEX_VERSIONS.includes(codexInstall.version)}`);
108
125
  console.log(`sloppydisk config block: ${managedConfigPresent ? "present" : "missing"}`);
109
- console.log(
110
- `bundled artifact: ${resolveArtifactCandidate(codexInstall.version, BUNDLED_ARTIFACT_ROOT) || "missing"}`
111
- );
112
- console.log(
113
- `cached artifact: ${resolveArtifactCandidate(codexInstall.version, ARTIFACT_ROOT) || "missing"}`
114
- );
115
- console.log(`release asset url: ${releaseArtifactUrl(codexInstall.version)}`);
116
126
 
117
127
  if (!state) {
118
128
  console.log("sloppydisk install state: not found");
119
129
  return;
120
130
  }
121
131
 
122
- console.log(`sloppydisk version: ${state.slopexVersion}`);
123
- console.log(`artifact binary: ${state.artifactBinary || "unknown"}`);
132
+ console.log(`sloppydisk version: ${state.version}`);
124
133
  console.log(`backup binary: ${state.backupBinary}`);
125
- console.log(
126
- `patched binary hash matches state: ${sha256File(codexInstall.vendorBinary) === state.binarySha256}`
127
- );
134
+ console.log(`patched binary hash matches state: ${sha256File(codexInstall.vendorBinary) === state.binarySha256}`);
128
135
  }
129
136
 
130
137
  async function uninstallSlopex() {
131
138
  const state = readInstallState();
132
- const codexInstall = resolveCodexInstall();
133
- const targetVersion = codexInstall?.version || state?.codexVersion;
134
- if (!state && !targetVersion) {
135
- throw new Error("No sloppydisk install state was found and Codex is not installed globally. Nothing to uninstall.");
139
+ if (!state) {
140
+ throw new Error("No sloppydisk install state found.");
136
141
  }
137
142
 
138
- if (canRestoreFromBackup({ state, codexInstall })) {
143
+ if (fs.existsSync(state.backupBinary)) {
139
144
  replaceBinaryAtomically(state.backupBinary, state.vendorBinary);
140
- removeManagedConfigBlock();
141
- fs.rmSync(INSTALL_STATE_PATH, { force: true });
142
145
  console.log(`Restored original Codex binary from ${state.backupBinary}`);
143
- return;
146
+ } else {
147
+ console.warn(`Backup not found at ${state.backupBinary}. Reinstalling @openai/codex...`);
148
+ reinstallOfficialCodex(state.codexVersion);
144
149
  }
145
150
 
146
- reinstallOfficialCodex(targetVersion);
147
151
  removeManagedConfigBlock();
148
152
  fs.rmSync(INSTALL_STATE_PATH, { force: true });
149
- console.log(`Reinstalled official Codex ${targetVersion} from npm.`);
150
- }
151
-
152
- function assertSupportedCodexVersion(version) {
153
- if (SUPPORTED_CODEX_VERSIONS.includes(version)) {
154
- return;
155
- }
156
-
157
- throw new Error(
158
- `Codex ${version} is not supported by this sloppydisk release. Supported versions: ${SUPPORTED_CODEX_VERSIONS.join(", ")}`
159
- );
160
153
  }
161
154
 
162
155
  function resolveCodexInstall() {
163
- const npmRoot = runChecked("npm", ["root", "-g"]).stdout.trim();
164
- const codexDir = path.join(npmRoot, "@openai", "codex");
165
- if (!fs.existsSync(codexDir)) {
166
- return null;
167
- }
156
+ try {
157
+ const npmRoot = runChecked("npm", ["root", "-g"]).stdout.trim();
158
+ const codexDir = path.join(npmRoot, "@openai", "codex");
159
+ if (!fs.existsSync(codexDir)) return null;
168
160
 
169
- const packageJsonPath = path.join(codexDir, "package.json");
170
- if (!fs.existsSync(packageJsonPath)) {
171
- throw new Error(`Could not find Codex package.json at ${packageJsonPath}`);
172
- }
161
+ const packageJson = JSON.parse(fs.readFileSync(path.join(codexDir, "package.json"), "utf8"));
162
+ const vendorBinary = findVendorBinary(codexDir);
163
+ if (!vendorBinary) throw new Error("Could not locate Codex vendor binary.");
173
164
 
174
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
175
- const vendorBinary = findVendorBinary(codexDir);
176
- if (!vendorBinary) {
177
- throw new Error(`Could not locate the Codex vendor binary inside ${codexDir}`);
165
+ return { codexDir, version: packageJson.version, vendorBinary };
166
+ } catch (e) {
167
+ return null;
178
168
  }
179
-
180
- return {
181
- npmRoot,
182
- codexDir,
183
- version: packageJson.version,
184
- vendorBinary
185
- };
186
169
  }
187
170
 
188
171
  function findVendorBinary(codexDir) {
189
172
  const root = path.join(codexDir, "node_modules");
190
- if (!fs.existsSync(root)) {
191
- return null;
192
- }
193
-
173
+ if (!fs.existsSync(root)) return null;
194
174
  const queue = [root];
195
175
  while (queue.length > 0) {
196
176
  const current = queue.shift();
@@ -198,100 +178,21 @@ function findVendorBinary(codexDir) {
198
178
  const fullPath = path.join(current, entry.name);
199
179
  if (entry.isDirectory()) {
200
180
  queue.push(fullPath);
201
- continue;
202
- }
203
- if (
204
- entry.isFile() &&
205
- entry.name === "codex" &&
206
- fullPath.includes(`${path.sep}vendor${path.sep}`) &&
207
- fullPath.includes(`${path.sep}codex${path.sep}codex`)
208
- ) {
181
+ } else if (entry.isFile() && entry.name === "codex" && fullPath.includes("vendor")) {
209
182
  return fullPath;
210
183
  }
211
184
  }
212
185
  }
213
-
214
186
  return null;
215
187
  }
216
188
 
217
189
  function replaceBinaryAtomically(sourceBinary, targetBinary) {
218
- const tempTarget = `${targetBinary}.slopex.tmp`;
190
+ const tempTarget = `${targetBinary}.tmp`;
219
191
  fs.copyFileSync(sourceBinary, tempTarget);
220
192
  fs.chmodSync(tempTarget, 0o755);
221
193
  fs.renameSync(tempTarget, targetBinary);
222
194
  }
223
195
 
224
- async function resolvePatchedBinary(codexVersion) {
225
- const localArtifact =
226
- resolveArtifactCandidate(codexVersion, BUNDLED_ARTIFACT_ROOT) ||
227
- resolveArtifactCandidate(codexVersion, ARTIFACT_ROOT);
228
- if (localArtifact) {
229
- return localArtifact;
230
- }
231
-
232
- return downloadReleaseArtifact(codexVersion, { allowFailure: true });
233
- }
234
-
235
- function resolveArtifactCandidate(codexVersion, rootDir) {
236
- const candidate = artifactBinaryPath(rootDir, codexVersion);
237
- return fs.existsSync(candidate) ? candidate : null;
238
- }
239
-
240
- function cachedArtifactBinaryPath(codexVersion) {
241
- return artifactBinaryPath(ARTIFACT_ROOT, codexVersion);
242
- }
243
-
244
- function artifactBinaryPath(rootDir, codexVersion) {
245
- return path.join(rootDir, codexVersion, artifactPlatformKey(), executableName("codex"));
246
- }
247
-
248
- function releaseArtifactName(codexVersion) {
249
- return executableName(`sloppydisk-codex-${codexVersion}-${artifactPlatformKey()}`);
250
- }
251
-
252
- function releaseArtifactUrl(codexVersion) {
253
- return `https://github.com/${repositorySlug()}/releases/download/v${PACKAGE_JSON.version}/${releaseArtifactName(codexVersion)}`;
254
- }
255
-
256
- function repositorySlug() {
257
- const repositoryUrl =
258
- typeof PACKAGE_JSON.repository === "string"
259
- ? PACKAGE_JSON.repository
260
- : PACKAGE_JSON.repository?.url;
261
- const match = repositoryUrl && repositoryUrl.match(/github\.com[:/](.+?)(?:\.git)?$/);
262
- if (!match) {
263
- throw new Error(
264
- `Unable to derive GitHub repository slug from package.json repository: ${repositoryUrl}`
265
- );
266
- }
267
- return match[1];
268
- }
269
-
270
- async function downloadReleaseArtifact(codexVersion, { allowFailure = false } = {}) {
271
- const targetBinary = cachedArtifactBinaryPath(codexVersion);
272
- const tempTarget = `${targetBinary}.download`;
273
- const url = releaseArtifactUrl(codexVersion);
274
-
275
- try {
276
- ensureDir(path.dirname(targetBinary));
277
- const response = await fetch(url, { redirect: "follow" });
278
- if (!response.ok || !response.body) {
279
- throw new Error(`download failed with HTTP ${response.status} for ${url}`);
280
- }
281
-
282
- await pipeline(Readable.fromWeb(response.body), fs.createWriteStream(tempTarget));
283
- fs.chmodSync(tempTarget, 0o755);
284
- fs.renameSync(tempTarget, targetBinary);
285
- return targetBinary;
286
- } catch (error) {
287
- fs.rmSync(tempTarget, { force: true });
288
- if (allowFailure) {
289
- return null;
290
- }
291
- throw error;
292
- }
293
- }
294
-
295
196
  function artifactPlatformKey() {
296
197
  return `${process.platform}-${process.arch}`;
297
198
  }
@@ -311,80 +212,19 @@ function writeManagedConfigBlock() {
311
212
  ].join("\n");
312
213
 
313
214
  const existing = fs.existsSync(CONFIG_PATH) ? fs.readFileSync(CONFIG_PATH, "utf8") : "";
314
- const next = upsertManagedBlock(existing, managedBlock);
315
- fs.writeFileSync(CONFIG_PATH, `${next.trimEnd()}\n`);
215
+ const stripped = existing.replace(/\n?# BEGIN slopex[\s\S]*?# END slopex\n?/g, "\n").trim();
216
+ fs.writeFileSync(CONFIG_PATH, `${(stripped + "\n\n" + managedBlock).trim()}\n`);
316
217
  }
317
218
 
318
219
  function removeManagedConfigBlock() {
319
- if (!fs.existsSync(CONFIG_PATH)) {
320
- return;
321
- }
322
-
220
+ if (!fs.existsSync(CONFIG_PATH)) return;
323
221
  const existing = fs.readFileSync(CONFIG_PATH, "utf8");
324
222
  const next = existing.replace(/\n?# BEGIN slopex[\s\S]*?# END slopex\n?/g, "\n");
325
- fs.writeFileSync(CONFIG_PATH, `${next.trimEnd()}\n`);
326
- }
327
-
328
- function upsertManagedBlock(existing, managedBlock) {
329
- const stripped = existing
330
- .replace(/\n?# BEGIN slopex[\s\S]*?# END slopex\n?/g, "\n")
331
- .trim();
332
-
333
- if (!stripped) {
334
- return managedBlock;
335
- }
336
-
337
- const firstTableMatch = stripped.match(/^\s*\[/m);
338
- if (!firstTableMatch || firstTableMatch.index === undefined) {
339
- return `${stripped}\n\n${managedBlock}`;
340
- }
341
-
342
- const firstTableIndex = firstTableMatch.index;
343
- const prefix = stripped.slice(0, firstTableIndex).trimEnd();
344
- const suffix = stripped.slice(firstTableIndex).replace(/^\n+/, "");
345
-
346
- if (!prefix) {
347
- return `${managedBlock}\n\n${suffix}`;
348
- }
349
-
350
- return `${prefix}\n\n${managedBlock}\n\n${suffix}`;
223
+ fs.writeFileSync(CONFIG_PATH, `${next.trim()}\n`);
351
224
  }
352
225
 
353
226
  function readInstallState() {
354
- if (!fs.existsSync(INSTALL_STATE_PATH)) {
355
- return null;
356
- }
357
- return JSON.parse(fs.readFileSync(INSTALL_STATE_PATH, "utf8"));
358
- }
359
-
360
- function canRestoreFromBackup({ state, codexInstall }) {
361
- if (!state || !codexInstall) {
362
- return false;
363
- }
364
- if (codexInstall.version !== state.codexVersion) {
365
- return false;
366
- }
367
- if (codexInstall.vendorBinary !== state.vendorBinary) {
368
- return false;
369
- }
370
- if (!fs.existsSync(state.backupBinary)) {
371
- return false;
372
- }
373
-
374
- const expectedPatchedSha256 = state.patchedBinarySha256 || state.binarySha256;
375
- const currentVendorSha256 = sha256File(codexInstall.vendorBinary);
376
- if (expectedPatchedSha256 && currentVendorSha256 !== expectedPatchedSha256) {
377
- return false;
378
- }
379
-
380
- if (
381
- state.originalBinarySha256 &&
382
- sha256File(state.backupBinary) !== state.originalBinarySha256
383
- ) {
384
- return false;
385
- }
386
-
387
- return true;
227
+ return fs.existsSync(INSTALL_STATE_PATH) ? JSON.parse(fs.readFileSync(INSTALL_STATE_PATH, "utf8")) : null;
388
228
  }
389
229
 
390
230
  function reinstallOfficialCodex(version) {
@@ -392,9 +232,7 @@ function reinstallOfficialCodex(version) {
392
232
  }
393
233
 
394
234
  function sha256File(filePath) {
395
- const hash = crypto.createHash("sha256");
396
- hash.update(fs.readFileSync(filePath));
397
- return hash.digest("hex");
235
+ return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
398
236
  }
399
237
 
400
238
  function ensureDir(dirPath) {
@@ -403,46 +241,19 @@ function ensureDir(dirPath) {
403
241
 
404
242
  function createChildEnv() {
405
243
  const cargoBin = path.join(os.homedir(), ".cargo", "bin");
406
- const pathEntries = (process.env.PATH || "")
407
- .split(path.delimiter)
408
- .filter(Boolean);
409
- if (!pathEntries.includes(cargoBin)) {
410
- pathEntries.unshift(cargoBin);
411
- }
412
- return {
413
- ...process.env,
414
- PATH: pathEntries.join(path.delimiter)
415
- };
244
+ const pathEntries = (process.env.PATH || "").split(path.delimiter).filter(Boolean);
245
+ if (!pathEntries.includes(cargoBin)) pathEntries.unshift(cargoBin);
246
+ return { ...process.env, PATH: pathEntries.join(path.delimiter) };
416
247
  }
417
248
 
418
249
  function runChecked(command, args, options = {}) {
419
- const result = spawnSync(command, args, {
420
- cwd: options.cwd,
421
- env: {
422
- ...CHILD_ENV,
423
- ...(options.env || {})
424
- },
425
- encoding: "utf8",
426
- stdio: ["ignore", "pipe", "pipe"]
427
- });
428
- if (result.error && !options.allowFailure) {
429
- throw result.error;
430
- }
431
- if (!options.allowFailure && result.status !== 0) {
432
- const stderr = (result.stderr || "").trim();
433
- throw new Error(
434
- `${command} ${args.join(" ")} failed with exit code ${result.status}${stderr ? `\n${stderr}` : ""}`
435
- );
436
- }
250
+ const result = spawnSync(command, args, { cwd: options.cwd, env: { ...CHILD_ENV, ...(options.env || {}) }, encoding: "utf8" });
251
+ if (result.status !== 0) throw new Error(`${command} failed with code ${result.status}\n${result.stderr}`);
437
252
  return result;
438
253
  }
439
254
 
440
- module.exports = {
441
- SUPPORTED_CODEX_VERSIONS,
442
- artifactPlatformKey,
443
- installSlopex,
444
- printStatus,
445
- releaseArtifactName,
446
- releaseArtifactUrl,
447
- uninstallSlopex
448
- };
255
+ function assertSupportedCodexVersion(version) {
256
+ if (!SUPPORTED_CODEX_VERSIONS.includes(version)) throw new Error(`Codex ${version} not supported.`);
257
+ }
258
+
259
+ module.exports = { installSlopex, printStatus, uninstallSlopex };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sloppydisk",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Minimal reset-based continuity patcher for OpenAI Codex.",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -10,20 +10,12 @@
10
10
  "files": [
11
11
  "bin",
12
12
  "lib",
13
- "README.md",
14
- "LICENSE"
13
+ "patches"
15
14
  ],
16
15
  "scripts": {
17
- "postinstall": "node bin/sloppydisk.js patch --postinstall",
18
- "build-release-artifact": "node scripts/build-release-artifact.cjs",
19
- "smoke:packaged": "node scripts/smoke-packaged-install.cjs"
20
- },
21
- "publishConfig": {
22
- "access": "public"
23
- },
24
- "repository": {
25
- "type": "git",
26
- "url": "https://github.com/lmtlssss/slopex.git"
16
+ "patch": "node bin/sloppydisk.js patch",
17
+ "status": "node bin/sloppydisk.js status",
18
+ "unpatch": "node bin/sloppydisk.js unpatch"
27
19
  },
28
20
  "keywords": [
29
21
  "codex",