Kobold 0.3.4 → 0.4.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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +5 -0
  3. data/.rubocop.yml +21 -1
  4. data/.rules/bugs/untestable.md +27 -0
  5. data/.rules/changelog/2026-03/30/01.md +55 -0
  6. data/.rules/changelog/2026-03/30/02.md +27 -0
  7. data/.rules/changelog/2026-03/30/03.md +36 -0
  8. data/.rules/changelog/2026-03/30/04.md +48 -0
  9. data/.rules/changelog/2026-03/30/05.md +19 -0
  10. data/.rules/changelog/2026-03/30/06.md +16 -0
  11. data/.rules/changelog/2026-03/30/07.md +28 -0
  12. data/.rules/changelog/2026-03/30/08.md +29 -0
  13. data/.rules/changelog/2026-03/30/09.md +33 -0
  14. data/.rules/changelog/2026-03/30/10.md +12 -0
  15. data/.rules/changelog/2026-03/30/11.md +47 -0
  16. data/.rules/changelog/2026-03/30/12.md +18 -0
  17. data/.rules/changelog/2026-03/30/13.md +36 -0
  18. data/.rules/changelog/2026-03/30/14.md +13 -0
  19. data/.rules/changelog/2026-03/30/15.md +24 -0
  20. data/.rules/default/rubocop.md +228 -0
  21. data/.rules/docs/kobold_api.md +491 -0
  22. data/README.md +131 -29
  23. data/Rakefile +19 -2
  24. data/exe/kobold +3 -63
  25. data/lib/Kobold/cli/admin_commands.rb +124 -0
  26. data/lib/Kobold/cli/checkout_commands.rb +73 -0
  27. data/lib/Kobold/cli/error_handling.rb +50 -0
  28. data/lib/Kobold/cli/flag_parser.rb +109 -0
  29. data/lib/Kobold/cli/init_commands.rb +108 -0
  30. data/lib/Kobold/cli/lifecycle_commands.rb +116 -0
  31. data/lib/Kobold/cli/list_commands.rb +80 -0
  32. data/lib/Kobold/cli/output.rb +40 -0
  33. data/lib/Kobold/cli/repo_commands.rb +101 -0
  34. data/lib/Kobold/cli/update_commands.rb +71 -0
  35. data/lib/Kobold/cli.rb +120 -0
  36. data/lib/Kobold/config.rb +136 -0
  37. data/lib/Kobold/database.rb +169 -0
  38. data/lib/Kobold/errors.rb +59 -0
  39. data/lib/Kobold/fetch.rb +12 -55
  40. data/lib/Kobold/git_ops.rb +162 -0
  41. data/lib/Kobold/init.rb +16 -28
  42. data/lib/Kobold/invoke.rb +12 -204
  43. data/lib/Kobold/linker.rb +87 -0
  44. data/lib/Kobold/manager/checkout.rb +78 -0
  45. data/lib/Kobold/manager/cleaning.rb +47 -0
  46. data/lib/Kobold/manager/fetching.rb +58 -0
  47. data/lib/Kobold/manager/invoking.rb +67 -0
  48. data/lib/Kobold/manager/lifecycle.rb +133 -0
  49. data/lib/Kobold/manager/registration.rb +32 -0
  50. data/lib/Kobold/manager.rb +140 -0
  51. data/lib/Kobold/repo/worktree_helpers.rb +56 -0
  52. data/lib/Kobold/repo.rb +135 -0
  53. data/lib/Kobold/settings.rb +103 -0
  54. data/lib/Kobold/version.rb +2 -8
  55. data/lib/Kobold.rb +14 -14
  56. data/prototyping/.kobold +19 -24
  57. data/sample-project-ideas/.kobold +19 -27
  58. data/sig/Kobold.rbs +217 -1
  59. metadata +59 -59
  60. data/lib/Kobold/first_time_setup.rb +0 -14
  61. data/lib/Kobold/read_config.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3365a9b108ba3abccb20d4040f8f10c2b3cfeafaffcb1eab97f8bb6ec31c96f2
4
- data.tar.gz: d5449335967f96c07777761a95a5de46b4a61857fd0c782b85dbfc8ab9ef7c20
3
+ metadata.gz: aac2217a763dde7fd61d408dfc0886bba7ccb4576900aefb9f58b78854c9b009
4
+ data.tar.gz: 82b0b9c56e06172b08fa7046d0dd7042754e92262ad06a5b9fa66ddedb3e0fd3
5
5
  SHA512:
