@cocorograph/hub-agent 0.6.88 → 0.6.89
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 +1 -1
- package/src/claude-md-sync.mjs +5 -0
- package/src/claude-md.mjs +74 -7
package/package.json
CHANGED
package/src/claude-md-sync.mjs
CHANGED
|
@@ -346,6 +346,11 @@ export async function syncClaudeMdWithHub({
|
|
|
346
346
|
return { action: "conflict" }
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
+
// メタ操作・ハッシュ計算は ensureClaudeMd 側 (Hub pull 初回配信) でも使うため
|
|
350
|
+
// named export する。同じファイルパス・同じスキーマで管理することで、初回配信と
|
|
351
|
+
// 以降の sync で食い違いを起こさない。
|
|
352
|
+
export { sha256, readMeta, writeMeta, nowIso }
|
|
353
|
+
|
|
349
354
|
// 内部テスト用エクスポート
|
|
350
355
|
export const _internals = {
|
|
351
356
|
sha256,
|
package/src/claude-md.mjs
CHANGED
|
@@ -2,17 +2,28 @@
|
|
|
2
2
|
* 新規 workspace ディレクトリ初期化時の CLAUDE.md 生成。
|
|
3
3
|
*
|
|
4
4
|
* ~/hub/bin/generate-claude-md (Python) と同等の仕様を Node 側に持つ。
|
|
5
|
-
* - `<dirName>/_director` slug で Hub director を引き当て、見つかれば
|
|
6
|
-
* frontmatter (client / domain / industry / service / tech_stack /
|
|
7
|
-
* google_drive) を反映した構造化 CLAUDE.md を書き出す
|
|
8
|
-
* - 認証トークン (`~/.claude/.hub_token.json`) が無い / API 失敗 / director
|
|
9
|
-
* 未登録ならプレースホルダ CLAUDE.md を書き出す
|
|
10
5
|
*
|
|
11
|
-
* CLAUDE.md
|
|
6
|
+
* 優先順 (新規生成時のみ。既存 CLAUDE.md は触らない):
|
|
7
|
+
* 1. **Hub の Project.claude_md 正本** (Stage 3 初回配信) — 非空ならそれを書く。
|
|
8
|
+
* 同期メタ (.cockpit-sync/claude-md.json) も初期化する。以降は
|
|
9
|
+
* syncClaudeMdWithHub が双方向同期する。
|
|
10
|
+
* 2. **Hub director frontmatter** — claude_md が空でも director があれば
|
|
11
|
+
* client/domain/industry/service/tech_stack/google_drive で構造化版を書く。
|
|
12
|
+
* 3. **placeholder** — token なし / API 失敗 / director 未登録なら最小プレースホルダ。
|
|
13
|
+
*
|
|
14
|
+
* 1 を最優先にしたのは、新規メンバーが workspace に入ったとき、組織で固まった
|
|
15
|
+
* CLAUDE.md(Stage 1/2 で正本化したもの)が即座に引かれて作業に取り掛かれる
|
|
16
|
+
* ようにするため。動的生成は「Hub に正本がまだ無いプロジェクト」の救済として
|
|
17
|
+
* のみ機能する。
|
|
12
18
|
*/
|
|
13
19
|
import fs from "node:fs/promises"
|
|
14
20
|
import os from "node:os"
|
|
15
21
|
import path from "node:path"
|
|
22
|
+
import {
|
|
23
|
+
sha256,
|
|
24
|
+
writeMeta,
|
|
25
|
+
nowIso,
|
|
26
|
+
} from "./claude-md-sync.mjs"
|
|
16
27
|
|
|
17
28
|
const DEFAULT_HUB_API = "https://api.hub.cocorograph.com"
|
|
18
29
|
const TOKEN_PATH = path.join(os.homedir(), ".claude", ".hub_token.json")
|
|
@@ -31,6 +42,34 @@ async function loadAccessToken() {
|
|
|
31
42
|
return (data && typeof data.access === "string" && data.access) || null
|
|
32
43
|
}
|
|
33
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Hub の Project.claude_md 正本を取得する (Stage 3 初回配信用)。
|
|
47
|
+
*
|
|
48
|
+
* - 404 (該当 Project 無し) → null
|
|
49
|
+
* - その他のエラー → null
|
|
50
|
+
* - 取得成功時は { claude_md, claude_md_hash, claude_md_updated_at } を返す
|
|
51
|
+
*
|
|
52
|
+
* 同じエンドポイントは syncClaudeMdWithHub も使うが、ensureClaudeMd は
|
|
53
|
+
* 初回生成 (メタ無し) 経路でしか呼ばれず、PUT もしないため import せず
|
|
54
|
+
* 個別実装する。
|
|
55
|
+
*/
|
|
56
|
+
async function fetchHubClaudeMdProject({ hubUrl, accessToken, dirName, fetchImpl }) {
|
|
57
|
+
const f = fetchImpl || globalThis.fetch
|
|
58
|
+
if (!f) return null
|
|
59
|
+
const url =
|
|
60
|
+
`${hubUrl.replace(/\/+$/, "")}/api/admin/project/claude-md-by-dir/` +
|
|
61
|
+
`?dir_name=${encodeURIComponent(dirName)}`
|
|
62
|
+
try {
|
|
63
|
+
const res = await f(url, {
|
|
64
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
65
|
+
})
|
|
66
|
+
if (!res.ok) return null
|
|
67
|
+
return await res.json()
|
|
68
|
+
} catch {
|
|
69
|
+
return null
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
34
73
|
async function fetchDirector({ hubUrl, accessToken, dirName, fetchImpl }) {
|
|
35
74
|
const f = fetchImpl || globalThis.fetch
|
|
36
75
|
if (!f) return null
|
|
@@ -320,7 +359,35 @@ export async function ensureClaudeMd({
|
|
|
320
359
|
const token =
|
|
321
360
|
accessToken === undefined ? await loadAccessToken() : accessToken || null
|
|
322
361
|
const url = hubUrl || DEFAULT_HUB_API
|
|
323
|
-
|
|
362
|
+
|
|
363
|
+
// Stage 3: Hub に正本があればそれを最優先で書き込み、メタも初期化する
|
|
364
|
+
// (以降の syncClaudeMdWithHub が双方向同期の起点として使う)。
|
|
365
|
+
// Hub 側未保存 (claude_md_updated_at が null) なら従来パスへフォールバック。
|
|
366
|
+
if (token) {
|
|
367
|
+
const hub = await fetchHubClaudeMdProject({
|
|
368
|
+
hubUrl: url,
|
|
369
|
+
accessToken: token,
|
|
370
|
+
dirName,
|
|
371
|
+
fetchImpl,
|
|
372
|
+
})
|
|
373
|
+
const hubBody = hub?.claude_md || ""
|
|
374
|
+
const hubInitialized = !!hub?.claude_md_updated_at
|
|
375
|
+
if (hubInitialized && hubBody) {
|
|
376
|
+
await fs.writeFile(claudeMdPath, hubBody, "utf-8")
|
|
377
|
+
await writeMeta(targetDir, {
|
|
378
|
+
lastSyncedHubUpdatedAt: hub.claude_md_updated_at,
|
|
379
|
+
lastSyncedHash: hub.claude_md_hash || sha256(hubBody),
|
|
380
|
+
lastSyncedAt: nowIso(),
|
|
381
|
+
})
|
|
382
|
+
logger?.info?.(
|
|
383
|
+
{ dirName, claudeMdPath },
|
|
384
|
+
"wrote CLAUDE.md from Hub project claude_md (initial sync)",
|
|
385
|
+
)
|
|
386
|
+
return { written: true, source: "hub" }
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// 従来パス: director と repositories は独立して取れるので並列フェッチする。
|
|
324
391
|
// どちらも失敗時は null / [] にフォールバックする (token なしの場合も同様)。
|
|
325
392
|
const [director, repositories] = token
|
|
326
393
|
? await Promise.all([
|