skalpel 4.0.39 → 4.0.40
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/eval-harness.mjs +17 -3
- package/package.json +1 -1
- package/skalpel-statusline.mjs +9 -2
- package/verify-shadow.mjs +17 -3
package/eval-harness.mjs
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import fs from "node:fs";
|
|
27
27
|
import path from "node:path";
|
|
28
|
+
import { fileURLToPath } from "node:url";
|
|
28
29
|
|
|
29
30
|
// ───────────────────────────── tunables (UNCALIBRATED defaults) ─────────────────────────────
|
|
30
31
|
// These thresholds are NOT tuned against a human gold set unless one is supplied via --gold.
|
|
@@ -1117,9 +1118,22 @@ function main() {
|
|
|
1117
1118
|
console.log("═".repeat(90));
|
|
1118
1119
|
}
|
|
1119
1120
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1121
|
+
// Robust main detection (mirrors verify-shadow.mjs / skalpel-setup.mjs): compare REAL paths via
|
|
1122
|
+
// realpathSync, not a hand-built path.resolve(url.pathname). On Windows, `new URL(import.meta.url)
|
|
1123
|
+
// .pathname` yields "/C:/Users/..." (a leading slash BEFORE the drive letter); path.resolve() on that
|
|
1124
|
+
// string produces "\C:\Users\..." — a different string than path.resolve(process.argv[1])'s
|
|
1125
|
+
// "C:\Users\...". isMain then silently evaluates false, so `node eval-harness.mjs <dir>` (the CLI's
|
|
1126
|
+
// entire purpose) does nothing at all on Windows: no usage, no report, no error, exit 0.
|
|
1127
|
+
const isMain = (() => {
|
|
1128
|
+
try {
|
|
1129
|
+
return (
|
|
1130
|
+
Boolean(process.argv[1]) &&
|
|
1131
|
+
fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url))
|
|
1132
|
+
);
|
|
1133
|
+
} catch {
|
|
1134
|
+
return false;
|
|
1135
|
+
}
|
|
1136
|
+
})();
|
|
1123
1137
|
if (isMain) main();
|
|
1124
1138
|
|
|
1125
1139
|
export { V1_onset, V2_cue, V3_repeat, FIRE_ALWAYS, FIRE_NEVER, calibrate };
|
package/package.json
CHANGED
package/skalpel-statusline.mjs
CHANGED
|
@@ -139,10 +139,17 @@ function steerLabel() {
|
|
|
139
139
|
// line (fresh + honest — the statusline never invents it, it only renders what the re-run recorded) or
|
|
140
140
|
// null. Auto-clears when stale (past the TTL) so an old catch can't wallpaper the bar. GATED entirely on
|
|
141
141
|
// SKALPEL_VERIFY_REVEAL: when off, this is never called and the bar is byte-identical to the baseline.
|
|
142
|
-
function revealNote() {
|
|
142
|
+
function revealNote(sessionId) {
|
|
143
143
|
try {
|
|
144
144
|
const r = JSON.parse(readFileSync(REVEAL_PATH, "utf8"));
|
|
145
145
|
if (!r || typeof r.line !== "string" || !r.line.trim()) return null;
|
|
146
|
+
// SESSION SCOPING: verify-reveal.json is a single shared path across every concurrent Claude Code
|
|
147
|
+
// session (multiple tabs/worktrees). Without this check, this pane would show — and misattribute to
|
|
148
|
+
// "your agent" — a catch that actually came from a DIFFERENT session's transcript. Only skip when
|
|
149
|
+
// BOTH sides know their session and they disagree; an unknown session on either side stays permissive.
|
|
150
|
+
// NOT deleted here (unlike the stale-TTL branch below) — it may still be the right reveal for whichever
|
|
151
|
+
// session actually owns it.
|
|
152
|
+
if (r.session && sessionId && r.session !== sessionId) return null;
|
|
146
153
|
const age = Date.now() - Date.parse(r.ts);
|
|
147
154
|
if (!Number.isFinite(age) || age > REVEAL_TTL_MS) {
|
|
148
155
|
try {
|
|
@@ -361,7 +368,7 @@ function main() {
|
|
|
361
368
|
// SKALPEL_VERIFY_REVEAL — when off (the default) this branch never runs and the bar is byte-identical to
|
|
362
369
|
// the always-on baseline below.
|
|
363
370
|
if (revealEnabled(process.env)) {
|
|
364
|
-
const reveal = revealNote();
|
|
371
|
+
const reveal = revealNote(payload.session_id);
|
|
365
372
|
if (reveal) {
|
|
366
373
|
process.stdout.write(`${BOLD}${reveal}${RESET}`);
|
|
367
374
|
return;
|
package/verify-shadow.mjs
CHANGED
|
@@ -877,9 +877,23 @@ function writeReveal(row) {
|
|
|
877
877
|
}
|
|
878
878
|
}
|
|
879
879
|
|
|
880
|
-
// clearReveal() — retract a prior catch (the agent actually fixed it: a later proof re-run
|
|
881
|
-
|
|
880
|
+
// clearReveal(session) — retract a prior catch (the agent actually fixed it: a later proof re-run
|
|
881
|
+
// PASSED). SESSION-SCOPED: verify-reveal.json is a single shared path under ~/.skalpel, read/written by
|
|
882
|
+
// every concurrent Claude Code session (multiple tabs/worktrees is a normal prosumer workflow). Without
|
|
883
|
+
// this guard, session B's PASSING proof would silently wipe out session A's still-unresolved GENUINE_FAIL
|
|
884
|
+
// reveal — the user in session A would never see the catch they hadn't gotten to yet, and session B gets
|
|
885
|
+
// credit for "fixing" something it never touched. Only refuse to clear when BOTH sides know their session
|
|
886
|
+
// and they disagree; an unknown session on either side stays permissive (matches prior single-session
|
|
887
|
+
// behavior, and a manual/CLI-driven re-run with no session context still self-heals as before).
|
|
888
|
+
function clearReveal(session) {
|
|
882
889
|
try {
|
|
890
|
+
let existing = null;
|
|
891
|
+
try {
|
|
892
|
+
existing = JSON.parse(readFileSync(REVEAL_PATH, "utf8"));
|
|
893
|
+
} catch {
|
|
894
|
+
/* no reveal file, or unreadable — nothing to protect; fall through to the (idempotent) remove */
|
|
895
|
+
}
|
|
896
|
+
if (existing && existing.session && session && existing.session !== session) return; // not ours
|
|
883
897
|
rmSync(REVEAL_PATH, { force: true });
|
|
884
898
|
} catch {
|
|
885
899
|
/* stale reveal self-expires via the statusline's TTL anyway */
|
|
@@ -946,7 +960,7 @@ function maybeSurfaceReveal(row) {
|
|
|
946
960
|
session: row.session || null,
|
|
947
961
|
});
|
|
948
962
|
} else if (isPass) {
|
|
949
|
-
clearReveal(); // resolved — don't wallpaper a catch the agent already fixed
|
|
963
|
+
clearReveal(row.session || null); // resolved — don't wallpaper a catch the agent already fixed
|
|
950
964
|
// The green VERDICT stamp is #612's TEST-pass path only: its line ("re-ran `<proof>`, exit 0") is a
|
|
951
965
|
// real test re-run receipt. A ship SHIP_OK (read-only probe came back positive) has no re-run and no
|
|
952
966
|
// proof_command, so it must NOT borrow that wording — it only clears any prior catch (as #611 did).
|