6
- metadata.gz: 65f41daea3213f01c72847b0cf4e51cc86580d1c514f3d89575273fb1f0437c720dce10bbc455c59ef8fa733eb59f433c78c2102cbd88856dab15ac4068422eb
7
- data.tar.gz: 2e12df3ae02950f89743efe353855c86409073d5031af3eba41c8c1ab4e5d7dc18d85e3e3546fbcf05c799ceef49cb09b222b7877d86193d6c4d120c758f0281
6
+ metadata.gz: 5d68f94b8a24f390c1a4d7bdad1e686cefa9321abac43e6e3a0dc5a3dea7dfe3d1df659f46f6d6910c466da2f05f64b524d661b64593a58b660111894fba0491
7
+ data.tar.gz: bdabb4d325e525b4f282f40f2f9804243f6044b693458b4250c832bd2b43d14f959f4684a25173a30c44a6c91d1d71ac11ac811cc8b39ef7a8d1ff3c24eb9178
data/.rspec ADDED
@@ -0,0 +1,5 @@
1
+ --require spec_helper
2
+ --format documentation
3
+ --format documentation --out tmp/reports/rspec_results.txt
4
+ --format html --out tmp/reports/rspec_results.html
5
+ --color
data/.rubocop.yml CHANGED
@@ -1,5 +1,10 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.6
2
+ TargetRubyVersion: 3.0
3
+ SuggestExtensions: false
4
+ Exclude:
5
+ - 'references/**/*'
6
+ - 'vendor/**/*'
7
+ - 'tmp/**/*'
3
8
 
4
9
  Style/StringLiterals:
5
10
  Enabled: true
@@ -9,5 +14,20 @@ Style/StringLiteralsInInterpolation:
9
14
  Enabled: true
10
15
  EnforcedStyle: double_quotes
11
16
 
17
+ Style/Documentation:
18
+ Enabled: false
19
+
20
+ Naming/FileName:
21
+ Exclude:
22
+ - 'lib/Kobold.rb'
23
+
12
24
  Layout/LineLength:
13
25
  Max: 120
