@cocorograph/hub-agent 0.6.77 → 0.6.79

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.77",
3
+ "version": "0.6.79",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの tmux/pty を中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -237,15 +237,33 @@ function Set-Systemd($distro) {
237
237
  }
238
238
  }
239
239
 
240
- # Register a logon task that wakes the distro (its systemd starts hub-agent).
240
+ # Register a logon task that keeps the distro ALIVE (so its systemd --user
241
+ # hub-agent stays online).
242
+ #
243
+ # 旧実装は `wsl ... /bin/true` で distro を一瞬起こすだけだった。これだと WSL2 の
244
+ # アイドルシャットダウンが数十秒で distro ごと畳んでしまい (agent.log に
245
+ # `SIGTERM shutting down` が出て `wsl -l -v` が Stopped になる)、hub-agent も停止して
246
+ # オフラインに戻る。systemd --user + linger は「distro が起動している間」しか効かない
247
+ # ため、distro 自体を起こし続ける常駐プロセスが必要。
248
+ #
249
+ # 対策: ログオン中ずっと `sleep infinity` を WSL 内で走らせて distro を起動状態に保つ。
250
+ # 併せて hub-agent.service を start しておく (enable + linger 済みなら冪等)。
241
251
  function Register-BootTask($distro, $user) {
242
- Write-Step "Registering autostart on logon (Task Scheduler)"
243
- $action = New-ScheduledTaskAction -Execute "wsl.exe" -Argument "-d $distro -u $user -- /bin/true"
252
+ Write-Step "Registering autostart on logon (Task Scheduler, keep-alive)"
253
+ # distro を起動し続ける keep-alive。systemctl start は冪等 (既に active なら no-op)。
254
+ $keepalive = "systemctl --user start hub-agent.service 2>/dev/null; exec sleep infinity"
255
+ $action = New-ScheduledTaskAction -Execute "wsl.exe" `
256
+ -Argument "-d $distro -u $user -- bash -lc `"$keepalive`""
244
257
  $trigger = New-ScheduledTaskTrigger -AtLogOn
245
- $set = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
258
+ # ExecutionTimeLimit=0 で無制限 (既定 72h で停止されると distro が落ちる)。
259
+ # keep-alive が万一終了したら 1 分後に最大 3 回まで再起動。多重起動は抑止。
260
+ $set = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries `
261
+ -StartWhenAvailable -MultipleInstances IgnoreNew `
262
+ -RestartInterval (New-TimeSpan -Minutes 1) -RestartCount 3 `
263
+ -ExecutionTimeLimit (New-TimeSpan -Seconds 0)
246
264
  Register-ScheduledTask -TaskName $TASK_NAME -Action $action -Trigger $trigger -Settings $set `
247
265
  -RunLevel Limited -Force | Out-Null
248
- Write-Ok "Logon task '$TASK_NAME' registered"
266
+ Write-Ok "Logon task '$TASK_NAME' registered (keeps WSL distro alive)"
249
267
  }
250
268
 
251
269
  # Run the existing install.sh inside WSL.
@@ -315,6 +333,16 @@ function Main {
315
333
  # --- autostart ---
316
334
  Register-BootTask $distro $user
317
335
 
336
+ # セットアップ完了時点でオンライン化まで完結させる: keep-alive タスクを今すぐ起動し、
337
+ # distro を起動状態に保つ (再ログオンを待たずに hub-agent が常駐する)。
338
+ Write-Step "Starting keep-alive now (online without re-logon)"
339
+ try {
340
+ Start-ScheduledTask -TaskName $TASK_NAME
341
+ Write-Ok "Keep-alive started; hub-agent should come online shortly"
342
+ } catch {
343
+ Write-Warn "Start-ScheduledTask failed ($($_.Exception.Message)); ログオンし直すと起動します"
344
+ }
345
+
318
346
  Write-Host ""
319
347
  Write-Ok "Setup complete. Check the online status in the Hub UI:"
320
348
  Write-Host " https://hub.cocorograph.com/user/cockpit/agents" -ForegroundColor Cyan
@@ -128,6 +128,43 @@ function run(cmd, args, opts = {}) {
128
128
  }
129
129
  }
