npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tyhld/conductor

v0.12.138

Published

采配くん管制の見守りアプリ(conductor-agent)。各PCで常駐し、中央(devlog-tracker)へ定期的に生存報告(heartbeat)を送る常駐CLI。

Readme

@tyhld/conductor(見守りアプリ / conductor-agent)

采配くん管制の「見守りアプリ」です。 各PCで動かしておくと、自分がいま作業中であること(生存報告 / heartbeat) を、 30秒ごとに中央サーバー(devlog-tracker)へ自動で送り続けます。

中央の管制画面では、どのPCがどの現場(リポジトリ)で、どのブランチを、 作業中(working)か待機中(idle)かが一覧で見えるようになります。

仕組みはシンプルです。あなたのPCから中央へ「生きてます」という小さな合図を 定期的に送るだけ。難しい設定は要りません。


これは何をするもの?

  • conductor start を実行すると、その場で常駐します。
  • 起動した瞬間に1回、そのあとは 30秒ごと(変更可)に中央へ報告します。
  • 報告する内容: PC名 / 現場名(リポ名) / ブランチ名 / 状態(working/idle) / 直近の作業メモ。
  • 止めたいときは Ctrl+C を押すだけです。

現場名(site)とブランチ名は、コマンドを実行したフォルダの git 情報から自動で判定します。 git のフォルダでなければ、現在のフォルダ名を現場名として使います。


必要なもの

  • Node.js 18以上(node -v で確認できます)

導入(他PC向け / git clone 方式)

メンバーの各PCで conductor を導入・起動する手順です。3人規模では git clone での配布で十分なので、現段階では GitHub Packages への publish は行いません(人数が増えたら publish 配布を再検討します)。

前提

  • Node.js 18以上(node -v で確認)
  • git
  • 対象リポジトリへのアクセス権(GitHub tyhld org)

手順

# 1) clone(URL は conductor リポジトリのもの)
git clone https://github.com/tyhld/conductor.git
cd conductor

# 2) 依存インストール
npm install

# 3) ビルド(tsc で dist/ を生成)
npm run build

各自で設定する環境変数

| 環境変数 | 値 | 備考 | |----------|----|------| | CONDUCTOR_URL | https://<your-conductor-host>(中央) | 接続先 | | CONDUCTOR_TOKEN | Bitwarden から取得 | テナントトークン。値はここに書きません | | CONDUCTOR_MACHINE | 任意 | PC識別名。未設定なら os.hostname() |

🔑 鍵(CONDUCTOR_TOKEN)は Bitwarden の共有項目から取得してください。 コード・リポジトリ・この README には値を一切書きません。

設定して起動する例:

export CONDUCTOR_URL=https://<your-conductor-host>
read -s -p 'tenant token: ' CONDUCTOR_TOKEN && export CONDUCTOR_TOKEN
node dist/cli.js start            # もしくは scripts/conductor-start.sh(後述)

