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.
Files changed (101) hide show
  1. checksums.yaml +7 -0
  2. data/.claude/commands/osoba/add-backlog.md +173 -0
  3. data/.claude/commands/osoba/implement.md +151 -0
  4. data/.claude/commands/osoba/plan.md +217 -0
  5. data/.claude/commands/osoba/review.md +133 -0
  6. data/.claude/commands/osoba/revise.md +176 -0
  7. data/.claude/commands/soba/implement.md +88 -0
  8. data/.claude/commands/soba/plan.md +93 -0
  9. data/.claude/commands/soba/review.md +91 -0
  10. data/.claude/commands/soba/revise.md +76 -0
  11. data/.devcontainer/.env +2 -0
  12. data/.devcontainer/Dockerfile +3 -0
  13. data/.devcontainer/LICENSE +21 -0
  14. data/.devcontainer/README.md +85 -0
  15. data/.devcontainer/bin/devcontainer-common.sh +50 -0
  16. data/.devcontainer/bin/down +35 -0
  17. data/.devcontainer/bin/rebuild +10 -0
  18. data/.devcontainer/bin/up +11 -0
  19. data/.devcontainer/compose.yaml +28 -0
  20. data/.devcontainer/devcontainer.json +53 -0
  21. data/.devcontainer/post-attach.sh +29 -0
  22. data/.devcontainer/post-create.sh +62 -0
  23. data/.devcontainer/setup/01-os-package.sh +19 -0
  24. data/.devcontainer/setup/02-npm-package.sh +22 -0
  25. data/.devcontainer/setup/03-mcp-server.sh +33 -0
  26. data/.devcontainer/setup/04-tool.sh +17 -0
  27. data/.devcontainer/setup/05-soba-setup.sh +66 -0
  28. data/.devcontainer/setup/scripts/functions/install_apt.sh +77 -0
  29. data/.devcontainer/setup/scripts/functions/install_npm.sh +71 -0
  30. data/.devcontainer/setup/scripts/functions/mcp_config.sh +14 -0
  31. data/.devcontainer/setup/scripts/functions/print_message.sh +59 -0
  32. data/.devcontainer/setup/scripts/setup/mcp-markdownify.sh +39 -0
  33. data/.devcontainer/sync-envs.sh +58 -0
  34. data/.envrc.sample +7 -0
  35. data/.rspec +4 -0
  36. data/.rubocop.yml +70 -0
  37. data/.rubocop_airbnb.yml +2 -0
  38. data/.rubocop_todo.yml +74 -0
  39. data/.tool-versions +1 -0
  40. data/CLAUDE.md +20 -0
  41. data/LICENSE +21 -0
  42. data/README.md +384 -0
  43. data/README_ja.md +384 -0
  44. data/Rakefile +18 -0
  45. data/bin/soba +120 -0
  46. data/config/config.yml.example +36 -0
  47. data/docs/business/INDEX.md +6 -0
  48. data/docs/business/overview.md +42 -0
  49. data/docs/business/workflow.md +143 -0
  50. data/docs/development/INDEX.md +10 -0
  51. data/docs/development/architecture.md +69 -0
  52. data/docs/development/coding-standards.md +152 -0
  53. data/docs/development/distribution.md +26 -0
  54. data/docs/development/implementation-guide.md +103 -0
  55. data/docs/development/testing-strategy.md +128 -0
  56. data/docs/development/tmux-management.md +253 -0
  57. data/docs/document_system.md +58 -0
  58. data/lib/soba/commands/config/show.rb +63 -0
  59. data/lib/soba/commands/init.rb +778 -0
  60. data/lib/soba/commands/open.rb +144 -0
  61. data/lib/soba/commands/start.rb +442 -0
  62. data/lib/soba/commands/status.rb +175 -0
  63. data/lib/soba/commands/stop.rb +147 -0
  64. data/lib/soba/config_loader.rb +32 -0
  65. data/lib/soba/configuration.rb +268 -0
  66. data/lib/soba/container.rb +48 -0
  67. data/lib/soba/domain/issue.rb +38 -0
  68. data/lib/soba/domain/phase_strategy.rb +74 -0
  69. data/lib/soba/infrastructure/errors.rb +23 -0
  70. data/lib/soba/infrastructure/github_client.rb +399 -0
  71. data/lib/soba/infrastructure/lock_manager.rb +129 -0
  72. data/lib/soba/infrastructure/tmux_client.rb +331 -0
  73. data/lib/soba/services/ansi_processor.rb +92 -0
  74. data/lib/soba/services/auto_merge_service.rb +133 -0
  75. data/lib/soba/services/closed_issue_window_cleaner.rb +96 -0
  76. data/lib/soba/services/daemon_service.rb +83 -0
  77. data/lib/soba/services/git_workspace_manager.rb +102 -0
  78. data/lib/soba/services/issue_monitor.rb +29 -0
  79. data/lib/soba/services/issue_processor.rb +215 -0
  80. data/lib/soba/services/issue_watcher.rb +193 -0
  81. data/lib/soba/services/pid_manager.rb +87 -0
  82. data/lib/soba/services/process_info.rb +58 -0
  83. data/lib/soba/services/queueing_service.rb +98 -0
  84. data/lib/soba/services/session_logger.rb +111 -0
  85. data/lib/soba/services/session_resolver.rb +72 -0
  86. data/lib/soba/services/slack_notifier.rb +121 -0
  87. data/lib/soba/services/status_manager.rb +74 -0
  88. data/lib/soba/services/test_process_manager.rb +84 -0
  89. data/lib/soba/services/tmux_session_manager.rb +251 -0
  90. data/lib/soba/services/workflow_blocking_checker.rb +73 -0
  91. data/lib/soba/services/workflow_executor.rb +256 -0
  92. data/lib/soba/services/workflow_integrity_checker.rb +151 -0
  93. data/lib/soba/templates/claude_commands/implement.md +88 -0
  94. data/lib/soba/templates/claude_commands/plan.md +93 -0
  95. data/lib/soba/templates/claude_commands/review.md +91 -0
  96. data/lib/soba/templates/claude_commands/revise.md +76 -0
  97. data/lib/soba/version.rb +5 -0
  98. data/lib/soba.rb +44 -0
  99. data/lib/tasks/gem.rake +75 -0
  100. data/soba-cli.gemspec +59 -0
  101. metadata +430 -0
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../configuration"
4
+
5
+ module Soba
6
+ module Services
7
+ class WorkflowIntegrityChecker
8
+ ACTIVE_LABELS = %w(
9
+ soba:queued
10
+ soba:planning
11
+ soba:doing
12
+ soba:reviewing
13
+ soba:revising
14
+ ).freeze
15
+
16
+ INTERMEDIATE_LABELS = %w(
17
+ soba:review-requested
18
+ soba:requires-changes
19
+ ).freeze
20
+
21
+ attr_reader :github_client, :logger
22
+
23
+ def initialize(github_client:, logger: nil)
24
+ @github_client = github_client
25
+ @logger = logger || SemanticLogger["WorkflowIntegrityChecker"]
26
+ end
27
+
28
+ def check_and_fix(repository, issues:, dry_run: false)
29
+ logger.info("Checking workflow integrity for #{repository}")
30
+
31
+ violations = detect_violations(issues)
32
+
33
+ if violations.empty?
34
+ logger.info("No workflow integrity violations found")
35
+ return {
36
+ violations_found: false,
37
+ fixed_count: 0,
38
+ violations: [],
39
+ dry_run: dry_run,
40
+ }
41
+ end
42
+
43
+ logger.warn("Found #{violations.size} workflow integrity violations")
44
+ violations.each do |violation|
45
+ logger.warn(" Issue ##{violation[:issue_number]}: #{violation[:label]} (#{violation[:action]})")
46
+ end
47
+
48
+ fixed_count = 0
49
+ failed_fixes = 0
50
+
51
+ if dry_run
52
+ logger.info("Dry run mode - no fixes applied")
53
+ else
54
+ violations.each do |violation|
55
+ if fix_violation(repository, violation)
56
+ fixed_count += 1
57
+ else
58
+ failed_fixes += 1
59
+ end
60
+ end
61
+ if fixed_count > 0 || failed_fixes > 0
62
+ logger.info("Fixed #{fixed_count} violations, #{failed_fixes} failed")
63
+ end
64
+ end
65
+
66
+ {
67
+ violations_found: true,
68
+ fixed_count: fixed_count,
69
+ failed_fixes: failed_fixes,
70
+ violations: violations,
71
+ dry_run: dry_run,
72
+ }
73
+ end
74
+
75
+ private
76
+
77
+ def detect_violations(issues)
78
+ violations = []
79
+
80
+ # Find all issues with active or intermediate labels
81
+ active_issues = issues.select do |issue|
82
+ labels = extract_label_names(issue.labels)
83
+ (labels & (ACTIVE_LABELS + INTERMEDIATE_LABELS)).any?
84
+ end
85
+
86
+ return violations if active_issues.size <= 1
87
+
88
+ # Multiple active issues detected - keep only the newest
89
+ # Sort by created_at descending (newest first)
90
+ sorted_issues = active_issues.sort_by { |issue| issue.created_at }.reverse
91
+ newest_issue = sorted_issues.first
92
+
93
+ # Mark all others as violations
94
+ sorted_issues[1..-1].each do |issue|
95
+ labels = extract_label_names(issue.labels)
96
+ conflicting_label = labels.find { |l| (ACTIVE_LABELS + INTERMEDIATE_LABELS).include?(l) }
97
+
98
+ violations << {
99
+ issue_number: issue.number,
100
+ label: conflicting_label,
101
+ action: "removed",
102
+ reason: "Multiple active issues detected, keeping newest (Issue ##{newest_issue.number})",
103
+ }
104
+ end
105
+
106
+ violations
107
+ end
108
+
109
+ def fix_violation(repository, violation)
110
+ logger.info("Fixing violation: Issue ##{violation[:issue_number]} - removing #{violation[:label]}")
111
+
112
+ # Determine the target label based on what's being removed
113
+ target_label = determine_target_label(violation[:label])
114
+
115
+ github_client.update_issue_labels(
116
+ repository,
117
+ violation[:issue_number],
118
+ from: violation[:label],
119
+ to: target_label
120
+ )
121
+
122
+ logger.info("Successfully fixed Issue ##{violation[:issue_number]}")
123
+ true
124
+ rescue => e
125
+ logger.error("Failed to fix violation for Issue ##{violation[:issue_number]}: #{e.message}")
126
+ false
127
+ end
128
+
129
+ def determine_target_label(from_label)
130
+ # Most labels should revert to todo
131
+ # Special cases can be handled here if needed
132
+ case from_label
133
+ when "soba:review-requested", "soba:requires-changes"
134
+ "soba:ready" # Review states go back to ready
135
+ else
136
+ "soba:todo" # Active states go back to todo
137
+ end
138
+ end
139
+
140
+ def extract_label_names(labels)
141
+ labels.map do |label|
142
+ if label.is_a?(Hash)
143
+ label[:name] || label["name"]
144
+ else
145
+ label.name
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,88 @@
1
+ ---
2
+ allowed-tools: TodoRead, TodoWrite, Bash, Read, Write, Edit, MultiEdit, Grep, Glob
3
+ description: "TDDによる実装とPR作成"
4
+ ---
5
+
6
+ ## 概要
7
+
8
+ 実装計画に基づいてTDDで開発を進め、Pull Requestを作成します。
9
+
10
+ ---
11
+
12
+ ## 前提条件
13
+
14
+ - Issueコメントに実装計画が存在
15
+ - ラベルは `soba:doing` の状態
16
+
17
+ ---
18
+
19
+ ## ルール
20
+
21
+ 1. **実装計画を必ず確認し従う**
22
+ 2. **TDD実践(テストファースト)**
23
+ 3. **既存設計・アーキテクチャを尊重**
24
+ 4. **実装完了後はPRを作成**
25
+ 5. **全テストのパスが必須条件**
26
+
27
+ ---
28
+
29
+ ## 実行手順
30
+
31
+ 1. **Issue・計画確認**
32
+ - `gh issue view <番号>` で内容確認
33
+ - `gh issue view <番号> --comments` でコメント確認
34
+
35
+ 2. **テスト作成**
36
+ - 計画に基づくテストケース作成
37
+ - Red → Green → Refactor
38
+
39
+ 3. **実装**
40
+ - 小さな単位でコミット
41
+ - 意味のあるコミットメッセージ
42
+
43
+ 4. **テスト実行**
44
+ - 単体テスト実行
45
+ - 全体テスト実行(必須)
46
+
47
+ 5. **PRテンプレート作成**
48
+ - `./.tmp/pull-request-<番号>.md` 作成
49
+
50
+ 6. **PR作成**
51
+ ```bash
52
+ gh pr create \
53
+ --title "feat: [機能名] (#<Issue番号>)" \
54
+ --body-file ./.tmp/pull-request-<番号>.md \
55
+ --base main
56
+ ```
57
+
58
+ 7. **Issueコメント**
59
+ - 「PR #<番号> を作成しました」
60
+
61
+ 8. **ラベル更新**
62
+ ```bash
63
+ gh issue edit <番号> \
64
+ --remove-label "soba:doing" \
65
+ --add-label "soba:review-requested"
66
+ ```
67
+
68
+ ---
69
+
70
+ ## PRテンプレート
71
+
72
+ ```markdown
73
+ ## 実装完了
74
+
75
+ fixes #<番号>
76
+
77
+ ### 変更内容
78
+ - [主要な変更点]
79
+
80
+ ### テスト結果
81
+ - 単体テスト: ✅ パス
82
+ - 全体テスト: ✅ パス
83
+
84
+ ### 確認事項
85
+ - [ ] 実装計画に沿った実装
86
+ - [ ] テストカバレッジ確保
87
+ - [ ] 既存機能への影響なし
88
+ ```
@@ -0,0 +1,93 @@
1
+ ---
2
+ allowed-tools: TodoWrite, TodoRead, Bash, Read, Grep, Glob
3
+ description: "GitHub Issueの実装計画を策定"
4
+ ---
5
+
6
+ ## 概要
7
+
8
+ GitHub Issueに対する実装計画を策定し、Issueコメントとして投稿します。
9
+
10
+ ---
11
+
12
+ ## 前提条件
13
+
14
+ - ラベルは `soba:planning` の状態
15
+
16
+ ---
17
+
18
+ ## ルール
19
+
20
+ 1. **コード修正は行わず、計画策定に専念**
21
+ 2. **TDDを前提とした計画設計**
22
+ 3. **既存アーキテクチャに従う**
23
+ 4. **実行可能な単位にステップ分割**
24
+ 5. **テンプレート形式で計画作成**
25
+ 6. **完了後ラベルを `soba:ready` に更新**
26
+
27
+ ---
28
+
29
+ ## 実行手順
30
+
31
+ 1. **Issue確認**
32
+ - `gh issue view <番号>` で内容確認
33
+ - `gh issue view <番号> --comments` でコメント確認
34
+
35
+ 2. **コードベース調査**
36
+ - 関連ファイル・過去実装を確認
37
+ - 影響範囲と依存関係を特定
38
+
39
+ 3. **技術選定**
40
+ - 使用ライブラリ・パターンを決定
41
+ - 選定理由を明確化
42
+
43
+ 4. **実装ステップ定義**
44
+ - テスト可能な単位に分割
45
+ - 関連ファイル・副作用を記載
46
+
47
+ 5. **テスト・リスク・スケジュール策定**
48
+ - テスト計画(単体・統合)
49
+ - リスクと対策
50
+ - 実装期間の見積もり
51
+
52
+ 6. **計画ファイル作成**
53
+ - `./.tmp/plan-[slug].md` に保存
54
+
55
+ 7. **コメント投稿**
56
+ - `gh issue comment <番号> --body-file ./.tmp/plan-[slug].md`
57
+
58
+ 8. **ラベル更新**
59
+ - `gh issue edit <番号> --remove-label "soba:planning" --add-label "soba:ready"`
60
+
61
+ ---
62
+
63
+ ## テンプレート
64
+
65
+ ```markdown
66
+ # 実装計画: [タイトル]
67
+
68
+ ## 要件概要
69
+ - [目的と背景]
70
+ - [機能要件]
71
+ - [受け入れ条件]
72
+
73
+ ## 設計方針
74
+ - [技術選定と理由]
75
+ - [アーキテクチャ上の考慮点]
76
+
77
+ ## 実装ステップ
78
+ 1. [ステップ名]
79
+ - 作業内容: [詳細]
80
+ - 関連ファイル: [ファイルパス]
81
+
82
+ ## テスト計画
83
+ - 単体テスト: [対象とケース]
84
+ - 統合テスト: [シナリオ]
85
+
86
+ ## リスクと対策
87
+ - リスク: [内容]
88
+ 対策: [方法]
89
+
90
+ ## スケジュール
91
+ - 見積もり: 合計[X]時間
92
+ - ステップ別: 各[Y]時間
93
+ ```
@@ -0,0 +1,91 @@
1
+ ---
2
+ allowed-tools: Bash, Read, Write, Edit, MultiEdit, Grep, Glob, LS
3
+ description: "Review a Pull Request for a soba Issue"
4
+ ---
5
+
6
+ # Review PR
7
+
8
+ PRレビューを実施します。
9
+
10
+ ## Context
11
+
12
+ - Issue番号: $ARGUMENTS
13
+
14
+ ## Workflow
15
+
16
+ ### 1. Issue確認
17
+
18
+ ```bash
19
+ GH_PAGER= gh issue view <issue-number>
20
+ GH_PAGER= gh issue view <issue-number> --comments
21
+ ```
22
+
23
+ ### 2. PR確認
24
+
25
+ ```bash
26
+ GH_PAGER= gh pr view <PR-number>
27
+ GH_PAGER= gh pr view <PR-number> --json mergeable,mergeStateStatus
28
+ ```
29
+
30
+ ### 3. コード変更確認
31
+
32
+ ```bash
33
+ GH_PAGER= gh pr diff <PR-number>
34
+ ```
35
+
36
+ レビュー観点:
37
+ - コーディング規約への準拠
38
+ - テストの実装状況
39
+ - セキュリティ上の懸念
40
+ - 不要な差分の有無
41
+
42
+ ### 4. CI確認(必須・完了まで待機)
43
+
44
+ ```bash
45
+ gh pr checks <PR-number> --watch # Timeout 600000
46
+ ```
47
+
48
+ ⚠️ **重要**: CI完了前にレビュー結果を投稿しないこと
49
+
50
+ ### 5. レビュー結果投稿
51
+
52
+ `./.tmp/review-result-<issue-number>.md`を作成:
53
+
54
+ ```markdown
55
+ ## レビュー結果
56
+
57
+ - Issue: #<issue-number>
58
+ - PR: #<PR-number>
59
+
60
+ ### ✅ 判定
61
+ - [ ] 承認(LGTM)
62
+ - [ ] 修正要求
63
+
64
+ ### 🔄 マージ状態
65
+ - [ ] コンフリクトなし
66
+ - [ ] コンフリクトあり(要リベース)
67
+
68
+ ### 👍 良い点
69
+ - [実装の良い点]
70
+
71
+ ### 🛠 改善提案
72
+ - [具体的な改善点]
73
+ ```
74
+
75
+ 投稿:
76
+ ```bash
77
+ gh pr comment <PR-number> --body "$(cat ./.tmp/review-result-<issue-number>.md)"
78
+ ```
79
+
80
+ ### 6. ラベル更新
81
+
82
+ 承認の場合:
83
+ ```bash
84
+ gh issue edit <issue-number> --remove-label "soba:reviewing" --add-label "soba:done"
85
+ gh pr edit <PR-number> --add-label "soba:lgtm"
86
+ ```
87
+
88
+ 修正要求の場合:
89
+ ```bash
90
+ gh issue edit <issue-number> --remove-label "soba:reviewing" --add-label "soba:requires-changes"
91
+ ```
@@ -0,0 +1,76 @@
1
+ ---
2
+ allowed-tools: Bash, Read, Write, Edit, MultiEdit, Grep, Glob, LS
3
+ description: "Revise implementation based on review feedback"
4
+ ---
5
+
6
+ # Revise PR
7
+
8
+ レビュー指摘事項に対応します。
9
+
10
+ ## Context
11
+
12
+ - Issue番号: $ARGUMENTS
13
+
14
+ ## Workflow
15
+
16
+ ### 1. PR確認
17
+
18
+ ```bash
19
+ GH_PAGER= gh pr list --search "linked:$ARGUMENTS" --state open --json number --jq '.[0].number'
20
+ ```
21
+
22
+ ### 2. レビューコメント確認
23
+
24
+ ```bash
25
+ GH_PAGER= gh pr view <PR-number> --comments
26
+ ```
27
+
28
+ ### 3. 指摘事項への対応
29
+
30
+ レビューコメントに基づいて修正を実施:
31
+ - コード品質の改善
32
+ - テストの追加・修正
33
+ - エラーハンドリングの改善
34
+ - 不要な差分の削除
35
+
36
+ ### 4. テスト実行
37
+
38
+ ```bash
39
+ bundle exec rspec # Timeout 600000
40
+ ```
41
+
42
+ ### 5. 修正内容のコミット
43
+
44
+ ```bash
45
+ git add -A
46
+ git commit -m "fix: レビュー指摘事項への対応
47
+
48
+ - [修正内容の要約]
49
+ "
50
+ git push
51
+ ```
52
+
53
+ ### 6. 対応完了コメント
54
+
55
+ `./.tmp/revise-complete-<issue-number>.md`を作成:
56
+
57
+ ```markdown
58
+ ## レビュー指摘対応完了
59
+
60
+ 以下の指摘事項に対応しました:
61
+ - ✅ [対応項目]
62
+
63
+ 全てのテストがパスすることを確認済みです。
64
+ 再レビューをお願いいたします。
65
+ ```
66
+
67
+ 投稿:
68
+ ```bash
69
+ gh pr comment <PR-number> --body "$(cat ./.tmp/revise-complete-<issue-number>.md)"
70
+ ```
71
+
72
+ ### 7. ラベル更新
73
+
74
+ ```bash
75
+ gh issue edit <issue-number> --remove-label "soba:revising" --add-label "soba:review-requested"
76
+ ```
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Soba
4
+ VERSION = "0.1.0"
5
+ end
data/lib/soba.rb ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gli"
4
+ require "dry-container"
5
+ require "dry-auto_inject"
6
+ require "faraday"
7
+ require "octokit"
8
+ require "concurrent"
9
+ require "semantic_logger"
10
+
11
+ require_relative "soba/version"
12
+
13
+ module Soba
14
+ class Error < StandardError; end
15
+ class ConfigError < Error; end
16
+ class ConfigurationError < Error; end
17
+ class GitHubError < Error; end
18
+ class CommandError < Error; end
19
+
20
+ module Domain; end
21
+ module Services; end
22
+ module Infrastructure; end
23
+ module Commands
24
+ module Issue; end
25
+ module Config; end
26
+ end
27
+
28
+ SemanticLogger.default_level = :info
29
+ SemanticLogger.add_appender(io: $stdout, formatter: :color)
30
+
31
+ def self.logger
32
+ @logger ||= SemanticLogger["Soba"]
33
+ end
34
+ end
35
+
36
+ require_relative "soba/configuration"
37
+ require_relative "soba/config_loader"
38
+ require_relative "soba/container"
39
+ require_relative "soba/domain/issue"
40
+ require_relative "soba/services/issue_monitor"
41
+ require_relative "soba/services/workflow_blocking_checker"
42
+ require_relative "soba/services/queueing_service"
43
+ require_relative "soba/infrastructure/errors"
44
+ require_relative "soba/infrastructure/github_client"
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../soba/version"
4
+
5
+ namespace :gem do
6
+ desc "Build the soba-cli gem"
7
+ task :build do
8
+ puts "Building soba-cli gem..."
9
+ system("gem build soba-cli.gemspec") || abort("Failed to build gem")
10
+ puts "Gem built successfully!"
11
+ end
12
+
13
+ desc "Install the soba-cli gem locally"
14
+ task install: "gem:build" do
15
+ gem_file = Dir.glob("soba-cli-*.gem").max_by { |f| File.mtime(f) }
16
+ abort("No gem file found") unless gem_file
17
+
18
+ puts "Installing #{gem_file}..."
19
+ system("gem install #{gem_file}") || abort("Failed to install gem")
20
+ puts "Gem installed successfully!"
21
+ end
22
+
23
+ desc "Uninstall the soba-cli gem"
24
+ task :uninstall do
25
+ puts "Uninstalling soba-cli gem..."
26
+ system("gem uninstall soba-cli -x") || puts("Gem may not be installed")
27
+ puts "Gem uninstalled successfully!"
28
+ end
29
+
30
+ desc "Clean up built gem files"
31
+ task :clean do
32
+ gem_files = Dir.glob("soba-cli-*.gem")
33
+ if gem_files.any?
34
+ puts "Removing gem files: #{gem_files.join(', ')}"
35
+ gem_files.each { |f| File.delete(f) }
36
+ puts "Cleaned up gem files"
37
+ else
38
+ puts "No gem files to clean"
39
+ end
40
+ end
41
+
42
+ desc "Build, tag, and push gem to RubyGems.org (manual release)"
43
+ task release: "gem:build" do
44
+ puts "🚨 NOTICE: This is a manual release task."
45
+ puts "📋 For automated releases, create a GitHub Release with a tag like 'v1.2.3'"
46
+ puts "🤖 GitHub Actions will automatically build and publish the gem."
47
+ puts ""
48
+
49
+ gem_file = Dir.glob("soba-cli-*.gem").max_by { |f| File.mtime(f) }
50
+ abort("No gem file found") unless gem_file
51
+
52
+ puts "WARNING: This will push #{gem_file} to RubyGems.org!"
53
+ print "Are you sure you want to proceed with manual release? (y/N): "
54
+ input = $stdin.gets.chomp
55
+
56
+ if input.downcase == "y"
57
+ system("gem push #{gem_file}") || abort("Failed to push gem")
58
+ puts "Gem released successfully!"
59
+
60
+ # Tag the release in git
61
+ version = Soba::VERSION
62
+ system("git tag v#{version}") || abort("Failed to create git tag")
63
+ system("git push origin v#{version}") || abort("Failed to push git tag")
64
+ puts "Git tag v#{version} created and pushed"
65
+ else
66
+ puts "Release cancelled"
67
+ end
68
+ end
69
+ end
70
+
71
+ desc "Alias for gem:build"
72
+ task build: "gem:build"
73
+
74
+ desc "Alias for gem:install"
75
+ task install: "gem:install"
data/soba-cli.gemspec ADDED
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/soba/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "soba-cli"
7
+ spec.version = Soba::VERSION
8
+ spec.authors = ["douhashi"]
9
+ spec.email = ["douhashi@gmail.com"]
10
+
11
+ spec.summary = "Autonomous GitHub Issue-driven development CLI with Claude Code"
12
+ spec.description = "Soba is an autonomous CLI tool that fully automates GitHub Issue-driven development workflows. " \
13
+ "It monitors issues, creates implementation plans, generates code, and manages pull requests " \
14
+ "through seamless integration with Claude Code AI, enabling hands-free development cycles."
15
+ spec.homepage = "https://github.com/douhashi/soba-cli"
16
+ spec.license = "MIT"
17
+ spec.required_ruby_version = ">= 3.0.0"
18
+
19
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = spec.homepage
22
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
23
+
24
+ # Specify which files should be added to the gem when it is released.
25
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
26
+ spec.files = Dir.chdir(__dir__) do
27
+ `git ls-files -z`.split("\x0").reject do |f|
28
+ (File.expand_path(f) == __FILE__) ||
29
+ f.start_with?(*%w(test/ spec/ features/ .git .github appveyor Gemfile scripts/ .tmp/))
30
+ end
31
+ end
32
+ spec.bindir = "bin"
33
+ spec.executables = ["soba"]
34
+ spec.require_paths = ["lib"]
35
+
36
+ # Runtime dependencies
37
+ spec.add_runtime_dependency "gli", "~> 2.21"
38
+ spec.add_runtime_dependency "dry-container", "~> 0.11"
39
+ spec.add_runtime_dependency "dry-auto_inject", "~> 1.0"
40
+ spec.add_runtime_dependency "faraday", "~> 2.9"
41
+ spec.add_runtime_dependency "faraday-retry", "~> 2.2"
42
+ spec.add_runtime_dependency "octokit", "~> 10.0"
43
+ spec.add_runtime_dependency "concurrent-ruby", "~> 1.2"
44
+ spec.add_runtime_dependency "semantic_logger", "~> 4.15"
45
+ spec.add_runtime_dependency "dry-configurable", "~> 1.1"
46
+ spec.add_runtime_dependency "activesupport", "~> 8.0"
47
+
48
+ # Development dependencies
49
+ spec.add_development_dependency "rake", "~> 13.0"
50
+ spec.add_development_dependency "rspec", "~> 3.12"
51
+ spec.add_development_dependency "webmock", "~> 3.19"
52
+ spec.add_development_dependency "vcr", "~> 6.2"
53
+ spec.add_development_dependency "factory_bot", "~> 6.4"
54
+ spec.add_development_dependency "rubocop-airbnb", "~> 6.0"
55
+ spec.add_development_dependency "simplecov", "~> 0.22"
56
+ spec.add_development_dependency "bundler-audit", "~> 0.9"
57
+ spec.add_development_dependency "pry", "~> 0.14"
58
+ spec.add_development_dependency "pry-byebug", "~> 3.10"
59
+ end