skalpel 4.0.22 → 4.0.24

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/install.mjs CHANGED
@@ -299,13 +299,17 @@ function stripManagedTomlBlocks(txt) {
299
299
 
300
300
  function codexToml() {
301
301
  if (!existsSync(CODEX_DIR)) return "no-codex";
302
- const txt = existsSync(CODEX_TOML) ? readFileSync(CODEX_TOML, "utf8") : "";
302
+ const hadToml = existsSync(CODEX_TOML);
303
+ const txt = hadToml ? readFileSync(CODEX_TOML, "utf8") : "";
303
304
  // Strip current managed blocks and older unmanaged skalpel blocks, so setup heals stale Codex
304
305
  // configs that still point at bare PATH commands from pre-staged installs.
305
306
  const stripped = stripManagedTomlBlocks(txt);
306
307
  let next = stripped.text.replace(/\n{3,}/g, "\n\n").trimEnd();
307
308
  if (uninstall) {
308
- writeFileSync(CODEX_TOML, next + "\n");
309
+ // Only rewrite a config.toml that already existed — never CREATE one during an uninstall. A user
310
+ // with ~/.codex but no config.toml has nothing of ours to strip, so writing `next + "\n"` here
311
+ // would leave a stray 1-byte file behind an operation that's supposed to clean up.
312
+ if (hadToml) writeFileSync(CODEX_TOML, next + "\n");
309
313
  return stripped.removed ? "removed" : "absent";
310
314
  }
311
315
  mkdirSync(CODEX_DIR, { recursive: true });
@@ -450,6 +454,7 @@ function cleanupLocalData() {
450
454
  rm(join(SKALPEL_DIR, "hooks"), "staged hooks");
451
455
  rm(join(SKALPEL_DIR, "ingest-outbox"), "raw transcript snapshots (ingest-outbox)");
452
456
  for (const f of [
457
+ "stats.json", // legacy "time saved" accumulator — nothing writes it now, but old installs left one
453
458
  "session.json",
454
459
  "steer.json",
455
460
  "traj.json",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skalpel",
3
- "version": "4.0.22",
3
+ "version": "4.0.24",
4
4
  "description": "Behavioral graph for AI-assisted coding — learns how you work and steers Claude Code + Codex in real time.",
5
5
  "type": "module",
6
6
  "bin": {
package/skalpel-setup.mjs CHANGED
@@ -30,7 +30,9 @@ const argv = process.argv.slice(2);
30
30
  const sub = argv[0] && !argv[0].startsWith("-") ? argv[0] : null;
31
31
  const flagOf = (name) => {
32
32
  const i = argv.indexOf(name);
33
- return i >= 0 && argv[i + 1] ? argv[i + 1] : null;
33
+ // A flag-looking next token is a missing value, not the value never swallow it (would poison
34
+ // client.json and let `--api --version` fall through to a full install).
35
+ return i >= 0 && argv[i + 1] && !argv[i + 1].startsWith("-") ? argv[i + 1] : null;
34
36
  };
35
37
  const apiFlag = flagOf("--api");
36
38
  const userFlag = flagOf("--user");
@@ -92,7 +94,9 @@ function validateArgv() {
92
94
  for (let i = 0; i < argv.length; i++) {
93
95
  const a = argv[i];
94
96
  if (VALUE_FLAGS.has(a)) {
95
- i++; // its value is not a token to validate
97
+ // Only skip a real value; a following flag (-v/--version/--help/unknown) is a missing value
98
+ // and must still be validated/handled, not eaten.
99
+ if (argv[i + 1] && !argv[i + 1].startsWith("-")) i++;
96
100
  continue;
97
101
  }
98
102
  if (a === "-v" || a === "--version") {
package/stats.mjs CHANGED
@@ -63,9 +63,8 @@ for (const ev of Object.keys(counts)) {
63
63
  }
64
64
  const L = lat[ev] || [];
65
65
  if (L.length) {
66
- console.log(
67
- ` latency p50=${pct(L, 50)}ms p95=${pct(L, 95)}ms max=${Math.max(...L)}ms`,
68
- );
66
+ const maxMs = L.reduce((a, b) => (b > a ? b : a), -Infinity);
67
+ console.log(` latency p50=${pct(L, 50)}ms p95=${pct(L, 95)}ms max=${maxMs}ms`);
69
68
  }
70
69
  console.log(
71
70
  ` → inject rate ${((100 * ok) / n).toFixed(1)}% cold-abort rate ${((100 * cold) / n).toFixed(1)}%\n`,