@cocorograph/hub-agent 0.6.57 → 0.6.58

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocorograph/hub-agent",
3
- "version": "0.6.57",
3
+ "version": "0.6.58",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの tmux/pty を中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -66,6 +66,8 @@ export class TuiViewerRegistry {
66
66
  this.ttlSec = ttlSec
67
67
  this.logger = logger
68
68
  this._sweepTimer = null
69
+ /** atomic write の tmp 名を一意化するための単調増加カウンタ (race 回避)。 */
70
+ this._tmpSeq = 0
69
71
  }
70
72
 
71
73
  /** ディレクトリを作成し、起動時の残骸を掃除して周期 sweep を張る。 */
@@ -131,15 +133,29 @@ export class TuiViewerRegistry {
131
133
 
132
134
  /**
133
135
  * atomic write (tmp+rename)。書けなくても agent は落とさない。
136
+ *
137
+ * tmp 名は ``<fp>.<pid>.<seq>.tmp`` で **書込ごとに一意化**する。固定 ``<fp>.tmp`` を
138
+ * 使うと、同一マーカー (同 session_id / 同 cwd) へ複数タブ・高頻度ハートビートが並行
139
+ * note() したとき、先勝ちの rename が tmp を移動した後に後発の rename が ENOENT で
140
+ * 失敗する (rename '<fp>.tmp' → '<fp>': no such file)。マーカー自体は勝者が書くので
141
+ * 致命的ではないが、ログを汚し鮮度更新を取りこぼす余地があった。一意 tmp なら各書込が
142
+ * 独立した tmp を rename するため衝突しない。
143
+ *
134
144
  * @param {string} fp
135
145
  * @param {string} body
136
146
  */
137
147
  async _atomicWrite(fp, body) {
138
- const tmp = `${fp}.tmp`
148
+ const tmp = `${fp}.${process.pid}.${++this._tmpSeq}.tmp`
139
149
  try {
140
150
  await writeFile(tmp, body)
141
151
  await rename(tmp, fp)
142
152
  } catch (err) {
153
+ // rename 前に書けた tmp が残りうるので掃除する (sweep は *.json のみ対象)。
154
+ try {
155
+ await unlink(tmp)
156
+ } catch {
157
+ /* 無ければ no-op */
158
+ }
143
159
  this.logger?.warn({ err: err?.message, fp }, "viewer marker write failed")
144
160
  }
145
161
  }