@cocorograph/hub-agent 0.8.21 → 0.8.22

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.8.21",
3
+ "version": "0.8.22",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの tmux/pty を中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -0,0 +1,222 @@
1
+ /**
2
+ * CLAUDE.md / AGENTS.md の **自動生成本文のレンダラ**(director 版 / placeholder 版)。
3
+ *
4
+ * `src/claude-md.mjs` から物理移動した(複製ではない)。当初は
5
+ * `claude-md-sync.mjs` の救済判定(旧 fallback 本文を「実際に生成し直して等値比較」で
6
+ * 見分ける移行措置)と共有するためだったが、**その救済は廃止した**(レンダラの本文が
7
+ * 2026-07-22 の aa58223 で変わっており、それ以前に生成されたファイルとの等値は
8
+ * 原理的に成立しないため、実データで 0 件しか救済できなかった)。
9
+ * 現在の呼び出し元は `claude-md.mjs` だけだが、分割自体は有益なので残している
10
+ * (レンダラだけを差し替え・比較できる/`claude-md.mjs` の肥大を防ぐ)。
11
+ *
12
+ * ⚠️ このモジュールは何も import しない(純粋な文字列生成)。ここに I/O や Hub 取得を
13
+ * 足すと `claude-md.mjs` との循環を招く。
14
+ *
15
+ * ⚠️ **ここの文言はドリフトする**(実際に aa58223 で見出し行が変わった)。同期の判定に
16
+ * 「レンダラで再現して一致するか」を使わないこと。現在の同期は本文の中身を一切見ず、
17
+ * meta の有無と hash の等値だけで判定する(`claude-md-sync.mjs` 参照)。
18
+ */
19
+
20
+ /**
21
+ * repo_url が GitHub の `owner/repo` slug 形式かを判定する。
22
+ *
23
+ * `://` や `@` を含むフル URL(GitLab の `git@gitlab.com:...` や
24
+ * `https://gitlab.com/...` 等)は false を返す。これらは `gh` ではなく
25
+ * 素の `git clone` でチェックアウトする。
26
+ */
27
+ export function isGitHubSlug(repoUrl) {
28
+ if (/:\/\/|@/.test(repoUrl)) return false
29
+ return /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repoUrl)
30
+ }
31
+
32
+ /**
33
+ * GitRepository 配列を CLAUDE.md のクローンレス作業手順セクションに描画する。
34
+ *
35
+ * リポジトリが 1 件もない場合は空文字列を返し、CLAUDE.md には何も追記しない。
36
+ */
37
+ export function renderRepositorySection(repositories, dirName = "", cliKind = "claude") {
38
+ if (!Array.isArray(repositories) || repositories.length === 0) return ""
39
+
40
+ const lines = ["## Cockpit クローンレス開発フロー", ""]
41
+ lines.push(
42
+ "この workspace ディレクトリには Git リポジトリを常設しません。",
43
+ "コードを修正するときは、毎回一時ディレクトリにチェックアウトして作業します。",
44
+ "",
45
+ )
46
+
47
+ for (const repo of repositories) {
48
+ const repoUrl = (repo?.repo_url || "").trim()
49
+ if (!repoUrl) continue
50
+ const branch = (repo?.default_branch || "main").trim()
51
+ const deployDisplay = (repo?.deploy_method_display || "").trim()
52
+ const deployNotes = (repo?.deploy_notes || "").trim()
53
+ const stagingName = (repo?.staging_server_name || "").trim()
54
+ const productionName = (repo?.production_server_name || "").trim()
55
+ const repoLabel = (repo?.name || "").trim()
56
+ const heading = repoLabel
57
+ ? `### ${repoUrl} — ${repoLabel}`
58
+ : `### ${repoUrl}`
59
+
60
+ lines.push(heading)
61
+ lines.push("")
62
+ lines.push(`- **デフォルトブランチ**: \`${branch}\``)
63
+ if (deployDisplay) lines.push(`- **デプロイ方式**: ${deployDisplay}`)
64
+ if (stagingName) lines.push(`- **ステージング**: ${stagingName}`)
65
+ if (productionName) lines.push(`- **本番**: ${productionName}`)
66
+ lines.push("")
67
+
68
+ const githubSlug = isGitHubSlug(repoUrl)
69
+ lines.push("**作業手順(クローンレス)**:")
70
+ lines.push("")
71
+ lines.push("```bash")
72
+ lines.push("TMPDIR=$(mktemp -d)")
73
+ if (githubSlug) {
74
+ // GitHub: gh CLI で clone・PR 作成
75
+ lines.push(`gh repo clone ${repoUrl} "$TMPDIR" -- --depth 1 --filter=blob:none --no-checkout`)
76
+ lines.push(`cd "$TMPDIR" && git fetch origin ${branch} && git checkout -b feat/<your-change> origin/${branch}`)
77
+ lines.push("# ファイル編集 → 動作確認")
78
+ lines.push('git commit -am "<message>"')
79
+ lines.push("git push -u origin HEAD")
80
+ lines.push(`gh pr create --base ${branch} --fill`)
81
+ } else {
82
+ // GitLab 等: 素の git clone。MR は push 後に Web/glab で作成
83
+ lines.push(`git clone --depth 1 --filter=blob:none --no-checkout ${repoUrl} "$TMPDIR"`)
84
+ lines.push(`cd "$TMPDIR" && git fetch origin ${branch} && git checkout -b feat/<your-change> origin/${branch}`)
85
+ lines.push("# ファイル編集 → 動作確認")
86
+ lines.push('git commit -am "<message>"')
87
+ lines.push("git push -u origin HEAD")
88
+ lines.push("# MR は GitLab の Web UI(push 時に表示される URL)か `glab mr create` で作成")
89
+ }
90
+ lines.push("# 作業終了後")
91
+ lines.push('cd / && rm -rf "$TMPDIR"')
92
+ lines.push("```")
93
+ lines.push("")
94
+
95
+ if (deployNotes) {
96
+ lines.push("**デプロイ手順メモ**:")
97
+ lines.push("")
98
+ lines.push("```")
99
+ lines.push(deployNotes)
100
+ lines.push("```")
101
+ lines.push("")
102
+ }
103
+
104
+ // デプロイ接続情報の安全な取得手順(秘匿値を会話に出さない)。
105
+ if (stagingName || productionName) {
106
+ const envExample = productionName ? "production" : "staging"
107
+ lines.push("**デプロイ接続情報の取得(秘匿値を会話に出さない)**:")
108
+ lines.push("")
109
+ lines.push("```bash")
110
+ lines.push(
111
+ "# 秘密鍵を ~/.ssh/hub_deploy/ に書き出し、ssh コマンドだけ受け取る",
112
+ )
113
+ lines.push(
114
+ `python3 ~/.${cliKind === "codex" ? "codex" : "claude"}/scripts/hub_helper.py deploy_creds ${dirName || "<dir_name>"} --env ${envExample}`,
115
+ )
116
+ lines.push("```")
117
+ lines.push("")
118
+ lines.push(
119
+ "返り値の `ssh_command` をそのまま使って接続します。`key_file` は",
120
+ "chmod 600 で書き出されます。パスワード認証のサーバーは `password_set: true`",
121
+ "だけ返るので、その場合は Hub の「サーバー情報」タブから人手で取得します。",
122
+ "",
123
+ )
124
+ }
125
+ }
126
+
127
+ lines.push("### デプロイ前の必須ガード", "")
128
+ lines.push(
129
+ "- **本番反映の前に必ず現状バックアップを取る**(DB ダンプ / 対象ディレクトリの退避)。",
130
+ "- ステージングで動作確認してから本番へ。",
131
+ "- 破壊的操作(`reset --hard` / `rm -rf` / DB 操作)の前に対象を確認する。",
132
+ "- Git 認証はローカルの `gh` CLI(GitHub)/ SSH 鍵(GitLab 等)を使用します。",
133
+ "",
134
+ )
135
+ return lines.join("\n")
136
+ }
137
+
138
+ export function renderWithDirector(dirName, director, repositorySection = "", configFilename = "CLAUDE.md") {
139
+ const fm = director?.frontmatter || {}
140
+ const client = (fm.client || "").trim()
141
+ const domain = (fm.domain || "").trim()
142
+ const industry = (fm.industry || "").trim()
143
+ const service = (fm.service || "").trim()
144
+ const techStack = Array.isArray(fm.tech_stack) ? fm.tech_stack : []
145
+ const googleDrive = (fm.google_drive || "").trim()
146
+
147
+ const lines = [
148
+ `# ${configFilename}`,
149
+ "",
150
+ `This file provides guidance to ${configFilename === "AGENTS.md" ? "Codex" : "Claude Code"} when working with code in this repository.`,
151
+ "",
152
+ "## プロジェクト概要",
153
+ "",
154
+ ]
155
+ if (client) lines.push(`- **クライアント**: ${client}`)
156
+ if (domain) lines.push(`- **ドメイン**: ${domain}`)
157
+ if (industry) lines.push(`- **業種**: ${industry}`)
158
+ if (service) lines.push(`- **サービス**: ${service}`)
159
+ if (!(client || domain || industry || service)) {
160
+ lines.push("- (director frontmatter に該当情報なし)")
161
+ }
162
+ lines.push("")
163
+
164
+ if (techStack.length > 0) {
165
+ lines.push("## 技術スタック")
166
+ lines.push("")
167
+ for (const t of techStack) lines.push(`- ${t}`)
168
+ lines.push("")
169
+ }
170
+
171
+ lines.push("## 関連")
172
+ lines.push("")
173
+ lines.push(
174
+ `- **Hub Director**: \`[[${dirName}/_director]]\` — 案件の進行・意思決定・直近ログ`,
175
+ )
176
+ if (googleDrive) {
177
+ lines.push(`- **Google Drive**: \`$GDRIVE/${googleDrive}/\` — 成果物・素材`)
178
+ }
179
+ lines.push("")
180
+
181
+ if (repositorySection) {
182
+ lines.push(repositorySection)
183
+ }
184
+
185
+ lines.push("## 初期化")
186
+ lines.push("")
187
+ lines.push(
188
+ "これは hub-agent が director frontmatter から自動生成した雛形です。",
189
+ )
190
+ lines.push(
191
+ "開発手順・SSH 接続情報・横断ナレッジへのポインタなど、より詳細な内容は",
192
+ )
193
+ lines.push(
194
+ `このリポジトリで ${configFilename === "AGENTS.md" ? "`codex` を起動して `/init-Codex-md`" : "`claude` を起動して `/init-claude-md`"} スキルを実行してください。`,
195
+ )
196
+ lines.push("")
197
+ return lines.join("\n")
198
+ }
199
+
200
+ export function renderPlaceholder(dirName, repositorySection = "", configFilename = "CLAUDE.md") {
201
+ const sections = [
202
+ `# ${configFilename}`,
203
+ "",
204
+ `This file provides guidance to ${configFilename === "AGENTS.md" ? "Codex" : "Claude Code"} when working with code in this repository.`,
205
+ "",
206
+ "## 関連",
207
+ "",
208
+ `- **Hub Director**: \`[[${dirName}/_director]]\` — 案件の進行・意思決定・直近ログ (未作成)`,
209
+ "",
210
+ ]
211
+ if (repositorySection) {
212
+ sections.push(repositorySection)
213
+ }
214
+ sections.push(
215
+ "## 初期化",
216
+ "",
217
+ "これは hub-agent の自動生成プレースホルダです。Hub director も未作成です。",
218
+ `詳細を生成するには、このリポジトリで ${configFilename === "AGENTS.md" ? "`codex` を起動して `/init-Codex-md`" : "`claude` を起動して `/init-claude-md`"} スキルを実行してください。`,
219
+ "",
220
+ )
221
+ return sections.join("\n")
222
+ }