agent-takkub 1.0.63 → 1.0.67

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.
@@ -92,10 +92,29 @@ function posixEnsure(binDir) {
92
92
  if (fs.existsSync(bashrc)) rcs.push(bashrc);
93
93
  let added = false;
94
94
  for (const rc of rcs) {
95
- const existing = fs.existsSync(rc) ? fs.readFileSync(rc, 'utf8') : '';
96
- if (existing.includes(MARKER)) continue;
97
- fs.writeFileSync(rc, existing + block);
98
- added = true;
95
+ // One fd carries the whole check-then-write cycle (not separate
96
+ // existsSync/readFileSync/writeFileSync path lookups): opening `rc`
97
+ // once and reusing that fd for both the read and the append means what
98
+ // we inspected and what we wrote to are provably the same file, with
99
+ // no window between "check" and "write" for `rc` to start pointing
100
+ // somewhere else. `wx+` on the create branch is itself atomic
101
+ // create-if-absent (and still readable, unlike plain `wx`), closing
102
+ // the same race on the exists check too.
103
+ let fd;
104
+ try {
105
+ fd = fs.openSync(rc, 'r+');
106
+ } catch (e) {
107
+ if (e.code !== 'ENOENT') throw e;
108
+ fd = fs.openSync(rc, 'wx+');
109
+ }
110
+ try {
111
+ const existing = fs.readFileSync(fd, 'utf8');
112
+ if (existing.includes(MARKER)) continue;
113
+ fs.writeSync(fd, block); // position advanced to EOF by the read above
114
+ added = true;
115
+ } finally {
116
+ fs.closeSync(fd);
117
+ }
99
118
  }
100
119
  return added;
101
120
  }
@@ -44,8 +44,15 @@ function createWindows() {
44
44
  // Run from a temp .ps1 FILE, not an inline -Command: passing a long quoted
45
45
  // command through Node→Windows arg-escaping mangles the quotes and produces
46
46
  // an empty shortcut. A -File avoids all of that.
47
- const ps1 = path.join(os.tmpdir(), `att-shortcut-${process.pid}.ps1`);
48
- fs.writeFileSync(ps1, lines.join('\r\n') + '\r\n', 'utf8');
47
+ //
48
+ // mkdtempSync (not a PID-based name in os.tmpdir() directly) gives a
49
+ // freshly-created, uniquely-named, current-user-owned directory — a
50
+ // predictable path there is guessable/plantable by another local account
51
+ // ahead of time (symlink pre-plant), which a plain writeFileSync would
52
+ // silently follow and overwrite.
53
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'att-shortcut-'));
54
+ const ps1 = path.join(tmpDir, 'shortcut.ps1');
55
+ fs.writeFileSync(ps1, lines.join('\r\n') + '\r\n', { encoding: 'utf8', flag: 'wx' });
49
56
  try {
50
57
  const r = spawnSync(
51
58
  'powershell',
@@ -55,7 +62,7 @@ function createWindows() {
55
62
  return r.status === 0 && fs.existsSync(lnk) ? lnk : null;
56
63
  } finally {
57
64
  try {
58
- fs.unlinkSync(ps1);
65
+ fs.rmSync(tmpDir, { recursive: true, force: true });
59
66
  } catch (_e) {
60
67
  /* ignore */
61
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-takkub",
3
- "version": "1.0.63",
3
+ "version": "1.0.67",
4
4
  "description": "Desktop cockpit for orchestrating a team of Claude Code agents (Windows + macOS). Install globally: npm i -g agent-takkub",
5
5
  "keywords": [
6
6
  "claude",