ocak 0.4.0 → 0.5.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -0
  3. data/lib/ocak/agent_generator.rb +2 -1
  4. data/lib/ocak/batch_processing.rb +102 -0
  5. data/lib/ocak/claude_runner.rb +12 -8
  6. data/lib/ocak/cli.rb +13 -0
  7. data/lib/ocak/command_runner.rb +39 -0
  8. data/lib/ocak/commands/hiz.rb +8 -7
  9. data/lib/ocak/commands/init.rb +5 -0
  10. data/lib/ocak/commands/issue/close.rb +37 -0
  11. data/lib/ocak/commands/issue/create.rb +59 -0
  12. data/lib/ocak/commands/issue/edit.rb +31 -0
  13. data/lib/ocak/commands/issue/list.rb +43 -0
  14. data/lib/ocak/commands/issue/view.rb +58 -0
  15. data/lib/ocak/commands/resume.rb +4 -3
  16. data/lib/ocak/commands/status.rb +20 -0
  17. data/lib/ocak/config.rb +4 -0
  18. data/lib/ocak/failure_reporting.rb +3 -2
  19. data/lib/ocak/git_utils.rb +18 -11
  20. data/lib/ocak/instance_builders.rb +50 -0
  21. data/lib/ocak/issue_backend.rb +31 -0
  22. data/lib/ocak/local_issue_fetcher.rb +165 -0
  23. data/lib/ocak/local_merge_manager.rb +104 -0
  24. data/lib/ocak/merge_manager.rb +31 -32
  25. data/lib/ocak/merge_orchestration.rb +8 -2
  26. data/lib/ocak/parallel_execution.rb +36 -0
  27. data/lib/ocak/pipeline_executor.rb +9 -183
  28. data/lib/ocak/pipeline_runner.rb +15 -180
  29. data/lib/ocak/planner.rb +1 -1
  30. data/lib/ocak/project_key.rb +38 -0
  31. data/lib/ocak/reready_processor.rb +11 -11
  32. data/lib/ocak/run_report.rb +5 -2
  33. data/lib/ocak/shutdown_handling.rb +67 -0
  34. data/lib/ocak/state_management.rb +104 -0
  35. data/lib/ocak/step_execution.rb +66 -0
  36. data/lib/ocak/templates/agents/auditor.md.erb +38 -9
  37. data/lib/ocak/templates/agents/implementer.md.erb +32 -8
  38. data/lib/ocak/templates/agents/merger.md.erb +12 -5
  39. data/lib/ocak/templates/agents/pipeline.md.erb +4 -0
  40. data/lib/ocak/templates/agents/reviewer.md.erb +2 -2
  41. data/lib/ocak/templates/agents/security_reviewer.md.erb +11 -0
  42. data/lib/ocak/templates/ocak.yml.erb +15 -0
  43. data/lib/ocak/verification.rb +6 -1
  44. data/lib/ocak/worktree_manager.rb +2 -0
  45. data/lib/ocak.rb +1 -1
  46. metadata +17 -1
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+
5
+ module Ocak
6
+ # State accumulation and reporting logic extracted from PipelineExecutor.
7
+ # Includers must provide @config, @logger instance variables and pipeline_state, current_branch methods.
8
+ module StateManagement
9
+ StepContext = Struct.new(:issue_number, :idx, :role, :result, :state, :logger, :chdir)
10
+
11
+ def record_step_result(ctx, mutex: nil)
12
+ sync(mutex) { accumulate_state(ctx) }
13
+ save_step_progress(ctx)
14
+ write_step_output(ctx.issue_number, ctx.idx, ctx.role, ctx.result.output)
15
+ post_step_completion_comment(ctx.issue_number, ctx.role, ctx.result)
16
+
17
+ check_step_failure(ctx) || check_cost_budget(ctx.state, ctx.logger)
18
+ end
19
+
20
+ def accumulate_state(ctx)
21
+ update_pipeline_state(ctx.role, ctx.result, ctx.state)
22
+ ctx.state[:completed_steps] << ctx.idx
23
+ ctx.state[:steps_run] += 1
24
+ ctx.state[:total_cost] += ctx.result.cost_usd.to_f
25
+ ctx.state[:step_results][ctx.role] = ctx.result
26
+ end
27
+
28
+ def sync(mutex, &)
29
+ if mutex
30
+ mutex.synchronize(&)
31
+ else
32
+ yield
33
+ end
34
+ end
35
+
36
+ def save_step_progress(ctx)
37
+ pipeline_state.save(ctx.issue_number,
38
+ completed_steps: ctx.state[:completed_steps],
39
+ worktree_path: ctx.chdir,
40
+ branch: current_branch(ctx.chdir, logger: ctx.logger))
41
+ end
42
+
43
+ def write_step_output(issue_number, idx, agent, output)
44
+ return if output.to_s.empty?
45
+ return unless issue_number.to_s.match?(/\A\d+\z/)
46
+
47
+ safe_agent = agent.to_s.gsub(/[^a-zA-Z0-9_-]/, '')
48
+ dir = File.join(@config.project_dir, '.ocak', 'logs', "issue-#{issue_number}")
49
+ FileUtils.mkdir_p(dir)
50
+ File.write(File.join(dir, "step-#{idx}-#{safe_agent}.md"), output)
51
+ rescue StandardError => e
52
+ @logger&.debug("Step output write failed: #{e.message}")
53
+ nil
54
+ end
55
+
56
+ def check_step_failure(ctx)
57
+ return nil if ctx.result.success? || !%w[implement merge].include?(ctx.role)
58
+
59
+ ctx.logger.error("#{ctx.role} failed")
60
+ { success: false, phase: ctx.role, output: ctx.result.output }
61
+ end
62
+
63
+ def check_cost_budget(state, logger)
64
+ return nil unless @config.cost_budget && state[:total_cost] > @config.cost_budget
65
+
66
+ cost = format('%.2f', state[:total_cost])
67
+ budget = format('%.2f', @config.cost_budget)
68
+ logger.error("Cost budget exceeded ($#{cost}/$#{budget})")
69
+ { success: false, phase: 'budget', output: "Cost budget exceeded: $#{cost}" }
70
+ end
71
+
72
+ def update_pipeline_state(role, result, state)
73
+ case role
74
+ when 'review', 'verify', 'security', 'audit'
75
+ state[:last_review_output] = result.output
76
+ if role == 'audit'
77
+ state[:audit_output] = result.output
78
+ state[:audit_blocked] = !result.success? || result.output.to_s.match?(/BLOCK|🔴/)
79
+ end
80
+ when 'fix'
81
+ state[:had_fixes] = true
82
+ state[:last_review_output] = nil
83
+ when 'implement'
84
+ state[:last_review_output] = nil
85
+ end
86
+ end
87
+
88
+ def log_cost_summary(total_cost, logger)
89
+ return if total_cost.zero?
90
+
91
+ budget = @config.cost_budget
92
+ budget_str = budget ? " / $#{format('%.2f', budget)} budget" : ''
93
+ logger.info("Pipeline cost: $#{format('%.4f', total_cost)}#{budget_str}")
94
+ end
95
+
96
+ def save_report(report, issue_number, success:, failed_phase: nil)
97
+ report.finish(success: success, failed_phase: failed_phase)
98
+ report.save(issue_number, project_dir: @config.project_dir)
99
+ rescue StandardError => e
100
+ @logger&.debug("Report save failed: #{e.message}")
101
+ nil
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ocak
4
+ # Individual step execution logic extracted from PipelineExecutor.
5
+ # Includers must provide @config, @skip_steps, post_step_comment, build_step_prompt methods.
6
+ module StepExecution
7
+ def run_single_step(step, idx, issue_number, state, logger:, claude:, chdir:, mutex: nil) # rubocop:disable Metrics/ParameterLists
8
+ role = step[:role].to_s
9
+ agent = step[:agent].to_s
10
+
11
+ return nil if handle_already_completed(idx, role, @skip_steps, logger)
12
+
13
+ reason = skip_reason(step, state)
14
+ if reason
15
+ logger.info("Skipping #{role} — #{reason}")
16
+ record_skipped_step(issue_number, state, idx, agent, role, reason)
17
+ return nil
18
+ end
19
+
20
+ result = execute_step(step, issue_number, state[:last_review_output], logger: logger, claude: claude,
21
+ chdir: chdir)
22
+ state[:report].record_step(index: idx, agent: agent, role: role, status: 'completed', result: result)
23
+ ctx = StateManagement::StepContext.new(issue_number, idx, role, result, state, logger, chdir)
24
+ record_step_result(ctx, mutex: mutex)
25
+ end
26
+
27
+ def handle_already_completed(idx, role, skip_steps, logger)
28
+ return false unless skip_steps.include?(idx)
29
+
30
+ logger.info("Skipping #{role} (already completed)")
31
+ true
32
+ end
33
+
34
+ def record_skipped_step(issue_number, state, idx, agent, role, reason)
35
+ post_step_comment(issue_number, "⏭️ **Skipping #{role}** — #{reason}")
36
+ state[:report].record_step(index: idx, agent: agent, role: role, status: 'skipped', skip_reason: reason)
37
+ state[:steps_skipped] += 1
38
+ end
39
+
40
+ def execute_step(step, issue_number, review_output, logger:, claude:, chdir:)
41
+ agent = step[:agent].to_s
42
+ role = step[:role].to_s
43
+ logger.info("--- Phase: #{role} (#{agent}) ---")
44
+ post_step_comment(issue_number, "🔄 **Phase: #{role}** (#{agent})")
45
+ prompt = build_step_prompt(role, issue_number, review_output)
46
+ opts = { chdir: chdir }
47
+ opts[:model] = step[:model].to_s if step[:model]
48
+ claude.run_agent(agent.tr('_', '-'), prompt, **opts)
49
+ end
50
+
51
+ def skip_reason(step, state)
52
+ condition = step[:condition]
53
+
54
+ return 'merge handled by MergeManager' if step[:role].to_s == 'merge' && @skip_merge
55
+ return 'audit found blocking issues' if step[:role].to_s == 'merge' && @config.audit_mode && state[:audit_blocked]
56
+ return 'manual review mode' if step[:role].to_s == 'merge' && @config.manual_review
57
+ return 'fast-track issue (simple complexity)' if step[:complexity] == 'full' && state[:complexity] == 'simple'
58
+ if condition == 'has_findings' && !state[:last_review_output]&.include?('🔴')
59
+ return 'no blocking findings from review'
60
+ end
61
+ return 'no fixes were made' if condition == 'had_fixes' && !state[:had_fixes]
62
+
63
+ nil
64
+ end
65
+ end
66
+ end
@@ -18,6 +18,7 @@ You audit changed files as a pre-merge gate. You are read-only. Focus ONLY on fi
18
18
  git diff main --name-only
