Skip to content

Introduce skul reset (de-materialize worktree)#6

Merged
sjquant merged 5 commits into
mainfrom
claude/review-tasks-1329y
Apr 4, 2026
Merged

Introduce skul reset (de-materialize worktree)#6
sjquant merged 5 commits into
mainfrom
claude/review-tasks-1329y

Conversation

@sjquant

@sjquant sjquant commented Apr 4, 2026

Copy link
Copy Markdown
Owner

What

Adds skul reset, which removes all Skul-managed files from the current worktree without touching the repository's desired state. It is the inverse of the upcoming skul apply.

Final command surface:

skul add <bundle>     # add to desired state + materialize
skul remove <bundle>  # remove from desired state + de-materialize
skul apply            # materialize desired state → this worktree  (next)
skul reset            # de-materialize all bundles from this worktree
skul status           # show state
skul list             # list available bundles

Why reset, not clean

clean reads like a build-tool artifact removal. reset makes the apply/reset pairing explicit — one materializes, the other de-materializes.

Behaviour

  • Removes all registry-owned files and directories from the current worktree
  • Prompts before removing any file the user has modified since materialization; aborts if the user declines
  • Removes the Skul exclude block from .git/info/exclude when done
  • Does not modify the repository's desired state — the bundle intentions are preserved for skul apply to re-materialize later
  • Returns a clear "nothing to reset" message if the worktree has no managed files

Changes

  • CommandName and CliParseResult updated: "clean""reset"
  • cleanWorktree renamed to resetWorktree; --bundle flag dropped (no compelling use case that remove + add don't already cover)
  • PromptClient interface, its implementation, and the internal confirmManagedFileRemovals helper updated from "clean" to "reset" literal — fixes a type/message mismatch where the user-visible prompt read "during clean" even after the rename
  • Tests updated throughout; "Placeholder command" description left as-is pending a full help-text pass

Open questions for review

  • Naming: reset could be confused with git reset (which alters index/HEAD). clean (like git clean) may be more intuitive. Happy to revert the rename if the team prefers clean.
  • --bundle scope: The spec listed per-bundle scoped de-materialization as a TODO. It was dropped here because skul remove + skul add covers the same ground. If multi-worktree workflows surface a real need for it, it can be re-added on top of this.

claude added 4 commits April 4, 2026 02:48
skul clean --bundle <name> removes only the named bundle's managed
files from the current worktree, leaving other bundles intact. The
git exclude block is updated accordingly (or removed if the last
bundle is cleaned). Desired state is not modified, matching the
clean-vs-remove distinction.

https://claude.ai/code/session_01QZw8LYCJATVjcgAgSMnrWB
- Distinguish unknown bundle (throws) from unmaterialized bundle (soft
  message) by checking desired_state before returning early
- Fix options shape: no longer stores { bundle: undefined } when
  --bundle is omitted; now stores {} to match the type accurately
- Add missing tests: clean --bundle outside a Git repo, clean --bundle
  on a bundle in desired state but not materialized in the current
  worktree (linked-worktree case), throws on unknown bundle name, and
  cleans all tools for a multi-tool bundle

https://claude.ai/code/session_01QZw8LYCJATVjcgAgSMnrWB
skul clean was confusing because "clean" reads like a build-tool
artifact removal rather than a worktree de-materialization. reset
better expresses that it is the inverse of apply.

Also remove the --bundle flag introduced in the previous two commits.
The distinction between remove (forgets intent) and clean --bundle
(de-materializes without forgetting) was too subtle and had no
compelling use case that add/remove don't already cover.

Final command surface: add / remove / apply / reset / status / list.

https://claude.ai/code/session_01QZw8LYCJATVjcgAgSMnrWB
The PromptClient interface, its implementation in createPromptClient,
and the confirmManagedFileRemovals private function still declared
"clean" as a valid operation literal after the rename. The
implementation was already passing "reset", so this was a type/message
mismatch rather than a runtime failure, but the user-facing prompt
message also read "during clean" instead of "during reset".

https://claude.ai/code/session_01QZw8LYCJATVjcgAgSMnrWB
@sjquant sjquant changed the title feat: add --bundle flag to skul clean for per-bundle cleanup Introduce skul reset (de-materialize worktree) Apr 4, 2026
- Rename stale test description 'cleans all' -> 'resets all'
- Give reset its own command registration with a real description
  instead of sharing the 'Placeholder command' loop with list/status
- Update TASKS.md: rename skul clean -> skul reset on line 18, mark
  remove and reset as DONE, drop the superseded clean --bundle entry,
  update handoff note to reflect current priorities
- Fix multi-bundle reset atomicity: collect all user confirmations
  before removing any files so a decline on bundle N does not leave
  bundles 0..N-1 deleted while the registry still records them

https://claude.ai/code/session_01QZw8LYCJATVjcgAgSMnrWB
@sjquant sjquant merged commit 250fa0f into main Apr 4, 2026
sjquant pushed a commit that referenced this pull request May 19, 2026
- Extract buildGlobalRepoRelPathRemapper() in tool-mapping.ts so the
  CLAUDE.md → .claude/CLAUDE.md mapping is derived from GLOBAL_TOOL_DEFINITIONS
  rather than hardcoded in two call sites.

- Remove redundant requestedTools/selectedTools dual-derivation in
  applyBundleGlobal; single selectedTools variable now covers both paths.

- Fix applyGlobal double-fetch: remove outer fetchRemoteSource loop and collect
  clone output directly from applyBundleGlobal return values, so clone lines are
  not duplicated or silently dropped when multiple bundles are applied.

- Drop hardcoded "Home: ~/.claude/" line from renderGlobalStatus; the function
  receives no homeDir and the string was always wrong for non-default home dirs.

- Use cloneMaterializedBundleState in cloneWorktreeState to eliminate the
  duplicated inline bundle-cloning block (review issue #6).

- Add JSDoc notes to getGlobalToolDefinition and resolveGlobalToolTargetPath
  explaining they are exported for external consumers.

- Add 3 integration tests: dry-run remove --global, dry-run reset --global,
  remove a bundle that is in desired_state but not materialized.

https://claude.ai/code/session_01LqY5ib47389veB72TSQmBW
sjquant pushed a commit that referenced this pull request May 19, 2026
- Extract buildGlobalRepoRelPathRemapper() in tool-mapping.ts so the
  CLAUDE.md → .claude/CLAUDE.md mapping is derived from GLOBAL_TOOL_DEFINITIONS
  rather than hardcoded in two call sites.

- Remove redundant requestedTools/selectedTools dual-derivation in
  applyBundleGlobal; single selectedTools variable now covers both paths.

- Fix applyGlobal double-fetch: remove outer fetchRemoteSource loop and collect
  clone output directly from applyBundleGlobal return values, so clone lines are
  not duplicated or silently dropped when multiple bundles are applied.

- Drop hardcoded "Home: ~/.claude/" line from renderGlobalStatus; the function
  receives no homeDir and the string was always wrong for non-default home dirs.

- Use cloneMaterializedBundleState in cloneWorktreeState to eliminate the
  duplicated inline bundle-cloning block (review issue #6).

- Add JSDoc notes to getGlobalToolDefinition and resolveGlobalToolTargetPath
  explaining they are exported for external consumers.

- Add 3 integration tests: dry-run remove --global, dry-run reset --global,
  remove a bundle that is in desired_state but not materialized.

https://claude.ai/code/session_01LqY5ib47389veB72TSQmBW
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.

2 participants