補足: 配布は公開 npm(@tyhld/conductor・取得先 https://registry.npmjs.org)1本です。各PCの常駐は、入っている配布物(npm install -g で入れた物)だけを動かし、clone した作業ツリーは動かしません(scripts/dist-source.sh)。

  • 自動更新が入っているPC(自社PC): 版は更新係(tyhld-autoupdate)が、管制の決めた版へ段階的にそろえます(先行機 → 自己診断 PASS → 残りのPCへ1台ずつ)。人が npm install -g で入れると順番が崩れるので打ちません。入れ方は下の「自社PCの自動更新」。
  • 自動更新が入っていないPC(お客さまのPC・入れる前の機): 人が npm install -g @tyhld/conductor --@tyhld:registry=https://registry.npmjs.org で入れ直します。

自社PCの自動更新(★自社PCだけ・人が更新の窓で1回)

bash "$(npm root -g)/@tyhld/conductor/scripts/autoupdate-install.sh"          # まず確認だけ(書き込みなし)
APPLY=1 bash "$(npm root -g)/@tyhld/conductor/scripts/autoupdate-install.sh"  # 入れる
~/.tyhld/bin/tyhld-selfcheck --now                                             # 自己診断を1回

★更新の窓で打つ行(ノートPC → メインPC → 社員PC・Ubuntu と PowerShell・再起動後の確かめ・止まったときの読み方)は1枚にまとめてあります: docs/自社PC-更新の窓-手順書.md。仕組みと決まりは ADR-027。

鍵(~/.tyhld/bin/autoupdate/enabled)・更新係と自己診断のタイマー・Claude Code 自身の自動更新を止める設定(DISABLE_AUTOUPDATER=1)を置きます。Claude Code が公式推奨の1方式(curl -fsSL https://claude.ai/install.sh | bash)だけになっていなければ、人が打つ行を出して止まります。お客さまの導入台本(sales-template/install.sh・setup.sh)には入っていません。


新PCの初回セットアップ(ブラウザ検品の道具)★人が1回だけ流す

職人(Claude Code)がブラウザ検品(Playwright)を行うPCでは、最初に1回だけこの2本を流してください。 流していないPCでは、職人が検品のたびに端末へ「サンドボックス外通信の許可(Host: cdn.playwright.dev)」を出して止まります。 この問いは番人を通らないため管制のカードに出せず、端末でしか押せません(→ 便が人待ちになる。経緯は ADR-010)。

# A) 共有ブラウザ … PCに1回だけ Chromium と playwright を入れる(職人は毎便ダウンロードしなくなる)
bash scripts/pw-browser-install.sh              # まず予定を表示(書き込みなし)
APPLY=1 bash scripts/pw-browser-install.sh      # 実際に入れる

# B) 通信許可(保険) … それでも取得が要るときのため、各現場へ許可ドメインを配る
bash scripts/update-allowed-domains.sh          # まず予定を表示(書き込みなし)
APPLY=1 bash scripts/update-allowed-domains.sh  # 実際に配る
  • A は何を置くか: $HOME/.tyhld/pw-venv(版を固定した playwright)と $HOME/.tyhld/pw-browsers(Chromium の実体)。 番人の $HOME/.tyhld/hooks と同じ「1台に1箇所」の流儀です。入れた後に実行ファイルの実在・サンドボックス内から読めるか・実際に起動するかを実測して表示します。
  • 職人は自分で入れません。$HOME/.tyhld はサンドボックスの中から読めるが書けないので、道具が無ければ職人はそこで止まり「人の手番」と報告します(鉄則8)。
  • B は他を触りません。sandbox.network.allowedDomains に不足分を追記するだけで、permissions(deny/ask/allow)・hooks は1文字も変えません。 scripts/update-guard.sh(全部入り)を流す場合は同じ一覧が同時に配られるので、B は不要です。
  • ★2026-09-03(甲)以降、外への通信は全部通します(allowedDomains: ["*"])。この問いは管制の3ボタンでは押せないと実測で確定したため(Claude Code 2.1.258 本体の作り)、聞かれる前に通して職人を自走させます。
    • 配るのは APPLY=1 bash scripts/update-guard.sh です(①-e3 がホームの ~/.claude/settings.json へ1か所だけ配る)。B は sandbox を持つ現場しか対象にしないので、B だけでは届かない現場があります。
    • 緩むのは「電話をかける」だけです。秘密の持ち出し(.env / ~/.ssh / $DATABASE_URL など)を止める番人は別の仕組みで、1ミリも緩みません。本番DBへの直結禁止(deniedDomains)も "*" より先に効くため、そのまま閉じたままです。
  • 鉄則(職人の作業規律)を直したときは APPLY=1 bash scripts/update-guard.sh を流してください。 稼働中の機体では ~/.claude/skills/conductor-craftsman/SKILL.md が古い写しのまま残るため、 これを流さないと職人の動きは変わりません(update-guard.sh ①-d。同一なら何もしません)。
  • setup.sh からは呼びません。顧客機の初期設置に大きなダウンロードを足すと設置そのものが止まるためです(ADR-010)。

職人が始まるのに要る物(先頭の確かめ・0.12.82〜)

1行インストーラ(sales-template/install.sh)と scripts/update-guard.sh は、設定を配る前に次を確かめ、足りなければ止まって「人が打つ1行」を出します。★台本は自分で sudo を打たず、何も入れません。

  • 職人のソフト(Claude Code)が 2.1.282 以上(えふさん確定 2026-10-02)。中継と同じ場所を同じ順で探し、いちばん新しい版で判定します。上げ方は入れ方で違います。
    • ネイティブ導入(~/.local/bin/claude)… ~/.local/bin/claude update
    • npm 導入(nvm の bin)… npm install -g @anthropic-ai/claude-code@latest
  • 囲いの部品(Linux・WSL): bwrap(bubblewrap)と socat。無いと職人が安全のため起動を断ります(設定 sandbox.failIfUnavailable)。
    • sudo apt-get install -y bubblewrap socat
    • sudo のパスワードが分からないとき(WSL・Windows の PowerShell で): wsl.exe -u root apt-get install -y bubblewrap socat
    • Mac は囲いが OS に組み込みなので求めません。分からない機は止めずに「確かめられませんでした」と出します。
  • 確認だけ(bash scripts/update-guard.sh)のときは、職人が管制へ知らせる口(ai-kana の MCP)がつながっているかも1行で出します(止めません)。

使い方

最低限、次の2つの環境変数を渡して conductor start を実行します。

CONDUCTOR_URL=https://<your-conductor-host> \
CONDUCTOR_TOKEN=(テナントトークン) \
  conductor start

実行すると、こんな1行ログが定期的に流れます。

[conductor] 開始: machine=my-pc site=kenzokun status=working interval=30s url=https://...
[conductor] 10:00:00 site=kenzokun status=working -> HTTP 200 OK
[conductor] 10:00:30 site=kenzokun status=working -> HTTP 200 OK

止めるときは Ctrl+C。

よく使うオプション

# 現場名を手動で指定したいとき
conductor start -s kenzokun

# 待機中として報告したいとき
conductor start -t idle

# 直近の作業メモを添えたいとき
conductor start -a "ログイン画面を実装中"

| 引数 | 意味 | 既定値 | |------|------|--------| | -s <site> | 現場名(リポ名) | git リポ名 → 無ければカレントフォルダ名 | | -t <idle\|working> | 状態 | working | | -a <lastAction> | 直近の作業メモ(自由文) | heartbeat |


環境変数一覧

| 環境変数 | 必須 | 意味 | 既定値 | |----------|------|------|--------| | CONDUCTOR_URL | ✅ | 中央(devlog-tracker)のベースURL。例: https://<your-conductor-host> | (なし) | | CONDUCTOR_TOKEN | ✅ | テナントトークン。中央API側の同名 env と一致させます | (なし) | | CONDUCTOR_MACHINE | – | PCの識別名 | os.hostname()(PCのホスト名) | | CONDUCTOR_INTERVAL_SEC | – | heartbeat送信間隔(秒) | 30 | | CONDUCTOR_RELAY_ENABLED | – | true で relay(指示の取得→アイドル時のみ tmux 送信→完了検出)を有効化 | false | | CONDUCTOR_RELAY_INTERVAL_SEC | – | relay のポーリング間隔(秒) | 15 | | CONDUCTOR_NUDGE_DIR | – | 耳 → relay の呼び鈴(空ファイル)の置き場 | $XDG_RUNTIME_DIR/conductor | | RELAY_FETCH_TIMEOUT_MS | – | 管制への問い合わせ1回の上限(ミリ秒)。返らない通信で relay が固まらないための上限 | 20000 | | RELAY_RECONNECT_BASE_MS | – | 管制へつながらないときの、最初の再試行までの待ち(ミリ秒)。以後 倍々に伸ばす | 5000 | | RELAY_RECONNECT_MAX_MS | – | 再試行の待ちの上限(ミリ秒)。★上限に達したあとも永久に試し続けます | 60000 |

管制につながらないとき(★relay は止まりません):管制(中央)が落ちる・切れる・応答しない・ 401 や 5xx を返す——このいずれでも relay は止まらず待って再試行します。待ちは 5秒 → 10 → 20 → 40 → 60秒 と伸び、60秒で頭打ち(以後は60秒おきに永久に)。つながらない間は 画面に 管制につながらない・再試行中(N回目・次は◯秒後) を毎回1行出し続け(黙りません)、 つながったら 管制に再接続しました を1行出して通常の間隔(15秒)へ自動で戻り、 自分の生存報告を1回送り直します。安全のため、つながらない間は職人へ便を配りません (管制と話せないのに送るのは危険)。人が exit → 再起動する必要はありません。

relay(ADR-029 段階3 / 既定 off):CONDUCTOR_RELAY_ENABLED=true のときだけ、 中央から自分宛(machine+site)の指示を取得し、送信先のtmuxセッション(名前 = 現場名 site)が 完全にアイドルのときだけ 指示を流し込みます。少しでも作業中っぽければ送らず次回に再挑戦する 保守的な判定(「誤爆より送り遅れ」)です。off の間は従来どおり heartbeat のみで挙動は変わりません。

指示の着信合図(ADR-066):relay 有効時は、上のポーリングに加えて、耳(下記)から届く 「今すぐ1周して」の呼び鈴でも動きます。指示が積まれてから職人へ届くまでの最大15秒の待ちが消えます。 呼び鈴は空ファイルの touch で、指示本文もトークンも載りません。指示の中身は従来どおり 既存の取得APIから取り直します。耳が動いていなくても、relay は上記の間隔のポーリングで これまでどおり完全に動きます(耳は加速装置であって依存先ではありません)。


耳(conductor ear)— このPCに1本の合図受け取り役

conductor ear は、中央からの「指示が積まれた」合図(Supabase Realtime)を PCにつき1本 の接続で 受け取り、その現場の relay(conductor@<現場>)へ「今すぐ1周して」とだけ伝える常駐です。 接続本数がソフト数ではなく PC数 で決まる形にするための集約役です(ADR-066 便2c)。

| | conductor@<現場> | conductor-ear | |---|---|---| | 本数 | 現場ごとに1本 | PCごとに1本 | | 役目 | heartbeat + relay(指示の配達・完了検出) | 合図を受けて relay へ呼び鈴を送るだけ | | 職人(tmux)への書き込み | する | しない(指示も取らない) |

  • 耳 → relay の呼び鈴は、置き場(既定 $XDG_RUNTIME_DIR/conductor、CONDUCTOR_NUDGE_DIR で変更可)に 置かれた 空ファイル <現場名>.nudge を書き直すだけ。relay は起動時に自分のファイルを作り (=「この現場が動いている」の名簿にもなります)、フォルダを見張ります。
  • このPCで動いていない現場宛ての合図は、渡さずログだけ残します。
  • 接続先URL・公開鍵・購読設定は中央の POST /api/conductor/realtime-token の応答から受け取るため、 追加の環境変数はありません(必要なのは CONDUCTOR_URL / CONDUCTOR_TOKEN だけ)。
  • 切断は自動で張り直し(5秒→10秒→…最大5分)、トークンは失効前に取り直します。
  • Node の版要件は上がりません(18以上のまま)。合図の通信に使う WebSocket は、実行環境に標準品が あればそれを、無ければ同梱の ws を使います(Node に標準の WebSocket が入ったのは 22 からで、 20 以下では Node.js detected but native WebSocket not found. で耳が張れませんでした)。 お客さま機の Node を上げていただく必要はありません。
  • 中央にRealtimeが未設定・@supabase/supabase-js 未インストール・耳を止めている——いずれの場合も relay は15秒ポーリングでそのまま動きます。

導入(ADR-066 便2e で自動化済み)

耳はどちらの導入経路でも自動で入ります。人が手でユニットを置く必要はありません。

| 機 | 入り方 | |---|---| | お客さま機 | bash setup.sh <現場名> の中で自動(⑥ systemd の段) | | 自社機 | bash scripts/systemd-install.sh の中で自動 | | 手動で入れ直す | bash systemd/ear-install.sh | | 前面で試す | bash scripts/ear-start.sh |

systemctl --user status conductor-ear      # 「合図の受け取りを開始しました」が出れば成功
journalctl --user -u conductor-ear -f      # ログ

# やめる(relay は15秒ポーリングでそのまま動きます)
systemctl --user disable --now conductor-ear
  • ユニットの正本は systemd/conductor-ear.service の1つだけ。ExecStart は配置時に systemd/ear-install.sh が「その機で実際に動くコマンド」へ置換します(お客さま機は npm の conductor、自社機はリポジトリの dist/cli.js)。そのままコピーしても動きません。
  • 耳が入らない機(systemd が無い・コマンドが見つからない等)でも、セットアップは成功扱いで進みます。 警告を残して先へ進み、relay は15秒ポーリングで従来どおり動きます。

台帳と掃除の順序(便2c の申し送り・便2e で解消):setup.sh の古いユニット掃除は 「台帳に載っている @ 無しの conductor-*.service」を撤去します。conductor-ear.service は その綴りに当たるため、掃除の例外(CURRENT_MACHINE_UNITS)に先に入れてから台帳へ載せています。 順序が崩れると「自分で入れた耳を次回セットアップで自分で消す」壊れ方をするので、 test/setup-ear-order.test.ts が順序と振る舞いを固定しています。


司令塔(conductor build-runner)— このPCに1本の試作の段取り役

conductor build-runner は、お客さまが管制で「この内容で試作する →」を押した設計書を拾い、 便(作業指示)に分けて管制へ1本ずつ積み、終わるまで見届ける常駐です(試作完走 便⑥)。 ねらいは「押したあと、人を止めない」こと。

| | conductor@<現場> | conductor-ear | conductor-build-runner | |---|---|---|---| | 本数 | 現場ごとに1本 | PCごとに1本 | PCごとに1本 | | 役目 | 指示の配達・完了検出 | 合図の前倒し | 指示を作って積む | | 職人(tmux)への書き込み | する | しない | しない |

流れ

① 探す  GET /api/proto/specs?status=approved&built=false   (60秒ごと+合図があれば即)
② 計画  会議(ai-roundtable)に便の一覧を起草させる
        ★返らなければ設計書(画面・データ・機能)から機械的に組む
③ 書く  POST /api/proto/records   collection='_build'  kind='plan'
        ★計画を書いた時点で①から外れる=同じ試作を二度始めない
④ 積む  POST /api/conductor/commands/enqueue(gate=white・現場 ai-kana-proto)
        ★同時1本。前の便が終わるまで次を積まない
⑤ 待つ  GET /commands/done(結末・報告)/GET /commands/:id(時間切れ等)//commands/orphans
⑥ 書く  POST /api/proto/records   kind='progress'(何本目・終わった数・結末・URL・通った数)
⑦ 直す  詰まったら同じ便を積み直す(最大3回)。超えたら止めて人へ回す
⑧ 締め  公開の便の報告の `URL:` から触れる場所、動作確認の便の `ACCEPTANCE: n/m` から通った数
  • 進み具合の正は中央('_build' に書いたもの)。この常駐が手元に持つのは 「いまどの試作の何本目を待っているか」だけで、置き場は ~/.local/state/conductor/build-runner.json(600)。
  • 落ちても続きから。起動時に GET /api/proto/builds/:projectId で計画と進み具合を読み直します。 手元の覚え書きが消えていても、積む前に必ず管制へ確かめるので同じ便を二度積みません。
  • 会議が使えなくても止まりません(設計書から組み立てて進みます)。
  • 記録(journalctl)には型番も鍵も出しません(redact が伏せます)。

導入(★人が明示的に入れます)

お客さま機の setup.sh からは入りません。試作を回す機だけに人が入れます。

# ~/.conductor.env に4つ足す(値は弊社からお渡しします)
#   PROTO_API_BASE=https://ai-kana.ty-hld.com
#   CONDUCTOR_PROTO_APP_KEY=…   ★司令塔専用の合言葉(試作アプリのものとは別)
#   ROUNDTABLE_BASE_URL=…
#   ROUNDTABLE_APP_KEY=…

bash systemd/build-runner-install.sh
journalctl --user -u conductor-build-runner -f
systemctl --user disable --now conductor-build-runner   # やめる
  • 4つが揃っていなければ設置台本が入れずに止まり、起動しても何が足りないかを言って止まります (黙って動かないのがいちばん困るため)。
  • 配備先は Vercel の試作プロジェクト(人が vercel.com/new で作り、main への push で自動配備)。 用意されていなければ公開の便がその旨を報告し、司令塔は「公開先の準備が要ります」で止めて人へ回します。
  • ユニットの正本は systemd/conductor-build-runner.service の1つだけ(耳と同じ作法)。 setup.sh の掃除の例外(CURRENT_MACHINE_UNITS)にも入れてあります。

CI(GitHub Actions)

main への push と、main を base とする pull request で .github/workflows/ci.yml が回ります。 ジョブは test の1本だけで、次を順に実行します(Node 22 / ubuntu-latest)。

| ステップ | コマンド | 見ているもの | |----------|---------|-------------| | Build | npm run build | TypeScript がコンパイルできるか(tsc) | | Test | npm test | relay 等の単体テスト(node --test) | | Hook test | python3 scripts/hooks/test_policy.py | 番人(policy.py / cc2_guard.py)の deny/allow/defer 判定 | | Shell syntax | bash -n(scripts と sales-template の *.sh) | シェルスクリプトの構文エラー | | Shell static analysis | shellcheck -x --severity=warning(同じ *.sh) | 未定義変数・クォート漏れ・空変数展開など bash -n が見ない欠陥 |

ローカルで同じチェックを回すには:

npm run build
npm test
python3 scripts/hooks/test_policy.py
for f in scripts/*.sh sales-template/*.sh sales-template/systemd/*.sh; do bash -n "$f"; done
shellcheck -x --severity=warning scripts/*.sh sales-template/*.sh sales-template/systemd/*.sh

lint / format は package.json の scripts に未定義のため CI に載せていません。 shellcheck はローカルには未導入です(CI の ubuntu-latest には標準搭載)。手元で回すなら sudo apt install shellcheck 等で入れてください。

Node のバージョン要件(実行と開発で意図的に違う)

| 要件 | バージョン | どこで表明しているか | |------|-----------|---------------------| | 実行要件(常駐を動かす) | Node 18 以上 | package.json の engines.node、sales-template/setup.sh の前提チェック、上の「必要なもの」 | | 開発・テスト要件(npm test を回す) | Node 22 以上 | .nvmrc(22)、CI の node-version: 22 |

  • 常駐(heartbeat / relay)が実行するのは tsc でコンパイル済みの dist/cli.js なので Node 18 で動きます。実際、この開発機の systemd は /usr/bin/node = v20.20.0 で稼働しています。
  • Node 22 が要るのは npm test が --experimental-strip-types で .ts を直接実行するときだけです。
  • この2つを混同して engines.node に開発要件(22)を書いてはいけません。 Node 18/20 の環境で npm i -g @tyhld/conductor が EBADENGINE 警告を出し、engine-strict=true の環境では実行できるのにインストールが拒まれます。
  • 開発時は nvm use / fnm use が .nvmrc を読んで 22 に切り替えます。

配布(リリース)★人が npm publish を打つ手順はありません

配布先は公開 npm(registry.npmjs.org)1本です(えふさん決定 2026-09-04)。

やることは1つだけ

package.json の version を上げて main に入れる。 それだけです。 main への push で .github/workflows/release.yml が走り、次のように動きます。

| 判定 | 動き | |---|---| | version が公開 npm の latest より新しい | build → テスト → npm publish(公開 npm へ) | | 同じ・古い | 何もしない(版を上げ忘れても事故りません) |

版を上げる必要があるのは、配布物を変えたときだけです(便 fb248f6e)。 配布物=package.json の files に載る物(README.md も含む)と、dist の元(src・tsconfig.json)、package.json・package-lock.json。 docs/・test/・.github/ だけの変更は版を上げずに緑で合流でき、合流しても公開は「出しません」で何も起きません。 配布物を変えたのに版がそのままだと、試験(test/release-public-npm.test.ts の「★空振り確認」)が赤で止めます。 くらべる相手は公開 npm の latest を出したコミット(gitHead)で、それが確かめられないときは安全側(版上げを求める)に倒れます。

★人が npm publish を打ってはいけません。

公開 npm には 0.3.0 しか出ておらず、0.5.0 は GitHub Packages(非公開) に出ていました。 手元で npm publish を打つと、そのPCの ~/.npmrc の @tyhld スコープ設定(GitHub Packages 向き)が効いてしまうためです。

その結果お客さまは公開 npm の 0.3.0 を掴みます。0.3.0 の中身は古い鍵の名前(CONDUCTOR_SHARED_SECRET)を読むので、いまの接続情報(CONDUCTOR_TOKEN)では「未設定です」で落ちます(migakia の設置で再現)。

根治は「人のPCの設定に依存しない場所から出す」こと。 CI から出せば、誰のPCの .npmrc も関係なくなります。 あわせて package.json に publishConfig(registry = 公開 npm / access = public)を明記してあります。publishConfig は publish のときだけ効き、.npmrc のスコープ設定より優先されます。取得側(他リポの @tyhld/* 部品)は一切変えていません。

どうやって名乗るか — Trusted Publishing(合言葉を持たない)

★合言葉(トークン)は使いません。 GitHub が発行する**身分証(OIDC)**で名乗ります。

npm 側に「この org のこのリポジトリのこのワークフローなら出してよい」とあらかじめ登録しておき、実行のたびに GitHub が短命の身分証を出します。

| なぜトークンをやめたか | |---| | npm の書き込みトークンは最長90日で切れる。切れるたびに人が入れ替える運用は続きません | | npm はトークンでの直接公開を 2027-01 に廃止予定(npm の画面に明記) | | トークンを作らない・置かない・配らない = 漏れて困るものが存在しない |

★証明書(--provenance)は付けていません。 証明書は公開リポジトリからしか出せない仕組みで、 非公開のこの conductor では E422(Only public source repositories are supported when publishing with provenance)で弾かれました(実測 2026-09-04・run 33785720505)。 conductor は非公開のままにするので、証明書のほうを外しています。 名乗り方(Trusted Publishing)はそのままで、認証はこれで通っています。

人の手番は1回だけ — npmjs に「出してよい相手」を登録する

https://www.npmjs.com/package/@tyhld/conductor → Settings → Trusted publisher → GitHub Actions で、次の5項目を入れて保存します。

| 入力欄 | 入れる値 | |---|---| | Publisher | GitHub Actions | | Organization or user | tyhld | | Repository | conductor | | Workflow filename | release.yml | | Environment name | (空のまま) |

★Workflow filename は release.yml(パスではなくファイル名だけ)。ここが違うと、 npm は「知らないワークフローからの publish」として拒みます。 Release はこの詰まり方を見分けて、上の表と同じ値を画面に出します。

★**NPM_TOKEN は使いません。** GitHub Secrets に入っていても参照しません。 「トークンでも出せる」道を残すと、どちらの経路で出たのか分からなくなるためです。 (0.3.0 への deprecate だけは npm の画面から人が打ちます。下記)

  1. main に入ったあと、Actions → Release の実行を開く
  2. 「公開 npm へ出す(Trusted Publishing)」 が緑になっていること(出しました。 が出ます)
  3. https://www.npmjs.com/package/@tyhld/conductor を開き、版が上がっていること

黒い画面で確かめるなら、次の1行で latest が読めます。

curl -s https://registry.npmjs.org/@tyhld/conductor | jq -r '."dist-tags".latest'

古い版に「使わないで」の印を付ける(1回だけ・人の手番)

公開 npm に残っている 0.3.0 は動きません。次の1行で印を付けてください(npm login 済みの端末で)。

npm deprecate @tyhld/[email protected] "古い版です。0.5.0 以上を使ってください"

消す(npm unpublish)のではなく deprecate(印を付ける)にします。消すと、その版を掴んでいる機体の再インストールが失敗するためです。

最低版

sales-template/install.sh と sales-template/setup.sh は MIN_CONDUCTOR_VERSION(この2か所だけ・テストで同一を固定)より古い本体を見つけると、更新を試し、それでも古ければ止まって案内します。


よくある質問

Q. オフライン(offline)は送らないの? A. 送りません。中央側は「最後の生存報告からの経過時間」でオフラインを判定する設計です。 そのため Ctrl+C で止めると、しばらく後に中央画面側で自動的にオフライン表示になります。

Q. 鍵(トークン)はどこに書くの? A. コードやリポジトリには絶対に書きません。 実行時に環境変数で渡してください。


職人(CC2)の起動手順 ★現行(2026-07-31 確定)

人が CC2(Claude Code)を起こすときの現行手順です。tmux で「箱」を作り、その中で職人を1コマンドで起動します。

① 箱(tmux)を作って入る

tmux new -s <現場名> -c ~/projects/<現場名>   # 例: tmux new -s kenzokun -c ~/projects/kenzokun

duplicate session と出たら既存の箱があります(=起動済み)。新しく作らず attach してください(並列禁止)。

tmux attach -t <現場名>

② tmux の中で職人を起動する

unset ANTHROPIC_API_KEY && claude --permission-mode acceptEdits

1コマンドで、最初から accept edits on の状態で立ち上がります(起動後に Shift+Tab で切り替える運用は不要になりました)。

relay の常駐を確認

systemctl --user is-active conductor@<現場名>.service
# active でなければ
systemctl --user enable --now conductor@<現場名>.service

補足

  • 画面下の緑の帯=いま tmux の中にいる印。
  • 認証ダイアログは Esc で閉じる。
  • 初回の trust 確認は Yes。
  • 箱から抜けるのは Ctrl+b → d(デタッチ。職人はそのまま動き続けます)。

補助スクリプト: CC2のワンタッチ起動(scripts/cc2.sh)※旧手順(履歴)

現行の起動手順は上の「職人(CC2)の起動手順」です。 本節は経緯として残しています(スクリプト自体は削除していません)。

CC2(人が起動する Claude Code)の起動手順を1コマンドに畳んで、起動ミスを根治するためのスクリプトです。 「箱(tmux)が未起動なのに気づかず指示だけ待機」「cd 忘れ / unset 忘れ / 現場名のタイプミス / 二重起動」を構造的に防ぎます。

bash scripts/cc2.sh <現場名>   # 例: bash scripts/cc2.sh kenzokun

~/.bashrc に次の alias を足すと、cc2 kenzokun だけで起動できます(.bashrc の自動編集はしません。手動で追記してください):

alias cc2='bash ~/projects/conductor/scripts/cc2.sh'

やること:

  • 引数なし → usage といま起動できる現場名(~/projects にフォルダが在るもの)を表示して終了。
  • フォルダが無い現場名 → **似た候補を提示(タイプミス検出)**してから一覧を表示。
  • 二重起動防止: 同名 tmux セッションがあれば attach するだけ(並列禁止)。同じディレクトリで動く別名セッションがあれば軽く警告。
  • 新規セッションは作業ディレクトリで作成 → unset ANTHROPIC_API_KEY → claude を起動 → attach。cd 忘れ・unset 忘れを構造的に不可能にします。

現場名の解決は scripts/sites.sh を単一の真実として再利用します(決め方を二重定義しない)。 ★2026-09-04 変更: 新しい現場は sites.sh を直す必要がありません。 起動できるかどうかは ~/projects/<現場名> がフォルダとして在るかだけで決まります(mkdir -p ~/projects/<名前> で足りる)。 以前は sites.sh の配列に名前を書き足すまで「未知の現場名です」で止まっていました(新現場 migakia で実測)。 sites.sh の配列に残っているのは ①置き場が既定と違う現場の対応表(plus1 → plus1-foryou、 jichinavi → ~/jichinavi)と ②一括処理(deploy-guard.sh / restart-all-cc2.sh)が回る名簿だけで、 起動可否には使いません。破壊的操作(tmux kill 等)はしません。


補助スクリプト: CC2の起動(scripts/cc2-start.sh)※旧手順(履歴)

現行の起動手順は上の「職人(CC2)の起動手順」です。 本節は経緯として残しています。

人が CC2(Claude Code)を起動するときの「tmux new → cd → unset ANTHROPIC_API_KEY → claude」を1コマンドにまとめた補助です(常駐/報告役とは無関係)。cc2.sh の前身で、タイプミス検出・同ディレクトリ警告は付いていません(基本動作は同じ)。

bash scripts/cc2-start.sh <現場名>   # 例: bash scripts/cc2-start.sh kenzokun

引数なし・フォルダが無い現場名で実行すると、いま起動できる現場名の一覧を表示します。同名の tmux セッションが既にあればそこへ接続し、無ければ作成して CC2 を起動します。

現場名の解決は scripts/sites.sh に集約し、cc2-start.sh / cc2.sh / conductor-start.sh が source して共有します(重複を持たない)。 ★起動できるかは ~/projects/<現場名> がフォルダとして在るかで決まります(名前の一覧では決めません)。


補助スクリプト: 報告役の常駐起動(scripts/conductor-start.sh)

報告役(heartbeat、必要なら relay)を1コマンドで起動する補助です。cc2-start.sh と同じ作法・同じ対応表を使います。

bash scripts/conductor-start.sh <現場名> [--relay]

# 例
bash scripts/conductor-start.sh kenzokun           # heartbeat のみ
bash scripts/conductor-start.sh kenzokun --relay   # heartbeat + relay
  • 第1引数=現場名(sites.sh の対応表から作業ディレクトリを解決)。
  • --relay 指定時のみ relay(CONDUCTOR_RELAY_ENABLED=true)を有効化します。
  • 内部では現場のディレクトリへ cd してから node dist/cli.js start -s <現場> -t working -a "<現場>稼働" を実行します(ブランチ名を現場の git から判定するため)。
  • CONDUCTOR_URL / CONDUCTOR_TOKEN は呼び出し元のシェルに設定済み前提で、スクリプトに鍵は書きません。未設定なら案内を出して終了します。
  • 未知の現場名・引数なしのときは有効な現場名一覧を表示します。

これは 人がログイン後に1回叩く半自動 です。PC起動時の完全自動は次の「自動常駐」を使います。


relay を手動で起動する(テスト・手動運用 / scripts/relay-start.sh)

relay(指示を CC2 に流す役)を 1コマンドで手動起動する補助です。これまで毎回打っていた source ~/.conductor.env → 各種 export → node dist/cli.js start ... を1コマンドにまとめ、source した鍵が子プロセス(node)に渡らない「未設定エラー」事故も set -a で根治しています。

bash scripts/relay-start.sh <現場名> [作業ラベル]

# 例
bash scripts/relay-start.sh relaytest
bash scripts/relay-start.sh relaytest "スタートアップ調査"

# relay 間隔を短くしてテスト(既定 15秒)
CONDUCTOR_RELAY_INTERVAL_SEC=5 bash scripts/relay-start.sh relaytest
  • 鍵(CONDUCTOR_URL / CONDUCTOR_TOKEN)は ~/.conductor.env から自動読込します。スクリプトには鍵を書かず、画面にも値を出しません。鍵ファイルが無ければ案内して終了します。
  • CONDUCTOR_RELAY_ENABLED=true を付けて relay を有効化します。間隔は CONDUCTOR_RELAY_INTERVAL_SEC(既定 15秒)で上書き可。
  • どのディレクトリから実行しても OK(スクリプト位置からリポルートを解決)。dist/cli.js が無ければ npm run build を案内して終了します。
  • 作業ラベル(第2引数)の既定は relay手動起動 です。

PC起動時の自動常駐(第1段 / scripts/autostart.sh)

リストに並べた現場を、それぞれ heartbeat のみ でバックグラウンド常駐させる、人手を介さない起動口です。WSL 上で bash scripts/autostart.sh を叩くと、リストの現場をまとめて常駐させます。

1) 鍵ファイル $HOME/.conductor.env を用意

鍵はスクリプトに書きません。各PCのホームに $HOME/.conductor.env を作り、そこから読み込みます。

cat > "$HOME/.conductor.env" <<'EOF'
CONDUCTOR_URL=https://<your-conductor-host>
CONDUCTOR_TOKEN=(Bitwarden から取得した値を貼る)
EOF
chmod 600 "$HOME/.conductor.env"   # 自分だけ読める権限に

🔑 CONDUCTOR_TOKEN の値は Bitwarden の共有項目から取得してください。 $HOME/.conductor.env は git 管理外(リポジトリには入れません)。このファイルが無い/鍵が空のときは案内を出して終了します。

2) 自動起動する現場リスト

「このPCで自動起動する現場」を1行1現場で並べます(# 始まりと空行は無視)。優先順位:

  1. bash scripts/autostart.sh <リストファイル> の第1引数
  2. $HOME/.conductor.autostart.list(各PC個別・git管理外)
  3. scripts/autostart.list(同梱サンプル)

各PCでは $HOME/.conductor.autostart.list を置く(または同梱の scripts/autostart.list を編集する)運用です。

3) 起動と停止

bash scripts/autostart.sh          # リストの現場を heartbeat のみで常駐起動
bash scripts/autostart-stop.sh     # 自動常駐(node dist/cli.js start)をまとめて停止
  • 各現場のログは $HOME/.conductor-logs/<現場>.log に追記されます。
  • 既に同じ現場の自動常駐が動いていれば二重起動しません。未知の現場名は warn を出してスキップします(全体は止めません)。
  • relay は有効化しません(heartbeat のみ)。relay が要るときは conductor-start.sh --relay を使ってください。

停止スクリプトは dist/cli.js start を含む node を対象にするため、conductor-start.sh や手動起動の報告役も一緒に止まります。

補足

  • Windows タスクスケジューラからの呼び出しは人間が別途設定します(このリポジトリでは設定しません)。
  • 次段では、自動起動する現場の ②管制画面からのトグル化(ファイル編集なしで ON/OFF)を予定しています。

PC起動時の自動常駐(第2段 / systemd ユーザーサービス)

第1段(autostart.sh)を systemd ユーザーサービスに置き換えたものです。各現場を conductor@<現場>.service として登録し、Restart=always で「落ちても自動復活」 します。これが常用、旧 autostart.sh は 手動予備として温存します。

前提

  • WSL で systemd が有効(/etc/wsl.conf の [boot] systemd=true、[user] default=fshim)。systemctl --user が使えること。
  • 鍵ファイル $HOME/.conductor.env(chmod 600 / git管理外)が用意済み。中身は第1段と同じ(CONDUCTOR_URL / CONDUCTOR_TOKEN)。鍵はリポジトリに入れません。
  • conductor リポで npm run build 済み(dist/cli.js が存在)。

導入

bash scripts/systemd-install.sh          # リストの現場を登録+起動(enable --now)
  • ユニット systemd/[email protected] を ~/.config/systemd/user/ にコピーし、daemon-reload。
  • リストファイル(第1段と同じ優先順: 第1引数 → $HOME/.conductor.autostart.list → scripts/autostart.list)の各現場を systemctl --user enable --now conductor@<現場>。
  • loginctl enable-linger $USER を実行(ログオフ中・PC起動直後でもユーザーサービスが動くように)。通常 sudo は不要です。
  • $HOME/.conductor.env が無ければ警告して中断します。
  • relay は有効化しません(heartbeat のみ)。

WorkingDirectory: 報告役はカレントの git からブランチを判定するため、現場ディレクトリで起動します。既定は %h/projects/<現場>(現状は「現場名 = ディレクトリ名」で一致)。将来この2つが食い違う現場が出た場合は、install スクリプトが sites.sh の対応表を見て drop-in(conductor@<現場>.service.d/override.conf)で WorkingDirectory を上書きします。テンプレート本体は触りません。

状態確認

systemctl --user status 'conductor@*'              # 全現場のサービス状態
systemctl --user list-units 'conductor@*'          # 一覧
journalctl --user -u 'conductor@kenzokun' -f       # 特定現場のログを追尾

停止 / 無効化

bash scripts/systemd-uninstall.sh        # 各現場を disable --now +ユニット削除+daemon-reload
  • linger は外しません(他用途の可能性があるため報告のみ)。完全に戻すときは手動で loginctl disable-linger "$USER"。

補足

  • 落ちても Restart=always(RestartSec=5)で自動復活します。第1段の nohup & と違い、クラッシュ・OOM 後も systemd が起こし直します。
  • 旧 scripts/autostart.sh は 手動予備として温存(常用は systemd)。
  • Windows タスクスケジューラは「WSL を起こす」役割に変更します(常駐の起動は systemd が担当)。例: ログオン時に wsl.exe -d Ubuntu -u fshim true 等で WSL を立ち上げるだけ。この変更は人間が別途設定します。
  • 次段では、自動起動する現場の ②管制画面からのトグル化(ファイル編集なしで ON/OFF)を予定しています。

開発

npm install
npm run build      # tsc で dist/ を生成
npm start          # = node dist/cli.js start