@cocorograph/hub-agent 0.7.12 → 0.7.13

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.7.12",
3
+ "version": "0.7.13",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの tmux/pty を中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -29,6 +29,7 @@ const DEFAULT_HUB_API = "https://api.hub.cocorograph.com"
29
29
  const TOKEN_PATH = path.join(os.homedir(), ".claude", ".hub_token.json")
30
30
  const META_DIR = ".cockpit-sync"
31
31
  const META_FILE = "claude-md.json"
32
+ const BASE_FILE = "CLAUDE.md.base"
32
33
  const BAK_KEEP = 3 // 通常 .bak と衝突 .bak それぞれ直近 3 件まで保持
33
34
 
34
35
  async function readJsonOrNull(p) {
@@ -160,6 +161,23 @@ async function writeMeta(targetDir, meta) {
160
161
  )
161
162
  }
162
163
 
164
+ /**
165
+ * 同期成功時の本文を `.cockpit-sync/CLAUDE.md.base` に保存する。
166
+ *
167
+ * session-end スキル (対話中の Claude) が CLAUDE.md を Hub と 3-way merge する際の
168
+ * "base" 入力として使う。前回 sync 直後のローカル == Hub の本文を保持しておくことで、
169
+ * 「ローカル変更」と「Hub 変更」の差分を別々に抽出してから意味マージできる。
170
+ *
171
+ * meta(claude-md.json) は hash と updated_at しか持たないため、本文そのものが要る
172
+ * 3-way merge の用途ではこのファイルが必要。
173
+ */
174
+ async function writeBaseBody(targetDir, body) {
175
+ if (body == null) return
176
+ const metaDir = path.join(targetDir, META_DIR)
177
+ await fs.mkdir(metaDir, { recursive: true })
178
+ await fs.writeFile(path.join(metaDir, BASE_FILE), body, "utf-8")
179
+ }
180
+
163
181
  /**
164
182
  * 既存ローカル CLAUDE.md を .cockpit-sync/CLAUDE.md.<prefix>.<ts>.bak に退避する。
165
183
  * 同 prefix の .bak は新しい順に BAK_KEEP 件保持し、古いものから FIFO 削除する。
@@ -289,6 +307,8 @@ export async function syncClaudeMdWithHub({
289
307
  lastSyncedHash: hubHash || sha256(hubBody),
290
308
  lastSyncedAt: nowIso(),
291
309
  })
310
+ // 3-way merge 用 base: pull 直後はローカル == Hub なので Hub 本文を base に。
311
+ await writeBaseBody(targetDir, hubBody)
292
312
  logger?.info?.({ dirName }, "syncClaudeMdWithHub: pull")
293
313
  return { action: "pull" }
294
314
  }
@@ -315,6 +335,9 @@ export async function syncClaudeMdWithHub({
315
335
  lastSyncedHash: localCurrentHash,
316
336
  lastSyncedAt: nowIso(),
317
337
  })
338
+ // 3-way merge 用 base: push 直後は Hub の正本がローカルと一致するので、
339
+ // 次回の base は今 push した本文 (= localBody)。
340
+ await writeBaseBody(targetDir, localBody || "")
318
341
  logger?.info?.({ dirName }, "syncClaudeMdWithHub: push")
319
342
  return { action: "push" }
320
343
  }
@@ -339,6 +362,8 @@ export async function syncClaudeMdWithHub({
339
362
  lastSyncedHash: localCurrentHash,
340
363
  lastSyncedAt: nowIso(),
341
364
  })
365
+ // 3-way merge 用 base: conflict push 後の Hub 正本は端末側本文 (= localBody)。
366
+ await writeBaseBody(targetDir, localBody || "")
342
367
  logger?.warn?.(
343
368
  { dirName },
344
369
  "syncClaudeMdWithHub: conflict (terminal wins); hub body saved to .bak.conflict",
@@ -349,13 +374,15 @@ export async function syncClaudeMdWithHub({
349
374
  // メタ操作・ハッシュ計算は ensureClaudeMd 側 (Hub pull 初回配信) でも使うため
350
375
  // named export する。同じファイルパス・同じスキーマで管理することで、初回配信と
351
376
  // 以降の sync で食い違いを起こさない。
352
- export { sha256, readMeta, writeMeta, nowIso }
377
+ export { sha256, readMeta, writeMeta, writeBaseBody, nowIso }
353
378
 
354
379
  // 内部テスト用エクスポート
355
380
  export const _internals = {
356
381
  sha256,
357
382
  readMeta,
358
383
  writeMeta,
384
+ writeBaseBody,
359
385
  backupLocalClaudeMd,
360
386
  BAK_KEEP,
387
+ BASE_FILE,
361
388
  }
package/src/claude-md.mjs CHANGED
@@ -22,6 +22,7 @@ import path from "node:path"
22
22
  import {
23
23
  sha256,
24
24
  writeMeta,
25
+ writeBaseBody,
25
26
  nowIso,
26
27
  } from "./claude-md-sync.mjs"
27
28
 
@@ -379,6 +380,8 @@ export async function ensureClaudeMd({
379
380
  lastSyncedHash: hub.claude_md_hash || sha256(hubBody),
380
381
  lastSyncedAt: nowIso(),
381
382
  })
383
+ // 初回 pull 直後は base = Hub 本文。以降の session-end 3-way merge の入力。
384
+ await writeBaseBody(targetDir, hubBody)
382
385
  logger?.info?.(
383
386
  { dirName, claudeMdPath },
384
387
  "wrote CLAUDE.md from Hub project claude_md (initial sync)",