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.
- checksums.yaml +4 -4
- data/.rspec +5 -0
- data/.rubocop.yml +21 -1
- data/.rules/bugs/untestable.md +27 -0
- data/.rules/changelog/2026-03/30/01.md +55 -0
- data/.rules/changelog/2026-03/30/02.md +27 -0
- data/.rules/changelog/2026-03/30/03.md +36 -0
- data/.rules/changelog/2026-03/30/04.md +48 -0
- data/.rules/changelog/2026-03/30/05.md +19 -0
- data/.rules/changelog/2026-03/30/06.md +16 -0
- data/.rules/changelog/2026-03/30/07.md +28 -0
- data/.rules/changelog/2026-03/30/08.md +29 -0
- data/.rules/changelog/2026-03/30/09.md +33 -0
- data/.rules/changelog/2026-03/30/10.md +12 -0
- data/.rules/changelog/2026-03/30/11.md +47 -0
- data/.rules/changelog/2026-03/30/12.md +18 -0
- data/.rules/changelog/2026-03/30/13.md +36 -0
- data/.rules/changelog/2026-03/30/14.md +13 -0
- data/.rules/changelog/2026-03/30/15.md +24 -0
- data/.rules/default/rubocop.md +228 -0
- data/.rules/docs/kobold_api.md +491 -0
- data/README.md +131 -29
- data/Rakefile +19 -2
- data/exe/kobold +3 -63
- data/lib/Kobold/cli/admin_commands.rb +124 -0
- data/lib/Kobold/cli/checkout_commands.rb +73 -0
- data/lib/Kobold/cli/error_handling.rb +50 -0
- data/lib/Kobold/cli/flag_parser.rb +109 -0
- data/lib/Kobold/cli/init_commands.rb +108 -0
- data/lib/Kobold/cli/lifecycle_commands.rb +116 -0
- data/lib/Kobold/cli/list_commands.rb +80 -0
- data/lib/Kobold/cli/output.rb +40 -0
- data/lib/Kobold/cli/repo_commands.rb +101 -0
- data/lib/Kobold/cli/update_commands.rb +71 -0
- data/lib/Kobold/cli.rb +120 -0
- data/lib/Kobold/config.rb +136 -0
- data/lib/Kobold/database.rb +169 -0
- data/lib/Kobold/errors.rb +59 -0
- data/lib/Kobold/fetch.rb +12 -55
- data/lib/Kobold/git_ops.rb +162 -0
- data/lib/Kobold/init.rb +16 -28
- data/lib/Kobold/invoke.rb +12 -204
- data/lib/Kobold/linker.rb +87 -0
- data/lib/Kobold/manager/checkout.rb +78 -0
- data/lib/Kobold/manager/cleaning.rb +47 -0
- data/lib/Kobold/manager/fetching.rb +58 -0
- data/lib/Kobold/manager/invoking.rb +67 -0
- data/lib/Kobold/manager/lifecycle.rb +133 -0
- data/lib/Kobold/manager/registration.rb +32 -0
- data/lib/Kobold/manager.rb +140 -0
- data/lib/Kobold/repo/worktree_helpers.rb +56 -0
- data/lib/Kobold/repo.rb +135 -0
- data/lib/Kobold/settings.rb +103 -0
- data/lib/Kobold/version.rb +2 -8
- data/lib/Kobold.rb +14 -14
- data/prototyping/.kobold +19 -24
- data/sample-project-ideas/.kobold +19 -27
- data/sig/Kobold.rbs +217 -1
- metadata +59 -59
- data/lib/Kobold/first_time_setup.rb +0 -14
- data/lib/Kobold/read_config.rb +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aac2217a763dde7fd61d408dfc0886bba7ccb4576900aefb9f58b78854c9b009
|
|
4
|
+
data.tar.gz: 82b0b9c56e06172b08fa7046d0dd7042754e92262ad06a5b9fa66ddedb3e0fd3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5d68f94b8a24f390c1a4d7bdad1e686cefa9321abac43e6e3a0dc5a3dea7dfe3d1df659f46f6d6910c466da2f05f64b524d661b64593a58b660111894fba0491
|
|
7
|
+
data.tar.gz: bdabb4d325e525b4f282f40f2f9804243f6044b693458b4250c832bd2b43d14f959f4684a25173a30c44a6c91d1d71ac11ac811cc8b39ef7a8d1ff3c24eb9178
|
data/.rspec
ADDED
data/.rubocop.yml
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
AllCops:
|
|
2
|
-
TargetRubyVersion:
|
|
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
|