Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixes

- `fledge work commit` no longer double-prefixes the conventional type: `-m` messages that already start with `type:` / `type(scope):` (case-insensitive, including breaking `!` variants) are committed verbatim instead of becoming `feat: feat: ...`
- Changelog prefix matching (`fledge changelog` and `fledge release`) is now case-insensitive and understands the CorvidLabs commit style: `Add:` → Features, `Update:` → Changes, `Remove:` → Removals, `Fix:`/`Refactor:`/etc. map to their lowercase categories instead of landing in "Other"
- `fledge run --init` generic template no longer emits an unclosed quote in the commented `# lint = ...` example, which made the file unparseable when uncommented
- `fledge lanes init` hint now points at `fledge lanes list` (previously `fledge lane`, which exits with a usage error)
- `fledge run --help` pass-through example now uses a flag that works when appended to `cargo test` (`-- --release` instead of `-- --nocapture`)

## [v1.5.0] - 2026-06-07

### Other
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Already have a project? `cd` into it, fledge auto-detects the stack:
```bash
fledge run test # runs your language's test command
fledge run build # same for build
fledge run test -- --nocapture # pass extra args through to the command after --
fledge run test -- --release # pass extra args through to the command after --
fledge review # AI code review against the default branch
fledge review --with-model ollama:gpt-oss:120b-cloud,ollama:qwen3-coder:480b-cloud
# multi-model panel, parallel critiques on the same diff
Expand Down
7 changes: 4 additions & 3 deletions specs/changelog/changelog.spec.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
module: changelog
version: 4
version: 5
status: active
files:
- src/changelog.rs
Expand Down Expand Up @@ -40,14 +40,14 @@ Generate changelogs from git tags and conventional commit messages. Groups commi

1. Lists tags sorted by version (newest first) using `git tag --sort=-version:refname`
2. Groups commits between adjacent tags using conventional commit prefixes
3. Recognizes prefixes: feat, fix, docs, style, refactor, perf, test, build, ci, chore
3. Recognizes prefixes case-insensitively: feat, fix, docs, style, refactor, perf, test, build, ci, chore, plus the CorvidLabs-style add (→ Features), update (→ Changes), and remove (→ Removals). `Fix:` and `fix:` classify identically
4. Handles scoped commits like `fix(parser): message`
5. Non-conventional commits are grouped under "Other"
6. `--unreleased` shows commits since the latest tag
7. `--tag` shows a single release
8. `--json` outputs structured JSON
9. Merge commits are excluded via `--no-merges`
10. Breaking change indicators (`!` after type, `BREAKING CHANGE:` footer) are not parsed separately — commits with `!` are classified by their base type (e.g. `feat!:` → Features)
10. Breaking change indicators (`!` after type, `BREAKING CHANGE:` footer) are not parsed separately — commits with `!` (`feat!:`, `fix(core)!:`) are classified by their base type (e.g. `feat!:` → Features)

## Behavioral Examples

Expand Down Expand Up @@ -98,6 +98,7 @@ None (uses only git CLI and standard library)

| Version | Date | Changes |
|---------|------|---------|
| 5 | 2026-06-11 | Prefix matching is now case-insensitive and understands the CorvidLabs commit style: `Add:` → Features, `Update:` → Changes, `Remove:` → Removals, `Fix:`/`Refactor:`/etc. map to their lowercase categories instead of landing in Other. Breaking `!` markers (`feat!:`, `fix(core)!:`) now classify by base type, matching invariant 10 |
| 4 | 2026-04-26 | Doc sync, behavioral example updated to show the post-tier-D envelope shape (was still showing the pre-1.0 bare-array form). No code change |
| 3 | 2026-04-26 | **Breaking (tier D, 1.0):** `changelog --json` migrated from a bare top-level array to `{schema_version: 1, action: "changelog", releases: [...]}`. Same shape break tier C (#274) applied to the three pillars, this caught a remaining bare-array output. Last-chance shape break before 1.0 freezes the contract. Consumers reading `result[0]` now read `result.releases[0]` |
| 2 | 2026-04-22 | Document that breaking changes are not parsed separately; note no types filter config |
Expand Down
4 changes: 3 additions & 1 deletion specs/lanes/lanes.spec.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
module: lanes
version: 24
version: 25
status: active
files:
- src/lanes/mod.rs
Expand Down Expand Up @@ -207,6 +207,7 @@ $ fledge lanes run check
# Init default lanes
$ fledge lanes init
✅ Added default lanes to fledge.toml
Run fledge lanes list to see them.

# Search community lanes on GitHub
$ fledge lanes search
Expand Down Expand Up @@ -333,6 +334,7 @@ files continue to load against v1 semantics indefinitely.

| Version | Date | Changes |
|---------|------|---------|
| 25 | 2026-06-11 | `lanes init` follow-up hint now points at `fledge lanes list` — it previously printed `fledge lane`, which is the subcommand alias without an action and exits with a usage error |
| 24 | 2026-05-04 | Follow-up polish: (a) New `retry_delay` step option (seconds, default 1) — overrides the inter-attempt sleep, supports immediate retry with `retry_delay = 0`. (b) Windows process tree reaping via Job Object + `TerminateJobObject` — mirrors the Unix `process_group` + `killpg` fix from v23 so timeout no longer leaks grandchildren on Windows either. (c) `evaluate_when` now exposes a closure-injected `evaluate_when_with` so tests can supply a `HashMap` instead of mutating process-global env vars (edition-2024 prep) |
| 23 | 2026-05-04 | Follow-up review fixes: (a) Process group kill on Unix — `timeout` now reaps the entire process tree via `killpg(SIGKILL)`, no more orphaned grandchildren from `sh -c "a && b"`. (b) Skipped step JSON entries normalized to include `success: null, duration_ms: null, error: null` so the per-step shape is consistent across completed and skipped rows; `LANES_RUN_SCHEMA` and `LANES_DRY_RUN_SCHEMA` reverted to 1 (additive only). (c) `--from <name>` on a parallel step now emits a specific error pointing at index targeting instead of the generic "no match" |
| 22 | 2026-05-04 | Review fixes: (a) 1-second retry delay between attempts. (b) Timeout is per-attempt — each retry gets a fresh deadline. (c) Bump `LANES_RUN_SCHEMA` and `LANES_DRY_RUN_SCHEMA` from 1 → 2 for new fields (later reverted in v23). (d) Fix spec: remove private fns from Exported Functions, document process tree limitation on timeout |
Expand Down
3 changes: 2 additions & 1 deletion specs/main/main.spec.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
module: main
version: 10
version: 11
status: active
files:
- src/main.rs
Expand Down Expand Up @@ -143,6 +143,7 @@ All modules are dependencies — main dispatches to every subcommand module. See

| Version | Date | Changes |
|---------|------|---------|
| 11 | 2026-06-11 | Help-text-only change in `src/cli.rs`: the `run` pass-through args example now shows `fledge run test -- --release` (valid when appended to `cargo test`) instead of `-- --nocapture`, which cargo rejects unless preceded by its own `--` |
| 10 | 2026-04-29 | Document all public exports from `cli.rs`, `config_cmds.rs`, and `template_cmds.rs` now that these files are listed in spec frontmatter. No API changes |
| 9 | 2026-04-26 | `templates list` empty case now exits 0 in both modes. JSON mode emits `{schema_version: 1, templates: [], hint}`; non-JSON prints "No templates configured" + hint. Previously both bailed with non-zero exit, breaking agents that call `templates list --json` defensively |
| 8 | 2026-04-25 | **Breaking (tier C, #272):** `templates search --json` migrated from bare top-level array to `{schema_version: 1, results: [...]}`. Last-chance shape break before 1.0 |
Expand Down
5 changes: 3 additions & 2 deletions specs/release/release.spec.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
module: release
version: 5
version: 6
status: active
files:
- src/release/mod.rs
Expand Down Expand Up @@ -54,7 +54,7 @@ Provides a unified release workflow: version bumping across language ecosystems,
10. The plugin.toml bumper is scoped to the `[plugin]` table — a `version` key in another table (e.g. a `[[commands]]` row) is left untouched
11. When a Rust plugin carries both `Cargo.toml` and `plugin.toml`, both are bumped in the same release commit so they stay in sync
12. All git commands use explicit `current_dir` for correctness in any working directory context
13. Release has its own `classify_for_changelog()` function that mirrors `changelog::classify_commit()` — same type labels but independent implementations
13. Release has its own `classify_for_changelog()` function that mirrors `changelog::classify_commit()` — same type labels but independent implementations. Both match prefixes case-insensitively, accept breaking `!` markers, and map CorvidLabs-style `Add:` → Features, `Update:` → Changes, `Remove:` → Removals; `strip_conventional_prefix` strips the same prefixes case-insensitively

## Behavioral Examples

Expand Down Expand Up @@ -133,6 +133,7 @@ Then version.txt is bumped alongside auto-detected files

| Version | Date | Changes |
|---------|------|---------|
| 6 | 2026-06-11 | `classify_for_changelog` and `strip_conventional_prefix` are now case-insensitive, accept breaking `!` markers, and recognize the CorvidLabs commit style (`Add:` → Features, `Update:` → Changes, `Remove:` → Removals) instead of grouping those commits under Other |
| 5 | 2026-05-01 | **1.0 contract finalize, last-mile fix:** `release --dry-run --json` `files_to_bump` array now includes `[release].files` extras (e.g. `flake.nix`) so the dry-run envelope accurately previews what a real run writes. Previously, `detect_version_files` only looked at the hardcoded language candidates while `bump_version_files` (the real write path) also processed `[release].files` from `fledge.toml` — so dry-run reported `["Cargo.toml"]` while a real run also bumped `flake.nix`. Mirrored the bumper's existence + version-line-regex check in the detection path. Three new tests pin the contract. Caught in independent third-pass review pre-tag |
| 4 | 2026-04-26 | Pre-release lane no longer pollutes `--json` stdout. When `--json` is set, `run_pre_lane` calls a new silent path `crate::lanes::run_for_pre_release(name, dry_run)` that runs steps with subprocess output suppressed and emits no envelope of its own. Fixes a double-envelope regression where `release --json --pre-lane <lane>` previously emitted lane and release envelopes back-to-back on stdout. Failure path unchanged: lane bails with a plain stderr error and exit code 1 |
| 3 | 2026-04-26 | Add `--json` flag. `release X.Y.Z --dry-run --json` emits `{schema_version: 1, action: "release", dry_run: true, version, no_bump, files_to_bump, will_changelog, will_tag, will_push, tag}`. `release X.Y.Z --json` (real run) emits `{schema_version: 1, action: "release", dry_run: false, version, old_version, files_bumped, changelog_updated, commit_created, tag_created, tag, pushed}` and suppresses prose output. Helper functions (`generate_changelog_entry`, `create_release_commit`, `create_tag`, `push_release`) gained a `quiet` param threaded from `opts.json`. New integration tests `cli_release_dry_run_json_emits_envelope` and `cli_release_dry_run_json_no_bump_flag` |
Expand Down
11 changes: 6 additions & 5 deletions specs/run/run.spec.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
module: run
version: 5
version: 6
status: active
files:
- src/run.rs
Expand Down Expand Up @@ -92,17 +92,17 @@ $ fledge run test --json
{"schema_version": 1, "action": "run_task", "task": "test", "command": "cargo test", "exit_code": 0, "success": true, "stdout": "...", "stderr": "..."}

# Pass arguments through to the task command (after `--`)
$ fledge run test -- --nocapture --test-threads=1
$ fledge run test -- --release --quiet
▶️ Running task: test
# → runs: cargo test --nocapture --test-threads=1
# → runs: cargo test --release --quiet

# Pass a value through (e.g. a version)
$ fledge run set-version -- 1.2.3
# → runs: ./set-version.sh 1.2.3

# Pass-through with JSON adds an `args` array to the envelope
$ fledge run test --json -- --nocapture
{"schema_version": 1, "action": "run_task", "task": "test", "command": "cargo test", "exit_code": 0, "success": true, "stdout": "...", "stderr": "...", "args": ["--nocapture"]}
$ fledge run test --json -- --release
{"schema_version": 1, "action": "run_task", "task": "test", "command": "cargo test", "exit_code": 0, "success": true, "stdout": "...", "stderr": "...", "args": ["--release"]}

# Override project type
$ fledge run --lang node
Expand Down Expand Up @@ -130,6 +130,7 @@ Available tasks:

| Version | Date | Changes |
|---------|------|---------|
| 6 | 2026-06-11 | Fix `run --init` generic template emitting an unclosed quote in the commented `# lint = "echo 'add your linter'"` example (uncommenting it made fledge.toml unparseable). Pass-through examples now use flags valid when appended to `cargo test` (`--release`) instead of `--nocapture`, which cargo only accepts after its own `--` separator |
| 5 | 2026-06-07 | Add task argument pass-through: `fledge run <task> -- <args…>` forwards args to the target task's command (named task only, not deps). POSIX uses real positional params (`"$@"`, auto-appended unless the command references `$1`/`$@`/…), so values are never interpolated into the command string — no injection surface. `--json` gains an `args` array when args are supplied. Additive and backward-compatible: arg-less runs are byte-identical to before. New `references_positional`/`build_task_command` helpers with unit + injection-safety tests |
| 4 | 2026-04-26 | Doc sync, behavioral examples updated to show the post-tier-D envelope shapes for `run --json`, `run <task> --json`, and `run --init --json`. No code change |
| 3 | 2026-04-26 | Tier-D 1.0 envelope: all three `--json` paths now emit `{schema_version: 1, action, ...}`. `run --init --json` previously emitted prose ("✅ Created fledge.toml"), now `{action: "run_init", file, project_type, files_created}`, a real fix not just a wrapping. `run --list --json` adds `action: "run_list"` (was bare `{auto_detected, tasks}`). `run <task> --json` adds `action: "run_task"` (was bare `{task, command, ...}`). Three new integration tests guard each shape |
Expand Down
13 changes: 11 additions & 2 deletions specs/work/work.spec.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
module: work
version: 14
version: 15
status: active
files:
- src/work.rs
Expand All @@ -27,7 +27,7 @@ Provides opinionated git workflow commands for feature branch development. `fled
| `WorkAction` | Enum of subcommands: Start, Commit, Push, Status, DeprecatedPr |
| `WorkConfig` | Deserializable config with `branch_format` and `default_type` fields |
| `sanitize_branch_name` | Normalizes a string into a valid git branch name (lowercase, hyphens, no leading/trailing hyphens) |
| `build_commit_message` | Builds a conventional-commit message string from type, optional scope, and message body |
| `build_commit_message` | Builds a conventional-commit message string from type, optional scope, and message body. Messages that already carry a conventional prefix are returned verbatim |
| `build_branch_name` | (test-only) Constructs a branch name from components using WorkConfig |

### Structs & Enums
Expand Down Expand Up @@ -72,6 +72,7 @@ Provides opinionated git workflow commands for feature branch development. `fled
9. `--prefix` bypasses type validation and format template, using raw `prefix/name`
10. `--issue N` prepends the issue number to the branch name segment: `N-name`
11. `commit` infers the commit type from the current branch prefix (e.g. `feat/` → `feat`) when `--type` is not provided; falls back to `WorkConfig.default_type`
12. `commit -m` messages that already start with a conventional-commit prefix (`type:`, `type(scope):`, or the breaking `type!:` / `type(scope)!:` variants) are used verbatim — the inferred type is never prepended a second time. The type is matched case-insensitively against the valid branch types plus `style`, `perf`, `test`, `build`, `ci`, and the CorvidLabs-style `add`/`update`/`remove`
13. `commit --all` runs `git add -A` before committing
14. `commit` requires staged changes; bails if nothing is staged (separate message if working tree is clean vs unstaged)
15. `commit` without `-m` or `--ai` prompts interactively via `dialoguer::Input`; non-interactive shells must provide `-m` or `--ai`
Expand Down Expand Up @@ -151,6 +152,13 @@ $ fledge work commit --all -m "wire up search"
feat: wire up search
```

### work commit — message already conventionally prefixed (used verbatim)
```
$ fledge work commit --all -m "feat: note change"
✅ Committed e7f8a9b on leif/feat/add-search
feat: note change
```

### work commit — AI-generated message
```
$ fledge work commit --ai
Expand Down Expand Up @@ -302,6 +310,7 @@ $ fledge work status --json

| Version | Date | Changes |
|---------|------|---------|
| 15 | 2026-06-11 | `commit` no longer double-prefixes the conventional type: `-m` messages that already start with `type:` / `type(scope):` (case-insensitive, incl. breaking `!` variants and CorvidLabs-style `Add:`/`Update:`/`Remove:`) are committed verbatim instead of becoming e.g. `feat: feat: …`. New invariant 12; `has_conventional_prefix` helper added |
| 14 | 2026-06-03 | Document `WorkConfig` in the export table to satisfy strict spec-sync validation |
| 12 | 2026-05-01 | **Security:** `commit --ai --scope <s>` now validates `<s>` against `[A-Za-z0-9_-]{1,64}` before interpolating it into the LLM prompt or commit message. Scopes containing whitespace, shell metacharacters, template syntax, or anything that could be read as instructions to the model are rejected at the boundary with a clear error |
| 11 | 2026-04-30 | Pure git split: removed `pr` subcommand (moved to `fledge-plugin-github`), added `commit` and `push` subcommands with `--ai` support and conventional-commit formatting. `status` drops PR info, adds `dirty` count, bumps schema to v2. `generate_body_from_commits` removed; `build_commit_message` added |
Expand Down
Loading
Loading