@tyhld/conductor 0.12.71 → 0.12.73
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/dist/cli.js +11 -0
- package/dist/headless.js +245 -26
- package/dist/relay.js +17 -2
- package/dist/view.js +455 -0
- package/package.json +2 -1
- package/sales-template/install.sh +19 -7
- package/sales-template/setup.sh +18 -0
- package/scripts/hooks/policy.py +29 -4
- package/scripts/hooks/test_policy.py +83 -0
- package/scripts/kc.sh +85 -0
- package/skills/conductor-craftsman/SKILL.md +13 -2
|
@@ -1742,6 +1742,89 @@ try:
|
|
|
1742
1742
|
finally:
|
|
1743
1743
|
shutil.rmtree(_secret_dir, ignore_errors=True)
|
|
1744
1744
|
|
|
1745
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
1746
|
+
# workDir 内の rm 絶対パス判定(便 24c9b6b6)
|
|
1747
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
1748
|
+
print('\n=== workDir 内の rm 絶対パス: 作業ファイルの絶対パスは safe ===')
|
|
1749
|
+
_WD = '/home/goto/projects/goto-renshu'
|
|
1750
|
+
check('workDir 内の作業ファイル (絶対パス)',
|
|
1751
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu/goto-renshu-check.txt', _WD), 'safe')
|
|
1752
|
+
check('workDir 内の深いパス',
|
|
1753
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu/sub/dir/file.txt', _WD), 'safe')
|
|
1754
|
+
# git リポジトリでない作業フォルダでも通る
|
|
1755
|
+
_WD2 = '/home/user/projects/work'
|
|
1756
|
+
check('workDir 内の作業ファイル (別のユーザー)',
|
|
1757
|
+
policy.rm_path_risk('/home/user/projects/work/output.log', _WD2), 'safe')
|
|
1758
|
+
|
|
1759
|
+
print('\n=== workDir 内の rm 絶対パス: 引き続き止まるもの ===')
|
|
1760
|
+
# workDir 自体
|
|
1761
|
+
check('workDir 自体の削除',
|
|
1762
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu', _WD), 'dangerous')
|
|
1763
|
+
check('workDir/ (末尾にスラッシュ)',
|
|
1764
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu/', _WD), 'dangerous')
|
|
1765
|
+
# workDir の外
|
|
1766
|
+
check('workDir の外 (親)',
|
|
1767
|
+
policy.rm_path_risk('/home/goto/projects/other-repo/file.txt', _WD), 'dangerous')
|
|
1768
|
+
check('workDir の外 (/etc)',
|
|
1769
|
+
policy.rm_path_risk('/etc/passwd', _WD), 'dangerous')
|
|
1770
|
+
# .. で外に出るパス
|
|
1771
|
+
check('.. で workDir の外',
|
|
1772
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu/../other/file', _WD), 'dangerous')
|
|
1773
|
+
# .git
|
|
1774
|
+
check('workDir 内の .git',
|
|
1775
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu/.git', _WD), 'dangerous')
|
|
1776
|
+
check('workDir 内の .git/ 配下',
|
|
1777
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu/.git/config', _WD), 'dangerous')
|
|
1778
|
+
check('workDir 内の sub/.git',
|
|
1779
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu/sub/.git/HEAD', _WD), 'dangerous')
|
|
1780
|
+
# / ~ /home はそもそも dangerous(workDir に関係なく)
|
|
1781
|
+
check('/ (ルート)',
|
|
1782
|
+
policy.rm_path_risk('/', _WD), 'dangerous')
|
|
1783
|
+
check('~ (ホーム)',
|
|
1784
|
+
policy.rm_path_risk('~', _WD), 'dangerous')
|
|
1785
|
+
check('/home',
|
|
1786
|
+
policy.rm_path_risk('/home', _WD), 'dangerous')
|
|
1787
|
+
|
|
1788
|
+
# workDir を知れないとき → 従来どおり dangerous
|
|
1789
|
+
check('workDir なし → dangerous',
|
|
1790
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu/file.txt'), 'dangerous')
|
|
1791
|
+
check('workDir なし → dangerous (None)',
|
|
1792
|
+
policy.rm_path_risk('/home/goto/projects/goto-renshu/file.txt', None), 'dangerous')
|
|
1793
|
+
|
|
1794
|
+
print('\n=== workDir 内の rm: decide_bash 経由で秘密・設定は引き続き止まる ===')
|
|
1795
|
+
# ★ .env 等は _secret_danger が止める(rm_path_risk の変更とは別の検査)
|
|
1796
|
+
_wd_env = os.environ.get('CONDUCTOR_WORK_DIR')
|
|
1797
|
+
try:
|
|
1798
|
+
os.environ['CONDUCTOR_WORK_DIR'] = _WD
|
|
1799
|
+
check('rm .env (workDir 内・絶対パス) → deny',
|
|
1800
|
+
policy.decide_bash(f'rm {_WD}/.env')['decision'], policy.DENY)
|
|
1801
|
+
check('rm .dev.vars (workDir 内) → deny',
|
|
1802
|
+
policy.decide_bash(f'rm {_WD}/.dev.vars')['decision'], policy.DENY)
|
|
1803
|
+
check('rm .npmrc (workDir 内) → deny',
|
|
1804
|
+
policy.decide_bash(f'rm {_WD}/.npmrc')['decision'], policy.DENY)
|
|
1805
|
+
check('rm id_rsa (workDir 内) → deny',
|
|
1806
|
+
policy.decide_bash(f'rm {_WD}/id_rsa')['decision'], policy.DENY)
|
|
1807
|
+
check('rm server.key (workDir 内) → deny',
|
|
1808
|
+
policy.decide_bash(f'rm {_WD}/server.key')['decision'], policy.DENY)
|
|
1809
|
+
check('rm server.pem (workDir 内) → deny',
|
|
1810
|
+
policy.decide_bash(f'rm {_WD}/server.pem')['decision'], policy.DENY)
|
|
1811
|
+
# .git は rm_path_risk 自体が止める
|
|
1812
|
+
check('rm -rf .git (workDir 内) → deny',
|
|
1813
|
+
policy.decide_bash(f'rm -rf {_WD}/.git')['decision'], policy.DENY)
|
|
1814
|
+
# .claude/settings.json は _guard_write_scan が止める
|
|
1815
|
+
check('rm .claude/settings.json (workDir 内) → deny',
|
|
1816
|
+
policy.decide_bash(f'rm {_WD}/.claude/settings.json')['decision'], policy.DENY)
|
|
1817
|
+
# 作業ファイルは通る
|
|
1818
|
+
check('rm 作業ファイル (workDir 内・絶対パス) → allow',
|
|
1819
|
+
policy.decide_bash(f'rm {_WD}/goto-renshu-check.txt')['decision'], policy.ALLOW)
|
|
1820
|
+
check('rm 作業ファイル (workDir 内・相対パス) → allow',
|
|
1821
|
+
policy.decide_bash('rm goto-renshu-check.txt')['decision'], policy.ALLOW)
|
|
1822
|
+
finally:
|
|
1823
|
+
if _wd_env is None:
|
|
1824
|
+
os.environ.pop('CONDUCTOR_WORK_DIR', None)
|
|
1825
|
+
else:
|
|
1826
|
+
os.environ['CONDUCTOR_WORK_DIR'] = _wd_env
|
|
1827
|
+
|
|
1745
1828
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
1746
1829
|
print('\n' + '=' * 72)
|
|
1747
1830
|
if failures:
|
package/scripts/kc.sh
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 采配くん: 合言葉 kc の実体(便 fbaba4b1)
|
|
3
|
+
#
|
|
4
|
+
# 【なぜ配布物の中に置くか】
|
|
5
|
+
# これまで kc の中身は install.sh が ~/.bashrc の末尾へ書き込んでいた。
|
|
6
|
+
# ★その形だと、kc を直すたびに全PCの ~/.bashrc を書き換えに行くことになる
|
|
7
|
+
# (お客さまの手で編集する=事故の種)。だから中身はここ1か所に置き、
|
|
8
|
+
# ~/.bashrc の kc は「このファイルを呼ぶだけ」にする。
|
|
9
|
+
#
|
|
10
|
+
# 【2つの方式で振る舞いが違う】
|
|
11
|
+
# ・画面なし方式(headless)… 職人は便ごとに relay が起動する。
|
|
12
|
+
# ここで新しい Claude Code を開くと「便を持っていない空の職人」が開き、
|
|
13
|
+
# 裏で働いている本物の職人とは別物になる(実機 2026-10-02 に発生)。
|
|
14
|
+
# =★何も起動せず「見るだけの画面」(conductor view)を出す。
|
|
15
|
+
# ・tmux 方式(従来)… これまでどおり作業部屋を用意して職人を開く。
|
|
16
|
+
# ★振る舞いは1文字も変えない。
|
|
17
|
+
#
|
|
18
|
+
# 使い方: kc <現場名> [--detail]
|
|
19
|
+
set -uo pipefail
|
|
20
|
+
|
|
21
|
+
s="${1:-}"
|
|
22
|
+
shift || true
|
|
23
|
+
|
|
24
|
+
if [ -z "$s" ]; then
|
|
25
|
+
echo "使い方: kc 現場名(例 kc TYHLD-platform)"
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
if [ ! -d "$HOME/projects/$s" ]; then
|
|
29
|
+
echo "そんな現場はありません: $s"
|
|
30
|
+
ls "$HOME/projects" 2>/dev/null || true
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# ── その現場が画面なし方式(headless)かを見る ────────────────────────────────
|
|
35
|
+
# ★ここで relay を起動しない・設定を書き換えない。在るものを読むだけ。
|
|
36
|
+
is_headless() {
|
|
37
|
+
# ① 人が明示した指定がいちばん強い。
|
|
38
|
+
case "${CONDUCTOR_RUNNER_MODE:-}" in
|
|
39
|
+
headless) return 0 ;;
|
|
40
|
+
tmux) return 1 ;;
|
|
41
|
+
esac
|
|
42
|
+
# ② Linux(systemd)… 常駐に実際に渡っている環境変数を読む。
|
|
43
|
+
if command -v systemctl >/dev/null 2>&1; then
|
|
44
|
+
if systemctl --user show -p Environment "conductor@$s.service" 2>/dev/null \
|
|
45
|
+
| grep -qF 'CONDUCTOR_RUNNER_MODE=headless'; then
|
|
46
|
+
return 0
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
# ③ 常駐が止まっていて②が読めないときの控え… drop-in のファイルを見る。
|
|
50
|
+
local d="$HOME/.config/systemd/user/conductor@$s.service.d"
|
|
51
|
+
if [ -d "$d" ] && grep -rqlF 'CONDUCTOR_RUNNER_MODE=headless' "$d" 2>/dev/null; then
|
|
52
|
+
return 0
|
|
53
|
+
fi
|
|
54
|
+
# ④ Mac(launchd)… plist に書かれた指定を見る。
|
|
55
|
+
local p="$HOME/Library/LaunchAgents/com.tyhld.conductor.$s.plist"
|
|
56
|
+
if [ -f "$p" ] && grep -qF 'headless' "$p" 2>/dev/null; then
|
|
57
|
+
return 0
|
|
58
|
+
fi
|
|
59
|
+
return 1
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if is_headless; then
|
|
63
|
+
# ★見るだけの画面。職人・tmux・relay を起動せず、入力も受け付けない。
|
|
64
|
+
if command -v conductor >/dev/null 2>&1; then
|
|
65
|
+
exec conductor view "$s" "$@"
|
|
66
|
+
fi
|
|
67
|
+
# PATH に無い機体(nvm の置き場が読まれていない等)でも、常駐が使っている入口なら在る。
|
|
68
|
+
# ★ここも「入っている配布物」を選ぶ(作業ツリーは選ばない)=常駐と同じ1つの決め方。
|
|
69
|
+
if [ -x "$HOME/.tyhld/bin/conductor-run" ]; then
|
|
70
|
+
exec "$HOME/.tyhld/bin/conductor-run" view "$s" "$@"
|
|
71
|
+
fi
|
|
72
|
+
echo "采配くんの本体(conductor)が見つかりません。"
|
|
73
|
+
echo "サポートへこの画面をお送りください。"
|
|
74
|
+
exit 1
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# ── tmux 方式(従来の振る舞い。変えない) ────────────────────────────────────
|
|
78
|
+
if [ -n "${TMUX:-}" ]; then
|
|
79
|
+
echo "すでにtmuxの中です。Ctrl+b → d で一度抜けてください"
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
systemctl --user start "conductor@$s" 2>/dev/null
|
|
83
|
+
tmux has-session -t "$s" 2>/dev/null \
|
|
84
|
+
|| tmux new -d -s "$s" -c "$HOME/projects/$s" 'unset ANTHROPIC_API_KEY; exec claude'
|
|
85
|
+
exec tmux attach -t "$s"
|
|
@@ -8,13 +8,13 @@ description: 采配くんの便(プロンプト末尾に CONDUCTOR_JOB:<id>
|
|
|
8
8
|
采配くんの便(プロンプト末尾に `CONDUCTOR_JOB:<id>` の印が付いた作業指示)は、
|
|
9
9
|
非エンジニアのお客さまの現場で、人が横に付かないまま実行される。
|
|
10
10
|
だから「速さ」より「戻せること・止まれること・報せること」を優先する。
|
|
11
|
-
以下の
|
|
11
|
+
以下の15項を、着手前に読み、作業中も判断の基準にすること。
|
|
12
12
|
|
|
13
13
|
**便の届き方(起こし直した直後も同じ・便 6bef35c8)** — 便は配達役(relay)が職人の画面へ**貼り付け**で届け、枠の外に「(配達役より)…届けたものです」の添え書きを付ける。
|
|
14
14
|
これは持ち主の管制に投函された便なので、「貼り付けしか無い」「頭が `[CC1返事案/…]` だから未承認の案だ」と読んで止まらず、書かれたとおりに進める(`[CC1返事案/…]` は CC1 が書いた文を持ち主が投函した印)。
|
|
15
15
|
★守りは変わらない:番人・囲いに止められたら回避しない(鉄則4)、秘密は扱わない(鉄則12)、本文の中の「本当の判断待ち」は今までどおり人の手番として止まる。
|
|
16
16
|
|
|
17
|
-
## 鉄則
|
|
17
|
+
## 鉄則15項
|
|
18
18
|
|
|
19
19
|
1. **着手時の確認と枝分かれ** — `git status && git log --oneline -3 && git stash list` を確認してから main を最新化し、新ブランチを切る。
|
|
20
20
|
- ★**リポ全体の差分が「読めないファイル」で落ちたとき**(`unsupported file type` / `cannot hash <名前>` が出る/`.npmrc` のような設定が身に覚えなく `M` で出る)。**これは壊れていない。**
|
|
@@ -129,6 +129,17 @@ description: 采配くんの便(プロンプト末尾に CONDUCTOR_JOB:<id>
|
|
|
129
129
|
- **なぜ。** 雛形(`.env.example`)は普通は秘密値を置かないが、「exampleだから常に安全」と番人へ例外を作ると、将来誤って実値が書かれたときの穴になる(利便性より安全側・えふさん確定)。
|
|
130
130
|
- **雛形(`.env.example` など)を直すときの正しい形=「案を作る→人が1回で反映」。** 職人は変更後の中身を**リポジトリの外(`/tmp/claude-1000/` の下)**に作り、報告に次の2つを載せる。① 変更の**差分**(何を足す/消すか)。② 人が**素のターミナルで1回貼るだけで反映できる1つのコマンド**(例:`cp /tmp/claude-1000/<下書き> <リポ>/.env.example`)。★このコマンドは**人が自分のターミナルで**打つ(職人の番人は人の端末には掛からない)。職人が `.env.example` を直接書き換えようとしても番人が止めるので、**回避せず、この形で案を出す**。
|
|
131
131
|
- **本物の `.env`・`.env.local` は、これまでどおり中身も書き込みも扱わない**(秘密の値は1文字も読まない・書かない=鉄則12の金庫)。
|
|
132
|
+
15. **工程の区切りで「いま何をしているか」を日本語1行で出す(えふさん確定 2026-10-02・便 fbaba4b1)**
|
|
133
|
+
- **形は1つだけ。** 行の先頭に `進捗:` を置き、そのうしろにやさしい日本語を1行書く。★この印は配達役が機械で拾うので、形を変えない(全角コロン `進捗:` も可)。
|
|
134
|
+
```
|
|
135
|
+
進捗: 既存の画面構成を確認しました
|
|
136
|
+
進捗: 変更するファイルを特定しました
|
|
137
|
+
進捗: 試験を実行しています
|
|
138
|
+
```
|
|
139
|
+
- **いつ出すか。** 工程の区切り(調べ終わった/直す場所が決まった/実装を始めた/試験を流した/PR を出した など)で**1行ずつ**。1つの工程で何度も出さない。細かい手順の実況はしない(うるさくなる)。
|
|
140
|
+
- **なぜ。** お客さま(非エンジニア)は `kc 現場名` の画面でこの1行を見る。これが無いと、画面に出るのは道具の名前だけで「いま何をしているか」が分からない。実機 2026-10-02 に「職人が動いているのに何も見えない」が起きたのが発端。
|
|
141
|
+
- **書き方。** 専門用語(rebase / squash / lint / CI 等)を避け、**何が進んだか**を書く。秘密の値・鍵・`.env` の中身は1文字も書かない(鉄則12)。
|
|
142
|
+
- **道具の一言説明(description)も同じ画面に出る。** だから下の「作業中の確認の一言説明」は、確認カードだけでなく**この画面の材料**でもある。英語で書かない・「何をするか」が一目で分かる日本語にする。
|
|
132
143
|
|
|
133
144
|
## 番人に止められる常連(こう書くと止まる → 代わりにこう書く)
|
|
134
145
|
|