26
+
27
+ Metrics/BlockLength:
28
+ Exclude:
29
+ - 'spec/**/*'
30
+
31
+ Metrics/MethodLength:
32
+ Exclude:
33
+ - 'spec/**/*'
@@ -0,0 +1,27 @@
1
+ # Untestable Bugs
2
+
3
+ These bugs require architectural changes and cannot be reliably caught by unit tests.
4
+
5
+ ---
6
+
7
+ ## 1. TOCTOU race in registry read/write (Low)
8
+
9
+ **File:** `lib/Kobold/database.rb` — `registry`, `write_registry`
10
+
11
+ Every call to `registry` re-reads and re-parses `registry.toml` from disk. Methods like `register_repo` and `unregister_repo` do a read-modify-write cycle without any locking. If multiple processes or threads operate on the same database concurrently, one process's write can silently overwrite another's.
12
+
13
+ **Impact:** Safe for single-process CLI use. Dangerous if the Ruby API is used from multiple processes or threads (e.g., the AI orchestrator spawning parallel subagents that share a database).
14
+
15
+ **Fix:** Add file locking (`File.flock`) around registry read/write operations, or cache the registry in memory with a write-through strategy.
16
+
17
+ ---
18
+
19
+ ## 2. Non-bare clone wastes disk space (Medium)
20
+
21
+ **File:** `lib/Kobold/git_ops.rb` — `clone`, `lib/Kobold/repo.rb` — `clone`, `cloned?`
22
+
23
+ The design describes cached repos as "bare-ish clones," but `GitOps.clone` performs a normal (non-bare) clone via `Git.clone(url, path)`. This creates a full working tree checkout inside the source cache directory that is never used, wasting disk space. Additionally, if anyone modifies files in the source working tree, it could cause confusion with worktree operations.
24
+
25
+ **Impact:** Every cached repo consumes roughly double the disk space needed. For large repos (e.g., raylib), this adds up.
26
+
27
+ **Fix:** Clone with `bare: true` (or `mirror: true`) and update `Repo#cloned?` to check for bare-repo markers (e.g., `HEAD`, `objects/`) instead of `.git`. Also update `GitOps.create_worktree` and `GitOps.open` to handle bare repos correctly (use `repo.repo.path` or `--git-dir` instead of `repo.dir`).
@@ -0,0 +1,55 @@
1
+ # Phase 1 — Internal Refactor and TOML Migration
2
+
3
+ ## Dependencies
4
+
5
+ - Removed `tty-config` and `inifile` gems
6
+ - Added `toml-rb ~> 3.0`
7
+ - Relaxed `git` to `~> 2.3`, `tty-option` to `~> 0.3`, `tty-progressbar` to `~> 0.18`
8
+ - Relaxed `rubocop` to `~> 1.0`
9
+ - Bumped `required_ruby_version` to `>= 3.0`
10
+ - Deleted stale `Gemfile.lock`
11
+ - Added `description` to gemspec
12
+
13
+ ## Version
14
+
15
+ - `VERSION`: `0.3.4` -> `0.4.0`
16
+ - `FORMAT_VERSION`: `0.3.0` -> `0.4.0`
17
+
18
+ ## New Classes/Modules
19
+
20
+ - `Kobold::Errors` — custom exception hierarchy
21
+ - `Kobold::GitOps` — shared Git operations (clone, open, worktree, fetch, resolve_ref)
22
+ - `Kobold::Config` — TOML .kobold file reader/writer/validator/generator
23
+ - `Kobold::Database` — named cache database with registry.toml
24
+ - `Kobold::Repo` — cached repo with worktree/branch/commit/label management
25
+ - `Kobold::Linker` — symlink creation, validation, cleanup
26
+
27
+ ## Rewritten
28
+
29
+ - `lib/Kobold.rb` — clean module entry point
30
+ - `lib/Kobold/invoke.rb` — uses new class structure
31
+ - `lib/Kobold/fetch.rb` — uses Database and Repo
32
+ - `lib/Kobold/init.rb` — generates TOML format
33
+ - `exe/kobold` — fixed bugs, added --database flag, error handling
34
+
35
+ ## Deleted
36
+
37
+ - `lib/Kobold/read_config.rb` (replaced by Config.read)
38
+ - `lib/Kobold/first_time_setup.rb` (replaced by Database#setup)
39
+
40
+ ## Config Format
41
+
42
+ - `prototyping/.kobold` — converted INI to TOML v0.4.0
43
+ - `sample-project-ideas/.kobold` — converted INI v0.1.0 to TOML v0.4.0
44
+
45
+ ## Bug Fixes
46
+
47
+ - Fixed `value['sha']` vs `value['commit']` inconsistency
48
+ - Fixed default command dispatch (`cmd.params == "invoke"`)
49
+ - Removed call to non-existent `Kobold.list`
50
+ - Removed `worktree_sha ||= :scoped` hack
51
+ - Stale symlinks now get replaced via Linker
52
+
53
+ ## Types
54
+
55
+ - Updated `sig/Kobold.rbs` with full signatures for all new classes
@@ -0,0 +1,27 @@
1
+ # Changelog — 2026-03-30 — 02
2
+
3
+ ## Phase 2: Ruby API (High-Level Interface)
4
+
5
+ ### Added
6
+ - **`lib/Kobold/manager.rb`** — New `Kobold::Manager` class providing the high-level Ruby API entry point.
7
+ - `register` / `unregister` — repo registration
8
+ - `fetch` / `fetch_all` — single-repo and config-wide fetching
9
+ - `checkout` — worktree creation with optional symlink
10
+ - `create_branch` — branch creation with worktree and optional symlink
11
+ - `remove_worktree` — worktree and symlink removal
12
+ - `invoke` — full `.kobold` config processing
13
+ - `init` — `.kobold` file creation
14
+ - `list_repos` / `list_worktrees` / `list_branches` — listing operations
15
+ - `generate_config` — programmatic `.kobold` file generation
16
+ - `clean` — stale worktree cleanup
17
+ - All methods return structured Hashes/Arrays instead of printing to stdout.
18
+
19
+ ### Changed
20
+ - **`lib/Kobold.rb`** — Added `require_relative "Kobold/manager"`.
21
+ - **`lib/Kobold/invoke.rb`** — Refactored to thin wrapper delegating to `Manager#invoke`.
22
+ - **`lib/Kobold/fetch.rb`** — Refactored to thin wrapper delegating to `Manager#fetch_all`.
23
+ - **`lib/Kobold/init.rb`** — Refactored to thin wrapper delegating to `Manager#init`.
24
+ - **`sig/Kobold.rbs`** — Updated with full `Manager` type signatures and corrected return types for module-level methods.
25
+
26
+ ### Moved
27
+ - **`.rules/plan/plan.md`** → **`.rules/default/plan.md`** — Plan file relocated per user request. Phase 1 and Phase 2 marked as complete.
@@ -0,0 +1,36 @@
1
+ # Phase 3 — CLI Overhaul
2
+
3
+ ## New Files
4
+
5
+ - `lib/Kobold/cli.rb` — New `Kobold::CLI` class replacing the old `Kobold::Command`. Every subcommand is a thin wrapper around `Kobold::Manager`. Includes custom flag parser, colored output helpers, and structured error handling with human-readable hints.
6
+
7
+ ## Modified Files
8
+
9
+ - `exe/kobold` — Replaced the old monolithic `Command` class (using `tty-option`) with a 3-line entry point delegating to `Kobold::CLI`.
10
+ - `lib/Kobold.rb` — Added `require_relative "Kobold/cli"`.
11
+ - `Kobold.gemspec` — Removed `tty-option` dependency (no longer used).
12
+
13
+ ## CLI Commands Implemented
14
+
15
+ - `kobold init` — Create `.kobold` file; supports non-interactive mode with `--repo`, `--source`, `--branch`, `--commit`, `--label`, `--name`, `--dep-dir`.
16
+ - `kobold invoke` — Process `.kobold` and set up all dependencies.
17
+ - `kobold fetch [REPO]` — Fetch single repo or all from `.kobold`.
18
+ - `kobold register REPO --source URL` — Register a repo in the database.
19
+ - `kobold unregister REPO` — Remove a repo from the registry.
20
+ - `kobold checkout REPO` — Create worktree with `--branch`, `--commit`, `--label`, `--dir`.
21
+ - `kobold branch REPO --name NAME` — Create branch with `--from`, `--dir`.
22
+ - `kobold list repos|worktrees|branches [REPO]` — List database contents.
23
+ - `kobold clean` — Remove stale worktrees.
24
+ - `kobold version` — Print version info.
25
+
26
+ ## Global Features
27
+
28
+ - `--database NAME` flag on all commands (defaults to `default`).
29
+ - Per-command `-h`/`--help` support.
30
+ - Colored terminal output (green checkmarks, blue info, yellow warnings, red errors).
31
+ - Human-readable error messages with suggested-fix hints.
32
+ - Proper exit codes: 0 (success), 1 (error), 2 (usage).
33
+
34
+ ## Removed Dependencies
35
+
36
+ - `tty-option` — replaced by custom lightweight flag parser for better subcommand support.
@@ -0,0 +1,48 @@
1
+ # Changelog — 2026-03-30 (04)
2
+
3
+ ## Phase 4: Cleanup, Remove, and Lifecycle
4
+
5
+ ### New Features
6
+
7
+ - **`add` command / `Manager#add`** — Add a dependency to an existing `.kobold` file. Registers and clones the repo if not already cached.
8
+ - **`remove` command / `Manager#remove`** — Remove a dependency from `.kobold`. `--cleanup` flag optionally removes the associated worktree and symlink.
9
+ - **`update` command / `Manager#update`** — Fetch latest and update the commit SHA in `.kobold` to the latest on the specified branch. Supports updating a single dependency or all at once.
10
+ - **`db` command** — Database lifecycle management: `db create`, `db delete`, `db list`.
11
+ - **`config` command** — View or change global settings: `config get-source`, `config set-source`.
12
+ - **`Kobold::Settings` module** — Global user-level settings stored at `~/.local/share/Kobold/config.toml`. Manages default source URL (defaults to `https://github.com`).
13
+ - **Default source URL** — `--source` is now optional for `register`, `add`, and `init` commands; defaults to the configured source (GitHub by default).
14
+ - **Enhanced `clean` command** — Now supports `--purge` flag to remove repos not referenced by any `.kobold` file.
15
+
16
+ ### New Error Classes
17
+
18
+ - `Kobold::Errors::DependencyNotFound`
19
+ - `Kobold::Errors::DatabaseExists`
20
+ - `Kobold::Errors::LinkError`
21
+
22
+ ### Config Mutations
23
+
24
+ - `Config#add_dependency`, `#remove_dependency`, `#dependency?`, `#dependency`, `#update_dependency` for in-memory `.kobold` manipulation.
25
+
26
+ ### Database Lifecycle
27
+
28
+ - `Database.list_databases`, `Database.exists?`, `Database#exists?`, `Database#delete` for managing named databases.
29
+
30
+ ### Repo Enhancements
31
+
32
+ - `Repo#resolve_branch_head` — resolve branch to latest commit SHA.
33
+ - `Repo#purge` — delete entire repo from cache.
34
+ - `Repo#worktree_path_for` — public worktree path resolver.
35
+
36
+ ### GitOps
37
+
38
+ - `GitOps.resolve_branch_head` — resolve branch HEAD checking remote then local branches.
39
+
40
+ ### CLI
41
+
42
+ - Boolean flag support in `parse_flags` for `--cleanup` and `--purge`.
43
+ - `short_sha` helper for displaying truncated commit SHAs.
44
+ - Updated help text for all commands.
45
+
46
+ ### README
47
+
48
+ - Full rewrite: project description, all CLI commands with examples, build/install instructions.
@@ -0,0 +1,19 @@
1
+ # Changelog — 2026-03-30 #05
2
+
3
+ ## Bug Fixes (High Severity) in `lib/Kobold/repo.rb`
4
+
5
+ ### `create_worktree` — branch HEAD now resolved to full SHA
6
+ - When `branch` is provided without `commit`, the branch HEAD is resolved via `GitOps.resolve_branch_head` so `resolved_sha` is always a real SHA. Previously, the branch name string was used as the SHA, producing incorrect worktree paths for `label + branch` combinations.
7
+ - When no arguments are given, the default branch is detected and used as the `branch` parameter, ensuring the worktree lands in `worktrees/branches/<name>/` instead of falling back to `source_path`.
8
+
9
+ ### `resolve_worktree_path` — removed `source_path` fallback
10
+ - The `else` branch now raises `Errors::GitError` instead of returning `source_path`, preventing accidental worktree creation on (or symlinking to) the shared source cache.
11
+
12
+ ### `worktree_path_for` — commit now resolved to full SHA
13
+ - Resolves the commit via `GitOps.resolve_ref` when the repo is cloned, so the returned path matches what `create_worktree` produces. Previously, the raw short SHA was used, causing path mismatches that broke `Manager#remove` cleanup.
14
+
15
+ ## Documentation
16
+
17
+ ### Filed medium and low severity bugs
18
+ - Created `.rules/bugs/medium.md` (3 bugs: Linker crash on non-symlink, relative symlink comparison, non-bare clone waste).
19
+ - Created `.rules/bugs/low.md` (4 bugs: dead `@registry` variable, TOCTOU races, mixed key types, silent `--database` ignore).
@@ -0,0 +1,16 @@
1
+ # Fix worktree creation "already checked out" error
2
+
3
+ ## Changed
4
+
5
+ - **`lib/Kobold/git_ops.rb`**
6
+ - `create_worktree`: Replaced `repo.worktree(path, ref).add` (from the `git` gem) with a direct `Open3.capture3` call using `git worktree add --detach`. The ref is resolved to a full SHA before creating the worktree, which avoids Git's "branch is already checked out" error when the branch (e.g., `master`) is already checked out in the source clone.
7
+ - `remove_worktree`: Replaced `repo.worktree(path).remove` with `Open3.capture3` using `git worktree remove --force` for consistency with the new `create_worktree` approach.
8
+ - Added `require "open3"` to support the new implementation.
9
+
10
+ ## Bug
11
+
12
+ When running `kobold invoke` on a `.kobold` file with a branch-only dependency (e.g., `branch = "master"`), the `git` gem's worktree API would fail with:
13
+ ```
14
+ fatal: 'master' is already used by worktree at '.../source'
15
+ ```
16
+ This happened because the source clone already has the default branch checked out, and Git refuses to create a second worktree for the same branch. Using `--detach` with a resolved SHA bypasses this restriction.
@@ -0,0 +1,28 @@
1
+ # Changelog — 2026-03-30 #07
2
+
3
+ ## Upgrade git gem from 2.3 to 4.3.1
4
+
5
+ ### Dependencies
6
+
7
+ - **`git`** — Updated from `~> 2.3` (v2.3.3) to `~> 4.3` (v4.3.1)
8
+ - **`tty-progressbar`** — Removed (no longer used)
9
+ - **`process_executer`** — Transitive dependency updated from v1.3 to v4.0.2 (via git gem)
10
+
11
+ ### API Compatibility Fixes (`lib/Kobold/git_ops.rb`)
12
+
13
+ - `Git::FailedError` → `Git::Error` in all rescue clauses (v4.x error hierarchy change)
14
+ - `repo.dir.path` → `repo.dir.to_s` in `create_worktree` and `remove_worktree` (`.path` deprecated in v4, removed in v5)
15
+ - Removed threaded TTY::ProgressBar from `clone` and `fetch` — `process_executer` v4.x conflicts with threading around subprocess management. Replaced with simple `puts` messages.
16
+
17
+ ### API Compatibility Fixes (`lib/Kobold/repo.rb`)
18
+
19
+ - `source_repo.branch.name` → `source_repo.current_branch` in `create_worktree` default branch detection
20
+ - `source_repo.lib.branch_new(name, start_point)` → `Open3.capture3("git", "-C", repo_dir, "branch", name, start_point)` in `create_branch` — v4.x `branch_new` only accepts one argument
21
+ - `rescue Git::FailedError` → `rescue Errors::GitError` with smarter "already exists" check in `create_branch`
22
+ - Added `require "open3"`
23
+
24
+ ### Gemspec
25
+
26
+ - `git` dependency: `~> 2.3` → `~> 4.3`
27
+ - Removed `tty-progressbar` dependency
28
+ - Added `spec.homepage`
@@ -0,0 +1,29 @@
1
+ # Changelog — 2026-03-30 (08)
2
+
3
+ ## Added: RSpec Integration Test Suite
4
+
5
+ ### New files
6
+ - `.rspec` — RSpec configuration with documentation format and report outputs to `tmp/reports/`
7
+ - `spec/spec_helper.rb` — Test helper with temp directory isolation, constant swapping for `KOBOLD_DIR`, and `GitTestHelpers` module for creating real Git repos on disk
8
+ - `spec/errors_spec.rb` — Tests for all error classes in `Kobold::Errors`
9
+ - `spec/config_spec.rb` — Tests for `Kobold::Config` (validation, read/write round-trip, generate, add/remove/update dependencies)
10
+ - `spec/database_spec.rb` — Tests for `Kobold::Database` (listing, creation, deletion, repo registration, slugify)
11
+ - `spec/settings_spec.rb` — Tests for `Kobold::Settings` (defaults, get/set, read/write, default source)
12
+ - `spec/linker_spec.rb` — Tests for `Kobold::Linker` (symlink creation, stale replacement, unlink, relink, validity)
13
+ - `spec/git_ops_spec.rb` — Tests for `Kobold::GitOps` (clone, open, resolve_ref, worktree create/remove, fetch, resolve_branch_head)
14
+ - `spec/repo_spec.rb` — Tests for `Kobold::Repo` (clone, fetch, worktree creation by branch/commit/label, removal, branch creation, listing, purge)
15
+ - `spec/manager_spec.rb` — Integration tests for `Kobold::Manager` (register, fetch, checkout, create_branch, remove_worktree, invoke, init, list, generate_config, add, remove, update, clean, database lifecycle)
16
+
17
+ ### Modified files
18
+ - `Gemfile` — Added `rspec ~> 3.13` dependency
19
+ - `Gemfile.lock` — Deleted (regenerated by `bundle install` with new dependencies)
20
+ - `Rakefile` — Added `RSpec::Core::RakeTask`, report directory setup, dual-format RuboCop output to `tmp/reports/rubocop_results.html`
21
+ - `.rubocop.yml` — Added `Exclude` for `references/`, `vendor/`, `tmp/` directories to prevent loading `references/ruby-git/.rubocop.yml` which references a missing shared gem
22
+ - `.gitignore` — Added `*.gem` to prevent built gem files from being tracked
23
+ - `Kobold.gemspec` — Added `.gem` file exclusion in `spec.files` to fix "contains itself" validation error
24
+
25
+ ### Summary
26
+ - 126 integration tests covering all modules
27
+ - Tests use real Git repos created in temp directories (no mocking, no network)
28
+ - Every test runs in an isolated temp directory with `KOBOLD_DIR` redirected
29
+ - Reports written to `tmp/reports/` (gitignored)
@@ -0,0 +1,33 @@
1
+ # Changelog — 2026-03-30 (09)
2
+
3
+ ## Fix RuboCop offenses and add Ruby style rules
4
+
5
+ ### `.rubocop.yml`
6
+ - Updated `TargetRubyVersion` from `2.6` to `3.0` to match gemspec `required_ruby_version` (fixes `Gemspec/RequiredRubyVersion`).
7
+ - Disabled `Style/Documentation` globally.
8
+ - Excluded `lib/Kobold.rb` from `Naming/FileName`.
9
+ - Excluded `spec/**/*` from all `Metrics` cops.
10
+
11
+ ### `lib/Kobold/settings.rb`
12
+ - Renamed `set_default_source` to `default_source=` (fixes `Naming/AccessorMethodName`).
13
+
14
+ ### `lib/Kobold/cli.rb`
15
+ - Updated call site from `Settings.set_default_source(...)` to `Settings.default_source = ...`.
16
+ - Split two lines exceeding 120-char limit in `cmd_update` (fixes `Layout/LineLength`).
17
+ - Removed redundant empty `else` clause in `parse_flags` (fixes `Style/EmptyElse`).
18
+ - Reverted autocorrect bug: restored `$stderr.puts` in `warn`, `error`, `hint` methods with `rubocop:disable Style/StderrPuts` to prevent infinite recursion.
19
+
20
+ ### `spec/settings_spec.rb`
21
+ - Updated test references from `set_default_source` to `default_source=`.
22
+
23
+ ### `spec/spec_helper.rb`
24
+ - Reverted autocorrect bug: restored `stub_const` approach instead of manual `remove_const`/`const_set`.
25
+
26
+ ### `spec/config_spec.rb`
27
+ - Added blank line after `require "English"`.
28
+
29
+ ### `sig/Kobold.rbs`
30
+ - Updated RBS signature from `set_default_source` to `default_source=`.
31
+
32
+ ### `.rules/default/rubocop.md` (new)
33
+ - Created agent rules file documenting all RuboCop Metrics constraints (MethodLength, AbcSize, CyclomaticComplexity, PerceivedComplexity, ClassLength, BlockNesting, ParameterLists) with examples and mitigation strategies.
@@ -0,0 +1,12 @@
1
+ # Changelog — 2026-03-30 (10)
2
+
3
+ ## Fix spec_helper const swap and RuboCop spec exclusions
4
+
5
+ ### `spec/spec_helper.rb`
6
+ - Replaced `stub_const` (not available in `around` hooks) with manual `remove_const`/`const_set` approach using `ensure` block for safe constant restoration.
7
+
8
+ ### `.rubocop.yml`
9
+ - Fixed Metrics exclusion for spec files: department-level `Metrics:` exclude doesn't propagate to individual cops. Replaced with explicit `Metrics/BlockLength` and `Metrics/MethodLength` exclusions for `spec/**/*`.
10
+
11
+ ### `.rules/default/rubocop.md` (new in 09)
12
+ - Created agent rules file documenting all RuboCop Metrics constraints with examples and mitigation strategies.
@@ -0,0 +1,47 @@
1
+ # Changelog — 2026-03-30 #11
2
+
3
+ ## Fix all 94 RuboCop offenses across 4 source files
4
+
5
+ ### Summary
6
+ Large refactoring pass to eliminate all 94 RuboCop convention violations
7
+ (Metrics/ClassLength, MethodLength, AbcSize, CyclomaticComplexity,
8
+ PerceivedComplexity, ParameterLists, BlockNesting, Layout, Naming, Style).
9
+
10
+ All 126 rspec tests continue to pass with zero failures.
11
+
12
+ ### Files changed
13
+
14
+ **`lib/Kobold/cli.rb`** — Reduced from 774-line monolithic class to a thin
15
+ ~100-line shell. Dispatch converted from case/when to hash table.
16
+
17
+ **New CLI modules extracted:**
18
+ - `lib/Kobold/cli/output.rb` — success/info/warn/error/hint helpers
19
+ - `lib/Kobold/cli/flag_parser.rb` — global and subcommand flag parsing
20
+ - `lib/Kobold/cli/error_handling.rb` — error dispatch table and reporters
21
+ - `lib/Kobold/cli/init_commands.rb` — init, invoke commands
22
+ - `lib/Kobold/cli/repo_commands.rb` — fetch, register, unregister commands
23
+ - `lib/Kobold/cli/checkout_commands.rb` — checkout, branch commands
24
+ - `lib/Kobold/cli/list_commands.rb` — list repos/worktrees/branches
25
+ - `lib/Kobold/cli/lifecycle_commands.rb` — clean, add, remove commands
26
+ - `lib/Kobold/cli/update_commands.rb` — update command
27
+ - `lib/Kobold/cli/admin_commands.rb` — db, config, version commands
28
+
29
+ **`lib/Kobold/manager.rb`** — Reduced from 313-line class to ~100-line shell.
30
+
31
+ **New Manager modules extracted:**
32
+ - `lib/Kobold/manager/registration.rb` — register/unregister
33
+ - `lib/Kobold/manager/fetching.rb` — fetch/fetch_all
34
+ - `lib/Kobold/manager/checkout.rb` — checkout, create_branch, remove_worktree
35
+ - `lib/Kobold/manager/invoking.rb` — invoke (process .kobold files)
36
+ - `lib/Kobold/manager/lifecycle.rb` — add, remove, update, update_all
37
+ - `lib/Kobold/manager/cleaning.rb` — clean, purge, referenced slug collection
38
+
39
+ **`lib/Kobold/config.rb`** — Split validate into 4 private class methods,
40
+ split generate into 2 helpers. Compacted instance methods.
41
+
42
+ **`lib/Kobold/repo.rb`** — Extracted worktree path resolution into
43
+ `lib/Kobold/repo/worktree_helpers.rb` module.
44
+
45
+ ### Offense count
46
+ - Before: 94 offenses across 4 files
47
+ - After: 0 offenses across 45 inspected files
@@ -0,0 +1,18 @@
1
+ # Changelog — 2026-03-30 #12
2
+
3
+ ## Bug audit and regression test suite
4
+
5
+ ### Added
6
+ - `spec/bug_regression_spec.rb` — 10 regression tests covering 7 identified bugs:
7
+ - **Bug 1 (High):** `clean_stale_worktrees` never detects stale worktrees because `list_worktrees` uses `Dir.glob` which only returns existing directories.
8
+ - **Bug 2 (Medium):** `check_nested_symlink` uses `slug.split("-").last` to derive the symlink name, but the actual symlink is named after the worktree basename (e.g., `"main"`), so cleanup never finds nested symlinks.
9
+ - **Bug 3 (Medium):** `Linker.link` raises raw `Errno::EEXIST` when a regular file or directory exists at the destination.
10
+ - **Bug 4 (Low):** `Database#setup` references unset `@registry` instance variable (dead code, guarded by `unless File.file?`).
11
+ - **Bug 5 (Low):** Mixed symbol/string keys in `CLI#build_init_dep` dep hash.
12
+ - **Bug 6 (Low):** `--database` flag after the command name is silently ignored.
13
+ - **Bug 7 (Medium):** `Linker.link` relative symlink target comparison resolves against `Dir.pwd` instead of the symlink's parent directory, causing false-negative staleness checks.
14
+ - `.rules/bugs/untestable.md` — documents 2 architectural bugs not coverable by unit tests (TOCTOU registry race, non-bare clone disk waste).
15
+
16
+ ### Removed
17
+ - `.rules/bugs/low.md` — replaced by regression tests and `untestable.md`.
18
+ - `.rules/bugs/medium.md` — replaced by regression tests and `untestable.md`.
@@ -0,0 +1,36 @@
1
+ # Fix 7 bug regressions and RuboCop offenses
2
+
3
+ ## Bug fixes
4
+
5
+ ### Bug 1: Stale worktrees not detected by clean
6
+ - `Repo#list_worktrees` now queries `git worktree list --porcelain` in addition to disk glob, so worktrees whose directories were manually deleted are still discovered and pruned.
7
+
8
+ ### Bug 2: Nested symlink cleanup fails for dir ending with /
9
+ - `link_dep_dir` in `Invoking` now preserves the trailing `/` after `File.expand_path`, so symlinks are correctly created inside the directory.
10
+ - `check_nested_symlink` in `Lifecycle` now scans `Dir.children` for actual symlinks instead of guessing the name from `slug.split("-").last`.
11
+
12
+ ### Bug 3: Linker.link raises Errno::EEXIST on regular files
13
+ - `Linker.link` now detects existing regular files and directories at the destination and removes them with `FileUtils.rm_rf` before creating the symlink.
14
+
15
+ ### Bug 6: --database flag ignored after command
16
+ - Added `handle_post_command_arg` in `FlagParser` to recognize `--database` even when placed after the command (e.g. `kobold init --database mydb`).
17
+
18
+ ### Bug 7: Relative symlink false negative in staleness check
19
+ - `Linker#existing_symlink_matches?` now resolves relative symlink targets using `File.expand_path(existing, File.dirname(symlink_path))` instead of `File.expand_path(existing)` which incorrectly resolved relative to `Dir.pwd`.
20
+
21
+ ## RuboCop fixes
22
+
23
+ - Fixed `Metrics/ModuleLength` in `Lifecycle` module (was 103/100) by condensing methods and removing unused `slug` parameter.
24
+ - Fixed `Layout/ArgumentAlignment` (7 offenses) in spec file by using parenthesized `to(matcher, message)` form.
25
+ - Fixed `Style/BlockDelimiters` (2 offenses) by converting multi-line `expect { }` to `expect do...end`.
26
+ - Fixed `Lint/UselessAssignment` by removing unused `default_db_path` variable.
27
+ - Fixed Ruby parsing ambiguity where `to be true, "msg"` was parsed as `be(true, "msg")` causing ArgumentError.
28
+
29
+ ## Files changed
30
+
31
+ - `lib/Kobold/repo.rb`
32
+ - `lib/Kobold/linker.rb`
33
+ - `lib/Kobold/manager/lifecycle.rb`
34
+ - `lib/Kobold/manager/invoking.rb`
35
+ - `lib/Kobold/cli/flag_parser.rb`
36
+ - `spec/bug_regression_spec.rb`
@@ -0,0 +1,13 @@
1
+ # Changelog — 2026-03-30 #14
2
+
3
+ ## Removed
4
+ - Deleted `.rules/default/plan.md` from the rules directory.
5
+
6
+ ## Changed
7
+ - `Manager#add` now defaults the dependency name to the repo name (last segment of repo identifier) when no name is provided. E.g. `raysan5/raylib` defaults to `raylib`.
8
+ - `Invoking#link_dep_dir` now uses the dependency name as the symlink basename when `dir` ends with `/`, instead of the worktree directory name (branch). E.g. `external/raylib` instead of `external/master`.
9
+
10
+ ## Updated Tests
11
+ - Added test in `manager_spec.rb` verifying `Manager#add` defaults name to repo name.
12
+ - Added assertion in invoke test confirming symlink basename matches dependency name.
13
+ - Updated Bug 2 regression tests in `bug_regression_spec.rb` to expect dependency name as symlink basename.
@@ -0,0 +1,24 @@
1
+ # Bug audit and fixes
2
+
3
+ ## Removed stale worktree cleaning capability
4
+ - Removed `clean_stale_worktrees`, `clean_repo_worktrees`, and `remove_stale_worktree` from `manager/cleaning.rb`
5
+ - `Manager#clean` now only handles purging unreferenced repos via `--config`
6
+ - Updated `cli/lifecycle_commands.rb`: removed `--purge` flag, `--config` is now required
7
+ - Removed Bug 1 regression test for stale worktree cleaning
8
+ - Updated `manager_spec.rb` `#clean` test to match new interface
9
+
10
+ ## Fixed `Database#setup` dead `@registry` reference
11
+ - `setup` previously referenced `@registry || {}` but `@registry` was never assigned
12
+ - Changed to just `{}` in `database.rb`
13
+
14
+ ## Fixed mixed symbol/string keys in `build_init_dep`
15
+ - Changed `{ name: dep_name, ... }` to `{ "name" => dep_name, ... }` in `cli/init_commands.rb`
16
+ - Added backward-compat test for symbol `:name` key in `bug_regression_spec.rb`
17
+
18
+ ## Fixed `Settings.read` shallow merge bug
19
+ - `defaults.merge(data)` lost nested default keys when user config overrode a parent hash
20
+ - Added `deep_merge` private helper that recursively merges nested hashes
21
+ - Added 2 tests in `settings_spec.rb` proving the fix
22
+
23
+ ## Updated regression test comments
24
+ - Bug 4 and Bug 5 comments updated to reflect fixes applied