Skip to content

release: prepare v1.0.0 - #449

Merged
erishforG merged 21 commits into
release/1.0from
release/v1.0-final
Sep 19, 2026
Merged

erishforG merged 21 commits into
release/1.0from
release/v1.0-final

Conversation

@erishforG

Copy link
Copy Markdown
Owner

Summary

  • merge the final develop line into release/1.0
  • preserve MCP v1 features and late v0.x commands
  • bump package version and align README, changelog, and LLM metadata

Conflict resolution

Combined both sides for AI PR descriptions, template substitution, ship cleanup control, smartlog overlay tests, checkpoint, crash-report, triage, and self-update.

Validation

  • cargo fmt --all -- --check
  • cargo clippy --all-targets -- -D warnings
  • cargo test --locked --all-targets (419 tests)
  • cargo publish --dry-run --locked

Release plan

After this lands, merge release/1.0 into develop, then develop into main. The main push triggers v1.0.0 tag, crates.io publication, GitHub Release, and binary builds.

erishforG and others added 21 commits August 31, 2026 11:30
…ry-pick) · Refs #414 (#415)

* feat(health): Phase 3 — detect in-progress git ops (rebase/merge/cherry-pick) · Refs #414

Adds three new read-only health indicators to `parsec health`:

| Indicator              | Detection                                  |
|------------------------|--------------------------------------------|
| rebase_in_progress     | .git/rebase-merge/ or .git/rebase-apply/  |
| merge_in_progress      | .git/MERGE_HEAD                            |
| cherry_pick_in_progress| .git/CHERRY_PICK_HEAD                      |

These catch the common "I started a rebase in worktree A and forgot about it"
pattern that index.lock alone cannot detect (lock only exists while git runs).

Works for both main worktrees (.git/ dir) and linked worktrees (.git file
containing a gitdir: pointer). Detection failures soft-fail to false.

Changes:
- src/output/mod.rs: 3 new bool fields on HealthRecord
- src/cli/commands/health.rs: resolve_git_dir() helper + detection logic
- src/output/human.rs: ⚠ red tags + icon rollup for in-progress ops
- src/output/json.rs: 3 new bool fields + all_healthy rollup update
- 7 unit tests covering main/linked worktree layout + per-state detection

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(workspace): clippy::for_kv_map — use values_mut() in pr_map loop

