claude-code-runrate 0.3.0 → 0.5.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/src/state-dir.js CHANGED
@@ -18,4 +18,64 @@ function ensureSecureDir(dir) {
18
18
  try { fs.chmodSync(dir, 0o700); } catch { /* best effort */ }
19
19
  }
20
20
 
21
- module.exports = { ensureSecureDir };
21
+ /**
22
+ * Record the directory ccr was launched in, for the git pane's launch-repo
23
+ * identity (features/git-repo-identity.feature: the launch repo is the tab's
24
+ * stable identity, while the current repo follows the session).
25
+ *
26
+ * It is written rather than inferred because only the LAUNCHER knows it. The
27
+ * sidecar's own `process.cwd()` happens to be the launch directory under tmux
28
+ * and wt.exe, where the pane inherits it — but not in VS Code, where the user
29
+ * pastes the sidecar one-liner into a terminal that opened wherever the editor
30
+ * felt like. Inferring would be right most of the time and quietly wrong in the
31
+ * host that needed it most, so the launcher states it.
32
+ *
33
+ * Best-effort by the same rule as everything else in this file: a tab that
34
+ * cannot record its launch directory falls back to naming only the current
35
+ * repo, which is a smaller loss than a launcher that fails.
36
+ *
37
+ * @param {string} dir The state directory.
38
+ * @param {string} cwd The launch directory.
39
+ */
40
+ function recordLaunchDir(dir, cwd) {
41
+ const path = require('node:path');
42
+ const file = path.join(dir, 'launch-cwd');
43
+ try {
44
+ // Never write THROUGH anything but a plain file, for the two reasons the
45
+ // heartbeat write (src/sidecar.js) and the cycle counter (src/cycle-view.js)
46
+ // already guard against at their own paths in this same directory:
47
+ //
48
+ // A SYMLINK turns this into an arbitrary-file overwrite of a directory
49
+ // name — verified: a link planted at launch-cwd had its target replaced.
50
+ //
51
+ // A FIFO is worse and quieter. Opening one for write BLOCKS until a reader
52
+ // appears, and this runs in all three launchers BEFORE Claude is spawned —
53
+ // verified: `ccr` hangs forever with no output at all. That is the silent
54
+ // -abort failure this project already shipped once (scripts/launch.sh's
55
+ // nvm glob under `set -e`), arriving by a different door.
56
+ //
57
+ // Anything under <stateDir> is writable by anything running as the user, so
58
+ // this is the same trust boundary, not a new one.
59
+ try { if (!fs.lstatSync(file).isFile()) fs.rmSync(file, { force: true }); } catch { /* absent */ }
60
+ fs.writeFileSync(file, String(cwd) + '\n', { mode: 0o600 });
61
+ } catch { /* best effort */ }
62
+ }
63
+
64
+ /**
65
+ * Forget the recorded launch directory.
66
+ *
67
+ * NOT the same as declining to write one. Slots are REUSED, so a record left by
68
+ * whatever ran in this slot before would still be sitting there — and
69
+ * src/sidecar.js launchDir() PREFERS the record over the pane's own cwd, so a
70
+ * stale one wins outright. The launcher calls this whenever it could not
71
+ * deliver the directory to the panes, which is the only moment it knows the
72
+ * record would be a lie.
73
+ *
74
+ * @param {string} dir The state directory.
75
+ */
76
+ function clearLaunchDir(dir) {
77
+ const path = require('node:path');
78
+ try { fs.rmSync(path.join(dir, 'launch-cwd'), { force: true }); } catch { /* best effort */ }
79
+ }
80
+
81
+ module.exports = { ensureSecureDir, recordLaunchDir, clearLaunchDir };