@cocorograph/hub-agent 0.6.58 → 0.6.59

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/main.mjs +57 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocorograph/hub-agent",
3
- "version": "0.6.58",
3
+ "version": "0.6.59",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの tmux/pty を中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
package/src/main.mjs CHANGED
@@ -10,7 +10,8 @@
10
10
  *
11
11
  * 仕様書: ナレッジ/インフラ/cockpit-hub-hosted-integration-spec (id=6080)
12
12
  */
13
- import { readFileSync, watch as fsWatch } from "node:fs"
13
+ import { spawn as _childSpawn } from "node:child_process"
14
+ import { existsSync, readFileSync, watch as fsWatch } from "node:fs"
14
15
  import { mkdir, readFile, readdir, rename, unlink, writeFile } from "node:fs/promises"
15
16
  import { randomUUID } from "node:crypto"
16
17
  import os from "node:os"
@@ -293,6 +294,57 @@ export async function syncTmuxProfileEnv(profile, log) {
293
294
  )
294
295
  }
295
296
 
297
+ /**
298
+ * `setup_hub_ai.py --silent` を best-effort でキックし、全プロファイルの settings.json へ
299
+ * bundle hooks (cockpit_permission_bridge 等) を反映させる。
300
+ *
301
+ * 新規プロファイル追加 (profile.add) 直後に呼ぶ。provisionProfile は
302
+ * `~/.claude/settings.json` を新プロファイルへコピーするが、コピー元が古い / setup 未走の
303
+ * タイミングだと新プロファイルにフックが欠けうる。setup_hub_ai は全プロファイル対応 (案1)
304
+ * なので 1 回叩けば新プロファイルの初回セッションでもフックが揃う。
305
+ *
306
+ * 失敗・未 setup 環境 (スクリプト不在 / python3 無し) でも **例外を投げない**。detached +
307
+ * stdio ignore で daemon をブロックしない。session_start.py の auto-update と同じ
308
+ * `--silent` で headless 実行する。
309
+ *
310
+ * @param {{logger?: object, spawnImpl?: Function, existsImpl?: Function, homedir?: string}} [opts]
311
+ * spawnImpl / existsImpl / homedir はテスト用の注入口 (既定は node 標準)。
312
+ * @returns {boolean} spawn を試みたら true、スクリプト不在等でスキップしたら false。
313
+ */
314
+ export function kickSetupHubAi({
315
+ logger,
316
+ spawnImpl,
317
+ existsImpl,
318
+ homedir,
319
+ } = {}) {
320
+ try {
321
+ const home = homedir || os.homedir()
322
+ const setupScript = path.join(home, ".claude", "scripts", "setup_hub_ai.py")
323
+ const exists = existsImpl || existsSync
324
+ if (!exists(setupScript)) {
325
+ logger?.info?.(
326
+ { setupScript },
327
+ "kickSetupHubAi: setup_hub_ai.py 不在 - skip",
328
+ )
329
+ return false
330
+ }
331
+ const doSpawn = spawnImpl || _childSpawn
332
+ const child = doSpawn("python3", [setupScript, "--silent"], {
333
+ detached: true,
334
+ stdio: "ignore",
335
+ })
336
+ child?.on?.("error", (e) =>
337
+ logger?.warn?.({ err: e?.message }, "kickSetupHubAi: spawn error"),
338
+ )
339
+ child?.unref?.()
340
+ logger?.info?.({}, "kickSetupHubAi: setup_hub_ai --silent を起動 (hooks 同期)")
341
+ return true
342
+ } catch (e) {
343
+ logger?.warn?.({ err: e?.message }, "kickSetupHubAi: 失敗 (無視)")
344
+ return false
345
+ }
346
+ }
347
+
296
348
  export async function startDaemon({ version, ptyModule, claudeSdk } = {}) {
297
349
  const config = await readConfig()
298
350
  if (!config) {
@@ -1795,6 +1847,10 @@ async function dispatch(msg, ctx) {
1795
1847
  needs_login: created.needsLogin,
1796
1848
  login_command: `CLAUDE_CONFIG_DIR=${created.configDir} claude`,
1797
1849
  })
1850
+ // 新規プロファイルへ bundle hooks (cockpit_permission_bridge 等) を即時反映する
1851
+ // best-effort キック (詳細は kickSetupHubAi の docstring 参照)。失敗・未 setup
1852
+ // 環境でも profile.add は成功扱い (kickSetupHubAi は例外を投げない)。
1853
+ kickSetupHubAi({ logger: ctx.logger })
1798
1854
  } catch (err) {
1799
1855
  ctx.client.send({
1800
1856
  type: "profile.add.result",