lathe-cli 1.0.0
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/README.md +118 -0
- package/bin/_lathe-lib.sh +38 -0
- package/bin/check-deps.sh +42 -0
- package/bin/lathe +51 -0
- package/bin/lathe-init +101 -0
- package/bin/lathe-meta +14 -0
- package/bin/lathe-process +88 -0
- package/bin/lathe-sync +20 -0
- package/bin/lathe-target +14 -0
- package/package.json +35 -0
- package/template/develop/bin/sync.sh +50 -0
- package/template/develop/harness/CLAUDE.md +134 -0
- package/template/develop/harness/agents/coder.md +145 -0
- package/template/develop/harness/agents/reviewer.md +155 -0
- package/template/develop/harness/hooks/commit-runs.sh +47 -0
- package/template/develop/harness/hooks/copy_transcript.sh +93 -0
- package/template/develop/harness/hooks/log.sh +53 -0
- package/template/develop/harness/plan_template.html +146 -0
- package/template/develop/harness/settings.json +47 -0
- package/template/develop/harness/skills/planning/SKILL.md +83 -0
- package/template/develop/harness/workflow/default.yaml +205 -0
- package/template/git-hooks/post-merge +21 -0
- package/template/main/README.md +25 -0
- package/template/meta-overlay/improvements/.gitkeep +0 -0
- package/template/meta-overlay/meta/.claude/settings.json +5 -0
- package/template/meta-overlay/meta/.claude/skills/improvement-recording/SKILL.md +92 -0
- package/template/meta-overlay/meta/.claude/skills/log-reading/SKILL.md +134 -0
- package/template/meta-overlay/meta/CLAUDE.md +133 -0
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Lathe
|
|
2
|
+
|
|
3
|
+
Claude Code を agent backend にした target/meta 二層 harness を、git branch + worktree で物理分離する CLI。
|
|
4
|
+
|
|
5
|
+
## 想定するロール分離
|
|
6
|
+
|
|
7
|
+
| role | やること | 接点 |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| 開発者 | feature branch で vibe coding、PR を develop に出す | git / gh |
|
|
10
|
+
| target agent | PR を polish 実装に置き換える、commit して PR を更新 | plan HTML 出力、approval で停止 |
|
|
11
|
+
| overseer | plan HTML レビュー、PR レビュー、merge | claude UI + GitHub PR |
|
|
12
|
+
| meta operator | runs/ を読み harness/ を改善、PR を develop に出す | meta agent と対話 |
|
|
13
|
+
|
|
14
|
+
## install
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install -g lathe-cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
依存:`git` 2.10+、`jq`、`claude` (Claude Code CLI)、`gh` (GitHub CLI、`lathe process` で必要)。`postinstall` で警告のみ出します(fail させません)。
|
|
21
|
+
|
|
22
|
+
## init
|
|
23
|
+
|
|
24
|
+
空のディレクトリで:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
mkdir myapp && cd myapp
|
|
28
|
+
lathe init
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
これで以下ができます:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
myapp/
|
|
35
|
+
├── .git/ 共有 bare repo
|
|
36
|
+
├── main/ main worktree(あなたの app code)
|
|
37
|
+
├── develop/ develop worktree(target が住む、target/.claude/ が sync で生成)
|
|
38
|
+
└── meta/ meta worktree(harness/ + meta agent + improvements/)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
3 つの worktree は同じ bare repo を共有しているので、git で内容を相互伝搬できます。
|
|
42
|
+
|
|
43
|
+
## 日常コマンド
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
lathe target [args...] # cd develop/target && claude args
|
|
47
|
+
lathe meta [args...] # cd meta/meta && claude args
|
|
48
|
+
lathe sync # develop/bin/sync.sh 手動実行
|
|
49
|
+
lathe process <pr#> # PR pickup → tasks/<pr#>/ worktree 作成 → target 起動
|
|
50
|
+
lathe help # ヘルプ
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
どの worktree や project root で実行しても、git の共通 dir から自動で正しい場所に移動します。
|
|
54
|
+
|
|
55
|
+
## 標準ワークフロー
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
cd myapp/main
|
|
59
|
+
|
|
60
|
+
# feature 切る(base は main / develop どちらでも好み)
|
|
61
|
+
git checkout -b feature/X main
|
|
62
|
+
# vibe coding(claude などで自由に)
|
|
63
|
+
git add . && git commit
|
|
64
|
+
git push -u origin feature/X
|
|
65
|
+
gh pr create --base develop --title "..." --body "..."
|
|
66
|
+
|
|
67
|
+
# overseer
|
|
68
|
+
lathe process <pr#>
|
|
69
|
+
# claude UI で「Read .lathe-task.md from the added directory and process it」を貼り付け
|
|
70
|
+
# orchestrator が plan → 承認 → coder/reviewer dispatch → commit/push → PR 更新
|
|
71
|
+
gh pr merge <pr#> # develop に merge
|
|
72
|
+
|
|
73
|
+
# meta operator(任意のタイミング)
|
|
74
|
+
cd myapp/meta
|
|
75
|
+
git fetch && git merge --no-edit develop # 最新 runs/ を取り込み
|
|
76
|
+
lathe meta
|
|
77
|
+
# meta agent が runs/ 読む → harness/ 編集 → improvements/<id>/ 記録 → commit
|
|
78
|
+
git push -u origin meta
|
|
79
|
+
gh pr create --base develop --head meta --title "harness: ..."
|
|
80
|
+
gh pr merge <meta pr#>
|
|
81
|
+
# develop に meta が merge されると post-merge hook が sync.sh 自動実行
|
|
82
|
+
# 次回 target session は更新後の harness で動く
|
|
83
|
+
|
|
84
|
+
# release
|
|
85
|
+
cd myapp/develop
|
|
86
|
+
git checkout main
|
|
87
|
+
git merge develop
|
|
88
|
+
git push origin main
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 設計の要点
|
|
92
|
+
|
|
93
|
+
- **branch / worktree でロール分離**:各 agent / role が物理的に別ディレクトリで動くので、CLAUDE.md / settings.json / hooks が混ざらない
|
|
94
|
+
- **harness は meta が編集し、sync で target/.claude/ に展開**:Claude Code 本体の `.claude/` sensitive-file guard を agent tool で突破できないため、meta は harness/ を編集(普通の dir、guard なし)→ develop で sync.sh が外部 shell から target/.claude/ を上書き、という回路で迂回
|
|
95
|
+
- **runs/ は develop で auto-commit**:target session の Stop hook が `git commit` するので、meta は `git merge develop` で読める。symlink や中央 store 不要
|
|
96
|
+
- **post-merge hook が auto-sync**:meta の harness 改善が develop に merge された瞬間に target/.claude/ が再生成される
|
|
97
|
+
|
|
98
|
+
## 動作確認済み(v1)
|
|
99
|
+
|
|
100
|
+
- npm パッケージ無しでも `git clone` install で動作
|
|
101
|
+
- `lathe init` で bare repo + 3 worktree + post-merge hook 設置
|
|
102
|
+
- target session 実行、runs auto-commit on develop
|
|
103
|
+
- meta worktree が `git merge develop` で runs/ 読込
|
|
104
|
+
- meta が harness/CLAUDE.md 編集 → develop merge → post-merge hook → sync 自動 → target/CLAUDE.md 反映
|
|
105
|
+
- `lathe target` / `lathe meta` / `lathe sync` がどの worktree から実行しても正しい worktree を見つける
|
|
106
|
+
|
|
107
|
+
## 既知の v1 制限
|
|
108
|
+
|
|
109
|
+
- meta → develop merge で meta/ + improvements/ overlay も develop に持ち込まれる(cherry-pick / 別 PR 機構で v2 解決)
|
|
110
|
+
- `lathe process` の prompt 渡しは手動ペースト(claude TUI が piped 初期 prompt を確実に取らないため)
|
|
111
|
+
- post-merge hook は local merge のみ発火、GitHub UI で merge した時は `git pull` 後に `lathe sync` 手動
|
|
112
|
+
- v1 は新 project 専用、既存 repo の自動 migration なし
|
|
113
|
+
- runs/ auto-commit は local commit のみ(remote push しない)。multi-machine 構成では別途 push 設計が必要
|
|
114
|
+
|
|
115
|
+
## 設計詳細
|
|
116
|
+
|
|
117
|
+
target orchestrator の指示書: `template/develop/harness/CLAUDE.md`
|
|
118
|
+
meta agent の指示書: `template/meta-overlay/meta/CLAUDE.md`
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Shared helpers for lathe subcommands. Sourced, not executed.
|
|
3
|
+
|
|
4
|
+
# Find the Lathe project root (the dir containing the bare repo .git).
|
|
5
|
+
# Works from inside any worktree (main/develop/meta/task-*) and from the
|
|
6
|
+
# project root itself.
|
|
7
|
+
lathe_project_root() {
|
|
8
|
+
local common_dir
|
|
9
|
+
if ! common_dir="$(git rev-parse --git-common-dir 2>/dev/null)"; then
|
|
10
|
+
return 1
|
|
11
|
+
fi
|
|
12
|
+
# Common dir is typically <project_root>/.git. Could be relative.
|
|
13
|
+
if [ "$common_dir" = "." ] || [ "$common_dir" = ".git" ]; then
|
|
14
|
+
common_dir="$(pwd)/.git"
|
|
15
|
+
elif [ "${common_dir#/}" = "$common_dir" ]; then
|
|
16
|
+
# relative path
|
|
17
|
+
common_dir="$(pwd)/$common_dir"
|
|
18
|
+
fi
|
|
19
|
+
(cd "$(dirname "$common_dir")" && pwd)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Find a worktree path by branch name.
|
|
23
|
+
# Usage: lathe_wt_for_branch <branch>
|
|
24
|
+
# Echoes the worktree path on stdout, or empty string if not found.
|
|
25
|
+
lathe_wt_for_branch() {
|
|
26
|
+
local target_branch="$1"
|
|
27
|
+
local root path branch line
|
|
28
|
+
root="$(lathe_project_root)" || return 1
|
|
29
|
+
while IFS= read -r line; do
|
|
30
|
+
path="$(echo "$line" | awk '{print $1}')"
|
|
31
|
+
branch="$(echo "$line" | awk '{print $3}' | tr -d '[]')"
|
|
32
|
+
if [ "$branch" = "$target_branch" ]; then
|
|
33
|
+
echo "$path"
|
|
34
|
+
return 0
|
|
35
|
+
fi
|
|
36
|
+
done < <(git --git-dir="$root/.git" worktree list)
|
|
37
|
+
return 1
|
|
38
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Lathe runtime dependency check. Runs as npm postinstall.
|
|
3
|
+
# Non-fatal: prints warnings but always exits 0 so install completes.
|
|
4
|
+
|
|
5
|
+
missing_required=()
|
|
6
|
+
missing_optional=()
|
|
7
|
+
|
|
8
|
+
for cmd in git jq claude bash; do
|
|
9
|
+
command -v "$cmd" >/dev/null 2>&1 || missing_required+=("$cmd")
|
|
10
|
+
done
|
|
11
|
+
|
|
12
|
+
command -v gh >/dev/null 2>&1 || missing_optional+=("gh (only needed for 'lathe process')")
|
|
13
|
+
|
|
14
|
+
if [ "${#missing_required[@]}" -gt 0 ]; then
|
|
15
|
+
echo ""
|
|
16
|
+
echo "[lathe] required dependencies missing:"
|
|
17
|
+
for c in "${missing_required[@]}"; do echo " - $c"; done
|
|
18
|
+
echo "[lathe] install them before running 'lathe init'."
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
if [ "${#missing_optional[@]}" -gt 0 ]; then
|
|
22
|
+
echo ""
|
|
23
|
+
echo "[lathe] optional dependencies missing:"
|
|
24
|
+
for c in "${missing_optional[@]}"; do echo " - $c"; done
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Git worktree feature requires 2.10+; warn if older.
|
|
28
|
+
if command -v git >/dev/null 2>&1; then
|
|
29
|
+
GIT_VER="$(git --version | awk '{print $3}')"
|
|
30
|
+
GIT_MAJOR="${GIT_VER%%.*}"
|
|
31
|
+
GIT_REST="${GIT_VER#*.}"
|
|
32
|
+
GIT_MINOR="${GIT_REST%%.*}"
|
|
33
|
+
if [ "$GIT_MAJOR" -lt 2 ] 2>/dev/null \
|
|
34
|
+
|| { [ "$GIT_MAJOR" = "2" ] && [ "$GIT_MINOR" -lt 10 ] 2>/dev/null; }; then
|
|
35
|
+
echo ""
|
|
36
|
+
echo "[lathe] git $GIT_VER detected. Lathe needs git 2.10+ for worktree hooks. Please upgrade."
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
echo ""
|
|
41
|
+
echo "[lathe] installed. Run 'lathe init' in an empty directory to start."
|
|
42
|
+
exit 0
|
package/bin/lathe
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lathe — agent harness CLI dispatcher.
|
|
3
|
+
# Resolves LATHE_HOME from script location, then dispatches to lathe-<cmd>.
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# Resolve LATHE_HOME = the Lathe install root (parent of bin/).
|
|
8
|
+
SCRIPT_PATH="$(cd "$(dirname "$0")" && pwd)/$(basename "$0")"
|
|
9
|
+
# Follow symlink if `lathe` was symlinked into PATH.
|
|
10
|
+
if [ -L "$SCRIPT_PATH" ]; then
|
|
11
|
+
SCRIPT_PATH="$(readlink "$SCRIPT_PATH")"
|
|
12
|
+
case "$SCRIPT_PATH" in
|
|
13
|
+
/*) ;; # absolute, fine
|
|
14
|
+
*) SCRIPT_PATH="$(cd "$(dirname "$0")" && cd "$(dirname "$SCRIPT_PATH")" && pwd)/$(basename "$SCRIPT_PATH")" ;;
|
|
15
|
+
esac
|
|
16
|
+
fi
|
|
17
|
+
LATHE_HOME="$(cd "$(dirname "$SCRIPT_PATH")/.." && pwd)"
|
|
18
|
+
export LATHE_HOME
|
|
19
|
+
|
|
20
|
+
CMD="${1:-help}"
|
|
21
|
+
shift || true
|
|
22
|
+
|
|
23
|
+
case "$CMD" in
|
|
24
|
+
help|-h|--help|"")
|
|
25
|
+
cat <<EOF
|
|
26
|
+
lathe — agent harness CLI
|
|
27
|
+
|
|
28
|
+
Commands:
|
|
29
|
+
init Initialize Lathe in current git repo
|
|
30
|
+
(creates develop + meta branches, two worktrees)
|
|
31
|
+
process <pr#> Pick up a PR for target processing
|
|
32
|
+
(creates task worktree, launches target with PR context)
|
|
33
|
+
sync Re-sync harness/ -> target/.claude/ in develop worktree
|
|
34
|
+
target Launch target agent (cd develop worktree, claude)
|
|
35
|
+
meta Launch meta agent (cd meta worktree, claude)
|
|
36
|
+
status Show worktrees, recent runs, recent improvements
|
|
37
|
+
help This message
|
|
38
|
+
|
|
39
|
+
LATHE_HOME=$LATHE_HOME
|
|
40
|
+
EOF
|
|
41
|
+
exit 0
|
|
42
|
+
;;
|
|
43
|
+
esac
|
|
44
|
+
|
|
45
|
+
SUB="$LATHE_HOME/bin/lathe-$CMD"
|
|
46
|
+
if [ ! -x "$SUB" ]; then
|
|
47
|
+
echo "lathe: unknown or unimplemented command: $CMD" >&2
|
|
48
|
+
echo "Try: lathe help" >&2
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
exec "$SUB" "$@"
|
package/bin/lathe-init
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lathe init — initialize a Lathe project in the current directory.
|
|
3
|
+
#
|
|
4
|
+
# Layout produced (nested under cwd):
|
|
5
|
+
# ./
|
|
6
|
+
# ├── .git/ (bare repo, shared by all worktrees)
|
|
7
|
+
# ├── main/ (worktree on 'main' branch — your app code)
|
|
8
|
+
# ├── develop/ (worktree on 'develop' — target harness)
|
|
9
|
+
# └── meta/ (worktree on 'meta' — meta agent + improvements/)
|
|
10
|
+
#
|
|
11
|
+
# Requirements: cwd should be empty. Existing repos are not auto-migrated.
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
: "${LATHE_HOME:?must be set by lathe dispatcher}"
|
|
16
|
+
|
|
17
|
+
PROJECT_ROOT="$(pwd)"
|
|
18
|
+
PROJECT_NAME="$(basename "$PROJECT_ROOT")"
|
|
19
|
+
|
|
20
|
+
# --- Validation ---
|
|
21
|
+
if [ -e "$PROJECT_ROOT/.git" ]; then
|
|
22
|
+
echo "lathe init: $PROJECT_ROOT/.git already exists. Aborting." >&2
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
for d in main develop meta; do
|
|
26
|
+
if [ -e "$PROJECT_ROOT/$d" ]; then
|
|
27
|
+
echo "lathe init: $PROJECT_ROOT/$d already exists. Aborting." >&2
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
done
|
|
31
|
+
|
|
32
|
+
# Warn (not error) if cwd has any other content.
|
|
33
|
+
EXTRA="$(ls -A "$PROJECT_ROOT" 2>/dev/null | grep -vE '^(\.|\.\.)$' || true)"
|
|
34
|
+
if [ -n "$EXTRA" ]; then
|
|
35
|
+
echo "Note: $PROJECT_ROOT is not empty. Existing files will remain at the project root and won't be in any worktree."
|
|
36
|
+
echo " (Lathe v1 doesn't auto-migrate existing repos. Move files into main/ manually if needed.)"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
GIT_DIR="$PROJECT_ROOT/.git"
|
|
40
|
+
|
|
41
|
+
echo "==> [1/5] Initializing bare repo at $GIT_DIR ..."
|
|
42
|
+
git init --bare --quiet "$GIT_DIR"
|
|
43
|
+
|
|
44
|
+
echo "==> [2/5] Creating main worktree with initial commit (template/main)..."
|
|
45
|
+
git --git-dir="$GIT_DIR" worktree add --quiet -b main "$PROJECT_ROOT/main" 2>/dev/null || {
|
|
46
|
+
# Empty bare repo: branch creation needs an existing commit. Make one via plumbing.
|
|
47
|
+
EMPTY_TREE="$(git --git-dir="$GIT_DIR" mktree </dev/null)"
|
|
48
|
+
INIT_COMMIT="$(printf 'lathe: empty initial\n' | git --git-dir="$GIT_DIR" commit-tree "$EMPTY_TREE")"
|
|
49
|
+
git --git-dir="$GIT_DIR" update-ref refs/heads/main "$INIT_COMMIT"
|
|
50
|
+
git --git-dir="$GIT_DIR" symbolic-ref HEAD refs/heads/main
|
|
51
|
+
git --git-dir="$GIT_DIR" worktree add --quiet "$PROJECT_ROOT/main" main
|
|
52
|
+
}
|
|
53
|
+
cp -R "$LATHE_HOME/template/main/." "$PROJECT_ROOT/main/"
|
|
54
|
+
# Replace placeholder in README
|
|
55
|
+
if [ -f "$PROJECT_ROOT/main/README.md" ]; then
|
|
56
|
+
sed -i.bak "s/{{project_name}}/$PROJECT_NAME/g" "$PROJECT_ROOT/main/README.md"
|
|
57
|
+
rm -f "$PROJECT_ROOT/main/README.md.bak"
|
|
58
|
+
fi
|
|
59
|
+
git -C "$PROJECT_ROOT/main" add -A
|
|
60
|
+
git -C "$PROJECT_ROOT/main" \
|
|
61
|
+
-c user.email="lathe@local" -c user.name="lathe" \
|
|
62
|
+
commit --quiet --allow-empty -m "lathe: init main"
|
|
63
|
+
|
|
64
|
+
echo "==> [3/5] Creating develop worktree from main (template/develop)..."
|
|
65
|
+
git --git-dir="$GIT_DIR" worktree add --quiet -b develop "$PROJECT_ROOT/develop" main
|
|
66
|
+
cp -R "$LATHE_HOME/template/develop/." "$PROJECT_ROOT/develop/"
|
|
67
|
+
"$PROJECT_ROOT/develop/bin/sync.sh"
|
|
68
|
+
mkdir -p "$PROJECT_ROOT/develop/runs" "$PROJECT_ROOT/develop/target/plans"
|
|
69
|
+
touch "$PROJECT_ROOT/develop/runs/.gitkeep" "$PROJECT_ROOT/develop/target/plans/.gitkeep"
|
|
70
|
+
git -C "$PROJECT_ROOT/develop" add -A
|
|
71
|
+
git -C "$PROJECT_ROOT/develop" \
|
|
72
|
+
-c user.email="lathe@local" -c user.name="lathe" \
|
|
73
|
+
commit --quiet -m "lathe: target harness on develop"
|
|
74
|
+
|
|
75
|
+
echo "==> [4/5] Creating meta worktree from develop (template/meta-overlay)..."
|
|
76
|
+
git --git-dir="$GIT_DIR" worktree add --quiet -b meta "$PROJECT_ROOT/meta" develop
|
|
77
|
+
cp -R "$LATHE_HOME/template/meta-overlay/." "$PROJECT_ROOT/meta/"
|
|
78
|
+
git -C "$PROJECT_ROOT/meta" add -A
|
|
79
|
+
git -C "$PROJECT_ROOT/meta" \
|
|
80
|
+
-c user.email="lathe@local" -c user.name="lathe" \
|
|
81
|
+
commit --quiet -m "lathe: meta agent on meta"
|
|
82
|
+
|
|
83
|
+
echo "==> [5/5] Installing post-merge hook (auto-sync on develop merges)..."
|
|
84
|
+
mkdir -p "$GIT_DIR/hooks"
|
|
85
|
+
cp "$LATHE_HOME/template/git-hooks/post-merge" "$GIT_DIR/hooks/post-merge"
|
|
86
|
+
chmod +x "$GIT_DIR/hooks/post-merge"
|
|
87
|
+
|
|
88
|
+
cat <<EOF
|
|
89
|
+
|
|
90
|
+
Lathe initialized at $PROJECT_ROOT/
|
|
91
|
+
|
|
92
|
+
main/ your app code (cd here to start working)
|
|
93
|
+
develop/ target harness (target launches from here)
|
|
94
|
+
meta/ meta agent (improvements/ live here)
|
|
95
|
+
.git/ shared bare repo
|
|
96
|
+
|
|
97
|
+
Next:
|
|
98
|
+
cd $PROJECT_ROOT/main
|
|
99
|
+
# vibe code; commit; PR a feature branch to develop
|
|
100
|
+
# then: lathe process <pr#>
|
|
101
|
+
EOF
|
package/bin/lathe-meta
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lathe meta — cd into meta worktree's meta/ and launch claude.
|
|
3
|
+
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
: "${LATHE_HOME:?must be set by lathe dispatcher}"
|
|
6
|
+
source "$LATHE_HOME/bin/_lathe-lib.sh"
|
|
7
|
+
|
|
8
|
+
META_WT="$(lathe_wt_for_branch meta)" || {
|
|
9
|
+
echo "lathe meta: meta worktree not found. Run 'lathe init' first." >&2
|
|
10
|
+
exit 1
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
cd "$META_WT/meta"
|
|
14
|
+
exec claude "$@"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lathe process <pr#> — pick up a PR for target processing.
|
|
3
|
+
# 1. fetch PR head + body via gh
|
|
4
|
+
# 2. add a worktree of the PR's branch under <project>/tasks/<pr#>
|
|
5
|
+
# 3. write the task brief into that worktree as .lathe-task.md
|
|
6
|
+
# 4. cd into develop worktree's target/, launch claude with --add-dir <task-wt>
|
|
7
|
+
#
|
|
8
|
+
# Interactive launch: the user pastes a "read .lathe-task.md and process it"
|
|
9
|
+
# prompt into the resulting claude TUI. (Auto-injection of the initial prompt
|
|
10
|
+
# is unreliable in claude's interactive mode.)
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
: "${LATHE_HOME:?must be set by lathe dispatcher}"
|
|
14
|
+
source "$LATHE_HOME/bin/_lathe-lib.sh"
|
|
15
|
+
|
|
16
|
+
PR="${1:-}"
|
|
17
|
+
if [ -z "$PR" ]; then
|
|
18
|
+
echo "Usage: lathe process <pr#>" >&2
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
command -v gh >/dev/null 2>&1 || {
|
|
23
|
+
echo "lathe process: gh (GitHub CLI) is required" >&2
|
|
24
|
+
exit 1
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
PROJECT_ROOT="$(lathe_project_root)" || {
|
|
28
|
+
echo "lathe process: not inside a Lathe project" >&2
|
|
29
|
+
exit 1
|
|
30
|
+
}
|
|
31
|
+
DEVELOP_WT="$(lathe_wt_for_branch develop)" || {
|
|
32
|
+
echo "lathe process: develop worktree not found" >&2
|
|
33
|
+
exit 1
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
echo "==> Fetching PR #$PR ..."
|
|
37
|
+
HEAD_REF="$(gh pr view "$PR" --json headRefName -q .headRefName)"
|
|
38
|
+
TITLE="$(gh pr view "$PR" --json title -q .title)"
|
|
39
|
+
BODY="$(gh pr view "$PR" --json body -q .body)"
|
|
40
|
+
|
|
41
|
+
git --git-dir="$PROJECT_ROOT/.git" fetch origin "$HEAD_REF" >/dev/null 2>&1 || true
|
|
42
|
+
|
|
43
|
+
mkdir -p "$PROJECT_ROOT/tasks"
|
|
44
|
+
TASK_WT="$PROJECT_ROOT/tasks/$PR"
|
|
45
|
+
if [ -e "$TASK_WT" ]; then
|
|
46
|
+
echo "lathe process: $TASK_WT already exists. Remove it or pick another PR." >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo "==> Creating task worktree at $TASK_WT (branch: $HEAD_REF)..."
|
|
51
|
+
git --git-dir="$PROJECT_ROOT/.git" worktree add --quiet "$TASK_WT" "$HEAD_REF"
|
|
52
|
+
|
|
53
|
+
PROMPT_FILE="$TASK_WT/.lathe-task.md"
|
|
54
|
+
cat > "$PROMPT_FILE" <<EOF
|
|
55
|
+
# PR #$PR: $TITLE
|
|
56
|
+
|
|
57
|
+
You are processing pull request #$PR. The vibe-coded changes are in this worktree.
|
|
58
|
+
|
|
59
|
+
**Task description (PR body):**
|
|
60
|
+
$BODY
|
|
61
|
+
|
|
62
|
+
**Your job:**
|
|
63
|
+
1. Read the existing changes in this worktree (the vibe-coded prototype)
|
|
64
|
+
2. Plan a polished implementation (planning skill, plans/<run_id>.html)
|
|
65
|
+
3. After approval, dispatch coder/reviewer to produce a clean implementation
|
|
66
|
+
4. Coder commits and pushes to branch \`$HEAD_REF\` so the PR updates
|
|
67
|
+
5. Do NOT delete the original vibe commits — your polish goes ON TOP
|
|
68
|
+
|
|
69
|
+
The task worktree is at: $TASK_WT
|
|
70
|
+
EOF
|
|
71
|
+
|
|
72
|
+
cat <<EOF
|
|
73
|
+
|
|
74
|
+
Task worktree ready.
|
|
75
|
+
Path: $TASK_WT
|
|
76
|
+
Branch: $HEAD_REF
|
|
77
|
+
Prompt file: $PROMPT_FILE
|
|
78
|
+
|
|
79
|
+
Launching target. Paste this into the claude TUI:
|
|
80
|
+
|
|
81
|
+
Read .lathe-task.md from the added directory ($TASK_WT) and process it.
|
|
82
|
+
|
|
83
|
+
Press Enter to launch claude (Ctrl-C to abort)...
|
|
84
|
+
EOF
|
|
85
|
+
read -r _
|
|
86
|
+
|
|
87
|
+
cd "$DEVELOP_WT/target"
|
|
88
|
+
exec claude --add-dir "$TASK_WT"
|
package/bin/lathe-sync
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lathe sync — re-sync harness/ to target/.claude/ in the develop worktree.
|
|
3
|
+
# Useful after manual harness edits, or if post-merge hook didn't fire (e.g.,
|
|
4
|
+
# merge happened via GitHub UI).
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
: "${LATHE_HOME:?must be set by lathe dispatcher}"
|
|
8
|
+
source "$LATHE_HOME/bin/_lathe-lib.sh"
|
|
9
|
+
|
|
10
|
+
DEVELOP_WT="$(lathe_wt_for_branch develop)" || {
|
|
11
|
+
echo "lathe sync: develop worktree not found. Run 'lathe init' first." >&2
|
|
12
|
+
exit 1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if [ ! -x "$DEVELOP_WT/bin/sync.sh" ]; then
|
|
16
|
+
echo "lathe sync: $DEVELOP_WT/bin/sync.sh missing or not executable" >&2
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
exec "$DEVELOP_WT/bin/sync.sh"
|
package/bin/lathe-target
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# lathe target — cd into develop worktree's target/ and launch claude.
|
|
3
|
+
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
: "${LATHE_HOME:?must be set by lathe dispatcher}"
|
|
6
|
+
source "$LATHE_HOME/bin/_lathe-lib.sh"
|
|
7
|
+
|
|
8
|
+
DEVELOP_WT="$(lathe_wt_for_branch develop)" || {
|
|
9
|
+
echo "lathe target: develop worktree not found. Run 'lathe init' first." >&2
|
|
10
|
+
exit 1
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
cd "$DEVELOP_WT/target"
|
|
14
|
+
exec claude "$@"
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lathe-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Agent harness CLI: target/meta git worktrees driven by Claude Code",
|
|
5
|
+
"bin": {
|
|
6
|
+
"lathe": "./bin/lathe"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"template/",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"postinstall": "node -e \"try { require('child_process').execSync('./bin/check-deps.sh', { stdio: 'inherit' }) } catch(e) {}\""
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=16"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/yutaro0915/Lathe.git"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"claude",
|
|
26
|
+
"agent",
|
|
27
|
+
"harness",
|
|
28
|
+
"git-worktree"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"os": [
|
|
32
|
+
"darwin",
|
|
33
|
+
"linux"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Sync harness/ (source of truth, editable by meta) into target/ (where
|
|
3
|
+
# Claude Code reads from, partly under .claude/ which Claude Code's
|
|
4
|
+
# sensitive-file guard blocks from in-tool edits).
|
|
5
|
+
#
|
|
6
|
+
# Run this whenever harness/ changes:
|
|
7
|
+
# - Manually after editing harness/ by hand
|
|
8
|
+
# - Automatically by meta-side hooks after meta improves harness/
|
|
9
|
+
# - On fresh clone before launching target the first time
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
REPO="$(cd "$(dirname "$0")/.." && pwd)"
|
|
14
|
+
HARNESS="$REPO/harness"
|
|
15
|
+
TARGET="$REPO/target"
|
|
16
|
+
|
|
17
|
+
if [ ! -d "$HARNESS" ]; then
|
|
18
|
+
echo "sync-harness: $HARNESS does not exist" >&2
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
# Top-level files at target/ root.
|
|
23
|
+
mkdir -p "$TARGET"
|
|
24
|
+
cp -f "$HARNESS/CLAUDE.md" "$TARGET/CLAUDE.md"
|
|
25
|
+
cp -f "$HARNESS/plan_template.html" "$TARGET/plan_template.html"
|
|
26
|
+
|
|
27
|
+
# workflow/ (yaml templates).
|
|
28
|
+
mkdir -p "$TARGET/workflow"
|
|
29
|
+
rm -rf "$TARGET/workflow"/*
|
|
30
|
+
cp -R "$HARNESS/workflow/." "$TARGET/workflow/"
|
|
31
|
+
|
|
32
|
+
# hooks/ (shell scripts — executable bit must be preserved).
|
|
33
|
+
mkdir -p "$TARGET/hooks"
|
|
34
|
+
rm -rf "$TARGET/hooks"/*
|
|
35
|
+
cp -R "$HARNESS/hooks/." "$TARGET/hooks/"
|
|
36
|
+
chmod +x "$TARGET/hooks"/*.sh
|
|
37
|
+
|
|
38
|
+
# .claude/ — the path Claude Code reads at startup. Sensitive-file guard
|
|
39
|
+
# blocks tool-based edits here, but cp from outside the claude process
|
|
40
|
+
# is fine. We rebuild settings.json + skills/ + agents/.
|
|
41
|
+
mkdir -p "$TARGET/.claude/skills" "$TARGET/.claude/agents"
|
|
42
|
+
rm -rf "$TARGET/.claude/skills"/* "$TARGET/.claude/agents"/*
|
|
43
|
+
cp -f "$HARNESS/settings.json" "$TARGET/.claude/settings.json"
|
|
44
|
+
cp -R "$HARNESS/skills/." "$TARGET/.claude/skills/"
|
|
45
|
+
cp -R "$HARNESS/agents/." "$TARGET/.claude/agents/"
|
|
46
|
+
|
|
47
|
+
# plans/ is runtime, NOT from harness. Keep what's there.
|
|
48
|
+
mkdir -p "$TARGET/plans"
|
|
49
|
+
|
|
50
|
+
echo "sync-harness: target/ rebuilt from harness/"
|