130
130
 
131
+ /** 現在のユーザー名。systemd の linger 操作対象に渡す。 */
132
+ function currentUsername() {
133
+ try {
134
+ return os.userInfo().username
135
+ } catch {
136
+ return process.env.USER || process.env.LOGNAME || ""
137
+ }
138
+ }
139
+
140
+ /**
141
+ * systemd の user linger を有効化する (Linux 専用・非致命)。
142
+ *
143
+ * hub-agent.service は `WantedBy=default.target` の **user サービス**
144
+ * (`systemctl --user`) のため、linger が無いとログインセッションが無い間は
145
+ * user systemd インスタンス自体が起動せず、サービスも常駐しない。とくに WSL2 の
146
+ * 自動起動は「ログオン時 Task Scheduler が `wsl ... /bin/true` で distro を一瞬
147
+ * 起こす」方式のため、linger 無しだとそのコマンド終了と同時に user セッションが
148
+ * 畳まれ hub-agent が即停止する (= セットアップ後に自動起動しない主因)。
149
+ * `loginctl enable-linger <user>` で boot 時から user インスタンスを常駐させる。
150
+ *
151
+ * loginctl が無い / systemd 不在の最小環境では失敗しうるが、その場合でも
152
+ * install 自体は続行する (warn のみ)。
153
+ */
154
+ function enableLinger(opts = {}) {
155
+ const spawn = opts.spawnSync ?? spawnSync
156
+ const user = opts.user ?? currentUsername()
157
+ const r = spawn("loginctl", ["enable-linger", user], { stdio: "ignore" })
158
+ if (r.error || r.status !== 0) {
159
+ console.warn(
160
+ `warning: loginctl enable-linger ${user} に失敗しました ` +
161
+ `(systemd/loginctl 不在の可能性)。WSL2/headless では自動起動しない場合があります。`,
162
+ )
163
+ return false
164
+ }
165
+ return true
166
+ }
167
+
131
168
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
132
169
 
133
170
  /**
@@ -282,9 +319,18 @@ export async function installService({ bin } = {}) {
282
319
  await ensureDir(path.dirname(dest))
283
320
  await fs.writeFile(dest, expanded, { mode: 0o644 })
284
321
 
322
+ // linger を先に有効化する。これが無いと user サービスは login セッションが
323
+ // 無い間 (= WSL2 のログオンタスク経由の boot や headless) に常駐しない。
324
+ const linger = enableLinger()
285
325
  run("systemctl", ["--user", "daemon-reload"])
286
326
  run("systemctl", ["--user", "enable", "--now", SYSTEMD_UNIT_NAME])
287
- return { platform: "linux", path: dest, unit: SYSTEMD_UNIT_NAME, bin: hubAgentBin }
327
+ return {
328
+ platform: "linux",
329
+ path: dest,
330
+ unit: SYSTEMD_UNIT_NAME,
331
+ bin: hubAgentBin,
332
+ linger,
333
+ }
288
334
  }
289
335
 
290
336
  throw new Error(`unsupported platform: ${process.platform}`)
@@ -348,6 +394,8 @@ export async function uninstallService() {
348
394
  spawnSync("systemctl", ["--user", "disable", "--now", SYSTEMD_UNIT_NAME], {
349
395
  stdio: "ignore",
350
396
  })
397
+ // install 時に有効化した linger を戻す (非致命)。
398
+ spawnSync("loginctl", ["disable-linger", currentUsername()], { stdio: "ignore" })
351
399
  const dest = linuxUnitPath()
352
400
  try {
353
401
  await fs.unlink(dest)
@@ -370,4 +418,6 @@ export const _internal = {
370
418
  repoTemplatesDir,
371
419
  waitUntilBootedOut,
372
420
  bootstrapWithRetry,
421
+ currentUsername,
422
+ enableLinger,
373
423
  }