feat: repo-scoping (brief auto-scope + viewer auto-focus), reconcile one-click apply, dedupe-tiers#370
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…acks (#359) (#360) Promoting a track to the shared tier normally moves its private original out, but bulk/manual promotion — or a failed unlink during push-track — leaves the private copy behind. discover_tracks then resolves the collision ("using shared") but warns "exists in both shared and private" on every invocation with no built-in cleanup path; the only fix was hand-deleting. - lib/tracks.py: add find_tier_duplicates() (returns colliding (shared,private) pairs across active + archived tiers without warning/dropping) and issue_refs() (frontmatter github.issues ∪ body #NNNN). Make both existing "exists in both" warnings actionable (point at `dedupe-tiers`). - commands/dedupe_tiers.py: new `dedupe-tiers [--repo] [--apply]`. Dry-run report by default; --apply removes private orphans whose issue refs are a subset of the shared twin's, and REFUSES any with refs the shared lacks (no silent data loss). Deletion lands in notes_root and the dispatcher's auto-commit makes it undoable. - hygiene: insert a report-only dedupe-tiers step (now 4 steps). Docs (README) land separately on dev. Tests: issue_refs union/non-int; pairing only colliding tracks; dry-run keeps files; --apply removes subset orphan; --apply keeps diverged orphan; repo filter; usage guard. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(export): emit tier_duplicates in the JSON read surface (#361) The viewer is otherwise blind to shared/private tier duplicates — discover_tracks drops the private copy with a stderr-only WARN that the extension never reads. Add an additive top-level tier_duplicates array so the viewer can surface them as a read-only health signal: {repo, folder, name, shared_path, private_path, safe} safe = issue_refs(private) ⊆ issue_refs(shared), mirroring dedupe-tiers' no-data-loss invariant so the viewer can distinguish auto-removable orphans from diverged ones needing manual review. Schema stays 1 (additive, same as untracked #288). find_tier_duplicates now returns early when cfg has no notes_root (no private tier ⇒ no duplicates), keeping it safe to call with a bare cfg. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(vscode): surface tier duplicates as a read-only health advisory (#361) Consume the new export.tier_duplicates field and render a ⚠ advisory row under each affected repo: 'N tracks duplicated across tiers', with the dedupe-tiers --repo=<folder> command in the description and a safe-vs-diverged breakdown in the tooltip. The node has NO command — surfacing only; the destructive cleanup stays in the CLI, so the viewer never deletes a track file. - model.ts: TierDuplicate interface + Export.tier_duplicates (additive). - treeModel.ts: RepoNode.tierDuplicates (populated like untracked) + TierDupWarningNode. - tree.ts: pin the advisory at the top of the repo's children (both empty and populated repos); getTreeItem renders it; getParent wires it to the repo. - treeModel.test.ts: population matched/unmatched + MOCKUP empty default. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…363) The extension's Check Label Drift was preview-only — the draft dumped to the output channel with no way to act on it, forcing a terminal trip to apply. After showing the preview it now offers an "Apply reconcile" action that runs the non-draft reconcile (`--yes`) through executeWrite, so the public-repo leak-guard still gates the write. - write.ts: new reconcileApply WriteAction → ["reconcile", "--yes", "--", track] - extension.ts: lift the draft run out of withProgress so the spinner clears before the Apply prompt; on Apply, re-run + refresh the tree - README: document the apply path Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The unittest matrix runs the CLI on ubuntu-latest but never invokes the installer, and it downloads the yq binary directly rather than via the README one-liners. Add a `smoke-install` job that mechanizes the installer-centric acceptance criteria from #5: `install.sh --help`, a real install into a scratch target, the `--target` override (Codex layout), and `work_plan.py --help` — asserting each lands. Leaves only the genuinely-manual checks on #5: the per-distro package-manager one-liners (apt/pacman/dnf) and non-Ubuntu distros, which a GitHub-hosted Ubuntu runner can't prove. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…365) Phase 1 of the cwd-aware repo-scoping pair. Adds the shared resolver both the `brief` auto-scope (#358) and the viewer auto-focus (#357) will call, so the two can't drift on how they map a directory to a configured repo. - lib/cwd_repo.py: resolve_repo_for_dir(cfg, dir) — local clone path first, git origin remote as fallback, local wins the tiebreak; returns None on no match / ambiguity / non-repo. Read-only, never raises (bounded _git). - commands/which_repo.py: `which-repo [--json]` surface for the viewer to spawn with cwd=workspaceFolder; human form gates exit 0/1, --json always exits 0 with {"key": ...}. - Registered in both SUBCOMMANDS and DESCRIPTIONS. - Tests: resolver (local/nested/remote/tiebreak/no-match/non-repo/ambiguous), URL normalizer (scp/https/ssh/.git), and dispatch+docs registration. No user-visible behavior change yet — Phases 2 and 3 wire it into brief and the viewer. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…#358) (#366) Run `brief` from inside a configured repo's checkout and it now scopes to that repo automatically, with a one-line banner — instead of showing every repo and forcing a manual --repo. Uses the Phase-1 resolver (clone path, then git remote). - One effective repo_key is computed once and threaded through both the track filter and the archived-reopen pass, so they can't diverge. - `--repo=all` forces the full cross-repo view (and short-circuits auto-detect); explicit `--repo=<key>` is unchanged and prints no banner. - Opt out with `brief_auto_scope: false` in config.yml. - Auto-scope only engages when the detected repo actually has tracks — the convenience never hides tracks you'd otherwise see. - README: both command tables updated; which-repo documented. Closes #358. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Phase 3 of the cwd-aware repo-scoping pair. When the open workspace folder
is a configured repo, the viewer now defaults the Tracks lens to that repo
(by GitHub slug — the field the repo lens filters on) instead of showing
every repo's issues, whose numbers collide.
- cli.ts: CliRunner gains an optional {cwd} so a probe can target a folder;
makeSpawnRunner threads it to spawn. New whichRepo(run, cwd) parses
`which-repo --json`, never throws.
- autofocus.ts (pure, unit-tested): lensShouldApply (a user lens is sticky —
auto never overrides it) + pickAutoFocusSlug (first folder that resolves to
a slug; multi-root aware).
- tree.ts: _lensSource + setLens(lens, source="user") so existing call sites
stay user-marked unchanged; resetLensSource() re-arms on folder change.
- extension.ts: autoFocusRepo() after initial load + on
onDidChangeWorkspaceFolders; setLens(..., "auto") respects the override.
- Setting workPlan.autoFocusRepo (default true) to opt out.
- vscode/README.md: lens + Configuration docs.
Focus by slug (not config key) per the spec-review HIGH finding. Provider/
extension glue is thin over the pure, tested autofocus + whichRepo functions.
Closes #357.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ry (#368) The defect scan flagged `looks_open` (F841 — assigned, never used; dead since the initial commit). It was the CLOSED-side trigger of an early symmetric draft (`gh CLOSED and looks_open`); the shipped broad check `not looks_closed` is a strict superset of it, so removing the variable changes no behavior. Drift detection is asymmetric on purpose: CLOSED is terminal (broad — a closed issue whose row doesn't read closed is drift), OPEN is not (narrow — only an explicit closed marker contradicts it). A symmetric `not looks_open` open-side would false-positive every in-progress row. - drift.py: drop the dead var; comment the why of the asymmetry. - test_drift.py: 4 tests pinning the previously-untested OPEN side + ambiguous-body cases, so nobody "restores symmetry" back into noise. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Hand-bump the extension version + Status line ahead of the deploy (they must move together — the listing's first paragraph has drifted before). 0.13.0 bundles the viewer-side work landing this deploy: repo auto-focus (#357), one-click Apply on Check Label Drift (#221), and the read-only tier-duplicate advisory (#361). CLI floor unchanged (>= 2026.06.15); all three degrade gracefully on an older CLI. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.
Deploy of the cwd-aware repo-scoping feature pair plus several CLI/viewer improvements bundled since the last release.
Highlights
Repo scoping (cwd-aware) — #358 / #357
which-reporesolver maps a directory to a configured repo (local clone path first, then git remote) — the shared substrate both surfaces use.briefauto-scopes to the repo of the cwd when--repois omitted (one-line banner;--repo=allfor the full view;brief_auto_scope: falseopt-out). Archived-reopen callouts are scoped to the same repo.workPlan.autoFocusRepoopt-out.Reconcile one-click apply — #221
dedupe-tiers — #359 / #361
dedupe-tiersCLI command removes private track copies a shared.work-plan/twin supersedes (refuses any whose private copy holds issue refs the shared one lacks). The viewer surfaces a read-only ⚠ tier-duplicate advisory naming the command.CI — #5
install.shis now smoke-tested on Linux in CI (help, real install,--targetoverride,work_plan.py --help).Chore
Surfaces published this deploy
@stylusnexus/work-plan(CLI changed).stylusnexus.work-plan-viewer0.13.0 (Marketplace + Open VSX).CLI floor for the viewer unchanged (≥
2026.06.15); all new viewer features degrade gracefully on an older CLI.