19
19
  ```
20
20
  3. Read every changed file in full
21
+ 4. Read the corresponding test files for each changed file
21
22
 
22
23
  ## Audit Checklist
23
24
 
@@ -55,6 +56,7 @@ For each changed file, check:
55
56
  - Are there tests for the changed code?
56
57
  - Do tests cover error paths?
57
58
  - Do tests cover edge cases?
59
+ - Do tests assert specific outcomes, not just "doesn't crash"?
58
60
 
59
61
  ### Data
60
62
  - Potential N+1 queries or unbounded queries
@@ -66,22 +68,49 @@ For each changed file, check:
66
68
  ```
67
69
  ## Audit Report
68
70
 
69
- ### Critical Issues (BLOCK if found)
70
- [List any critical security or correctness issues. Use the word BLOCK for critical items.]
71
+ **Files audited**: N
71
72
 
72
- ### Warnings
73
- [Pattern violations, missing tests, minor issues]
73
+ ### Findings
74
74
 
75
- ### Observations
76
- [Non-blocking notes and suggestions]
75
+ #### 🔴 Critical — [Title]
76
+ **File**: `path/to/file:42`
77
+ **Category**: [Security | Pattern | Error Handling | Test Coverage | Data]
78
+ **Issue**: [What's wrong]
79
+ **Impact**: [What could go wrong]
80
+ **Recommendation**: [Exact fix]
77
81
 
78
- ### Files Audited
79
- - [file]: [status]
82
+ #### 🟡 Warning — [Title]
83
+ **File**: `path/to/file:78`
84
+ **Category**: [category]
85
+ **Issue**: [What's wrong]
86
+ **Recommendation**: [How to fix]
87
+
88
+ #### 🟢 Good — [Title]
89
+ [What was done well]
90
+
91
+ ### Test Coverage Summary
92
+
93
+ | Changed File | Test File | Methods Tested | Missing Coverage |
94
+ |-------------|-----------|---------------|-----------------|
95
+ | `path/to/file` | `path/to/file_test` | 4/5 | `edge_case_method` |
96
+ | `path/to/other` | ❌ None | 0/3 | All methods |
97
+
98
+ ### Verdict
99
+
100
+ **PASS** — No critical findings. Safe to merge.
101
+ or
102
+ **PASS WITH WARNINGS** — N warnings found. Review recommended but not blocking.
103
+ or
104
+ **BLOCK** — N critical findings. Must fix before merge. [List the critical items]
80
105
  ```
81
106
 
82
- Use the word **BLOCK** for any finding that should prevent merging. Only use BLOCK for:
107
+ ## Blocking Rules
108
+
109
+ The auditor blocks merge (outputs "BLOCK" verdict) ONLY for:
83
110
  - Authentication/authorization bypass
84
111
  - Injection vulnerabilities
85
112
  - Secrets exposure
86
113
  - Data corruption risks
87
114
  - Critical missing tests for dangerous operations
115
+
116
+ All other findings are warnings — reported but not blocking.
@@ -11,10 +11,11 @@ You implement GitHub issues. The issue is your single source of truth — everyt
11
11
 
12
12
  ## Before You Start
13
13
 
14
- 1. Read the issue via `gh issue view <number> --json title,body,labels`
15
- 2. Read `CLAUDE.md` for project conventions
16
- 3. Read every file listed in the issue's "Relevant files" and "Patterns to Follow" sections
17
- 4. Understand the existing patterns before writing any code
14
+ 1. Check branch state: `git log main..HEAD --oneline` and `git diff main --stat` — work may already be partially done
15
+ 2. Read the issue via `gh issue view <number> --json title,body,labels`
16
+ 3. Read `CLAUDE.md` for project conventions
17
+ 4. Read every file listed in the issue's "Relevant files" and "Patterns to Follow" sections
18
+ 5. When writing new code, find the closest existing example first (neighboring file in the same directory/namespace) and mirror its structure exactly
18
19
 
19
20
  ## Implementation Rules
20
21
 
@@ -103,6 +104,20 @@ You implement GitHub issues. The issue is your single source of truth — everyt
103
104
  - Do NOT add comments, docstrings, or type annotations to code you didn't write
104
105
  - Match the existing code style exactly — look at neighboring files
105
106
 
107
+ ### Scope Discipline (CRITICAL)
108
+
109
+ You MUST NOT modify code outside the issue's scope. This is the #1 source of pipeline regressions. Specifically:
110
+
111
+ - **Do NOT change existing method signatures** unless the issue requires it
112
+ - **Do NOT change error messages or string literals** unless the issue requires it
113
+ - **Do NOT change query logic** (e.g., operators, sort order) unless the issue requires it
114
+ - **Do NOT change data types** unless the issue requires it
115
+ - **Do NOT delete existing tests** — only add new ones or modify tests for code you changed
116
+ - **Do NOT remove security protections** (rate limiting, input validation, access checks)
117
+ - **Do NOT change configuration files** unless the issue requires it
118
+
119
+ Before each commit, run `git diff main --stat` and verify EVERY changed file is justified by the issue's acceptance criteria. If a file appears that shouldn't be there, revert it with `git checkout main -- <file>`.
120
+
106
121
  ## Testing Requirements
107
122
 
108
123
  Write tests for every acceptance criterion in the issue:
@@ -153,21 +168,30 @@ Combine related changes: a class and its tests go in one commit, not two.
153
168
  - If a lint fix is needed for already-committed code, make a separate `style` commit
154
169
  - Keep commits small and reviewable — if a commit touches 10+ files across unrelated areas, split it
155
170
 
171
+ ## When Stuck
172
+
173
+ - **Test won't pass after 2 attempts**: Re-read the full source file and the full test file. The answer is usually in existing code you haven't read yet.
174
+ - **Can't find the right pattern**: Look at the nearest neighboring file in the same directory — don't invent a new approach.
175
+ - **Unsure what a method does**: Read the method's test file, not just its source.
176
+ - **Don't iterate on a broken approach**: If your approach fails twice, switch to a different strategy.
177
+
156
178
  ## Verification Checklist
157
179
 
158
180
  After implementation, run these commands and fix ALL failures before finishing:
159
181
 
182
+ 1. **Scope check**: `git diff main --stat` — verify every file is justified by the issue. Revert any unrelated changes.
183
+ 2. **Deleted test check**: `git diff main` — verify you haven't deleted any existing test methods. If you have, restore them.
160
184
  <%- if test_command -%>
161
- 1. **Tests**: `<%= test_command %>`
185
+ 3. **Tests**: `<%= test_command %>`
162
186
  <%- end -%>
163
187
  <%- if lint_command -%>
164
- 2. **Lint**: `<%= lint_command %>`
188
+ 4. **Lint**: `<%= lint_command %>`
165
189
  <%- end -%>
166
190
  <%- if format_command -%>
167
- 3. **Format**: `<%= format_command %>`
191
+ 5. **Format**: `<%= format_command %>`
168
192
  <%- end -%>
169
193
  <%- security_commands.each_with_index do |cmd, i| -%>
170
- <%= i + 4 %>. **Security**: `<%= cmd %>`
194
+ <%= i + 6 %>. **Security**: `<%= cmd %>`
171
195
  <%- end -%>
172
196
 
173
197
  Do NOT stop until all commands pass. If a test fails, read the error, fix the code, and re-run. Maximum 5 fix attempts per command — if still failing after 5 attempts, report what's failing and why.
@@ -13,21 +13,20 @@ You handle the git workflow for completed issues.
13
13
 
14
14
  ### 1. Verify Readiness
15
15
 
16
- Before creating a PR, verify:
16
+ Tests and linters were already verified by the implementer. Do NOT re-run the full test suite — it wastes time and money.
17
17
 
18
+ Only re-run tests if you had to resolve merge conflicts or edit files:
18
19
  ```bash
19
20
  <%- if test_command -%>
20
- # Tests pass
21
+ # ONLY after resolving merge conflicts:
21
22
  <%= test_command %>
22
23
  <%- end -%>
23
-
24
24
  <%- if lint_command -%>
25
- # Linter passes
26
25
  <%= lint_command %>
27
26
  <%- end -%>
28
27
  ```
29
28
 
30
- If anything fails, STOP and report the failures. Do not create a PR with failing checks.
29
+ If anything fails after conflict resolution, STOP and report the failures. Do not create a PR with failing checks.
31
30
 
32
31
  ### 2. Create Pull Request
33
32
 
@@ -87,6 +86,13 @@ gh pr merge --merge --delete-branch
87
86
  gh issue close <number> --comment "Implemented in PR #<pr-number>"
88
87
  ```
89
88
 
89
+ ### 5. Clean Up
90
+
91
+ ```bash
92
+ git checkout main
93
+ git pull origin main
94
+ ```
95
+
90
96
  ## Output
91
97
 
92
98
  ```
@@ -94,4 +100,5 @@ gh issue close <number> --comment "Implemented in PR #<pr-number>"
94
100
  - PR: #<number> (<url>)
95
101
  - Issue: #<number> closed
96
102
  - Branch: <name> (deleted)
103
+ - Merge commit: <sha>
97
104
  ```
@@ -43,6 +43,10 @@ git diff main --stat
43
43
  git diff main
44
44
  ```
45
45
 
46
+ **Scope check**: Verify EVERY changed file is justified by the issue's acceptance criteria. If a file appears that shouldn't be there, revert it with `git checkout main -- <file>`.
47
+
48
+ **Deleted test check**: Verify you haven't deleted any existing test methods. If you have, restore them.
49
+
46
50
  For each acceptance criterion, verify:
47
51
  - Is it implemented correctly?
48
52
  - Is it tested?
@@ -85,8 +85,8 @@ Rate each finding:
85
85
  [What was done well]
86
86
 
87
87
  ### Acceptance Criteria Check
88
- - [ ] Criterion 1: implemented and tested / missing [details]
89
- - [ ] Criterion 2: ...
88
+ - [ ] Criterion 1: Implemented and tested / Missing [details]
89
+ - [ ] Criterion 2: ✅ / ❌
90
90
 
91
91
  ### Test Coverage
92
92
  - [List any untested paths or missing edge cases]
@@ -10,6 +10,10 @@ model: sonnet
10
10
 
11
11
  You perform security-focused code review. You are read-only.
12
12
 
13
+ ## Focus
14
+
15
+ You run AFTER the code reviewer. Focus on security-specific concerns that a general code reviewer would miss. Do NOT repeat general code quality findings (missing tests, naming, patterns). Your value is catching auth bypasses, injection vectors, data exposure, and business logic integrity issues that require security expertise.
16
+
13
17
  ## Setup
14
18
 
15
19
  1. Read CLAUDE.md for auth architecture and conventions
@@ -64,6 +68,13 @@ You perform security-focused code review. You are read-only.
64
68
  - [ ] Logs don't contain PII or secrets
65
69
  - [ ] No secrets in code (API keys, passwords, tokens)
66
70
 
71
+ ### Business Logic Integrity
72
+
73
+ - [ ] Domain invariants maintained (e.g., balances sum correctly, state transitions are valid)
74
+ - [ ] Calculations use appropriate precision (no floating-point for monetary/exact values)
75
+ - [ ] Race conditions handled where concurrent access is possible (database locks, transactions)
76
+ - [ ] Multi-tenant data properly scoped — no cross-tenant access paths
77
+
67
78
  ### Dependencies
68
79
 
69
80
  Run and report results of:
@@ -27,6 +27,12 @@ stack:
27
27
  <%- end -%>
28
28
  <%- end -%>
29
29
 
30
+ # Issue backend — 'github' (default) or 'local'
31
+ # Local mode stores issues as files in .ocak/issues/ (no gh CLI needed for issues).
32
+ # Auto-detected: if .ocak/issues/ contains .md files, local mode is used automatically.
33
+ # issues:
34
+ # backend: local
35
+
30
36
  # Pipeline settings
31
37
  pipeline:
32
38
  max_parallel: 5
@@ -57,29 +63,38 @@ labels:
57
63
  steps:
58
64
  - agent: implementer
59
65
  role: implement
66
+ model: sonnet
60
67
  - agent: reviewer
61
68
  role: review
69
+ model: opus
62
70
  - agent: implementer
63
71
  role: fix
64
72
  condition: has_findings
73
+ model: sonnet
65
74
  - agent: reviewer
66
75
  role: verify
67
76
  condition: had_fixes
77
+ model: opus
68
78
  - agent: security_reviewer
69
79
  role: security
80
+ model: sonnet
70
81
  complexity: full # skipped for simple issues and --fast mode
71
82
  - agent: implementer
72
83
  role: fix
73
84
  condition: has_findings
74
85
  complexity: full # skipped for simple issues
86
+ model: sonnet
75
87
  - agent: documenter
76
88
  role: document
77
89
  complexity: full # skipped for simple issues
90
+ model: sonnet
78
91
  - agent: auditor
79
92
  role: audit
80
93
  complexity: full # skipped for simple issues
94
+ model: sonnet
81
95
  - agent: merger
82
96
  role: merge
97
+ model: sonnet
83
98
 
84
99
  # Agent file paths — override to use custom agents
85
100
  agents:
@@ -52,7 +52,12 @@ module Ocak
52
52
  end
53
53
 
54
54
  def run_scoped_lint(logger, chdir:)
55
- changed_stdout, = Open3.capture3('git', 'diff', '--name-only', 'main', chdir: chdir)
55
+ changed_stdout, stderr, status = Open3.capture3('git', 'diff', '--name-only', 'main', chdir: chdir)
56
+ unless status.success?
57
+ logger&.warn("Scoped lint skipped — git diff failed: #{stderr[0..200]}")
58
+ return nil
59
+ end
60
+
56
61
  changed_files = changed_stdout.lines.map(&:strip).reject(&:empty?)
57
62
 
58
63
  extensions = lint_extensions_for(@config.language)
@@ -16,6 +16,8 @@ module Ocak
16
16
 
17
17
  def create(issue_number, setup_command: nil)
18
18
  @mutex.synchronize do
19
+ raise ArgumentError, "Invalid issue number: #{issue_number}" unless issue_number.to_s.match?(/\A\d+\z/)
20
+
19
21
  FileUtils.mkdir_p(@worktree_base)
20
22
 
21
23
  branch = "auto/issue-#{issue_number}-#{SecureRandom.hex(4)}"
data/lib/ocak.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ocak
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
 
6
6
  def self.root
7
7
  File.expand_path('..', __dir__)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ocak
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Clay Harmon
@@ -36,35 +36,51 @@ files:
36
36
  - bin/ocak
37
37
  - lib/ocak.rb
38
38
  - lib/ocak/agent_generator.rb
39
+ - lib/ocak/batch_processing.rb
39
40
  - lib/ocak/claude_runner.rb
40
41
  - lib/ocak/cli.rb
42
+ - lib/ocak/command_runner.rb
41
43
  - lib/ocak/commands/audit.rb
42
44
  - lib/ocak/commands/clean.rb
43
45
  - lib/ocak/commands/debt.rb
44
46
  - lib/ocak/commands/design.rb
45
47
  - lib/ocak/commands/hiz.rb
46
48
  - lib/ocak/commands/init.rb
49
+ - lib/ocak/commands/issue/close.rb
50
+ - lib/ocak/commands/issue/create.rb
51
+ - lib/ocak/commands/issue/edit.rb
52
+ - lib/ocak/commands/issue/list.rb
53
+ - lib/ocak/commands/issue/view.rb
47
54
  - lib/ocak/commands/resume.rb
48
55
  - lib/ocak/commands/run.rb
49
56
  - lib/ocak/commands/status.rb
50
57
  - lib/ocak/config.rb
51
58
  - lib/ocak/failure_reporting.rb
52
59
  - lib/ocak/git_utils.rb
60
+ - lib/ocak/instance_builders.rb
61
+ - lib/ocak/issue_backend.rb
53
62
  - lib/ocak/issue_fetcher.rb
63
+ - lib/ocak/local_issue_fetcher.rb
64
+ - lib/ocak/local_merge_manager.rb
54
65
  - lib/ocak/logger.rb
55
66
  - lib/ocak/merge_manager.rb
56
67
  - lib/ocak/merge_orchestration.rb
57
68
  - lib/ocak/monorepo_detector.rb
69
+ - lib/ocak/parallel_execution.rb
58
70
  - lib/ocak/pipeline_executor.rb
59
71
  - lib/ocak/pipeline_runner.rb
60
72
  - lib/ocak/pipeline_state.rb
61
73
  - lib/ocak/planner.rb
62
74
  - lib/ocak/process_registry.rb
63
75
  - lib/ocak/process_runner.rb
76
+ - lib/ocak/project_key.rb
64
77
  - lib/ocak/reready_processor.rb
65
78
  - lib/ocak/run_report.rb
79
+ - lib/ocak/shutdown_handling.rb
66
80
  - lib/ocak/stack_detector.rb
81
+ - lib/ocak/state_management.rb
67
82
  - lib/ocak/step_comments.rb
83
+ - lib/ocak/step_execution.rb
68
84
  - lib/ocak/stream_parser.rb
69
85
  - lib/ocak/templates/agents/auditor.md.erb
70
86
  - lib/ocak/templates/agents/documenter.md.erb