Pre-existing lint (clippy::for_kv_map) that started failing on CI ubuntu runner.
workspace.rs:318 iterated over (key, value) pairs but only used values;
replacing with .values_mut() satisfies the lint with no behaviour change.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
… (#423)

Add `--no-cleanup` flag to `parsec ship` so users working incrementally
(multiple commits / ships on the same ticket) can push + create/update the PR
without losing their worktree.

Also fix a latent gap: `ship_cleanup()` existed in WorktreeManager but was
never called from the `ship` command handler. The combined `manager.ship()`
(dead_code) already called it, but the refactored command path (ship_push →
PR creation) forgot Phase 3. Now wired correctly with the escape hatch.

## Changes
- `src/cli/mod.rs`: add `no_cleanup: bool` to `Command::Ship`, pass through
  to handler and dry-run message
- `src/cli/commands/ship.rs`: add `no_cleanup` param; Phase 3 block calls
  `manager.ship_cleanup(ticket)` when `!no_cleanup` (still respects
  `config.ship.auto_cleanup`)
- `src/cli/commands/stack.rs`: forward `no_cleanup = false` in stack-ship
  call to satisfy updated signature (stack always uses config default)
- `tests/cli_tests.rs`: two new integration tests —
  `test_ship_no_cleanup_preserves_worktree` and
  `test_ship_auto_cleanup_removes_worktree`

Refs #313

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add `substitute_template_vars()` helper that expands `{{ticket}}`,
`{{branch}}`, `{{title}}`, `{{ticket_url}}` placeholders in PR
template content before embedding it into the PR body.

Changes:
- src/cli/commands/ship.rs:
  - New `substitute_template_vars()` with RustDoc explaining each var
  - `build_pr_body()` gains `branch: &str` parameter; passes it + other
    context to substitute_template_vars when template content is present
  - Template section comment updated to reference #304 alongside #233
  - 5 unit tests: all-vars, optional-vars-empty, unknown-var-intact,
    multi-occurrence, build_pr_body end-to-end

Unknown `{{…}}` tokens are left intact so templates using other
tooling variables are not silently mangled.

Refs #304

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…efs #296 (#425)

Add `parsec self-update` subcommand that queries the GitHub releases API,
compares the running version against the latest published release, and
prints a cargo-install upgrade command when a newer version is available.

## Changes
- src/cli/commands/update.rs (new): async fetch + semver compare + output
- src/cli/commands/mod.rs: wire update module
- src/cli/mod.rs: SelfUpdate command variant + run dispatch

## Implementation detail
- Uses reqwest (already a dep) with 8 s timeout and a parsec/VERSION User-Agent
- Numeric semver comparison handles 0.10.0 > 0.9.0 correctly (7 unit tests)
- Gracefully degrades on network error (prints current version + releases URL)
- Respects global --offline flag: skips network call, prints version only
- Phase 2 will add in-place binary replacement (see issue #296)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Refs #304

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…e · Refs #296 (#427)

Adds a startup version-check that runs after every command (Human mode only)
and prints a one-line stderr hint when a newer release is available.

## What
- VersionCheckCache (serde JSON) persisted in dirs::cache_dir()
- Throttled to one live GitHub API call per 24 h (STARTUP_CHECK_TIMEOUT_SECS = 2 s)
- Uses cached result between checks — instant on subsequent runs
- Hint written to stderr (never pollutes piped stdout / JSON mode)
- Skipped for: --offline, --quiet, --json, parsec self-update command

## How it works
1. Load cache from ~/.cache/.parsec-version-check
2. If age < 24 h → show hint if cache.latest_tag is newer (instant, no network)
3. If age ≥ 24 h → quick reqwest call (2 s timeout), update cache, show hint if newer
4. Network failure → bump last_checked_secs, preserve existing latest_tag

## Tests
5 new unit tests: cache serde round-trip, default-cache-is-stale, hint logic
(newer/older/equal/None) — all deterministic, no network

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…n · Refs #296

- Add `UpdateConfig` to `ParsecConfig` with `check_on_startup` (bool, default true)
  and `check_interval_hours` (u64, default 24) fields
- `startup_version_hint()` now accepts config values; returns immediately when
  `check_on_startup = false`, honoring `[update] check_on_startup = false` in
  `.parsec.toml`
- `check_interval_hours` replaces the hard-coded 24 h constant, allowing users
  to tune the poll cadence without code changes
- Add `upgrade_command()`: detects Homebrew (/homebrew/ or /Cellar/ in exe path),
  Cargo (/.cargo/bin/), or prebuilt binary, and returns the appropriate upgrade
  command string shown in `parsec self-update` output
- Remove stale note about Phase 2 from upgrade output now that it is shipped
- Add 5 new tests: `upgrade_command_homebrew`, `upgrade_command_contains_repo`,
  `throttle_secs_from_hours` (pure arithmetic), and existing tests still pass
- 108+83+5 tests, clippy-clean, fmt-pass

Closes AC: 알림 opt-out config, 다양한 설치 경로 지원 (homebrew/cargo/prebuilt)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes #429

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Register a custom panic hook that prints a user-friendly crash banner
(always) and optionally saves a structured JSON report to
~/.cache/parsec/crash-<ts>.json (opt-in).

## What
- src/panic_handler.rs: new module
  - setup(enabled): registers std::panic::set_hook
  - Always: human-readable crash banner (version, location, message)
  - Opt-in: JSON report (version, ts, os, shell, argv[1], location, msg)
  - save_report(): writes ~/.cache/parsec/crash-<ts>.json
  - unix_to_utc_fields(): stdlib-only UTC decomposition (no new deps)
  - 6 unit tests: date decomposition, report fields, escape, setup idempotency
- src/config/settings.rs: CrashReportConfig { enabled: bool } (default false)
  + ParsecConfig::crash_report field
- src/main.rs: call panic_handler::setup(config.crash_report.enabled) early
- docs/crash-report.md: privacy policy (what is/isn't collected, opt-in, retention)

## What is NOT collected
No stack trace, no flags, no ticket IDs, no tokens. argv[1] only.
No automatic transmission; user must manually share.

## Tests
114 unit tests pass (6 new in panic_handler), 5 integration, 83 total.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…ds · Refs #298

* feat(panic-handler): Phase 2 — crash-report list/show/clear subcommands · Refs #298

Add `parsec crash-report` with three sub-commands for managing the
opt-in crash report cache written by the Phase 1 panic hook.

## Subcommands

| Command                      | Description                                  |
|------------------------------|----------------------------------------------|
| `parsec crash-report list`   | Table of all reports + panic preview         |
| `parsec crash-report show ID`| Full JSON pretty-print for one report        |
| `parsec crash-report clear`  | Remove all reports (--dry-run safe)          |

## Changes

| File                                    | Change                              |
|-----------------------------------------|-------------------------------------|
| `src/cli/commands/crash_report.rs`     | New: list/show/clear + 5 unit tests |
| `src/cli/commands/mod.rs`              | Re-export new module                |
| `src/cli/mod.rs`                       | CrashReport + CrashReportAction enum + dispatch |

## Behaviour

- `list` respects `--json` (array of {id, timestamp, panic_message, panic_location})
- `show` accepts id with or without `.json` suffix; bail if not found
- `clear` respects global `--dry-run`; all operations read-only except clear
- Cache dir: `<OS cache>/parsec/crash-*.json` (same as Phase 1 writer)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(panic-handler): use epoch-second stems in test fixtures (Windows colon-in-filename)

Windows forbids  in filenames, so test fixtures using ISO-8601 stems
like  failed on the windows-latest CI runner.

Switch to Unix epoch-second stems (e.g. ) to match
the actual filename format written by the Phase 1 panic hook.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add `parsec checkpoint` with two subcommands:

- `parsec checkpoint create [name]` — stashes current worktree state
  (staged, unstaged, untracked) under a `parsec-checkpoint:<name>`
  label. Defaults to a UTC timestamp when no name is given. Exits
  cleanly when the working tree is clean.
- `parsec checkpoint list` — filters `git stash list` to show only
  parsec-managed checkpoints; renders a STASH REF / NAME / BRANCH
  table (--json supported).

Implementation details:
- Purely stash-based — no new files written to disk.
- Prefix convention (`parsec-checkpoint:`) isolates parsec stashes from
  ordinary WIP stashes without data loss risk.
- `--dry-run` respected via the global flag (stash not created when dry).
- 8 unit tests covering happy paths, WIP-prefix variant, filtering of
  non-parsec stashes, and malformed input.

Phase 2 will add `restore <name>` and `drop <name>`.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
)

Add `parsec checkpoint restore <name>` and `parsec checkpoint drop <name>`
subcommands that perform name-based lookup of parsec-managed stash entries.

## Changes
- `checkpoint_restore`: finds stash by name, runs `git stash pop`
- `checkpoint_drop`: finds stash by name, runs `git stash drop`
- `find_checkpoint` helper: exact-match lookup with helpful error listing
  available checkpoint names when the given name is not found
- CLI: `CheckpointAction::{Restore,Drop}` variants wired through dispatcher
- Tests: 6 new unit tests covering exact-match lookup, partial-name rejection,
  hyphenated names, timestamp names, missing name error path

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…Refs #435

Add 11 integration tests to tests/cli_tests.rs covering the checkpoint
and crash-report commands (both shipped in Phase 1+2 with zero prior
CLI-level test coverage).

## checkpoint (8 tests)
- help shows all four subcommands
- list empty repo → human 'No checkpoints found'
- list empty repo --json → []
- create on clean tree → exit 0 + 'clean' message
- create with uncommitted changes → checkpoint created, name in stdout
- create then list → name appears in list
- drop removes checkpoint → list returns empty again
- name with ':' is rejected (colon collides with prefix delimiter)

## crash-report (3 tests)
- help shows list/show/clear
- list with no reports → human 'No crash reports found'
- list --json with no reports → []
  (uses XDG_CACHE_HOME isolation to avoid host crash reports)

All tests: cargo test --quiet passes (94/94 cli_tests, 132/132 unit).
cargo fmt + clippy -D warnings clean.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…efs #302 (#437)

Auto-merged by parsec-daily-improvement cron. All CI checks passed. Gates: CI CLEAN · diff matches #302 · no breaking changes · 10 unit tests.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Closes #439

Co-authored-by: OpenAI Codex <noreply@openai.com>
Closes #441

Co-authored-by: OpenAI Codex <noreply@openai.com>
Closes #443

Co-authored-by: OpenAI Codex <noreply@openai.com>
Co-authored-by: OpenAI Codex <noreply@openai.com>
Closes #447

Co-authored-by: OpenAI Codex <noreply@openai.com>
Merge the final develop line into release/1.0, preserve both MCP and late v0.x features, and align version and release documentation.

Co-Authored-By: OpenAI Codex <noreply@openai.com>
@erishforG
erishforG merged commit db3f1a8 into release/1.0 Sep 19, 2026
24 checks passed
@erishforG
erishforG deleted the release/v1.0-final branch September 19, 2026 01:00
This was referenced Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant