soba-cli 0.1.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.
- checksums.yaml +7 -0
- data/.claude/commands/osoba/add-backlog.md +173 -0
- data/.claude/commands/osoba/implement.md +151 -0
- data/.claude/commands/osoba/plan.md +217 -0
- data/.claude/commands/osoba/review.md +133 -0
- data/.claude/commands/osoba/revise.md +176 -0
- data/.claude/commands/soba/implement.md +88 -0
- data/.claude/commands/soba/plan.md +93 -0
- data/.claude/commands/soba/review.md +91 -0
- data/.claude/commands/soba/revise.md +76 -0
- data/.devcontainer/.env +2 -0
- data/.devcontainer/Dockerfile +3 -0
- data/.devcontainer/LICENSE +21 -0
- data/.devcontainer/README.md +85 -0
- data/.devcontainer/bin/devcontainer-common.sh +50 -0
- data/.devcontainer/bin/down +35 -0
- data/.devcontainer/bin/rebuild +10 -0
- data/.devcontainer/bin/up +11 -0
- data/.devcontainer/compose.yaml +28 -0
- data/.devcontainer/devcontainer.json +53 -0
- data/.devcontainer/post-attach.sh +29 -0
- data/.devcontainer/post-create.sh +62 -0
- data/.devcontainer/setup/01-os-package.sh +19 -0
- data/.devcontainer/setup/02-npm-package.sh +22 -0
- data/.devcontainer/setup/03-mcp-server.sh +33 -0
- data/.devcontainer/setup/04-tool.sh +17 -0
- data/.devcontainer/setup/05-soba-setup.sh +66 -0
- data/.devcontainer/setup/scripts/functions/install_apt.sh +77 -0
- data/.devcontainer/setup/scripts/functions/install_npm.sh +71 -0
- data/.devcontainer/setup/scripts/functions/mcp_config.sh +14 -0
- data/.devcontainer/setup/scripts/functions/print_message.sh +59 -0
- data/.devcontainer/setup/scripts/setup/mcp-markdownify.sh +39 -0
- data/.devcontainer/sync-envs.sh +58 -0
- data/.envrc.sample +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +70 -0
- data/.rubocop_airbnb.yml +2 -0
- data/.rubocop_todo.yml +74 -0
- data/.tool-versions +1 -0
- data/CLAUDE.md +20 -0
- data/LICENSE +21 -0
- data/README.md +384 -0
- data/README_ja.md +384 -0
- data/Rakefile +18 -0
- data/bin/soba +120 -0
- data/config/config.yml.example +36 -0
- data/docs/business/INDEX.md +6 -0
- data/docs/business/overview.md +42 -0
- data/docs/business/workflow.md +143 -0
- data/docs/development/INDEX.md +10 -0
- data/docs/development/architecture.md +69 -0
- data/docs/development/coding-standards.md +152 -0
- data/docs/development/distribution.md +26 -0
- data/docs/development/implementation-guide.md +103 -0
- data/docs/development/testing-strategy.md +128 -0
- data/docs/development/tmux-management.md +253 -0
- data/docs/document_system.md +58 -0
- data/lib/soba/commands/config/show.rb +63 -0
- data/lib/soba/commands/init.rb +778 -0
- data/lib/soba/commands/open.rb +144 -0
- data/lib/soba/commands/start.rb +442 -0
- data/lib/soba/commands/status.rb +175 -0
- data/lib/soba/commands/stop.rb +147 -0
- data/lib/soba/config_loader.rb +32 -0
- data/lib/soba/configuration.rb +268 -0
- data/lib/soba/container.rb +48 -0
- data/lib/soba/domain/issue.rb +38 -0
- data/lib/soba/domain/phase_strategy.rb +74 -0
- data/lib/soba/infrastructure/errors.rb +23 -0
- data/lib/soba/infrastructure/github_client.rb +399 -0
- data/lib/soba/infrastructure/lock_manager.rb +129 -0
- data/lib/soba/infrastructure/tmux_client.rb +331 -0
- data/lib/soba/services/ansi_processor.rb +92 -0
- data/lib/soba/services/auto_merge_service.rb +133 -0
- data/lib/soba/services/closed_issue_window_cleaner.rb +96 -0
- data/lib/soba/services/daemon_service.rb +83 -0
- data/lib/soba/services/git_workspace_manager.rb +102 -0
- data/lib/soba/services/issue_monitor.rb +29 -0
- data/lib/soba/services/issue_processor.rb +215 -0
- data/lib/soba/services/issue_watcher.rb +193 -0
- data/lib/soba/services/pid_manager.rb +87 -0
- data/lib/soba/services/process_info.rb +58 -0
- data/lib/soba/services/queueing_service.rb +98 -0
- data/lib/soba/services/session_logger.rb +111 -0
- data/lib/soba/services/session_resolver.rb +72 -0
- data/lib/soba/services/slack_notifier.rb +121 -0
- data/lib/soba/services/status_manager.rb +74 -0
- data/lib/soba/services/test_process_manager.rb +84 -0
- data/lib/soba/services/tmux_session_manager.rb +251 -0
- data/lib/soba/services/workflow_blocking_checker.rb +73 -0
- data/lib/soba/services/workflow_executor.rb +256 -0
- data/lib/soba/services/workflow_integrity_checker.rb +151 -0
- data/lib/soba/templates/claude_commands/implement.md +88 -0
- data/lib/soba/templates/claude_commands/plan.md +93 -0
- data/lib/soba/templates/claude_commands/review.md +91 -0
- data/lib/soba/templates/claude_commands/revise.md +76 -0
- data/lib/soba/version.rb +5 -0
- data/lib/soba.rb +44 -0
- data/lib/tasks/gem.rake +75 -0
- data/soba-cli.gemspec +59 -0
- metadata +430 -0
@@ -0,0 +1,253 @@
|
|
1
|
+
# tmux管理機能
|
2
|
+
|
3
|
+
## 概要
|
4
|
+
|
5
|
+
sobaのtmux管理機能は、Claude Codeの実行環境をtmuxセッション内で分離・管理することで、長時間実行される処理の監視や並行実行を可能にします。
|
6
|
+
|
7
|
+
## アーキテクチャ
|
8
|
+
|
9
|
+
### コンポーネント構成
|
10
|
+
|
11
|
+
```
|
12
|
+
┌────────────────────────────┐
|
13
|
+
│ WorkflowExecutor │ → ワークフロー実行制御
|
14
|
+
└────────┬───────────────────┘
|
15
|
+
│
|
16
|
+
▼
|
17
|
+
┌────────────────────────────┐
|
18
|
+
│ TmuxSessionManager │ → セッション管理ロジック
|
19
|
+
└────────┬───────────────────┘
|
20
|
+
│
|
21
|
+
▼
|
22
|
+
┌────────────────────────────┐
|
23
|
+
│ TmuxClient │ → tmuxコマンドラッパー
|
24
|
+
└────────────────────────────┘
|
25
|
+
```
|
26
|
+
|
27
|
+
### 責務分担
|
28
|
+
|
29
|
+
| コンポーネント | 責務 |
|
30
|
+
|--------------|------|
|
31
|
+
| **TmuxSessionManager** | セッションライフサイクル管理、命名規則の実装、古いセッションのクリーンアップ |
|
32
|
+
| **TmuxClient** | tmuxコマンドの実行、エラーハンドリング、出力のパース |
|
33
|
+
|
34
|
+
## 主要機能
|
35
|
+
|
36
|
+
### セッション管理
|
37
|
+
|
38
|
+
#### 命名規則
|
39
|
+
セッション名は以下の形式で統一されています:
|
40
|
+
```
|
41
|
+
soba-{repository}
|
42
|
+
```
|
43
|
+
- `repository`: GitHubリポジトリ名(スラッシュやドットはハイフンに変換)
|
44
|
+
|
45
|
+
#### ライフサイクル
|
46
|
+
1. **作成**: `find_or_create_repository_session` - リポジトリ用セッションを作成または取得
|
47
|
+
2. **ウィンドウ作成**: `create_issue_window` - Issue用ウィンドウを作成
|
48
|
+
3. **ペイン作成**: `create_phase_pane` - フェーズ用ペインを作成
|
49
|
+
4. **クリーンアップ**: 自動または手動でセッション・ウィンドウ・ペインを削除
|
50
|
+
|
51
|
+
### ペイン操作
|
52
|
+
|
53
|
+
#### 基本操作
|
54
|
+
- `send_keys`: コマンドをペインに送信
|
55
|
+
- `capture_pane`: ペイン出力をキャプチャ
|
56
|
+
- `capture_pane_continuous`: 出力を継続的に監視(ストリーミング)
|
57
|
+
|
58
|
+
#### 高度な操作
|
59
|
+
- `split_pane`: ペインの分割(水平/垂直)
|
60
|
+
- `resize_pane`: ペインサイズ調整
|
61
|
+
- `select_pane`: アクティブペインの切り替え
|
62
|
+
- `list_panes`: ペイン一覧と作成時刻の取得
|
63
|
+
- `kill_pane`: 指定ペインの削除
|
64
|
+
- `select_layout`: レイアウトの自動調整
|
65
|
+
|
66
|
+
### ペイン管理の自動化
|
67
|
+
|
68
|
+
#### ペイン数制限機能
|
69
|
+
フェーズ実行時に自動的にペイン数を管理:
|
70
|
+
- **最大ペイン数**: デフォルトで3つに制限
|
71
|
+
- **自動削除**: 4つ目のペイン作成時に最古のペインを自動削除
|
72
|
+
- **作成時刻追跡**: `#{pane_start_time}`フォーマットを使用
|
73
|
+
|
74
|
+
#### レイアウト自動調整
|
75
|
+
ペイン作成・削除後に自動的にレイアウトを調整:
|
76
|
+
- **水平分割**: フェーズ実行時のデフォルト(`vertical: false`)
|
77
|
+
- **自動調整**: `even-horizontal`レイアウトを適用
|
78
|
+
- **均等配置**: すべてのペインが同じ幅になるよう調整
|
79
|
+
|
80
|
+
### 自動クリーンアップ
|
81
|
+
|
82
|
+
クローズされたIssueのウィンドウは自動的に削除されます:
|
83
|
+
- `soba start`コマンド実行時に自動チェック
|
84
|
+
- GitHub APIでIssueステータスを確認
|
85
|
+
- クローズされたIssueのウィンドウを自動削除
|
86
|
+
|
87
|
+
## 使用例
|
88
|
+
|
89
|
+
### リポジトリセッションの作成
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
# TmuxSessionManagerのインスタンス作成
|
93
|
+
manager = Soba::Services::TmuxSessionManager.new(
|
94
|
+
tmux_client: Soba::Infrastructure::TmuxClient.new
|
95
|
+
)
|
96
|
+
|
97
|
+
# リポジトリセッションの作成または取得
|
98
|
+
result = manager.find_or_create_repository_session
|
99
|
+
|
100
|
+
if result[:success]
|
101
|
+
session_name = result[:session_name]
|
102
|
+
# => "soba-owner-repo"
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
### Issueウィンドウの作成
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
# Issueごとのウィンドウを作成
|
110
|
+
window_result = manager.create_issue_window(
|
111
|
+
session_name: "soba-owner-repo",
|
112
|
+
issue_number: 42
|
113
|
+
)
|
114
|
+
# => {
|
115
|
+
# success: true,
|
116
|
+
# window_name: "issue-42",
|
117
|
+
# created: true
|
118
|
+
# }
|
119
|
+
```
|
120
|
+
|
121
|
+
### 並行実行の管理
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
# リポジトリセッション内で複数Issueを並行処理
|
125
|
+
session_result = manager.find_or_create_repository_session
|
126
|
+
|
127
|
+
[24, 25, 26].each do |issue_number|
|
128
|
+
window_result = manager.create_issue_window(
|
129
|
+
session_name: session_result[:session_name],
|
130
|
+
issue_number: issue_number
|
131
|
+
)
|
132
|
+
|
133
|
+
pane_result = manager.create_phase_pane(
|
134
|
+
session_name: session_result[:session_name],
|
135
|
+
window_name: window_result[:window_name],
|
136
|
+
phase: 'implementation'
|
137
|
+
)
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
### フェーズごとのペイン管理
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
# リポジトリセッションとIssueウィンドウの作成
|
145
|
+
session_result = manager.find_or_create_repository_session
|
146
|
+
window_result = manager.create_issue_window(
|
147
|
+
session_name: session_result[:session_name],
|
148
|
+
issue_number: 42
|
149
|
+
)
|
150
|
+
|
151
|
+
# フェーズごとにペインを作成(水平分割、最大3ペイン)
|
152
|
+
phases = ['planning', 'implementation', 'review', 'testing']
|
153
|
+
phases.each do |phase|
|
154
|
+
pane_result = manager.create_phase_pane(
|
155
|
+
session_name: session_result[:session_name],
|
156
|
+
window_name: window_result[:window_name],
|
157
|
+
phase: phase,
|
158
|
+
vertical: false, # 水平分割
|
159
|
+
max_panes: 3 # 最大3ペイン(4つ目から古いペインを削除)
|
160
|
+
)
|
161
|
+
|
162
|
+
if pane_result[:success]
|
163
|
+
puts "Phase #{phase} started in pane #{pane_result[:pane_id]}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
```
|
167
|
+
|
168
|
+
### クリーンアップ実行
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
# クローズされたIssueのウィンドウを削除
|
172
|
+
manager = Soba::Services::TmuxSessionManager.new
|
173
|
+
sessions = manager.list_soba_sessions
|
174
|
+
|
175
|
+
sessions.each do |session_name|
|
176
|
+
windows = @tmux_client.list_windows(session_name)
|
177
|
+
windows.select { |w| w.start_with?('issue-') }.each do |window|
|
178
|
+
issue_number = window.match(/issue-(\d+)/)[1]
|
179
|
+
# GitHub APIでクローズ状態を確認して削除
|
180
|
+
end
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
184
|
+
## エラーハンドリング
|
185
|
+
|
186
|
+
### TmuxNotInstalled例外
|
187
|
+
tmuxがインストールされていない場合に発生:
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
begin
|
191
|
+
client.create_session("test")
|
192
|
+
rescue Soba::Infrastructure::TmuxNotInstalled => e
|
193
|
+
puts "tmuxをインストールしてください"
|
194
|
+
end
|
195
|
+
```
|
196
|
+
|
197
|
+
### ウィンドウ作成失敗
|
198
|
+
セッションが存在しない場合など:
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
result = manager.create_issue_window(
|
202
|
+
session_name: "non-existent",
|
203
|
+
issue_number: 24
|
204
|
+
)
|
205
|
+
if !result[:success]
|
206
|
+
puts "エラー: #{result[:error]}"
|
207
|
+
end
|
208
|
+
```
|
209
|
+
|
210
|
+
## テスト戦略
|
211
|
+
|
212
|
+
### モックを使用した単体テスト
|
213
|
+
```ruby
|
214
|
+
RSpec.describe Soba::Services::TmuxSessionManager do
|
215
|
+
let(:tmux_client) { instance_double(Soba::Infrastructure::TmuxClient) }
|
216
|
+
|
217
|
+
it "creates repository session with correct name" do
|
218
|
+
allow(tmux_client).to receive(:session_exists?).and_return(false)
|
219
|
+
allow(tmux_client).to receive(:create_session).and_return(true)
|
220
|
+
|
221
|
+
result = manager.find_or_create_repository_session
|
222
|
+
expect(result[:session_name]).to match(/^soba-[\w-]+$/)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
```
|
226
|
+
|
227
|
+
### 実環境での統合テスト
|
228
|
+
```ruby
|
229
|
+
RSpec.describe "Tmux Integration", integration: true do
|
230
|
+
it "manages window lifecycle" do
|
231
|
+
session = manager.find_or_create_repository_session
|
232
|
+
window = manager.create_issue_window(
|
233
|
+
session_name: session[:session_name],
|
234
|
+
issue_number: 99
|
235
|
+
)
|
236
|
+
expect(window[:success]).to be true
|
237
|
+
|
238
|
+
pane = manager.create_phase_pane(
|
239
|
+
session_name: session[:session_name],
|
240
|
+
window_name: window[:window_name],
|
241
|
+
phase: 'test'
|
242
|
+
)
|
243
|
+
expect(pane[:success]).to be true
|
244
|
+
end
|
245
|
+
end
|
246
|
+
```
|
247
|
+
|
248
|
+
## 注意事項
|
249
|
+
|
250
|
+
- tmuxセッションは手動でアタッチ可能(`tmux attach-session -t soba-{repository}`)
|
251
|
+
- リポジトリごとに1つのセッションを使用し、Issue単位でウィンドウを管理
|
252
|
+
- フェーズごとにペインを作成し、最大3ペインまで自動管理
|
253
|
+
- tmuxがインストールされていない環境では動作しない
|
@@ -0,0 +1,58 @@
|
|
1
|
+
You are part of a documentation-aware AI system.
|
2
|
+
|
3
|
+
This project uses a structured **Document System** under the `docs/` directory to manage business and technical documents in a hierarchical and searchable format.
|
4
|
+
|
5
|
+
## Folder Structure Overview
|
6
|
+
|
7
|
+
```
|
8
|
+
docs/
|
9
|
+
├── business/ # Business documents
|
10
|
+
│ ├── INDEX.md # Index file for this folder
|
11
|
+
│ ├── overview.md # Project overview
|
12
|
+
│ └── model.md # Business model description
|
13
|
+
│
|
14
|
+
├── development/ # Development-related documents
|
15
|
+
│ ├── INDEX.md # Index file for this folder
|
16
|
+
│ ├── guideline.md # Development guide
|
17
|
+
│ └── coding-rule.md # Coding standards
|
18
|
+
│
|
19
|
+
├── operations/ # (Planned) Operational documents
|
20
|
+
│ ├── INDEX.md # Index file for this folder
|
21
|
+
│ ├── server.md # Server operations
|
22
|
+
│ └── monitoring.md # Monitoring and incident response
|
23
|
+
```
|
24
|
+
|
25
|
+
## Document Characteristics
|
26
|
+
|
27
|
+
- All documents are written in Markdown format.
|
28
|
+
- Each directory contains an `INDEX.md` file listing:
|
29
|
+
- The filenames in the same directory
|
30
|
+
- A brief description for each
|
31
|
+
|
32
|
+
Example:
|
33
|
+
```markdown
|
34
|
+
# Development Documents
|
35
|
+
|
36
|
+
- `guideline.md`: A guide to the development workflow.
|
37
|
+
- `coding-rule.md`: Coding standards for this project.
|
38
|
+
```
|
39
|
+
|
40
|
+
## Integration with CLAUDE.md
|
41
|
+
|
42
|
+
The AI system does **not directly reference documents**. Instead, it recognizes document availability via `CLAUDE.md`, where paths are listed using the format:
|
43
|
+
|
44
|
+
```
|
45
|
+
@docs/development/INDEX.md
|
46
|
+
```
|
47
|
+
|
48
|
+
This tells the AI:
|
49
|
+
- The document exists
|
50
|
+
- It may be referenced when needed
|
51
|
+
- But the AI should **autonomously decide** which document to consult
|
52
|
+
|
53
|
+
## Purpose
|
54
|
+
|
55
|
+
The Document System allows AI agents to:
|
56
|
+
- Navigate structured, maintainable documentation
|
57
|
+
- Understand the project context through index files
|
58
|
+
- Autonomously choose and reference relevant documents during tasks
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/object/blank"
|
4
|
+
require_relative "../../config_loader"
|
5
|
+
require_relative "../../configuration"
|
6
|
+
|
7
|
+
module Soba
|
8
|
+
module Commands
|
9
|
+
module Config
|
10
|
+
class Show
|
11
|
+
def execute(config_path: nil)
|
12
|
+
config = Soba::ConfigLoader.load(path: config_path)
|
13
|
+
|
14
|
+
puts "=== soba Configuration ==="
|
15
|
+
puts ""
|
16
|
+
puts "GitHub:"
|
17
|
+
puts " Repository: #{config.github.repository}"
|
18
|
+
puts " Token: #{mask_token(config.github.token)}"
|
19
|
+
puts ""
|
20
|
+
puts "Workflow:"
|
21
|
+
puts " Interval: #{config.workflow.interval} seconds"
|
22
|
+
puts ""
|
23
|
+
puts "Configuration loaded from: #{find_config_path(config_path)}"
|
24
|
+
rescue Soba::ConfigurationError => e
|
25
|
+
Soba.logger.error "Configuration Error: #{e.message}"
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def mask_token(token)
|
32
|
+
return "Not set" if token.blank?
|
33
|
+
|
34
|
+
if token.length > 8
|
35
|
+
"#{token[0..3]}...#{token[-4..]}"
|
36
|
+
else
|
37
|
+
"*" * token.length
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_config_path(path)
|
42
|
+
return path if path
|
43
|
+
|
44
|
+
project_root = find_project_root
|
45
|
+
return "Not found" unless project_root
|
46
|
+
|
47
|
+
project_root.join('.soba', 'config.yml')
|
48
|
+
end
|
49
|
+
|
50
|
+
def find_project_root
|
51
|
+
current = Pathname.pwd
|
52
|
+
|
53
|
+
until current.root?
|
54
|
+
return current if current.join('.git').exist?
|
55
|
+
current = current.parent
|
56
|
+
end
|
57
|
+
|
58
|
+
Pathname.pwd
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|