@cocorograph/hub-agent 0.8.68 → 0.8.69

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.68",
3
+ "version": "0.8.69",
4
4
  "description": "Hub Hosted Cockpit のローカル常駐 agent。Hub と outbound WSS で接続し、ローカルの Claude / Codex チャットと tmux セッションを中継する。",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -266,11 +266,42 @@ function Register-BootTask($distro, $user) {
266
266
  Write-Ok "Logon task '$TASK_NAME' registered (keeps WSL distro alive)"
267
267
  }
268
268
 
269
+ # Quote a value as ONE POSIX-shell word, so a quote inside it cannot end the
270
+ # quoting and turn the rest of the value into shell syntax. `'` becomes `'\''`
271
+ # (close, escaped quote, reopen): o'hare -> 'o'\''hare'.
272
+ #
273
+ # WARNING: this is bash quoting only. Do NOT reuse it for the PowerShell that
274
+ # Register-BootTask generates -- that text is parsed by PowerShell, not by a shell,
275
+ # and these escapes would be passed through literally.
276
+ function ConvertTo-BashSingleQuoted($value) {
277
+ return "'" + (([string]$value) -replace "'", "'\''") + "'"
278
+ }
279
+
269
280
  # Run the existing install.sh inside WSL.
281
+ #
282
+ # NOTE: do NOT use `curl ... | bash` here. A pipeline's exit status is the LAST
283
+ # command's, so curl failing (DNS, 404, proxy) still leaves $LASTEXITCODE at 0 and
284
+ # the guard below can never fire. That is exactly how this stayed broken: every run
285
+ # printed "[OK] Setup complete" while install.sh had not run at all (2026-09-09).
286
+ # Downloading to a file first makes curl's failure propagate through `&&`, and makes
287
+ # $LASTEXITCODE install.sh's own exit code. It also keeps install.sh's stdin free
288
+ # instead of handing it the script text.
289
+ #
290
+ # The EXIT trap removes the temp file when the run is interrupted. That one trap is
291
+ # enough: a bash waiting on a foreground job handles SIGTERM after that job returns,
292
+ # and exits through the normal path, so the EXIT trap runs and the exit code stays
293
+ # non-zero. WARNING: do NOT add `trap ... TERM` on top of it. A TERM trap that only
294
+ # cleans up and returns makes bash exit 0, i.e. a killed run would be reported as
295
+ # success -- the very failure mode fixed above (both measured 2026-09-10, bash 5.2.21).
270
296
  function Invoke-WslInstaller($distro, $user) {
271
297
  Write-Step "Setting up hub-agent inside WSL (existing install.sh)"
272
298
  $tok = if ($Token) { $Token } else { "" }
273
- $inner = "curl -fsSL '$INSTALL_SH' | HUB_AGENT_TOKEN='$tok' HUB_AGENT_URL='$HubUrl' bash"
299
+ # Single-quoted here so $t stays literal for bash; '' is a literal quote.
300
+ # `|| exit 1` covers mktemp failing before there is anything to clean up.
301
+ $fmt = 't=$(mktemp) || exit 1; trap ''rm -f "$t"'' EXIT; curl -fsSL {0} -o "$t" && HUB_AGENT_TOKEN={1} HUB_AGENT_URL={2} bash "$t"'
302
+ $inner = $fmt -f (ConvertTo-BashSingleQuoted $INSTALL_SH),
303
+ (ConvertTo-BashSingleQuoted $tok),
304
+ (ConvertTo-BashSingleQuoted $HubUrl)
274
305
  wsl.exe -d $distro -u $user -- bash -lc $inner
275
306
  if ($LASTEXITCODE -ne 0) { throw "install.sh inside WSL failed (exit $LASTEXITCODE)" }
276
307
  }
@@ -1443,12 +1443,26 @@ main() {
1443
1443
  }
1444
1444
 
1445
1445
  # このファイルが source されたか(実行されたか)を判定する。
1446
- # - `bash -c "$(curl ...)"` / `curl ... | bash` : BASH_SOURCE が空 → 実行
1447
- # - `bash install.sh` / `./install.sh` : BASH_SOURCE[0] == $0 → 実行
1448
- # - `source install.sh`(test/install-sh.test.mjs): BASH_SOURCE[0] != $0 → source
1446
+ # - `bash -c "$(curl ...)"` / `curl ... | bash` / `bash -s` : 実行
1447
+ # - `bash install.sh` / `./install.sh` : 実行
1448
+ # - `source install.sh`(test/install-sh.test.mjs) : source
1449
+ #
1450
+ # ⚠️ `BASH_SOURCE[0]` と `$0` の比較で判定してはいけない。関数の中で見る
1451
+ # `BASH_SOURCE[0]` は「その関数が定義されたファイル」を指すが、標準入力から読ませた
1452
+ # ときの値は bash の版で割れる: bash 5.2 系は文字列 `main`、bash 3.2 / 5.3 は空。
1453
+ # 5.2 系では `main` != `bash` が成立して **source と誤判定**され、
1454
+ # `curl ... | bash` のワンライナーが main を呼ばずに無言・exit 0 で終わっていた
1455
+ # (2026-09-09 実測。Ubuntu 24.04 の 5.2.21 / Debian trixie の 5.2.37 で再現し、
1456
+ # macOS の 3.2.57 / 5.3.15 では再現しない。開発機だけで確かめると気づけない)。
1457
+ #
1458
+ # FUNCNAME はコールスタックで、bash は source したファイルのトップレベルを `source`
1459
+ # という枠として積む。したがってこの関数をトップレベルから呼ぶと、source されたときだけ
1460
+ # `FUNCNAME[1]` が `source` になる。3.2 / 5.2 / 5.3 のいずれでも一致する。
1461
+ # ⚠️ この関数は**トップレベルから直接呼ぶこと**。別の関数を挟むと `FUNCNAME[1]` が
1462
+ # その関数名になり、判定が壊れる。
1449
1463
  # 環境変数で切り替えると、変数が残ったシェルや CI でワンライナーが無言の no-op になるため使わない。
1450
1464
  _install_sh_is_sourced() {
1451
- [[ -n "${BASH_SOURCE[0]:-}" && "${BASH_SOURCE[0]}" != "$0" ]]
1465
+ [[ "${FUNCNAME[1]:-}" == "source" ]]
1452
1466
  }
1453
1467
 
1454
1468
  if ! _install_sh_is_sourced; then