Repository navigation
release: prepare v1.0.0 - #449
Merged
Merged
Conversation
…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>
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>
This was referenced Sep 19, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
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
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.